summaryrefslogtreecommitdiff
path: root/libjava/classpath/java/awt/font
diff options
context:
space:
mode:
authorupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
committerupstream source tree <ports@midipix.org>2015-03-15 20:14:05 -0400
commit554fd8c5195424bdbcabf5de30fdc183aba391bd (patch)
tree976dc5ab7fddf506dadce60ae936f43f58787092 /libjava/classpath/java/awt/font
downloadcbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.bz2
cbb-gcc-4.6.4-554fd8c5195424bdbcabf5de30fdc183aba391bd.tar.xz
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig; imported gcc-4.6.4 source tree from verified upstream tarball. downloading a git-generated archive based on the 'upstream' tag should provide you with a source tree that is binary identical to the one extracted from the above tarball. if you have obtained the source via the command 'git clone', however, do note that line-endings of files in your working directory might differ from line-endings of the respective files in the upstream repository.
Diffstat (limited to 'libjava/classpath/java/awt/font')
-rw-r--r--libjava/classpath/java/awt/font/FontRenderContext.java137
-rw-r--r--libjava/classpath/java/awt/font/GlyphJustificationInfo.java77
-rw-r--r--libjava/classpath/java/awt/font/GlyphMetrics.java138
-rw-r--r--libjava/classpath/java/awt/font/GlyphVector.java174
-rw-r--r--libjava/classpath/java/awt/font/GraphicAttribute.java137
-rw-r--r--libjava/classpath/java/awt/font/ImageGraphicAttribute.java187
-rw-r--r--libjava/classpath/java/awt/font/LineBreakMeasurer.java148
-rw-r--r--libjava/classpath/java/awt/font/LineMetrics.java67
-rw-r--r--libjava/classpath/java/awt/font/MultipleMaster.java61
-rw-r--r--libjava/classpath/java/awt/font/NumericShaper.java425
-rw-r--r--libjava/classpath/java/awt/font/OpenType.java111
-rw-r--r--libjava/classpath/java/awt/font/ShapeGraphicAttribute.java185
-rw-r--r--libjava/classpath/java/awt/font/TextAttribute.java309
-rw-r--r--libjava/classpath/java/awt/font/TextHitInfo.java128
-rw-r--r--libjava/classpath/java/awt/font/TextLayout.java1420
-rw-r--r--libjava/classpath/java/awt/font/TextMeasurer.java190
-rw-r--r--libjava/classpath/java/awt/font/TransformAttribute.java100
-rw-r--r--libjava/classpath/java/awt/font/package.html46
18 files changed, 4040 insertions, 0 deletions
diff --git a/libjava/classpath/java/awt/font/FontRenderContext.java b/libjava/classpath/java/awt/font/FontRenderContext.java
new file mode 100644
index 000000000..8d530ec5f
--- /dev/null
+++ b/libjava/classpath/java/awt/font/FontRenderContext.java
@@ -0,0 +1,137 @@
+/* FontRenderContext.java
+ Copyright (C) 2002, 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+
+/**
+ * @author Michael Koch
+ */
+public class FontRenderContext
+{
+ private AffineTransform affineTransform;
+ private boolean isAntiAliased;
+ private boolean usesFractionalMetrics;
+
+ /**
+ * Construct a new <code>FontRenderContext</code>.
+ */
+ protected FontRenderContext()
+ {
+ // Do nothing here.
+ }
+
+ /**
+ * Construct a new <code>FontRenderContext</code>.
+ */
+ public FontRenderContext (AffineTransform tx, boolean isAntiAliased,
+ boolean usesFractionalMetrics)
+ {
+ if (tx != null
+ && !tx.isIdentity ())
+ {
+ this.affineTransform = new AffineTransform (tx);
+ }
+
+ this.isAntiAliased = isAntiAliased;
+ this.usesFractionalMetrics = usesFractionalMetrics;
+ }
+
+ public boolean equals (Object obj)
+ {
+ if (! (obj instanceof FontRenderContext))
+ return false;
+
+ return equals ((FontRenderContext) obj);
+ }
+
+ public boolean equals (FontRenderContext rhs)
+ {
+ if (rhs == null)
+ return false;
+
+ if (affineTransform == null && rhs.affineTransform != null
+ || affineTransform != null && rhs.affineTransform == null)
+ return false;
+
+ return ((affineTransform == rhs.affineTransform
+ || affineTransform.equals (rhs.getTransform ()))
+ && isAntiAliased == rhs.isAntiAliased ()
+ && usesFractionalMetrics == rhs.usesFractionalMetrics ());
+ }
+
+
+ /**
+ * Retrieves the affine transform for scaling typographical points
+ * to raster pixels.
+ *
+ * @return a clone of the transform object.
+ */
+ public AffineTransform getTransform ()
+ {
+ if (affineTransform == null)
+ return new AffineTransform ();
+ else
+ return new AffineTransform (affineTransform);
+ }
+
+
+ /**
+ * Returns the hash code of the font render context.
+ */
+ public int hashCode ()
+ {
+ int code = ( isAntiAliased ? 1 : 0 ) + ( usesFractionalMetrics ? 2 : 0 );
+
+ if( affineTransform != null && !affineTransform.isIdentity() )
+ code ^= affineTransform.hashCode();
+
+ return code;
+ }
+
+ public boolean isAntiAliased ()
+ {
+ return isAntiAliased;
+ }
+
+ public boolean usesFractionalMetrics ()
+ {
+ return usesFractionalMetrics;
+ }
+}
diff --git a/libjava/classpath/java/awt/font/GlyphJustificationInfo.java b/libjava/classpath/java/awt/font/GlyphJustificationInfo.java
new file mode 100644
index 000000000..cfa64f05e
--- /dev/null
+++ b/libjava/classpath/java/awt/font/GlyphJustificationInfo.java
@@ -0,0 +1,77 @@
+/* GlyphJustificationInfo.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+/**
+ * @author Michael Koch
+ */
+public final class GlyphJustificationInfo
+{
+ public static final int PRIORITY_KASHIDA = 0;
+ public static final int PRIORITY_WHITESPACE = 1;
+ public static final int PRIORITY_INTERCHAR = 2;
+ public static final int PRIORITY_NONE = 3;
+
+ public final float weight;
+ public final int growPriority;
+ public final boolean growAbsorb;
+ public final float growLeftLimit;
+ public final float growRightLimit;
+ public final int shrinkPriority;
+ public final boolean shrinkAbsorb;
+ public final float shrinkLeftLimit;
+ public final float shrinkRightLimit;
+
+ public GlyphJustificationInfo (float weight, boolean growAbsorb,
+ int growPriority, float growLeftLimit,
+ float growRightLimit, boolean shrinkAbsorb,
+ int shrinkPriority, float shrinkLeftLimit,
+ float shrinkRightLimit)
+ {
+ this.weight = weight;
+ this.growAbsorb = growAbsorb;
+ this.growPriority = growPriority;
+ this.growLeftLimit = growLeftLimit;
+ this.growRightLimit = growRightLimit;
+ this.shrinkAbsorb = shrinkAbsorb;
+ this.shrinkPriority = shrinkPriority;
+ this.shrinkLeftLimit = shrinkLeftLimit;
+ this.shrinkRightLimit = shrinkRightLimit;
+ }
+}
diff --git a/libjava/classpath/java/awt/font/GlyphMetrics.java b/libjava/classpath/java/awt/font/GlyphMetrics.java
new file mode 100644
index 000000000..b41b7f45b
--- /dev/null
+++ b/libjava/classpath/java/awt/font/GlyphMetrics.java
@@ -0,0 +1,138 @@
+/* GlyphMetrics.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.geom.Rectangle2D;
+
+/**
+ * @author Michael Koch
+ */
+public final class GlyphMetrics
+{
+ public static final byte COMBINING = 2;
+ public static final byte COMPONENT = 3;
+ public static final byte LIGATURE = 1;
+ public static final byte STANDARD = 0;
+ public static final byte WHITESPACE = 4;
+
+ private boolean horizontal;
+ private float advanceX;
+ private float advanceY;
+ private Rectangle2D bounds;
+ private byte glyphType;
+
+ public GlyphMetrics (boolean horizontal, float advanceX, float advanceY,
+ Rectangle2D bounds, byte glyphType)
+ {
+ this.horizontal = horizontal;
+ this.advanceX = advanceX;
+ this.advanceY = advanceY;
+ this.bounds = bounds;
+ this.glyphType = glyphType;
+ }
+
+ public GlyphMetrics (float advance, Rectangle2D bounds, byte glyphType)
+ {
+ this (true, advance, advance, bounds, glyphType);
+ }
+
+ public float getAdvance ()
+ {
+ return horizontal ? advanceX : advanceY;
+ }
+
+ public float getAdvanceX ()
+ {
+ return advanceX;
+ }
+
+ public float getAdvanceY ()
+ {
+ return advanceY;
+ }
+
+ public Rectangle2D getBounds2D ()
+ {
+ return bounds;
+ }
+
+ public float getLSB()
+ {
+ if (horizontal)
+ return (float) bounds.getX();
+ return (float) bounds.getY();
+ }
+
+ public float getRSB()
+ {
+ if (horizontal)
+ return (float) (advanceX - (bounds.getX() + bounds.getWidth()));
+ return (float) (advanceY - (bounds.getY() + bounds.getHeight()));
+ }
+
+ public int getType ()
+ {
+ return glyphType;
+ }
+
+ public boolean isCombining ()
+ {
+ return (glyphType == COMBINING);
+ }
+
+ public boolean isComponent ()
+ {
+ return (glyphType == COMPONENT);
+ }
+
+ public boolean isLigature()
+ {
+ return (glyphType == LIGATURE);
+ }
+
+ public boolean isStandard()
+ {
+ return (glyphType == STANDARD);
+ }
+
+ public boolean isWhitespace()
+ {
+ return (glyphType == WHITESPACE);
+ }
+}
diff --git a/libjava/classpath/java/awt/font/GlyphVector.java b/libjava/classpath/java/awt/font/GlyphVector.java
new file mode 100644
index 000000000..4a87f4c62
--- /dev/null
+++ b/libjava/classpath/java/awt/font/GlyphVector.java
@@ -0,0 +1,174 @@
+/* GlyphVector.java
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.Font;
+import java.awt.Rectangle;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * @author Lillian Angel (langel at redhat dot com)
+ * @author Michael Koch
+ */
+public abstract class GlyphVector implements Cloneable
+{
+ public static final int FLAG_COMPLEX_GLYPHS = 8;
+ public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2;
+ public static final int FLAG_HAS_TRANSFORMS = 1;
+ public static final int FLAG_MASK = 15;
+ public static final int FLAG_RUN_RTL = 4;
+
+ /**
+ * Constructs a <code>GlyphVector</code> object.
+ */
+ public GlyphVector ()
+ {
+ }
+
+ public abstract boolean equals (GlyphVector set);
+
+ public abstract Font getFont ();
+
+ public abstract FontRenderContext getFontRenderContext ();
+
+ public int getGlyphCharIndex (int glyphIndex)
+ {
+ return glyphIndex;
+ }
+
+ public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries,
+ int[] codeReturn)
+ {
+ if (codeReturn == null)
+ codeReturn = new int[numEntries];
+
+ int i = 0;
+ int j = beginGlyphIndex;
+ while (j < numEntries)
+ codeReturn[i++] = getGlyphCharIndex(j++);
+
+ return codeReturn;
+ }
+
+ public abstract int getGlyphCode (int glyphIndex);
+
+ public abstract int[] getGlyphCodes (int beginGlyphIndex, int numEntries,
+ int[] codeReturn);
+
+ public abstract GlyphJustificationInfo getGlyphJustificationInfo
+ (int glyphIndex);
+
+ public abstract Shape getGlyphLogicalBounds (int glyphIndex);
+
+ public abstract GlyphMetrics getGlyphMetrics (int glyphIndex);
+
+ public abstract Shape getGlyphOutline (int glyphIndex);
+
+ public Shape getGlyphOutline(int glyphIndex, float x, float y)
+ {
+ Shape s = getGlyphOutline(glyphIndex);
+
+ // This is the only way to translate the origin of a shape
+ AffineTransform at = AffineTransform.getTranslateInstance(x, y);
+ return at.createTransformedShape(s);
+ }
+
+ public Rectangle getGlyphPixelBounds(int index, FontRenderContext renderFRC,
+ float x, float y)
+ {
+ Rectangle bounds = new Rectangle();
+ Rectangle2D rect = getGlyphVisualBounds(index).getBounds2D();
+
+ bounds.x = (int) (rect.getX() + x);
+ bounds.y = (int) (rect.getY() + y);
+ bounds.width = (int) rect.getMaxX() - bounds.x;
+ bounds.height = (int) rect.getMaxY() - bounds.y;
+
+ return bounds;
+ }
+
+ public abstract Point2D getGlyphPosition (int glyphIndex);
+
+ public abstract float[] getGlyphPositions (int beginGlyphIndex,
+ int numEntries,
+ float[] positionReturn);
+
+ public abstract AffineTransform getGlyphTransform (int glyphIndex);
+
+ public abstract Shape getGlyphVisualBounds (int glyphIndex);
+
+ public int getLayoutFlags()
+ {
+ return 0;
+ }
+
+ public abstract Rectangle2D getLogicalBounds ();
+
+ public abstract int getNumGlyphs ();
+
+ public abstract Shape getOutline ();
+
+ public abstract Shape getOutline (float x, float y);
+
+ public Rectangle getPixelBounds (FontRenderContext renderFRC,
+ float x, float y)
+ {
+ Rectangle bounds = new Rectangle();
+ Rectangle2D rect = getVisualBounds();
+
+ bounds.x = (int) (rect.getX() + x);
+ bounds.y = (int) (rect.getY() + y);
+ bounds.width = (int) rect.getMaxX() - bounds.x;
+ bounds.height = (int) rect.getMaxY() - bounds.y;
+
+ return bounds;
+ }
+
+ public abstract Rectangle2D getVisualBounds ();
+
+ public abstract void performDefaultLayout ();
+
+ public abstract void setGlyphPosition (int glyphIndex, Point2D newPos);
+
+ public abstract void setGlyphTransform (int glyphIndex,
+ AffineTransform newTX);
+}
diff --git a/libjava/classpath/java/awt/font/GraphicAttribute.java b/libjava/classpath/java/awt/font/GraphicAttribute.java
new file mode 100644
index 000000000..edf0c204d
--- /dev/null
+++ b/libjava/classpath/java/awt/font/GraphicAttribute.java
@@ -0,0 +1,137 @@
+/* GraphicAttribute.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * This class represents a graphic embedded in text.
+ *
+ * @author Michael Koch
+ * @author Lillian Angel (langel at redhat dot com)
+ */
+public abstract class GraphicAttribute
+{
+ public static final int BOTTOM_ALIGNMENT = - 2;
+ public static final int CENTER_BASELINE = 1;
+ public static final int HANGING_BASELINE = 2;
+ public static final int ROMAN_BASELINE = 0;
+ public static final int TOP_ALIGNMENT = - 1;
+
+ private int alignment;
+
+ /**
+ * Constructor.
+ *
+ * @param alignment - the alignment to use for the graphic
+ */
+ protected GraphicAttribute(int alignment)
+ {
+ if (alignment < BOTTOM_ALIGNMENT || alignment > HANGING_BASELINE)
+ throw new IllegalArgumentException("Invalid alignment");
+ this.alignment = alignment;
+ }
+
+ /**
+ * Draws the graphic.
+ *
+ * @param graphics - the graphics configuration to use
+ * @param x - the x location
+ * @param y - the y location
+ */
+ public abstract void draw(Graphics2D graphics, float x, float y);
+
+ /**
+ * Gets the distance from the origin of its graphic to the right side of the
+ * bounds of its graphic.
+ *
+ * @return the advance
+ */
+ public abstract float getAdvance();
+
+ /**
+ * Gets the positive distance from the origin of its graphic to the top of
+ * bounds.
+ *
+ * @return the ascent
+ */
+ public abstract float getAscent();
+
+ /**
+ * Gets the distance from the origin of its graphic to the bottom of the bounds.
+ *
+ * @return the descent
+ */
+ public abstract float getDescent();
+
+ /**
+ * Gets the alignment.
+ *
+ * @return the alignment
+ */
+ public final int getAlignment()
+ {
+ return alignment;
+ }
+
+ /**
+ * Returns a Rectangle2D that encloses the rendered area.
+ * Default bounds is the rectangle (0, -ascent, advance, ascent+descent).
+ *
+ * @return the bounds of the rendered area
+ */
+ public Rectangle2D getBounds()
+ {
+ float asc = getAscent();
+ return new Rectangle2D.Float(0, - asc, getAdvance(), asc + getDescent());
+ }
+
+ /**
+ * Returns the justification information for this object.
+ *
+ * @return the justification information
+ */
+ public GlyphJustificationInfo getJustificationInfo()
+ {
+ float adv = getAdvance();
+ return new GlyphJustificationInfo(adv, false, 2, adv / 3, adv / 3, false,
+ 1, 0, 0);
+ }
+}
diff --git a/libjava/classpath/java/awt/font/ImageGraphicAttribute.java b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java
new file mode 100644
index 000000000..63fff4101
--- /dev/null
+++ b/libjava/classpath/java/awt/font/ImageGraphicAttribute.java
@@ -0,0 +1,187 @@
+/* ImageGraphicAttribute.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.Image;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * This is an implementation of GraphicAttribute which draws images in a
+ * TextLayout.
+ *
+ * @author Lillian Angel
+ * @author Michael Koch
+ */
+public final class ImageGraphicAttribute
+ extends GraphicAttribute
+{
+ private Image image;
+ private float originX;
+ private float originY;
+
+ /**
+ * Constucts an instance from the specified Image. The origin is at (0, 0).
+ *
+ * @param image - image to construct from.
+ * @param alignment - the alignment
+ */
+ public ImageGraphicAttribute(Image image, int alignment)
+ {
+ this(image, alignment, 0, 0);
+ }
+
+ /**
+ * Constucts an instance from the specified Image. The origin is at (originX,
+ * originY).
+ *
+ * @param image - image to construct from
+ * @param alignment - the alignment
+ * @param originX - x point of origin
+ * @param originY - y point of origin
+ */
+ public ImageGraphicAttribute(Image image, int alignment, float originX,
+ float originY)
+ {
+ super(alignment);
+ this.image = image;
+ this.originX = originX;
+ this.originY = originY;
+ }
+
+ /**
+ * Draws the image at the specified location, relative to the
+ * origin.
+ *
+ * @param g - the graphics to use to render the image
+ * @param x - the x location
+ * @param y - the y location
+ */
+ public void draw(Graphics2D g, float x, float y)
+ {
+ g.drawImage(image, (int) (x - originX), (int) (y - originY), null);
+ }
+
+ /**
+ * Compares this to the specified Object
+ *
+ * @param obj - the object to compare
+ * @return true if the obj and this are equivalent
+ */
+ public boolean equals(Object obj)
+ {
+ if (! (obj instanceof ImageGraphicAttribute))
+ return false;
+
+ return equals((ImageGraphicAttribute) obj);
+ }
+
+ /**
+ * Compares this to the ImageGraphicAttribute given, by
+ * comparing all fields and values.
+ *
+ * @param rhs - the ImageGraphicAttribute to compare
+ * @return true if the object given is equivalent to this
+ */
+ public boolean equals(ImageGraphicAttribute rhs)
+ {
+ return ((this == rhs) || ((this.getAscent() == rhs.getAscent())
+ && (this.getAdvance() == rhs.getAdvance())
+ && (this.getAlignment() == rhs.getAlignment())
+ && (this.getBounds().equals(rhs.getBounds()))
+ && (this.getDescent() == rhs.getDescent())
+ && (this.hashCode() == rhs.hashCode())
+ && (this.image.equals(rhs.image))
+ && (this.originX == rhs.originX)
+ && (this.originY == rhs.originY)));
+ }
+
+ /**
+ * Returns distance from the origin to the right edge of the image of this.
+ *
+ * @return the advance
+ */
+ public float getAdvance()
+ {
+ return Math.max(0, image.getWidth(null) - originX);
+ }
+
+ /**
+ * Returns the the distance from the top of the image to the origin of this.
+ *
+ * @return the ascent.
+ */
+ public float getAscent()
+ {
+ return Math.max(0, originY);
+ }
+
+ /**
+ * Gets the bounds of the object rendered, relative to the position.
+ *
+ * @return the bounds of the object rendered, relative to the position.
+ */
+ public Rectangle2D getBounds()
+ {
+ // This is equivalent to what Sun's JDK returns.
+ // I am not entirely sure why the origin is negative.
+ return new Rectangle2D.Float(- originX, - originY, image.getWidth(null),
+ image.getHeight(null));
+ }
+
+ /**
+ * Returns the distance from the origin to the bottom of the image.
+ *
+ * @return the descent
+ */
+ public float getDescent()
+ {
+ return Math.max(0, image.getHeight(null) - originY);
+ }
+
+ /**
+ * Gets the hash code for this image.
+ *
+ * @return the hash code
+ */
+ public int hashCode()
+ {
+ return image.hashCode();
+ }
+}
diff --git a/libjava/classpath/java/awt/font/LineBreakMeasurer.java b/libjava/classpath/java/awt/font/LineBreakMeasurer.java
new file mode 100644
index 000000000..d11f20d1f
--- /dev/null
+++ b/libjava/classpath/java/awt/font/LineBreakMeasurer.java
@@ -0,0 +1,148 @@
+/* LineBreakMeasurer.java
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.text.AttributedCharacterIterator;
+import java.text.BreakIterator;
+
+public final class LineBreakMeasurer
+{
+ private AttributedCharacterIterator text;
+ private int position;
+ private TextMeasurer tm;
+ private int numChars;
+
+ public LineBreakMeasurer(AttributedCharacterIterator text,
+ BreakIterator breakIter, FontRenderContext frc)
+ {
+ this( text, frc );
+ }
+
+ public LineBreakMeasurer(AttributedCharacterIterator text,
+ FontRenderContext frc)
+ {
+ this.text = text;
+ position = 0;
+ numChars = text.getEndIndex();
+ tm = new TextMeasurer( text, frc );
+ }
+
+ public void deleteChar(AttributedCharacterIterator newParagraph,
+ int deletePos)
+ {
+ tm.deleteChar( newParagraph, deletePos );
+ position = 0;
+ }
+
+ public void insertChar(AttributedCharacterIterator newParagraph,
+ int insertPos)
+ {
+ tm.insertChar( newParagraph, insertPos );
+ position = 0;
+ }
+
+ public TextLayout nextLayout(float wrappingWidth)
+ {
+ return nextLayout( wrappingWidth, numChars, false );
+ }
+
+ public TextLayout nextLayout(float wrappingWidth, int offsetLimit,
+ boolean requireNextWord)
+ {
+ int next = nextOffset( wrappingWidth, offsetLimit, requireNextWord );
+ TextLayout tl = tm.getLayout( position, next );
+ position = next;
+ return tl;
+ }
+
+ public int nextOffset(float wrappingWidth)
+ {
+ return nextOffset( wrappingWidth, numChars, false );
+ }
+
+ public int nextOffset(float wrappingWidth, int offsetLimit,
+ boolean requireNextWord)
+ {
+ int guessOffset = tm.getLineBreakIndex(position, wrappingWidth);
+ if( offsetLimit > numChars )
+ offsetLimit = numChars;
+
+ if( guessOffset > offsetLimit )
+ {
+ text.setIndex( offsetLimit );
+ return offsetLimit;
+ }
+
+ text.setIndex( guessOffset );
+
+ // If we're on a breaking character, return directly
+ if( Character.isWhitespace( text.current() ) )
+ return guessOffset;
+
+ // Otherwise jump forward or backward to the last such char.
+ if( !requireNextWord )
+ while( !Character.isWhitespace( text.previous() ) &&
+ guessOffset > position )
+ guessOffset--;
+ else
+ while( !Character.isWhitespace( text.next() ) &&
+ guessOffset < offsetLimit )
+ guessOffset++;
+
+ if( guessOffset > offsetLimit )
+ {
+ text.setIndex( offsetLimit );
+ return offsetLimit;
+ }
+
+ text.setIndex( guessOffset );
+
+ return guessOffset;
+ }
+
+ public void setPosition(int newPosition)
+ {
+ position = newPosition;
+ }
+
+ public int getPosition()
+ {
+ return position;
+ }
+}
diff --git a/libjava/classpath/java/awt/font/LineMetrics.java b/libjava/classpath/java/awt/font/LineMetrics.java
new file mode 100644
index 000000000..d43fd98bb
--- /dev/null
+++ b/libjava/classpath/java/awt/font/LineMetrics.java
@@ -0,0 +1,67 @@
+/* LineMetrics.java -- Information about about a line display characteristics
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+/**
+ * @author Michael Koch
+ */
+public abstract class LineMetrics
+{
+ public abstract float getAscent();
+
+ public abstract int getBaselineIndex();
+
+ public abstract float[] getBaselineOffsets();
+
+ public abstract float getDescent();
+
+ public abstract float getHeight();
+
+ public abstract float getLeading();
+
+ public abstract int getNumChars();
+
+ public abstract float getStrikethroughOffset();
+
+ public abstract float getStrikethroughThickness();
+
+ public abstract float getUnderlineOffset();
+
+ public abstract float getUnderlineThickness();
+}
diff --git a/libjava/classpath/java/awt/font/MultipleMaster.java b/libjava/classpath/java/awt/font/MultipleMaster.java
new file mode 100644
index 000000000..1be44bd75
--- /dev/null
+++ b/libjava/classpath/java/awt/font/MultipleMaster.java
@@ -0,0 +1,61 @@
+/* MultipleMaster.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.Font;
+
+/**
+ * @author Michael Koch
+ */
+public interface MultipleMaster
+{
+ Font deriveMMFont (float[] axes);
+
+ Font deriveMMFont (float[] glyphWidths, float avgStemWidth,
+ float typicalCapHeight, float typicalXHeight,
+ float italicAngle);
+
+ float[] getDesignAxisDefaults();
+
+ String[] getDesignAxisNames();
+
+ float[] getDesignAxisRanges();
+
+ int getNumDesignAxes();
+}
diff --git a/libjava/classpath/java/awt/font/NumericShaper.java b/libjava/classpath/java/awt/font/NumericShaper.java
new file mode 100644
index 000000000..add1c6a44
--- /dev/null
+++ b/libjava/classpath/java/awt/font/NumericShaper.java
@@ -0,0 +1,425 @@
+/* NumericShaper.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.io.Serializable;
+import java.lang.Character.UnicodeBlock;
+
+/**
+ * This class handles numeric shaping. A shaper can either be contextual
+ * or not. A non-contextual shaper will always translate ASCII digits
+ * in its input into the target Unicode range. A contextual shaper will
+ * change the target Unicode range depending on the characters it has
+ * previously processed.
+ *
+ * @author Michael Koch
+ * @author Tom Tromey
+ *
+ * @since 1.4
+ * @specnote This class does not handle LIMBU or OSMANYA.
+ * @specnote The JDK does not seem to properly handle ranges without a
+ * digit zero, such as TAMIL. This implementation does.
+ */
+public final class NumericShaper implements Serializable
+{
+ private static final long serialVersionUID = -8022764705923730308L;
+
+ /** Convenience constant representing all the valid Unicode ranges. */
+ public static final int ALL_RANGES = 524287;
+
+ /**
+ * Constant representing the Unicode ARABIC range. Shaping done
+ * using this range will translate to the arabic decimal characters.
+ * Use EASTERN_ARABIC if you want to shape to the eastern arabic
+ * (also known as the extended arabic) decimal characters.
+ */
+ public static final int ARABIC = 2;
+
+ /** Constant representing the Unicode BENGALI range. */
+ public static final int BENGALI = 16;
+
+ /** Constant representing the Unicode DEVANAGARI range. */
+ public static final int DEVANAGARI = 8;
+
+ /**
+ * Constant representing the Unicode extended arabic range.
+ * In Unicode there are two different sets of arabic digits;
+ * this selects the extended or eastern set.
+ */
+ public static final int EASTERN_ARABIC = 4;
+
+ /**
+ * Constant representing the Unicode ETHIOPIC range. Note that
+ * there is no digit zero in this range; an ASCII digit zero
+ * is left unchanged when shaping to this range.
+ */
+ public static final int ETHIOPIC = 65536;
+
+ /**
+ * Constant representing the Unicode EUROPEAN range. For
+ * contextual shaping purposes, characters in the various
+ * extended Latin character blocks are recognized as EUROPEAN.
+ */
+ public static final int EUROPEAN = 1;
+
+ /** Constant representing the Unicode GUJARATI range. */
+ public static final int GUJARATI = 64;
+
+ /** Constant representing the Unicode GURMUKHI range. */
+ public static final int GURMUKHI = 32;
+
+ /** Constant representing the Unicode KANNADA range. */
+ public static final int KANNADA = 1024;
+
+ /** Constant representing the Unicode KHMER range. */
+ public static final int KHMER = 131072;
+
+ /** Constant representing the Unicode LAO range. */
+ public static final int LAO = 8192;
+
+ /** Constant representing the Unicode MALAYALAM range. */
+ public static final int MALAYALAM = 2048;
+
+ /** Constant representing the Unicode MONGOLIAN range. */
+ public static final int MONGOLIAN = 262144;
+
+ /** Constant representing the Unicode MYANMAR range. */
+ public static final int MYANMAR = 32768;
+
+ /** Constant representing the Unicode ORIYA range. */
+ public static final int ORIYA = 128;
+
+ /**
+ * Constant representing the Unicode TAMIL range. Note that
+ * there is no digit zero in this range; an ASCII digit zero
+ * is left unchanged when shaping to this range.
+ */
+ public static final int TAMIL = 256;
+
+ /** Constant representing the Unicode TELUGU range. */
+ public static final int TELUGU = 512;
+
+ /** Constant representing the Unicode THAI range. */
+ public static final int THAI = 4096;
+
+ /** Constant representing the Unicode TIBETAN range. */
+ public static final int TIBETAN = 16384;
+
+ /**
+ * This table holds the zero digits for each language. This is hard-coded
+ * because the values will not change and the table layout is tied to the
+ * other constants in this class in any case. In the two places where a
+ * language does not have a zero digit, the character immediately preceeding
+ * the one digit is used instead. These languages are special-cased in
+ * the shaping code.
+ */
+ private static final char[] zeroDigits =
+ {
+ '0', // EUROPEAN
+ '\u0660', // ARABIC
+ '\u06f0', // EASTERN_ARABIC
+ '\u0966', // DEVANAGARI
+ '\u09e6', // BENGALI
+ '\u0a66', // GURMUKHI
+ '\u0ae6', // GUJARATI
+ '\u0b66', // ORIYA
+ '\u0be6', // TAMIL - special case as there is no digit zero
+ '\u0c66', // TELUGU
+ '\u0ce6', // KANNADA
+ '\u0d66', // MALAYALAM
+ '\u0e50', // THAI
+ '\u0ed0', // LAO
+ '\u0f20', // TIBETAN
+ '\u1040', // MYANMAR
+ '\u1368', // ETHIOPIC - special case as there is no digit zero
+ '\u17e0', // KHMER
+ '\u1810' // MONGOLIAN
+ };
+
+ /**
+ * The default initial context for this shaper, specified as
+ * an integer from 0 to 18.
+ */
+ private int key;
+
+ /**
+ * The target ranges handled by this shaper. If the shaper
+ * is not contextual, the high bit of this field will be set.
+ * @specnote This was discovered by reading the serialization spec
+ */
+ private int mask;
+
+ /**
+ * Create a new numeric shaper. The key given is a constant from
+ * this class, the constructor turns it into its internal form.
+ * @param key the key to use, as one of the manifest constants
+ * @param mask a mask of languages to shape for
+ */
+ private NumericShaper (int key, int mask)
+ {
+ // This internal form is a bit goofy, but it is specified by
+ // the serialization spec.
+ this.key = Integer.numberOfTrailingZeros(key);
+ this.mask = mask;
+ }
+
+ /**
+ * Return an integer representing all the languages for which this
+ * shaper will shape. The result is taken by "or"ing together
+ * the constants representing the various languages.
+ */
+ public int getRanges ()
+ {
+ return mask & ALL_RANGES;
+ }
+
+ /**
+ * Return true if this shaper is contextual, false if it is not.
+ */
+ public boolean isContextual ()
+ {
+ return mask > 0;
+ }
+
+ /**
+ * Shape the text in the given array. The starting context will
+ * be the context passed to the shaper at creation time.
+ * @param text the text to shape
+ * @param start the index of the starting character of the array
+ * @param count the number of characters in the array
+ */
+ public void shape (char[] text, int start, int count)
+ {
+ shape (text, start, count, 1 << key);
+ }
+
+ /**
+ * Given a unicode block object, return corresponding language constant.
+ * If the block is not recognized, returns zero. Note that as there
+ * is no separate ARABIC block in Character, this case must
+ * be specially handled by the caller; EASTERN_ARABIC is preferred when
+ * both are specified.
+ * @param b the unicode block to classify
+ * @return the language constant, or zero if not recognized
+ */
+ private int classify(UnicodeBlock b)
+ {
+ if (b == null)
+ return 0;
+ // ARABIC is handled by the caller; from testing we know
+ // that EASTERN_ARABIC takes precedence.
+ if (b == UnicodeBlock.ARABIC)
+ return EASTERN_ARABIC;
+ if (b == UnicodeBlock.BENGALI)
+ return BENGALI;
+ if (b == UnicodeBlock.DEVANAGARI)
+ return DEVANAGARI;
+ if (b == UnicodeBlock.ETHIOPIC)
+ return ETHIOPIC;
+ if (b == UnicodeBlock.BASIC_LATIN
+ || b == UnicodeBlock.LATIN_1_SUPPLEMENT
+ || b == UnicodeBlock.LATIN_EXTENDED_A
+ || b == UnicodeBlock.LATIN_EXTENDED_ADDITIONAL
+ || b == UnicodeBlock.LATIN_EXTENDED_B)
+ return EUROPEAN;
+ if (b == UnicodeBlock.GUJARATI)
+ return GUJARATI;
+ if (b == UnicodeBlock.GURMUKHI)
+ return GURMUKHI;
+ if (b == UnicodeBlock.KANNADA)
+ return KANNADA;
+ if (b == UnicodeBlock.KHMER)
+ return KHMER;
+ if (b == UnicodeBlock.LAO)
+ return LAO;
+ if (b == UnicodeBlock.MALAYALAM)
+ return MALAYALAM;
+ if (b == UnicodeBlock.MONGOLIAN)
+ return MONGOLIAN;
+ if (b == UnicodeBlock.MYANMAR)
+ return MYANMAR;
+ if (b == UnicodeBlock.ORIYA)
+ return ORIYA;
+ if (b == UnicodeBlock.TAMIL)
+ return TAMIL;
+ if (b == UnicodeBlock.TELUGU)
+ return TELUGU;
+ if (b == UnicodeBlock.THAI)
+ return THAI;
+ if (b == UnicodeBlock.TIBETAN)
+ return TIBETAN;
+ return 0;
+ }
+
+ /**
+ * Shape the given text, using the indicated initial context.
+ * If this shaper is not a contextual shaper, then the given context
+ * will be ignored.
+ * @param text the text to shape
+ * @param start the index of the first character of the text to shape
+ * @param count the number of characters to shape in the text
+ * @param context the initial context
+ * @throws IllegalArgumentException if the initial context is invalid
+ */
+ public void shape (char[] text, int start, int count, int context)
+ {
+ int currentContext;
+ if (isContextual())
+ {
+ if (Integer.bitCount(context) != 1 || (context & ~ALL_RANGES) != 0)
+ throw new IllegalArgumentException("invalid context argument");
+ // If the indicated context is not one we are handling, reset it.
+ if ((context & mask) == 0)
+ currentContext = -1;
+ else
+ currentContext = Integer.numberOfTrailingZeros(context);
+ }
+ else
+ currentContext = key;
+
+ for (int i = 0; i < count; ++i)
+ {
+ char c = text[start + i];
+ if (c >= '0' && c <= '9')
+ {
+ if (currentContext >= 0)
+ {
+ // Shape into the current context.
+ if (c == '0'
+ && ((1 << currentContext) == TAMIL
+ || (1 << currentContext) == ETHIOPIC))
+ {
+ // No digit 0 in this context; do nothing.
+ }
+ else
+ text[start + i]
+ = (char) (zeroDigits[currentContext] + c - '0');
+ }
+ }
+ else if (isContextual())
+ {
+ // if c is in a group, set currentContext; else reset it.
+ int group = classify(UnicodeBlock.of(c));
+ // Specially handle ARABIC.
+ if (group == EASTERN_ARABIC && (mask & EASTERN_ARABIC) == 0
+ && (mask & ARABIC) != 0)
+ group = ARABIC;
+ if ((mask & group) != 0)
+ {
+ // The character was classified as being in a group
+ // we recognize, and it was selected by the shaper.
+ // So, change the context.
+ currentContext = Integer.numberOfTrailingZeros(group);
+ }
+ }
+ }
+ }
+
+ public boolean equals (Object obj)
+ {
+ if (! (obj instanceof NumericShaper))
+ return false;
+ NumericShaper tmp = (NumericShaper) obj;
+ return key == tmp.key && mask == tmp.mask;
+ }
+
+ public int hashCode ()
+ {
+ return key ^ mask;
+ }
+
+ public String toString ()
+ {
+ // For debugging only.
+ return "key=" + key + "; mask=" + mask;
+ }
+
+ /**
+ * Return a non-contextual shaper which can shape to a single range.
+ * All ASCII digits in the input text are translated to this language.
+ * @param singleRange the target language
+ * @return a non-contextual shaper for this language
+ * @throws IllegalArgumentException if the argument does not name a
+ * single language, as specified by the constants declared in this class
+ */
+ public static NumericShaper getShaper (int singleRange)
+ {
+ if (Integer.bitCount(singleRange) != 1)
+ throw new IllegalArgumentException("more than one bit set in argument");
+ if ((singleRange & ~ALL_RANGES) != 0)
+ throw new IllegalArgumentException("argument out of range");
+ return new NumericShaper(singleRange, Integer.MIN_VALUE | singleRange);
+ }
+
+ /**
+ * Return a contextual shaper which can shape to any of the indicated
+ * languages. The default initial context for this shaper is EUROPEAN.
+ * @param ranges the ranges to shape to
+ * @return a contextual shaper which will target any of these ranges
+ * @throws IllegalArgumentException if the argument specifies an
+ * unrecognized range
+ */
+ public static NumericShaper getContextualShaper (int ranges)
+ {
+ if ((ranges & ~ALL_RANGES) != 0)
+ throw new IllegalArgumentException("argument out of range");
+ return new NumericShaper(EUROPEAN, ranges);
+ }
+
+ /**
+ * Return a contextual shaper which can shape to any of the indicated
+ * languages. The default initial context for this shaper is given as
+ * an argument.
+ * @param ranges the ranges to shape to
+ * @param defaultContext the default initial context
+ * @return a contextual shaper which will target any of these ranges
+ * @throws IllegalArgumentException if the ranges argument specifies an
+ * unrecognized range, or if the defaultContext argument does not specify
+ * a single valid range
+ */
+ public static NumericShaper getContextualShaper (int ranges,
+ int defaultContext)
+ {
+ if (Integer.bitCount(defaultContext) != 1)
+ throw new IllegalArgumentException("more than one bit set in context");
+ if ((ranges & ~ALL_RANGES) != 0 || (defaultContext & ~ALL_RANGES) != 0)
+ throw new IllegalArgumentException("argument out of range");
+ return new NumericShaper(defaultContext, ranges);
+ }
+}
diff --git a/libjava/classpath/java/awt/font/OpenType.java b/libjava/classpath/java/awt/font/OpenType.java
new file mode 100644
index 000000000..e992d0700
--- /dev/null
+++ b/libjava/classpath/java/awt/font/OpenType.java
@@ -0,0 +1,111 @@
+/* OpenType.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+/**
+ * @author Michael Koch
+ */
+public interface OpenType
+{
+ int TAG_ACNT = 1633906292;
+ int TAG_AVAR = 1635148146;
+ int TAG_BASE = 1111577413;
+ int TAG_BDAT = 1650745716;
+ int TAG_BLOC = 1651273571;
+ int TAG_BSLN = 1651731566;
+ int TAG_CFF = 1128678944;
+ int TAG_CMAP = 1668112752;
+ int TAG_CVAR = 1668702578;
+ int TAG_CVT = 1668707360;
+ int TAG_DSIG = 1146308935;
+ int TAG_EBDT = 1161970772;
+ int TAG_EBLC = 1161972803;
+ int TAG_EBSC = 1161974595;
+ int TAG_FDSC = 1717859171;
+ int TAG_FEAT = 1717920116;
+ int TAG_FMTX = 1718449272;
+ int TAG_FPGM = 1718642541;
+ int TAG_FVAR = 1719034226;
+ int TAG_GASP = 1734439792;
+ int TAG_GDEF = 1195656518;
+ int TAG_GLYF = 1735162214;
+ int TAG_GPOS = 1196445523;
+ int TAG_GSUB = 1196643650;
+ int TAG_GVAR = 1735811442;
+ int TAG_HDMX = 1751412088;
+ int TAG_HEAD = 1751474532;
+ int TAG_HHEA = 1751672161;
+ int TAG_HMTX = 1752003704;
+ int TAG_JSTF = 1246975046;
+ int TAG_JUST = 1786082164;
+ int TAG_KERN = 1801810542;
+ int TAG_LCAR = 1818452338;
+ int TAG_LOCA = 1819239265;
+ int TAG_LTSH = 1280594760;
+ int TAG_MAXP = 1835104368;
+ int TAG_MMFX = 1296909912;
+ int TAG_MMSD = 1296913220;
+ int TAG_MORT = 1836020340;
+ int TAG_NAME = 1851878757;
+ int TAG_OPBD = 1836020340;
+ int TAG_OS2 = 1330851634;
+ int TAG_PCLT = 1346587732;
+ int TAG_POST = 1886352244;
+ int TAG_PREP = 1886545264;
+ int TAG_PROP = 1886547824;
+ int TAG_TRAK = 1953653099;
+ int TAG_TYP1 = 1954115633;
+ int TAG_VDMX = 1447316824;
+ int TAG_VHEA = 1986553185;
+ int TAG_VMTX = 1986884728;
+
+ byte[] getFontTable (int sfntTag);
+
+ byte[] getFontTable (int sfntTag, int offset, int count);
+
+ byte[] getFontTable (String strSfntTag);
+
+ byte[] getFontTable (String strSfntTag, int offset, int count);
+
+ int getFontTableSize (int sfntTag);
+
+ int getFontTableSize (String strSfntTag);
+
+ int getVersion ();
+}
diff --git a/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java
new file mode 100644
index 000000000..8d6891632
--- /dev/null
+++ b/libjava/classpath/java/awt/font/ShapeGraphicAttribute.java
@@ -0,0 +1,185 @@
+/* ShapeGraphicAttribute.java
+ Copyright (C) 2003 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * This is an implementation of GraphicAttribute that draws shapes in a TextLayout.
+ *
+ * @author Lillian Angel (langel at redhat dot com)
+ */
+public final class ShapeGraphicAttribute extends GraphicAttribute
+{
+ /** True if the shape should be filled. */
+ public static final boolean FILL = false;
+
+ /** True if the shape should be stroked with a 1-pixel wide stroke. */
+ public static final boolean STROKE = true;
+
+ private Shape shape;
+ private boolean stroke;
+ private Rectangle2D bounds;
+
+ /**
+ * Constructor.
+ *
+ * @param shape - the Shape to render. The Shape is rendered with its origin.
+ * @param alignment - the alignment
+ * @param stroke - true if the Shape should be stroked; false if the Shape
+ * should be filled.
+ */
+ public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke)
+ {
+ super(alignment);
+ this.shape = shape;
+ this.stroke = stroke;
+ this.bounds = shape.getBounds2D();
+ }
+
+ /**
+ * Draws the graphic at the given location.
+ *
+ * @param graphics - the graphics to use.
+ * @param x - the x location to draw at.
+ * @param y - the y location to draw at.
+ */
+ public void draw(Graphics2D graphics, float x, float y)
+ {
+ graphics.translate(x, y);
+ if (stroke == STROKE)
+ graphics.draw(shape);
+ else
+ graphics.fill(shape);
+ graphics.translate(- x, - y);
+ }
+
+ /**
+ * Compares this ShapeGraphicAttribute to obj.
+ *
+ * @param obj - the object to compare.
+ */
+ public boolean equals(Object obj)
+ {
+ if (! (obj instanceof ShapeGraphicAttribute))
+ return false;
+
+ return equals((ShapeGraphicAttribute) obj);
+ }
+
+ /**
+ * Compares this ShapeGraphicAttribute to rhs.
+ *
+ * @param rhs - the ShapeGraphicAttribute to compare.
+ */
+ public boolean equals(ShapeGraphicAttribute rhs)
+ {
+ return (this == rhs || (this.shape.equals(rhs.shape)
+ && getAlignment() == rhs.getAlignment()
+ && stroke == rhs.stroke
+ && getAdvance() == rhs.getAdvance()
+ && getAscent() == rhs.getAscent()
+ && getBounds().equals(rhs.getBounds())
+ && getDescent() == rhs.getDescent()
+ && hashCode() == rhs.hashCode()));
+ }
+
+ /**
+ * Gets the distance from the origin of its Shape to the right side of the
+ * bounds of its Shape.
+ *
+ * @return the advance
+ */
+ public float getAdvance()
+ {
+ return Math.max(0, (float) bounds.getMaxX());
+ }
+
+ /**
+ * Gets the positive distance from the origin of its Shape to the top of
+ * bounds.
+ *
+ * @return the ascent
+ */
+ public float getAscent()
+ {
+ return Math.max(0, -(float) bounds.getMinY());
+ }
+
+ /**
+ * Gets the distance from the origin of its Shape to the bottom of the bounds.
+ *
+ * @return the descent
+ */
+ public float getDescent()
+ {
+ return Math.max(0, (float) bounds.getMaxY());
+ }
+
+ /**
+ * Returns a Rectangle2D that encloses all of the bits drawn by this shape.
+ *
+ * @return the bounds of the shape.
+ */
+ public Rectangle2D getBounds()
+ {
+ Rectangle2D.Float bounds = new Rectangle2D.Float();
+ bounds.setRect(this.bounds);
+
+ if (stroke == STROKE)
+ {
+ bounds.width++;
+ bounds.height++;
+ }
+
+ return bounds;
+ }
+
+ /**
+ * Gets the hash code.
+ *
+ * @return the hash code.
+ */
+ public int hashCode()
+ {
+ return shape.hashCode();
+ }
+}
diff --git a/libjava/classpath/java/awt/font/TextAttribute.java b/libjava/classpath/java/awt/font/TextAttribute.java
new file mode 100644
index 000000000..bfade21bb
--- /dev/null
+++ b/libjava/classpath/java/awt/font/TextAttribute.java
@@ -0,0 +1,309 @@
+/* TextAttribute.java --
+ Copyright (C) 2003, 2004, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.io.InvalidObjectException;
+import java.text.AttributedCharacterIterator;
+
+/**
+ * Attributes (and associated values) that can be used to define an
+ * {@link java.text.AttributedString}.
+ */
+public final class TextAttribute extends AttributedCharacterIterator.Attribute
+{
+ private static final long serialVersionUID = 7744112784117861702L;
+
+ /** A key for the background paint attribute. */
+ public static final TextAttribute BACKGROUND =
+ new TextAttribute("background");
+
+ /** A key for the BIDI_EMBEDDING attribute. */
+ public static final TextAttribute BIDI_EMBEDDING =
+ new TextAttribute("bidi_embedding");
+
+ /** A key for the CHAR_REPLACEMENT attribute. */
+ public static final TextAttribute CHAR_REPLACEMENT =
+ new TextAttribute("char_replacement");
+
+ /** A key for the FAMILY attribute. */
+ public static final TextAttribute FAMILY = new TextAttribute("family");
+
+ /** A key for the font attribute. */
+ public static final TextAttribute FONT = new TextAttribute("font");
+
+ /** A key for the foreground paint attribute. */
+ public static final TextAttribute FOREGROUND =
+ new TextAttribute("foreground");
+
+ /** A key for the INPUT_METHOD_HIGHLIGHT attribute. */
+ public static final TextAttribute INPUT_METHOD_HIGHLIGHT =
+ new TextAttribute("input method highlight");
+
+ /** A key for the INPUT_METHOD_UNDERLINE attribute. */
+ public static final TextAttribute INPUT_METHOD_UNDERLINE =
+ new TextAttribute("input method underline");
+
+ /** A key for the text justification attribute. */
+ public static final TextAttribute JUSTIFICATION =
+ new TextAttribute("justification");
+
+ /**
+ * A value that can be used with the {@link #JUSTIFICATION} attribute to
+ * indicate full justification of the text.
+ */
+ public static final Float JUSTIFICATION_FULL = new Float(1.0);
+
+ /**
+ * A value that can be used with the {@link #JUSTIFICATION} attribute to
+ * indicate no justification of the text.
+ */
+ public static final Float JUSTIFICATION_NONE = new Float(0.0);
+
+ /** A key for the NUMERIC_SHAPING attribute. */
+ public static final TextAttribute NUMERIC_SHAPING =
+ new TextAttribute("numeric_shaping");
+
+ /** A key for the POSTURE attribute. */
+ public static final TextAttribute POSTURE = new TextAttribute("posture");
+
+ /** A value that can be used with the {@link #POSTURE} attribute. */
+ public static final Float POSTURE_OBLIQUE = new Float(0.2);
+
+ /** A value that can be used with the {@link #POSTURE} attribute. */
+ public static final Float POSTURE_REGULAR = new Float(0.0);
+
+ /** A key for the RUN_DIRECTION attribute. */
+ public static final TextAttribute RUN_DIRECTION =
+ new TextAttribute("run_direction");
+
+ /** A value that can be used with the {@link #RUN_DIRECTION} attribute. */
+ public static final Boolean RUN_DIRECTION_LTR = Boolean.FALSE;
+
+ /** A value that can be used with the {@link #RUN_DIRECTION} attribute. */
+ public static final Boolean RUN_DIRECTION_RTL = Boolean.TRUE;
+
+ /** A key for the text size attribute. */
+ public static final TextAttribute SIZE = new TextAttribute("size");
+
+ /** A key for the STRIKETHROUGH attribute. */
+ public static final TextAttribute STRIKETHROUGH =
+ new TextAttribute("strikethrough");
+
+ /** A value that can be used with the {@link #STRIKETHROUGH} attribute. */
+ public static final Boolean STRIKETHROUGH_ON = Boolean.TRUE;
+
+ /** A key for the SUPERSCRIPT attribute. */
+ public static final TextAttribute SUPERSCRIPT =
+ new TextAttribute("superscript");
+
+ /** A value that can be used with the {@link #SUPERSCRIPT} attribute. */
+ public static final Integer SUPERSCRIPT_SUB = new Integer(-1);
+
+ /** A value that can be used with the {@link #SUPERSCRIPT} attribute. */
+ public static final Integer SUPERSCRIPT_SUPER = new Integer(1);
+
+ /** A key for the SWAP_COLORS attribute. */
+ public static final TextAttribute SWAP_COLORS =
+ new TextAttribute("swap_colors");
+
+ /** A value that can be used with the {@link #SWAP_COLORS} attribute. */
+ public static final Boolean SWAP_COLORS_ON = Boolean.TRUE;
+
+ /** A key for the TRANFORM attribute. */
+ public static final TextAttribute TRANSFORM = new TextAttribute("transform");
+
+ /** A key for the UNDERLINE attribute. */
+ public static final TextAttribute UNDERLINE = new TextAttribute("underline");
+
+ /** A value that can be used with the {@link #UNDERLINE} attribute. */
+ public static final Integer UNDERLINE_LOW_DASHED = new Integer(5);
+
+ /** A value that can be used with the {@link #UNDERLINE} attribute. */
+ public static final Integer UNDERLINE_LOW_DOTTED = new Integer(3);
+
+ /** A value that can be used with the {@link #UNDERLINE} attribute. */
+ public static final Integer UNDERLINE_LOW_GRAY = new Integer(4);
+
+ /** A value that can be used with the {@link #UNDERLINE} attribute. */
+ public static final Integer UNDERLINE_LOW_ONE_PIXEL = new Integer(1);
+
+ /** A value that can be used with the {@link #UNDERLINE} attribute. */
+ public static final Integer UNDERLINE_LOW_TWO_PIXEL = new Integer(2);
+
+ /** A value that can be used with the {@link #UNDERLINE} attribute. */
+ public static final Integer UNDERLINE_ON = new Integer(0);
+
+ /** A key for the WEIGHT attribute. */
+ public static final TextAttribute WEIGHT = new TextAttribute("weight");
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_BOLD = new Float(2.0);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_DEMIBOLD = new Float(1.75);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_DEMILIGHT = new Float(0.875);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_EXTRA_LIGHT = new Float(0.5);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_EXTRABOLD = new Float(2.5);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_HEAVY = new Float(2.25);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_LIGHT = new Float(0.75);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_MEDIUM = new Float(1.5);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_REGULAR = new Float(1.0);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_SEMIBOLD = new Float(1.25);
+
+ /** A value that can be used with the {@link #WEIGHT} attribute. */
+ public static final Float WEIGHT_ULTRABOLD = new Float(2.75);
+
+ /** A key for the WIDTH attribute. */
+ public static final TextAttribute WIDTH = new TextAttribute("width");
+
+ /** A value that can be used with the {@link #WIDTH} attribute. */
+ public static final Float WIDTH_CONDENSED = new Float(0.75);
+
+ /** A value that can be used with the {@link #WIDTH} attribute. */
+ public static final Float WIDTH_EXTENDED = new Float(1.5);
+
+ /** A value that can be used with the {@link #WIDTH} attribute. */
+ public static final Float WIDTH_REGULAR = new Float(1.0);
+
+ /** A value that can be used with the {@link #WIDTH} attribute. */
+ public static final Float WIDTH_SEMI_CONDENSED = new Float(0.875);
+
+ /** A value that can be used with the {@link #WIDTH} attribute. */
+ public static final Float WIDTH_SEMI_EXTENDED = new Float(1.25);
+
+ /**
+ * Creates a new attribute.
+ *
+ * @param name the name.
+ */
+ protected TextAttribute(String name)
+ {
+ super(name);
+ }
+
+ /**
+ * After deserialization, this method ensures that only one instance of
+ * each attribute is used.
+ *
+ * @return The (single) attribute instance.
+ *
+ * @throws InvalidObjectException if the attribute is not recognised.
+ */
+ protected Object readResolve()
+ throws InvalidObjectException
+ {
+ if (this.getName().equals("background"))
+ return BACKGROUND;
+
+ if (this.getName().equals("bidi_embedding"))
+ return BIDI_EMBEDDING;
+
+ if (this.getName().equals("char_replacement"))
+ return CHAR_REPLACEMENT;
+
+ if (this.getName().equals("family"))
+ return FAMILY;
+
+ if (this.getName().equals("font"))
+ return FONT;
+
+ if (this.getName().equals("foreground"))
+ return FOREGROUND;
+
+ if (this.getName().equals("input method highlight"))
+ return INPUT_METHOD_HIGHLIGHT;
+
+ if (this.getName().equals("input method underline"))
+ return INPUT_METHOD_UNDERLINE;
+
+ if (this.getName().equals("justification"))
+ return JUSTIFICATION;
+
+ if (this.getName().equals("numeric_shaping"))
+ return NUMERIC_SHAPING;
+
+ if (this.getName().equals("posture"))
+ return POSTURE;
+
+ if (this.getName().equals("run_direction"))
+ return RUN_DIRECTION;
+
+ if (this.getName().equals("size"))
+ return SIZE;
+
+ if (this.getName().equals("strikethrough"))
+ return STRIKETHROUGH;
+
+ if (this.getName().equals("superscript"))
+ return SUPERSCRIPT;
+
+ if (this.getName().equals("swap_colors"))
+ return SWAP_COLORS;
+
+ if (this.getName().equals("transform"))
+ return TRANSFORM;
+
+ if (this.getName().equals("underline"))
+ return UNDERLINE;
+
+ if (this.getName().equals("weight"))
+ return WEIGHT;
+
+ if (this.getName().equals("width"))
+ return WIDTH;
+
+ throw new InvalidObjectException("Can't resolve Attribute: " + getName());
+ }
+}
diff --git a/libjava/classpath/java/awt/font/TextHitInfo.java b/libjava/classpath/java/awt/font/TextHitInfo.java
new file mode 100644
index 000000000..17479b09e
--- /dev/null
+++ b/libjava/classpath/java/awt/font/TextHitInfo.java
@@ -0,0 +1,128 @@
+/* TextHitInfo.java --
+ Copyright (C) 2002, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+package java.awt.font;
+
+/**
+ * @author John Leuner (jewel@debian.org)
+ */
+public final class TextHitInfo
+{
+ private int charIndex;
+ private boolean leadingEdge;
+
+ TextHitInfo (int charIndex, boolean leadingEdge)
+ {
+ this.charIndex = charIndex;
+ this.leadingEdge = leadingEdge;
+ }
+
+ public int getCharIndex()
+ {
+ return charIndex;
+ }
+
+ public boolean isLeadingEdge()
+ {
+ return leadingEdge;
+ }
+
+ public int getInsertionIndex()
+ {
+ return (leadingEdge ? charIndex : charIndex + 1);
+ }
+
+ public int hashCode()
+ {
+ return charIndex;
+ }
+
+ public boolean equals(Object obj)
+ {
+ if(obj instanceof TextHitInfo)
+ return this.equals((TextHitInfo) obj);
+
+ return false;
+ }
+
+ public boolean equals(TextHitInfo hitInfo)
+ {
+ if (hitInfo == null)
+ return false;
+
+ return (charIndex == hitInfo.getCharIndex ())
+ && (leadingEdge == hitInfo.isLeadingEdge ());
+ }
+
+ public static TextHitInfo leading(int charIndex)
+ {
+ return new TextHitInfo (charIndex, true);
+ }
+
+ public static TextHitInfo trailing(int charIndex)
+ {
+ return new TextHitInfo (charIndex, false);
+ }
+
+ public static TextHitInfo beforeOffset(int offset)
+ {
+ return new TextHitInfo ((offset - 1), false);
+ }
+
+ public static TextHitInfo afterOffset(int offset)
+ {
+ return new TextHitInfo (offset, true);
+ }
+
+ public TextHitInfo getOtherHit()
+ {
+ return (leadingEdge ? trailing (charIndex - 1) : leading (charIndex + 1));
+ }
+
+ public TextHitInfo getOffsetHit(int offset)
+ {
+ return new TextHitInfo (charIndex + offset, leadingEdge);
+ }
+
+ public String toString()
+ {
+ return "TextHitInfo["
+ + charIndex
+ + (leadingEdge ? "L" : "T" )
+ + "]";
+ }
+}
diff --git a/libjava/classpath/java/awt/font/TextLayout.java b/libjava/classpath/java/awt/font/TextLayout.java
new file mode 100644
index 000000000..c4f174245
--- /dev/null
+++ b/libjava/classpath/java/awt/font/TextLayout.java
@@ -0,0 +1,1420 @@
+/* TextLayout.java --
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import gnu.java.lang.CPStringBuilder;
+
+import java.awt.Font;
+import java.awt.Graphics2D;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Line2D;
+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.ArrayList;
+import java.util.Map;
+
+/**
+ * @author Sven de Marothy
+ */
+public final class TextLayout implements Cloneable
+{
+ /**
+ * Holds the layout data that belongs to one run of characters.
+ */
+ private class Run
+ {
+ /**
+ * The actual glyph vector.
+ */
+ GlyphVector glyphVector;
+
+ /**
+ * The font for this text run.
+ */
+ Font font;
+
+ /**
+ * The start of the run.
+ */
+ int runStart;
+
+ /**
+ * The end of the run.
+ */
+ int runEnd;
+
+ /**
+ * The layout location of the beginning of the run.
+ */
+ float location;
+
+ /**
+ * Initializes the Run instance.
+ *
+ * @param gv the glyph vector
+ * @param start the start index of the run
+ * @param end the end index of the run
+ */
+ Run(GlyphVector gv, Font f, int start, int end)
+ {
+ glyphVector = gv;
+ font = f;
+ runStart = start;
+ runEnd = end;
+ }
+
+ /**
+ * Returns <code>true</code> when this run is left to right,
+ * <code>false</code> otherwise.
+ *
+ * @return <code>true</code> when this run is left to right,
+ * <code>false</code> otherwise
+ */
+ boolean isLeftToRight()
+ {
+ return (glyphVector.getLayoutFlags() & GlyphVector.FLAG_RUN_RTL) == 0;
+ }
+ }
+
+ /**
+ * The laid out character runs.
+ */
+ private Run[] runs;
+
+ private FontRenderContext frc;
+ private char[] string;
+ private int offset;
+ private int length;
+ private Rectangle2D boundsCache;
+ private LineMetrics lm;
+
+ /**
+ * The total advance of this text layout. This is cache for maximum
+ * performance.
+ */
+ private float totalAdvance = -1F;
+
+ /**
+ * The cached natural bounds.
+ */
+ private Rectangle2D naturalBounds;
+
+ /**
+ * 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;
+
+ /**
+ * Whether this layout contains whitespace or not.
+ */
+ private boolean hasWhitespace = false;
+
+ /**
+ * The {@link Bidi} object that is used for reordering and by
+ * {@link #getCharacterLevel(int)}.
+ */
+ private Bidi bidi;
+
+ /**
+ * Mpas the logical position of each individual character in the original
+ * string to its visual position.
+ */
+ private int[] logicalToVisual;
+
+ /**
+ * Maps visual positions of a character to its logical position
+ * in the original string.
+ */
+ private int[] visualToLogical;
+
+ /**
+ * The cached hashCode.
+ */
+ private int hash;
+
+ /**
+ * The default caret policy.
+ */
+ public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY =
+ new CaretPolicy();
+
+ /**
+ * Constructs a TextLayout.
+ */
+ public TextLayout (String str, Font font, FontRenderContext frc)
+ {
+ this.frc = frc;
+ string = str.toCharArray();
+ offset = 0;
+ length = this.string.length;
+ lm = font.getLineMetrics(this.string, offset, length, frc);
+
+ // Get base direction and whitespace info
+ getStringProperties();
+
+ if (Bidi.requiresBidi(string, offset, offset + length))
+ {
+ bidi = new Bidi(str, 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 Run[rc];
+ for(int i = 0; i < rc; i++)
+ {
+ int start = bidi.getRunStart(i);
+ int end = bidi.getRunLimit(i);
+ if(start != end) // no empty runs.
+ {
+ GlyphVector gv = font.layoutGlyphVector(frc,
+ string, start, end,
+ ((table[i] & 1) == 0) ? Font.LAYOUT_LEFT_TO_RIGHT
+ : Font.LAYOUT_RIGHT_TO_LEFT );
+ runs[i] = new Run(gv, font, start, end);
+ }
+ }
+ Bidi.reorderVisually( table, 0, runs, 0, runs.length );
+ // Clean up null runs.
+ ArrayList cleaned = new ArrayList(rc);
+ for (int i = 0; i < rc; i++)
+ {
+ if (runs[i] != null)
+ cleaned.add(runs[i]);
+ }
+ runs = new Run[cleaned.size()];
+ runs = (Run[]) cleaned.toArray(runs);
+ }
+ else
+ {
+ GlyphVector gv = font.layoutGlyphVector( frc, string, offset, length,
+ leftToRight ? Font.LAYOUT_LEFT_TO_RIGHT
+ : Font.LAYOUT_RIGHT_TO_LEFT );
+ Run run = new Run(gv, font, 0, length);
+ runs = new Run[]{ run };
+ }
+ setCharIndices();
+ setupMappings();
+ layoutRuns();
+ }
+
+ public TextLayout (String string,
+ Map<? extends AttributedCharacterIterator.Attribute, ?> attributes,
+ FontRenderContext frc)
+ {
+ this( string, new Font( attributes ), frc );
+ }
+
+ public TextLayout (AttributedCharacterIterator text, FontRenderContext frc)
+ {
+ // 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)
+ {
+ frc = t.frc;
+ boundsCache = null;
+ lm = t.lm;
+ leftToRight = t.leftToRight;
+
+ if( endIndex > t.getCharacterCount() )
+ endIndex = t.getCharacterCount();
+ string = t.string;
+ offset = startIndex + offset;
+ length = endIndex - startIndex;
+
+ int startingRun = t.charIndices[startIndex][0];
+ int nRuns = 1 + t.charIndices[endIndex - 1][0] - startingRun;
+
+ runs = new Run[nRuns];
+ for( int i = 0; i < nRuns; i++ )
+ {
+ Run run = t.runs[i + startingRun];
+ GlyphVector gv = run.glyphVector;
+ Font font = run.font;
+ // 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) ? gv.getNumGlyphs() :
+ 1 + t.charIndices[endIndex - 1][1] - beginGlyphIndex;
+
+ int[] codes = gv.getGlyphCodes(beginGlyphIndex, numEntries, null);
+ gv = font.createGlyphVector(frc, codes);
+ runs[i] = new Run(gv, font, run.runStart - startIndex,
+ run.runEnd - startIndex);
+ }
+ runs[nRuns - 1].runEnd = endIndex - 1;
+
+ setCharIndices();
+ setupMappings();
+ determineWhiteSpace();
+ layoutRuns();
+ }
+
+ private void setCharIndices()
+ {
+ charIndices = new int[ getCharacterCount() ][2];
+ int i = 0;
+ int currentChar = 0;
+ for(int run = 0; run < runs.length; run++)
+ {
+ currentChar = -1;
+ Run current = runs[run];
+ GlyphVector gv = current.glyphVector;
+ for( int gi = 0; gi < gv.getNumGlyphs(); gi++)
+ {
+ if( gv.getGlyphCharIndex( gi ) != currentChar )
+ {
+ charIndices[ i ][0] = run;
+ charIndices[ i ][1] = gi;
+ currentChar = gv.getGlyphCharIndex( gi );
+ i++;
+ }
+ }
+ }
+ }
+
+ /**
+ * Initializes the logicalToVisual and visualToLogial maps.
+ */
+ private void setupMappings()
+ {
+ int numChars = getCharacterCount();
+ logicalToVisual = new int[numChars];
+ visualToLogical = new int[numChars];
+ int lIndex = 0;
+ int vIndex = 0;
+ // We scan the runs in visual order and set the mappings accordingly.
+ for (int i = 0; i < runs.length; i++)
+ {
+ Run run = runs[i];
+ if (run.isLeftToRight())
+ {
+ for (lIndex = run.runStart; lIndex < run.runEnd; lIndex++)
+ {
+ logicalToVisual[lIndex] = vIndex;
+ visualToLogical[vIndex] = lIndex;
+ vIndex++;
+ }
+ }
+ else
+ {
+ for (lIndex = run.runEnd - 1; lIndex >= run.runStart; lIndex--)
+ {
+ logicalToVisual[lIndex] = vIndex;
+ visualToLogical[vIndex] = lIndex;
+ vIndex++;
+ }
+ }
+ }
+ }
+
+ private static String getText(AttributedCharacterIterator iter)
+ {
+ CPStringBuilder sb = new CPStringBuilder();
+ 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;
+ }
+
+ /**
+ * Scan the character run for the first strongly directional character,
+ * which in turn defines the base directionality of the whole layout.
+ */
+ private void getStringProperties()
+ {
+ boolean gotDirection = false;
+ int i = offset;
+ int endOffs = offset + length;
+ leftToRight = true;
+ while( i < endOffs && !gotDirection )
+ switch( Character.getDirectionality(string[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;
+ }
+ determineWhiteSpace();
+ }
+
+ private void determineWhiteSpace()
+ {
+ // Determine if there's whitespace in the thing.
+ // Ignore trailing chars.
+ int i = offset + length - 1;
+ hasWhitespace = false;
+ while( i >= offset && Character.isWhitespace( string[i] ) )
+ i--;
+ // Check the remaining chars
+ while( i >= offset )
+ if( Character.isWhitespace( string[i--] ) )
+ hasWhitespace = true;
+ }
+
+ protected Object clone ()
+ {
+ return new TextLayout( this, 0, length);
+ }
+
+ public void draw (Graphics2D g2, float x, float y)
+ {
+ for(int i = 0; i < runs.length; i++)
+ {
+ Run run = runs[i];
+ GlyphVector gv = run.glyphVector;
+ g2.drawGlyphVector(gv, x, y);
+ Rectangle2D r = gv.getLogicalBounds();
+ x += r.getWidth();
+ }
+ }
+
+ public boolean equals (Object obj)
+ {
+ if( !( obj instanceof TextLayout) )
+ return false;
+
+ return equals( (TextLayout) obj );
+ }
+
+ public boolean equals (TextLayout tl)
+ {
+ 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 ()
+ {
+ if (totalAdvance == -1F)
+ {
+ totalAdvance = 0f;
+ for(int i = 0; i < runs.length; i++)
+ {
+ Run run = runs[i];
+ GlyphVector gv = run.glyphVector;
+ totalAdvance += gv.getLogicalBounds().getWidth();
+ }
+ }
+ return totalAdvance;
+ }
+
+ public float getAscent ()
+ {
+ return lm.getAscent();
+ }
+
+ public byte getBaseline ()
+ {
+ return (byte)lm.getBaselineIndex();
+ }
+
+ public float[] getBaselineOffsets ()
+ {
+ return lm.getBaselineOffsets();
+ }
+
+ public Shape getBlackBoxBounds (int firstEndpoint, int secondEndpoint)
+ {
+ if( secondEndpoint - firstEndpoint <= 0 )
+ return new Rectangle2D.Float(); // Hmm?
+
+ if( firstEndpoint < 0 || secondEndpoint > getCharacterCount())
+ return new Rectangle2D.Float();
+
+ GeneralPath gp = new GeneralPath();
+
+ int ri = charIndices[ firstEndpoint ][0];
+ int gi = charIndices[ firstEndpoint ][1];
+
+ double advance = 0;
+
+ for( int i = 0; i < ri; i++ )
+ {
+ Run run = runs[i];
+ GlyphVector gv = run.glyphVector;
+ advance += gv.getLogicalBounds().getWidth();
+ }
+
+ for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ )
+ {
+ Run run = runs[i];
+ GlyphVector gv = run.glyphVector;
+ int dg;
+ if( i == charIndices[ secondEndpoint - 1 ][0] )
+ dg = charIndices[ secondEndpoint - 1][1];
+ else
+ dg = gv.getNumGlyphs() - 1;
+
+ for( int j = 0; j <= dg; j++ )
+ {
+ Rectangle2D r2 = (gv.getGlyphVisualBounds( j )).
+ getBounds2D();
+ Point2D p = gv.getGlyphPosition( j );
+ r2.setRect( advance + r2.getX(), r2.getY(),
+ r2.getWidth(), r2.getHeight() );
+ gp.append(r2, false);
+ }
+
+ advance += gv.getLogicalBounds().getWidth();
+ }
+ return gp;
+ }
+
+ public Rectangle2D getBounds()
+ {
+ if( boundsCache == null )
+ boundsCache = getOutline(new AffineTransform()).getBounds();
+ return boundsCache;
+ }
+
+ public float[] getCaretInfo (TextHitInfo hit)
+ {
+ return getCaretInfo(hit, getNaturalBounds());
+ }
+
+ public float[] getCaretInfo (TextHitInfo hit, Rectangle2D bounds)
+ {
+ float[] info = new float[2];
+ int index = hit.getCharIndex();
+ boolean leading = hit.isLeadingEdge();
+ // For the boundary cases we return the boundary runs.
+ Run run;
+
+ if (index >= length)
+ {
+ info[0] = getAdvance();
+ info[1] = 0;
+ }
+ else
+ {
+ if (index < 0)
+ {
+ run = runs[0];
+ index = 0;
+ leading = true;
+ }
+ else
+ run = findRunAtIndex(index);
+
+ int glyphIndex = index - run.runStart;
+ Shape glyphBounds = run.glyphVector.getGlyphLogicalBounds(glyphIndex);
+ Rectangle2D glyphRect = glyphBounds.getBounds2D();
+ if (isVertical())
+ {
+ if (leading)
+ info[0] = (float) glyphRect.getMinY();
+ else
+ info[0] = (float) glyphRect.getMaxY();
+ }
+ else
+ {
+ if (leading)
+ info[0] = (float) glyphRect.getMinX();
+ else
+ info[0] = (float) glyphRect.getMaxX();
+ }
+ info[0] += run.location;
+ info[1] = run.font.getItalicAngle();
+ }
+ return info;
+ }
+
+ public Shape getCaretShape(TextHitInfo hit)
+ {
+ return getCaretShape(hit, getBounds());
+ }
+
+ public Shape getCaretShape(TextHitInfo hit, Rectangle2D bounds)
+ {
+ // TODO: Handle vertical shapes somehow.
+ float[] info = getCaretInfo(hit);
+ float x1 = info[0];
+ float y1 = (float) bounds.getMinY();
+ float x2 = info[0];
+ float y2 = (float) bounds.getMaxY();
+ if (info[1] != 0)
+ {
+ // Shift x1 and x2 according to the slope.
+ x1 -= y1 * info[1];
+ x2 -= y2 * info[1];
+ }
+ GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD, 2);
+ path.moveTo(x1, y1);
+ path.lineTo(x2, y2);
+ return path;
+ }
+
+ public Shape[] getCaretShapes(int offset)
+ {
+ return getCaretShapes(offset, getNaturalBounds());
+ }
+
+ public Shape[] getCaretShapes(int offset, Rectangle2D bounds)
+ {
+ return getCaretShapes(offset, bounds, DEFAULT_CARET_POLICY);
+ }
+
+ public Shape[] getCaretShapes(int offset, Rectangle2D bounds,
+ CaretPolicy policy)
+ {
+ // The RI returns a 2-size array even when there's only one
+ // shape in it.
+ Shape[] carets = new Shape[2];
+ TextHitInfo hit1 = TextHitInfo.afterOffset(offset);
+ int caretHit1 = hitToCaret(hit1);
+ TextHitInfo hit2 = hit1.getOtherHit();
+ int caretHit2 = hitToCaret(hit2);
+ if (caretHit1 == caretHit2)
+ {
+ carets[0] = getCaretShape(hit1);
+ carets[1] = null; // The RI returns null in this seldom case.
+ }
+ else
+ {
+ Shape caret1 = getCaretShape(hit1);
+ Shape caret2 = getCaretShape(hit2);
+ TextHitInfo strong = policy.getStrongCaret(hit1, hit2, this);
+ if (strong == hit1)
+ {
+ carets[0] = caret1;
+ carets[1] = caret2;
+ }
+ else
+ {
+ carets[0] = caret2;
+ carets[1] = caret1;
+ }
+ }
+ return carets;
+ }
+
+ public int getCharacterCount ()
+ {
+ return length;
+ }
+
+ public byte getCharacterLevel (int index)
+ {
+ byte level;
+ if( bidi == null )
+ level = 0;
+ else
+ level = (byte) bidi.getLevelAt(index);
+ return level;
+ }
+
+ public float getDescent ()
+ {
+ return lm.getDescent();
+ }
+
+ public TextLayout getJustifiedLayout (float justificationWidth)
+ {
+ TextLayout newLayout = (TextLayout)clone();
+
+ if( hasWhitespace )
+ newLayout.handleJustify( justificationWidth );
+
+ return newLayout;
+ }
+
+ public float getLeading ()
+ {
+ return lm.getLeading();
+ }
+
+ public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint)
+ {
+ return getLogicalHighlightShape( firstEndpoint, secondEndpoint,
+ getBounds() );
+ }
+
+ public Shape getLogicalHighlightShape (int firstEndpoint, int secondEndpoint,
+ Rectangle2D bounds)
+ {
+ if( secondEndpoint - firstEndpoint <= 0 )
+ return new Rectangle2D.Float(); // Hmm?
+
+ if( firstEndpoint < 0 || secondEndpoint > getCharacterCount())
+ return new Rectangle2D.Float();
+
+ Rectangle2D r = null;
+ int ri = charIndices[ firstEndpoint ][0];
+ int gi = charIndices[ firstEndpoint ][1];
+
+ double advance = 0;
+
+ for( int i = 0; i < ri; i++ )
+ advance += runs[i].glyphVector.getLogicalBounds().getWidth();
+
+ for( int i = ri; i <= charIndices[ secondEndpoint - 1 ][0]; i++ )
+ {
+ Run run = runs[i];
+ GlyphVector gv = run.glyphVector;
+ int dg; // last index in this run to use.
+ if( i == charIndices[ secondEndpoint - 1 ][0] )
+ dg = charIndices[ secondEndpoint - 1][1];
+ else
+ dg = gv.getNumGlyphs() - 1;
+
+ for(; gi <= dg; gi++ )
+ {
+ Rectangle2D r2 = (gv.getGlyphLogicalBounds( gi )).
+ getBounds2D();
+ if( r == null )
+ r = r2;
+ else
+ r = r.createUnion(r2);
+ }
+ gi = 0; // reset glyph index into run for next run.
+
+ advance += gv.getLogicalBounds().getWidth();
+ }
+
+ return r;
+ }
+
+ public int[] getLogicalRangesForVisualSelection (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint)
+ {
+ // Check parameters.
+ checkHitInfo(firstEndpoint);
+ checkHitInfo(secondEndpoint);
+
+ // Convert to visual and order correctly.
+ int start = hitToCaret(firstEndpoint);
+ int end = hitToCaret(secondEndpoint);
+ if (start > end)
+ {
+ // Swap start and end so that end >= start.
+ int temp = start;
+ start = end;
+ end = temp;
+ }
+
+ // Now walk through the visual indices and mark the included pieces.
+ boolean[] include = new boolean[length];
+ for (int i = start; i < end; i++)
+ {
+ include[visualToLogical[i]] = true;
+ }
+
+ // Count included runs.
+ int numRuns = 0;
+ boolean in = false;
+ for (int i = 0; i < length; i++)
+ {
+ if (include[i] != in) // At each run in/out point we toggle the in var.
+ {
+ in = ! in;
+ if (in) // At each run start we count up.
+ numRuns++;
+ }
+ }
+
+ // Put together the ranges array.
+ int[] ranges = new int[numRuns * 2];
+ int index = 0;
+ in = false;
+ for (int i = 0; i < length; i++)
+ {
+ if (include[i] != in)
+ {
+ ranges[index] = i;
+ index++;
+ in = ! in;
+ }
+ }
+ // If the last run ends at the very end, include that last bit too.
+ if (in)
+ ranges[index] = length;
+
+ return ranges;
+ }
+
+ public TextHitInfo getNextLeftHit(int offset)
+ {
+ return getNextLeftHit(offset, DEFAULT_CARET_POLICY);
+ }
+
+ public TextHitInfo getNextLeftHit(int offset, CaretPolicy policy)
+ {
+ if (policy == null)
+ throw new IllegalArgumentException("Null policy not allowed");
+ if (offset < 0 || offset > length)
+ throw new IllegalArgumentException("Offset out of bounds");
+
+ TextHitInfo hit1 = TextHitInfo.afterOffset(offset);
+ TextHitInfo hit2 = hit1.getOtherHit();
+
+ TextHitInfo strong = policy.getStrongCaret(hit1, hit2, this);
+ TextHitInfo next = getNextLeftHit(strong);
+ TextHitInfo ret = null;
+ if (next != null)
+ {
+ TextHitInfo next2 = getVisualOtherHit(next);
+ ret = policy.getStrongCaret(next2, next, this);
+ }
+ return ret;
+ }
+
+ public TextHitInfo getNextLeftHit (TextHitInfo hit)
+ {
+ checkHitInfo(hit);
+ int index = hitToCaret(hit);
+ TextHitInfo next = null;
+ if (index != 0)
+ {
+ index--;
+ next = caretToHit(index);
+ }
+ return next;
+ }
+
+ public TextHitInfo getNextRightHit(int offset)
+ {
+ return getNextRightHit(offset, DEFAULT_CARET_POLICY);
+ }
+
+ public TextHitInfo getNextRightHit(int offset, CaretPolicy policy)
+ {
+ if (policy == null)
+ throw new IllegalArgumentException("Null policy not allowed");
+ if (offset < 0 || offset > length)
+ throw new IllegalArgumentException("Offset out of bounds");
+
+ TextHitInfo hit1 = TextHitInfo.afterOffset(offset);
+ TextHitInfo hit2 = hit1.getOtherHit();
+
+ TextHitInfo next = getNextRightHit(policy.getStrongCaret(hit1, hit2, this));
+ TextHitInfo ret = null;
+ if (next != null)
+ {
+ TextHitInfo next2 = getVisualOtherHit(next);
+ ret = policy.getStrongCaret(next2, next, this);
+ }
+ return ret;
+ }
+
+ public TextHitInfo getNextRightHit(TextHitInfo hit)
+ {
+ checkHitInfo(hit);
+ int index = hitToCaret(hit);
+ TextHitInfo next = null;
+ if (index < length)
+ {
+ index++;
+ next = caretToHit(index);
+ }
+ return next;
+ }
+
+ public Shape getOutline (AffineTransform tx)
+ {
+ float x = 0f;
+ GeneralPath gp = new GeneralPath();
+ for(int i = 0; i < runs.length; i++)
+ {
+ GlyphVector gv = runs[i].glyphVector;
+ gp.append( gv.getOutline( x, 0f ), false );
+ Rectangle2D r = gv.getLogicalBounds();
+ x += r.getWidth();
+ }
+ if( tx != null )
+ gp.transform( tx );
+ return gp;
+ }
+
+ public float getVisibleAdvance ()
+ {
+ float totalAdvance = 0f;
+
+ if( runs.length <= 0 )
+ return 0f;
+
+ // No trailing whitespace
+ if( !Character.isWhitespace( string[offset + 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].glyphVector.getLogicalBounds().getWidth();
+
+ int lastRun = runs[runs.length - 1].runStart;
+ int j = length - 1;
+ while( j >= lastRun && Character.isWhitespace( string[j] ) ) j--;
+
+ if( j < lastRun )
+ return totalAdvance; // entire last run is whitespace
+
+ int lastNonWSChar = j - lastRun;
+ j = 0;
+ while( runs[ runs.length - 1 ].glyphVector.getGlyphCharIndex( j )
+ <= lastNonWSChar )
+ {
+ totalAdvance += runs[ runs.length - 1 ].glyphVector
+ .getGlyphLogicalBounds( j )
+ .getBounds2D().getWidth();
+ j ++;
+ }
+
+ return totalAdvance;
+ }
+
+ public Shape getVisualHighlightShape (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint)
+ {
+ return getVisualHighlightShape( firstEndpoint, secondEndpoint,
+ getBounds() );
+ }
+
+ public Shape getVisualHighlightShape (TextHitInfo firstEndpoint,
+ TextHitInfo secondEndpoint,
+ Rectangle2D bounds)
+ {
+ GeneralPath path = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+ Shape caret1 = getCaretShape(firstEndpoint, bounds);
+ path.append(caret1, false);
+ Shape caret2 = getCaretShape(secondEndpoint, bounds);
+ path.append(caret2, false);
+ // Append left (top) bounds to selection if necessary.
+ int c1 = hitToCaret(firstEndpoint);
+ int c2 = hitToCaret(secondEndpoint);
+ if (c1 == 0 || c2 == 0)
+ {
+ path.append(left(bounds), false);
+ }
+ // Append right (bottom) bounds if necessary.
+ if (c1 == length || c2 == length)
+ {
+ path.append(right(bounds), false);
+ }
+ return path.getBounds2D();
+ }
+
+ /**
+ * Returns the shape that makes up the left (top) edge of this text layout.
+ *
+ * @param b the bounds
+ *
+ * @return the shape that makes up the left (top) edge of this text layout
+ */
+ private Shape left(Rectangle2D b)
+ {
+ GeneralPath left = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+ left.append(getCaretShape(TextHitInfo.beforeOffset(0)), false);
+ if (isVertical())
+ {
+ float y = (float) b.getMinY();
+ left.append(new Line2D.Float((float) b.getMinX(), y,
+ (float) b.getMaxX(), y), false);
+ }
+ else
+ {
+ float x = (float) b.getMinX();
+ left.append(new Line2D.Float(x, (float) b.getMinY(),
+ x, (float) b.getMaxY()), false);
+ }
+ return left.getBounds2D();
+ }
+
+ /**
+ * Returns the shape that makes up the right (bottom) edge of this text
+ * layout.
+ *
+ * @param b the bounds
+ *
+ * @return the shape that makes up the right (bottom) edge of this text
+ * layout
+ */
+ private Shape right(Rectangle2D b)
+ {
+ GeneralPath right = new GeneralPath(GeneralPath.WIND_EVEN_ODD);
+ right.append(getCaretShape(TextHitInfo.afterOffset(length)), false);
+ if (isVertical())
+ {
+ float y = (float) b.getMaxY();
+ right.append(new Line2D.Float((float) b.getMinX(), y,
+ (float) b.getMaxX(), y), false);
+ }
+ else
+ {
+ float x = (float) b.getMaxX();
+ right.append(new Line2D.Float(x, (float) b.getMinY(),
+ x, (float) b.getMaxY()), false);
+ }
+ return right.getBounds2D();
+ }
+
+ public TextHitInfo getVisualOtherHit (TextHitInfo hit)
+ {
+ checkHitInfo(hit);
+ int hitIndex = hit.getCharIndex();
+
+ int index;
+ boolean leading;
+ if (hitIndex == -1 || hitIndex == length)
+ {
+ // Boundary case.
+ int visual;
+ if (isLeftToRight() == (hitIndex == -1))
+ visual = 0;
+ else
+ visual = length - 1;
+ index = visualToLogical[visual];
+ if (isLeftToRight() == (hitIndex == -1))
+ leading = isCharacterLTR(index); // LTR.
+ else
+ leading = ! isCharacterLTR(index); // RTL.
+ }
+ else
+ {
+ // Normal case.
+ int visual = logicalToVisual[hitIndex];
+ boolean b;
+ if (isCharacterLTR(hitIndex) == hit.isLeadingEdge())
+ {
+ visual--;
+ b = false;
+ }
+ else
+ {
+ visual++;
+ b = true;
+ }
+ if (visual >= 0 && visual < length)
+ {
+ index = visualToLogical[visual];
+ leading = b == isLeftToRight();
+ }
+ else
+ {
+ index = b == isLeftToRight() ? length : -1;
+ leading = index == length;
+ }
+ }
+ return leading ? TextHitInfo.leading(index) : TextHitInfo.trailing(index);
+ }
+
+ /**
+ * This is a protected method of a <code>final</code> class, meaning
+ * it exists only to taunt you.
+ */
+ protected void handleJustify (float 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 = offset + length - 1;
+ while( Character.isWhitespace( string[lastNWS] ) ) lastNWS--;
+
+ // locations of the glyphs.
+ int[] wsglyphs = new int[length * 10];
+ for(int run = 0; run < runs.length; run++ )
+ {
+ Run current = runs[run];
+ for(int i = 0; i < current.glyphVector.getNumGlyphs(); i++ )
+ {
+ int cindex = current.runStart
+ + current.glyphVector.getGlyphCharIndex( i );
+ if( Character.isWhitespace( string[cindex] ) )
+ // && cindex < lastNWS )
+ {
+ wsglyphs[ nglyphs * 2 ] = run;
+ wsglyphs[ nglyphs * 2 + 1] = i;
+ nglyphs++;
+ }
+ }
+ }
+ 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++ )
+ {
+ Run current = runs[run];
+ for(int i = 0; i < current.glyphVector.getNumGlyphs(); i++ )
+ {
+ if( wsglyphs[ cws * 2 ] == run && wsglyphs[ cws * 2 + 1 ] == i )
+ {
+ cws++; // update 'current whitespace'
+ w += deltaW; // increment the shift
+ }
+ Point2D p = current.glyphVector.getGlyphPosition( i );
+ p.setLocation( p.getX() + w, p.getY() );
+ current.glyphVector.setGlyphPosition( i, p );
+ }
+ }
+ }
+
+ public TextHitInfo hitTestChar (float x, float y)
+ {
+ return hitTestChar(x, y, getNaturalBounds());
+ }
+
+ /**
+ * Finds the character hit at the specified point. This 'clips' this
+ * text layout against the specified <code>bounds</code> rectangle. That
+ * means that in the case where a point is outside these bounds, this method
+ * returns the leading edge of the first character or the trailing edge of
+ * the last character.
+ *
+ * @param x the X location to test
+ * @param y the Y location to test
+ * @param bounds the bounds to test against
+ *
+ * @return the character hit at the specified point
+ */
+ public TextHitInfo hitTestChar (float x, float y, Rectangle2D bounds)
+ {
+ // Check bounds.
+ if (isVertical())
+ {
+ if (y < bounds.getMinY())
+ return TextHitInfo.leading(0);
+ else if (y > bounds.getMaxY())
+ return TextHitInfo.trailing(getCharacterCount() - 1);
+ }
+ else
+ {
+ if (x < bounds.getMinX())
+ return TextHitInfo.leading(0);
+ else if (x > bounds.getMaxX())
+ return TextHitInfo.trailing(getCharacterCount() - 1);
+ }
+
+ TextHitInfo hitInfo = null;
+ if (isVertical())
+ {
+ // Search for the run at the location.
+ // TODO: Perform binary search for maximum efficiency. However, we
+ // need the run location laid out statically to do that.
+ int numRuns = runs.length;
+ Run hitRun = null;
+ for (int i = 0; i < numRuns && hitRun == null; i++)
+ {
+ Run run = runs[i];
+ Rectangle2D lBounds = run.glyphVector.getLogicalBounds();
+ if (lBounds.getMinY() + run.location <= y
+ && lBounds.getMaxY() + run.location >= y)
+ hitRun = run;
+ }
+ // Now we have (hopefully) found a run that hits. Now find the
+ // right character.
+ if (hitRun != null)
+ {
+ GlyphVector gv = hitRun.glyphVector;
+ for (int i = hitRun.runStart;
+ i < hitRun.runEnd && hitInfo == null; i++)
+ {
+ int gi = i - hitRun.runStart;
+ Rectangle2D lBounds = gv.getGlyphLogicalBounds(gi)
+ .getBounds2D();
+ if (lBounds.getMinY() + hitRun.location <= y
+ && lBounds.getMaxY() + hitRun.location >= y)
+ {
+ // Found hit. Now check if we are leading or trailing.
+ boolean leading = true;
+ if (lBounds.getCenterY() + hitRun.location <= y)
+ leading = false;
+ hitInfo = leading ? TextHitInfo.leading(i)
+ : TextHitInfo.trailing(i);
+ }
+ }
+ }
+ }
+ else
+ {
+ // Search for the run at the location.
+ // TODO: Perform binary search for maximum efficiency. However, we
+ // need the run location laid out statically to do that.
+ int numRuns = runs.length;
+ Run hitRun = null;
+ for (int i = 0; i < numRuns && hitRun == null; i++)
+ {
+ Run run = runs[i];
+ Rectangle2D lBounds = run.glyphVector.getLogicalBounds();
+ if (lBounds.getMinX() + run.location <= x
+ && lBounds.getMaxX() + run.location >= x)
+ hitRun = run;
+ }
+ // Now we have (hopefully) found a run that hits. Now find the
+ // right character.
+ if (hitRun != null)
+ {
+ GlyphVector gv = hitRun.glyphVector;
+ for (int i = hitRun.runStart;
+ i < hitRun.runEnd && hitInfo == null; i++)
+ {
+ int gi = i - hitRun.runStart;
+ Rectangle2D lBounds = gv.getGlyphLogicalBounds(gi)
+ .getBounds2D();
+ if (lBounds.getMinX() + hitRun.location <= x
+ && lBounds.getMaxX() + hitRun.location >= x)
+ {
+ // Found hit. Now check if we are leading or trailing.
+ boolean leading = true;
+ if (lBounds.getCenterX() + hitRun.location <= x)
+ leading = false;
+ hitInfo = leading ? TextHitInfo.leading(i)
+ : TextHitInfo.trailing(i);
+ }
+ }
+ }
+ }
+ return hitInfo;
+ }
+
+ public boolean isLeftToRight ()
+ {
+ return leftToRight;
+ }
+
+ public boolean isVertical ()
+ {
+ return false; // FIXME: How do you create a vertical layout?
+ }
+
+ public int hashCode ()
+ {
+ // This is implemented in sync to equals().
+ if (hash == 0 && runs.length > 0)
+ {
+ hash = runs.length;
+ for (int i = 0; i < runs.length; i++)
+ hash ^= runs[i].glyphVector.hashCode();
+ }
+ return hash;
+ }
+
+ public String toString ()
+ {
+ return "TextLayout [string:"+ new String(string, offset, length)
+ +" Rendercontext:"+
+ frc+"]";
+ }
+
+ /**
+ * Returns the natural bounds of that text layout. This is made up
+ * of the ascent plus descent and the text advance.
+ *
+ * @return the natural bounds of that text layout
+ */
+ private Rectangle2D getNaturalBounds()
+ {
+ if (naturalBounds == null)
+ naturalBounds = new Rectangle2D.Float(0.0F, -getAscent(), getAdvance(),
+ getAscent() + getDescent());
+ return naturalBounds;
+ }
+
+ private void checkHitInfo(TextHitInfo hit)
+ {
+ if (hit == null)
+ throw new IllegalArgumentException("Null hit info not allowed");
+ int index = hit.getInsertionIndex();
+ if (index < 0 || index > length)
+ throw new IllegalArgumentException("Hit index out of range");
+ }
+
+ private int hitToCaret(TextHitInfo hit)
+ {
+ int index = hit.getCharIndex();
+ int ret;
+ if (index < 0)
+ ret = isLeftToRight() ? 0 : length;
+ else if (index >= length)
+ ret = isLeftToRight() ? length : 0;
+ else
+ {
+ ret = logicalToVisual[index];
+ if (hit.isLeadingEdge() != isCharacterLTR(index))
+ ret++;
+ }
+ return ret;
+ }
+
+ private TextHitInfo caretToHit(int index)
+ {
+ TextHitInfo hit;
+ if (index == 0 || index == length)
+ {
+ if ((index == length) == isLeftToRight())
+ hit = TextHitInfo.leading(length);
+ else
+ hit = TextHitInfo.trailing(-1);
+ }
+ else
+ {
+ int logical = visualToLogical[index];
+ boolean leading = isCharacterLTR(logical); // LTR.
+ hit = leading ? TextHitInfo.leading(logical)
+ : TextHitInfo.trailing(logical);
+ }
+ return hit;
+ }
+
+ private boolean isCharacterLTR(int index)
+ {
+ byte level = getCharacterLevel(index);
+ return (level & 1) == 0;
+ }
+
+ /**
+ * Finds the run that holds the specified (logical) character index. This
+ * returns <code>null</code> when the index is not inside the range.
+ *
+ * @param index the index of the character to find
+ *
+ * @return the run that holds the specified character
+ */
+ private Run findRunAtIndex(int index)
+ {
+ Run found = null;
+ // TODO: Can we do better than linear searching here?
+ for (int i = 0; i < runs.length && found == null; i++)
+ {
+ Run run = runs[i];
+ if (run.runStart <= index && run.runEnd > index)
+ found = run;
+ }
+ return found;
+ }
+
+ /**
+ * Computes the layout locations for each run.
+ */
+ private void layoutRuns()
+ {
+ float loc = 0.0F;
+ float lastWidth = 0.0F;
+ for (int i = 0; i < runs.length; i++)
+ {
+ runs[i].location = loc;
+ Rectangle2D bounds = runs[i].glyphVector.getLogicalBounds();
+ loc += isVertical() ? bounds.getHeight() : bounds.getWidth();
+ }
+ }
+
+ /**
+ * Inner class describing a caret policy
+ */
+ public static class CaretPolicy
+ {
+ public CaretPolicy()
+ {
+ }
+
+ public TextHitInfo getStrongCaret(TextHitInfo hit1,
+ TextHitInfo hit2,
+ TextLayout layout)
+ {
+ byte l1 = layout.getCharacterLevel(hit1.getCharIndex());
+ byte l2 = layout.getCharacterLevel(hit2.getCharIndex());
+ TextHitInfo strong;
+ if (l1 == l2)
+ {
+ if (hit2.isLeadingEdge() && ! hit1.isLeadingEdge())
+ strong = hit2;
+ else
+ strong = hit1;
+ }
+ else
+ {
+ if (l1 < l2)
+ strong = hit1;
+ else
+ strong = hit2;
+ }
+ return strong;
+ }
+ }
+}
diff --git a/libjava/classpath/java/awt/font/TextMeasurer.java b/libjava/classpath/java/awt/font/TextMeasurer.java
new file mode 100644
index 000000000..e443e8bc7
--- /dev/null
+++ b/libjava/classpath/java/awt/font/TextMeasurer.java
@@ -0,0 +1,190 @@
+/* TextMeasurer.java
+ Copyright (C) 2006 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.text.AttributedCharacterIterator;
+import java.awt.Shape;
+
+/**
+ * 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 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.text = text;
+ this.frc = frc;
+ totalLayout = new TextLayout( text, frc );
+ numChars = totalLayout.getCharacterCount();
+ }
+
+ /**
+ * Clones the TextMeasurer object
+ */
+ protected Object clone ()
+ {
+ 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)
+ {
+ totalLayout = new TextLayout(newParagraph, frc);
+ if( deletePos < 0 || deletePos > totalLayout.getCharacterCount() )
+ throw new NullPointerException("Invalid deletePos:"+deletePos);
+ numChars = totalLayout.getCharacterCount();
+ text = newParagraph;
+ }
+
+ /**
+ * 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)
+ {
+ totalLayout = new TextLayout(newParagraph, frc);
+ if( insertPos < 0 || insertPos > totalLayout.getCharacterCount() )
+ throw new NullPointerException("Invalid insertPos:"+insertPos);
+ numChars = totalLayout.getCharacterCount();
+ text = newParagraph;
+ }
+
+ /***
+ * 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)
+ {
+ 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)
+ {
+ if( start >= limit )
+ throw new IllegalArgumentException("Start position must be < limit.");
+ 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;
+
+ 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;
+ }
+}
diff --git a/libjava/classpath/java/awt/font/TransformAttribute.java b/libjava/classpath/java/awt/font/TransformAttribute.java
new file mode 100644
index 000000000..56d15bb0b
--- /dev/null
+++ b/libjava/classpath/java/awt/font/TransformAttribute.java
@@ -0,0 +1,100 @@
+/* TransformAttribute.java --
+ Copyright (C) 2003, 2005 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. */
+
+
+package java.awt.font;
+
+import java.awt.geom.AffineTransform;
+import java.io.Serializable;
+
+/**
+ * This class provides a mechanism for using an {@link AffineTransform} as
+ * an <i>immutable</i> attribute (for example, in the
+ * {@link java.text.AttributedString} class). Any transform passed to
+ * this class is copied before being stored, and any transform handed out
+ * by this class is a copy of the stored transform. In this way, it is
+ * not possible to modify the stored transform.
+ *
+ * @author Michael Koch
+ */
+public final class TransformAttribute implements Serializable
+{
+ private static final long serialVersionUID = 3356247357827709530L;
+
+ private AffineTransform affineTransform;
+
+ /**
+ * Creates a new attribute that contains a copy of the given transform.
+ *
+ * @param transform the transform (<code>null</code> not permitted).
+ *
+ * @throws IllegalArgumentException if <code>transform</code> is
+ * <code>null</code>.
+ */
+ public TransformAttribute (AffineTransform transform)
+ {
+ if (transform == null)
+ {
+ throw new IllegalArgumentException("Null 'transform' not permitted.");
+ }
+ this.affineTransform = new AffineTransform (transform);
+ }
+
+ /**
+ * Returns a copy of the transform contained by this attribute.
+ *
+ * @return A copy of the transform.
+ */
+ public AffineTransform getTransform ()
+ {
+ return (AffineTransform) affineTransform.clone();
+ }
+
+ /**
+ * Returns <code>true</code> if the transform contained by this attribute is
+ * an identity transform, and <code>false</code> otherwise.
+ *
+ * @return <code>true</code> if the transform contained by this attribute is
+ * an identity transform, and <code>false</code> otherwise.
+ *
+ * @since 1.4
+ */
+ public boolean isIdentity ()
+ {
+ return (affineTransform == null ? false : affineTransform.isIdentity ());
+ }
+}
diff --git a/libjava/classpath/java/awt/font/package.html b/libjava/classpath/java/awt/font/package.html
new file mode 100644
index 000000000..8c3c61a40
--- /dev/null
+++ b/libjava/classpath/java/awt/font/package.html
@@ -0,0 +1,46 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
+<!-- package.html - describes classes in java.awt.font package.
+ Copyright (C) 2002 Free Software Foundation, Inc.
+
+This file is part of GNU Classpath.
+
+GNU Classpath is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2, or (at your option)
+any later version.
+
+GNU Classpath is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Classpath; see the file COPYING. If not, write to the
+Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+02110-1301 USA.
+
+Linking this library statically or dynamically with other modules is
+making a combined work based on this library. Thus, the terms and
+conditions of the GNU General Public License cover the whole
+combination.
+
+As a special exception, the copyright holders of this library give you
+permission to link this library with independent modules to produce an
+executable, regardless of the license terms of these independent
+modules, and to copy and distribute the resulting executable under
+terms of your choice, provided that you also meet, for each linked
+independent module, the terms and conditions of the license of that
+module. An independent module is a module which is not derived from
+or based on this library. If you modify this library, you may extend
+this exception to your version of the library, but you are not
+obligated to do so. If you do not wish to do so, delete this
+exception statement from your version. -->
+
+<html>
+<head><title>GNU Classpath - java.awt.font</title></head>
+
+<body>
+<p>Representations of different kind of characters and fonts.</p>
+
+</body>
+</html>