summaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorXavier Ducrohet <xav@android.com>2010-12-23 10:22:14 -0800
committerXavier Ducrohet <xav@android.com>2010-12-24 00:21:51 -0800
commitb44b43b1579486ff7ecd0f7528f17711acdeae98 (patch)
tree47542b0726249f3b7fb02c41412088f15f816cec /tools
parentd43909c7503e11eb335a452d296a10804bb01fd6 (diff)
downloadframeworks_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')
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java4
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java29
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java59
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java14
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java306
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/GcSnapshot.java100
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/CreateInfo.java1
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",