2362N/A * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 0N/A * This code is free software; you can redistribute it and/or modify it 0N/A * under the terms of the GNU General Public License version 2 only, as 0N/A * published by the Free Software Foundation. Oracle designates this 0N/A * particular file as subject to the "Classpath" exception as provided 0N/A * by Oracle in the LICENSE file that accompanied this code. 0N/A * This code is distributed in the hope that it will be useful, but WITHOUT 0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 0N/A * version 2 for more details (a copy is included in the LICENSE file that 0N/A * accompanied this code). 0N/A * You should have received a copy of the GNU General Public License version 0N/A * 2 along with this work; if not, write to the Free Software Foundation, 2362N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 0N/A * or visit www.oracle.com if you need additional information or have any 0N/A * The <code>Dasher</code> class takes a series of linear commands 0N/A * (<code>moveTo</code>, <code>lineTo</code>, <code>close</code> and * <code>end</code>) and breaks them into smaller segments according to a * dash pattern array and a starting dash phase. * <p> Issues: in J2Se, a zero length dash segment as drawn as a very * short dash, whereas Pisces does not draw anything. The PostScript private final float[]
dash;
// temporary storage for the current curve * Constructs a <code>Dasher</code>. * @param out an output <code>PathConsumer2D</code>. * @param dash an array of <code>float</code>s containing the dash pattern * @param phase a <code>float</code> containing the dash phase // Normalize so 0 <= phase < dash[0] // we need curCurvepts to be able to contain 2 curves because when // dashing curves, we need to subdivide it // We don't emit the first dash right away. If we did, caps would be // drawn on it, but we need joins to be drawn if there's a closePath() // So, we store the path elements that make up the first dash in the // precondition: pts must be in relative coordinates (relative to x0,y0) // fullCurve is true iff the curve in pts has not been split. // The scaling factors needed to get the dx and dy of the // transformed dash segments. // Advance phase within current dash segment // Advance to next dash segment // preconditions: curCurvepts must be an array of length at least 2 * type, // that contains the curve we want to dash in the first type elements int curCurveoff =
0;
// initially the current curve is at curCurvepts[0...type] // Advance to next dash segment for (
int i =
2; i <
type; i++) {
// Objects of this class are used to iterate through curves. They return // t values where the left side of the curve has a specified length. // It does this by subdividing the input curve until a certain error // condition has been met. A recursive subdivision procedure would // return as many as 1<<limit curves, but this is an iterator and we // don't need all the curves all at once, so what we carry out a // lazy inorder traversal of the recursion tree (meaning we only move // through the tree when we need the next subdivided curve). This saves // us a lot of memory because at any one time we only need to store // limit+1 curves - one for each level of the tree + 1. // NOTE: the way we do things here is not enough to traverse a general // tree; however, the trees we are interested in have the property that // every non leaf node has exactly 2 children // Holds the curves at various levels of the recursion. The root // (i.e. the original curve) is at recCurveStack[0] (but then it // gets subdivided, the left half is put at 1, so most of the time // only the right half of the original curve is at 0) // sides[i] indicates whether the node at level i+1 in the path from // the root to the current leaf is a left or right child of its parent. // lastT and nextT delimit the current leaf. // the current level in the recursion tree. 0 is the root. limit // is the deepest possible leaf. // the lengths of the lines of the control polygon. Only its first // curveType/2 - 1 elements are valid. This is an optimization. See // next(float) for more detail. // if any methods are called without first initializing this object on // a curve, we want it to fail ASAP. goLeft();
// initializes nextT and lenAtNextT properly // the root of the tree is a leaf so we're done. // 0 == false, 1 == true, -1 == invalid cached value. // the test below is equivalent to !within(len1/len2, 1, err). // It is using a multiplication instead of a division, so it // should be a bit faster. // if len1 is close to 2 and 2 is close to 3, that probably // means 1 is close to 3 so the second part of this test might // not be needed, but it doesn't hurt to include it. // caches the coefficients of the current leaf in its flattened // form (see inside next() for what that means). The cache is // invalid when it's third element is negative, since in any // valid flattened curve, this would be >= 0. // returns the t value where the remaining curve should be split in // order for the left subdivided curve to have length len. If len // is >= than the length of the uniterated curve, it returns 1. public float next(
final float len) {
// cubicRootsInAB is a fairly expensive call, so we just don't do it // if the acceleration in this section of the curve is small enough. // We flatten the current leaf along the x axis, so that we're // left with a, b, c which define a 1D Bezier curve. We then // solve this to get the parameter of the original leaf that // gives us the desired length. // we use cubicRootsInAB here, because we want only roots in 0, 1, // and our quadratic root finder doesn't filter, so it's just a // matter of convenience. // t is relative to the current leaf, so we must make it a valid parameter // of the original curve. // even if done = true, if we're here, that means targetLength // is equal to, or very, very close to the total length of the // curve, so lastSegLen won't be too high. In cases where len // overshoots the curve, this method will exit in the while // loop, and lastSegLen will still be set to the right value. // go to the next leaf (in an inorder traversal) in the recursion tree // preconditions: must be on a leaf, and that leaf must not be the root. // We must go to the first ancestor node that has an unvisited // go to the leftmost node from the current node. Return its length. // this is a bit of a hack. It returns -1 if we're not on a leaf, and // the length of the leaf if we are on a leaf. throw new InternalError(
"Dasher does not use a native consumer");