[cp-patches] FYI: More font stuff

Sven de Marothy sven at physto.se
Sun Jun 18 02:43:57 UTC 2006


2006-06-18  Sven de Marothy  <sven at physto.se>

	* gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
	(FreetypeGlyphVector, clone): Implement cloning.
	(getGlyphLogicalBounds): Bounds should be offset to the glyph 
position.
	* java/awt/font/TextMeasurer.java: Implement.
	* java/awt/font/LineBreakMeasurer.java: 
	Reimplement to use TextMeasurer.
	* java/awt/font/TextLayout.java
	New constructors.
	(getBlackboxBounds, getLogicalHighlightShape): Reimplement.
	(getText, getFont): New private static methods.
	(setCharIndices): New method.
	* java/text/AttributedString.java
	(AttributedString): Fix constructor to stop at end point.
	
-------------- next part --------------
Index: gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java,v
retrieving revision 1.6
diff -U3 -r1.6 FreetypeGlyphVector.java
--- gnu/java/awt/peer/gtk/FreetypeGlyphVector.java	11 Jun 2006 08:29:57 -0000	1.6
+++ gnu/java/awt/peer/gtk/FreetypeGlyphVector.java	18 Jun 2006 00:47:35 -0000
@@ -137,6 +137,35 @@
   }
 
   /**
+   * Cloning constructor
+   */  
+  private FreetypeGlyphVector( FreetypeGlyphVector gv )
+  {
+    font = gv.font;
+    peer = gv.peer;
+    frc = gv.frc;
+    s = gv.s;
+    nGlyphs = gv.nGlyphs;
+    logicalBounds = gv.logicalBounds.getBounds2D();
+
+    if( gv.metricsCache != null )
+      {
+	metricsCache = new GlyphMetrics[ nGlyphs ];
+	System.arraycopy(gv.metricsCache, 0, metricsCache, 0, nGlyphs);
+      }
+
+    glyphCodes = new int[ nGlyphs ];
+    glyphPositions = new float[ nGlyphs ];
+    glyphTransforms = new AffineTransform[ nGlyphs ];
+    for(int i = 0; i < nGlyphs; i++ )
+      {
+	glyphTransforms[ i ] = new AffineTransform( gv.glyphTransforms[ i ] );
+	glyphCodes[i] = gv.glyphCodes[ i ];
+	glyphPositions[i] = gv.glyphPositions[ i ];
+      }
+  }
+
+  /**
    * Create the array of glyph codes.
    */
   private void getGlyphs()
@@ -172,6 +201,12 @@
 
   private native GeneralPath getGlyphOutlineNative(int glyphIndex);
 
+
+  public Object clone()
+  {
+    return new FreetypeGlyphVector( this );
+  }
+
   /**
    * Duh, compares two instances.
    */
@@ -260,8 +295,11 @@
     if( gm == null )
       return null; 
     Rectangle2D r = gm.getBounds2D();
