diff options
Diffstat (limited to 'awt/java/awt/font')
-rw-r--r-- | awt/java/awt/font/FontRenderContext.java | 178 | ||||
-rw-r--r-- | awt/java/awt/font/GlyphJustificationInfo.java | 197 | ||||
-rw-r--r-- | awt/java/awt/font/GlyphMetrics.java | 266 | ||||
-rw-r--r-- | awt/java/awt/font/GlyphVector.java | 403 | ||||
-rw-r--r-- | awt/java/awt/font/GraphicAttribute.java | 179 | ||||
-rw-r--r-- | awt/java/awt/font/ImageGraphicAttribute.java | 185 | ||||
-rw-r--r-- | awt/java/awt/font/LineBreakMeasurer.java | 238 | ||||
-rw-r--r-- | awt/java/awt/font/LineMetrics.java | 116 | ||||
-rw-r--r-- | awt/java/awt/font/MultipleMaster.java | 91 | ||||
-rw-r--r-- | awt/java/awt/font/OpenType.java | 418 | ||||
-rw-r--r-- | awt/java/awt/font/ShapeGraphicAttribute.java | 206 | ||||
-rw-r--r-- | awt/java/awt/font/TextHitInfo.java | 215 | ||||
-rw-r--r-- | awt/java/awt/font/TextLayout.java | 927 | ||||
-rw-r--r-- | awt/java/awt/font/TextMeasurer.java | 182 | ||||
-rw-r--r-- | awt/java/awt/font/TransformAttribute.java | 86 | ||||
-rw-r--r-- | awt/java/awt/font/package.html | 8 |
16 files changed, 3895 insertions, 0 deletions
diff --git a/awt/java/awt/font/FontRenderContext.java b/awt/java/awt/font/FontRenderContext.java new file mode 100644 index 0000000..d7de00f --- /dev/null +++ b/awt/java/awt/font/FontRenderContext.java @@ -0,0 +1,178 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ +package java.awt.font; + +import java.awt.geom.AffineTransform; + +/** + * The FontRenderContext class contains the information about text measurement. + * Anti-aliasing and fractional-metrics modes are defined by an application and + * affect the size of a character. + * + * @since Android 1.0 + */ +public class FontRenderContext { + + // Affine transform of this mode + /** + * The transform. + */ + private AffineTransform transform; + + // Is the anti-aliased mode used + /** + * The anti aliased. + */ + private boolean fAntiAliased; + + // Is the fractional metrics used + /** + * The fractional metrics. + */ + private boolean fFractionalMetrics; + + + /** + * Instantiates a new FontRenderContext object with the specified + * AffineTransform, anti-aliasing and fractional metrics flags. + * + * @param trans + * the AffineTransform. + * @param antiAliased + * the anti-aliasing flag. + * @param usesFractionalMetrics + * the fractional metrics flag. + */ + public FontRenderContext(AffineTransform trans, boolean antiAliased, + boolean usesFractionalMetrics) { + if (trans != null){ + transform = new AffineTransform(trans); + } + fAntiAliased = antiAliased; + fFractionalMetrics = usesFractionalMetrics; + } + + /** + * Instantiates a new FontRenderContext object. + */ + protected FontRenderContext() { + } + + /** + * Compares the specified Object with current FontRenderContext object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is equal to current + * FontRenderContext object. + */ + @Override + public boolean equals(Object obj) { + if (obj == this) { + return true; + } + + if (obj != null) { + try { + return equals((FontRenderContext) obj); + } catch (ClassCastException e) { + return false; + } + } + return false; + + } + + /** + * Gets the transform which is used for scaling typographical points to + * pixels in this FontRenderContext. + * + * @return the AffineTransform which is used for scaling typographical + * points to pixels in this FontRenderContext. + */ + public AffineTransform getTransform() { + if (transform != null){ + return new AffineTransform(transform); + } + return new AffineTransform(); + } + + /** + * Compares the specified FontRenderContext object with current + * FontRenderContext. + * + * @param frc + * the FontRenderContext object to be compared. + * @return true, if the specified FontRenderContext object is equal to + * current FontRenderContext. + */ + public boolean equals(FontRenderContext frc) { + if (this == frc){ + return true; + } + + if (frc == null){ + return false; + } + + if (!frc.getTransform().equals(this.getTransform()) && + !frc.isAntiAliased() == this.fAntiAliased && + !frc.usesFractionalMetrics() == this.fFractionalMetrics){ + return false; + } + return true; + } + + /** + * Returns true if the text fractional metrics are used in this + * FontRenderContext. + * + * @return true, if the text fractional metrics are used in this + * FontRenderContext, false otherwise. + */ + public boolean usesFractionalMetrics() { + return this.fFractionalMetrics; + } + + /** + * Returns true if anti-aliasing is used in this FontRenderContext. + * + * @return true, if is anti-aliasing is used in this FontRenderContext, + * false otherwise. + */ + public boolean isAntiAliased() { + return this.fAntiAliased; + } + + /** + * Returns hash code of the FontRenderContext object. + * + * @return the hash code of the FontRenderContext object. + */ + @Override + public int hashCode() { + return this.getTransform().hashCode() ^ + new Boolean(this.fFractionalMetrics).hashCode() ^ + new Boolean(this.fAntiAliased).hashCode(); + } + +} + diff --git a/awt/java/awt/font/GlyphJustificationInfo.java b/awt/java/awt/font/GlyphJustificationInfo.java new file mode 100644 index 0000000..b03de0a --- /dev/null +++ b/awt/java/awt/font/GlyphJustificationInfo.java @@ -0,0 +1,197 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GlyphJustificationInfo class provides information about the glyph's + * justification properties. There are four justification properties: weight, + * priority, absorb, and limit. + * <p> + * There are two sets of metrics: growing and shrinking. Growing metrics are + * used when the glyphs are to be spread apart to fit a larger width. Shrinking + * metrics are used when the glyphs are to be moved together to fit a smaller + * width. + * </p> + * + * @since Android 1.0 + */ +public final class GlyphJustificationInfo { + + /** + * The Constant PRIORITY_KASHIDA indicates the highest justification + * priority. + */ + public static final int PRIORITY_KASHIDA = 0; + + /** + * The Constant PRIORITY_WHITESPACE indicates the second highest + * justification priority. + */ + public static final int PRIORITY_WHITESPACE = 1; + + /** + * The Constant PRIORITY_INTERCHAR indicates the second lowest justification + * priority. + */ + public static final int PRIORITY_INTERCHAR = 2; + + /** + * The Constant PRIORITY_NONE indicates the lowest justification priority. + */ + public static final int PRIORITY_NONE = 3; + + /** + * The grow absorb flag indicates if this glyph absorbs all extra space at + * this and lower priority levels when it grows. + */ + public final boolean growAbsorb; + + /** + * The grow left limit value represents the maximum value by which the left + * side of this glyph grows. + */ + public final float growLeftLimit; + + /** + * The grow right limit value repesents the maximum value by which the right + * side of this glyph grows. + */ + public final float growRightLimit; + + /** + * The grow priority value represents the priority level of this glyph as it + * is growing. + */ + public final int growPriority; + + /** + * The shrink absorb fleg indicates this glyph absorbs all remaining + * shrinkage at this and lower priority levels as it shrinks. + */ + public final boolean shrinkAbsorb; + + /** + * The shrink left limit value represents the maximum value by which the + * left side of this glyph shrinks. + */ + public final float shrinkLeftLimit; + + /** + * The shrink right limit value represents the maximum value by which the + * right side of this glyph shrinks. + */ + public final float shrinkRightLimit; + + /** + * The shrink priority represents the glyth's priority level as it is + * shrinking. + */ + public final int shrinkPriority; + + /** + * The weight of the glyph. + */ + public final float weight; + + /** + * Instantiates a new GlyphJustificationInfo object which contains glyph's + * justification properties. + * + * @param weight + * the weight of glyph. + * @param growAbsorb + * indicates if this glyph contais all space at this priority and + * lower priority levels when it grows. + * @param growPriority + * indicates the priority level of this glyph when it grows. + * @param growLeftLimit + * indicates the maximum value of which the left side of this + * glyph can grow. + * @param growRightLimit + * the maximum value of which the right side of this glyph can + * grow. + * @param shrinkAbsorb + * indicates if this glyph contains all remaining shrinkage at + * this and lower priority levels when it shrinks. + * @param shrinkPriority + * indicates the glyph's priority level when it shrinks. + * @param shrinkLeftLimit + * indicates the maximum value of which the left side of this + * glyph can shrink. + * @param shrinkRightLimit + * indicates the maximum amount by which the right side of this + * glyph can shrink. + */ + public GlyphJustificationInfo(float weight, boolean growAbsorb, int growPriority, + float growLeftLimit, float growRightLimit, boolean shrinkAbsorb, int shrinkPriority, + float shrinkLeftLimit, float shrinkRightLimit) { + + if (weight < 0) { + // awt.19C=weight must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19C")); //$NON-NLS-1$ + } + this.weight = weight; + + if (growLeftLimit < 0) { + // awt.19D=growLeftLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19D")); //$NON-NLS-1$ + } + this.growLeftLimit = growLeftLimit; + + if (growRightLimit < 0) { + // awt.19E=growRightLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.19E")); //$NON-NLS-1$ + } + this.growRightLimit = growRightLimit; + + if ((shrinkPriority < 0) || (shrinkPriority > PRIORITY_NONE)) { + // awt.19F=incorrect value for shrinkPriority, more than + // PRIORITY_NONE or less than PRIORITY_KASHIDA value + throw new IllegalArgumentException(Messages.getString("awt.19F")); //$NON-NLS-1$ + } + this.shrinkPriority = shrinkPriority; + + if ((growPriority < 0) || (growPriority > PRIORITY_NONE)) { + // awt.200=incorrect value for growPriority, more than PRIORITY_NONE + // or less than PRIORITY_KASHIDA value + throw new IllegalArgumentException(Messages.getString("awt.200")); //$NON-NLS-1$ + } + this.growPriority = growPriority; + + if (shrinkLeftLimit < 0) { + // awt.201=shrinkLeftLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.201")); //$NON-NLS-1$ + } + this.shrinkLeftLimit = shrinkLeftLimit; + + if (shrinkRightLimit < 0) { + // awt.202=shrinkRightLimit must be a positive number + throw new IllegalArgumentException(Messages.getString("awt.202")); //$NON-NLS-1$ + } + this.shrinkRightLimit = shrinkRightLimit; + + this.shrinkAbsorb = shrinkAbsorb; + this.growAbsorb = growAbsorb; + } +} diff --git a/awt/java/awt/font/GlyphMetrics.java b/awt/java/awt/font/GlyphMetrics.java new file mode 100644 index 0000000..2871722 --- /dev/null +++ b/awt/java/awt/font/GlyphMetrics.java @@ -0,0 +1,266 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.geom.Rectangle2D; + +/** + * The GlyphMetrics class provides information about the size and shape of a + * single glyph. Each glyph has information to specify whether its baseline is + * horizontal or vertical as well as information on how it interacts with other + * characters in a text, given as one of the following types: STANDARD, + * LIGATURE, COMBINING, or COMPONENT. + * + * @since Android 1.0 + */ +public final class GlyphMetrics { + + // advance width of the glyph character cell + /** + * The advance x. + */ + private float advanceX; + + // advance height of the glyph character cell + /** + * The advance y. + */ + private float advanceY; + + // flag if the glyph horizontal + /** + * The horizontal. + */ + private boolean horizontal; + + // glyph type code + /** + * The glyph type. + */ + private byte glyphType; + + // bounding box for outline of the glyph + /** + * The bounds. + */ + private Rectangle2D.Float bounds; + + /** + * The Constant STANDARD indicates a glyph that represents a single + * character. + */ + public static final byte STANDARD = 0; + + /** + * The Constant LIGATURE indicates a glyph that represents multiple + * characters as a ligature. + */ + public static final byte LIGATURE = 1; + + /** + * The Constant COMBINING indicates a glyph which has no caret position + * between glyphs (for example umlaut). + */ + public static final byte COMBINING = 2; + + /** + * The Constant COMPONENT indicates a glyph with no corresponding character + * in the backing store. + */ + public static final byte COMPONENT = 3; + + /** + * The Constant WHITESPACE indicates a glyph without visual representation. + */ + public static final byte WHITESPACE = 4; + + /** + * Instantiates a new GlyphMetrics object with the specified parameters. + * + * @param horizontal + * specifies if metrics are for a horizontal baseline (true + * value), or a vertical baseline (false value). + * @param advanceX + * the X component of the glyph's advance. + * @param advanceY + * the Y component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. + */ + public GlyphMetrics(boolean horizontal, float advanceX, float advanceY, Rectangle2D bounds, + byte glyphType) { + this.horizontal = horizontal; + this.advanceX = advanceX; + this.advanceY = advanceY; + + this.bounds = new Rectangle2D.Float(); + this.bounds.setRect(bounds); + + this.glyphType = glyphType; + } + + /** + * Instantiates a new horizontal GlyphMetrics with the specified parameters. + * + * @param advanceX + * the X component of the glyph's advance. + * @param bounds + * the glyph's bounds. + * @param glyphType + * the glyph's type. + */ + public GlyphMetrics(float advanceX, Rectangle2D bounds, byte glyphType) { + this.advanceX = advanceX; + this.advanceY = 0; + + this.horizontal = true; + + this.bounds = new Rectangle2D.Float(); + this.bounds.setRect(bounds); + + this.glyphType = glyphType; + } + + /** + * Gets the glyph's bounds. + * + * @return glyph's bounds. + */ + public Rectangle2D getBounds2D() { + return (Rectangle2D.Float)this.bounds.clone(); + } + + /** + * Checks if this glyph is whitespace or not. + * + * @return true, if this glyph is whitespace, false otherwise. + */ + public boolean isWhitespace() { + return ((this.glyphType & 4) == WHITESPACE); + } + + /** + * Checks if this glyph is standard or not. + * + * @return true, if this glyph is standard, false otherwise. + */ + public boolean isStandard() { + return ((this.glyphType & 3) == STANDARD); + } + + /** + * Checks if this glyph is ligature or not. + * + * @return true, if this glyph is ligature, false otherwise. + */ + public boolean isLigature() { + return ((this.glyphType & 3) == LIGATURE); + } + + /** + * Checks if this glyph is component or not. + * + * @return true, if this glyph is component, false otherwise. + */ + public boolean isComponent() { + return ((this.glyphType & 3) == COMPONENT); + } + + /** + * Checks if this glyph is combining or not. + * + * @return true, if this glyph is combining, false otherwise. + */ + public boolean isCombining() { + return ((this.glyphType & 3) == COMBINING); + } + + /** + * Gets the glyph's type. + * + * @return the glyph's type. + */ + public int getType() { + return this.glyphType; + } + + /** + * Gets the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. + * + * @return the distance from the right (for horizontal) or bottom (for + * vertical) of the glyph bounds to the advance. + */ + public float getRSB() { + if (this.horizontal) { + return this.advanceX - this.bounds.x - (float)this.bounds.getWidth(); + } + return this.advanceY - this.bounds.y - (float)this.bounds.getHeight(); + } + + /** + * Gets the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. + * + * @return the distance from 0, 0 to the left (for horizontal) or top (for + * vertical) of the glyph bounds. + */ + public float getLSB() { + if (this.horizontal) { + return this.bounds.x; + } + return this.bounds.y; + } + + /** + * Gets the Y component of the glyph's advance. + * + * @return the Y component of the glyph's advance. + */ + public float getAdvanceY() { + return this.advanceY; + } + + /** + * Gets the X component of the glyph's advance. + * + * @return the X component of the glyph's advance. + */ + public float getAdvanceX() { + return this.advanceX; + } + + /** + * Gets the glyph's advance along the baseline. + * + * @return the glyph's advance. + */ + public float getAdvance() { + if (this.horizontal) { + return this.advanceX; + } + return this.advanceY; + } + +} diff --git a/awt/java/awt/font/GlyphVector.java b/awt/java/awt/font/GlyphVector.java new file mode 100644 index 0000000..a72b774 --- /dev/null +++ b/awt/java/awt/font/GlyphVector.java @@ -0,0 +1,403 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; +import java.awt.font.FontRenderContext; +import java.awt.font.GlyphJustificationInfo; +import java.awt.font.GlyphMetrics; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; + +/** + * The GlyphVector class contains a collection of glyphs with geometric + * information and each glyph's location. Each GlyphVector can be associated + * with only one Font. GlyphVector contains the following properties for each + * glyph: + * <ul> + * <li>the glyph position;</li> + * <li>the transform of the glyph;</li> + * <li>the metrics of the glyph in the context of the GlyphVector.</li> + * </ul> + * + * @since Android 1.0 + */ +public abstract class GlyphVector implements Cloneable { + + /** + * The Constant FLAG_HAS_TRANSFORMS indicates that this GlyphVector has + * per-glyph transforms. + */ + public static final int FLAG_HAS_TRANSFORMS = 1; + + /** + * The Constant FLAG_HAS_POSITION_ADJUSTMENTS indicates that the GlyphVector + * has per-glyph position adjustments. + */ + public static final int FLAG_HAS_POSITION_ADJUSTMENTS = 2; + + /** + * The Constant FLAG_RUN_RTL indicates that this GlyphVector has a right to + * left run direction. + */ + public static final int FLAG_RUN_RTL = 4; + + /** + * The Constant FLAG_COMPLEX_GLYPHS indicates that this GlyphVector has a + * complex glyph to char mapping. + */ + public static final int FLAG_COMPLEX_GLYPHS = 8; + + /** + * The Constant FLAG_MASK indicates a mask for supported flags from + * getLayoutFlags. + */ + public static final int FLAG_MASK = 15; // (|) mask of other flags + + /** + * Instantiates a new GlyphVector. + */ + public GlyphVector() { + } + + /** + * Gets the pixel bounds of the GlyphVector when rendered at the specified + * location with the specified FontRenderContext. + * + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. + * @return the pixel bounds + */ + public Rectangle getPixelBounds(FontRenderContext frc, float x, float y) { + // default implementation - integer Rectangle, that encloses visual + // bounds rectangle + Rectangle2D visualRect = getVisualBounds(); + + int minX = (int)Math.floor(visualRect.getMinX() + x); + int minY = (int)Math.floor(visualRect.getMinY() + y); + int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX; + int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY; + + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the pixel bounds of the glyph with the specified index in this + * GlyphVector which is rendered with the specified FontRenderContext at the + * specified location. + * + * @param index + * the glyph index in this GlyphVector. + * @param frc + * the FontRenderContext. + * @param x + * the X coordinate of the GlyphVector's location. + * @param y + * the Y coordinate of the GlyphVector's location. + * @return a Rectangle bounds. + */ + public Rectangle getGlyphPixelBounds(int index, FontRenderContext frc, float x, float y) { + Rectangle2D visualRect = getGlyphVisualBounds(index).getBounds2D(); + + int minX = (int)Math.floor(visualRect.getMinX() + x); + int minY = (int)Math.floor(visualRect.getMinY() + y); + int width = (int)Math.ceil(visualRect.getMaxX() + x) - minX; + int height = (int)Math.ceil(visualRect.getMaxY() + y) - minY; + + return new Rectangle(minX, minY, width, height); + } + + /** + * Gets the visual bounds of the GlyphVector. + * + * @return the visual bounds of the GlyphVector. + */ + public abstract Rectangle2D getVisualBounds(); + + /** + * Gets the logical bounds of the GlyphVector. + * + * @return the logical bounds of the GlyphVector. + */ + public abstract Rectangle2D getLogicalBounds(); + + /** + * Sets the position of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @param newPos + * the new position of the glyph at the specified glyphIndex. + */ + public abstract void setGlyphPosition(int glyphIndex, Point2D newPos); + + /** + * Gets the position of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the position of the specified glyph in this GlyphVector. + */ + public abstract Point2D getGlyphPosition(int glyphIndex); + + /** + * Sets the affine transform to a glyph with the specified index in this + * GlyphVector. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param trans + * the AffineTransform to be assigned to the specified glyph. + */ + public abstract void setGlyphTransform(int glyphIndex, AffineTransform trans); + + /** + * Gets the transform of the specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the new transform of the glyph. + */ + public abstract AffineTransform getGlyphTransform(int glyphIndex); + + /** + * Compares this GlyphVector with the specified GlyphVector objects. + * + * @param glyphVector + * the GlyphVector object to be compared. + * @return true, if this GlyphVector is equal to the specified GlyphVector + * object, false otherwise. + */ + public abstract boolean equals(GlyphVector glyphVector); + + /** + * Gets the metrics of the glyph with the specified index in this + * GlyphVector. + * + * @param glyphIndex + * index in this GlyphVector. + * @return the metrics of the glyph with the specified index in this + * GlyphVector. + */ + public abstract GlyphMetrics getGlyphMetrics(int glyphIndex); + + /** + * Gets the justification information of the glyph whose index is specified. + * + * @param glyphIndex + * the glyph index. + * @return the GlyphJustificationInfo for the specified glyph. + */ + public abstract GlyphJustificationInfo getGlyphJustificationInfo(int glyphIndex); + + /** + * Gets the FontRenderContext of this GlyphVector. + * + * @return the FontRenderContext of this GlyphVector. + */ + public abstract FontRenderContext getFontRenderContext(); + + /** + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector, translated a distance of x in the X + * direction and y in the Y direction. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @param x + * the distance in the X direction to translate the shape object + * before returning it. + * @param y + * the distance in the Y direction to translate the shape object + * before returning it. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. + */ + public Shape getGlyphOutline(int glyphIndex, float x, float y) { + Shape initialShape = getGlyphOutline(glyphIndex); + AffineTransform trans = AffineTransform.getTranslateInstance(x, y); + return trans.createTransformedShape(initialShape); + } + + /** + * Gets the visual bounds of the specified glyph in the GlyphVector. + * + * @param glyphIndex + * the glyph index in this GlyphVector. + * @return the glyph visual bounds of the glyph with the specified index in + * the GlyphVector. + */ + public abstract Shape getGlyphVisualBounds(int glyphIndex); + + /** + * Gets a Shape object which defines the visual representation of the + * specified glyph in this GlyphVector. + * + * @param glyphIndex + * the glyth index in this GlyphVector. + * @return a Shape object which represents the visual representation of the + * specified glyph in this GlyphVector - glyph outline. + */ + public abstract Shape getGlyphOutline(int glyphIndex); + + /** + * Gets the logical bounds of the specified glyph in the GlyphVector. + * + * @param glyphIndex + * the index in this GlyphVector of the glyph from which to + * retrieve its logical bounds + * @return the logical bounds of the specified glyph in the GlyphVector. + */ + public abstract Shape getGlyphLogicalBounds(int glyphIndex); + + /** + * Gets the visual representation of this GlyphVector rendered in x, y + * location as a Shape object. + * + * @param x + * the x coordinate of the GlyphVector. + * @param y + * the y coordinate of the GlyphVector. + * @return the visual representation of this GlyphVector as a Shape object. + */ + public abstract Shape getOutline(float x, float y); + + /** + * Gets the visual representation of this GlyphVector as a Shape object. + * + * @return the visual representation of this GlyphVector as a Shape object. + */ + public abstract Shape getOutline(); + + /** + * Gets the font of this GlyphVector. + * + * @return the font of this GlyphVector. + */ + public abstract Font getFont(); + + /** + * Gets an array of the glyph codes of the specified glyphs. + * + * @param beginGlyphIndex + * the index into this GlyphVector at which to start retrieving + * glyph codes. + * @param numEntries + * the number of glyph codes. + * @param codeReturn + * the array into which the resulting glyphcodes will be written. + * @return the array of the glyph codes. + */ + public abstract int[] getGlyphCodes(int beginGlyphIndex, int numEntries, int[] codeReturn); + + /** + * Gets an array of the character indices of the specified glyphs. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyph indices to return. + * @param codeReturn + * the array into which the resulting character indices will be + * written. + * @return an array of character indices for the specifies glyphs. + */ + public int[] getGlyphCharIndices(int beginGlyphIndex, int numEntries, int[] codeReturn) { + if (codeReturn == null) { + codeReturn = new int[numEntries]; + } + + for (int i = 0; i < numEntries; i++) { + codeReturn[i] = getGlyphCharIndex(i + beginGlyphIndex); + } + return codeReturn; + } + + /** + * Gets an array of the positions of the specified glyphs in this + * GlyphVector. + * + * @param beginGlyphIndex + * the index of the first glyph to return information for. + * @param numEntries + * the number of glyphs to return information for. + * @param positionReturn + * the array where the result will be stored. + * @return an array of glyph positions. + */ + public abstract float[] getGlyphPositions(int beginGlyphIndex, int numEntries, + float[] positionReturn); + + /** + * Gets the glyph code of the specified glyph. + * + * @param glyphIndex + * the index in this GlyphVector which corresponds to the glyph + * from which to retrieve the glyphcode. + * @return the glyphcode of the specified glyph. + */ + public abstract int getGlyphCode(int glyphIndex); + + /** + * Gets the first logical character's index of the specified glyph. + * + * @param glyphIndex + * the glyph index. + * @return the the first logical character's index. + */ + public int getGlyphCharIndex(int glyphIndex) { + // default implemetation one-to-one + return glyphIndex; + } + + /** + * Sets default layout to this GlyphVector. + */ + public abstract void performDefaultLayout(); + + /** + * Gets the number of glyphs in the GlyphVector. + * + * @return the number of glyphs in the GlyphVector. + */ + public abstract int getNumGlyphs(); + + /** + * Gets flags which describe the global state of the GlyphVector. The + * default implementation returns 0. + * + * @return the layout flags + */ + public int getLayoutFlags() { + // default implementation - returned value is 0 + return 0; + } + +} diff --git a/awt/java/awt/font/GraphicAttribute.java b/awt/java/awt/font/GraphicAttribute.java new file mode 100644 index 0000000..8480e0f --- /dev/null +++ b/awt/java/awt/font/GraphicAttribute.java @@ -0,0 +1,179 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The GraphicAttribute abstract class provides an opportunity to insert + * graphical elements in printed text. + * + * @since Android 1.0 + */ +public abstract class GraphicAttribute { + + /** + * The Constant TOP_ALIGNMENT indicates using the top line to calculate + * placement of graphics. + */ + public static final int TOP_ALIGNMENT = -1; + + /** + * The Constant BOTTOM_ALIGNMENT indicates using the bottom line to + * calculate placement of graphics. + */ + public static final int BOTTOM_ALIGNMENT = -2; + + /** + * The Constant ROMAN_BASELINE indicates the placement of the roman baseline + * with respect to the graphics origin. + */ + public static final int ROMAN_BASELINE = 0; + + /** + * The Constant CENTER_BASELINE indicates the placement of the center + * baseline with respect to the graphics origin. + */ + public static final int CENTER_BASELINE = 1; + + /** + * The Constant HANGING_BASELINE indicates the placement of the hanging + * baseline with respect to the graphics origin. + */ + public static final int HANGING_BASELINE = 2; + + // the alignment of this GraphicAttribute + /** + * The alignment. + */ + private int alignment; + + /** + * Instantiates a new graphic attribute with the specified alignment. + * + * @param align + * the specified alignment. + */ + protected GraphicAttribute(int align) { + if ((align < BOTTOM_ALIGNMENT) || (align > HANGING_BASELINE)) { + // awt.198=Illegal alignment argument + throw new IllegalArgumentException(Messages.getString("awt.198")); //$NON-NLS-1$ + } + this.alignment = align; + } + + /** + * Draws the GraphicAttribute at the specified location. + * + * @param graphics + * the Graphics. + * @param x + * the X coordinate of GraphicAttribute location. + * @param y + * the Y coordinate of GraphicAttribute location. + */ + public abstract void draw(Graphics2D graphics, float x, float y); + + /** + * Gets the GraphicAttribute's advance. It's the distance from the point at + * which the graphic is rendered and the point where the next character or + * graphic is rendered. + * + * @return the GraphicAttribute's advance. + */ + public abstract float getAdvance(); + + /** + * Gets the alignment of this GraphicAttribute. + * + * @return the alignment of this GraphicAttribute. + */ + public final int getAlignment() { + return this.alignment; + } + + /** + * Gets the ascent of this GraphicAttribute. + * + * @return the ascent of this GraphicAttribute. + */ + public abstract float getAscent(); + + /** + * Gets the bounds of this GraphicAttribute. + * + * @return the bounds of this GraphicAttribute. + */ + public Rectangle2D getBounds() { + float ascent = getAscent(); + float advance = getAdvance(); + float descent = getDescent(); + + // Default implementation - see API documentation. + return new Rectangle2D.Float(0, -ascent, advance, ascent + descent); + } + + /** + * Gets the descent of this GraphicAttribute. + * + * @return the descent of this GraphicAttribute. + */ + public abstract float getDescent(); + + /** + * Gets the GlyphJustificationInfo of this GraphicAttribute. + * + * @return the GlyphJustificationInfo of this GraphicAttribute. + */ + public GlyphJustificationInfo getJustificationInfo() { + + /* + * Default implementation. Since documentation doesn't describe default + * values, they were calculated based on 1.5 release behavior and can be + * obtained using next test sample: // Create GraphicAttribute class + * implementation public class MyGraphicAttribute extends + * GraphicAttribute { protected MyGraphicAttribute(int align) { + * super(align); } public float getDescent() { return 0; } public float + * getAdvance() { return 1; } public void draw(Graphics2D g2, float x, + * float y) { } public float getAscent() { return 0; } } + * MyGraphicAttribute myGA = gat.new MyGraphicAttribute(0); // print + * justification parameters + * System.out.println(myGA.getJustificationInfo().growAbsorb); + * System.out.println(myGA.getJustificationInfo().shrinkAbsorb); + * System.out.println(myGA.getJustificationInfo().growLeftLimit); + * System.out.println(myGA.getJustificationInfo().growPriority); + * System.out.println(myGA.getJustificationInfo().growRightLimit); + * System.out.println(myGA.getJustificationInfo().shrinkLeftLimit); + * System.out.println(myGA.getJustificationInfo().shrinkPriority); + * System.out.println(myGA.getJustificationInfo().shrinkRightLimit); + * System.out.println(myGA.getJustificationInfo().weight); + */ + float advance = getAdvance(); + return new GlyphJustificationInfo(advance, false, + GlyphJustificationInfo.PRIORITY_INTERCHAR, advance / 3, advance / 3, false, + GlyphJustificationInfo.PRIORITY_WHITESPACE, 0, 0); + } + +} diff --git a/awt/java/awt/font/ImageGraphicAttribute.java b/awt/java/awt/font/ImageGraphicAttribute.java new file mode 100644 index 0000000..d6d4758 --- /dev/null +++ b/awt/java/awt/font/ImageGraphicAttribute.java @@ -0,0 +1,185 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.misc.HashCode; + +/** + * The ImageGraphicAttribute class provides an opportunity to insert images to a + * text. + * + * @since Android 1.0 + */ +public final class ImageGraphicAttribute extends GraphicAttribute { + + // Image object rendered by this ImageGraphicAttribute + /** + * The image. + */ + private Image fImage; + + // X coordinate of the origin point + /** + * The origin x. + */ + private float fOriginX; + + // Y coordinate of the origin point + /** + * The origin y. + */ + private float fOriginY; + + // the width of the image object + /** + * The img width. + */ + private float fImgWidth; + + // the height of the image object + /** + * The img height. + */ + private float fImgHeight; + + /** + * Instantiates a new ImageGraphicAttribute with the specified image, + * alignment and origins. + * + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. + * @param originX + * the origin X coordinate in the image of ImageGraphicAttribute. + * @param originY + * the origin Y coordinate in the image of ImageGraphicAttribute. + */ + public ImageGraphicAttribute(Image image, int alignment, float originX, float originY) { + super(alignment); + + this.fImage = image; + this.fOriginX = originX; + this.fOriginY = originY; + + this.fImgWidth = fImage.getWidth(null); + this.fImgHeight = fImage.getHeight(null); + + } + + /** + * Instantiates a new ImageGraphicAttribute with the specified image and + * alignment. + * + * @param image + * the Image to be rendered by ImageGraphicAttribute. + * @param alignment + * the alignment of the ImageGraphicAttribute. + */ + public ImageGraphicAttribute(Image image, int alignment) { + this(image, alignment, 0, 0); + } + + /** + * Returns a hash code of this ImageGraphicAttribute object. + * + * @return the hash code of this ImageGraphicAttribute object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(fImage.hashCode()); + hash.append(getAlignment()); + return hash.hashCode(); + } + + /** + * Compares the specified ImageGraphicAttribute object with this + * ImageGraphicAttribute object. + * + * @param iga + * the ImageGraphicAttribute object to be compared. + * @return true, if the specified ImageGraphicAttribute object is equal to + * this ImageGraphicAttribute object, false otherwise. + */ + public boolean equals(ImageGraphicAttribute iga) { + if (iga == null) { + return false; + } + + if (iga == this) { + return true; + } + + return (fOriginX == iga.fOriginX && fOriginY == iga.fOriginY + && getAlignment() == iga.getAlignment() && fImage.equals(iga.fImage)); + } + + /** + * Compares the specified Object with this ImageGraphicAttribute object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified Object is equal to this + * ImageGraphicAttribute object, false otherwise. + */ + @Override + public boolean equals(Object obj) { + try { + return equals((ImageGraphicAttribute)obj); + } catch (ClassCastException e) { + return false; + } + + } + + @Override + public void draw(Graphics2D g2, float x, float y) { + g2.drawImage(fImage, (int)(x - fOriginX), (int)(y - fOriginY), null); + } + + @Override + public float getAdvance() { + return Math.max(0, fImgWidth - fOriginX); + } + + @Override + public float getAscent() { + return Math.max(0, fOriginY); + } + + @Override + public Rectangle2D getBounds() { + return new Rectangle2D.Float(-fOriginX, -fOriginY, fImgWidth, fImgHeight); + } + + @Override + public float getDescent() { + return Math.max(0, fImgHeight - fOriginY); + } + +} diff --git a/awt/java/awt/font/LineBreakMeasurer.java b/awt/java/awt/font/LineBreakMeasurer.java new file mode 100644 index 0000000..4800093 --- /dev/null +++ b/awt/java/awt/font/LineBreakMeasurer.java @@ -0,0 +1,238 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.text.AttributedCharacterIterator; //???AWT: import java.text.BreakIterator; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The class LineBreakMeasurer provides methods to measure the graphical + * representation of a text in order to determine where to add line breaks so + * the resulting line of text fits its wrapping width. The wrapping width + * defines the visual width of the paragraph. + * + * @since Android 1.0 + */ +public final class LineBreakMeasurer { + + /** + * The tm. + */ + private TextMeasurer tm = null; + + // ???AWT private BreakIterator bi = null; + /** + * The position. + */ + private int position = 0; + + /** + * The maxpos. + */ + int maxpos = 0; + + /** + * Instantiates a new LineBreakMeasurer object for the specified text. + * + * @param text + * the AttributedCharacterIterator object which contains text + * with at least one character. + * @param frc + * the FontRenderContext represented information about graphic + * device. + */ + public LineBreakMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { + // ???AWT: this(text, BreakIterator.getLineInstance(), frc); + } + + /* + * ???AWT public LineBreakMeasurer( AttributedCharacterIterator text, + * BreakIterator bi, FontRenderContext frc ) { tm = new TextMeasurer(text, + * frc); this.bi = bi; this.bi.setText(text); position = + * text.getBeginIndex(); maxpos = tm.aci.getEndIndex(); } + */ + + /** + * Deletes a character from the specified position of the text, updates this + * LineBreakMeasurer object. + * + * @param newText + * the new text. + * @param pos + * the position of the character which is deleted. + */ + public void deleteChar(AttributedCharacterIterator newText, int pos) { + tm.deleteChar(newText, pos); + // ???AWT: bi.setText(newText); + + position = newText.getBeginIndex(); + + maxpos--; + } + + /** + * Gets current position of this LineBreakMeasurer. + * + * @return the current position of this LineBreakMeasurer + */ + public int getPosition() { + return position; + } + + /** + * Inserts a character at the specified position in the text, updates this + * LineBreakMeasurer object. + * + * @param newText + * the new text. + * @param pos + * the position of the character which is inserted. + */ + public void insertChar(AttributedCharacterIterator newText, int pos) { + tm.insertChar(newText, pos); + // ???AWT: bi.setText(newText); + + position = newText.getBeginIndex(); + + maxpos++; + } + + /** + * Returns the next line of text, updates current position in this + * LineBreakMeasurer. + * + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point within the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, null is returned (the entire word at the current + * position does not fit within the wrapping width); if false, a + * valid layout is returned that includes at least the character + * at the current position. + * @return the next TextLayout which begins at the current position and + * represents the next line of text with width wrappingWidth, null + * is returned if the entire word at the current position does not + * fit within the wrapping width. + */ + public TextLayout nextLayout(float wrappingWidth, int offsetLimit, boolean requireNextWord) { + if (position == maxpos) { + return null; + } + + int nextPosition = nextOffset(wrappingWidth, offsetLimit, requireNextWord); + + if (nextPosition == position) { + return null; + } + TextLayout layout = tm.getLayout(position, nextPosition); + position = nextPosition; + return layout; + } + + /** + * Returns the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @return the next line of text. + */ + public TextLayout nextLayout(float wrappingWidth) { + return nextLayout(wrappingWidth, maxpos, false); + } + + /** + * Returns the end position of the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @return the end position of the next line of text. + */ + public int nextOffset(float wrappingWidth) { + return nextOffset(wrappingWidth, maxpos, false); + } + + /** + * Returns the end position of the next line of text. + * + * @param wrappingWidth + * the maximum visible line width. + * @param offsetLimit + * the limit point withing the text indicating that no further + * text should be included on the line; the paragraph break. + * @param requireNextWord + * if true, the current position is returned if the entire next + * word does not fit within wrappingWidth; if false, the offset + * returned is at least one greater than the current position. + * @return the end position of the next line of text. + * @throws IllegalArgumentException + * if the offsetLimit is less than the current position. + */ + public int nextOffset(float wrappingWidth, int offsetLimit, boolean requireNextWord) { + if (offsetLimit <= position) { + // awt.203=Offset limit should be greater than current position. + throw new IllegalArgumentException(Messages.getString("awt.203")); //$NON-NLS-1$ + } + + if (position == maxpos) { + return position; + } + + int breakPos = tm.getLineBreakIndex(position, wrappingWidth); + int correctedPos = breakPos; + + // This check is required because bi.preceding(maxpos) throws an + // exception + /* + * ???AWT if (breakPos == maxpos) { correctedPos = maxpos; } else if + * (Character.isWhitespace(bi.getText().setIndex(breakPos))) { + * correctedPos = bi.following(breakPos); } else { correctedPos = + * bi.preceding(breakPos); } + */ + + if (position >= correctedPos) { + if (requireNextWord) { + correctedPos = position; + } else { + correctedPos = Math.max(position + 1, breakPos); + } + } + + return Math.min(correctedPos, offsetLimit); + } + + /** + * Sets the new position of this LineBreakMeasurer. + * + * @param pos + * the new position of this LineBreakMeasurer. + */ + public void setPosition(int pos) { + if (tm.aci.getBeginIndex() > pos || maxpos < pos) { + // awt.33=index is out of range + throw new IllegalArgumentException(Messages.getString("awt.33")); //$NON-NLS-1$ + } + position = pos; + } +} diff --git a/awt/java/awt/font/LineMetrics.java b/awt/java/awt/font/LineMetrics.java new file mode 100644 index 0000000..4b03e5d --- /dev/null +++ b/awt/java/awt/font/LineMetrics.java @@ -0,0 +1,116 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +/** + * The LineMetrics class provides information such as concerning how the text is + * positioned with respect to the base line, such as ascent, descent, and + * leading. + * + * @since Android 1.0 + */ +public abstract class LineMetrics { + + /** + * Gets the baseline offsets of the text according to the the baseline of + * this text. + * + * @return the baseline offsets of the text according to the the baseline of + * this text. + */ + public abstract float[] getBaselineOffsets(); + + /** + * Gets the number of characters of the text. + * + * @return the number of characters of the text. + */ + public abstract int getNumChars(); + + /** + * Gets the baseline index, returns one of the following index: + * ROMAN_BASELINE, CENTER_BASELINE, HANGING_BASELINE. + * + * @return the baseline index: ROMAN_BASELINE, CENTER_BASELINE or + * HANGING_BASELINE. + */ + public abstract int getBaselineIndex(); + + /** + * Gets the thickness of the underline. + * + * @return the thickness of the underline. + */ + public abstract float getUnderlineThickness(); + + /** + * Gets the offset of the underline. + * + * @return the offset of the underline. + */ + public abstract float getUnderlineOffset(); + + /** + * Gets the thickness of strike through line. + * + * @return the thickness of strike through line. + */ + public abstract float getStrikethroughThickness(); + + /** + * Gets the offset of the strike through line. + * + * @return the offset of the strike through line. + */ + public abstract float getStrikethroughOffset(); + + /** + * Gets the leading of the text. + * + * @return the leading of the text. + */ + public abstract float getLeading(); + + /** + * Gets the height of the text as a sum of the ascent, the descent and the + * leading. + * + * @return the height of the text as a sum of the ascent, the descent and + * the leading. + */ + public abstract float getHeight(); + + /** + * Gets the descent of the text. + * + * @return the descent of the text. + */ + public abstract float getDescent(); + + /** + * Gets the ascent of the text. + * + * @return the ascent of the text. + */ + public abstract float getAscent(); + +} diff --git a/awt/java/awt/font/MultipleMaster.java b/awt/java/awt/font/MultipleMaster.java new file mode 100644 index 0000000..d264f24 --- /dev/null +++ b/awt/java/awt/font/MultipleMaster.java @@ -0,0 +1,91 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; + +/** + * The MultipleMaster interface provides methods to manipulate MultipleMaster + * type fonts and retrieve graphical and design data from them. + * + * @since Android 1.0 + */ +public interface MultipleMaster { + + /** + * Derives a new multiple master font based on the specified parameters. + * + * @param glyphWidths + * float array which represents width of each glyph in font + * space. + * @param avgStemWidth + * the average stem width in font space. + * @param typicalCapHeight + * the typical upper case char height. + * @param typicalXHeight + * the typical lower case char height. + * @param italicAngle + * the slope angle for italics. + * @return a MultipleMaster font. + */ + public Font deriveMMFont(float[] glyphWidths, float avgStemWidth, float typicalCapHeight, + float typicalXHeight, float italicAngle); + + /** + * Derives a new multiple master font based on the design axis values + * contained in the specified array. + * + * @param axes + * an float array which contains axis values. + * @return a MultipleMaster font. + */ + public Font deriveMMFont(float[] axes); + + /** + * Gets default design values for the axes. + * + * @return the default design values for the axes. + */ + public float[] getDesignAxisDefaults(); + + /** + * Gets the array of design axis names. + * + * @return the array of design axis names. + */ + public String[] getDesignAxisNames(); + + /** + * Gets the array of design axis ranges. + * + * @return the array of design axis ranges. + */ + public float[] getDesignAxisRanges(); + + /** + * Gets the number of multiple master design controls. + * + * @return the number of multiple master design controls. + */ + public int getNumDesignAxes(); + +} diff --git a/awt/java/awt/font/OpenType.java b/awt/java/awt/font/OpenType.java new file mode 100644 index 0000000..db66911 --- /dev/null +++ b/awt/java/awt/font/OpenType.java @@ -0,0 +1,418 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +/** + * The OpenType interface provides constants and methods for getting instance + * data for fonts of type OpenType and TrueType. For more information, see the + * <a + * href="http://partners.adobe.com/public/developer/opentype/index_spec.html"> + * OpenType specification</a>. + * + * @since Android 1.0 + */ +public interface OpenType { + + /** + * The Constant TAG_ACNT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_ACNT = 1633906292; + + /** + * The Constant TAG_AVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_AVAR = 1635148146; + + /** + * The Constant TAG_BASE indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BASE = 1111577413; + + /** + * The Constant TAG_BDAT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BDAT = 1650745716; + + /** + * The Constant TAG_BLOC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BLOC = 1651273571; + + /** + * The Constant TAG_BSLN indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_BSLN = 1651731566; + + /** + * The Constant TAG_CFF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CFF = 1128678944; + + /** + * The Constant TAG_CMAP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CMAP = 1668112752; + + /** + * The Constant TAG_CVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CVAR = 1668702578; + + /** + * The Constant TAG_CVT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_CVT = 1668707360; + + /** + * The Constant TAG_DSIG indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_DSIG = 1146308935; + + /** + * The Constant TAG_EBDT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBDT = 1161970772; + + /** + * The Constant TAG_EBLC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBLC = 1161972803; + + /** + * The Constant TAG_EBSC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_EBSC = 1161974595; + + /** + * The Constant TAG_FDSC indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FDSC = 1717859171; + + /** + * The Constant TAG_FEAT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FEAT = 1717920116; + + /** + * The Constant TAG_FMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FMTX = 1718449272; + + /** + * The Constant TAG_FPGM indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FPGM = 1718642541; + + /** + * The Constant TAG_FVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_FVAR = 1719034226; + + /** + * The Constant TAG_GASP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GASP = 1734439792; + + /** + * The Constant TAG_GDEF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GDEF = 1195656518; + + /** + * The Constant TAG_GLYF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GLYF = 1735162214; + + /** + * The Constant TAG_GPOS indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GPOS = 1196445523; + + /** + * The Constant TAG_GSUB indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GSUB = 1196643650; + + /** + * The Constant TAG_GVAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_GVAR = 1735811442; + + /** + * The Constant TAG_HDMX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HDMX = 1751412088; + + /** + * The Constant TAG_HEAD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HEAD = 1751474532; + + /** + * The Constant TAG_HHEA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HHEA = 1751672161; + + /** + * The Constant TAG_HMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_HMTX = 1752003704; + + /** + * The Constant TAG_JSTF indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_JSTF = 1246975046; + + /** + * The Constant TAG_JUST indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_JUST = 1786082164; + + /** + * The Constant TAG_KERN indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_KERN = 1801810542; + + /** + * The Constant TAG_LCAR indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LCAR = 1818452338; + + /** + * The Constant TAG_LOCA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LOCA = 1819239265; + + /** + * The Constant TAG_LTSH indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_LTSH = 1280594760; + + /** + * The Constant TAG_MAXP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MAXP = 1835104368; + + /** + * The Constant TAG_MMFX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MMFX = 1296909912; + + /** + * The Constant TAG_MMSD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MMSD = 1296913220; + + /** + * The Constant TAG_MORT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_MORT = 1836020340; + + /** + * The Constant TAG_NAME indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_NAME = 1851878757; + + /** + * The Constant TAG_OPBD indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_OPBD = 1836020340; + + /** + * The Constant TAG_OS2 indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_OS2 = 1330851634; + + /** + * The Constant TAG_PCLT indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PCLT = 1346587732; + + /** + * The Constant TAG_POST indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_POST = 1886352244; + + /** + * The Constant TAG_PREP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PREP = 1886545264; + + /** + * The Constant TAG_PROP indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_PROP = 1886547824; + + /** + * The Constant TAG_TRAK indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_TRAK = 1953653099; + + /** + * The Constant TAG_TYP1 indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_TYP1 = 1954115633; + + /** + * The Constant TAG_VDMX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VDMX = 1447316824; + + /** + * The Constant TAG_VHEA indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VHEA = 1986553185; + + /** + * The Constant TAG_VMTX indicates corresponding table tag in the Open Type + * Specification. + */ + public static final int TAG_VMTX = 1986884728; + + /** + * Returns the OpenType font version. + * + * @return the the OpenType font version. + */ + public int getVersion(); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param sfntTag + * the sfnt tag. + * @return a byte array contains the font data corresponding to the + * specified tag. + */ + public byte[] getFontTable(int sfntTag); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param sfntTag + * the sfnt tag. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. + */ + public byte[] getFontTable(int sfntTag, int offset, int count); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param strSfntTag + * the str sfnt tag as a String. + * @return a byte array contains the font data corresponding to the + * specified tag. + */ + public byte[] getFontTable(String strSfntTag); + + /** + * Gets the table for a specified tag. Sfnt tables include cmap, name and + * head items. + * + * @param strSfntTag + * the sfnt tag as a String. + * @param offset + * the offset of the returned table. + * @param count + * the number of returned table. + * @return the table corresponding to sfntTag and containing the bytes + * starting at offset byte and including count bytes. + */ + public byte[] getFontTable(String strSfntTag, int offset, int count); + + /** + * Gets the table size for a specified tag. + * + * @param strSfntTag + * the sfnt tag as a String. + * @return the table size for a specified tag. + */ + public int getFontTableSize(String strSfntTag); + + /** + * Gets the table size for a specified tag. + * + * @param sfntTag + * the sfnt tag. + * @return the table size for a specified tag. + */ + public int getFontTableSize(int sfntTag); + +} diff --git a/awt/java/awt/font/ShapeGraphicAttribute.java b/awt/java/awt/font/ShapeGraphicAttribute.java new file mode 100644 index 0000000..182bffd --- /dev/null +++ b/awt/java/awt/font/ShapeGraphicAttribute.java @@ -0,0 +1,206 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.BasicStroke; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.Stroke; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; + +import org.apache.harmony.misc.HashCode; + +/** + * The ShapeGraphicAttribute class provides an opportunity to insert shapes to a + * text. + * + * @since Android 1.0 + */ +public final class ShapeGraphicAttribute extends GraphicAttribute { + + // shape to render + /** + * The shape. + */ + private Shape fShape; + + // flag, if the shape should be stroked (true) or filled (false) + /** + * The stroke. + */ + private boolean fStroke; + + // bounds of the shape + /** + * The bounds. + */ + private Rectangle2D fBounds; + + // X coordinate of the origin point + /** + * The origin x. + */ + private float fOriginX; + + // Y coordinate of the origin point + /** + * The origin y. + */ + private float fOriginY; + + // width of the shape + /** + * The shape width. + */ + private float fShapeWidth; + + // height of the shape + /** + * The shape height. + */ + private float fShapeHeight; + + /** + * The Constant STROKE indicates whether the Shape is stroked or not. + */ + public static final boolean STROKE = true; + + /** + * The Constant FILL indicates whether the Shape is filled or not. + */ + public static final boolean FILL = false; + + /** + * Instantiates a new ShapeGraphicAttribute object for the specified Shape. + * + * @param shape + * the shape to be rendered by this ShapeGraphicAttribute. + * @param alignment + * the alignment of this ShapeGraphicAttribute. + * @param stroke + * true if the Shape is stroked, false if the Shape is filled. + */ + public ShapeGraphicAttribute(Shape shape, int alignment, boolean stroke) { + super(alignment); + + this.fShape = shape; + this.fStroke = stroke; + + this.fBounds = fShape.getBounds2D(); + + this.fOriginX = (float)fBounds.getMinX(); + this.fOriginY = (float)fBounds.getMinY(); + + this.fShapeWidth = (float)fBounds.getWidth(); + this.fShapeHeight = (float)fBounds.getHeight(); + } + + /** + * Returns a hash code of this ShapeGraphicAttribute object. + * + * @return a hash code of this ShapeGraphicAttribute object. + */ + @Override + public int hashCode() { + HashCode hash = new HashCode(); + + hash.append(fShape.hashCode()); + hash.append(getAlignment()); + return hash.hashCode(); + } + + /** + * Compares this ShapeGraphicAttribute object to the specified + * ShapeGraphicAttribute object. + * + * @param sga + * the ShapeGraphicAttribute object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified ShapeGraphicAttribute object, false otherwise. + */ + public boolean equals(ShapeGraphicAttribute sga) { + if (sga == null) { + return false; + } + + if (sga == this) { + return true; + } + + return (fStroke == sga.fStroke && getAlignment() == sga.getAlignment() && fShape + .equals(sga.fShape)); + + } + + /** + * Compares this ShapeGraphicAttribute object to the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if this ShapeGraphicAttribute object is equal to the + * specified Object, false otherwise. + */ + @Override + public boolean equals(Object obj) { + try { + return equals((ShapeGraphicAttribute)obj); + } catch (ClassCastException e) { + return false; + } + } + + @Override + public void draw(Graphics2D g2, float x, float y) { + AffineTransform at = AffineTransform.getTranslateInstance(x, y); + if (fStroke == STROKE) { + Stroke oldStroke = g2.getStroke(); + g2.setStroke(new BasicStroke()); + g2.draw(at.createTransformedShape(fShape)); + g2.setStroke(oldStroke); + } else { + g2.fill(at.createTransformedShape(fShape)); + } + + } + + @Override + public float getAdvance() { + return Math.max(0, fShapeWidth + fOriginX); + } + + @Override + public float getAscent() { + return Math.max(0, -fOriginY); + } + + @Override + public Rectangle2D getBounds() { + return (Rectangle2D)fBounds.clone(); + } + + @Override + public float getDescent() { + return Math.max(0, fShapeHeight + fOriginY); + } + +} diff --git a/awt/java/awt/font/TextHitInfo.java b/awt/java/awt/font/TextHitInfo.java new file mode 100644 index 0000000..6460eba --- /dev/null +++ b/awt/java/awt/font/TextHitInfo.java @@ -0,0 +1,215 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import org.apache.harmony.misc.HashCode; + +/** + * The TextHitInfo class provides information about a caret position in a text + * model for insertion or deletion of a character in a text. The TextHitInfo + * defines two biases of the character: leading or trailing. Leading position + * means the left edge of the specified character (TextHitInfo.leading(2) method + * for "text" returns the left side of "x"). Trailing position means the right + * edge of the specified character (TextHitInfo.trailing(2) method for "text" + * returns the right side of "x"). + * + * @since Android 1.0 + */ +public final class TextHitInfo { + + /** + * The char idx. + */ + private int charIdx; // Represents character index in the line + + /** + * The is trailing. + */ + private boolean isTrailing; + + /** + * Instantiates a new text hit info. + * + * @param idx + * the idx. + * @param isTrailing + * the is trailing. + */ + private TextHitInfo(int idx, boolean isTrailing) { + charIdx = idx; + this.isTrailing = isTrailing; + } + + /** + * Returns the textual string representation of this TextHitInfo instance. + * + * @return the string representation. + */ + @Override + public String toString() { + return new String("TextHitInfo[" + charIdx + ", " + //$NON-NLS-1$ //$NON-NLS-2$ + (isTrailing ? "Trailing" : "Leading") + "]" //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + ); + } + + /** + * Compares this TextHitInfo object with the specified object. + * + * @param obj + * the Object to be compared. + * @return true, if the specified object is a TextHitInfo object with the + * same data values as this TextHitInfo, false otherwise. + */ + @Override + public boolean equals(Object obj) { + if (obj instanceof TextHitInfo) { + return equals((TextHitInfo)obj); + } + return false; + } + + /** + * Compares this TextHitInfo object with the specified TextHitInfo object. + * + * @param thi + * the TextHitInfo object to be compared. + * @return true, if this TextHitInfo object has the same data values as the + * specified TextHitInfo object, false otherwise. + */ + public boolean equals(TextHitInfo thi) { + return thi != null && thi.charIdx == charIdx && thi.isTrailing == isTrailing; + } + + /** + * Gets a TextHitInfo object with its character index at the specified + * offset from the character index of this TextHitInfo. + * + * @param offset + * the offset. + * @return the TextHitInfo. + */ + public TextHitInfo getOffsetHit(int offset) { + return new TextHitInfo(charIdx + offset, isTrailing); + } + + /** + * Gets a TextHitInfo associated with the other side of the insertion point. + * + * @return the other hit. + */ + public TextHitInfo getOtherHit() { + return isTrailing ? new TextHitInfo(charIdx + 1, false) + : new TextHitInfo(charIdx - 1, true); + } + + /** + * Returns true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. + * + * @return true if the leading edge of the character is hit, false if the + * trailing edge of the character is hit. + */ + public boolean isLeadingEdge() { + return !isTrailing; + } + + /** + * Returns the hash code value of this TextHitInfo instance. + * + * @return the hash code value. + */ + @Override + public int hashCode() { + return HashCode.combine(charIdx, isTrailing); + } + + /** + * Gets the insertion index. + * + * @return the insertion index: character index if the leading edge is hit, + * or character index + 1 if the trailing edge is hit. + */ + public int getInsertionIndex() { + return isTrailing ? charIdx + 1 : charIdx; + } + + /** + * Gets the index of the character hit. + * + * @return the character hit's index. + */ + public int getCharIndex() { + return charIdx; + } + + /** + * Returns a TextHitInfo associated with the trailing edge of the character + * at the specified char index. + * + * @param charIndex + * the char index. + * @return the TextHitInfo associated with the trailing edge of the + * character at the specified char index. + */ + public static TextHitInfo trailing(int charIndex) { + return new TextHitInfo(charIndex, true); + } + + /** + * Returns a TextHitInfo object associated with the leading edge of the + * character at the specified char index. + * + * @param charIndex + * the char index. + * @return the TextHitInfo object associated with the leading edge of the + * character at the specified char index. + */ + public static TextHitInfo leading(int charIndex) { + return new TextHitInfo(charIndex, false); + } + + /** + * Returns a (trailing) TextHitInfo object associated with the character + * before the specified offset. + * + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character before the + * specified offset. + */ + public static TextHitInfo beforeOffset(int offset) { + return new TextHitInfo(offset - 1, true); + } + + /** + * Returns a (leading) TextHitInfo object associated with the character + * after the specified offset. + * + * @param offset + * the offset. + * @return the TextHitInfo object associated with the character after the + * specified offset. + */ + public static TextHitInfo afterOffset(int offset) { + return new TextHitInfo(offset, false); + } +} diff --git a/awt/java/awt/font/TextLayout.java b/awt/java/awt/font/TextLayout.java new file mode 100644 index 0000000..cc6f0ba --- /dev/null +++ b/awt/java/awt/font/TextLayout.java @@ -0,0 +1,927 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.Font; +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Rectangle2D; +import java.awt.geom.GeneralPath; +import java.text.AttributedCharacterIterator; +import java.text.AttributedString; +import java.util.Map; + +import org.apache.harmony.awt.gl.font.BasicMetrics; +import org.apache.harmony.awt.gl.font.CaretManager; +import org.apache.harmony.awt.gl.font.TextMetricsCalculator; +import org.apache.harmony.awt.gl.font.TextRunBreaker; +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The TextLayout class defines the graphical representation of character data. + * This class provides method for obtaining information about cursor positioning + * and movement, split cursors for text with different directions, logical and + * visual highlighting, multiple baselines, hits, justification, ascent, + * descent, and advance, and rendering. A TextLayout object can be rendered + * using Graphics context. + * + * @since Android 1.0 + */ +public final class TextLayout implements Cloneable { + + /** + * The CaretPolicy class provides a policy for obtaining the caret location. + * The single getStrongCaret method specifies the policy. + */ + public static class CaretPolicy { + + /** + * Instantiates a new CaretPolicy. + */ + public CaretPolicy() { + // Nothing to do + } + + /** + * Returns whichever of the two specified TextHitInfo objects has the + * stronger caret (higher character level) in the specified TextLayout. + * + * @param hit1 + * the first TextHitInfo of the specified TextLayout. + * @param hit2 + * the second TextHitInfo of the specified TextLayout. + * @param layout + * the TextLayout. + * @return the TextHitInfo with the stronger caret. + */ + public TextHitInfo getStrongCaret(TextHitInfo hit1, TextHitInfo hit2, TextLayout layout) { + // Stronger hit is the one with greater level. + // If the level is same, leading edge is stronger. + + int level1 = layout.getCharacterLevel(hit1.getCharIndex()); + int level2 = layout.getCharacterLevel(hit2.getCharIndex()); + + if (level1 == level2) { + return (hit2.isLeadingEdge() && (!hit1.isLeadingEdge())) ? hit2 : hit1; + } + return level1 > level2 ? hit1 : hit2; + } + + } + + /** + * The Constant DEFAULT_CARET_POLICY indicates the default caret policy. + */ + public static final TextLayout.CaretPolicy DEFAULT_CARET_POLICY = new CaretPolicy(); + + /** + * The breaker. + */ + private TextRunBreaker breaker; + + /** + * The metrics valid. + */ + private boolean metricsValid = false; + + /** + * The tmc. + */ + private TextMetricsCalculator tmc; + + /** + * The metrics. + */ + private BasicMetrics metrics; + + /** + * The caret manager. + */ + private CaretManager caretManager; + + /** + * The justification width. + */ + float justificationWidth = -1; + + /** + * Instantiates a new TextLayout object from the specified string and Font. + * + * @param string + * the string to be displayed. + * @param font + * the font of the text. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(String string, Font font, FontRenderContext frc) { + if (string == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (font == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "font")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (string.length() == 0) { + // awt.02='{0}' parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + AttributedString as = new AttributedString(string); + as.addAttribute(TextAttribute.FONT, font); + this.breaker = new TextRunBreaker(as.getIterator(), frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new TextLayout from the specified text and a map of + * attributes. + * + * @param string + * the string to be displayed. + * @param attributes + * the attributes to be used for obtaining the text style. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(String string, + Map<? extends java.text.AttributedCharacterIterator.Attribute, ?> attributes, + FontRenderContext frc) { + if (string == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (attributes == null) { + // awt.01='{0}' parameter is null + throw new IllegalArgumentException(Messages.getString("awt.01", "attributes")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (string.length() == 0) { + // awt.02='{0}' parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.02", "string")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + AttributedString as = new AttributedString(string); + as.addAttributes(attributes, 0, string.length()); + this.breaker = new TextRunBreaker(as.getIterator(), frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new TextLayout from the AttributedCharacterIterator. + * + * @param text + * the AttributedCharacterIterator. + * @param frc + * the FontRenderContext object for obtaining information about a + * graphics device. + */ + public TextLayout(AttributedCharacterIterator text, FontRenderContext frc) { + if (text == null) { + // awt.03='{0}' iterator parameter is null + throw new IllegalArgumentException(Messages.getString("awt.03", "text")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + if (text.getBeginIndex() == text.getEndIndex()) { + // awt.04='{0}' iterator parameter has zero length + throw new IllegalArgumentException(Messages.getString("awt.04", "text")); //$NON-NLS-1$ //$NON-NLS-2$ + } + + this.breaker = new TextRunBreaker(text, frc); + caretManager = new CaretManager(breaker); + } + + /** + * Instantiates a new text layout. + * + * @param breaker + * the breaker. + */ + TextLayout(TextRunBreaker breaker) { + this.breaker = breaker; + caretManager = new CaretManager(this.breaker); + } + + /** + * Returns a hash code of this TextLayout object. + * + * @return a hash code of this TextLayout object. + */ + @Override + public int hashCode() { + return breaker.hashCode(); + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object. + */ + @Override + protected Object clone() { + TextLayout res = new TextLayout((TextRunBreaker)breaker.clone()); + + if (justificationWidth >= 0) { + res.handleJustify(justificationWidth); + } + + return res; + } + + /** + * Compares this TextLayout object to the specified TextLayout object. + * + * @param layout + * the TextLayout object to be compared. + * @return true, if this TextLayout object is equal to the specified + * TextLayout object, false otherwise. + */ + public boolean equals(TextLayout layout) { + if (layout == null) { + return false; + } + return this.breaker.equals(layout.breaker); + } + + /** + * Compares this TextLayout object to the specified Object. + * + * @param obj + * the Object to be compared. + * @return true, if this TextLayout object is equal to the specified Object, + * false otherwise. + */ + @Override + public boolean equals(Object obj) { + return obj instanceof TextLayout ? equals((TextLayout)obj) : false; + } + + /** + * Gets the string representation for this TextLayout. + * + * @return the string representation for this TextLayout. + */ + @Override + public String toString() { // what for? + return super.toString(); + } + + /** + * Draws this TextLayout at the specified location with the specified + * Graphics2D context. + * + * @param g2d + * the Graphics2D object which renders this TextLayout. + * @param x + * the X coordinate of the TextLayout origin. + * @param y + * the Y coordinate of the TextLayout origin. + */ + public void draw(Graphics2D g2d, float x, float y) { + updateMetrics(); + breaker.drawSegments(g2d, x, y); + } + + /** + * Update metrics. + */ + private void updateMetrics() { + if (!metricsValid) { + breaker.createAllSegments(); + tmc = new TextMetricsCalculator(breaker); + metrics = tmc.createMetrics(); + metricsValid = true; + } + } + + /** + * Gets the advance of this TextLayout object. + * + * @return the advance of this TextLayout object. + */ + public float getAdvance() { + updateMetrics(); + return metrics.getAdvance(); + } + + /** + * Gets the ascent of this TextLayout object. + * + * @return the ascent of this TextLayout object. + */ + public float getAscent() { + updateMetrics(); + return metrics.getAscent(); + } + + /** + * Gets the baseline of this TextLayout object. + * + * @return the baseline of this TextLayout object. + */ + public byte getBaseline() { + updateMetrics(); + return (byte)metrics.getBaseLineIndex(); + } + + /** + * Gets the float array of offsets for the baselines which are used in this + * TextLayout. + * + * @return the float array of offsets for the baselines which are used in + * this TextLayout. + */ + public float[] getBaselineOffsets() { + updateMetrics(); + return tmc.getBaselineOffsets(); + } + + /** + * Gets the black box bounds of the characters in the specified area. The + * black box bounds is an Shape which contains all bounding boxes of all the + * glyphs of the characters between firstEndpoint and secondEndpoint + * parameters values. + * + * @param firstEndpoint + * the first point of the area. + * @param secondEndpoint + * the second point of the area. + * @return the Shape which contains black box bounds. + */ + public Shape getBlackBoxBounds(int firstEndpoint, int secondEndpoint) { + updateMetrics(); + if (firstEndpoint < secondEndpoint) { + return breaker.getBlackBoxBounds(firstEndpoint, secondEndpoint); + } + return breaker.getBlackBoxBounds(secondEndpoint, firstEndpoint); + } + + /** + * Gets the bounds of this TextLayout. + * + * @return the bounds of this TextLayout. + */ + public Rectangle2D getBounds() { + updateMetrics(); + return breaker.getVisualBounds(); + } + + /** + * Gets information about the caret of the specified TextHitInfo. + * + * @param hitInfo + * the TextHitInfo. + * @return the information about the caret of the specified TextHitInfo. + */ + public float[] getCaretInfo(TextHitInfo hitInfo) { + updateMetrics(); + return caretManager.getCaretInfo(hitInfo); + } + + /** + * Gets information about the caret of the specified TextHitInfo of a + * character in this TextLayout. + * + * @param hitInfo + * the TextHitInfo of a character in this TextLayout. + * @param bounds + * the bounds to which the caret info is constructed. + * @return the caret of the specified TextHitInfo. + */ + public float[] getCaretInfo(TextHitInfo hitInfo, Rectangle2D bounds) { + updateMetrics(); + return caretManager.getCaretInfo(hitInfo); + } + + /** + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. + * + * @param hitInfo + * the TextHitInfo. + * @param bounds + * the bounds to which the caret info is constructed. + * @return the Shape which represents the caret. + */ + public Shape getCaretShape(TextHitInfo hitInfo, Rectangle2D bounds) { + updateMetrics(); + return caretManager.getCaretShape(hitInfo, this); + } + + /** + * Gets a Shape which represents the caret of the specified TextHitInfo in + * the bounds of this TextLayout. + * + * @param hitInfo + * the TextHitInfo. + * @return the Shape which represents the caret. + */ + public Shape getCaretShape(TextHitInfo hitInfo) { + updateMetrics(); + return caretManager.getCaretShape(hitInfo, this); + } + + /** + * Gets two Shapes for the strong and weak carets with default caret policy + * and null bounds: the first element is the strong caret, the second is the + * weak caret or null. + * + * @param offset + * an offset in the TextLayout. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset) { + return getCaretShapes(offset, null, TextLayout.DEFAULT_CARET_POLICY); + } + + /** + * Gets two Shapes for the strong and weak carets with the default caret + * policy: the first element is the strong caret, the second is the weak + * caret or null. + * + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset, Rectangle2D bounds) { + return getCaretShapes(offset, bounds, TextLayout.DEFAULT_CARET_POLICY); + } + + /** + * Gets two Shapes for the strong and weak carets: the first element is the + * strong caret, the second is the weak caret or null. + * + * @param offset + * an offset in the TextLayout. + * @param bounds + * the bounds to which to extend the carets. + * @param policy + * the specified CaretPolicy. + * @return an array of two Shapes corresponded to the strong and weak + * carets. + */ + public Shape[] getCaretShapes(int offset, Rectangle2D bounds, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + updateMetrics(); + return caretManager.getCaretShapes(offset, bounds, policy, this); + } + + /** + * Gets the number of characters in this TextLayout. + * + * @return the number of characters in this TextLayout. + */ + public int getCharacterCount() { + return breaker.getCharCount(); + } + + /** + * Gets the level of the character with the specified index. + * + * @param index + * the specified index of the character. + * @return the level of the character. + */ + public byte getCharacterLevel(int index) { + if (index == -1 || index == getCharacterCount()) { + return (byte)breaker.getBaseLevel(); + } + return breaker.getLevel(index); + } + + /** + * Gets the descent of this TextLayout. + * + * @return the descent of this TextLayout. + */ + public float getDescent() { + updateMetrics(); + return metrics.getDescent(); + } + + /** + * Gets the TextLayout wich is justified with the specified width related to + * this TextLayout. + * + * @param justificationWidth + * the width which is used for justification. + * @return a TextLayout justified to the specified width. + * @throws Error + * the error occures if this TextLayout has been already + * justified. + */ + public TextLayout getJustifiedLayout(float justificationWidth) throws Error { + float justification = breaker.getJustification(); + + if (justification < 0) { + // awt.196=Justification impossible, layout already justified + throw new Error(Messages.getString("awt.196")); //$NON-NLS-1$ + } else if (justification == 0) { + return this; + } + + TextLayout justifiedLayout = new TextLayout((TextRunBreaker)breaker.clone()); + justifiedLayout.handleJustify(justificationWidth); + return justifiedLayout; + } + + /** + * Gets the leading of this TextLayout. + * + * @return the leading of this TextLayout. + */ + public float getLeading() { + updateMetrics(); + return metrics.getLeading(); + } + + /** + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the natural bounds of this TextLayout. + * + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @return a Shape represented the logical selection betweeen the specified + * endpoints. + */ + public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint) { + updateMetrics(); + return getLogicalHighlightShape(firstEndpoint, secondEndpoint, breaker.getLogicalBounds()); + } + + /** + * Gets a Shape representing the logical selection betweeen the specified + * endpoints and extended to the specified bounds of this TextLayout. + * + * @param firstEndpoint + * the first selected endpoint within the area of characters + * @param secondEndpoint + * the second selected endpoint within the area of characters + * @param bounds + * the specified bounds of this TextLayout. + * @return a Shape represented the logical selection betweeen the specified + * endpoints. + */ + public Shape getLogicalHighlightShape(int firstEndpoint, int secondEndpoint, Rectangle2D bounds) { + updateMetrics(); + + if (firstEndpoint > secondEndpoint) { + if (secondEndpoint < 0 || firstEndpoint > breaker.getCharCount()) { + // awt.197=Endpoints are out of range + throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ + } + return caretManager.getLogicalHighlightShape(secondEndpoint, firstEndpoint, bounds, + this); + } + if (firstEndpoint < 0 || secondEndpoint > breaker.getCharCount()) { + // awt.197=Endpoints are out of range + throw new IllegalArgumentException(Messages.getString("awt.197")); //$NON-NLS-1$ + } + return caretManager.getLogicalHighlightShape(firstEndpoint, secondEndpoint, bounds, this); + } + + /** + * Gets the logical ranges of text which corresponds to a visual selection. + * + * @param hit1 + * the first endpoint of the visual range. + * @param hit2 + * the second endpoint of the visual range. + * @return the logical ranges of text which corresponds to a visual + * selection. + */ + public int[] getLogicalRangesForVisualSelection(TextHitInfo hit1, TextHitInfo hit2) { + return caretManager.getLogicalRangesForVisualSelection(hit1, hit2); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset. + * + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(int offset) { + return getNextLeftHit(offset, DEFAULT_CARET_POLICY); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified hit. + * + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the left (or up at the end + * of the line) of the specified hit, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(TextHitInfo hitInfo) { + breaker.createAllSegments(); + return caretManager.getNextLeftHit(hitInfo); + } + + /** + * Gets the TextHitInfo for the next caret to the left (or up at the end of + * the line) of the specified offset, given the specified caret policy. + * + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the left of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextLeftHit(int offset, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + TextHitInfo hit = TextHitInfo.afterOffset(offset); + TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this); + TextHitInfo nextLeftHit = getNextLeftHit(strongHit); + + if (nextLeftHit != null) { + return policy.getStrongCaret(getVisualOtherHit(nextLeftHit), nextLeftHit, this); + } + return null; + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified hit. + * + * @param hitInfo + * the initial hit. + * @return the TextHitInfo for the next caret to the right (or down at the + * end of the line) of the specified hit, or null if there is no + * hit. + */ + public TextHitInfo getNextRightHit(TextHitInfo hitInfo) { + breaker.createAllSegments(); + return caretManager.getNextRightHit(hitInfo); + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset. + * + * @param offset + * the offset in this TextLayout. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextRightHit(int offset) { + return getNextRightHit(offset, DEFAULT_CARET_POLICY); + } + + /** + * Gets the TextHitInfo for the next caret to the right (or down at the end + * of the line) of the specified offset, given the specified caret policy. + * + * @param offset + * the offset in this TextLayout. + * @param policy + * the policy to be used for obtaining the strong caret. + * @return the TextHitInfo for the next caret to the right of the specified + * offset, or null if there is no hit. + */ + public TextHitInfo getNextRightHit(int offset, TextLayout.CaretPolicy policy) { + if (offset < 0 || offset > breaker.getCharCount()) { + // awt.195=Offset is out of bounds + throw new IllegalArgumentException(Messages.getString("awt.195")); //$NON-NLS-1$ + } + + TextHitInfo hit = TextHitInfo.afterOffset(offset); + TextHitInfo strongHit = policy.getStrongCaret(hit, hit.getOtherHit(), this); + TextHitInfo nextRightHit = getNextRightHit(strongHit); + + if (nextRightHit != null) { + return policy.getStrongCaret(getVisualOtherHit(nextRightHit), nextRightHit, this); + } + return null; + } + + /** + * Gets the outline of this TextLayout as a Shape. + * + * @param xform + * the AffineTransform to be used to transform the outline before + * returning it, or null if no transformation is desired. + * @return the outline of this TextLayout as a Shape. + */ + public Shape getOutline(AffineTransform xform) { + breaker.createAllSegments(); + + GeneralPath outline = breaker.getOutline(); + + if (outline != null && xform != null) { + outline.transform(xform); + } + + return outline; + } + + /** + * Gets the visible advance of this TextLayout which is defined as diffence + * between leading (advance) and trailing whitespace. + * + * @return the visible advance of this TextLayout. + */ + public float getVisibleAdvance() { + updateMetrics(); + + // Trailing whitespace _SHOULD_ be reordered (Unicode spec) to + // base direction, so it is also trailing + // in logical representation. We use this fact. + int lastNonWhitespace = breaker.getLastNonWhitespace(); + + if (lastNonWhitespace < 0) { + return 0; + } else if (lastNonWhitespace == getCharacterCount() - 1) { + return getAdvance(); + } else if (justificationWidth >= 0) { // Layout is justified + return justificationWidth; + } else { + breaker.pushSegments(breaker.getACI().getBeginIndex(), lastNonWhitespace + + breaker.getACI().getBeginIndex() + 1); + + breaker.createAllSegments(); + + float visAdvance = tmc.createMetrics().getAdvance(); + + breaker.popSegments(); + return visAdvance; + } + } + + /** + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text and extends to the bounds. + * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. + * @param bounds + * the rectangle that the highlighted area should be extended or + * restricted to. + * @return a Shape which corresponds to the highlighted (selected) area. + */ + public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2, Rectangle2D bounds) { + return caretManager.getVisualHighlightShape(hit1, hit2, bounds, this); + } + + /** + * Gets a Shape which corresponds to the highlighted (selected) area based + * on two hit locations within the text. + * + * @param hit1 + * the first text hit location. + * @param hit2 + * the second text hit location. + * @return a Shape which corresponds to the highlighted (selected) area. + */ + public Shape getVisualHighlightShape(TextHitInfo hit1, TextHitInfo hit2) { + breaker.createAllSegments(); + return caretManager.getVisualHighlightShape(hit1, hit2, breaker.getLogicalBounds(), this); + } + + /** + * Gets the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. + * + * @param hitInfo + * the specified TextHitInfo. + * @return the TextHitInfo for a hit on the opposite side of the specified + * hit's caret. + */ + public TextHitInfo getVisualOtherHit(TextHitInfo hitInfo) { + return caretManager.getVisualOtherHit(hitInfo); + } + + /** + * Justifies the text; this method should be overridden by subclasses. + * + * @param justificationWidth + * the width for justification. + */ + protected void handleJustify(float justificationWidth) { + float justification = breaker.getJustification(); + + if (justification < 0) { + // awt.196=Justification impossible, layout already justified + throw new IllegalStateException(Messages.getString("awt.196")); //$NON-NLS-1$ + } else if (justification == 0) { + return; + } + + float gap = (justificationWidth - getVisibleAdvance()) * justification; + breaker.justify(gap); + this.justificationWidth = justificationWidth; + + // Correct metrics + tmc = new TextMetricsCalculator(breaker); + tmc.correctAdvance(metrics); + } + + /** + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates. + * + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. TextHitInfo object + * corresponding to the given coordinates within the text. + * @return the information about the character at the specified position. + */ + public TextHitInfo hitTestChar(float x, float y) { + return hitTestChar(x, y, getBounds()); + } + + /** + * Returns a TextHitInfo object that gives information on which division + * point (between two characters) is corresponds to a hit (such as a mouse + * click) at the specified coordinates within the specified text rectangle. + * + * @param x + * the X coordinate in this TextLayout. + * @param y + * the Y coordinate in this TextLayout. + * @param bounds + * the bounds of the text area. TextHitInfo object corresponding + * to the given coordinates within the text. + * @return the information about the character at the specified position. + */ + public TextHitInfo hitTestChar(float x, float y, Rectangle2D bounds) { + if (x > bounds.getMaxX()) { + return breaker.isLTR() ? TextHitInfo.trailing(breaker.getCharCount() - 1) : TextHitInfo + .leading(0); + } + + if (x < bounds.getMinX()) { + return breaker.isLTR() ? TextHitInfo.leading(0) : TextHitInfo.trailing(breaker + .getCharCount() - 1); + } + + return breaker.hitTest(x, y); + } + + /** + * Returns true if this TextLayout has a "left to right" direction. + * + * @return true if this TextLayout has a "left to right" direction, false if + * this TextLayout has a "right to left" direction. + */ + public boolean isLeftToRight() { + return breaker.isLTR(); + } + + /** + * Returns true if this TextLayout is vertical, false otherwise. + * + * @return true if this TextLayout is vertical, false if horizontal. + */ + public boolean isVertical() { + return false; + } +} diff --git a/awt/java/awt/font/TextMeasurer.java b/awt/java/awt/font/TextMeasurer.java new file mode 100644 index 0000000..9741f59 --- /dev/null +++ b/awt/java/awt/font/TextMeasurer.java @@ -0,0 +1,182 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/* + * @author Oleg V. Khaschansky + * @version $Revision$ + */ + +package java.awt.font; + +import java.text.AttributedCharacterIterator; + +import org.apache.harmony.awt.gl.font.TextMetricsCalculator; +import org.apache.harmony.awt.gl.font.TextRunBreaker; + +/** + * The TextMeasurer class provides utilities for line break operations. + * + * @since Android 1.0 + */ +public final class TextMeasurer implements Cloneable { + + /** + * The aci. + */ + AttributedCharacterIterator aci; + + /** + * The frc. + */ + FontRenderContext frc; + + /** + * The breaker. + */ + TextRunBreaker breaker = null; + + /** + * The tmc. + */ + TextMetricsCalculator tmc = null; + + /** + * Instantiates a new text measurer from the specified text. + * + * @param text + * the source text. + * @param frc + * the FontRenderContext. + */ + public TextMeasurer(AttributedCharacterIterator text, FontRenderContext frc) { + this.aci = text; + this.frc = frc; + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } + + /** + * Replaces the current text with the new text, inserting a break character + * at the specified insert position. + * + * @param newParagraph + * the new paragraph text. + * @param insertPos + * the position in the text where the character is inserted. + */ + public void insertChar(AttributedCharacterIterator newParagraph, int insertPos) { + AttributedCharacterIterator oldAci = aci; + aci = newParagraph; + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != -1) { + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } else { + breaker.insertChar(newParagraph, insertPos); + } + } + + /** + * Replaces the current text with the new text and deletes a character at + * the specified position. + * + * @param newParagraph + * the paragraph text after deletion. + * @param deletePos + * the position in the text where the character is removed. + */ + public void deleteChar(AttributedCharacterIterator newParagraph, int deletePos) { + AttributedCharacterIterator oldAci = aci; + aci = newParagraph; + if ((oldAci.getEndIndex() - oldAci.getBeginIndex()) + - (aci.getEndIndex() - aci.getBeginIndex()) != 1) { + breaker = new TextRunBreaker(aci, this.frc); + tmc = new TextMetricsCalculator(breaker); + } else { + breaker.deleteChar(newParagraph, deletePos); + } + } + + /** + * Returns a copy of this object. + * + * @return a copy of this object. + */ + @Override + protected Object clone() { + return new TextMeasurer((AttributedCharacterIterator)aci.clone(), frc); + } + + /** + * Returns a TextLayout of the specified character range. + * + * @param start + * the index of the first character. + * @param limit + * the index after the last character. + * @return a TextLayout for the characters beginning at "start" up to "end". + */ + public TextLayout getLayout(int start, int limit) { + breaker.pushSegments(start - aci.getBeginIndex(), limit - aci.getBeginIndex()); + + breaker.createAllSegments(); + TextLayout layout = new TextLayout((TextRunBreaker)breaker.clone()); + + breaker.popSegments(); + return layout; + } + + /** + * Returns the graphical width of a line beginning at "start" parameter and + * including characters up to "end" parameter. "start" and "end" are + * absolute indices, not relative to the "start" of the paragraph. + * + * @param start + * the character index at which to start measuring. + * @param end + * the character index at which to stop measuring. + * @return the graphical width of a line beginning at "start" and including + * characters up to "end". + */ + public float getAdvanceBetween(int start, int end) { + breaker.pushSegments(start - aci.getBeginIndex(), end - aci.getBeginIndex()); + + breaker.createAllSegments(); + float retval = tmc.createMetrics().getAdvance(); + + breaker.popSegments(); + return retval; + } + + /** + * Returns the index of the first character which is not fit on a line + * beginning at start and possible measuring up to maxAdvance in graphical + * width. + * + * @param start + * he character index at which to start measuring. + * @param maxAdvance + * the graphical width in which the line must fit. + * @return the index after the last character that is fit on a line + * beginning at start, which is not longer than maxAdvance in + * graphical width. + */ + public int getLineBreakIndex(int start, float maxAdvance) { + breaker.createAllSegments(); + return breaker.getLineBreakIndex(start - aci.getBeginIndex(), maxAdvance) + + aci.getBeginIndex(); + } +} diff --git a/awt/java/awt/font/TransformAttribute.java b/awt/java/awt/font/TransformAttribute.java new file mode 100644 index 0000000..ff2caa2 --- /dev/null +++ b/awt/java/awt/font/TransformAttribute.java @@ -0,0 +1,86 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Ilya S. Okomin + * @version $Revision$ + */ + +package java.awt.font; + +import java.awt.geom.AffineTransform; +import java.io.Serializable; + +import org.apache.harmony.awt.internal.nls.Messages; + +/** + * The TransformAttribute class is a wrapper for the AffineTransform class in + * order to use it as attribute. + * + * @since Android 1.0 + */ +public final class TransformAttribute implements Serializable { + + /** + * The Constant serialVersionUID. + */ + private static final long serialVersionUID = 3356247357827709530L; + + // affine transform of this TransformAttribute instance + /** + * The transform. + */ + private AffineTransform fTransform; + + /** + * Instantiates a new TransformAttribute from the specified AffineTransform. + * + * @param transform + * the AffineTransform to be wrapped. + */ + public TransformAttribute(AffineTransform transform) { + if (transform == null) { + // awt.94=transform can not be null + throw new IllegalArgumentException(Messages.getString("awt.94")); //$NON-NLS-1$ + } + if (!transform.isIdentity()) { + this.fTransform = new AffineTransform(transform); + } + } + + /** + * Gets the initial AffineTransform which is wrapped. + * + * @return the initial AffineTransform which is wrapped. + */ + public AffineTransform getTransform() { + if (fTransform != null) { + return new AffineTransform(fTransform); + } + return new AffineTransform(); + } + + /** + * Checks if this transform is an identity transform. + * + * @return true, if this transform is an identity transform, false + * otherwise. + */ + public boolean isIdentity() { + return (fTransform == null); + } + +} diff --git a/awt/java/awt/font/package.html b/awt/java/awt/font/package.html new file mode 100644 index 0000000..788dcc0 --- /dev/null +++ b/awt/java/awt/font/package.html @@ -0,0 +1,8 @@ +<html> + <body> + <p> + This package contains classes to support the representation of different types of fonts for example TrueType fonts. + </p> + @since Android 1.0 + </body> +</html> |