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 Load more
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();