-    return new Rectangle2D.Double( r.getX() - gm.getLSB(), r.getY(),
-				   gm.getAdvanceX(), r.getHeight() );
+    Point2D p = getGlyphPosition( glyphIndex );
+    return new Rectangle2D.Double( p.getX() + r.getX() - gm.getLSB(), 
+				   p.getY() + r.getY(),
+				   gm.getAdvanceX(), 
+				   r.getHeight() );
   }
 
   /*
@@ -385,8 +423,6 @@
     for( int i = 1; i < nGlyphs; i++ )
       {
 	Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
-	Point2D p = getGlyphPosition( i );
-	r2.setRect( p.getX(), p.getY(), r2.getWidth(), r2.getHeight() );
 	rect = rect.createUnion( r2 );
       }
 
Index: java/awt/font/LineBreakMeasurer.java
===================================================================
RCS file: /sources/classpath/classpath/java/awt/font/LineBreakMeasurer.java,v
retrieving revision 1.4
diff -U3 -r1.4 LineBreakMeasurer.java
--- java/awt/font/LineBreakMeasurer.java	13 Jun 2006 00:14:27 -0000	1.4
+++ java/awt/font/LineBreakMeasurer.java	18 Jun 2006 00:47:36 -0000
@@ -41,57 +41,41 @@
 import java.text.AttributedCharacterIterator;
 import java.text.AttributedString;
 import java.text.BreakIterator;
-import java.awt.font.TextLayout;
-import java.awt.font.FontRenderContext;
 import java.awt.Shape;
 
 public final class LineBreakMeasurer
 {
   private AttributedCharacterIterator text;
   private int position;
-  private FontRenderContext frc;
-  private TextLayout totalLayout;
+  private TextMeasurer tm; 
   private int numChars;
 
   public LineBreakMeasurer(AttributedCharacterIterator text, 
 			   BreakIterator breakIter, FontRenderContext frc)
   {
-    this.text = text;
-    this.frc = frc;
-    position = 0;
-    totalLayout = new TextLayout(text, frc);
-    numChars = totalLayout.getCharacterCount();
+    this( text, frc );
   }
 
   public LineBreakMeasurer(AttributedCharacterIterator text, 
 			   FontRenderContext frc)
   {
     this.text = text;
-    this.frc = frc;
     position = 0;
-    totalLayout = new TextLayout(text, frc);
-    numChars = totalLayout.getCharacterCount();
+    numChars = text.getEndIndex();
+    tm = new TextMeasurer( text, frc );
   }
 
   public void deleteChar(AttributedCharacterIterator newParagraph, 
 			 int deletePos)
   {
-    totalLayout = new TextLayout(newParagraph, frc);
-    if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() )
-      throw new NullPointerException("Invalid deletePos:"+deletePos);
-    numChars = totalLayout.getCharacterCount();
-    text = newParagraph;
+    tm.deleteChar( newParagraph, deletePos );
     position = 0;
   }
 
   public void insertChar(AttributedCharacterIterator newParagraph, 
 			 int insertPos)
   {
-    totalLayout = new TextLayout(newParagraph, frc);
-    if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() )
-      throw new NullPointerException("Invalid insertPos:"+insertPos);
-    numChars = totalLayout.getCharacterCount();
-    text = newParagraph;
+    tm.insertChar( newParagraph, insertPos );
     position = 0;
   }
 
@@ -104,11 +88,9 @@
 			       boolean requireNextWord)
   {
     int next = nextOffset( wrappingWidth, offsetLimit, requireNextWord );
-    AttributedCharacterIterator aci = (new AttributedString( text, 
-							     position, next )
-				       ).getIterator();
+    TextLayout tl = tm.getLayout( position, next );
     position = next;
-    return new TextLayout( aci, frc );
+    return tl;
   }
 
   public int nextOffset(float wrappingWidth)
@@ -119,69 +101,40 @@
   public int nextOffset(float wrappingWidth, int offsetLimit, 
 			boolean requireNextWord)
   {
-    Shape s = totalLayout.getBlackBoxBounds( position, offsetLimit );
-    double remainingLength = s.getBounds2D().getWidth();
+    int guessOffset = tm.getLineBreakIndex(position, wrappingWidth);
+    if( offsetLimit > numChars )
+      offsetLimit = numChars;
 
-    int guessOffset = (int)( ( (double)wrappingWidth / (double)remainingLength)
-			     * ( (double)numChars - (double)position ) );
-    guessOffset += position;
     if( guessOffset > offsetLimit )
-      guessOffset = offsetLimit;
-
-    s = totalLayout.getBlackBoxBounds( position, guessOffset );
-    double guessLength = s.getBounds2D().getWidth();
-
-    boolean makeSmaller = ( guessLength > wrappingWidth );
-    int inc = makeSmaller ? -1 : 1;
-    boolean keepGoing = true;
-
-    do
       {
-	guessOffset = guessOffset + inc;
-	if( guessOffset <= position || guessOffset > offsetLimit )
-	  {
-	    keepGoing = false;
-	  }
-	else
-	  {
-	    s = totalLayout.getBlackBoxBounds( position, guessOffset );
-	    guessLength = s.getBounds2D().getWidth();
-	    if( makeSmaller && ( guessLength <= wrappingWidth) )	  
-	      keepGoing = false;
-	    if( !makeSmaller && ( guessLength >= wrappingWidth) )
-	      keepGoing = false;
-	  }
+	text.setIndex( offsetLimit );
+	return offsetLimit;
       }
-    while( keepGoing );
 
-    if( !makeSmaller )
-      guessOffset--;
+    text.setIndex( guessOffset );
 
-    if( guessOffset >= offsetLimit )
-      return offsetLimit;
+    // If we're on a breaking character, return directly
+    if( Character.isWhitespace( text.current() ) )
+      return guessOffset;
 
-    text.setIndex( guessOffset );
+    // Otherwise jump forward or backward to the last such char.
     if( !requireNextWord )
-      {
-	char c = text.previous();
-	while( !Character.isWhitespace( c ) && c != '-' && 
-	       guessOffset > position )
-	  { 
-	    guessOffset--; 
-	    c = text.previous();
-	  }
-      }
+      while( !Character.isWhitespace( text.previous() ) && 
+	     guessOffset > position )
+	guessOffset--; 
     else
+      while( !Character.isWhitespace( text.next() ) && 
+	     guessOffset < offsetLimit )
+	guessOffset++;
+    
+    if( guessOffset > offsetLimit )
       {
-	char c = text.next();
-	while( !Character.isWhitespace( c ) && c != '-' && 
-	       guessOffset < offsetLimit )
-	  {
-	    guessOffset++;
-	    c = text.next();
-	  }
+	text.setIndex( offsetLimit );
+	return offsetLimit;
       }
 
+    text.setIndex( guessOffset );
+
     return guessOffset;
   }
 
Index: java/awt/font/TextLayout.java
===================================================================
RCS file: /sources/classpath/classpath/java/awt/font/TextLayout.java,v
retrieving revision 1.12
diff -U3 -r1.12 TextLayout.java
--- java/awt/font/TextLayout.java	16 Jun 2006 15:14:56 -0000	1.12
+++ java/awt/font/TextLayout.java	18 Jun 2006 00:47:36 -0000
@@ -47,6 +47,7 @@
 import java.awt.geom.Rectangle2D;
 import java.awt.geom.GeneralPath;
 import java.awt.geom.Point2D;
+import java.text.CharacterIterator;
 import java.text.AttributedCharacterIterator;
 import java.text.Bidi;
 import java.util.Map;
@@ -71,6 +72,12 @@
   private int[][] runIndices;
 
   /**
+   * Character indices.
+   * Fixt index is the glyphvector, second index is the (first) glyph.
+   */
+  private int[][] charIndices;
+
+  /**
    * Base directionality, determined from the first char.
    */
   private boolean leftToRight;
