CVSROOT: /sources/classpath Module name: classpath Changes by: Sven de Marothy <smarothy> 06/06/18 00:54:47
Modified files: . : ChangeLog gnu/java/awt/peer/gtk: FreetypeGlyphVector.java java/awt/font : LineBreakMeasurer.java TextLayout.java TextMeasurer.java java/text : AttributedString.java Log message: 2006-06-18 Sven de Marothy <[EMAIL PROTECTED]> * 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. CVSWeb URLs: http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog?cvsroot=classpath&r1=1.7861&r2=1.7862 http://cvs.savannah.gnu.org/viewcvs/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java?cvsroot=classpath&r1=1.6&r2=1.7 http://cvs.savannah.gnu.org/viewcvs/classpath/java/awt/font/LineBreakMeasurer.java?cvsroot=classpath&r1=1.4&r2=1.5 http://cvs.savannah.gnu.org/viewcvs/classpath/java/awt/font/TextLayout.java?cvsroot=classpath&r1=1.12&r2=1.13 http://cvs.savannah.gnu.org/viewcvs/classpath/java/awt/font/TextMeasurer.java?cvsroot=classpath&r1=1.3&r2=1.4 http://cvs.savannah.gnu.org/viewcvs/classpath/java/text/AttributedString.java?cvsroot=classpath&r1=1.15&r2=1.16 Patches: Index: ChangeLog =================================================================== RCS file: /sources/classpath/classpath/ChangeLog,v retrieving revision 1.7861 retrieving revision 1.7862 diff -u -b -r1.7861 -r1.7862 --- ChangeLog 17 Jun 2006 23:58:41 -0000 1.7861 +++ ChangeLog 18 Jun 2006 00:54:46 -0000 1.7862 @@ -1,4 +1,20 @@ -2006-0-12 Mario torre <neugens at limasoftware.net> +2006-06-18 Sven de Marothy <[EMAIL PROTECTED]> + + * 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. + +2006-06-12 Mario torre <neugens at limasoftware.net> * gnu/java/util/prefs/GConfBasedPreferences.java: new class. * gnu/java/util/prefs/GConfBasedFactory.java: new class. 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 retrieving revision 1.7 diff -u -b -r1.6 -r1.7 --- 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:54:47 -0000 1.7 @@ -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 retrieving revision 1.5 diff -u -b -r1.4 -r1.5 --- java/awt/font/LineBreakMeasurer.java 13 Jun 2006 00:14:27 -0000 1.4 +++ java/awt/font/LineBreakMeasurer.java 18 Jun 2006 00:54:47 -0000 1.5 @@ -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 != '-' && + while( !Character.isWhitespace( text.previous() ) && guessOffset > position ) - { guessOffset--; - c = text.previous(); - } - } else - { - char c = text.next(); - while( !Character.isWhitespace( c ) && c != '-' && + while( !Character.isWhitespace( text.next() ) && guessOffset < offsetLimit ) - { guessOffset++; - c = text.next(); - } + + if( guessOffset > offsetLimit ) + { + 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 retrieving revision 1.13 diff -u -b -r1.12 -r1.13 --- java/awt/font/TextLayout.java 16 Jun 2006 15:14:56 -0000 1.12 +++ java/awt/font/TextLayout.java 18 Jun 2006 00:54:47 -0000 1.13 @@ -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 + + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; + double advance = 0; - // go to first run - while( runIndices[i + 1][1] < firstEndpoint ) - { + for( int i = 0; i < ri; i++ ) advance += runs[i].getLogicalBounds().getWidth(); - i++; - } - 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++; - } - - 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; } - 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 + Rectangle2D r = null; + int ri = charIndices[ firstEndpoint ][0]; + int gi = charIndices[ firstEndpoint ][1]; + double advance = 0; - // go to first run - if( i > 0 ) - while( runIndices[i + 1][1] < firstEndpoint ) - { + for( int i = 0; i < ri; i++ ) advance += runs[i].getLogicalBounds().getWidth(); - i++; - } - 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 + for(; gi <= dg; gi++ ) { - while( j < runs[i].getNumGlyphs() && - runs[i].getGlyphCharIndex( j ) + runIndices[i][0] < - secondEndpoint ) - { - 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; } - 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 retrieving revision 1.4 diff -u -b -r1.3 -r1.4 --- java/awt/font/TextMeasurer.java 22 Mar 2006 19:15:24 -0000 1.3 +++ java/awt/font/TextMeasurer.java 18 Jun 2006 00:54:47 -0000 1.4 @@ -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(); } + /** + * 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) + { +// 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) - throws NotImplementedException { - throw new Error ("not implemented"); - } + if( start < 0 ) + throw new IllegalArgumentException("Start parameter must be > 0."); - public void insertChar (AttributedCharacterIterator newParagraph, - int insertPos) - throws NotImplementedException + 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; + + do { - throw new Error ("not implemented"); + 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 retrieving revision 1.16 diff -u -b -r1.15 -r1.16 --- java/text/AttributedString.java 24 Oct 2005 10:04:22 -0000 1.15 +++ java/text/AttributedString.java 18 Jun 2006 00:54:47 -0000 1.16 @@ -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);