diff options
author | Xavier Ducrohet <xav@android.com> | 2011-01-06 15:50:42 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2011-01-06 18:13:49 -0800 |
commit | a7cac5e0542779cadf0f5ccf71584e4b4425f7a6 (patch) | |
tree | 3a58441f7362a9e2b03afec07fe9f669da9a828d /tools | |
parent | adba8021cd2fd0d20856fb4fbfed2cb000f3f1d5 (diff) | |
download | frameworks_base-a7cac5e0542779cadf0f5ccf71584e4b4425f7a6.zip frameworks_base-a7cac5e0542779cadf0f5ccf71584e4b4425f7a6.tar.gz frameworks_base-a7cac5e0542779cadf0f5ccf71584e4b4425f7a6.tar.bz2 |
LayoutLib: fix clipping issues.
There were two issues:
- Graphics2D.setClip only works on rectangular shapes.
This means doing a setClip on a non rectangular shape should
basically reset the clip and intersect with the new shape.
- the current clip can be null, so the combineShape method
must handle it.
Change-Id: Id2cd7475e991d8b533ff2e8850cc2c27663f9e52
Diffstat (limited to 'tools')
3 files changed, 87 insertions, 14 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index def0f02..61bf33b 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -499,13 +499,14 @@ public final class Canvas_Delegate { } Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds(); - if (rect != null) { + if (rect != null && rect.isEmpty() == false) { bounds.left = rect.x; bounds.top = rect.y; bounds.right = rect.x + rect.width; bounds.bottom = rect.y + rect.height; return true; } + return false; } diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java index 684bb90..bc13b52 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java @@ -69,39 +69,64 @@ public class Region_Delegate { * * If the Op is not one that combines two shapes, then this return null * - * @param shape1 the firt shape to combine + * @param shape1 the firt shape to combine which can be null if there's no original clip. * @param shape2 the 2nd shape to combine * @param regionOp the operande for the combine * @return a new area or null. */ public static Area combineShapes(Shape shape1, Shape shape2, int regionOp) { if (regionOp == Region.Op.DIFFERENCE.nativeInt) { + // if shape1 is null (empty), then the result is null. + if (shape1 == null) { + return null; + } + // result is always a new area. Area result = new Area(shape1); result.subtract(shape2 instanceof Area ? (Area) shape2 : new Area(shape2)); return result; } else if (regionOp == Region.Op.INTERSECT.nativeInt) { + // if shape1 is null, then the result is simply shape2. + if (shape1 == null) { + return new Area(shape2); + } + // result is always a new area. Area result = new Area(shape1); result.intersect(shape2 instanceof Area ? (Area) shape2 : new Area(shape2)); return result; } else if (regionOp == Region.Op.UNION.nativeInt) { + // if shape1 is null, then the result is simply shape2. + if (shape1 == null) { + return new Area(shape2); + } + // result is always a new area. Area result = new Area(shape1); result.add(shape2 instanceof Area ? (Area) shape2 : new Area(shape2)); return result; } else if (regionOp == Region.Op.XOR.nativeInt) { + // if shape1 is null, then the result is simply shape2 + if (shape1 == null) { + return new Area(shape2); + } + // result is always a new area. Area result = new Area(shape1); result.exclusiveOr(shape2 instanceof Area ? (Area) shape2 : new Area(shape2)); + return result; } else if (regionOp == Region.Op.REVERSE_DIFFERENCE.nativeInt) { // result is always a new area. Area result = new Area(shape2); - result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1)); + + if (shape1 != null) { + result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1)); + } + return result; } 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 index a2fcb3b..72773c8 100644 --- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java +++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java @@ -170,6 +170,29 @@ public class GcSnapshot { mBitmap.change(); } } + + /** + * Sets the clip for the graphics2D object associated with the layer. + * This should be used over the normal Graphics2D setClip method. + * + * @param clipShape the shape to use a the clip shape. + */ + void setClip(Shape clipShape) { + // because setClip is only guaranteed to work with rectangle shape, + // first reset the clip to max and then intersect the current (empty) + // clip with the shap. + mGraphics.setClip(null); + mGraphics.clip(clipShape); + } + + /** + * Clips the layer with the given shape. This performs an intersect between the current + * clip shape and the given shape. + * @param shape the new clip shape. + */ + public void clip(Shape shape) { + mGraphics.clip(shape); + } } /** @@ -287,12 +310,13 @@ public class GcSnapshot { AffineTransform currentMtx = baseLayer.getGraphics().getTransform(); layerGraphics.setTransform(currentMtx); - Shape currentClip = baseLayer.getGraphics().getClip(); - layerGraphics.setClip(currentClip); - // create a new layer for this new layer and add it to the list at the end. mLayers.add(mLocalLayer = new Layer(layerGraphics, layerImage, flags)); + // set the clip on it. + Shape currentClip = baseLayer.getGraphics().getClip(); + mLocalLayer.setClip(currentClip); + // if the drawing is not clipped to the local layer only, we save the current content // of all other layers. We are only interested in the part that will actually // be drawn, so we create as small bitmaps as we can. @@ -369,15 +393,24 @@ public class GcSnapshot { */ public void setBitmap(Bitmap_Delegate bitmap) { assert mLayers.size() == 0; + + // create a new Layer for the bitmap. This will be the base layer. Graphics2D graphics2D = bitmap.getImage().createGraphics(); - mLayers.add(new Layer(graphics2D, bitmap)); + Layer baseLayer = new Layer(graphics2D, bitmap); + + // add it to the list. + mLayers.add(baseLayer); + + // if transform and clip where modified before, get the information and give it to the + // layer. + if (mTransform != null) { graphics2D.setTransform(mTransform); mTransform = null; } if (mClip != null) { - graphics2D.setClip(mClip); + baseLayer.setClip(mClip); mClip = null; } } @@ -447,7 +480,20 @@ public class GcSnapshot { } public boolean clip(Shape shape, int regionOp) { + // Simple case of intersect with existing layers. + // Because Graphics2D#setClip works a bit peculiarly, we optimize + // the case of clipping by intersection, as it's supported natively. + if (regionOp == Region.Op.INTERSECT.nativeInt && mLayers.size() > 0) { + for (Layer layer : mLayers) { + layer.clip(shape); + } + + Shape currentClip = getClip(); + return currentClip != null && currentClip.getBounds().isEmpty() == false; + } + Area area = null; + if (regionOp == Region.Op.REPLACE.nativeInt) { area = new Area(shape); } else { @@ -459,11 +505,12 @@ public class GcSnapshot { if (mLayers.size() > 0) { if (area != null) { for (Layer layer : mLayers) { - layer.getGraphics().setClip(area); + layer.setClip(area); } } - return getClip().getBounds().isEmpty() == false; + Shape currentClip = getClip(); + return currentClip != null && currentClip.getBounds().isEmpty() == false; } else { if (area != null) { mClip = area; @@ -479,14 +526,14 @@ public class GcSnapshot { return clip(new Rectangle2D.Float(left, top, right - left, bottom - top), regionOp); } + /** + * Returns the current clip, or null if none have been setup. + */ public Shape getClip() { if (mLayers.size() > 0) { // they all have the same clip return mLayers.get(0).getGraphics().getClip(); } else { - if (mClip == null) { - mClip = new Area(); - } return mClip; } } @@ -603,7 +650,7 @@ public class GcSnapshot { if ((mFlags & Canvas.CLIP_SAVE_FLAG) == 0) { Shape clip = getClip(); for (Layer layer : mPrevious.mLayers) { - layer.getGraphics().setClip(clip); + layer.setClip(clip); } } } |