diff options
author | Xavier Ducrohet <xav@android.com> | 2010-12-23 10:22:14 -0800 |
---|---|---|
committer | Xavier Ducrohet <xav@android.com> | 2010-12-24 00:21:51 -0800 |
commit | b44b43b1579486ff7ecd0f7528f17711acdeae98 (patch) | |
tree | 47542b0726249f3b7fb02c41412088f15f816cec /tools | |
parent | d43909c7503e11eb335a452d296a10804bb01fd6 (diff) | |
download | frameworks_base-b44b43b1579486ff7ecd0f7528f17711acdeae98.zip frameworks_base-b44b43b1579486ff7ecd0f7528f17711acdeae98.tar.gz frameworks_base-b44b43b1579486ff7ecd0f7528f17711acdeae98.tar.bz2 |
LayoutLib: Support Region through delegates.
also finish supporting some clip operation
on the canvas.
Change-Id: I743b9e52a7aa6e9340506f1c904cc1cfbf3ff81f
Diffstat (limited to 'tools')
7 files changed, 415 insertions, 98 deletions
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java index 1e1b2cf..dd57bd1 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java @@ -384,7 +384,7 @@ public final class Bitmap_Delegate { // This is only called by Bitmap.CREATOR (Parcelable.Creator<Bitmap>), which is only // used during aidl call so really this should not be called. Bridge.getLog().error(null, - "AIDL is not suppored, and therefore bitmap cannot be created from parcels"); + "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels."); return null; } @@ -393,7 +393,7 @@ public final class Bitmap_Delegate { // This is only called when sending a bitmap through aidl, so really this should not // be called. Bridge.getLog().error(null, - "AIDL is not suppored, and therefore bitmap cannot be written to parcels"); + "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels."); return false; } diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java index b3a490f..def0f02 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java @@ -271,8 +271,7 @@ public final class Canvas_Delegate { } /*package*/ static void freeCaches() { - // FIXME - throw new UnsupportedOperationException(); + // nothing to be done here. } /*package*/ static int initRaster(int nativeBitmapOrZero) { @@ -440,15 +439,33 @@ public final class Canvas_Delegate { /*package*/ static boolean native_clipPath(int nativeCanvas, int nativePath, int regionOp) { - // FIXME - throw new UnsupportedOperationException(); + Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + return true; + } + + Path_Delegate pathDelegate = Path_Delegate.getDelegate(nativePath); + if (pathDelegate == null) { + return true; + } + + return canvasDelegate.mSnapshot.clip(pathDelegate.getJavaShape(), regionOp); } /*package*/ static boolean native_clipRegion(int nativeCanvas, int nativeRegion, int regionOp) { - // FIXME - throw new UnsupportedOperationException(); + Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas); + if (canvasDelegate == null) { + return true; + } + + Region_Delegate region = Region_Delegate.getDelegate(nativeRegion); + if (region == null) { + return true; + } + + return canvasDelegate.mSnapshot.clip(region.getJavaArea(), regionOp); } /*package*/ static void nativeSetDrawFilter(int nativeCanvas, diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java index fc58475..9d4970f 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java @@ -25,6 +25,8 @@ import android.text.TextUtils; import java.awt.BasicStroke; import java.awt.Font; +import java.awt.Shape; +import java.awt.Stroke; import java.awt.Toolkit; import java.awt.font.FontRenderContext; import java.awt.geom.AffineTransform; @@ -167,6 +169,30 @@ public class Paint_Delegate { } } + public Stroke getJavaStroke() { + PathEffect_Delegate effectDelegate = PathEffect_Delegate.getDelegate(mPathEffect); + if (effectDelegate != null) { + if (effectDelegate.isSupported()) { + Stroke stroke = effectDelegate.getStroke(this); + assert stroke != null; + if (stroke != null) { + return stroke; + } + } else { + Bridge.getLog().fidelityWarning(null, + effectDelegate.getSupportMessage(), + null); + } + } + + // if no custom stroke as been set, set the default one. + return new BasicStroke( + getStrokeWidth(), + getJavaCap(), + getJavaJoin(), + getJavaStrokeMiter()); + } + /** * Returns the {@link Xfermode} delegate or null if none have been set * @@ -195,15 +221,6 @@ public class Paint_Delegate { } /** - * Returns the {@link PathEffect} delegate or null if none have been set - * - * @return the delegate or null. - */ - public PathEffect_Delegate getPathEffect() { - return PathEffect_Delegate.getDelegate(mPathEffect); - } - - /** * Returns the {@link MaskFilter} delegate or null if none have been set * * @return the delegate or null. @@ -628,8 +645,28 @@ public class Paint_Delegate { } /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) { - // FIXME - throw new UnsupportedOperationException(); + Paint_Delegate paint = sManager.getDelegate(native_object); + if (paint == null) { + return false; + } + + Path_Delegate srcPath = Path_Delegate.getDelegate(src); + if (srcPath == null) { + return true; + } + + Path_Delegate dstPath = Path_Delegate.getDelegate(dst); + if (dstPath == null) { + return true; + } + + Stroke stroke = paint.getJavaStroke(); + Shape strokeShape = stroke.createStrokedShape(srcPath.getJavaShape()); + + dstPath.setJavaShape(strokeShape); + + // FIXME figure out the return value? + return true; } /*package*/ static int native_setShader(int native_object, int shader) { diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java index c5c3220..66ab29c 100644 --- a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java +++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java @@ -67,6 +67,20 @@ public final class Path_Delegate { return mPath; } + public void setJavaShape(Shape shape) { + mPath.reset(); + mPath.append(shape, false /*connect*/); + } + + public void reset() { + mPath.reset(); + } + + public void setPathIterator(PathIterator iterator) { + mPath.reset(); + mPath.append(iterator, false /*connect*/); + } + // ---- native methods ---- /*package*/ static int init1() { diff --git a/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java new file mode 100644 index 0000000..684bb90 --- /dev/null +++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java @@ -0,0 +1,306 @@ +/* + * 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 android.graphics; + +import com.android.layoutlib.bridge.Bridge; +import com.android.layoutlib.bridge.impl.DelegateManager; + +import android.os.Parcel; + +import java.awt.Rectangle; +import java.awt.Shape; +import java.awt.geom.AffineTransform; +import java.awt.geom.Area; +import java.awt.geom.Rectangle2D; + +/** + * Delegate implementing the native methods of android.graphics.Region + * + * Through the layoutlib_create tool, the original native methods of Region have been replaced + * by calls to methods of the same name in this delegate class. + * + * This class behaves like the original native implementation, but in Java, keeping previously + * native data into its own objects and mapping them to int that are sent back and forth between + * it and the original Region class. + * + * This also serve as a base class for all Region delegate classes. + * + * @see DelegateManager + * + */ +public class Region_Delegate { + + // ---- delegate manager ---- + protected static final DelegateManager<Region_Delegate> sManager = + new DelegateManager<Region_Delegate>(); + + // ---- delegate helper data ---- + + // ---- delegate data ---- + private Area mArea = new Area(); + + // ---- Public Helper methods ---- + + public static Region_Delegate getDelegate(int nativeShader) { + return sManager.getDelegate(nativeShader); + } + + public Area getJavaArea() { + return mArea; + } + + /** + * Combines two {@link Shape} into another one (actually an {@link Area}), according + * to the given {@link Region.Op}. + * + * If the Op is not one that combines two shapes, then this return null + * + * @param shape1 the firt shape to combine + * @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) { + // 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) { + // 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) { + // 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) { + // result is always a new area. + Area result = new Area(shape1); + result.exclusiveOr(shape2 instanceof Area ? (Area) shape2 : new Area(shape2)); + + } 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)); + return result; + } + + return null; + } + + // ---- native methods ---- + + /*package*/ static int nativeConstructor() { + Region_Delegate newDelegate = new Region_Delegate(); + return sManager.addDelegate(newDelegate); + } + + /*package*/ static void nativeDestructor(int native_region) { + sManager.removeDelegate(native_region); + } + + /*package*/ static boolean nativeSetRegion(int native_dst, int native_src) { + Region_Delegate dstRegion = sManager.getDelegate(native_dst); + if (dstRegion == null) { + return true; + } + + Region_Delegate srcRegion = sManager.getDelegate(native_src); + if (srcRegion == null) { + return true; + } + + dstRegion.mArea.reset(); + dstRegion.mArea.add(srcRegion.mArea); + + return true; + } + + /*package*/ static boolean nativeSetRect(int native_dst, + int left, int top, int right, int bottom) { + Region_Delegate dstRegion = sManager.getDelegate(native_dst); + if (dstRegion == null) { + return true; + } + + dstRegion.mArea = new Area(new Rectangle2D.Float(left, top, right - left, bottom - top)); + return dstRegion.mArea.getBounds().isEmpty() == false; + } + + /*package*/ static boolean nativeSetPath(int native_dst, int native_path, int native_clip) { + Region_Delegate dstRegion = sManager.getDelegate(native_dst); + if (dstRegion == null) { + return true; + } + + Path_Delegate path = Path_Delegate.getDelegate(native_path); + if (path == null) { + return true; + } + + dstRegion.mArea = new Area(path.getJavaShape()); + + Region_Delegate clip = sManager.getDelegate(native_clip); + if (clip != null) { + dstRegion.mArea.subtract(clip.getJavaArea()); + } + + return dstRegion.mArea.getBounds().isEmpty() == false; + } + + /*package*/ static boolean nativeGetBounds(int native_region, Rect rect) { + Region_Delegate region = sManager.getDelegate(native_region); + if (region == null) { + return true; + } + + Rectangle bounds = region.mArea.getBounds(); + if (bounds.isEmpty()) { + rect.left = rect.top = rect.right = rect.bottom = 0; + return false; + } + + rect.left = bounds.x; + rect.top = bounds.y; + rect.right = bounds.x + bounds.width; + rect.bottom = bounds.y + bounds.height; + return true; + } + + /*package*/ static boolean nativeGetBoundaryPath(int native_region, int native_path) { + Region_Delegate region = sManager.getDelegate(native_region); + if (region == null) { + return false; + } + + Path_Delegate path = Path_Delegate.getDelegate(native_path); + if (path == null) { + return false; + } + + if (region.mArea.isEmpty()) { + path.reset(); + return false; + } + + path.setPathIterator(region.mArea.getPathIterator(new AffineTransform())); + return true; + } + + /*package*/ static boolean nativeOp(int native_dst, + int left, int top, int right, int bottom, int op) { + Region_Delegate region = sManager.getDelegate(native_dst); + if (region == null) { + return false; + } + + region.mArea = combineShapes(region.mArea, + new Rectangle2D.Float(left, top, right - left, bottom - top), op); + + assert region.mArea != null; + if (region.mArea != null) { + region.mArea = new Area(); + } + + return region.mArea.getBounds().isEmpty() == false; + } + + /*package*/ static boolean nativeOp(int native_dst, Rect rect, int native_region, int op) { + Region_Delegate region = sManager.getDelegate(native_dst); + if (region == null) { + return false; + } + + region.mArea = combineShapes(region.mArea, + new Rectangle2D.Float(rect.left, rect.top, rect.width(), rect.height()), op); + + assert region.mArea != null; + if (region.mArea != null) { + region.mArea = new Area(); + } + + return region.mArea.getBounds().isEmpty() == false; + } + + /*package*/ static boolean nativeOp(int native_dst, + int native_region1, int native_region2, int op) { + Region_Delegate dstRegion = sManager.getDelegate(native_dst); + if (dstRegion == null) { + return true; + } + + Region_Delegate region1 = sManager.getDelegate(native_region1); + if (region1 == null) { + return false; + } + + Region_Delegate region2 = sManager.getDelegate(native_region2); + if (region2 == null) { + return false; + } + + dstRegion.mArea = combineShapes(region1.mArea, region2.mArea, op); + + assert dstRegion.mArea != null; + if (dstRegion.mArea != null) { + dstRegion.mArea = new Area(); + } + + return dstRegion.mArea.getBounds().isEmpty() == false; + + } + + /*package*/ static int nativeCreateFromParcel(Parcel p) { + // This is only called by Region.CREATOR (Parcelable.Creator<Region>), which is only + // used during aidl call so really this should not be called. + Bridge.getLog().error(null, + "AIDL is not suppored, and therefore Regions cannot be created from parcels."); + return 0; + } + + /*package*/ static boolean nativeWriteToParcel(int native_region, + Parcel p) { + // This is only called when sending a region through aidl, so really this should not + // be called. + Bridge.getLog().error(null, + "AIDL is not suppored, and therefore Regions cannot be written to parcels."); + return false; + } + + /*package*/ static boolean nativeEquals(int native_r1, int native_r2) { + Region_Delegate region1 = sManager.getDelegate(native_r1); + if (region1 == null) { + return false; + } + + Region_Delegate region2 = sManager.getDelegate(native_r2); + if (region2 == null) { + return false; + } + + return region1.mArea.equals(region2.mArea); + } + + // ---- Private delegate/helper methods ---- + +} 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 afe75a0..a2fcb3b 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 @@ -22,21 +22,19 @@ import android.graphics.Bitmap_Delegate; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.Paint_Delegate; -import android.graphics.PathEffect_Delegate; import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; +import android.graphics.Region_Delegate; import android.graphics.Shader_Delegate; import android.graphics.Xfermode_Delegate; import java.awt.AlphaComposite; -import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.Shape; -import java.awt.Stroke; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Rectangle2D; @@ -448,72 +446,39 @@ public class GcSnapshot { } } - public boolean clipRect(float left, float top, float right, float bottom, int regionOp) { - if (mLayers.size() > 0) { - Shape clip = null; - if (regionOp == Region.Op.DIFFERENCE.nativeInt) { - Area newClip = new Area(getClip()); - newClip.subtract(new Area( - new Rectangle2D.Float(left, top, right - left, bottom - top))); - clip = newClip; - - } else if (regionOp == Region.Op.INTERSECT.nativeInt) { - for (Layer layer : mLayers) { - layer.getGraphics().clipRect( - (int) left, (int) top, (int) (right - left), (int) (bottom - top)); - } + public boolean clip(Shape shape, int regionOp) { + Area area = null; + if (regionOp == Region.Op.REPLACE.nativeInt) { + area = new Area(shape); + } else { + area = Region_Delegate.combineShapes(getClip(), shape, regionOp); + } - } else if (regionOp == Region.Op.UNION.nativeInt) { - Area newClip = new Area(getClip()); - newClip.add(new Area( - new Rectangle2D.Float(left, top, right - left, bottom - top))); - clip = newClip; - - } else if (regionOp == Region.Op.XOR.nativeInt) { - Area newClip = new Area(getClip()); - newClip.exclusiveOr(new Area( - new Rectangle2D.Float(left, top, right - left, bottom - top))); - clip = 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(getClip())); - clip = newClip; - - } else if (regionOp == Region.Op.REPLACE.nativeInt) { - for (Layer layer : mLayers) { - layer.getGraphics().setClip( - (int) left, (int) top, (int) (right - left), (int) (bottom - top)); - } - } + assert area != null; - if (clip != null) { + if (mLayers.size() > 0) { + if (area != null) { for (Layer layer : mLayers) { - layer.getGraphics().setClip(clip); + layer.getGraphics().setClip(area); } } return getClip().getBounds().isEmpty() == false; } else { - if (mClip == null) { + if (area != null) { + mClip = area; + } else { 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 boolean clipRect(float left, float top, float right, float bottom, int regionOp) { + return clip(new Rectangle2D.Float(left, top, right - left, bottom - top), regionOp); + } + public Shape getClip() { if (mLayers.size() > 0) { // they all have the same clip @@ -727,31 +692,8 @@ public class GcSnapshot { g.setColor(new Color(paint.getColor(), true /*hasAlpha*/)); } - boolean customStroke = false; - PathEffect_Delegate effectDelegate = paint.getPathEffect(); - if (effectDelegate != null) { - if (effectDelegate.isSupported()) { - Stroke stroke = effectDelegate.getStroke(paint); - assert stroke != null; - if (stroke != null) { - g.setStroke(stroke); - customStroke = true; - } - } else { - Bridge.getLog().fidelityWarning(null, - effectDelegate.getSupportMessage(), - null); - } - } - - // if no custom stroke as been set, set the default one. - if (customStroke == false) { - g.setStroke(new BasicStroke( - paint.getStrokeWidth(), - paint.getJavaCap(), - paint.getJavaJoin(), - paint.getJavaStrokeMiter())); - } + // set the stroke + g.setStroke(paint.getJavaStroke()); } // the alpha for the composite. Always opaque if the normal paint color is used since diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java index dc843ac..6b589d7 100644 --- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java +++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java @@ -136,6 +136,7 @@ public final class CreateInfo implements ICreateInfo { "android.graphics.PorterDuffXfermode", "android.graphics.RadialGradient", "android.graphics.Rasterizer", + "android.graphics.Region", "android.graphics.Shader", "android.graphics.SumPathEffect", "android.graphics.SweepGradient", |