| /* ZonePathIterator.java -- A PathIterator over glyph zones. |
| Copyright (C) 2006 Free Software Foundation, Inc. |
| |
| This file is part of GNU Classpath. |
| |
| GNU Classpath is free software; you can redistribute it and/or modify |
| it under the terms of the GNU General Public License as published by |
| the Free Software Foundation; either version 2, or (at your option) |
| any later version. |
| |
| GNU Classpath is distributed in the hope that it will be useful, but |
| WITHOUT ANY WARRANTY; without even the implied warranty of |
| MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| General Public License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GNU Classpath; see the file COPYING. If not, write to the |
| Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
| 02110-1301 USA. |
| |
| Linking this library statically or dynamically with other modules is |
| making a combined work based on this library. Thus, the terms and |
| conditions of the GNU General Public License cover the whole |
| combination. |
| |
| As a special exception, the copyright holders of this library give you |
| permission to link this library with independent modules to produce an |
| executable, regardless of the license terms of these independent |
| modules, and to copy and distribute the resulting executable under |
| terms of your choice, provided that you also meet, for each linked |
| independent module, the terms and conditions of the license of that |
| module. An independent module is a module which is not derived from |
| or based on this library. If you modify this library, you may extend |
| this exception to your version of the library, but you are not |
| obligated to do so. If you do not wish to do so, delete this |
| exception statement from your version. */ |
| |
| package gnu.java.awt.font.opentype.truetype; |
| |
| import java.awt.geom.PathIterator; |
| |
| |
| /** |
| * A PathIterator that enumerates the non-phantom points in a zone. |
| * |
| * <p><b>Lack of thread safety:</b> Instances of this class are |
| * <i>not</i> safe to access from multiple concurrent threads. |
| * |
| * @see Zone |
| * |
| * @author Sascha Brawer (brawer@dandelis.ch) |
| */ |
| final class ZonePathIterator |
| implements PathIterator |
| { |
| /** |
| * If <code>state</code> has this value, <code>currentSegment</code> |
| * will emit a <code>SEG_LINETO</code> or <code>SEG_QUADTO</code> segment |
| * to the current point. For a discussion of subtleties of on-curve |
| * and off-curve points, please refer to the documentation for |
| * {@link #getSegment}. |
| */ |
| private static final int EMIT_SEGMENT = 0; |
| |
| |
| /** |
| * If <code>state</code> has this value, <code>currentSegment</code> |
| * will emit a <code>SEG_CLOSE</code> in order to close the sub-path |
| * for the current contour. |
| */ |
| private static final int EMIT_CLOSE = 1; |
| |
| |
| /** |
| * If <code>state</code> has this value, <code>currentSegment</code> |
| * will emit a <code>SEG_MOVETO</code> segment to the first point in |
| * the current contour. If the first point is off-curve, a suitable |
| * on-curve point is calculated. |
| * |
| * @see #getStartSegment |
| */ |
| private static final int EMIT_MOVETO = 2; |
| |
| |
| /** |
| * The state of the iterator, which is one of |
| * <code>EMIT_SEGMENT</code>, <code>EMIT_CLOSE</code>, or |
| * <code>EMIT_MOVETO</code>. |
| */ |
| private int state; |
| |
| |
| |
| /** |
| * The zone whose segments are enumerated by this iterator. |
| */ |
| private Zone zone; |
| |
| |
| /** |
| * The total number of points in the zone, not including the four |
| * phantom points at its end. |
| */ |
| private int numPoints; |
| |
| |
| /** |
| * The number of the current point. |
| */ |
| private int curPoint; |
| |
| |
| /** |
| * The number of the first point in the current contour. |
| */ |
| private int contourStart; |
| |
| |
| |
| /** |
| * Constructs a ZonePathIterator for the specified zone. |
| * |
| * @param zone the zone whose segments will be enumerated |
| * by this iterator. |
| */ |
| ZonePathIterator(Zone zone) |
| { |
| this.zone = zone; |
| numPoints = zone.getSize() - /* four phantom points */ 4; |
| |
| // The first segment that needs to be emitted is a SEG_MOVETO. |
| state = EMIT_MOVETO; |
| } |
| |
| |
| /** |
| * Returns the winding rule. TrueType glyphs always use the non-zero |
| * winding rule, so this method will always return {@link |
| * PathIterator#WIND_NON_ZERO}. |
| */ |
| public int getWindingRule() |
| { |
| return PathIterator.WIND_NON_ZERO; |
| } |
| |
| |
| |
| public boolean isDone() |
| { |
| return (state != EMIT_CLOSE) && (curPoint >= numPoints); |
| } |
| |
| |
| public void next() |
| { |
| boolean onCurve; |
| |
| /* If the current point is the end of a segment, and no SEG_CLOSE |
| * has been emitted yet, this will be the next segment. |
| */ |
| if (zone.isContourEnd(curPoint) && (state != EMIT_CLOSE)) |
| { |
| state = EMIT_CLOSE; |
| return; |
| } |
| |
| /* If the previously emitted segment was a SEG_CLOSE, we are now |
| * at the beginning of a new contour. |
| */ |
| if (state == EMIT_CLOSE) |
| { |
| contourStart = ++curPoint; |
| state = EMIT_MOVETO; |
| return; |
| } |
| |
| onCurve = zone.isOnCurve(curPoint); |
| |
| /* If the last segment was a moveto, and the current point |
| * (which is the first point in the contour) is off-curve, |
| * we need to emit a quadto segment for the first point. |
| */ |
| if ((state == EMIT_MOVETO) && !onCurve) |
| { |
| state = EMIT_SEGMENT; |
| return; |
| } |
| |
| |
| curPoint++; |
| |
| /* If the last point has been off-curve, and the now current |
| * point is on-curve, the last segment was a quadto that |
| * had the now current point at its end. In this case, we can |
| * skip a segment. |
| */ |
| if (!onCurve && zone.isOnCurve(curPoint)) |
| { |
| /* But if the skipped point is the end of a contour, we must not |
| * skip the SEG_CLOSE. An example where this matters is the 'o' |
| * glyph in the Helvetica font face that comes with MacOS X |
| * 10.1.5. |
| */ |
| if (zone.isContourEnd(curPoint)) |
| { |
| state = EMIT_CLOSE; |
| return; |
| } |
| |
| curPoint++; |
| } |
| |
| state = EMIT_SEGMENT; |
| } |
| |
| |
| /** |
| * Determines the successor of the current point in the current |
| * contour. The successor of the last point in a contour is the |
| * start of that contour. |
| * |
| * @return the number of the point that follows the current point in |
| * the same contour. |
| */ |
| private int getSuccessor(int p) |
| { |
| if (zone.isContourEnd(p)) |
| return contourStart; |
| else |
| return p + 1; |
| } |
| |
| |
| |
| /** |
| * Retrieves the current path segment using single-precision |
| * coordinate values. |
| */ |
| public int currentSegment(float[] coords) |
| { |
| switch (state) |
| { |
| case EMIT_CLOSE: |
| return PathIterator.SEG_CLOSE; |
| |
| case EMIT_MOVETO: |
| return getStartSegment(curPoint, coords); |
| |
| default: |
| return getSegment(curPoint, coords); |
| } |
| } |
| |
| |
| /** |
| * A helper array that is used by {@link |
| * #currentSegment(double[])}. |
| */ |
| float[] floats; |
| |
| |
| /** |
| * Retrieves the current path segment using double-precision |
| * coordinate values. |
| */ |
| public int currentSegment(double[] coords) |
| { |
| if (floats == null) |
| floats = new float[6]; |
| int result; |
| |
| result = currentSegment(floats); |
| for (int i = 0; i < 6; i++) |
| coords[i] = floats[i]; |
| return result; |
| } |
| |
| |
| /** |
| * Returns the segment for the specified point. |
| * |
| * <p><img src="doc-files/ZonePathIterator-1.png" width="426" |
| * height="194" alt="An example curve" /></p> |
| * |
| * <p>If <code>cur</code> is an on-curve point, the returned segment |
| * is a straight line to <code>cur</code>. In the illustration, this |
| * would be the case for <code>cur = 4</code>.</p> |
| * |
| * <p>If <code>cur</code> is an off-curve point, and |
| * <code>cur</code>’s successor <code>succ</code> is also |
| * off-curve, the returned segment is a quadratic Bézier |
| * spline whose control point is <code>cur</code>, and whose end |
| * point is located at the middle of the line connecting |
| * <code>cur</code> and <code>succ</code>. In the illustration, |
| * this would be the case for <code>cur = 5</code>.</p> |
| * |
| * <p>If <code>cur</code> is an off-curve point, and |
| * <code>cur</code>’s successor <code>succ</code> is |
| * on-curve, the returned segment is a quadratic Bézier |
| * spline whose control point is <code>cur</code>, and whose end |
| * point is <code>succ</code>. In the illustration, this would |
| * be the case for <code>cur = 6</code>.</p> |
| * |
| * @return either <code>PathIterator.SEG_LINETO</code> or |
| * <code>PathIterator.SEG_QUADTO</code>. |
| */ |
| private int getSegment(int cur, float[] coords) |
| { |
| int curX, curY; |
| int succ, succX, succY; |
| |
| curX = zone.getX(cur); |
| curY = zone.getY(cur); |
| coords[0] = Fixed.floatValue(curX); |
| coords[1] = Fixed.floatValue(curY); |
| |
| if (zone.isOnCurve(cur)) |
| return PathIterator.SEG_LINETO; |
| |
| succ = getSuccessor(cur); |
| succX = zone.getX(succ); |
| succY = zone.getY(succ); |
| |
| if (zone.isOnCurve(succ)) |
| { |
| coords[2] = Fixed.floatValue(succX); |
| coords[3] = Fixed.floatValue(succY); |
| } |
| else |
| { |
| coords[2] = Fixed.floatValue((curX + succX) / 2); |
| coords[3] = Fixed.floatValue((curY + succY) / 2); |
| } |
| return PathIterator.SEG_QUADTO; |
| } |
| |
| |
| /** |
| * Returns the start segment for the contour which starts |
| * at the specified point. |
| * |
| * <p>If the contour starts with an on-curve point, the returned |
| * segment is a <code>SEG_MOVETO</code> to that point.</p> |
| * |
| * <p>If the contour starts with an off-curve point, and the contour |
| * ends with an on-curve point, the returned segment is a |
| * <code>SEG_MOVETO</code> to the end point.</p> |
| * |
| * <p>If the contour starts with an off-curve point, and the contour |
| * also ends with an off-curve point, the returned segment is a |
| * <code>SEG_MOVETO</code> to the location at the middle between the |
| * start and end points of the contour.</p> |
| * |
| * @return <code>PathIterator.SEG_MOVETO</code>. |
| */ |
| private int getStartSegment(int contourStart, float[] coords) |
| { |
| int x, y; |
| |
| if (zone.isOnCurve(contourStart)) |
| { |
| x = zone.getX(contourStart); |
| y = zone.getY(contourStart); |
| } |
| else |
| { |
| /* Find the last point of the current contour. */ |
| int contourEnd = contourStart; |
| while (!zone.isContourEnd(contourEnd)) |
| ++contourEnd; |
| |
| if (zone.isOnCurve(contourEnd)) |
| { |
| /* An example is the 'o' glyph of the Helvetica which comes |
| * with Apple MacOS X 10.1.5. |
| */ |
| x = zone.getX(contourEnd); |
| y = zone.getY(contourEnd); |
| } |
| else |
| { |
| x = (zone.getX(contourStart) + zone.getX(contourEnd)) / 2; |
| y = (zone.getY(contourStart) + zone.getY(contourEnd)) / 2; |
| } |
| } |
| |
| coords[0] = Fixed.floatValue(x); |
| coords[1] = Fixed.floatValue(y); |
| return PathIterator.SEG_MOVETO; |
| } |
| } |