3310 lines · 121.6 KB · Java
RawDownload
            double widthsquared;            if ((transform.getType() & NON_UNIFORM_SCALE_MASK) == 0) {                /* sqrt omitted, compare to squared limits below. */                widthsquared = Math.abs(transform.getDeterminant());            } else {                /* First calculate the "maximum scale" of this transform. */                double A = transform.getScaleX();       // m00                double C = transform.getShearX();       // m01                double B = transform.getShearY();       // m10                double D = transform.getScaleY();       // m11                 /*                 * Given a 2 x 2 affine matrix [ A B ] such that                 *                             [ C D ]                 * v' = [x' y'] = [Ax + Cy, Bx + Dy], we want to                 * find the maximum magnitude (norm) of the vector v'                 * with the constraint (x^2 + y^2 = 1).                 * The equation to maximize is                 *     |v'| = sqrt((Ax+Cy)^2+(Bx+Dy)^2)                 * or  |v'| = sqrt((AA+BB)x^2 + 2(AC+BD)xy + (CC+DD)y^2).                 * Since sqrt is monotonic we can maximize |v'|^2                 * instead and plug in the substitution y = sqrt(1 - x^2).                 * Trigonometric equalities can then be used to get                 * rid of most of the sqrt terms.                 */                double EA = A*A + B*B;          // x^2 coefficient                double EB = 2*(A*C + B*D);      // xy coefficient                double EC = C*C + D*D;          // y^2 coefficient                 /*                 * There is a lot of calculus omitted here.                 *                 * Conceptually, in the interests of understanding the                 * terms that the calculus produced we can consider                 * that EA and EC end up providing the lengths along                 * the major axes and the hypot term ends up being an                 * adjustment for the additional length along the off-axis                 * angle of rotated or sheared ellipses as well as an                 * adjustment for the fact that the equation below                 * averages the two major axis lengths.  (Notice that                 * the hypot term contains a part which resolves to the                 * difference of these two axis lengths in the absence                 * of rotation.)                 *                 * In the calculus, the ratio of the EB and (EA-EC) terms                 * ends up being the tangent of 2*theta where theta is                 * the angle that the long axis of the ellipse makes                 * with the horizontal axis.  Thus, this equation is                 * calculating the length of the hypotenuse of a triangle                 * along that axis.                 */                double hypot = Math.sqrt(EB*EB + (EA-EC)*(EA-EC));                 /* sqrt omitted, compare to squared limits below. */                widthsquared = ((EA + EC + hypot)/2.0);            }            if (bs != defaultStroke) {                widthsquared *= bs.getLineWidth() * bs.getLineWidth();            }            if (widthsquared <=                (aa ? MinPenSizeAASquared : MinPenSizeSquared))            {                if (bs.getDashArray() == null) {                    strokeState = STROKE_THIN;                } else {                    strokeState = STROKE_THINDASHED;                }            } else {                strokeState = STROKE_WIDE;            }        }    }     /*     * Sets the Stroke in the current graphics state.     * @param s The Stroke object to be used to stroke a Path in     * the rendering process.     * @see BasicStroke     */    public void setStroke(Stroke s) {        if (s == null) {            throw new IllegalArgumentException("null Stroke");        }        int saveStrokeState = strokeState;        stroke = s;        if (s instanceof BasicStroke) {            validateBasicStroke((BasicStroke) s);        } else {            strokeState = STROKE_CUSTOM;        }        if (strokeState != saveStrokeState) {            invalidatePipe();        }    }     /**     * Sets the preferences for the rendering algorithms.     * Hint categories include controls for rendering quality and     * overall time/quality trade-off in the rendering process.     * @param hintKey The key of hint to be set. The strings are     * defined in the RenderingHints class.     * @param hintValue The value indicating preferences for the specified     * hint category. These strings are defined in the RenderingHints     * class.     * @see RenderingHints     */    public void setRenderingHint(Key hintKey, Object hintValue) {        // If we recognize the key, we must recognize the value        //     otherwise throw an IllegalArgumentException        //     and do not change the Hints object        // If we do not recognize the key, just pass it through        //     to the Hints object untouched        if (!hintKey.isCompatibleValue(hintValue)) {            throw new IllegalArgumentException                (hintValue+" is not compatible with "+hintKey);        }        if (hintKey instanceof SunHints.Key) {            boolean stateChanged;            boolean textStateChanged = false;            boolean recognized = true;            SunHints.Key sunKey = (SunHints.Key) hintKey;            int newHint;            if (sunKey == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST) {                newHint = ((Integer)hintValue).intValue();            } else {                newHint = ((SunHints.Value) hintValue).getIndex();            }            switch (sunKey.getIndex()) {            case SunHints.INTKEY_RENDERING:                stateChanged = (renderHint != newHint);                if (stateChanged) {                    renderHint = newHint;                    if (interpolationHint == -1) {                        interpolationType =                            (newHint == SunHints.INTVAL_RENDER_QUALITY                             ? AffineTransformOp.TYPE_BILINEAR                             : AffineTransformOp.TYPE_NEAREST_NEIGHBOR);                    }                }                break;            case SunHints.INTKEY_ANTIALIASING:                stateChanged = (antialiasHint != newHint);                antialiasHint = newHint;                if (stateChanged) {                    textStateChanged =                        (textAntialiasHint ==                         SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT);                    if (strokeState != STROKE_CUSTOM) {                        validateBasicStroke((BasicStroke) stroke);                    }                }                break;            case SunHints.INTKEY_TEXT_ANTIALIASING:                stateChanged = (textAntialiasHint != newHint);                textStateChanged = stateChanged;                textAntialiasHint = newHint;                break;            case SunHints.INTKEY_FRACTIONALMETRICS:                stateChanged = (fractionalMetricsHint != newHint);                textStateChanged = stateChanged;                fractionalMetricsHint = newHint;                break;            case SunHints.INTKEY_AATEXT_LCD_CONTRAST:                stateChanged = false;                /* Already have validated it is an int 100 <= newHint <= 250 */                lcdTextContrast = newHint;                break;            case SunHints.INTKEY_INTERPOLATION:                interpolationHint = newHint;                switch (newHint) {                case SunHints.INTVAL_INTERPOLATION_BICUBIC:                    newHint = AffineTransformOp.TYPE_BICUBIC;                    break;                case SunHints.INTVAL_INTERPOLATION_BILINEAR:                    newHint = AffineTransformOp.TYPE_BILINEAR;                    break;                default:                case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:                    newHint = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;                    break;                }                stateChanged = (interpolationType != newHint);                interpolationType = newHint;                break;            case SunHints.INTKEY_STROKE_CONTROL:                stateChanged = (strokeHint != newHint);                strokeHint = newHint;                break;            default:                recognized = false;                stateChanged = false;                break;            }            if (recognized) {                if (stateChanged) {                    invalidatePipe();                    if (textStateChanged) {                        fontMetrics = null;                        this.cachedFRC = null;                        validFontInfo = false;                        this.glyphVectorFontInfo = null;                    }                }                if (hints != null) {                    hints.put(hintKey, hintValue);                }                return;            }        }        // Nothing we recognize so none of "our state" has changed        if (hints == null) {            hints = makeHints(null);        }        hints.put(hintKey, hintValue);    }      /**     * Returns the preferences for the rendering algorithms.     * @param hintCategory The category of hint to be set. The strings     * are defined in the RenderingHints class.     * @return The preferences for rendering algorithms. The strings     * are defined in the RenderingHints class.     * @see RenderingHints     */    public Object getRenderingHint(Key hintKey) {        if (hints != null) {            return hints.get(hintKey);        }        if (!(hintKey instanceof SunHints.Key)) {            return null;        }        int keyindex = ((SunHints.Key)hintKey).getIndex();        switch (keyindex) {        case SunHints.INTKEY_RENDERING:            return SunHints.Value.get(SunHints.INTKEY_RENDERING,                                      renderHint);        case SunHints.INTKEY_ANTIALIASING:            return SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,                                      antialiasHint);        case SunHints.INTKEY_TEXT_ANTIALIASING:            return SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,                                      textAntialiasHint);        case SunHints.INTKEY_FRACTIONALMETRICS:            return SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,                                      fractionalMetricsHint);        case SunHints.INTKEY_AATEXT_LCD_CONTRAST:            return new Integer(lcdTextContrast);        case SunHints.INTKEY_INTERPOLATION:            switch (interpolationHint) {            case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:                return SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;            case SunHints.INTVAL_INTERPOLATION_BILINEAR:                return SunHints.VALUE_INTERPOLATION_BILINEAR;            case SunHints.INTVAL_INTERPOLATION_BICUBIC:                return SunHints.VALUE_INTERPOLATION_BICUBIC;            }            return null;        case SunHints.INTKEY_STROKE_CONTROL:            return SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,                                      strokeHint);        }        return null;    }     /**     * Sets the preferences for the rendering algorithms.     * Hint categories include controls for rendering quality and     * overall time/quality trade-off in the rendering process.     * @param hints The rendering hints to be set     * @see RenderingHints     */    public void setRenderingHints(Map<?,?> hints) {        this.hints = null;        renderHint = SunHints.INTVAL_RENDER_DEFAULT;        antialiasHint = SunHints.INTVAL_ANTIALIAS_OFF;        textAntialiasHint = SunHints.INTVAL_TEXT_ANTIALIAS_DEFAULT;        fractionalMetricsHint = SunHints.INTVAL_FRACTIONALMETRICS_OFF;        lcdTextContrast = lcdTextContrastDefaultValue;        interpolationHint = -1;        interpolationType = AffineTransformOp.TYPE_NEAREST_NEIGHBOR;        boolean customHintPresent = false;        Iterator iter = hints.keySet().iterator();        while (iter.hasNext()) {            Object key = iter.next();            if (key == SunHints.KEY_RENDERING ||                key == SunHints.KEY_ANTIALIASING ||                key == SunHints.KEY_TEXT_ANTIALIASING ||                key == SunHints.KEY_FRACTIONALMETRICS ||                key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST ||                key == SunHints.KEY_STROKE_CONTROL ||                key == SunHints.KEY_INTERPOLATION)            {                setRenderingHint((Key) key, hints.get(key));            } else {                customHintPresent = true;            }        }        if (customHintPresent) {            this.hints = makeHints(hints);        }        invalidatePipe();    }     /**     * Adds a number of preferences for the rendering algorithms.     * Hint categories include controls for rendering quality and     * overall time/quality trade-off in the rendering process.     * @param hints The rendering hints to be set     * @see RenderingHints     */    public void addRenderingHints(Map<?,?> hints) {        boolean customHintPresent = false;        Iterator iter = hints.keySet().iterator();        while (iter.hasNext()) {            Object key = iter.next();            if (key == SunHints.KEY_RENDERING ||                key == SunHints.KEY_ANTIALIASING ||                key == SunHints.KEY_TEXT_ANTIALIASING ||                key == SunHints.KEY_FRACTIONALMETRICS ||                key == SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST ||                key == SunHints.KEY_STROKE_CONTROL ||                key == SunHints.KEY_INTERPOLATION)            {                setRenderingHint((Key) key, hints.get(key));            } else {                customHintPresent = true;            }        }        if (customHintPresent) {            if (this.hints == null) {                this.hints = makeHints(hints);            } else {                this.hints.putAll(hints);            }        }    }     /**     * Gets the preferences for the rendering algorithms.     * Hint categories include controls for rendering quality and     * overall time/quality trade-off in the rendering process.     * @see RenderingHints     */    public RenderingHints getRenderingHints() {        if (hints == null) {            return makeHints(null);        } else {            return (RenderingHints) hints.clone();        }    }     RenderingHints makeHints(Map hints) {        RenderingHints model = new RenderingHints(hints);        model.put(SunHints.KEY_RENDERING,                  SunHints.Value.get(SunHints.INTKEY_RENDERING,                                     renderHint));        model.put(SunHints.KEY_ANTIALIASING,                  SunHints.Value.get(SunHints.INTKEY_ANTIALIASING,                                     antialiasHint));        model.put(SunHints.KEY_TEXT_ANTIALIASING,                  SunHints.Value.get(SunHints.INTKEY_TEXT_ANTIALIASING,                                     textAntialiasHint));        model.put(SunHints.KEY_FRACTIONALMETRICS,                  SunHints.Value.get(SunHints.INTKEY_FRACTIONALMETRICS,                                     fractionalMetricsHint));        model.put(SunHints.KEY_TEXT_ANTIALIAS_LCD_CONTRAST,                  Integer.valueOf(lcdTextContrast));        Object value;        switch (interpolationHint) {        case SunHints.INTVAL_INTERPOLATION_NEAREST_NEIGHBOR:            value = SunHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR;            break;        case SunHints.INTVAL_INTERPOLATION_BILINEAR:            value = SunHints.VALUE_INTERPOLATION_BILINEAR;            break;        case SunHints.INTVAL_INTERPOLATION_BICUBIC:            value = SunHints.VALUE_INTERPOLATION_BICUBIC;            break;        default:            value = null;            break;        }        if (value != null) {            model.put(SunHints.KEY_INTERPOLATION, value);        }        model.put(SunHints.KEY_STROKE_CONTROL,                  SunHints.Value.get(SunHints.INTKEY_STROKE_CONTROL,                                     strokeHint));        return model;    }     /**     * Concatenates the current transform of this Graphics2D with a     * translation transformation.     * This is equivalent to calling transform(T), where T is an     * AffineTransform represented by the following matrix:     * <pre>     *          [   1    0    tx  ]     *          [   0    1    ty  ]     *          [   0    0    1   ]     * </pre>     */    public void translate(double tx, double ty) {        transform.translate(tx, ty);        invalidateTransform();    }     /**     * Concatenates the current transform of this Graphics2D with a     * rotation transformation.     * This is equivalent to calling transform(R), where R is an     * AffineTransform represented by the following matrix:     * <pre>     *          [   cos(theta)    -sin(theta)    0   ]     *          [   sin(theta)     cos(theta)    0   ]     *          [       0              0         1   ]     * </pre>     * Rotating with a positive angle theta rotates points on the positive     * x axis toward the positive y axis.     * @param theta The angle of rotation in radians.     */    public void rotate(double theta) {        transform.rotate(theta);        invalidateTransform();    }     /**     * Concatenates the current transform of this Graphics2D with a     * translated rotation transformation.     * This is equivalent to the following sequence of calls:     * <pre>     *          translate(x, y);     *          rotate(theta);     *          translate(-x, -y);     * </pre>     * Rotating with a positive angle theta rotates points on the positive     * x axis toward the positive y axis.     * @param theta The angle of rotation in radians.     * @param x The x coordinate of the origin of the rotation     * @param y The x coordinate of the origin of the rotation     */    public void rotate(double theta, double x, double y) {        transform.rotate(theta, x, y);        invalidateTransform();    }     /**     * Concatenates the current transform of this Graphics2D with a     * scaling transformation.     * This is equivalent to calling transform(S), where S is an     * AffineTransform represented by the following matrix:     * <pre>     *          [   sx   0    0   ]     *          [   0    sy   0   ]     *          [   0    0    1   ]     * </pre>     */    public void scale(double sx, double sy) {        transform.scale(sx, sy);        invalidateTransform();    }     /**     * Concatenates the current transform of this Graphics2D with a     * shearing transformation.     * This is equivalent to calling transform(SH), where SH is an     * AffineTransform represented by the following matrix:     * <pre>     *          [   1   shx   0   ]     *          [  shy   1    0   ]     *          [   0    0    1   ]     * </pre>     * @param shx The factor by which coordinates are shifted towards the     * positive X axis direction according to their Y coordinate     * @param shy The factor by which coordinates are shifted towards the     * positive Y axis direction according to their X coordinate     */    public void shear(double shx, double shy) {        transform.shear(shx, shy);        invalidateTransform();    }     /**     * Composes a Transform object with the transform in this     * Graphics2D according to the rule last-specified-first-applied.     * If the currrent transform is Cx, the result of composition     * with Tx is a new transform Cx'.  Cx' becomes the current     * transform for this Graphics2D.     * Transforming a point p by the updated transform Cx' is     * equivalent to first transforming p by Tx and then transforming     * the result by the original transform Cx.  In other words,     * Cx'(p) = Cx(Tx(p)).     * A copy of the Tx is made, if necessary, so further     * modifications to Tx do not affect rendering.     * @param Tx The Transform object to be composed with the current     * transform.     * @see #setTransform     * @see AffineTransform     */

Lines 1001–1500 of 3310. Previous lines