diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index f6d7b3a0243ae..c75e1b6a23d7b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -18,7 +18,7 @@ package android.graphics; import com.android.layoutlib.bridge.Bridge; import com.android.layoutlib.bridge.impl.DelegateManager; -import com.android.layoutlib.bridge.impl.Stack; +import com.android.layoutlib.bridge.impl.GcSnapshot; import android.graphics.Paint_Delegate.FontInfo; import android.text.TextUtils; @@ -26,7 +26,6 @@ import android.text.TextUtils; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Composite; import java.awt.Graphics2D; import java.awt.Rectangle; import java.awt.RenderingHints; @@ -58,7 +57,7 @@ public class Canvas_Delegate { // ---- delegate data ---- private BufferedImage mBufferedImage; - private final Stack mGraphicsStack = new Stack(); + private GcSnapshot mSnapshot = new GcSnapshot(); // ---- Public Helper methods ---- @@ -79,8 +78,8 @@ public class Canvas_Delegate { /** * Returns the current {@link Graphics2D} used to draw. */ - public Graphics2D getGraphics2d() { - return mGraphicsStack.peek(); + public GcSnapshot getGcSnapshot() { + return mSnapshot; } // ---- native methods ---- @@ -120,7 +119,7 @@ public class Canvas_Delegate { return; } - canvasDelegate.getGraphics2d().translate(dx, dy); + canvasDelegate.getGcSnapshot().translate(dx, dy); } /*package*/ static void rotate(Canvas thisCanvas, float degrees) { @@ -131,7 +130,7 @@ public class Canvas_Delegate { return; } - canvasDelegate.getGraphics2d().rotate(Math.toRadians(degrees)); + canvasDelegate.getGcSnapshot().rotate(Math.toRadians(degrees)); } /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) { @@ -142,7 +141,7 @@ public class Canvas_Delegate { return; } - canvasDelegate.getGraphics2d().scale(sx, sy); + canvasDelegate.getGcSnapshot().scale(sx, sy); } /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) { @@ -154,7 +153,7 @@ public class Canvas_Delegate { } // get the current top graphics2D object. - Graphics2D g = canvasDelegate.getGraphics2d(); + GcSnapshot g = canvasDelegate.getGcSnapshot(); // get its current matrix AffineTransform currentTx = g.getTransform(); @@ -170,21 +169,16 @@ public class Canvas_Delegate { } /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) { - return clipRect(thisCanvas, - (int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom); + return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom); } /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) { - return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom); + return clipRect(thisCanvas, (float) rect.left, (float) rect.top, + (float) rect.right, (float) rect.bottom); } /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right, float bottom) { - return clipRect(thisCanvas, (int) left, (int) top, (int) right, (int) bottom); - } - - /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right, - int bottom) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); if (canvasDelegate == null) { @@ -195,7 +189,17 @@ public class Canvas_Delegate { return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt); } + /*package*/ static boolean clipRect(Canvas thisCanvas, int left, int top, int right, + int bottom) { + + return clipRect(thisCanvas, (float) left, (float) top, (float) right, (float) bottom); + } + /*package*/ static int save(Canvas thisCanvas) { + return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG); + } + + /*package*/ static int save(Canvas thisCanvas, int saveFlags) { // get the delegate from the native int. Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas); if (canvasDelegate == null) { @@ -203,21 +207,7 @@ public class Canvas_Delegate { return 0; } - // get the current save count - int count = canvasDelegate.mGraphicsStack.size(); - - // create a new graphics and add it to the stack - Graphics2D g = (Graphics2D)canvasDelegate.getGraphics2d().create(); - canvasDelegate.mGraphicsStack.push(g); - - // return the old save count - return count; - - } - - /*package*/ static int save(Canvas thisCanvas, int saveFlags) { - // FIXME implement save(flags) - return save(thisCanvas); + return canvasDelegate.save(saveFlags); } /*package*/ static void restore(Canvas thisCanvas) { @@ -228,7 +218,7 @@ public class Canvas_Delegate { return; } - canvasDelegate.mGraphicsStack.pop(); + canvasDelegate.restore(); } /*package*/ static int getSaveCount(Canvas thisCanvas) { @@ -239,7 +229,7 @@ public class Canvas_Delegate { return 0; } - return canvasDelegate.mGraphicsStack.size(); + return canvasDelegate.getGcSnapshot().size(); } /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) { @@ -250,9 +240,7 @@ public class Canvas_Delegate { return; } - while (canvasDelegate.mGraphicsStack.size() > saveCount) { - canvasDelegate.mGraphicsStack.pop(); - } + canvasDelegate.restoreTo(saveCount); } /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count, @@ -282,7 +270,7 @@ public class Canvas_Delegate { } // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); + Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate); try { for (int i = 0 ; i < count ; i += 4) { @@ -378,10 +366,10 @@ public class Canvas_Delegate { } // get the current top graphics2D object. - Graphics2D g = canvasDelegate.getGraphics2d(); + GcSnapshot snapshot = canvasDelegate.getGcSnapshot(); // get its current matrix - AffineTransform currentTx = g.getTransform(); + AffineTransform currentTx = snapshot.getTransform(); // get the AffineTransform of the given matrix AffineTransform matrixTx = matrixDelegate.getAffineTransform(); @@ -389,7 +377,7 @@ public class Canvas_Delegate { currentTx.preConcatenate(matrixTx); // give it to the graphics2D as a new matrix replacing all previous transform - g.setTransform(currentTx); + snapshot.setTransform(currentTx); } /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) { @@ -405,15 +393,16 @@ public class Canvas_Delegate { } // get the current top graphics2D object. - Graphics2D g = canvasDelegate.getGraphics2d(); + GcSnapshot snapshot = canvasDelegate.getGcSnapshot(); // get the AffineTransform of the given matrix AffineTransform matrixTx = matrixDelegate.getAffineTransform(); // give it to the graphics2D as a new matrix replacing all previous transform - g.setTransform(matrixTx); + snapshot.setTransform(matrixTx); if (matrixDelegate.hasPerspective()) { + assert false; Bridge.getLog().warning(null, "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " + "supports affine transformations in the Layout Preview."); @@ -431,9 +420,7 @@ public class Canvas_Delegate { assert false; } - return canvasDelegate.clipRect( - (int) left, (int) top, (int) right, (int) bottom, - regionOp); + return canvasDelegate.clipRect(left, top, right, bottom, regionOp); } /*package*/ static boolean native_clipPath(int nativeCanvas, @@ -465,7 +452,7 @@ public class Canvas_Delegate { return false; } - Rectangle rect = canvasDelegate.getGraphics2d().getClipBounds(); + Rectangle rect = canvasDelegate.getGcSnapshot().getClip().getBounds(); if (rect != null) { bounds.left = rect.x; bounds.top = rect.y; @@ -527,7 +514,7 @@ public class Canvas_Delegate { } // get a new graphics context. - Graphics2D graphics = (Graphics2D)canvasDelegate.getGraphics2d().create(); + Graphics2D graphics = (Graphics2D)canvasDelegate.getGcSnapshot().create(); try { // reset its transform just in case graphics.setTransform(new AffineTransform()); @@ -568,12 +555,14 @@ public class Canvas_Delegate { } // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); + Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate); - g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); - - // dispose Graphics2D object - g.dispose(); + try { + g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY); + } finally { + // dispose Graphics2D object + g.dispose(); + } } /*package*/ static void native_drawRect(int nativeCanvas, RectF rect, @@ -600,23 +589,25 @@ public class Canvas_Delegate { if (right > left && bottom > top) { // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); + Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate); - int style = paintDelegate.getStyle(); + try { + int style = paintDelegate.getStyle(); - // draw - if (style == Paint.Style.FILL.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - g.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); + // draw + if (style == Paint.Style.FILL.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + g.fillRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); + } + + if (style == Paint.Style.STROKE.nativeInt || + style == Paint.Style.FILL_AND_STROKE.nativeInt) { + g.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); + } + } finally { + // dispose Graphics2D object + g.dispose(); } - - if (style == Paint.Style.STROKE.nativeInt || - style == Paint.Style.FILL_AND_STROKE.nativeInt) { - g.drawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top)); - } - - // dispose Graphics2D object - g.dispose(); } } @@ -638,7 +629,7 @@ public class Canvas_Delegate { if (oval.right > oval.left && oval.bottom > oval.top) { // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); + Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate); int style = paintDelegate.getStyle(); @@ -692,7 +683,7 @@ public class Canvas_Delegate { if (rect.right > rect.left && rect.bottom > rect.top) { // get a Graphics2D object configured with the drawing parameters. - Graphics2D g = canvasDelegate.getCustomGraphics(paintDelegate); + Graphics2D g = canvasDelegate.createCustomGraphics(paintDelegate); int style = paintDelegate.getStyle(); @@ -833,7 +824,7 @@ public class Canvas_Delegate { return; } - Graphics2D g = (Graphics2D) canvasDelegate.getCustomGraphics(paintDelegate); + Graphics2D g = (Graphics2D) canvasDelegate.createCustomGraphics(paintDelegate); try { // Paint.TextAlign indicates how the text is positioned relative to X. // LEFT is the default and there's nothing to do. @@ -1018,34 +1009,53 @@ public class Canvas_Delegate { * Disposes of the {@link Graphics2D} stack. */ private void dispose() { - while (mGraphicsStack.size() > 0) { - mGraphicsStack.pop().dispose(); - } + mSnapshot.dispose(); } - private boolean clipRect(int left, int top, int right, int bottom, int regionOp) { - if (regionOp == Region.Op.INTERSECT.nativeInt) { - Graphics2D gc = getGraphics2d(); - gc.clipRect(left, top, right - left, bottom - top); - return gc.getClip().getBounds().isEmpty() == false; - } else { - throw new UnsupportedOperationException(); - } + private int save(int saveFlags) { + // get the current save count + int count = mSnapshot.size(); + + // create a new snapshot and add it to the stack + mSnapshot = new GcSnapshot(mSnapshot, saveFlags); + + // return the old save count + return count; + } + + /** + * Restores the {@link GcSnapshot} to saveCount + * @param saveCount the saveCount + */ + private void restoreTo(int saveCount) { + mSnapshot = mSnapshot.restoreTo(saveCount); + } + + /** + * Restores the {@link GcSnapshot} to saveCount + * @param saveCount the saveCount + */ + private void restore() { + mSnapshot = mSnapshot.restore(); + } + + private boolean clipRect(float left, float top, float right, float bottom, int regionOp) { + return mSnapshot.clipRect(left, top, right, bottom, regionOp); } private void setBitmap(BufferedImage image) { mBufferedImage = image; - mGraphicsStack.push(mBufferedImage.createGraphics()); + assert mSnapshot.size() == 1; + mSnapshot.setGraphics2D(mBufferedImage.createGraphics()); } /** * Creates a new {@link Graphics2D} based on the {@link Paint} parameters. *

The object must be disposed ({@link Graphics2D#dispose()}) after being used. */ - /*package*/ Graphics2D getCustomGraphics(Paint_Delegate paint) { + /*package*/ Graphics2D createCustomGraphics(Paint_Delegate paint) { // make new one - Graphics2D g = getGraphics2d(); - g = (Graphics2D)g.create(); + Graphics2D g = getGcSnapshot().create(); // configure it @@ -1062,6 +1072,7 @@ public class Canvas_Delegate { Shader_Delegate shaderDelegate = Shader_Delegate.getDelegate(paint.getShader()); if (shaderDelegate != null) { java.awt.Paint shaderPaint = shaderDelegate.getJavaPaint(); + assert shaderPaint != null; if (shaderPaint != null) { g.setPaint(shaderPaint); useColorPaint = false; @@ -1113,6 +1124,7 @@ public class Canvas_Delegate { // if xfermode wasn't null, then it's something we don't support. log it. if (xfermodeDelegate != null) { + assert false; Bridge.getLog().warning(null, String.format( "Xfermode '%1$s' is not supported in the Layout Preview.", @@ -1217,30 +1229,18 @@ public class Canvas_Delegate { int sleft, int stop, int sright, int sbottom, int dleft, int dtop, int dright, int dbottom) { - Graphics2D g = canvasDelegate.getGraphics2d(); - - Composite c = null; - - if (paintDelegate != null) { - if (paintDelegate.isFilterBitmap()) { - g = (Graphics2D)g.create(); + Graphics2D g = canvasDelegate.getGcSnapshot().create(); + try { + if (paintDelegate != null && paintDelegate.isFilterBitmap()) { g.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); } - } - g.drawImage(image, dleft, dtop, dright, dbottom, - sleft, stop, sright, sbottom, null); - - if (paintDelegate != null) { - if (paintDelegate.isFilterBitmap()) { - g.dispose(); - } - if (c != null) { - g.setComposite(c); - } + g.drawImage(image, dleft, dtop, dright, dbottom, + sleft, stop, sright, sbottom, null); + } finally { + g.dispose(); } } - } diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java index 6b43544f19df9..b464f66b4311c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java @@ -195,7 +195,8 @@ public final class Matrix_Delegate { setTranslate(d.mValues, dx, dy); } - /*package*/ static void native_setScale(int native_object, float sx, float sy, float px, float py) { + /*package*/ static void native_setScale(int native_object, float sx, float sy, + float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { assert false; @@ -272,7 +273,8 @@ public final class Matrix_Delegate { setRotate(d.mValues, sinValue, cosValue); } - /*package*/ static void native_setSkew(int native_object, float kx, float ky, float px, float py) { + /*package*/ static void native_setSkew(int native_object, float kx, float ky, + float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { assert false; @@ -364,7 +366,8 @@ public final class Matrix_Delegate { return true; } - /*package*/ static boolean native_preRotate(int native_object, float degrees, float px, float py) { + /*package*/ static boolean native_preRotate(int native_object, float degrees, + float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { assert false; @@ -464,7 +467,8 @@ public final class Matrix_Delegate { return true; } - /*package*/ static boolean native_postRotate(int native_object, float degrees, float px, float py) { + /*package*/ static boolean native_postRotate(int native_object, float degrees, + float px, float py) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { assert false; @@ -526,7 +530,8 @@ public final class Matrix_Delegate { return true; } - /*package*/ static boolean native_setRectToRect(int native_object, RectF src, RectF dst, int stf) { + /*package*/ static boolean native_setRectToRect(int native_object, RectF src, + RectF dst, int stf) { Matrix_Delegate d = sManager.getDelegate(native_object); if (d == null) { assert false; diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java index 95663ec6c28c9..fe9bef934bd1d 100644 --- a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java @@ -160,20 +160,17 @@ public class NinePatch_Delegate { Graphics2D graphics; if (paint_delegate != null) { - graphics = canvas_delegate.getCustomGraphics(paint_delegate); + graphics = canvas_delegate.createCustomGraphics(paint_delegate); } else { - graphics = canvas_delegate.getGraphics2d(); + graphics = canvas_delegate.getGcSnapshot().create(); } try { chunkObject.draw(bitmap_delegate.getImage(), graphics, left, top, right - left, bottom - top, destDensity, srcDensity); } finally { - if (paint_delegate != null) { - graphics.dispose(); - } + graphics.dispose(); } - } /*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) { diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java new file mode 100644 index 0000000000000..8c6b1be82551b --- /dev/null +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java @@ -0,0 +1,288 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.layoutlib.bridge.impl; + +import android.graphics.Canvas; +import android.graphics.Region; + +import java.awt.Graphics2D; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; + +/** + * Class representing a graphics context snapshot, as well as a context stack as a linked list. + *

+ * This is based on top of {@link Graphics2D} but can operate independently if none are available + * yet when setting transforms and clip information. + * + */ +public class GcSnapshot { + + private final GcSnapshot mPrevious; + private final int mFlags; + + private Graphics2D mGraphics2D = null; + /** temp transform in case transformation are set before a Graphics2D exists */ + private AffineTransform mTransform = null; + /** temp clip in case clipping is set before a Graphics2D exists */ + private Area mClip = null; + + /** + * Creates a new {@link GcSnapshot} on top of another one. + *

+ * This is basically the equivalent of {@link Canvas#save(int)} + * @param previous the previous snapshot head. + * @param flags the flags regarding what should be saved. + */ + public GcSnapshot(GcSnapshot previous, int flags) { + assert previous != null; + mPrevious = previous; + mFlags = flags; + mGraphics2D = (Graphics2D) previous.mGraphics2D.create(); + } + + /** + * Creates the root snapshot. + * {@link #setGraphics2D(Graphics2D)} will have to be called on it when possible. + */ + public GcSnapshot() { + mPrevious = null; + mFlags = 0; + } + + public void dispose() { + if (mGraphics2D != null) { + mGraphics2D.dispose(); + } + + if (mPrevious != null) { + mPrevious.dispose(); + } + } + + /** + * Restores the top {@link GcSnapshot}, and returns the next one. + */ + public GcSnapshot restore() { + return doRestore(); + } + + /** + * Restores the {@link GcSnapshot} to saveCount. + * @param saveCount the saveCount or -1 to only restore 1. + * + * @return the new head of the Gc snapshot stack. + */ + public GcSnapshot restoreTo(int saveCount) { + return doRestoreTo(size(), saveCount); + } + + public int size() { + if (mPrevious != null) { + return mPrevious.size() + 1; + } + + return 1; + } + + /** + * Sets the Graphics2D object for this snapshot if it was created through {@link #GcSnapshot()}. + * If any transform or clip information was set before, they are put into the Graphics object. + * @param graphics2D the graphics object to set. + */ + public void setGraphics2D(Graphics2D graphics2D) { + mGraphics2D = graphics2D; + if (mTransform != null) { + mGraphics2D.setTransform(mTransform); + mTransform = null; + } + + if (mClip != null) { + mGraphics2D.setClip(mClip); + mClip = null; + } + } + + /** + * Creates and return a copy of the current {@link Graphics2D}. + * @return a new {@link Graphics2D}. + */ + public Graphics2D create() { + assert mGraphics2D != null; + return (Graphics2D) mGraphics2D.create(); + } + + public void translate(float dx, float dy) { + if (mGraphics2D != null) { + mGraphics2D.translate(dx, dy); + } else { + if (mTransform == null) { + mTransform = new AffineTransform(); + } + mTransform.translate(dx, dy); + } + } + + public void rotate(double radians) { + if (mGraphics2D != null) { + mGraphics2D.rotate(radians); + } else { + if (mTransform == null) { + mTransform = new AffineTransform(); + } + mTransform.rotate(radians); + } + } + + public void scale(float sx, float sy) { + if (mGraphics2D != null) { + mGraphics2D.scale(sx, sy); + } else { + if (mTransform == null) { + mTransform = new AffineTransform(); + } + mTransform.scale(sx, sy); + } + } + + public AffineTransform getTransform() { + if (mGraphics2D != null) { + return mGraphics2D.getTransform(); + } else { + if (mTransform == null) { + mTransform = new AffineTransform(); + } + return mTransform; + } + } + + public void setTransform(AffineTransform transform) { + if (mGraphics2D != null) { + mGraphics2D.setTransform(transform); + } else { + if (mTransform == null) { + mTransform = new AffineTransform(); + } + mTransform.setTransform(transform); + } + } + + public boolean clipRect(float left, float top, float right, float bottom, int regionOp) { + if (mGraphics2D != null) { + if (regionOp == Region.Op.DIFFERENCE.nativeInt) { + Area newClip = new Area(mGraphics2D.getClip()); + newClip.subtract(new Area( + new Rectangle2D.Float(left, top, right - left, bottom - top))); + mGraphics2D.setClip(newClip); + + } else if (regionOp == Region.Op.INTERSECT.nativeInt) { + mGraphics2D.clipRect((int) left, (int) top, + (int) (right - left), (int) (bottom - top)); + + } else if (regionOp == Region.Op.UNION.nativeInt) { + Area newClip = new Area(mGraphics2D.getClip()); + newClip.add(new Area( + new Rectangle2D.Float(left, top, right - left, bottom - top))); + mGraphics2D.setClip(newClip); + + } else if (regionOp == Region.Op.XOR.nativeInt) { + Area newClip = new Area(mGraphics2D.getClip()); + newClip.exclusiveOr(new Area( + new Rectangle2D.Float(left, top, right - left, bottom - top))); + mGraphics2D.setClip(newClip); + + } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) { + Area newClip = new Area( + new Rectangle2D.Float(left, top, right - left, bottom - top)); + newClip.subtract(new Area(mGraphics2D.getClip())); + mGraphics2D.setClip(newClip); + } else if (regionOp == Region.Op.REPLACE.nativeInt) { + mGraphics2D.setClip((int) left, (int) top, + (int) (right - left), (int) (bottom - top)); + } + + return mGraphics2D.getClip().getBounds().isEmpty() == false; + } else { + if (mClip == null) { + mClip = new Area(); + } + + if (regionOp == Region.Op.DIFFERENCE.nativeInt) { + //FIXME + } else if (regionOp == Region.Op.DIFFERENCE.nativeInt) { + } else if (regionOp == Region.Op.INTERSECT.nativeInt) { + } else if (regionOp == Region.Op.UNION.nativeInt) { + } else if (regionOp == Region.Op.XOR.nativeInt) { + } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) { + } else if (regionOp == Region.Op.REPLACE.nativeInt) { + } + + return mClip.getBounds().isEmpty() == false; + } + } + + public Shape getClip() { + if (mGraphics2D != null) { + return mGraphics2D.getClip(); + } else { + if (mClip == null) { + mClip = new Area(); + } + return mClip; + } + } + + private GcSnapshot doRestoreTo(int size, int saveCount) { + if (size <= saveCount) { + return this; + } + + // restore the current one first. + GcSnapshot previous = doRestore(); + + if (size == saveCount + 1) { // this was the only one that needed restore. + return previous; + } else { + return previous.doRestoreTo(size - 1, saveCount); + } + } + + private GcSnapshot doRestore() { + // if this snapshot does not save everything, then set the previous snapshot + // to this snapshot content + if (mPrevious != null) { + // didn't save the matrix? set the current matrix on the previous snapshot + if ((mFlags & Canvas.MATRIX_SAVE_FLAG) == 0) { + mPrevious.mGraphics2D.setTransform(getTransform()); + } + + // didn't save the clip? set the current clip on the previous snapshot + if ((mFlags & Canvas.CLIP_SAVE_FLAG) == 0) { + mPrevious.mGraphics2D.setClip(mGraphics2D.getClip()); + } + } + + if (mGraphics2D != null) { + mGraphics2D.dispose(); + } + + return mPrevious; + } + +}