3310 lines · 121.6 KB · Java
RawDownload
    public void transform(AffineTransform xform) {        this.transform.concatenate(xform);        invalidateTransform();    }     /**     * Translate     */    public void translate(int x, int y) {        transform.translate(x, y);        if (transformState <= TRANSFORM_INT_TRANSLATE) {            transX += x;            transY += y;            transformState = (((transX | transY) == 0) ?                              TRANSFORM_ISIDENT : TRANSFORM_INT_TRANSLATE);        } else {            invalidateTransform();        }    }     /**     * Sets the Transform in the current graphics state.     * @param Tx The Transform object to be used in the rendering process.     * @see #transform     * @see TransformChain     * @see AffineTransform     */    public void setTransform(AffineTransform Tx) {        if ((constrainX|constrainY) == 0) {            transform.setTransform(Tx);        } else {            transform.setToTranslation(constrainX, constrainY);            transform.concatenate(Tx);        }        invalidateTransform();    }     protected void invalidateTransform() {        int type = transform.getType();        int origTransformState = transformState;        if (type == AffineTransform.TYPE_IDENTITY) {            transformState = TRANSFORM_ISIDENT;            transX = transY = 0;        } else if (type == AffineTransform.TYPE_TRANSLATION) {            double dtx = transform.getTranslateX();            double dty = transform.getTranslateY();            transX = (int) Math.floor(dtx + 0.5);            transY = (int) Math.floor(dty + 0.5);            if (dtx == transX && dty == transY) {                transformState = TRANSFORM_INT_TRANSLATE;            } else {                transformState = TRANSFORM_ANY_TRANSLATE;            }        } else if ((type & (AffineTransform.TYPE_FLIP |                            AffineTransform.TYPE_MASK_ROTATION |                            AffineTransform.TYPE_GENERAL_TRANSFORM)) == 0)        {            transformState = TRANSFORM_TRANSLATESCALE;            transX = transY = 0;        } else {            transformState = TRANSFORM_GENERIC;            transX = transY = 0;        }         if (transformState >= TRANSFORM_TRANSLATESCALE ||            origTransformState >= TRANSFORM_TRANSLATESCALE)        {            /* Its only in this case that the previous or current transform             * was more than a translate that font info is invalidated             */            cachedFRC = null;            this.validFontInfo = false;            this.fontMetrics = null;            this.glyphVectorFontInfo = null;             if (transformState != origTransformState) {                invalidatePipe();            }        }        if (strokeState != STROKE_CUSTOM) {            validateBasicStroke((BasicStroke) stroke);        }    }     /**     * Returns the current Transform in the Graphics2D state.     * @see #transform     * @see #setTransform     */    public AffineTransform getTransform() {        if ((constrainX|constrainY) == 0) {            return new AffineTransform(transform);        }        AffineTransform tx =            AffineTransform.getTranslateInstance(-constrainX, -constrainY);        tx.concatenate(transform);        return tx;    }     /**     * Returns the current Transform ignoring the "constrain"     * rectangle.     */    public AffineTransform cloneTransform() {        return new AffineTransform(transform);    }     /**     * Returns the current Paint in the Graphics2D state.     * @see #setPaint     * @see java.awt.Graphics#setColor     */    public Paint getPaint() {        return paint;    }     /**     * Returns the current Composite in the Graphics2D state.     * @see #setComposite     */    public Composite getComposite() {        return composite;    }     public Color getColor() {        return foregroundColor;    }     /*     * Validate the eargb and pixel fields against the current color.     *     * The eargb field must take into account the extraAlpha     * value of an AlphaComposite.  It may also take into account     * the Fsrc Porter-Duff blending function if such a function is     * a constant (see handling of Clear mode below).  For instance,     * by factoring in the (Fsrc == 0) state of the Clear mode we can     * use a SrcNoEa loop just as easily as a general Alpha loop     * since the math will be the same in both cases.     *     * The pixel field will always be the best pixel data choice for     * the final result of all calculations applied to the eargb field.     *     * Note that this method is only necessary under the following     * conditions:     *     (paintState <= PAINT_ALPHA_COLOR &&     *      compositeState <= COMP_CUSTOM)     * though nothing bad will happen if it is run in other states.     */    final void validateColor() {        int eargb;        if (imageComp == CompositeType.Clear) {            eargb = 0;        } else {            eargb = foregroundColor.getRGB();            if (compositeState <= COMP_ALPHA &&                imageComp != CompositeType.SrcNoEa &&                imageComp != CompositeType.SrcOverNoEa)            {                AlphaComposite alphacomp = (AlphaComposite) composite;                int a = Math.round(alphacomp.getAlpha() * (eargb >>> 24));                eargb = (eargb & 0x00ffffff) | (a << 24);            }        }        this.eargb = eargb;        this.pixel = surfaceData.pixelFor(eargb);    }     public void setColor(Color color) {        if (color == null || color == paint) {            return;        }        this.paint = foregroundColor = color;        validateColor();        if ((eargb >> 24) == -1) {            if (paintState == PAINT_OPAQUECOLOR) {                return;            }            paintState = PAINT_OPAQUECOLOR;            if (imageComp == CompositeType.SrcOverNoEa) {                // special case where compState depends on opacity of paint                compositeState = COMP_ISCOPY;            }        } else {            if (paintState == PAINT_ALPHACOLOR) {                return;            }            paintState = PAINT_ALPHACOLOR;            if (imageComp == CompositeType.SrcOverNoEa) {                // special case where compState depends on opacity of paint                compositeState = COMP_ALPHA;            }        }        validFontInfo = false;        invalidatePipe();    }     /**     * Sets the background color in this context used for clearing a region.     * When Graphics2D is constructed for a component, the backgroung color is     * inherited from the component. Setting the background color in the     * Graphics2D context only affects the subsequent clearRect() calls and     * not the background color of the component. To change the background     * of the component, use appropriate methods of the component.     * @param color The background color that should be used in     * subsequent calls to clearRect().     * @see getBackground     * @see Graphics.clearRect()     */    public void setBackground(Color color) {        backgroundColor = color;    }     /**     * Returns the background color used for clearing a region.     * @see setBackground     */    public Color getBackground() {        return backgroundColor;    }     /**     * Returns the current Stroke in the Graphics2D state.     * @see setStroke     */    public Stroke getStroke() {        return stroke;    }     public Rectangle getClipBounds() {        Rectangle r;        if (clipState == CLIP_DEVICE) {            r = null;        } else if (transformState <= TRANSFORM_INT_TRANSLATE) {            if (usrClip instanceof Rectangle) {                r = new Rectangle((Rectangle) usrClip);            } else {                r = usrClip.getBounds();            }            r.translate(-transX, -transY);        } else {            r = getClip().getBounds();        }        return r;    }     public Rectangle getClipBounds(Rectangle r) {        if (clipState != CLIP_DEVICE) {            if (transformState <= TRANSFORM_INT_TRANSLATE) {                if (usrClip instanceof Rectangle) {                    r.setBounds((Rectangle) usrClip);                } else {                    r.setBounds(usrClip.getBounds());                }                r.translate(-transX, -transY);            } else {                r.setBounds(getClip().getBounds());            }        } else if (r == null) {            throw new NullPointerException("null rectangle parameter");        }        return r;    }     public boolean hitClip(int x, int y, int width, int height) {        if (width <= 0 || height <= 0) {            return false;        }        if (transformState > TRANSFORM_INT_TRANSLATE) {            // Note: Technically the most accurate test would be to            // raster scan the parallelogram of the transformed rectangle            // and do a span for span hit test against the clip, but for            // speed we approximate the test with a bounding box of the            // transformed rectangle.  The cost of rasterizing the            // transformed rectangle is probably high enough that it is            // not worth doing so to save the caller from having to call            // a rendering method where we will end up discovering the            // same answer in about the same amount of time anyway.            // This logic breaks down if this hit test is being performed            // on the bounds of a group of shapes in which case it might            // be beneficial to be a little more accurate to avoid lots            // of subsequent rendering calls.  In either case, this relaxed            // test should not be significantly less accurate than the            // optimal test for most transforms and so the conservative            // answer should not cause too much extra work.             double d[] = {                x, y,                x+width, y,                x, y+height,                x+width, y+height            };            transform.transform(d, 0, d, 0, 4);            x = (int) Math.floor(Math.min(Math.min(d[0], d[2]),                                          Math.min(d[4], d[6])));            y = (int) Math.floor(Math.min(Math.min(d[1], d[3]),                                          Math.min(d[5], d[7])));            width = (int) Math.ceil(Math.max(Math.max(d[0], d[2]),                                             Math.max(d[4], d[6])));            height = (int) Math.ceil(Math.max(Math.max(d[1], d[3]),                                              Math.max(d[5], d[7])));        } else {            x += transX;            y += transY;            width += x;            height += y;        }        if (!getCompClip().intersectsQuickCheckXYXY(x, y, width, height)) {            return false;        }        // REMIND: We could go one step further here and examine the        // non-rectangular clip shape more closely if there is one.        // Since the clip has already been rasterized, the performance        // penalty of doing the scan is probably still within the bounds        // of a good tradeoff between speed and quality of the answer.        return true;    }     protected void validateCompClip() {        int origClipState = clipState;        if (usrClip == null) {            clipState = CLIP_DEVICE;            clipRegion = devClip;        } else if (usrClip instanceof Rectangle2D) {            clipState = CLIP_RECTANGULAR;            if (usrClip instanceof Rectangle) {                clipRegion = devClip.getIntersection((Rectangle)usrClip);            } else {                clipRegion = devClip.getIntersection(usrClip.getBounds());            }        } else {            PathIterator cpi = usrClip.getPathIterator(null);            int box[] = new int[4];            ShapeSpanIterator sr = LoopPipe.getFillSSI(this);            try {                sr.setOutputArea(devClip);                sr.appendPath(cpi);                sr.getPathBox(box);                Region r = Region.getInstance(box);                r.appendSpans(sr);                clipRegion = r;                clipState =                    r.isRectangular() ? CLIP_RECTANGULAR : CLIP_SHAPE;            } finally {                sr.dispose();            }        }        if (origClipState != clipState &&            (clipState == CLIP_SHAPE || origClipState == CLIP_SHAPE))        {            validFontInfo = false;            invalidatePipe();        }    }     static final int NON_RECTILINEAR_TRANSFORM_MASK =        (AffineTransform.TYPE_GENERAL_TRANSFORM |         AffineTransform.TYPE_GENERAL_ROTATION);     protected Shape transformShape(Shape s) {        if (s == null) {            return null;        }        if (transformState > TRANSFORM_INT_TRANSLATE) {            return transformShape(transform, s);        } else {            return transformShape(transX, transY, s);        }    }     public Shape untransformShape(Shape s) {        if (s == null) {            return null;        }        if (transformState > TRANSFORM_INT_TRANSLATE) {            try {                return transformShape(transform.createInverse(), s);            } catch (NoninvertibleTransformException e) {                return null;            }        } else {            return transformShape(-transX, -transY, s);        }    }     protected static Shape transformShape(int tx, int ty, Shape s) {        if (s == null) {            return null;        }         if (s instanceof Rectangle) {            Rectangle r = s.getBounds();            r.translate(tx, ty);            return r;        }        if (s instanceof Rectangle2D) {            Rectangle2D rect = (Rectangle2D) s;            return new Rectangle2D.Double(rect.getX() + tx,                                          rect.getY() + ty,                                          rect.getWidth(),                                          rect.getHeight());        }         if (tx == 0 && ty == 0) {            return cloneShape(s);        }         AffineTransform mat = AffineTransform.getTranslateInstance(tx, ty);        return mat.createTransformedShape(s);    }     protected static Shape transformShape(AffineTransform tx, Shape clip) {        if (clip == null) {            return null;        }         if (clip instanceof Rectangle2D &&            (tx.getType() & NON_RECTILINEAR_TRANSFORM_MASK) == 0)        {            Rectangle2D rect = (Rectangle2D) clip;            double matrix[] = new double[4];            matrix[0] = rect.getX();            matrix[1] = rect.getY();            matrix[2] = matrix[0] + rect.getWidth();            matrix[3] = matrix[1] + rect.getHeight();            tx.transform(matrix, 0, matrix, 0, 2);            rect = new Rectangle2D.Float();            rect.setFrameFromDiagonal(matrix[0], matrix[1],                                      matrix[2], matrix[3]);            return rect;        }         if (tx.isIdentity()) {            return cloneShape(clip);        }         return tx.createTransformedShape(clip);    }     public void clipRect(int x, int y, int w, int h) {        clip(new Rectangle(x, y, w, h));    }     public void setClip(int x, int y, int w, int h) {        setClip(new Rectangle(x, y, w, h));    }     public Shape getClip() {        return untransformShape(usrClip);    }     public void setClip(Shape sh) {        usrClip = transformShape(sh);        validateCompClip();    }     /**     * Intersects the current clip with the specified Path and sets the     * current clip to the resulting intersection. The clip is transformed     * with the current transform in the Graphics2D state before being     * intersected with the current clip. This method is used to make the     * current clip smaller. To make the clip larger, use any setClip method.     * @param p The Path to be intersected with the current clip.     */    public void clip(Shape s) {        s = transformShape(s);        if (usrClip != null) {            s = intersectShapes(usrClip, s, true, true);        }        usrClip = s;        validateCompClip();    }     public void setPaintMode() {        setComposite(AlphaComposite.SrcOver);    }     public void setXORMode(Color c) {        if (c == null) {            throw new IllegalArgumentException("null XORColor");        }        setComposite(new XORComposite(c, surfaceData));    }     Blit lastCAblit;    Composite lastCAcomp;     public void copyArea(int x, int y, int w, int h, int dx, int dy) {        try {            doCopyArea(x, y, w, h, dx, dy);        } catch (InvalidPipeException e) {            revalidateAll();            try {                doCopyArea(x, y, w, h, dx, dy);            } catch (InvalidPipeException e2) {                // Still catching the exception; we are not yet ready to                // validate the surfaceData correctly.  Fail for now and                // try again next time around.            }        } finally {            surfaceData.markDirty();

Lines 1501–2000 of 3310. Previous lines