[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[commit-cp] classpath ChangeLog gnu/java/awt/peer/gtk/Freet...
From: |
Sven de Marothy |
Subject: |
[commit-cp] classpath ChangeLog gnu/java/awt/peer/gtk/Freet... |
Date: |
Fri, 09 Jun 2006 20:23:55 +0000 |
CVSROOT: /sources/classpath
Module name: classpath
Changes by: Sven de Marothy <smarothy> 06/06/09 20:23:55
Modified files:
. : ChangeLog
gnu/java/awt/peer/gtk: FreetypeGlyphVector.java GdkFontPeer.java
java/awt/font : TextLayout.java
java/text : Bidi.java
Log message:
2006-06-08 Sven de Marothy <address@hidden>
* java/text/Bidi.java: Treat WS as neutral for rules N1 & N2.
* gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
New constructor for bidirectionality.
(getGlyphMetrics): Return whitespace glyphs.
(getLogicalBounds): Offset rectangles to correct positions.
* gnu/java/awt/peer/gtk/GdkFontPeer.java
(getBaselineFor): Default to ROMAN_BASELINE.
(GdkFontLineMetrics): Guess some values for underline and
strikethrough.
(layoutGlyphVector): Use bidirectionality.
* java/awt/font/TextLayout.java: Implement, mostly.
CVSWeb URLs:
http://cvs.savannah.gnu.org/viewcvs/classpath/ChangeLog?cvsroot=classpath&r1=1.7743&r2=1.7744
http://cvs.savannah.gnu.org/viewcvs/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java?cvsroot=classpath&r1=1.3&r2=1.4
http://cvs.savannah.gnu.org/viewcvs/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java?cvsroot=classpath&r1=1.15&r2=1.16
http://cvs.savannah.gnu.org/viewcvs/classpath/java/awt/font/TextLayout.java?cvsroot=classpath&r1=1.7&r2=1.8
http://cvs.savannah.gnu.org/viewcvs/classpath/java/text/Bidi.java?cvsroot=classpath&r1=1.5&r2=1.6
Patches:
Index: ChangeLog
===================================================================
RCS file: /sources/classpath/classpath/ChangeLog,v
retrieving revision 1.7743
retrieving revision 1.7744
diff -u -b -r1.7743 -r1.7744
--- ChangeLog 9 Jun 2006 17:02:31 -0000 1.7743
+++ ChangeLog 9 Jun 2006 20:23:54 -0000 1.7744
@@ -1,3 +1,17 @@
+2006-06-08 Sven de Marothy <address@hidden>
+
+ * java/text/Bidi.java: Treat WS as neutral for rules N1 & N2.
+ * gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
+ New constructor for bidirectionality.
+ (getGlyphMetrics): Return whitespace glyphs.
+ (getLogicalBounds): Offset rectangles to correct positions.
+ * gnu/java/awt/peer/gtk/GdkFontPeer.java
+ (getBaselineFor): Default to ROMAN_BASELINE.
+ (GdkFontLineMetrics): Guess some values for underline and
+ strikethrough.
+ (layoutGlyphVector): Use bidirectionality.
+ * java/awt/font/TextLayout.java: Implement, mostly.
+
2006-06-09 Anthony Green <address@hidden>
PR classpath/27888:
Index: gnu/java/awt/peer/gtk/FreetypeGlyphVector.java
===================================================================
RCS file:
/sources/classpath/classpath/gnu/java/awt/peer/gtk/FreetypeGlyphVector.java,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -b -r1.3 -r1.4
--- gnu/java/awt/peer/gtk/FreetypeGlyphVector.java 7 Jun 2006 23:48:05
-0000 1.3
+++ gnu/java/awt/peer/gtk/FreetypeGlyphVector.java 9 Jun 2006 20:23:55
-0000 1.4
@@ -82,10 +82,25 @@
private AffineTransform[] glyphTransforms;
/**
+ * Keep track of which glyphs are whitespace, since we don't have
+ * reporting from the peers yet. TextLayout needs this for justification.
+ */
+ private boolean[] whiteSpace;
+
+ /**
* Create a glyphvector from a given (Freetype) font and a String.
*/
public FreetypeGlyphVector(Font f, String s, FontRenderContext frc)
{
+ this(f, s, frc, Font.LAYOUT_LEFT_TO_RIGHT);
+ }
+
+ /**
+ * Create a glyphvector from a given (Freetype) font and a String.
+ */
+ public FreetypeGlyphVector(Font f, String s, FontRenderContext frc,
+ int flags)
+ {
this.s = s;
this.font = f;
this.frc = frc;
@@ -94,6 +109,14 @@
peer = (GdkFontPeer)font.getPeer();
getGlyphs();
+ if( flags == Font.LAYOUT_RIGHT_TO_LEFT )
+ {
+ // reverse the glyph ordering.
+ int[] temp = new int[ nGlyphs ];
+ for(int i = 0; i < nGlyphs; i++)
+ temp[ i ] = glyphCodes[ nGlyphs - i - 1];
+ glyphCodes = temp;
+ }
performDefaultLayout();
}
@@ -180,10 +203,12 @@
*/
public void performDefaultLayout()
{
+ whiteSpace = new boolean[ nGlyphs ];
glyphTransforms = new AffineTransform[ nGlyphs ];
double x = 0;
for(int i = 0; i < nGlyphs; i++)
{
+ whiteSpace[i] = Character.isWhitespace( glyphCodes[ i ] );
GlyphMetrics gm = getGlyphMetrics( i );
Rectangle2D r = gm.getBounds2D();
glyphTransforms[ i ] = AffineTransform.getTranslateInstance(x, 0);
@@ -237,17 +262,20 @@
/**
* Returns the metrics of a single glyph.
+ * FIXME: Not all glyph types are supported.
*/
public GlyphMetrics getGlyphMetrics(int glyphIndex)
{
double[] val = getMetricsNative( glyphCodes[ glyphIndex ] );
if( val == null )
return null;
+ byte type = whiteSpace[ glyphIndex ] ?
+ GlyphMetrics.WHITESPACE : GlyphMetrics.STANDARD;
return new GlyphMetrics( true, (float)val[1], (float)val[2],
new Rectangle2D.Double( val[3], val[4],
val[5], val[6] ),
- GlyphMetrics.STANDARD );
+ type );
}
/**
@@ -319,7 +347,12 @@
Rectangle2D rect = (Rectangle2D)getGlyphLogicalBounds( 0 );
for( int i = 1; i < nGlyphs; i++ )
- rect = rect.createUnion( (Rectangle2D)getGlyphLogicalBounds( i ) );
+ {
+ Rectangle2D r2 = (Rectangle2D)getGlyphLogicalBounds( i );
+ Point2D p = getGlyphPosition( i );
+ r2.setRect( p.getX(), p.getY(), r2.getWidth(), r2.getHeight() );
+ rect = rect.createUnion( r2 );
+ }
return rect;
}
Index: gnu/java/awt/peer/gtk/GdkFontPeer.java
===================================================================
RCS file: /sources/classpath/classpath/gnu/java/awt/peer/gtk/GdkFontPeer.java,v
retrieving revision 1.15
retrieving revision 1.16
diff -u -b -r1.15 -r1.16
--- gnu/java/awt/peer/gtk/GdkFontPeer.java 7 Jun 2006 13:54:32 -0000
1.15
+++ gnu/java/awt/peer/gtk/GdkFontPeer.java 9 Jun 2006 20:23:55 -0000
1.16
@@ -252,18 +252,24 @@
public byte getBaselineFor (Font font, char c)
{
- throw new UnsupportedOperationException ();
+ // FIXME: Actually check.
+ return Font.ROMAN_BASELINE;
}
- protected class GdkFontLineMetrics extends LineMetrics
+ private static class GdkFontLineMetrics extends LineMetrics
{
- FontMetrics fm;
- int nchars;
+ private FontMetrics fm;
+ private int nchars;
+ private float strikethroughOffset, strikethroughThickness,
+ underlineOffset, underlineThickness;
- public GdkFontLineMetrics (FontMetrics m, int n)
+ public GdkFontLineMetrics (GdkFontPeer fp, FontMetrics m, int n)
{
fm = m;
nchars = n;
+ strikethroughOffset = 0f;
+ strikethroughThickness = underlineThickness = ((float)fp.size) / 12f;
+ underlineOffset = 0f;
}
public float getAscent()
@@ -273,6 +279,7 @@
public int getBaselineIndex()
{
+ // FIXME
return Font.ROMAN_BASELINE;
}
@@ -303,7 +310,7 @@
public LineMetrics getLineMetrics (Font font, CharacterIterator ci,
int begin, int limit, FontRenderContext
rc)
{
- return new GdkFontLineMetrics (getFontMetrics (font), limit - begin);
+ return new GdkFontLineMetrics (this, getFontMetrics (font), limit - begin);
}
public Rectangle2D getMaxCharBounds (Font font, FontRenderContext rc)
@@ -350,20 +357,15 @@
char[] chars, int start, int limit,
int flags)
{
- int nchars = (limit - start) + 1;
- char[] nc = new char[nchars];
-
- for (int i = 0; i < nchars; ++i)
- nc[i] = chars[start + i];
-
- return createGlyphVector (font, frc,
- new StringCharacterIterator (new String (nc)));
+ return new FreetypeGlyphVector( font, new String( chars, start,
+ limit - start),
+ frc, flags);
}
public LineMetrics getLineMetrics (Font font, String str,
FontRenderContext frc)
{
- return new GdkFontLineMetrics (getFontMetrics (font), str.length ());
+ return new GdkFontLineMetrics (this, getFontMetrics (font), str.length ());
}
public FontMetrics getFontMetrics (Font font)
Index: java/awt/font/TextLayout.java
===================================================================
RCS file: /sources/classpath/classpath/java/awt/font/TextLayout.java,v
retrieving revision 1.7
retrieving revision 1.8
diff -u -b -r1.7 -r1.8
--- java/awt/font/TextLayout.java 2 Jul 2005 20:32:29 -0000 1.7
+++ java/awt/font/TextLayout.java 9 Jun 2006 20:23:55 -0000 1.8
@@ -1,5 +1,5 @@
/* TextLayout.java --
- Copyright (C) 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 2006 Free Software Foundation, Inc.
This file is part of GNU Classpath.
@@ -38,8 +38,7 @@
package java.awt.font;
-import gnu.java.awt.ClasspathToolkit;
-import gnu.java.awt.peer.ClasspathTextLayoutPeer;
+import gnu.classpath.NotImplementedException;
import java.awt.Font;
import java.awt.Graphics2D;
@@ -47,116 +46,269 @@
import java.awt.Toolkit;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.Point2D;
import java.text.AttributedCharacterIterator;
import java.text.AttributedString;
+import java.text.Bidi;
import java.util.Map;
/**
- * @author Michael Koch
+ * @author Sven de Marothy
*/
public final class TextLayout implements Cloneable
{
- public static final CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy ();
- ClasspathTextLayoutPeer peer;
+ private GlyphVector[] runs;
+ private Font font;
+ private FontRenderContext frc;
+ private String string;
+ private Rectangle2D boundsCache;
+ private LineMetrics lm;
+
+ /**
+ * Start and end character indices of the runs.
+ * First index is the run number, second is 0 or 1 for the starting
+ * and ending character index of the run, respectively.
+ */
+ private int[][] runIndices;
- public static class CaretPolicy
- {
- public CaretPolicy ()
- {
- // Do nothing here.
- }
+ /**
+ * Base directionality, determined from the first char.
+ */
+ private boolean leftToRight;
- public TextHitInfo getStrongCaret (TextHitInfo hit1, TextHitInfo hit2,
- TextLayout layout)
+ /**
+ * Whether this layout contains whitespace or not.
+ */
+ private boolean hasWhitespace = false;
+
+ /**
+ * The default caret policy.
+ */
+ static TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy();
+
+ /**
+ * Constructs a TextLayout.
+ */
+ public TextLayout (String string, Font font, FontRenderContext frc)
{
- return layout.peer.getStrongCaret(hit1, hit2);
+ this.font = font;
+ this.frc = frc;
+ this.string = string;
+ lm = font.getLineMetrics(string, frc);
+
+ // Get base direction and whitespace info
+ getStringProperties();
+
+ if( Bidi.requiresBidi( string.toCharArray(), 0, string.length() ) )
+ {
+ Bidi bidi = new Bidi( string, leftToRight ?
+ Bidi.DIRECTION_LEFT_TO_RIGHT :
+ Bidi.DIRECTION_RIGHT_TO_LEFT );
+ int rc = bidi.getRunCount();
+ byte[] table = new byte[ rc ];
+ for(int i = 0; i < table.length; i++)
+ table[i] = (byte)bidi.getRunLevel(i);
+
+ runs = new GlyphVector[ rc ];
+ runIndices = new int[rc][2];
+ for(int i = 0; i < runs.length; i++)
+ {
+ runIndices[i][0] = bidi.getRunStart( i );
+ runIndices[i][1] = bidi.getRunLimit( i );
+ if( runIndices[i][0] != runIndices[i][1] ) // no empty runs.
+ {
+ runs[i] = font.layoutGlyphVector
+ ( frc, string.toCharArray(),
+ runIndices[i][0], runIndices[i][1],
+ ((table[i] & 1) == 0) ? Font.LAYOUT_LEFT_TO_RIGHT :
+ Font.LAYOUT_RIGHT_TO_LEFT );
+ }
+ }
+ Bidi.reorderVisually( table, 0, runs, 0, runs.length );
+ }
+ else
+ {
+ runs = new GlyphVector[ 1 ];
+ runIndices = new int[1][2];
+ runIndices[0][0] = 0;
+ runIndices[0][1] = string.length();
+ runs[ 0 ] = font.layoutGlyphVector( frc, string.toCharArray(),
+ 0, string.length(),
+ leftToRight ?
+ Font.LAYOUT_LEFT_TO_RIGHT :
+ Font.LAYOUT_RIGHT_TO_LEFT );
}
}
- public TextLayout (AttributedCharacterIterator text, FontRenderContext frc)
+ public TextLayout (String string, Map attributes, FontRenderContext frc)
{
- AttributedString as = new AttributedString (text);
- ClasspathToolkit tk = (ClasspathToolkit)(Toolkit.getDefaultToolkit ());
- peer = tk.getClasspathTextLayoutPeer(as, frc);
+ this( string, new Font( attributes ), frc );
}
- public TextLayout (String string, Font font, FontRenderContext frc)
+ public TextLayout (AttributedCharacterIterator text, FontRenderContext frc)
+ throws NotImplementedException
{
- AttributedString as = new AttributedString (string);
- as.addAttribute (TextAttribute.FONT, font);
- ClasspathToolkit tk = (ClasspathToolkit)(Toolkit.getDefaultToolkit ());
- peer = tk.getClasspathTextLayoutPeer(as, frc);
+ throw new Error ("not implemented");
}
- public TextLayout (String string, Map attributes, FontRenderContext frc)
+ /**
+ * Scan the character run for the first strongly directional character,
+ * which in turn defines the base directionality of the whole layout.
+ */
+ private void getStringProperties()
{
- AttributedString as = new AttributedString (string, attributes);
- ClasspathToolkit tk = (ClasspathToolkit)(Toolkit.getDefaultToolkit ());
- peer = tk.getClasspathTextLayoutPeer(as, frc);
+ boolean gotDirection = false;
+ int i = 0;
+
+ leftToRight = true;
+ while( i < string.length() && !gotDirection )
+ switch( Character.getDirectionality( string.charAt( i++ ) ) )
+ {
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_EMBEDDING:
+ case Character.DIRECTIONALITY_LEFT_TO_RIGHT_OVERRIDE:
+ gotDirection = true;
+ break;
+
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_ARABIC:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_EMBEDDING:
+ case Character.DIRECTIONALITY_RIGHT_TO_LEFT_OVERRIDE:
+ leftToRight = false;
+ gotDirection = true;
+ break;
+ }
+
+ // Determine if there's whitespace in the thing.
+ // Ignore trailing chars.
+ i = string.length() - 1;
+ hasWhitespace = false;
+ while( i >= 0 && Character.isWhitespace( string.charAt(i) ) )
+ i--;
+ // Check the remaining chars
+ while( i >= 0 )
+ if( Character.isWhitespace( string.charAt(i--) ) )
+ hasWhitespace = true;
}
protected Object clone ()
{
- try
- {
- TextLayout tl = (TextLayout) super.clone ();
- tl.peer = (ClasspathTextLayoutPeer) this.peer.clone();
- return tl;
+ return new TextLayout( string, font, frc );
}
- catch (CloneNotSupportedException e)
- {
- // This should never occur
- throw new InternalError ();
- }
- }
-
public void draw (Graphics2D g2, float x, float y)
{
- peer.draw(g2, x, y);
+ for(int i = 0; i < runs.length; i++)
+ {
+ g2.drawGlyphVector(runs[i], x, y);
+ Rectangle2D r = runs[i].getLogicalBounds();
+ x += r.getWidth();
+ }
}
public boolean equals (Object obj)
{
- if (! (obj instanceof TextLayout))
+ if( !( obj instanceof TextLayout) )
return false;
- return equals ((TextLayout) obj);
+ return equals( (TextLayout) obj );
}
public boolean equals (TextLayout tl)
{
- return this.peer.equals(tl.peer);
+ if( runs.length != tl.runs.length )
+ return false;
+ // Compare all glyph vectors.
+ for( int i = 0; i < runs.length; i++ )
+ if( !runs[i].equals( tl.runs[i] ) )
+ return false;
+ return true;
}
public float getAdvance ()
{
- return peer.getAdvance();
+ float totalAdvance = 0f;
+ for(int i = 0; i < runs.length; i++)
+ totalAdvance += runs[i].getLogicalBounds().getWidth();
+ return totalAdvance;
}
public float getAscent ()
{
- return peer.getAscent();
+ return lm.getAscent();
}
public byte getBaseline ()
{
- return peer.getBaseline();
+ return (byte)lm.getBaselineIndex();
}
public float[] getBaselineOffsets ()
{
- return peer.getBaselineOffsets();
+ return lm.getBaselineOffsets();
}
public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint)
{
- return peer.getBlackBoxBounds(firstEndpoint, secondEndpoint);
+ 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 j = 0; // index into the run.
+ if( runIndices[i][1] - runIndices[i][0] > 1 )
+ {
+ while( runs[i].getGlyphCharIndex( j + 1 ) <
+ (firstEndpoint - runIndices[i][0] ) )j++;
+ }
+
+ gp.append(runs[i].getGlyphVisualBounds( j ), false);
+ boolean keepGoing = true;;
+
+ do
+ {
+ while( j < runs[i].getNumGlyphs() &&
+ runs[i].getGlyphCharIndex( j ) + runIndices[i][0] <
+ secondEndpoint )
+ {
+ Rectangle2D r2 = (runs[i].getGlyphVisualBounds( j )).
+ getBounds2D();
+ Point2D p = runs[i].getGlyphPosition( j );
+ r2.setRect( advance + p.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;
}
public Rectangle2D getBounds()
{
- return peer.getBounds();
+ if( boundsCache == null )
+ boundsCache = getOutline(new AffineTransform()).getBounds();
+ return boundsCache;
}
public float[] getCaretInfo (TextHitInfo hit)
@@ -165,144 +317,272 @@
}
public float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds)
+ throws NotImplementedException
{
- return peer.getCaretInfo(hit, bounds);
+ throw new Error ("not implemented");
}
public Shape getCaretShape (TextHitInfo hit)
{
- return getCaretShape(hit, getBounds());
+ return getCaretShape( hit, getBounds() );
}
public Shape getCaretShape (TextHitInfo hit, Rectangle2D bounds)
+ throws NotImplementedException
{
- return peer.getCaretShape(hit, bounds);
+ throw new Error ("not implemented");
}
public Shape[] getCaretShapes (int offset)
{
- return getCaretShapes(offset, getBounds());
+ return getCaretShapes( offset, getBounds() );
}
public Shape[] getCaretShapes (int offset, Rectangle2D bounds)
+ throws NotImplementedException
{
- return getCaretShapes(offset, getBounds(), DEFAULT_CARET_POLICY);
- }
-
- public Shape[] getCaretShapes (int offset, Rectangle2D bounds,
- TextLayout.CaretPolicy policy)
- {
- return peer.getCaretShapes(offset, bounds, policy);
+ throw new Error ("not implemented");
}
public int getCharacterCount ()
{
- return peer.getCharacterCount();
+ return string.length();
}
public byte getCharacterLevel (int index)
+ throws NotImplementedException
{
- return peer.getCharacterLevel(index);
+ throw new Error ("not implemented");
}
public float getDescent ()
{
- return peer.getDescent();
+ return lm.getDescent();
}
public TextLayout getJustifiedLayout (float justificationWidth)
{
- return peer.getJustifiedLayout(justificationWidth);
+ TextLayout newLayout = (TextLayout)clone();
+
+ if( hasWhitespace )
+ newLayout.handleJustify( justificationWidth );
+
+ return newLayout;
}
public float getLeading ()
{
- return peer.getLeading();
+ return lm.getLeading();
}
public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint)
{
- return getLogicalHighlightShape (firstEndpoint, secondEndpoint,
getBounds());
+ return getLogicalHighlightShape( firstEndpoint, secondEndpoint,
+ getBounds() );
}
public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint,
Rectangle2D bounds)
{
- return peer.getLogicalHighlightShape(firstEndpoint, secondEndpoint,
bounds);
+ if( firstEndpoint < 0 || secondEndpoint > getCharacterCount() )
+ return new Rectangle2D.Float();
+
+ int i = 0; // run index
+ double advance = 0;
+
+ // go to first run
+ while( runIndices[i + 1][1] < firstEndpoint )
+ {
+ advance += runs[i].getLogicalBounds().getWidth();
+ i++;
}
- public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint,
- TextHitInfo secondEndpoint)
+ int j = 0; // index into the run.
+ if( runIndices[i][1] - runIndices[i][0] > 1 )
{
- return peer.getLogicalRangesForVisualSelection(firstEndpoint,
secondEndpoint);
+ while( runs[i].getGlyphCharIndex( j + 1 ) <
+ (firstEndpoint - runIndices[i][0] ) )j++;
}
- public TextHitInfo getNextLeftHit (int offset)
+ Rectangle2D r = (runs[i].getGlyphLogicalBounds( j )).getBounds2D();
+ boolean keepGoing = true;;
+
+ do
+ {
+ while( j < runs[i].getNumGlyphs() &&
+ runs[i].getGlyphCharIndex( j ) + runIndices[i][0] <
+ secondEndpoint )
{
- return getNextLeftHit(offset, DEFAULT_CARET_POLICY);
+ Rectangle2D r2 = (runs[i].getGlyphLogicalBounds( j )).
+ getBounds2D();
+ Point2D p = runs[i].getGlyphPosition( j );
+ r2.setRect( advance + p.getX(), r2.getY(),
+ r2.getWidth(), r2.getHeight() );
+ r = r.createUnion( r2 );
+ j++;
}
- public TextHitInfo getNextLeftHit (int offset, TextLayout.CaretPolicy policy)
+ if( j >= runs[i].getNumGlyphs() )
{
- return peer.getNextLeftHit(offset, policy);
+ advance += runs[i].getLogicalBounds().getWidth();
+ i++;
+ j = 0;
}
+ else
+ keepGoing = false;
+ }
+ while( keepGoing );
- public TextHitInfo getNextLeftHit (TextHitInfo hit)
+ return r;
+ }
+
+ public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint)
+ throws NotImplementedException
{
- return getNextLeftHit(hit.getCharIndex());
+ throw new Error ("not implemented");
}
- public TextHitInfo getNextRightHit (int offset)
+ public TextHitInfo getNextLeftHit (int offset)
+ throws NotImplementedException
{
- return getNextRightHit(offset, DEFAULT_CARET_POLICY);
+ throw new Error ("not implemented");
}
- public TextHitInfo getNextRightHit (int offset, TextLayout.CaretPolicy
policy)
+ public TextHitInfo getNextLeftHit (TextHitInfo hit)
+ throws NotImplementedException
{
- return peer.getNextRightHit(offset, policy);
+ throw new Error ("not implemented");
+ }
+
+ public TextHitInfo getNextRightHit (int offset)
+ throws NotImplementedException
+ {
+ throw new Error ("not implemented");
}
public TextHitInfo getNextRightHit (TextHitInfo hit)
+ throws NotImplementedException
{
- return getNextRightHit(hit.getCharIndex());
+ throw new Error ("not implemented");
}
public Shape getOutline (AffineTransform tx)
{
- return peer.getOutline(tx);
+ float x = 0f;
+ GeneralPath gp = new GeneralPath();
+ for(int i = 0; i < runs.length; i++)
+ {
+ gp.append( runs[i].getOutline( x, 0f ), false );
+ Rectangle2D r = runs[i].getLogicalBounds();
+ x += r.getWidth();
+ }
+ gp.transform( tx );
+ return gp;
}
public float getVisibleAdvance ()
{
- return peer.getVisibleAdvance();
+ float totalAdvance = 0f;
+
+ if( runs.length <= 0 )
+ return 0f;
+
+ // No trailing whitespace
+ if( !Character.isWhitespace( string.charAt( string.length() -1 ) ) )
+ return getAdvance();
+
+ // Get length of all runs up to the last
+ for(int i = 0; i < runs.length - 1; i++)
+ totalAdvance += runs[i].getLogicalBounds().getWidth();
+
+ int lastRun = runIndices[ runs.length - 1 ][0];
+ int j = string.length() - 1;
+ while( j >= lastRun && Character.isWhitespace( string.charAt( j ) ) ) j--;
+
+ if( j < lastRun )
+ return totalAdvance; // entire last run is whitespace
+
+ int lastNonWSChar = j - lastRun;
+ j = 0;
+ while( runs[ runs.length - 1 ].getGlyphCharIndex( j )
+ <= lastNonWSChar )
+ {
+ totalAdvance += runs[ runs.length - 1 ].getGlyphLogicalBounds( j ).
+ getBounds2D().getWidth();
+ j ++;
+ }
+
+ return totalAdvance;
}
public Shape getVisualHighlightShape (TextHitInfo firstEndpoint,
TextHitInfo secondEndpoint)
{
- return getVisualHighlightShape(firstEndpoint, secondEndpoint, getBounds());
+ return getVisualHighlightShape( firstEndpoint, secondEndpoint,
+ getBounds() );
}
public Shape getVisualHighlightShape (TextHitInfo firstEndpoint,
TextHitInfo secondEndpoint,
Rectangle2D bounds)
+ throws NotImplementedException
{
- return peer.getVisualHighlightShape(firstEndpoint, secondEndpoint, bounds);
+ throw new Error ("not implemented");
}
public TextHitInfo getVisualOtherHit (TextHitInfo hit)
+ throws NotImplementedException
{
- return peer.getVisualOtherHit(hit);
+ throw new Error ("not implemented");
}
+ /**
+ * This is a protected method of a <code>final</code> class, meaning
+ * it exists only to taunt you.
+ */
protected void handleJustify (float justificationWidth)
{
- peer.handleJustify(justificationWidth);
+ // We assume that the text has non-trailing whitespace.
+ // First get the change in width to insert into the whitespaces.
+ double deltaW = justificationWidth - getVisibleAdvance();
+ int nglyphs = 0; // # of whitespace chars
+
+ // determine last non-whitespace char.
+ int lastNWS = string.length() - 1;
+ while( Character.isWhitespace( string.charAt( lastNWS ) ) ) lastNWS--;
+
+ // locations of the glyphs.
+ int[] wsglyphs = new int[string.length() * 10];
+ for(int run = 0; run < runs.length; run++ )
+ for(int i = 0; i < runs[run].getNumGlyphs(); i++ )
+ {
+ int cindex = runIndices[run][0] + runs[run].getGlyphCharIndex( i );
+ if( Character.isWhitespace( string.charAt( cindex ) ) )
+ // && cindex < lastNWS )
+ {
+ wsglyphs[ nglyphs * 2 ] = run;
+ wsglyphs[ nglyphs * 2 + 1] = i;
+ nglyphs++;
+ }
}
- public int hashCode ()
+ deltaW = deltaW / nglyphs; // Change in width per whitespace glyph
+ double w = 0;
+ int cws = 0;
+ // Shift all characters
+ for(int run = 0; run < runs.length; run++ )
+ for(int i = 0; i < runs[ run ].getNumGlyphs(); i++ )
{
- return peer.hashCode();
+ if( wsglyphs[ cws * 2 ] == run && wsglyphs[ cws * 2 + 1 ] == i )
+ {
+ cws++; // update 'current whitespace'
+ w += deltaW; // increment the shift
+ }
+ Point2D p = runs[ run ].getGlyphPosition( i );
+ p.setLocation( p.getX() + w, p.getY() );
+ runs[ run ].setGlyphPosition( i, p );
+ }
}
public TextHitInfo hitTestChar (float x, float y)
@@ -312,21 +592,48 @@
public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds)
{
- return peer.hitTestChar(x, y, bounds);
+ return hitTestChar( x, y, getBounds() );
}
public boolean isLeftToRight ()
{
- return peer.isLeftToRight();
+ return leftToRight;
}
public boolean isVertical ()
{
- return peer.isVertical();
+ return false; // FIXME: How do you create a vertical layout?
+ }
+
+ public int hashCode ()
+ throws NotImplementedException
+ {
+ throw new Error ("not implemented");
}
public String toString ()
{
- return peer.toString();
+ return "TextLayout [string:"+string+", Font:"+font+" Rendercontext:"+
+ frc+"]";
+ }
+
+ /**
+ * Inner class describing a caret policy
+ */
+ public static class CaretPolicy
+ {
+ public CaretPolicy()
+ {
+ }
+
+ public TextHitInfo getStrongCaret(TextHitInfo hit1,
+ TextHitInfo hit2,
+ TextLayout layout)
+ throws NotImplementedException
+ {
+ throw new Error ("not implemented");
+ }
}
}
+
+
Index: java/text/Bidi.java
===================================================================
RCS file: /sources/classpath/classpath/java/text/Bidi.java,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -b -r1.5 -r1.6
--- java/text/Bidi.java 8 Jun 2006 23:32:13 -0000 1.5
+++ java/text/Bidi.java 9 Jun 2006 20:23:55 -0000 1.6
@@ -644,6 +644,7 @@
case Character.DIRECTIONALITY_OTHER_NEUTRALS:
case Character.DIRECTIONALITY_SEGMENT_SEPARATOR:
case Character.DIRECTIONALITY_PARAGRAPH_SEPARATOR:
+ case Character.DIRECTIONALITY_WHITESPACE:
if (neutralStart == -1)
neutralStart = i;
break;