@@ -137,6 +144,7 @@
 					    Font.LAYOUT_LEFT_TO_RIGHT :
 					    Font.LAYOUT_RIGHT_TO_LEFT );
       }
+    setCharIndices();
   }
 
   public TextLayout (String string, Map attributes, FontRenderContext frc)  
@@ -145,9 +153,97 @@
   }
 
   public TextLayout (AttributedCharacterIterator text, FontRenderContext frc)
-    throws NotImplementedException
   {
-    throw new Error ("not implemented");
+    // FIXME: Very rudimentary.
+    this(getText(text), getFont(text), frc);
+  }
+
+  /**
+   * Package-private constructor to make a textlayout from an existing one.
+   * This is used by TextMeasurer for returning sub-layouts, and it 
+   * saves a lot of time in not having to relayout the text.
+   */
+  TextLayout(TextLayout t, int startIndex, int endIndex)
+  {
+    font = t.font;
+    frc = t.frc;
+    boundsCache = null;
+    lm = t.lm;
+    leftToRight = t.leftToRight;
+
+    if( endIndex > t.getCharacterCount() )
+      endIndex = t.getCharacterCount();
+    string = t.string.substring( startIndex, endIndex );
+
+    int startingRun = t.charIndices[startIndex][0];
+    int nRuns = 1 + t.charIndices[endIndex - 1][0] - startingRun;
+    runIndices = new int[ nRuns ][2];
+
+    runs = new GlyphVector[ nRuns ];
+    for( int i = 0; i < nRuns; i++ )
+      {
+	GlyphVector run = t.runs[ i + startingRun ];
+	// Copy only the relevant parts of the first and last runs.
+	int beginGlyphIndex = (i > 0) ? 0 : t.charIndices[startIndex][1];
+	int numEntries = ( i < nRuns - 1) ? run.getNumGlyphs() : 
+	  1 + t.charIndices[endIndex - 1][1] - beginGlyphIndex;
+	
+	int[] codes = run.getGlyphCodes(beginGlyphIndex, numEntries, null);
+	runs[ i ] = font.createGlyphVector( frc, codes );
+	runIndices[ i ][0] = t.runIndices[i + startingRun][0] - startIndex;
+	runIndices[ i ][1] = t.runIndices[i + startingRun][1] - startIndex;
+      }
+    runIndices[ nRuns - 1 ][1] = endIndex - 1;
+
+    setCharIndices();
+    determineWhiteSpace();
+  }
+
+  private void setCharIndices()
+  {
+    charIndices = new int[ getCharacterCount() ][2];
+    int i = 0;
+    int currentChar = 0;
+    for(int run = 0; run < runs.length; run++)
+      {
+	currentChar = -1;
+	for( int gi = 0; gi < runs[ run ].getNumGlyphs(); gi++)
+	  {
+	    if( runs[ run ].getGlyphCharIndex( gi ) != currentChar )
+	      {
+		charIndices[ i ][0] = run;
+		charIndices[ i ][1] = gi;
+		currentChar = runs[ run ].getGlyphCharIndex( gi );
+		i++;
+	      }
+	  }
+      }
+  }
+
+  private static String getText(AttributedCharacterIterator iter)
+  {
+    StringBuffer sb = new StringBuffer();
+    int idx = iter.getIndex();
+    for(char c = iter.first(); c != CharacterIterator.DONE; c = iter.next()) 
+      sb.append(c);
+    iter.setIndex( idx );
+    return sb.toString();
+  }
+
+  private static Font getFont(AttributedCharacterIterator iter)
+  {
+    Font f = (Font)iter.getAttribute(TextAttribute.FONT);
+    if( f == null )
+      {
+	int size;
+	Float i = (Float)iter.getAttribute(TextAttribute.SIZE);
+	if( i != null )
+	  size = (int)i.floatValue();
+	else
+	  size = 14;
+	f = new Font("Dialog", Font.PLAIN, size );
+      }
+    return f;
   }
 
   /**
@@ -177,10 +273,14 @@
 	  gotDirection = true;
 	  break;
 	}
+    determineWhiteSpace();
+  }
 
+  private void determineWhiteSpace()
+  {
     // Determine if there's whitespace in the thing.
     // Ignore trailing chars.
-    i = string.length() - 1; 
+    int i = string.length() - 1; 
     hasWhitespace = false;
     while( i >= 0 && Character.isWhitespace( string.charAt(i) ) )
       i--;
@@ -249,56 +349,42 @@
 
   public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint)
   {
-    if( firstEndpoint < 0 || secondEndpoint > getCharacterCount() )
+    if( secondEndpoint - firstEndpoint <= 0 )
+      return new Rectangle2D.Float(); // Hmm? 
+
+    if( firstEndpoint < 0 || secondEndpoint > getCharacterCount())
       return new Rectangle2D.Float();
 
     GeneralPath gp = new GeneralPath();
-    int i = 0; // run index
-    double advance = 0;
-
-    // go to first run
-    while( runIndices[i + 1][1] < firstEndpoint ) 
-      {
-	advance += runs[i].getLogicalBounds().getWidth();
-	i++;
-      }
+    
+    int ri = charIndices[ firstEndpoint ][0];
+    int gi = charIndices[ firstEndpoint ][1];
 
-    int j = 0; // index into the run.
-    if( runIndices[i][1] - runIndices[i][0] > 1 )
+    double advance = 0;
+   
+    for( int i = 0; i < ri; i++ )
+      advance += runs[i].getLogicalBounds().getWidth();
+    
+    for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ )
       {
-	while( runs[i].getGlyphCharIndex( j + 1 ) <
-	       (firstEndpoint - runIndices[i][0] ) )j++;
-      }
-
-    gp.append(runs[i].getGlyphVisualBounds( j ), false);
-    boolean keepGoing = true;;
+	int dg;
+	if( i == charIndices[ secondEndpoint - 1 ][0] )
+	  dg = charIndices[ secondEndpoint - 1][1];
+	else
+	  dg = runs[i].getNumGlyphs() - 1;
 
-    do
-      {
-	while( j < runs[i].getNumGlyphs() && 
-	       runs[i].getGlyphCharIndex( j ) + runIndices[i][0] < 
-	       secondEndpoint )
+	for( int j = 0; j <= dg; j++ )
 	  {
 	    Rectangle2D r2 = (runs[i].getGlyphVisualBounds( j )).
 	      getBounds2D();
 	    Point2D p = runs[i].getGlyphPosition( j );
-	    r2.setRect( advance + p.getX(), r2.getY(), 
+	    r2.setRect( advance + r2.getX(), r2.getY(), 
 			r2.getWidth(), r2.getHeight() );
 	    gp.append(r2, false);
-	    j++;
 	  }
 
-	if( j >= runs[i].getNumGlyphs() )
-	  {
-	    advance += runs[i].getLogicalBounds().getWidth();
-	    i++; 
-	    j = 0;
-	  }
-	else
-	  keepGoing = false;
+	advance += runs[i].getLogicalBounds().getWidth();
       }
-    while( keepGoing );
-
     return gp;
   }
 
@@ -382,55 +468,42 @@
   public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint,
                                          Rectangle2D bounds)
   {
-    if( firstEndpoint < 0 || secondEndpoint > getCharacterCount() )
+    if( secondEndpoint - firstEndpoint <= 0 )
+      return new Rectangle2D.Float(); // Hmm? 
+
+    if( firstEndpoint < 0 || secondEndpoint > getCharacterCount())
       return new Rectangle2D.Float();
 
-    int i = 0; // run index
-    double advance = 0;
+    Rectangle2D r = null;
+    int ri = charIndices[ firstEndpoint ][0];
+    int gi = charIndices[ firstEndpoint ][1];
 
-    // go to first run
-    if( i > 0 )
-      while( runIndices[i + 1][1] < firstEndpoint ) 
-	{
-	  advance += runs[i].getLogicalBounds().getWidth();
-	  i++;
-	}
+    double advance = 0;
+   
+    for( int i = 0; i < ri; i++ )
+      advance += runs[i].getLogicalBounds().getWidth();
 
-    int j = 0; // index into the run.
-    if( runIndices[i][1] - runIndices[i][0] > 1 )
+    for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ )
       {
-	while( runs[i].getGlyphCharIndex( j + 1 ) <
-	       (firstEndpoint - runIndices[i][0] ) )j++;
-      }
-
-    Rectangle2D r = (runs[i].getGlyphLogicalBounds( j )).getBounds2D();
-    boolean keepGoing = true;;
+	int dg; // last index in this run to use.
+	if( i == charIndices[ secondEndpoint - 1 ][0] )
+	  dg = charIndices[ secondEndpoint - 1][1];
+	else
+	  dg = runs[i].getNumGlyphs() - 1;
 
-    do
-      {
-	while( j < runs[i].getNumGlyphs() && 
-	       runs[i].getGlyphCharIndex( j ) + runIndices[i][0] < 
-	       secondEndpoint )
+	for(; gi <= dg; gi++ )
 	  {
-	    Rectangle2D r2 = (runs[i].getGlyphLogicalBounds( j )).
+	    Rectangle2D r2 = (runs[i].getGlyphLogicalBounds( gi )).
 	      getBounds2D();
-	    Point2D p = runs[i].getGlyphPosition( j );
-	    r2.setRect( advance + p.getX(), r2.getY(), 
-			r2.getWidth(), r2.getHeight() );
-	    r = r.createUnion( r2 );
-	    j++;
+	    if( r == null )
+	      r = r2;
+	    else
+	      r = r.createUnion(r2);
 	  }
+	gi = 0; // reset glyph index into run for next run.
 
-	if( j >= runs[i].getNumGlyphs() )
-	  {
-	    advance += runs[i].getLogicalBounds().getWidth();
-	    i++; 
-	    j = 0;
-	  }
-	else
-	  keepGoing = false;
+	advance += runs[i].getLogicalBounds().getWidth();
       }
-    while( keepGoing );
 
     return r;
   }
Index: java/awt/font/TextMeasurer.java
===================================================================
RCS file: /sources/classpath/classpath/java/awt/font/TextMeasurer.java,v
retrieving revision 1.3
diff -U3 -r1.3 TextMeasurer.java
--- java/awt/font/TextMeasurer.java	22 Mar 2006 19:15:24 -0000	1.3
+++ java/awt/font/TextMeasurer.java	18 Jun 2006 00:47:36 -0000
@@ -38,67 +38,156 @@
 
 package java.awt.font;
 
-import gnu.classpath.NotImplementedException;
-
 import java.text.AttributedCharacterIterator;
+import java.text.AttributedString;
+import java.awt.Shape;
 
 /**
- * @author Michael Koch
+ * TextMeasurer is a small utility class for measuring the length of laid-out
+ * text objects. 
+ *
+ * @author Sven de Marothy
  * @since 1.3
  */
 public final class TextMeasurer implements Cloneable
 {
-  private AttributedCharacterIterator ci;
+  private AttributedCharacterIterator text;
   private FontRenderContext frc;
-  
+  private TextLayout totalLayout;
+  private int numChars;
+
+  /**
+   * Creates a TextMeasurer from a given text in the form of an
+   * <code>AttributedCharacterIterator</code> and a 
+   * <code>FontRenderContext</code>.
+   */  
   public TextMeasurer (AttributedCharacterIterator text, FontRenderContext frc)
   {
-    this.ci = text;
+    this.text = text;
     this.frc = frc;
+    totalLayout = new TextLayout( text, frc );
+    numChars = totalLayout.getCharacterCount();
   }
 
+  /**
+   * Clones the TextMeasurer object
+   */
   protected Object clone ()
   {
-    try
-      {
-        return super.clone ();
-      }
-    catch (CloneNotSupportedException e)
-      {
-        // This may never occur
-        throw new InternalError ();
-      }
+    return new TextMeasurer( text, frc );
   }
 
+  /**
+   * Update the text if a character is deleted at the position deletePos
+   * @param newParagraph - the updated paragraph.
+   * @param deletePos - the deletion position
+   */
   public void deleteChar (AttributedCharacterIterator newParagraph,
                           int deletePos)
-    throws NotImplementedException
   {
-    throw new Error ("not implemented");
+    totalLayout = new TextLayout(newParagraph, frc);
+    if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() )
+      throw new NullPointerException("Invalid deletePos:"+deletePos);
+    numChars = totalLayout.getCharacterCount();
+    text = newParagraph;
   }
 
-  public float getAdvanceBetween (int start, int limit)
-    throws NotImplementedException
+  /**
+   * Update the text if a character is inserted at the position insertPos
+   * @param newParagraph - the updated paragraph.
+   * @param insertPos - the insertion position
+   */
+  public void insertChar (AttributedCharacterIterator newParagraph,
+                          int insertPos)
   {
-    throw new Error ("not implemented");
+    totalLayout = new TextLayout(newParagraph, frc);
+    if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() )
+      throw new NullPointerException("Invalid insertPos:"+insertPos);
+    numChars = totalLayout.getCharacterCount();
+    text = newParagraph;
   }
 
-  public TextLayout getLayout (int start, int limit)
-    throws NotImplementedException
+  /***
+   * Returns the total advance between two positions in the paragraph.
+   * Characters from start to limit-1 (inclusive) are included in this count.
+   *
+   * @param start - the starting character index.
+   * @param limit - the limiting index.
+   */
+  public float getAdvanceBetween (int start, int limit)
   {
-    throw new Error ("not implemented");
+    Shape s = totalLayout.getLogicalHighlightShape( start, limit );
+    return (float)s.getBounds2D().getWidth();
   }
 
-  public int getLineBreakIndex (int start, float maxAdvance)
-    throws NotImplementedException
+  /**
+   * Returns a <code>TextLayout</code> object corresponding to the characters
+   * from text to limit.
+   * @param start - the starting character index.
+   * @param limit - the limiting index.
+   */
+  public TextLayout getLayout (int start, int limit)
   {
-    throw new Error ("not implemented");
-  }
+//     AttributedCharacterIterator aci = (new AttributedString( text, 
+// 							     start, limit
+// 							     ) ).getIterator();
+//     return new TextLayout( aci, frc );
+    return new TextLayout( totalLayout, start, limit );
+  }
+
+  /**
+   * Returns the line-break index from a given starting index and a maximum
+   * advance. The index returned is the first character outside the given
+   * advance (or the limit of the string, if all remaining characters fit.)
+   *
+   * @param start - the starting index.
+   * @param maxAdvance - the maximum advance allowed.
+   * @return the index of the first character beyond maxAdvance, or the 
+   * index of the last character + 1.
+   */
+  public int getLineBreakIndex (int start, float maxAdvance)
+  {   
+    if( start < 0 )
+      throw new IllegalArgumentException("Start parameter must be > 0.");
+
+    double remainingLength = getAdvanceBetween( start, numChars );
+    
+    int guessOffset = (int)( ( (double)maxAdvance / (double)remainingLength)
+			     * ( (double)numChars - (double)start ) );
+    guessOffset += start;
+    if( guessOffset > numChars )
+      guessOffset = numChars;
+    
+    double guessLength = getAdvanceBetween( start, guessOffset );
+    boolean makeSmaller = ( guessLength > maxAdvance );
+    int inc = makeSmaller ? -1 : 1;
+    boolean keepGoing = true;
 
-  public void insertChar (AttributedCharacterIterator newParagraph,
-                          int insertPos)
-    throws NotImplementedException
-  {
-    throw new Error ("not implemented");
+    do
+      {
+	guessOffset = guessOffset + inc;
+	if( guessOffset <= start || guessOffset > numChars )
+	  {
+	    keepGoing = false;
+	  }
+	else
+	  {
+	    guessLength = getAdvanceBetween( start, guessOffset );
+	    if( makeSmaller && ( guessLength <= maxAdvance) )	  
+	      keepGoing = false;
+	    if( !makeSmaller && ( guessLength >= maxAdvance) )
+	      keepGoing = false;
+	  }
+      }
+    while( keepGoing );
+
+    // Return first index that doesn't fit.
+    if( !makeSmaller )
+      guessOffset--;
+
+    if( guessOffset > numChars )
+      return numChars;
+
+    return guessOffset;
   }
 }
Index: java/text/AttributedString.java
===================================================================
RCS file: /sources/classpath/classpath/java/text/AttributedString.java,v
retrieving revision 1.15
diff -U3 -r1.15 AttributedString.java
--- java/text/AttributedString.java	24 Oct 2005 10:04:22 -0000	1.15
+++ java/text/AttributedString.java	18 Jun 2006 00:47:36 -0000
@@ -221,16 +221,13 @@
             // If the attribute run starts before the beginning index, we
             // need to junk it if it is an Annotation.
             Object attrib_obj = aci.getAttribute(attrib);
-            if (rs < begin)
+	    rs -= begin;
+            if (rs < 0)
               {
                 if (attrib_obj instanceof Annotation)
                    continue;
 
-                rs = begin;
-              }
-            else
-              {
-                rs -= begin;
+                rs = 0;
               }
 
             // Create a map object.  Yes this will only contain one attribute
@@ -243,7 +240,7 @@
 
         c = aci.next();
       }
-    while(c != CharacterIterator.DONE);
+    while( aci.getIndex() < end );
 
     attribs = new AttributeRange[accum.size()];
     attribs = (AttributeRange[]) accum.toArray(attribs);


More information about the Classpath-patches mailing list