summaryrefslogtreecommitdiffstats
path: root/tools/layoutlib/bridge/src/android
diff options
context:
space:
mode:
Diffstat (limited to 'tools/layoutlib/bridge/src/android')
-rw-r--r--tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java59
-rw-r--r--tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java104
-rw-r--r--tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java67
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java70
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap.java278
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java566
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java167
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapShader.java48
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java247
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java563
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas.java1279
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java1334
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java70
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ComposeShader.java53
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java97
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java54
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java89
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java65
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java (renamed from tools/layoutlib/bridge/src/android/graphics/GradientShader.java)52
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java69
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java70
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LinearGradient.java173
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java236
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix.java1032
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java1129
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java225
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint.java1211
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java1240
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path.java611
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java72
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java69
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java761
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java70
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java140
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/RadialGradient.java132
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java211
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java64
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java484
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Shader.java83
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java105
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/SweepGradient.java140
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java218
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface.java190
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java191
-rw-r--r--tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java69
-rw-r--r--tools/layoutlib/bridge/src/android/os/Build_Delegate.java48
-rw-r--r--tools/layoutlib/bridge/src/android/os/Handler_Delegate.java57
-rw-r--r--tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java71
-rw-r--r--tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java (renamed from tools/layoutlib/bridge/src/android/util/FloatMath.java)36
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java227
-rw-r--r--tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java97
-rw-r--r--tools/layoutlib/bridge/src/android/view/View_Delegate.java (renamed from tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode.java)34
62 files changed, 9368 insertions, 6134 deletions
diff --git a/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
new file mode 100644
index 0000000..7b444aa
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/animation/PropertyValuesHolder_Delegate.java
@@ -0,0 +1,59 @@
+/*
+ * 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.animation;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.animation.PropertyValuesHolder
+ *
+ * Through the layoutlib_create tool, the original native methods of PropertyValuesHolder have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ * The main goal of this class' methods are to provide a native way to access setters and getters
+ * on some object. In this case we want to default to using Java reflection instead so the native
+ * methods do nothing.
+ *
+ */
+/*package*/ class PropertyValuesHolder_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static int nGetIntMethod(Class<?> targetClass, String methodName) {
+ // return 0 to force PropertyValuesHolder to use Java reflection.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nGetFloatMethod(Class<?> targetClass, String methodName) {
+ // return 0 to force PropertyValuesHolder to use Java reflection.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallIntMethod(Object target, int methodID, int arg) {
+ // do nothing
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nCallFloatMethod(Object target, int methodID, float arg) {
+ // do nothing
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
new file mode 100644
index 0000000..aabd3f1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/app/Fragment_Delegate.java
@@ -0,0 +1,104 @@
+/*
+ * 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.app;
+
+import com.android.ide.common.rendering.api.IProjectCallback;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.Context;
+import android.os.Bundle;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Fragment}
+ *
+ * Through the layoutlib_create tool, the original methods of Fragment have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * The methods being re-implemented are the ones responsible for instantiating Fragment objects.
+ * Because the classes of these objects are found in the project, these methods need access to
+ * {@link IProjectCallback} object. They are however static methods, so the callback is set
+ * before the inflation through {@link #setProjectCallback(IProjectCallback)}.
+ */
+public class Fragment_Delegate {
+
+ private static IProjectCallback sProjectCallback;
+
+ /**
+ * Sets the current {@link IProjectCallback} to be used to instantiate classes coming
+ * from the project being rendered.
+ */
+ public static void setProjectCallback(IProjectCallback projectCallback) {
+ sProjectCallback = projectCallback;
+ }
+
+ /**
+ * Like {@link #instantiate(Context, String, Bundle)} but with a null
+ * argument Bundle.
+ */
+ @LayoutlibDelegate
+ /*package*/ static Fragment instantiate(Context context, String fname) {
+ return instantiate(context, fname, null);
+ }
+
+ /**
+ * Create a new instance of a Fragment with the given class name. This is
+ * the same as calling its empty constructor.
+ *
+ * @param context The calling context being used to instantiate the fragment.
+ * This is currently just used to get its ClassLoader.
+ * @param fname The class name of the fragment to instantiate.
+ * @param args Bundle of arguments to supply to the fragment, which it
+ * can retrieve with {@link #getArguments()}. May be null.
+ * @return Returns a new fragment instance.
+ * @throws InstantiationException If there is a failure in instantiating
+ * the given fragment class. This is a runtime exception; it is not
+ * normally expected to happen.
+ */
+ @LayoutlibDelegate
+ /*package*/ static Fragment instantiate(Context context, String fname, Bundle args) {
+ try {
+ if (sProjectCallback != null) {
+ Fragment f = (Fragment) sProjectCallback.loadView(fname,
+ new Class[0], new Object[0]);
+
+ if (args != null) {
+ args.setClassLoader(f.getClass().getClassLoader());
+ f.mArguments = args;
+ }
+ return f;
+ }
+
+ return null;
+ } catch (ClassNotFoundException e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ } catch (java.lang.InstantiationException e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ } catch (IllegalAccessException e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ } catch (Exception e) {
+ throw new Fragment.InstantiationException("Unable to instantiate fragment " + fname
+ + ": make sure class name exists, is public, and has an"
+ + " empty constructor that is public", e);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
new file mode 100644
index 0000000..413894b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/content/res/Resources_Theme_Delegate.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 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.content.res;
+
+import com.android.layoutlib.bridge.impl.RenderSessionImpl;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.res.Resources.NotFoundException;
+import android.content.res.Resources.Theme;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link Theme}
+ *
+ * Through the layoutlib_create tool, the original methods of Theme have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class Resources_Theme_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static TypedArray obtainStyledAttributes(
+ Resources thisResources, Theme thisTheme,
+ int[] attrs) {
+ return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(attrs);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static TypedArray obtainStyledAttributes(
+ Resources thisResources, Theme thisTheme,
+ int resid, int[] attrs)
+ throws NotFoundException {
+ return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(resid, attrs);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static TypedArray obtainStyledAttributes(
+ Resources thisResources, Theme thisTheme,
+ AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
+ return RenderSessionImpl.getCurrentContext().obtainStyledAttributes(
+ set, attrs, defStyleAttr, defStyleRes);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean resolveAttribute(
+ Resources thisResources, Theme thisTheme,
+ int resid, TypedValue outValue,
+ boolean resolveRefs) {
+ return RenderSessionImpl.getCurrentContext().resolveThemeAttribute(
+ resid, outValue, resolveRefs);
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
new file mode 100644
index 0000000..a50a2bd
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/AvoidXfermode_Delegate.java
@@ -0,0 +1,70 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.AvoidXfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of AvoidXfermode 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 AvoidXfermode class.
+ *
+ * Because this extends {@link Xfermode_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link Xfermode_Delegate}.
+ *
+ */
+public class AvoidXfermode_Delegate extends Xfermode_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Composite getComposite(int alpha) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Avoid Xfermodes are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int opColor, int tolerance, int nativeMode) {
+ AvoidXfermode_Delegate newDelegate = new AvoidXfermode_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
deleted file mode 100644
index 35f022e..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Bitmap.java
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2008 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 java.awt.image.BufferedImage;
-import java.io.File;
-import java.io.IOException;
-import java.io.InputStream;
-
-import javax.imageio.ImageIO;
-
-public final class Bitmap extends _Original_Bitmap {
-
- private BufferedImage mImage;
-
- public Bitmap(File input) throws IOException {
- super(1, true, null, -1);
-
- mImage = ImageIO.read(input);
- }
-
- public Bitmap(InputStream is) throws IOException {
- super(1, true, null, -1);
-
- mImage = ImageIO.read(is);
- }
-
- Bitmap(BufferedImage image) {
- super(1, true, null, -1);
- mImage = image;
- }
-
- public BufferedImage getImage() {
- return mImage;
- }
-
- // ----- overriden methods
-
- public enum Config {
- // these native values must match up with the enum in SkBitmap.h
- ALPHA_8 (2),
- RGB_565 (4),
- ARGB_4444 (5),
- ARGB_8888 (6);
-
- Config(int ni) {
- this.nativeInt = ni;
- }
- final int nativeInt;
-
- /* package */ static Config nativeToConfig(int ni) {
- return sConfigs[ni];
- }
-
- private static Config sConfigs[] = {
- null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888
- };
- }
-
- @Override
- public int getWidth() {
- return mImage.getWidth();
- }
-
- @Override
- public int getHeight() {
- return mImage.getHeight();
- }
-
- /**
- * Returns an immutable bitmap from the source bitmap. The new bitmap may
- * be the same object as source, or a copy may have been made.
- */
- public static Bitmap createBitmap(Bitmap src) {
- return createBitmap(src, 0, 0, src.getWidth(), src.getHeight(), null, false);
- }
-
- /**
- * Returns an immutable bitmap from the specified subset of the source
- * bitmap. The new bitmap may be the same object as source, or a copy may
- * have been made.
- *
- * @param source The bitmap we are subsetting
- * @param x The x coordinate of the first pixel in source
- * @param y The y coordinate of the first pixel in source
- * @param width The number of pixels in each row
- * @param height The number of rows
- */
- public static Bitmap createBitmap(Bitmap source, int x, int y,
- int width, int height) {
- return new Bitmap(source.mImage.getSubimage(x, y, width, height));
- }
-
- /**
- * Returns an immutable bitmap from subset of the source bitmap,
- * transformed by the optional matrix.
- *
- * @param source The bitmap we are subsetting
- * @param x The x coordinate of the first pixel in source
- * @param y The y coordinate of the first pixel in source
- * @param width The number of pixels in each row
- * @param height The number of rows
- * @param m Option matrix to be applied to the pixels
- * @param filter true if the source should be filtered.
- * Only applies if the matrix contains more than just
- * translation.
- * @return A bitmap that represents the specified subset of source
- * @throws IllegalArgumentException if the x, y, width, height values are
- * outside of the dimensions of the source bitmap.
- */
- public static Bitmap createBitmap(Bitmap source, int x, int y, int width,
- int height, Matrix m, boolean filter) {
- checkXYSign(x, y);
- checkWidthHeight(width, height);
- if (x + width > source.getWidth()) {
- throw new IllegalArgumentException(
- "x + width must be <= bitmap.width()");
- }
- if (y + height > source.getHeight()) {
- throw new IllegalArgumentException(
- "y + height must be <= bitmap.height()");
- }
-
- // check if we can just return our argument unchanged
- if (!source.isMutable() && x == 0 && y == 0
- && width == source.getWidth() && height == source.getHeight()
- && (m == null || m.isIdentity())) {
- return source;
- }
-
- if (m == null || m.isIdentity()) {
- return new Bitmap(source.mImage.getSubimage(x, y, width, height));
- }
-
- int neww = width;
- int newh = height;
- Paint paint;
-
- Rect srcR = new Rect(x, y, x + width, y + height);
- RectF dstR = new RectF(0, 0, width, height);
-
- /* the dst should have alpha if the src does, or if our matrix
- doesn't preserve rectness
- */
- boolean hasAlpha = source.hasAlpha() || !m.rectStaysRect();
- RectF deviceR = new RectF();
- m.mapRect(deviceR, dstR);
- neww = Math.round(deviceR.width());
- newh = Math.round(deviceR.height());
-
- Canvas canvas = new Canvas(neww, newh);
-
- canvas.translate(-deviceR.left, -deviceR.top);
- canvas.concat(m);
- paint = new Paint();
- paint.setFilterBitmap(filter);
- if (!m.rectStaysRect()) {
- paint.setAntiAlias(true);
- }
-
- canvas.drawBitmap(source, srcR, dstR, paint);
-
- return new Bitmap(canvas.getImage());
- }
-
- /**
- * Returns a mutable bitmap with the specified width and height.
- *
- * @param width The width of the bitmap
- * @param height The height of the bitmap
- * @param config The bitmap config to create.
- * @throws IllegalArgumentException if the width or height are <= 0
- */
- public static Bitmap createBitmap(int width, int height, Config config) {
- return new Bitmap(new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB));
- }
-
- /**
- * Returns a immutable bitmap with the specified width and height, with each
- * pixel value set to the corresponding value in the colors array.
- *
- * @param colors Array of {@link Color} used to initialize the pixels.
- * @param offset Number of values to skip before the first color in the
- * array of colors.
- * @param stride Number of colors in the array between rows (must be >=
- * width or <= -width).
- * @param width The width of the bitmap
- * @param height The height of the bitmap
- * @param config The bitmap config to create. If the config does not
- * support per-pixel alpha (e.g. RGB_565), then the alpha
- * bytes in the colors[] will be ignored (assumed to be FF)
- * @throws IllegalArgumentException if the width or height are <= 0, or if
- * the color array's length is less than the number of pixels.
- */
- public static Bitmap createBitmap(int colors[], int offset, int stride,
- int width, int height, Config config) {
- checkWidthHeight(width, height);
- if (Math.abs(stride) < width) {
- throw new IllegalArgumentException("abs(stride) must be >= width");
- }
- int lastScanline = offset + (height - 1) * stride;
- int length = colors.length;
- if (offset < 0 || (offset + width > length)
- || lastScanline < 0
- || (lastScanline + width > length)) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // TODO: create an immutable bitmap...
- throw new UnsupportedOperationException();
- }
-
- /**
- * Returns a immutable bitmap with the specified width and height, with each
- * pixel value set to the corresponding value in the colors array.
- *
- * @param colors Array of {@link Color} used to initialize the pixels.
- * This array must be at least as large as width * height.
- * @param width The width of the bitmap
- * @param height The height of the bitmap
- * @param config The bitmap config to create. If the config does not
- * support per-pixel alpha (e.g. RGB_565), then the alpha
- * bytes in the colors[] will be ignored (assumed to be FF)
- * @throws IllegalArgumentException if the width or height are <= 0, or if
- * the color array's length is less than the number of pixels.
- */
- public static Bitmap createBitmap(int colors[], int width, int height,
- Config config) {
- return createBitmap(colors, 0, width, width, height, config);
- }
-
- public static Bitmap createScaledBitmap(Bitmap src, int dstWidth,
- int dstHeight, boolean filter) {
- Matrix m;
- synchronized (Bitmap.class) {
- // small pool of just 1 matrix
- m = sScaleMatrix;
- sScaleMatrix = null;
- }
-
- if (m == null) {
- m = new Matrix();
- }
-
- final int width = src.getWidth();
- final int height = src.getHeight();
- final float sx = dstWidth / (float)width;
- final float sy = dstHeight / (float)height;
- m.setScale(sx, sy);
- Bitmap b = Bitmap.createBitmap(src, 0, 0, width, height, m, filter);
-
- synchronized (Bitmap.class) {
- // do we need to check for null? why not just assign everytime?
- if (sScaleMatrix == null) {
- sScaleMatrix = m;
- }
- }
-
- return b;
- }
-
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
deleted file mode 100644
index e978fe8..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory.java
+++ /dev/null
@@ -1,566 +0,0 @@
-/*
- * 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 android.content.res.AssetManager;
-import android.content.res.Resources;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
-
-import java.io.BufferedInputStream;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * Creates Bitmap objects from various sources, including files, streams,
- * and byte-arrays.
- */
-public class BitmapFactory {
- public static class Options {
- /**
- * Create a default Options object, which if left unchanged will give
- * the same result from the decoder as if null were passed.
- */
- public Options() {
- inDither = true;
- inScaled = true;
- }
-
- /**
- * If set to true, the decoder will return null (no bitmap), but
- * the out... fields will still be set, allowing the caller to query
- * the bitmap without having to allocate the memory for its pixels.
- */
- public boolean inJustDecodeBounds;
-
- /**
- * If set to a value > 1, requests the decoder to subsample the original
- * image, returning a smaller image to save memory. The sample size is
- * the number of pixels in either dimension that correspond to a single
- * pixel in the decoded bitmap. For example, inSampleSize == 4 returns
- * an image that is 1/4 the width/height of the original, and 1/16 the
- * number of pixels. Any value <= 1 is treated the same as 1. Note: the
- * decoder will try to fulfill this request, but the resulting bitmap
- * may have different dimensions that precisely what has been requested.
- * Also, powers of 2 are often faster/easier for the decoder to honor.
- */
- public int inSampleSize;
-
- /**
- * If this is non-null, the decoder will try to decode into this
- * internal configuration. If it is null, or the request cannot be met,
- * the decoder will try to pick the best matching config based on the
- * system's screen depth, and characteristics of the original image such
- * as if it has per-pixel alpha (requiring a config that also does).
- */
- public Bitmap.Config inPreferredConfig;
-
- /**
- * If dither is true, the decoder will attempt to dither the decoded
- * image.
- */
- public boolean inDither;
-
- /**
- * The pixel density to use for the bitmap. This will always result
- * in the returned bitmap having a density set for it (see
- * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)). In addition,
- * if {@link #inScaled} is set (which it is by default} and this
- * density does not match {@link #inTargetDensity}, then the bitmap
- * will be scaled to the target density before being returned.
- *
- * <p>If this is 0,
- * {@link BitmapFactory#decodeResource(Resources, int)},
- * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
- * and {@link BitmapFactory#decodeResourceStream}
- * will fill in the density associated with the resource. The other
- * functions will leave it as-is and no density will be applied.
- *
- * @see #inTargetDensity
- * @see #inScreenDensity
- * @see #inScaled
- * @see Bitmap#setDensity(int)
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inDensity;
-
- /**
- * The pixel density of the destination this bitmap will be drawn to.
- * This is used in conjunction with {@link #inDensity} and
- * {@link #inScaled} to determine if and how to scale the bitmap before
- * returning it.
- *
- * <p>If this is 0,
- * {@link BitmapFactory#decodeResource(Resources, int)},
- * {@link BitmapFactory#decodeResource(Resources, int, android.graphics.BitmapFactory.Options)},
- * and {@link BitmapFactory#decodeResourceStream}
- * will fill in the density associated the Resources object's
- * DisplayMetrics. The other
- * functions will leave it as-is and no scaling for density will be
- * performed.
- *
- * @see #inDensity
- * @see #inScreenDensity
- * @see #inScaled
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inTargetDensity;
-
- /**
- * The pixel density of the actual screen that is being used. This is
- * purely for applications running in density compatibility code, where
- * {@link #inTargetDensity} is actually the density the application
- * sees rather than the real screen density.
- *
- * <p>By setting this, you
- * allow the loading code to avoid scaling a bitmap that is currently
- * in the screen density up/down to the compatibility density. Instead,
- * if {@link #inDensity} is the same as {@link #inScreenDensity}, the
- * bitmap will be left as-is. Anything using the resulting bitmap
- * must also used {@link Bitmap#getScaledWidth(int)
- * Bitmap.getScaledWidth} and {@link Bitmap#getScaledHeight
- * Bitmap.getScaledHeight} to account for any different between the
- * bitmap's density and the target's density.
- *
- * <p>This is never set automatically for the caller by
- * {@link BitmapFactory} itself. It must be explicitly set, since the
- * caller must deal with the resulting bitmap in a density-aware way.
- *
- * @see #inDensity
- * @see #inTargetDensity
- * @see #inScaled
- * @see android.util.DisplayMetrics#densityDpi
- */
- public int inScreenDensity;
-
- /**
- * When this flag is set, if {@link #inDensity} and
- * {@link #inTargetDensity} are not 0, the
- * bitmap will be scaled to match {@link #inTargetDensity} when loaded,
- * rather than relying on the graphics system scaling it each time it
- * is drawn to a Canvas.
- *
- * <p>This flag is turned on by default and should be turned off if you need
- * a non-scaled version of the bitmap. Nine-patch bitmaps ignore this
- * flag and are always scaled.
- */
- public boolean inScaled;
-
- /**
- * If this is set to true, then the resulting bitmap will allocate its
- * pixels such that they can be purged if the system needs to reclaim
- * memory. In that instance, when the pixels need to be accessed again
- * (e.g. the bitmap is drawn, getPixels() is called), they will be
- * automatically re-decoded.
- *
- * For the re-decode to happen, the bitmap must have access to the
- * encoded data, either by sharing a reference to the input
- * or by making a copy of it. This distinction is controlled by
- * inInputShareable. If this is true, then the bitmap may keep a shallow
- * reference to the input. If this is false, then the bitmap will
- * explicitly make a copy of the input data, and keep that. Even if
- * sharing is allowed, the implementation may still decide to make a
- * deep copy of the input data.
- */
- public boolean inPurgeable;
-
- /**
- * This field works in conjuction with inPurgeable. If inPurgeable is
- * false, then this field is ignored. If inPurgeable is true, then this
- * field determines whether the bitmap can share a reference to the
- * input data (inputstream, array, etc.) or if it must make a deep copy.
- */
- public boolean inInputShareable;
-
- /**
- * Normally bitmap allocations count against the dalvik heap, which
- * means they help trigger GCs when a lot have been allocated. However,
- * in rare cases, the caller may want to allocate the bitmap outside of
- * that heap. To request that, set inNativeAlloc to true. In these
- * rare instances, it is solely up to the caller to ensure that OOM is
- * managed explicitly by calling bitmap.recycle() as soon as such a
- * bitmap is no longer needed.
- *
- * @hide pending API council approval
- */
- public boolean inNativeAlloc;
-
- /**
- * The resulting width of the bitmap, set independent of the state of
- * inJustDecodeBounds. However, if there is an error trying to decode,
- * outWidth will be set to -1.
- */
- public int outWidth;
-
- /**
- * The resulting height of the bitmap, set independent of the state of
- * inJustDecodeBounds. However, if there is an error trying to decode,
- * outHeight will be set to -1.
- */
- public int outHeight;
-
- /**
- * If known, this string is set to the mimetype of the decoded image.
- * If not know, or there is an error, it is set to null.
- */
- public String outMimeType;
-
- /**
- * Temp storage to use for decoding. Suggest 16K or so.
- */
- public byte[] inTempStorage;
-
- private native void requestCancel();
-
- /**
- * Flag to indicate that cancel has been called on this object. This
- * is useful if there's an intermediary that wants to first decode the
- * bounds and then decode the image. In that case the intermediary
- * can check, inbetween the bounds decode and the image decode, to see
- * if the operation is canceled.
- */
- public boolean mCancel;
-
- /**
- * This can be called from another thread while this options object is
- * inside a decode... call. Calling this will notify the decoder that
- * it should cancel its operation. This is not guaranteed to cancel
- * the decode, but if it does, the decoder... operation will return
- * null, or if inJustDecodeBounds is true, will set outWidth/outHeight
- * to -1
- */
- public void requestCancelDecode() {
- mCancel = true;
- requestCancel();
- }
- }
-
- /**
- * Decode a file path into a bitmap. If the specified file name is null,
- * or cannot be decoded into a bitmap, the function returns null.
- *
- * @param pathName complete path name for the file to be decoded.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeFile(String pathName, Options opts) {
- Bitmap bm = null;
- InputStream stream = null;
- try {
- stream = new FileInputStream(pathName);
- bm = decodeStream(stream, null, opts);
- } catch (Exception e) {
- /* do nothing.
- If the exception happened on open, bm will be null.
- */
- } finally {
- if (stream != null) {
- try {
- stream.close();
- } catch (IOException e) {
- // do nothing here
- }
- }
- }
- return bm;
- }
-
- /**
- * Decode a file path into a bitmap. If the specified file name is null,
- * or cannot be decoded into a bitmap, the function returns null.
- *
- * @param pathName complete path name for the file to be decoded.
- * @return the resulting decoded bitmap, or null if it could not be decoded.
- */
- public static Bitmap decodeFile(String pathName) {
- return decodeFile(pathName, null);
- }
-
- /**
- * Decode a new Bitmap from an InputStream. This InputStream was obtained from
- * resources, which we pass to be able to scale the bitmap accordingly.
- */
- public static Bitmap decodeResourceStream(Resources res, TypedValue value,
- InputStream is, Rect pad, Options opts) {
-
- if (opts == null) {
- opts = new Options();
- }
-
- if (opts.inDensity == 0 && value != null) {
- final int density = value.density;
- if (density == TypedValue.DENSITY_DEFAULT) {
- opts.inDensity = DisplayMetrics.DENSITY_DEFAULT;
- } else if (density != TypedValue.DENSITY_NONE) {
- opts.inDensity = density;
- }
- }
-
- if (opts.inTargetDensity == 0 && res != null) {
- opts.inTargetDensity = res.getDisplayMetrics().densityDpi;
- }
-
- return decodeStream(is, pad, opts);
- }
-
- /**
- * Synonym for opening the given resource and calling
- * {@link #decodeResourceStream}.
- *
- * @param res The resources object containing the image data
- * @param id The resource id of the image data
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeResource(Resources res, int id, Options opts) {
- Bitmap bm = null;
- InputStream is = null;
-
- try {
- final TypedValue value = new TypedValue();
- is = res.openRawResource(id, value);
-
- bm = decodeResourceStream(res, value, is, null, opts);
- } catch (Exception e) {
- /* do nothing.
- If the exception happened on open, bm will be null.
- If it happened on close, bm is still valid.
- */
- } finally {
- try {
- if (is != null) is.close();
- } catch (IOException e) {
- // Ignore
- }
- }
-
- return bm;
- }
-
- /**
- * Synonym for {@link #decodeResource(Resources, int, android.graphics.BitmapFactory.Options)}
- * will null Options.
- *
- * @param res The resources object containing the image data
- * @param id The resource id of the image data
- * @return The decoded bitmap, or null if the image could not be decode.
- */
- public static Bitmap decodeResource(Resources res, int id) {
- return decodeResource(res, id, null);
- }
-
- /**
- * Decode an immutable bitmap from the specified byte array.
- *
- * @param data byte array of compressed image data
- * @param offset offset into imageData for where the decoder should begin
- * parsing.
- * @param length the number of bytes, beginning at offset, to parse
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeByteArray(byte[] data, int offset, int length, Options opts) {
- if ((offset | length) < 0 || data.length < offset + length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // FIXME: implement as needed, but it's unlikely that this is needed in the context of the bridge.
- return null;
- //return nativeDecodeByteArray(data, offset, length, opts);
- }
-
- /**
- * Decode an immutable bitmap from the specified byte array.
- *
- * @param data byte array of compressed image data
- * @param offset offset into imageData for where the decoder should begin
- * parsing.
- * @param length the number of bytes, beginning at offset, to parse
- * @return The decoded bitmap, or null if the image could not be decode.
- */
- public static Bitmap decodeByteArray(byte[] data, int offset, int length) {
- return decodeByteArray(data, offset, length, null);
- }
-
- /**
- * Decode an input stream into a bitmap. If the input stream is null, or
- * cannot be used to decode a bitmap, the function returns null.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is, Rect outPadding, Options opts) {
- // we don't throw in this case, thus allowing the caller to only check
- // the cache, and not force the image to be decoded.
- if (is == null) {
- return null;
- }
-
- // we need mark/reset to work properly
-
- if (!is.markSupported()) {
- is = new BufferedInputStream(is, 16 * 1024);
- }
-
- // so we can call reset() if a given codec gives up after reading up to
- // this many bytes. FIXME: need to find out from the codecs what this
- // value should be.
- is.mark(1024);
-
- Bitmap bm;
-
- if (is instanceof AssetManager.AssetInputStream) {
- // FIXME: log this.
- return null;
- } else {
- // pass some temp storage down to the native code. 1024 is made up,
- // but should be large enough to avoid too many small calls back
- // into is.read(...) This number is not related to the value passed
- // to mark(...) above.
- try {
- bm = new Bitmap(is);
- } catch (IOException e) {
- return null;
- }
- }
-
- return finishDecode(bm, outPadding, opts);
- }
-
- private static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
- if (bm == null || opts == null) {
- return bm;
- }
-
- final int density = opts.inDensity;
- if (density == 0) {
- return bm;
- }
-
- bm.setDensity(density);
- final int targetDensity = opts.inTargetDensity;
- if (targetDensity == 0 || density == targetDensity
- || density == opts.inScreenDensity) {
- return bm;
- }
-
- byte[] np = bm.getNinePatchChunk();
- final boolean isNinePatch = false; //np != null && NinePatch.isNinePatchChunk(np);
- if (opts.inScaled || isNinePatch) {
- float scale = targetDensity / (float)density;
- // TODO: This is very inefficient and should be done in native by Skia
- final Bitmap oldBitmap = bm;
- bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
- (int) (bm.getHeight() * scale + 0.5f), true);
- oldBitmap.recycle();
-
- if (isNinePatch) {
- //np = nativeScaleNinePatch(np, scale, outPadding);
- bm.setNinePatchChunk(np);
- }
- bm.setDensity(targetDensity);
- }
-
- return bm;
- }
-
- /**
- * Decode an input stream into a bitmap. If the input stream is null, or
- * cannot be used to decode a bitmap, the function returns null.
- * The stream's position will be where ever it was after the encoded data
- * was read.
- *
- * @param is The input stream that holds the raw data to be decoded into a
- * bitmap.
- * @return The decoded bitmap, or null if the image data could not be
- * decoded, or, if opts is non-null, if opts requested only the
- * size be returned (in opts.outWidth and opts.outHeight)
- */
- public static Bitmap decodeStream(InputStream is) {
- return decodeStream(is, null, null);
- }
-
- /**
- * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
- * return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as-is.
- *
- * @param fd The file descriptor containing the bitmap data to decode
- * @param outPadding If not null, return the padding rect for the bitmap if
- * it exists, otherwise set padding to [-1,-1,-1,-1]. If
- * no bitmap is returned (null) then padding is
- * unchanged.
- * @param opts null-ok; Options that control downsampling and whether the
- * image should be completely decoded, or just is size returned.
- * @return the decoded bitmap, or null
- */
- public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) {
- return null;
-
- /* FIXME: implement as needed
- try {
- if (MemoryFile.isMemoryFile(fd)) {
- int mappedlength = MemoryFile.getMappedSize(fd);
- MemoryFile file = new MemoryFile(fd, mappedlength, "r");
- InputStream is = file.getInputStream();
- Bitmap bm = decodeStream(is, outPadding, opts);
- return finishDecode(bm, outPadding, opts);
- }
- } catch (IOException ex) {
- // invalid filedescriptor, no need to call nativeDecodeFileDescriptor()
- return null;
- }
- //Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts);
- //return finishDecode(bm, outPadding, opts);
- */
- }
-
- /**
- * Decode a bitmap from the file descriptor. If the bitmap cannot be decoded
- * return null. The position within the descriptor will not be changed when
- * this returns, so the descriptor can be used again as is.
- *
- * @param fd The file descriptor containing the bitmap data to decode
- * @return the decoded bitmap, or null
- */
- public static Bitmap decodeFileDescriptor(FileDescriptor fd) {
- return decodeFileDescriptor(fd, null, null);
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
new file mode 100644
index 0000000..080b85f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapFactory_Delegate.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2011 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.android.BridgeResources.NinePatchInputStream;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.ninepatch.NinePatchChunk;
+import com.android.resources.Density;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.BitmapFactory.Options;
+
+import java.io.FileDescriptor;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BitmapFactory
+ *
+ * Through the layoutlib_create tool, the original native methods of BitmapFactory have been
+ * replaced by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+/*package*/ class BitmapFactory_Delegate {
+
+ // ------ Java delegates ------
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap finishDecode(Bitmap bm, Rect outPadding, Options opts) {
+ if (bm == null || opts == null) {
+ return bm;
+ }
+
+ final int density = opts.inDensity;
+ if (density == 0) {
+ return bm;
+ }
+
+ bm.setDensity(density);
+ final int targetDensity = opts.inTargetDensity;
+ if (targetDensity == 0 || density == targetDensity || density == opts.inScreenDensity) {
+ return bm;
+ }
+
+ byte[] np = bm.getNinePatchChunk();
+ final boolean isNinePatch = np != null && NinePatch.isNinePatchChunk(np);
+ // DELEGATE CHANGE: never scale 9-patch
+ if (opts.inScaled && isNinePatch == false) {
+ float scale = targetDensity / (float)density;
+ // TODO: This is very inefficient and should be done in native by Skia
+ final Bitmap oldBitmap = bm;
+ bm = Bitmap.createScaledBitmap(oldBitmap, (int) (bm.getWidth() * scale + 0.5f),
+ (int) (bm.getHeight() * scale + 0.5f), true);
+ oldBitmap.recycle();
+
+ if (isNinePatch) {
+ np = nativeScaleNinePatch(np, scale, outPadding);
+ bm.setNinePatchChunk(np);
+ }
+ bm.setDensity(targetDensity);
+ }
+
+ return bm;
+ }
+
+
+ // ------ Native Delegates ------
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetDefaultConfig(int nativeConfig) {
+ // pass
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeStream(InputStream is, byte[] storage,
+ Rect padding, Options opts) {
+ Bitmap bm = null;
+
+ Density density = Density.MEDIUM;
+ if (opts != null) {
+ density = Density.getEnum(opts.inDensity);
+ }
+
+ try {
+ if (is instanceof NinePatchInputStream) {
+ NinePatchInputStream npis = (NinePatchInputStream) is;
+ npis.disableFakeMarkSupport();
+
+ // load the bitmap as a nine patch
+ com.android.ninepatch.NinePatch ninePatch = com.android.ninepatch.NinePatch.load(
+ npis, true /*is9Patch*/, false /*convert*/);
+
+ // get the bitmap and chunk objects.
+ bm = Bitmap_Delegate.createBitmap(ninePatch.getImage(), true /*isMutable*/,
+ density);
+ NinePatchChunk chunk = ninePatch.getChunk();
+
+ // put the chunk in the bitmap
+ bm.setNinePatchChunk(NinePatch_Delegate.serialize(chunk));
+
+ // read the padding
+ int[] paddingarray = chunk.getPadding();
+ padding.left = paddingarray[0];
+ padding.top = paddingarray[1];
+ padding.right = paddingarray[2];
+ padding.bottom = paddingarray[3];
+ } else {
+ // load the bitmap directly.
+ bm = Bitmap_Delegate.createBitmap(is, true, density);
+ }
+ } catch (IOException e) {
+ Bridge.getLog().error(null,"Failed to load image" , e, null);
+ }
+
+ return bm;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeFileDescriptor(FileDescriptor fd,
+ Rect padding, Options opts) {
+ opts.inBitmap = null;
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeAsset(int asset, Rect padding, Options opts) {
+ opts.inBitmap = null;
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeDecodeByteArray(byte[] data, int offset,
+ int length, Options opts) {
+ opts.inBitmap = null;
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad) {
+ // don't scale for now. This should not be called anyway since we re-implement
+ // BitmapFactory.finishDecode();
+ return chunk;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeIsSeekable(FileDescriptor fd) {
+ return true;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader.java
deleted file mode 100644
index ad3974c..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/BitmapShader.java
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * Copyright (C) 2008 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 java.awt.Paint;
-
-public class BitmapShader extends Shader {
-
- // we hold on just for the GC, since our native counterpart is using it
- private final Bitmap mBitmap;
-
- /**
- * Call this to create a new shader that will draw with a bitmap.
- *
- * @param bitmap The bitmap to use inside the shader
- * @param tileX The tiling mode for x to draw the bitmap in.
- * @param tileY The tiling mode for y to draw the bitmap in.
- */
- public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) {
- mBitmap = bitmap;
- }
-
- //---------- Custom methods
-
- public Bitmap getBitmap() {
- return mBitmap;
- }
-
- @Override
- Paint getJavaPaint() {
- return null;
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
new file mode 100644
index 0000000..9a8cf04
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BitmapShader_Delegate.java
@@ -0,0 +1,247 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BitmapShader
+ *
+ * Through the layoutlib_create tool, the original native methods of BitmapShader 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 BitmapShader class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class BitmapShader_Delegate extends Shader_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // no message since isSupported returns true;
+ return null;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int native_bitmap, int shaderTileModeX,
+ int shaderTileModeY) {
+ Bitmap_Delegate bitmap = Bitmap_Delegate.getDelegate(native_bitmap);
+ if (bitmap == null) {
+ return 0;
+ }
+
+ BitmapShader_Delegate newDelegate = new BitmapShader_Delegate(
+ bitmap.getImage(),
+ Shader_Delegate.getTileMode(shaderTileModeX),
+ Shader_Delegate.getTileMode(shaderTileModeY));
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate(int native_shader, int native_bitmap,
+ int shaderTileModeX, int shaderTileModeY) {
+ // pass, not needed.
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private BitmapShader_Delegate(java.awt.image.BufferedImage image,
+ TileMode tileModeX, TileMode tileModeY) {
+ mJavaPaint = new BitmapShaderPaint(image, tileModeX, tileModeY);
+ }
+
+ private class BitmapShaderPaint implements java.awt.Paint {
+ private final java.awt.image.BufferedImage mImage;
+ private final TileMode mTileModeX;
+ private final TileMode mTileModeY;
+
+ BitmapShaderPaint(java.awt.image.BufferedImage image,
+ TileMode tileModeX, TileMode tileModeY) {
+ mImage = image;
+ mTileModeX = tileModeX;
+ mTileModeY = tileModeY;
+ }
+
+ public java.awt.PaintContext createContext(
+ java.awt.image.ColorModel colorModel,
+ java.awt.Rectangle deviceBounds,
+ java.awt.geom.Rectangle2D userBounds,
+ java.awt.geom.AffineTransform xform,
+ java.awt.RenderingHints hints) {
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in BitmapShader", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in BitmapShader", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new BitmapShaderContext(canvasMatrix, localMatrix, colorModel);
+ }
+
+ private class BitmapShaderContext implements java.awt.PaintContext {
+
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
+ private final java.awt.image.ColorModel mColorModel;
+
+ public BitmapShaderContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
+ mColorModel = colorModel;
+ }
+
+ public void dispose() {
+ }
+
+ public java.awt.image.ColorModel getColorModel() {
+ return mColorModel;
+ }
+
+ public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
+ java.awt.image.BufferedImage.TYPE_INT_ARGB);
+
+ int[] data = new int[w*h];
+
+ int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
+ for (int iy = 0 ; iy < h ; iy++) {
+ for (int ix = 0 ; ix < w ; ix++) {
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix.
+ pt1[0] = pt2[0];
+ pt1[1] = pt2[1];
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ data[index++] = getColor(pt2[0], pt2[1]);
+ }
+ }
+
+ image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+ return image.getRaster();
+ }
+ }
+
+ /**
+ * Returns a color for an arbitrary point.
+ */
+ private int getColor(float fx, float fy) {
+ int x = getCoordinate(Math.round(fx), mImage.getWidth(), mTileModeX);
+ int y = getCoordinate(Math.round(fy), mImage.getHeight(), mTileModeY);
+
+ return mImage.getRGB(x, y);
+ }
+
+ private int getCoordinate(int i, int size, TileMode mode) {
+ if (i < 0) {
+ switch (mode) {
+ case CLAMP:
+ i = 0;
+ break;
+ case REPEAT:
+ i = size - 1 - (-i % size);
+ break;
+ case MIRROR:
+ // this is the same as the positive side, just make the value positive
+ // first.
+ i = -i;
+ int count = i / size;
+ i = i % size;
+
+ if ((count % 2) == 1) {
+ i = size - 1 - i;
+ }
+ break;
+ }
+ } else if (i >= size) {
+ switch (mode) {
+ case CLAMP:
+ i = size - 1;
+ break;
+ case REPEAT:
+ i = i % size;
+ break;
+ case MIRROR:
+ int count = i / size;
+ i = i % size;
+
+ if ((count % 2) == 1) {
+ i = size - 1 - i;
+ }
+ break;
+ }
+ }
+
+ return i;
+ }
+
+
+ public int getTransparency() {
+ return java.awt.Paint.TRANSLUCENT;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
new file mode 100644
index 0000000..66e59d8
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Bitmap_Delegate.java
@@ -0,0 +1,563 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.resources.Density;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.os.Parcel;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.Buffer;
+import java.util.Arrays;
+
+import javax.imageio.ImageIO;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Bitmap
+ *
+ * Through the layoutlib_create tool, the original native methods of Bitmap 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 Bitmap class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Bitmap_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Bitmap_Delegate> sManager =
+ new DelegateManager<Bitmap_Delegate>(Bitmap_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+ private final Config mConfig;
+ private BufferedImage mImage;
+ private boolean mHasAlpha = true;
+ private int mGenerationId = 0;
+
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Returns the native delegate associated to a given {@link Bitmap_Delegate} object.
+ */
+ public static Bitmap_Delegate getDelegate(Bitmap bitmap) {
+ return sManager.getDelegate(bitmap.mNativeBitmap);
+ }
+
+ /**
+ * Returns the native delegate associated to a given an int referencing a {@link Bitmap} object.
+ */
+ public static Bitmap_Delegate getDelegate(int native_bitmap) {
+ return sManager.getDelegate(native_bitmap);
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given file content.
+ *
+ * @param input the file from which to read the bitmap content
+ * @param isMutable whether the bitmap is mutable
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(File input, boolean isMutable, Density density)
+ throws IOException {
+ // create a delegate with the content of the file.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
+
+ return createBitmap(delegate, isMutable, density.getDpiValue());
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given stream content.
+ *
+ * @param input the stream from which to read the bitmap content
+ * @param isMutable whether the bitmap is mutable
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(InputStream input, boolean isMutable, Density density)
+ throws IOException {
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(ImageIO.read(input), Config.ARGB_8888);
+
+ return createBitmap(delegate, isMutable, density.getDpiValue());
+ }
+
+ /**
+ * Creates and returns a {@link Bitmap} initialized with the given {@link BufferedImage}
+ *
+ * @param image the bitmap content
+ * @param isMutable whether the bitmap is mutable
+ * @param density the density associated with the bitmap
+ *
+ * @see Bitmap#isMutable()
+ * @see Bitmap#getDensity()
+ */
+ public static Bitmap createBitmap(BufferedImage image, boolean isMutable,
+ Density density) throws IOException {
+ // create a delegate with the given image.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ARGB_8888);
+
+ return createBitmap(delegate, isMutable, density.getDpiValue());
+ }
+
+ /**
+ * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
+ */
+ public static BufferedImage getImage(Bitmap bitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(bitmap.mNativeBitmap);
+ if (delegate == null) {
+ return null;
+ }
+
+ return delegate.mImage;
+ }
+
+ public static int getBufferedImageType(int nativeBitmapConfig) {
+ switch (Config.sConfigs[nativeBitmapConfig]) {
+ case ALPHA_8:
+ return BufferedImage.TYPE_INT_ARGB;
+ case RGB_565:
+ return BufferedImage.TYPE_INT_ARGB;
+ case ARGB_4444:
+ return BufferedImage.TYPE_INT_ARGB;
+ case ARGB_8888:
+ return BufferedImage.TYPE_INT_ARGB;
+ }
+
+ return BufferedImage.TYPE_INT_ARGB;
+ }
+
+ /**
+ * Returns the {@link BufferedImage} used by the delegate of the given {@link Bitmap}.
+ */
+ public BufferedImage getImage() {
+ return mImage;
+ }
+
+ /**
+ * Returns the Android bitmap config. Note that this not the config of the underlying
+ * Java2D bitmap.
+ */
+ public Config getConfig() {
+ return mConfig;
+ }
+
+ /**
+ * Returns the hasAlpha rendering hint
+ * @return true if the bitmap alpha should be used at render time
+ */
+ public boolean hasAlpha() {
+ return mHasAlpha && mConfig != Config.RGB_565;
+ }
+
+ /**
+ * Update the generationId.
+ *
+ * @see Bitmap#getGenerationId()
+ */
+ public void change() {
+ mGenerationId++;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCreate(int[] colors, int offset, int stride, int width,
+ int height, int nativeConfig, boolean mutable) {
+ int imageType = getBufferedImageType(nativeConfig);
+
+ // create the image
+ BufferedImage image = new BufferedImage(width, height, imageType);
+
+ if (colors != null) {
+ image.setRGB(0, 0, width, height, colors, offset, stride);
+ }
+
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
+
+ return createBitmap(delegate, mutable, Bitmap.getDefaultDensity());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCopy(int srcBitmap, int nativeConfig, boolean isMutable) {
+ Bitmap_Delegate srcBmpDelegate = sManager.getDelegate(srcBitmap);
+ if (srcBmpDelegate == null) {
+ return null;
+ }
+
+ BufferedImage srcImage = srcBmpDelegate.getImage();
+
+ int width = srcImage.getWidth();
+ int height = srcImage.getHeight();
+
+ int imageType = getBufferedImageType(nativeConfig);
+
+ // create the image
+ BufferedImage image = new BufferedImage(width, height, imageType);
+
+ // copy the source image into the image.
+ int[] argb = new int[width * height];
+ srcImage.getRGB(0, 0, width, height, argb, 0, width);
+ image.setRGB(0, 0, width, height, argb, 0, width);
+
+ // create a delegate with the content of the stream.
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.sConfigs[nativeConfig]);
+
+ return createBitmap(delegate, isMutable, Bitmap.getDefaultDensity());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int nativeBitmap) {
+ sManager.removeJavaReferenceFor(nativeBitmap);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeRecycle(int nativeBitmap) {
+ sManager.removeJavaReferenceFor(nativeBitmap);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeCompress(int nativeBitmap, int format, int quality,
+ OutputStream stream, byte[] tempStorage) {
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.compress() is not supported", null /*data*/);
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeErase(int nativeBitmap, int color) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ BufferedImage image = delegate.mImage;
+
+ Graphics2D g = image.createGraphics();
+ try {
+ g.setColor(new java.awt.Color(color, true));
+
+ g.fillRect(0, 0, image.getWidth(), image.getHeight());
+ } finally {
+ g.dispose();
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeWidth(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getWidth();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeHeight(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getHeight();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeRowBytes(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getWidth();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConfig(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mConfig.nativeInt;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeHasAlpha(int nativeBitmap) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return true;
+ }
+
+ return delegate.mHasAlpha;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeGetPixel(int nativeBitmap, int x, int y) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mImage.getRGB(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeGetPixels(int nativeBitmap, int[] pixels, int offset,
+ int stride, int x, int y, int width, int height) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.getImage().getRGB(x, y, width, height, pixels, offset, stride);
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetPixel(int nativeBitmap, int x, int y, int color) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.getImage().setRGB(x, y, color);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetPixels(int nativeBitmap, int[] colors, int offset,
+ int stride, int x, int y, int width, int height) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.getImage().setRGB(x, y, width, height, colors, offset, stride);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst) {
+ // FIXME implement native delegate
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.copyPixelsToBuffer is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeCopyPixelsFromBuffer(int nb, Buffer src) {
+ // FIXME implement native delegate
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Bitmap.copyPixelsFromBuffer is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeGenerationId(int nativeBitmap) {
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mGenerationId;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeCreateFromParcel(Parcel p) {
+ // 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(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Bitmaps cannot be created from parcels.",
+ null /*data*/);
+ return null;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeWriteToParcel(int nativeBitmap, boolean isMutable,
+ int density, Parcel p) {
+ // This is only called when sending a bitmap through aidl, so really this should not
+ // be called.
+ Bridge.getLog().error(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Bitmaps cannot be written to parcels.",
+ null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static Bitmap nativeExtractAlpha(int nativeBitmap, int nativePaint,
+ int[] offsetXY) {
+ Bitmap_Delegate bitmap = sManager.getDelegate(nativeBitmap);
+ if (bitmap == null) {
+ return null;
+ }
+
+ // get the paint which can be null if nativePaint is 0.
+ Paint_Delegate paint = Paint_Delegate.getDelegate(nativePaint);
+
+ if (paint != null && paint.getMaskFilter() != null) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
+ "MaskFilter not supported in Bitmap.extractAlpha",
+ null, null /*data*/);
+ }
+
+ int alpha = paint != null ? paint.getAlpha() : 0xFF;
+ BufferedImage image = createCopy(bitmap.getImage(), BufferedImage.TYPE_INT_ARGB, alpha);
+
+ // create the delegate. The actual Bitmap config is only an alpha channel
+ Bitmap_Delegate delegate = new Bitmap_Delegate(image, Config.ALPHA_8);
+
+ // the density doesn't matter, it's set by the Java method.
+ return createBitmap(delegate, false /*isMutable*/,
+ Density.DEFAULT_DENSITY /*density*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativePrepareToDraw(int nativeBitmap) {
+ // nothing to be done here.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetHasAlpha(int nativeBitmap, boolean hasAlpha) {
+ // get the delegate from the native int.
+ Bitmap_Delegate delegate = sManager.getDelegate(nativeBitmap);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mHasAlpha = hasAlpha;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean nativeSameAs(int nb0, int nb1) {
+ Bitmap_Delegate delegate1 = sManager.getDelegate(nb0);
+ if (delegate1 == null) {
+ return false;
+ }
+
+ Bitmap_Delegate delegate2 = sManager.getDelegate(nb1);
+ if (delegate2 == null) {
+ return false;
+ }
+
+ BufferedImage image1 = delegate1.getImage();
+ BufferedImage image2 = delegate2.getImage();
+ if (delegate1.mConfig != delegate2.mConfig ||
+ image1.getWidth() != image2.getWidth() ||
+ image1.getHeight() != image2.getHeight()) {
+ return false;
+ }
+
+ // get the internal data
+ int w = image1.getWidth();
+ int h = image2.getHeight();
+ int[] argb1 = new int[w*h];
+ int[] argb2 = new int[w*h];
+
+ image1.getRGB(0, 0, w, h, argb1, 0, w);
+ image2.getRGB(0, 0, w, h, argb2, 0, w);
+
+ // compares
+ if (delegate1.mConfig == Config.ALPHA_8) {
+ // in this case we have to manually compare the alpha channel as the rest is garbage.
+ final int length = w*h;
+ for (int i = 0 ; i < length ; i++) {
+ if ((argb1[i] & 0xFF000000) != (argb2[i] & 0xFF000000)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ return Arrays.equals(argb1, argb2);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private Bitmap_Delegate(BufferedImage image, Config config) {
+ mImage = image;
+ mConfig = config;
+ }
+
+ private static Bitmap createBitmap(Bitmap_Delegate delegate, boolean isMutable, int density) {
+ // get its native_int
+ int nativeInt = sManager.addNewDelegate(delegate);
+
+ // and create/return a new Bitmap with it
+ return new Bitmap(nativeInt, null /* buffer */, isMutable, null /*ninePatchChunk*/, density);
+ }
+
+ /**
+ * Creates and returns a copy of a given BufferedImage.
+ * <p/>
+ * if alpha is different than 255, then it is applied to the alpha channel of each pixel.
+ *
+ * @param image the image to copy
+ * @param imageType the type of the new image
+ * @param alpha an optional alpha modifier
+ * @return a new BufferedImage
+ */
+ /*package*/ static BufferedImage createCopy(BufferedImage image, int imageType, int alpha) {
+ int w = image.getWidth();
+ int h = image.getHeight();
+
+ BufferedImage result = new BufferedImage(w, h, imageType);
+
+ int[] argb = new int[w * h];
+ image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
+
+ if (alpha != 255) {
+ final int length = argb.length;
+ for (int i = 0 ; i < length; i++) {
+ int a = (argb[i] >>> 24 * alpha) / 255;
+ argb[i] = (a << 24) | (argb[i] & 0x00FFFFFF);
+ }
+ }
+
+ result.setRGB(0, 0, w, h, argb, 0, w);
+
+ return result;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
new file mode 100644
index 0000000..4becba1
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/BlurMaskFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.BlurMaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of BlurMaskFilter 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 BlurMaskFilter class.
+ *
+ * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link MaskFilter_Delegate}.
+ *
+ * @see MaskFilter_Delegate
+ *
+ */
+public class BlurMaskFilter_Delegate extends MaskFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Blur Mask Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor(float radius, int style) {
+ BlurMaskFilter_Delegate newDelegate = new BlurMaskFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas.java b/tools/layoutlib/bridge/src/android/graphics/Canvas.java
deleted file mode 100644
index d5d315e..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Canvas.java
+++ /dev/null
@@ -1,1279 +0,0 @@
-/*
- * Copyright (C) 2008 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.api.ILayoutLog;
-
-import android.graphics.DrawFilter;
-import android.graphics.Picture;
-import android.graphics.PorterDuff;
-import android.graphics.Rect;
-import android.graphics.RectF;
-import android.graphics.Region;
-import android.graphics.Xfermode;
-import android.graphics.Paint.Align;
-import android.graphics.Paint.FontInfo;
-import android.graphics.Paint.Style;
-import android.graphics.Region.Op;
-
-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;
-import java.awt.geom.AffineTransform;
-import java.awt.image.BufferedImage;
-import java.util.List;
-import java.util.Stack;
-
-import javax.microedition.khronos.opengles.GL;
-
-/**
- * Re-implementation of the Canvas, 100% in java on top of a BufferedImage.
- */
-public class Canvas extends _Original_Canvas {
-
- private BufferedImage mBufferedImage;
- private final Stack<Graphics2D> mGraphicsStack = new Stack<Graphics2D>();
- private final ILayoutLog mLogger;
-
- public Canvas() {
- mLogger = null;
- // the mBufferedImage will be taken from a bitmap in #setBitmap()
- }
-
- public Canvas(Bitmap bitmap) {
- mLogger = null;
- mBufferedImage = bitmap.getImage();
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
- public Canvas(int nativeCanvas) {
- mLogger = null;
- throw new UnsupportedOperationException("Can't create Canvas(int)");
- }
-
- public Canvas(javax.microedition.khronos.opengles.GL gl) {
- mLogger = null;
- throw new UnsupportedOperationException("Can't create Canvas(javax.microedition.khronos.opengles.GL)");
- }
-
- // custom constructors for our use.
- public Canvas(int width, int height, ILayoutLog logger) {
- mLogger = logger;
- mBufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
- public Canvas(int width, int height) {
- this(width, height, null /* logger*/);
- }
-
- // custom mehtods
- public BufferedImage getImage() {
- return mBufferedImage;
- }
-
- public Graphics2D getGraphics2d() {
- return mGraphicsStack.peek();
- }
-
- public void dispose() {
- while (mGraphicsStack.size() > 0) {
- mGraphicsStack.pop().dispose();
- }
- }
-
- /**
- * Creates a new {@link Graphics2D} based on the {@link Paint} parameters.
- * <p/>The object must be disposed ({@link Graphics2D#dispose()}) after being used.
- */
- private Graphics2D getCustomGraphics(Paint paint) {
- // make new one
- Graphics2D g = getGraphics2d();
- g = (Graphics2D)g.create();
-
- // configure it
- g.setColor(new Color(paint.getColor()));
- int alpha = paint.getAlpha();
- float falpha = alpha / 255.f;
-
- Style style = paint.getStyle();
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- PathEffect e = paint.getPathEffect();
- if (e instanceof DashPathEffect) {
- DashPathEffect dpe = (DashPathEffect)e;
- g.setStroke(new BasicStroke(
- paint.getStrokeWidth(),
- paint.getStrokeCap().getJavaCap(),
- paint.getStrokeJoin().getJavaJoin(),
- paint.getStrokeMiter(),
- dpe.getIntervals(),
- dpe.getPhase()));
- } else {
- g.setStroke(new BasicStroke(
- paint.getStrokeWidth(),
- paint.getStrokeCap().getJavaCap(),
- paint.getStrokeJoin().getJavaJoin(),
- paint.getStrokeMiter()));
- }
- }
-
- Xfermode xfermode = paint.getXfermode();
- if (xfermode instanceof PorterDuffXfermode) {
- PorterDuff.Mode mode = ((PorterDuffXfermode)xfermode).getMode();
-
- setModeInGraphics(mode, g, falpha);
- } else {
- if (mLogger != null && xfermode != null) {
- mLogger.warning(String.format(
- "Xfermode '%1$s' is not supported in the Layout Editor.",
- xfermode.getClass().getCanonicalName()));
- }
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
- }
-
- Shader shader = paint.getShader();
- if (shader != null) {
- java.awt.Paint shaderPaint = shader.getJavaPaint();
- if (shaderPaint != null) {
- g.setPaint(shaderPaint);
- } else {
- if (mLogger != null) {
- mLogger.warning(String.format(
- "Shader '%1$s' is not supported in the Layout Editor.",
- shader.getClass().getCanonicalName()));
- }
- }
- }
-
- return g;
- }
-
- private void setModeInGraphics(PorterDuff.Mode mode, Graphics2D g, float falpha) {
- switch (mode) {
- case CLEAR:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha));
- break;
- case DARKEN:
- break;
- case DST:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST, falpha));
- break;
- case DST_ATOP:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha));
- break;
- case DST_IN:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha));
- break;
- case DST_OUT:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha));
- break;
- case DST_OVER:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha));
- break;
- case LIGHTEN:
- break;
- case MULTIPLY:
- break;
- case SCREEN:
- break;
- case SRC:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC, falpha));
- break;
- case SRC_ATOP:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha));
- break;
- case SRC_IN:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha));
- break;
- case SRC_OUT:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha));
- break;
- case SRC_OVER:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
- break;
- case XOR:
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.XOR, falpha));
- break;
- }
- }
-
-
- // --------------------
- // OVERRIDEN ENUMS
- // This is needed since we rename Canvas into _Original_Canvas
- // --------------------
-
- public enum EdgeType {
- BW(0), //!< treat edges by just rounding to nearest pixel boundary
- AA(1); //!< treat edges by rounding-out, since they may be antialiased
-
- EdgeType(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
-
- // --------------------
- // OVERRIDEN METHODS
- // --------------------
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setBitmap(android.graphics.Bitmap)
- */
- @Override
- public void setBitmap(Bitmap bitmap) {
- mBufferedImage = bitmap.getImage();
- mGraphicsStack.push(mBufferedImage.createGraphics());
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#translate(float, float)
- */
- @Override
- public void translate(float dx, float dy) {
- getGraphics2d().translate(dx, dy);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#save()
- */
- @Override
- public int save() {
- // get the current save count
- int count = mGraphicsStack.size();
-
- // create a new graphics and add it to the stack
- Graphics2D g = (Graphics2D)getGraphics2d().create();
- mGraphicsStack.push(g);
-
- // return the old save count
- return count;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#save(int)
- */
- @Override
- public int save(int saveFlags) {
- // For now we ignore saveFlags
- return save();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#restore()
- */
- @Override
- public void restore() {
- mGraphicsStack.pop();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#restoreToCount(int)
- */
- @Override
- public void restoreToCount(int saveCount) {
- while (mGraphicsStack.size() > saveCount) {
- mGraphicsStack.pop();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getSaveCount()
- */
- @Override
- public int getSaveCount() {
- return mGraphicsStack.size();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(float, float, float, float, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(float left, float top, float right, float bottom, Op op) {
- return clipRect(left, top, right, bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(float, float, float, float)
- */
- @Override
- public boolean clipRect(float left, float top, float right, float bottom) {
- getGraphics2d().clipRect((int)left, (int)top, (int)(right-left), (int)(bottom-top));
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(int, int, int, int)
- */
- @Override
- public boolean clipRect(int left, int top, int right, int bottom) {
- getGraphics2d().clipRect(left, top, right-left, bottom-top);
- return true;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.Rect, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(Rect rect, Op op) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.Rect)
- */
- @Override
- public boolean clipRect(Rect rect) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.RectF, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRect(RectF rect, Op op) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRect(android.graphics.RectF)
- */
- @Override
- public boolean clipRect(RectF rect) {
- return clipRect(rect.left, rect.top, rect.right, rect.bottom);
- }
-
- public boolean quickReject(RectF rect, EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(RectF rect, _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public boolean quickReject(Path path, EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(Path path, _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public boolean quickReject(float left, float top, float right, float bottom,
- EdgeType type) {
- return false;
- }
-
- @Override
- public boolean quickReject(float left, float top, float right, float bottom,
- _Original_Canvas.EdgeType type) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Retrieve the clip bounds, returning true if they are non-empty.
- *
- * @param bounds Return the clip bounds here. If it is null, ignore it but
- * still return true if the current clip is non-empty.
- * @return true if the current clip is non-empty.
- */
- @Override
- public boolean getClipBounds(Rect bounds) {
- Rectangle rect = getGraphics2d().getClipBounds();
- if (rect != null) {
- bounds.left = rect.x;
- bounds.top = rect.y;
- bounds.right = rect.x + rect.width;
- bounds.bottom = rect.y + rect.height;
- return true;
- }
- return false;
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawColor(int, android.graphics.PorterDuff.Mode)
- */
- @Override
- public void drawColor(int color, PorterDuff.Mode mode) {
- Graphics2D g = getGraphics2d();
-
- // save old color
- Color c = g.getColor();
-
- Composite composite = g.getComposite();
-
- // get the alpha from the color
- int alpha = color >>> 24;
- float falpha = alpha / 255.f;
-
- setModeInGraphics(mode, g, falpha);
-
- g.setColor(new Color(color));
-
- g.fillRect(0, 0, getWidth(), getHeight());
-
- g.setComposite(composite);
-
- // restore color
- g.setColor(c);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawColor(int)
- */
- @Override
- public void drawColor(int color) {
- drawColor(color, PorterDuff.Mode.SRC_OVER);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawARGB(int, int, int, int)
- */
- @Override
- public void drawARGB(int a, int r, int g, int b) {
- drawColor(a << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRGB(int, int, int)
- */
- @Override
- public void drawRGB(int r, int g, int b) {
- drawColor(0xFF << 24 | r << 16 | g << 8 | b, PorterDuff.Mode.SRC_OVER);
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getWidth()
- */
- @Override
- public int getWidth() {
- return mBufferedImage.getWidth();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getHeight()
- */
- @Override
- public int getHeight() {
- return mBufferedImage.getHeight();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPaint(android.graphics.Paint)
- */
- @Override
- public void drawPaint(Paint paint) {
- drawColor(paint.getColor());
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, float, float, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- (int)left, (int)top,
- (int)left+bitmap.getWidth(), (int)top+bitmap.getHeight(), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Matrix, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
- boolean needsRestore = false;
- if (matrix.isIdentity() == false) {
- // create a new graphics and apply the matrix to it
- save(); // this creates a new Graphics2D, and stores it for children call to use
- needsRestore = true;
- Graphics2D g = getGraphics2d(); // get the newly create Graphics2D
-
- // get the Graphics2D current matrix
- AffineTransform currentTx = g.getTransform();
- // get the AffineTransform from the matrix
- AffineTransform matrixTx = matrix.getTransform();
-
- // combine them so that the matrix is applied after.
- currentTx.preConcatenate(matrixTx);
-
- // give it to the graphics as a new matrix replacing all previous transform
- g.setTransform(currentTx);
- }
-
- // draw the bitmap
- drawBitmap(bitmap, 0, 0, paint);
-
- if (needsRestore) {
- // remove the new graphics
- restore();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.Rect, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
- if (src == null) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- dst.left, dst.top, dst.right, dst.bottom, paint);
- } else {
- drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
- dst.left, dst.top, dst.right, dst.bottom, paint);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(android.graphics.Bitmap, android.graphics.Rect, android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
- if (src == null) {
- drawBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(),
- (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
- } else {
- drawBitmap(bitmap, src.left, src.top, src.width(), src.height(),
- (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom, paint);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmap(int[], int, int, int, int, int, int, boolean, android.graphics.Paint)
- */
- @Override
- public void drawBitmap(int[] colors, int offset, int stride, int x, int y, int width,
- int height, boolean hasAlpha, Paint paint) {
- throw new UnsupportedOperationException();
- }
-
- private void drawBitmap(Bitmap bitmap, int sleft, int stop, int sright, int sbottom, int dleft,
- int dtop, int dright, int dbottom, Paint paint) {
- BufferedImage image = bitmap.getImage();
-
- Graphics2D g = getGraphics2d();
-
- Composite c = null;
-
- if (paint != null) {
- if (paint.isFilterBitmap()) {
- g = (Graphics2D)g.create();
- g.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
- RenderingHints.VALUE_INTERPOLATION_BILINEAR);
- }
-
- if (paint.getAlpha() != 0xFF) {
- c = g.getComposite();
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
- paint.getAlpha()/255.f));
- }
- }
-
- g.drawImage(image, dleft, dtop, dright, dbottom,
- sleft, stop, sright, sbottom, null);
-
- if (paint != null) {
- if (paint.isFilterBitmap()) {
- g.dispose();
- }
- if (c != null) {
- g.setComposite(c);
- }
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#rotate(float, float, float)
- */
- @Override
- public void rotate(float degrees, float px, float py) {
- if (degrees != 0) {
- Graphics2D g = getGraphics2d();
- g.translate(px, py);
- g.rotate(Math.toRadians(degrees));
- g.translate(-px, -py);
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#rotate(float)
- */
- @Override
- public void rotate(float degrees) {
- getGraphics2d().rotate(Math.toRadians(degrees));
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#scale(float, float, float, float)
- */
- @Override
- public void scale(float sx, float sy, float px, float py) {
- Graphics2D g = getGraphics2d();
- g.translate(px, py);
- g.scale(sx, sy);
- g.translate(-px, -py);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#scale(float, float)
- */
- @Override
- public void scale(float sx, float sy) {
- getGraphics2d().scale(sx, sy);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(char[], int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
- // WARNING: the logic in this method is similar to Paint.measureText.
- // Any change to this method should be reflected in Paint.measureText
- Graphics2D g = getGraphics2d();
-
- g = (Graphics2D)g.create();
- g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
-
- // set the color. because this only handles RGB, the alpha channel is handled
- // as a composite.
- g.setColor(new Color(paint.getColor()));
- int alpha = paint.getAlpha();
- float falpha = alpha / 255.f;
- g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha));
-
-
- // Paint.TextAlign indicates how the text is positioned relative to X.
- // LEFT is the default and there's nothing to do.
- if (paint.getTextAlign() != Align.LEFT) {
- float m = paint.measureText(text, index, count);
- if (paint.getTextAlign() == Align.CENTER) {
- x -= m / 2;
- } else if (paint.getTextAlign() == Align.RIGHT) {
- x -= m;
- }
- }
-
- List<FontInfo> fonts = paint.getFonts();
- try {
- if (fonts.size() > 0) {
- FontInfo mainFont = fonts.get(0);
- int i = index;
- int lastIndex = index + count;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // draw all the rest and exit.
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, lastIndex - i, (int)x, (int)y);
- return;
- } else if (upTo > 0) {
- // draw what's possible
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, upTo - i, (int)x, (int)y);
-
- // compute the width that was drawn to increase x
- x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
-
- // move index to the first non displayed char.
- i = upTo;
-
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < fonts.size() ; f++) {
- FontInfo fontInfo = fonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- // draw that char
- g.setFont(fontInfo.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
-
- // update x
- x += fontInfo.mMetrics.charsWidth(text, i, charCount);
-
- // update the index in the text, and move on
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, display it with the main font.
- // (it'll put a square probably)
- if (foundFont == false) {
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
-
- g.setFont(mainFont.mFont);
- g.drawChars(text, i, charCount, (int)x, (int)y);
-
- // measure it to advance x
- x += mainFont.mMetrics.charsWidth(text, i, charCount);
-
- // and move to the next chars.
- i += charCount;
- }
- }
- }
- } finally {
- g.dispose();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.CharSequence, int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
- drawText(text.toString().toCharArray(), start, end - start, x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.String, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(String text, float x, float y, Paint paint) {
- drawText(text.toCharArray(), 0, text.length(), x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawText(java.lang.String, int, int, float, float, android.graphics.Paint)
- */
- @Override
- public void drawText(String text, int start, int end, float x, float y, Paint paint) {
- drawText(text.toCharArray(), start, end - start, x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawRect(RectF rect, Paint paint) {
- doDrawRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(float, float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawRect(float left, float top, float right, float bottom, Paint paint) {
- doDrawRect((int)left, (int)top, (int)(right-left), (int)(bottom-top), paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRect(android.graphics.Rect, android.graphics.Paint)
- */
- @Override
- public void drawRect(Rect r, Paint paint) {
- doDrawRect(r.left, r.top, r.width(), r.height(), paint);
- }
-
- private final void doDrawRect(int left, int top, int width, int height, Paint paint) {
- if (width > 0 && height > 0) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillRect(left, top, width, height);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawRect(left, top, width, height);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawRoundRect(android.graphics.RectF, float, float, android.graphics.Paint)
- */
- @Override
- public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
- if (rect.width() > 0 && rect.height() > 0) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
-
- int arcWidth = (int)(rx * 2);
- int arcHeight = (int)(ry * 2);
-
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- arcWidth, arcHeight);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawRoundRect((int)rect.left, (int)rect.top, (int)rect.width(), (int)rect.height(),
- arcWidth, arcHeight);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLine(float, float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- g.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLines(float[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawLines(float[] pts, int offset, int count, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- for (int i = 0 ; i < count ; i += 4) {
- g.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
- (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawLines(float[], android.graphics.Paint)
- */
- @Override
- public void drawLines(float[] pts, Paint paint) {
- drawLines(pts, 0, pts.length, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawCircle(float, float, float, android.graphics.Paint)
- */
- @Override
- public void drawCircle(float cx, float cy, float radius, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- int size = (int)(radius * 2);
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillOval((int)(cx - radius), (int)(cy - radius), size, size);
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawOval((int)(cx - radius), (int)(cy - radius), size, size);
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawOval(android.graphics.RectF, android.graphics.Paint)
- */
- @Override
- public void drawOval(RectF oval, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fillOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.drawOval((int)oval.left, (int)oval.top, (int)oval.width(), (int)oval.height());
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPath(android.graphics.Path, android.graphics.Paint)
- */
- @Override
- public void drawPath(Path path, Paint paint) {
- // get a Graphics2D object configured with the drawing parameters.
- Graphics2D g = getCustomGraphics(paint);
-
- Style style = paint.getStyle();
-
- // draw
- if (style == Style.FILL || style == Style.FILL_AND_STROKE) {
- g.fill(path.getAwtShape());
- }
-
- if (style == Style.STROKE || style == Style.FILL_AND_STROKE) {
- g.draw(path.getAwtShape());
- }
-
- // dispose Graphics2D object
- g.dispose();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setMatrix(android.graphics.Matrix)
- */
- @Override
- public void setMatrix(Matrix matrix) {
- // get the new current graphics
- Graphics2D g = getGraphics2d();
-
- // and apply the matrix
- g.setTransform(matrix.getTransform());
-
- if (mLogger != null && matrix.hasPerspective()) {
- mLogger.warning("android.graphics.Canvas#setMatrix(android.graphics.Matrix) only supports affine transformations in the Layout Editor.");
- }
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#concat(android.graphics.Matrix)
- */
- @Override
- public void concat(Matrix matrix) {
- // get the current top graphics2D object.
- Graphics2D g = getGraphics2d();
-
- // get its current matrix
- AffineTransform currentTx = g.getTransform();
- // get the AffineTransform of the given matrix
- AffineTransform matrixTx = matrix.getTransform();
-
- // combine them so that the given matrix is applied after.
- currentTx.preConcatenate(matrixTx);
-
- // give it to the graphics2D as a new matrix replacing all previous transform
- g.setTransform(currentTx);
- }
-
-
- // --------------------
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipPath(android.graphics.Path, android.graphics.Region.Op)
- */
- @Override
- public boolean clipPath(Path path, Op op) {
- // TODO Auto-generated method stub
- return super.clipPath(path, op);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipPath(android.graphics.Path)
- */
- @Override
- public boolean clipPath(Path path) {
- // TODO Auto-generated method stub
- return super.clipPath(path);
- }
-
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRegion(android.graphics.Region, android.graphics.Region.Op)
- */
- @Override
- public boolean clipRegion(Region region, Op op) {
- // TODO Auto-generated method stub
- return super.clipRegion(region, op);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#clipRegion(android.graphics.Region)
- */
- @Override
- public boolean clipRegion(Region region) {
- // TODO Auto-generated method stub
- return super.clipRegion(region);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawArc(android.graphics.RectF, float, float, boolean, android.graphics.Paint)
- */
- @Override
- public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
- Paint paint) {
- // TODO Auto-generated method stub
- super.drawArc(oval, startAngle, sweepAngle, useCenter, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawBitmapMesh(android.graphics.Bitmap, int, int, float[], int, int[], int, android.graphics.Paint)
- */
- @Override
- public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight, float[] verts,
- int vertOffset, int[] colors, int colorOffset, Paint paint) {
- // TODO Auto-generated method stub
- super.drawBitmapMesh(bitmap, meshWidth, meshHeight, verts, vertOffset, colors, colorOffset, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.Rect)
- */
- @Override
- public void drawPicture(Picture picture, Rect dst) {
- // TODO Auto-generated method stub
- super.drawPicture(picture, dst);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture, android.graphics.RectF)
- */
- @Override
- public void drawPicture(Picture picture, RectF dst) {
- // TODO Auto-generated method stub
- super.drawPicture(picture, dst);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPicture(android.graphics.Picture)
- */
- @Override
- public void drawPicture(Picture picture) {
- // TODO Auto-generated method stub
- super.drawPicture(picture);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoint(float, float, android.graphics.Paint)
- */
- @Override
- public void drawPoint(float x, float y, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoint(x, y, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoints(float[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawPoints(float[] pts, int offset, int count, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoints(pts, offset, count, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPoints(float[], android.graphics.Paint)
- */
- @Override
- public void drawPoints(float[] pts, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPoints(pts, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPosText(char[], int, int, float[], android.graphics.Paint)
- */
- @Override
- public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPosText(text, index, count, pos, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawPosText(java.lang.String, float[], android.graphics.Paint)
- */
- @Override
- public void drawPosText(String text, float[] pos, Paint paint) {
- // TODO Auto-generated method stub
- super.drawPosText(text, pos, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawTextOnPath(char[], int, int, android.graphics.Path, float, float, android.graphics.Paint)
- */
- @Override
- public void drawTextOnPath(char[] text, int index, int count, Path path, float offset,
- float offset2, Paint paint) {
- // TODO Auto-generated method stub
- super.drawTextOnPath(text, index, count, path, offset, offset2, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawTextOnPath(java.lang.String, android.graphics.Path, float, float, android.graphics.Paint)
- */
- @Override
- public void drawTextOnPath(String text, Path path, float offset, float offset2, Paint paint) {
- // TODO Auto-generated method stub
- super.drawTextOnPath(text, path, offset, offset2, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#drawVertices(android.graphics.Canvas.VertexMode, int, float[], int, float[], int, int[], int, short[], int, int, android.graphics.Paint)
- */
- @Override
- public void drawVertices(VertexMode mode, int vertexCount, float[] verts, int vertOffset,
- float[] texs, int texOffset, int[] colors, int colorOffset, short[] indices,
- int indexOffset, int indexCount, Paint paint) {
- // TODO Auto-generated method stub
- super.drawVertices(mode, vertexCount, verts, vertOffset, texs, texOffset, colors, colorOffset,
- indices, indexOffset, indexCount, paint);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getDrawFilter()
- */
- @Override
- public DrawFilter getDrawFilter() {
- // TODO Auto-generated method stub
- return super.getDrawFilter();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getGL()
- */
- @Override
- public GL getGL() {
- // TODO Auto-generated method stub
- return super.getGL();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getMatrix()
- */
- @Override
- public Matrix getMatrix() {
- // TODO Auto-generated method stub
- return super.getMatrix();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#getMatrix(android.graphics.Matrix)
- */
- @Override
- public void getMatrix(Matrix ctm) {
- // TODO Auto-generated method stub
- super.getMatrix(ctm);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#isOpaque()
- */
- @Override
- public boolean isOpaque() {
- // TODO Auto-generated method stub
- return super.isOpaque();
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayer(float, float, float, float, android.graphics.Paint, int)
- */
- @Override
- public int saveLayer(float left, float top, float right, float bottom, Paint paint,
- int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayer(left, top, right, bottom, paint, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayer(android.graphics.RectF, android.graphics.Paint, int)
- */
- @Override
- public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayer(bounds, paint, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayerAlpha(float, float, float, float, int, int)
- */
- @Override
- public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
- int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayerAlpha(left, top, right, bottom, alpha, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#saveLayerAlpha(android.graphics.RectF, int, int)
- */
- @Override
- public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
- // TODO Auto-generated method stub
- return super.saveLayerAlpha(bounds, alpha, saveFlags);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setDrawFilter(android.graphics.DrawFilter)
- */
- @Override
- public void setDrawFilter(DrawFilter filter) {
- // TODO Auto-generated method stub
- super.setDrawFilter(filter);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#setViewport(int, int)
- */
- @Override
- public void setViewport(int width, int height) {
- // TODO Auto-generated method stub
- super.setViewport(width, height);
- }
-
- /* (non-Javadoc)
- * @see android.graphics.Canvas#skew(float, float)
- */
- @Override
- public void skew(float sx, float sy) {
- // TODO Auto-generated method stub
- super.skew(sx, sy);
- }
-
-
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
new file mode 100644
index 0000000..4decd1a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Canvas_Delegate.java
@@ -0,0 +1,1334 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.GcSnapshot;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Bitmap.Config;
+import android.graphics.Paint_Delegate.FontInfo;
+import android.text.TextUtils;
+
+import java.awt.Color;
+import java.awt.Composite;
+import java.awt.Graphics2D;
+import java.awt.Rectangle;
+import java.awt.RenderingHints;
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.util.List;
+
+
+/**
+ * Delegate implementing the native methods of android.graphics.Canvas
+ *
+ * Through the layoutlib_create tool, the original native methods of Canvas 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 Canvas class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Canvas_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Canvas_Delegate> sManager =
+ new DelegateManager<Canvas_Delegate>(Canvas_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ private final static boolean[] sBoolOut = new boolean[1];
+
+ // ---- delegate data ----
+ private Bitmap_Delegate mBitmap;
+ private GcSnapshot mSnapshot;
+
+ private DrawFilter_Delegate mDrawFilter = null;
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Returns the native delegate associated to a given {@link Canvas} object.
+ */
+ public static Canvas_Delegate getDelegate(Canvas canvas) {
+ return sManager.getDelegate(canvas.mNativeCanvas);
+ }
+
+ /**
+ * Returns the native delegate associated to a given an int referencing a {@link Canvas} object.
+ */
+ public static Canvas_Delegate getDelegate(int native_canvas) {
+ return sManager.getDelegate(native_canvas);
+ }
+
+ /**
+ * Returns the current {@link Graphics2D} used to draw.
+ */
+ public GcSnapshot getSnapshot() {
+ return mSnapshot;
+ }
+
+ /**
+ * Returns the {@link DrawFilter} delegate or null if none have been set.
+ *
+ * @return the delegate or null.
+ */
+ public DrawFilter_Delegate getDrawFilter() {
+ return mDrawFilter;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isOpaque(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ return canvasDelegate.mBitmap.getConfig() == Config.RGB_565;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getWidth(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.mBitmap.getImage().getWidth();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getHeight(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.mBitmap.getImage().getHeight();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void translate(Canvas thisCanvas, float dx, float dy) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().translate(dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void rotate(Canvas thisCanvas, float degrees) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().rotate(Math.toRadians(degrees));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void scale(Canvas thisCanvas, float sx, float sy) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.getSnapshot().scale(sx, sy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void skew(Canvas thisCanvas, float kx, float ky) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the current top graphics2D object.
+ GcSnapshot g = canvasDelegate.getSnapshot();
+
+ // get its current matrix
+ AffineTransform currentTx = g.getTransform();
+ // get the AffineTransform for the given skew.
+ float[] mtx = Matrix_Delegate.getSkew(kx, ky);
+ AffineTransform matrixTx = Matrix_Delegate.getAffineTransform(mtx);
+
+ // combine them so that the given matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ g.setTransform(currentTx);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean clipRect(Canvas thisCanvas, RectF rect) {
+ return clipRect(thisCanvas, rect.left, rect.top, rect.right, rect.bottom);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean clipRect(Canvas thisCanvas, Rect rect) {
+ return clipRect(thisCanvas, (float) rect.left, (float) rect.top,
+ (float) rect.right, (float) rect.bottom);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean clipRect(Canvas thisCanvas, float left, float top, float right,
+ float bottom) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ return canvasDelegate.clipRect(left, top, right, bottom, Region.Op.INTERSECT.nativeInt);
+ }
+
+ @LayoutlibDelegate
+ /*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);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int save(Canvas thisCanvas) {
+ return save(thisCanvas, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG);
+ }
+
+ @LayoutlibDelegate
+ /*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) {
+ return 0;
+ }
+
+ return canvasDelegate.save(saveFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void restore(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.restore();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getSaveCount(Canvas thisCanvas) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.getSnapshot().size();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void restoreToCount(Canvas thisCanvas, int saveCount) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(thisCanvas.mNativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.restoreTo(saveCount);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void drawPoints(Canvas thisCanvas, float[] pts, int offset, int count,
+ Paint paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void drawPoint(Canvas thisCanvas, float x, float y, Paint paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPoint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void drawLines(Canvas thisCanvas,
+ final float[] pts, final int offset, final int count,
+ Paint paint) {
+ draw(thisCanvas.mNativeCanvas, paint.mNativePaint, false /*compositeOnly*/,
+ false /*forceSrcMode*/, new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ for (int i = 0 ; i < count ; i += 4) {
+ graphics.drawLine((int)pts[i + offset], (int)pts[i + offset + 1],
+ (int)pts[i + offset + 2], (int)pts[i + offset + 3]);
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void freeCaches() {
+ // nothing to be done here.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int initRaster(int nativeBitmapOrZero) {
+ if (nativeBitmapOrZero > 0) {
+ // get the Bitmap from the int
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nativeBitmapOrZero);
+
+ // create a new Canvas_Delegate with the given bitmap and return its new native int.
+ Canvas_Delegate newDelegate = new Canvas_Delegate(bitmapDelegate);
+
+ return sManager.addNewDelegate(newDelegate);
+ } else {
+ // create a new Canvas_Delegate and return its new native int.
+ Canvas_Delegate newDelegate = new Canvas_Delegate();
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setBitmap(int nativeCanvas, int bitmap) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.setBitmap(bitmapDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayer(int nativeCanvas, RectF bounds,
+ int paint, int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+ if (paintDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayer(bounds, paintDelegate, layerFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayer(int nativeCanvas, float l,
+ float t, float r, float b,
+ int paint, int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(paint);
+ if (paintDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayer(new RectF(l, t, r, b),
+ paintDelegate, layerFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayerAlpha(int nativeCanvas,
+ RectF bounds, int alpha,
+ int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayerAlpha(bounds, alpha, layerFlags);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_saveLayerAlpha(int nativeCanvas, float l,
+ float t, float r, float b,
+ int alpha, int layerFlags) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return 0;
+ }
+
+ return canvasDelegate.saveLayerAlpha(new RectF(l, t, r, b), alpha, layerFlags);
+ }
+
+
+ @LayoutlibDelegate
+ /*package*/ static void native_concat(int nCanvas, int nMatrix) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ // get the current top graphics2D object.
+ GcSnapshot snapshot = canvasDelegate.getSnapshot();
+
+ // get its current matrix
+ AffineTransform currentTx = snapshot.getTransform();
+ // get the AffineTransform of the given matrix
+ AffineTransform matrixTx = matrixDelegate.getAffineTransform();
+
+ // combine them so that the given matrix is applied after.
+ currentTx.preConcatenate(matrixTx);
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ snapshot.setTransform(currentTx);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setMatrix(int nCanvas, int nMatrix) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ // get the current top graphics2D object.
+ GcSnapshot snapshot = canvasDelegate.getSnapshot();
+
+ // get the AffineTransform of the given matrix
+ AffineTransform matrixTx = matrixDelegate.getAffineTransform();
+
+ // give it to the graphics2D as a new matrix replacing all previous transform
+ snapshot.setTransform(matrixTx);
+
+ if (matrixDelegate.hasPerspective()) {
+ assert false;
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
+ "android.graphics.Canvas#setMatrix(android.graphics.Matrix) only " +
+ "supports affine transformations.", null, null /*data*/);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_clipRect(int nCanvas,
+ float left, float top,
+ float right, float bottom,
+ int regionOp) {
+
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ return canvasDelegate.clipRect(left, top, right, bottom, regionOp);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_clipPath(int nativeCanvas,
+ int nativePath,
+ int regionOp) {
+ 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);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_clipRegion(int nativeCanvas,
+ int nativeRegion,
+ int regionOp) {
+ 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);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetDrawFilter(int nativeCanvas, int nativeFilter) {
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.mDrawFilter = DrawFilter_Delegate.getDelegate(nativeFilter);
+
+ if (canvasDelegate.mDrawFilter != null &&
+ canvasDelegate.mDrawFilter.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_DRAWFILTER,
+ canvasDelegate.mDrawFilter.getSupportMessage(), null, null /*data*/);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_getClipBounds(int nativeCanvas,
+ Rect bounds) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return false;
+ }
+
+ Rectangle rect = canvasDelegate.getSnapshot().getClip().getBounds();
+ 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;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getCTM(int canvas, int matrix) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(canvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ AffineTransform transform = canvasDelegate.getSnapshot().getTransform();
+ matrixDelegate.set(Matrix_Delegate.makeValues(transform));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ RectF rect,
+ int native_edgeType) {
+ // FIXME properly implement quickReject
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ int path,
+ int native_edgeType) {
+ // FIXME properly implement quickReject
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_quickReject(int nativeCanvas,
+ float left, float top,
+ float right, float bottom,
+ int native_edgeType) {
+ // FIXME properly implement quickReject
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRGB(int nativeCanvas, int r, int g, int b) {
+ native_drawColor(nativeCanvas, 0xFF000000 | r << 16 | (g&0xFF) << 8 | (b&0xFF),
+ PorterDuff.Mode.SRC_OVER.nativeInt);
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawARGB(int nativeCanvas, int a, int r, int g, int b) {
+ native_drawColor(nativeCanvas, a << 24 | (r&0xFF) << 16 | (g&0xFF) << 8 | (b&0xFF),
+ PorterDuff.Mode.SRC_OVER.nativeInt);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawColor(int nativeCanvas, int color) {
+ native_drawColor(nativeCanvas, color, PorterDuff.Mode.SRC_OVER.nativeInt);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawColor(int nativeCanvas, final int color, final int mode) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ final int w = canvasDelegate.mBitmap.getImage().getWidth();
+ final int h = canvasDelegate.mBitmap.getImage().getHeight();
+ draw(nativeCanvas, new GcSnapshot.Drawable() {
+
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ // reset its transform just in case
+ graphics.setTransform(new AffineTransform());
+
+ // set the color
+ graphics.setColor(new Color(color, true /*alpha*/));
+
+ Composite composite = PorterDuffXfermode_Delegate.getComposite(
+ PorterDuffXfermode_Delegate.getPorterDuffMode(mode), 0xFF);
+ if (composite != null) {
+ graphics.setComposite(composite);
+ }
+
+ graphics.fillRect(0, 0, w, h);
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPaint(int nativeCanvas, int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPaint is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawLine(int nativeCanvas,
+ final float startX, final float startY, final float stopX, final float stopY,
+ int paint) {
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ graphics.drawLine((int)startX, (int)startY, (int)stopX, (int)stopY);
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRect(int nativeCanvas, RectF rect,
+ int paint) {
+ native_drawRect(nativeCanvas, rect.left, rect.top, rect.right, rect.bottom, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRect(int nativeCanvas,
+ final float left, final float top, final float right, final float bottom, int paint) {
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ int style = paint.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillRect((int)left, (int)top,
+ (int)(right-left), (int)(bottom-top));
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawRect((int)left, (int)top,
+ (int)(right-left), (int)(bottom-top));
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawOval(int nativeCanvas, final RectF oval, int paint) {
+ if (oval.right > oval.left && oval.bottom > oval.top) {
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ int style = paint.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillOval((int)oval.left, (int)oval.top,
+ (int)oval.width(), (int)oval.height());
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawOval((int)oval.left, (int)oval.top,
+ (int)oval.width(), (int)oval.height());
+ }
+ }
+ });
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawCircle(int nativeCanvas,
+ float cx, float cy, float radius, int paint) {
+ native_drawOval(nativeCanvas,
+ new RectF(cx - radius, cy - radius, radius*2, radius*2),
+ paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawArc(int nativeCanvas,
+ RectF oval, float startAngle, float sweep, boolean useCenter, int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawArc is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawRoundRect(int nativeCanvas,
+ final RectF rect, final float rx, final float ry, int paint) {
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ int style = paint.getStyle();
+
+ // draw
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fillRoundRect(
+ (int)rect.left, (int)rect.top,
+ (int)rect.width(), (int)rect.height(),
+ (int)rx, (int)ry);
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.drawRoundRect(
+ (int)rect.left, (int)rect.top,
+ (int)rect.width(), (int)rect.height(),
+ (int)rx, (int)ry);
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPath(int nativeCanvas, int path, int paint) {
+ final Path_Delegate pathDelegate = Path_Delegate.getDelegate(path);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ Shape shape = pathDelegate.getJavaShape();
+ int style = paint.getStyle();
+
+ if (style == Paint.Style.FILL.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.fill(shape);
+ }
+
+ if (style == Paint.Style.STROKE.nativeInt ||
+ style == Paint.Style.FILL_AND_STROKE.nativeInt) {
+ graphics.draw(shape);
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+ float left, float top,
+ int nativePaintOrZero,
+ int canvasDensity,
+ int screenDensity,
+ int bitmapDensity) {
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+ float right = left + image.getWidth();
+ float bottom = top + image.getHeight();
+
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ (int)left, (int)top, (int)right, (int)bottom);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(Canvas thisCanvas, int nativeCanvas, int bitmap,
+ Rect src, RectF dst,
+ int nativePaintOrZero,
+ int screenDensity,
+ int bitmapDensity) {
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+
+ if (src == null) {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
+ } else {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ src.left, src.top, src.width(), src.height(),
+ (int)dst.left, (int)dst.top, (int)dst.right, (int)dst.bottom);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(int nativeCanvas, int bitmap,
+ Rect src, Rect dst,
+ int nativePaintOrZero,
+ int screenDensity,
+ int bitmapDensity) {
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(bitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ BufferedImage image = bitmapDelegate.getImage();
+
+ if (src == null) {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ 0, 0, image.getWidth(), image.getHeight(),
+ dst.left, dst.top, dst.right, dst.bottom);
+ } else {
+ drawBitmap(nativeCanvas, bitmapDelegate, nativePaintOrZero,
+ src.left, src.top, src.width(), src.height(),
+ dst.left, dst.top, dst.right, dst.bottom);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawBitmap(int nativeCanvas, int[] colors,
+ int offset, int stride, final float x,
+ final float y, int width, int height,
+ boolean hasAlpha,
+ int nativePaintOrZero) {
+
+ // create a temp BufferedImage containing the content.
+ final BufferedImage image = new BufferedImage(width, height,
+ hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB);
+ image.setRGB(0, 0, width, height, colors, offset, stride);
+
+ draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ graphics.drawImage(image, (int) x, (int) y, null);
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDrawBitmapMatrix(int nCanvas, int nBitmap,
+ int nMatrix, int nPaint) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the delegate from the native int, which can be null
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
+
+ // get the delegate from the native int.
+ Bitmap_Delegate bitmapDelegate = Bitmap_Delegate.getDelegate(nBitmap);
+ if (bitmapDelegate == null) {
+ return;
+ }
+
+ final BufferedImage image = getImageToDraw(bitmapDelegate, paintDelegate, sBoolOut);
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(nMatrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ final AffineTransform mtx = matrixDelegate.getAffineTransform();
+
+ canvasDelegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ //FIXME add support for canvas, screen and bitmap densities.
+ graphics.drawImage(image, mtx, null);
+ }
+ }, paintDelegate, true /*compositeOnly*/, false /*forceSrcMode*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDrawBitmapMesh(int nCanvas, int nBitmap,
+ int meshWidth, int meshHeight, float[] verts, int vertOffset, int[] colors,
+ int colorOffset, int nPaint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawBitmapMesh is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDrawVertices(int nCanvas, int mode, int n,
+ float[] verts, int vertOffset,
+ float[] texs, int texOffset,
+ int[] colors, int colorOffset,
+ short[] indices, int indexOffset,
+ int indexCount, int nPaint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawVertices is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawText(int nativeCanvas,
+ final char[] text, final int index, final int count,
+ final float startX, final float startY, int flags, int paint) {
+ draw(nativeCanvas, paint, false /*compositeOnly*/, false /*forceSrcMode*/,
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ // WARNING: the logic in this method is similar to Paint_Delegate.measureText.
+ // Any change to this method should be reflected in Paint.measureText
+ // Paint.TextAlign indicates how the text is positioned relative to X.
+ // LEFT is the default and there's nothing to do.
+ float x = startX;
+ float y = startY;
+ if (paint.getTextAlign() != Paint.Align.LEFT.nativeInt) {
+ float m = paint.measureText(text, index, count);
+ if (paint.getTextAlign() == Paint.Align.CENTER.nativeInt) {
+ x -= m / 2;
+ } else if (paint.getTextAlign() == Paint.Align.RIGHT.nativeInt) {
+ x -= m;
+ }
+ }
+
+ List<FontInfo> fonts = paint.getFonts();
+
+ if (fonts.size() > 0) {
+ FontInfo mainFont = fonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // draw all the rest and exit.
+ graphics.setFont(mainFont.mFont);
+ graphics.drawChars(text, i, lastIndex - i, (int)x, (int)y);
+ return;
+ } else if (upTo > 0) {
+ // draw what's possible
+ graphics.setFont(mainFont.mFont);
+ graphics.drawChars(text, i, upTo - i, (int)x, (int)y);
+
+ // compute the width that was drawn to increase x
+ x += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+
+ // move index to the first non displayed char.
+ i = upTo;
+
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < fonts.size() ; f++) {
+ FontInfo fontInfo = fonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ // draw that char
+ graphics.setFont(fontInfo.mFont);
+ graphics.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // update x
+ x += fontInfo.mMetrics.charsWidth(text, i, charCount);
+
+ // update the index in the text, and move on
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, display it with the main font.
+ // (it'll put a square probably)
+ if (foundFont == false) {
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+
+ graphics.setFont(mainFont.mFont);
+ graphics.drawChars(text, i, charCount, (int)x, (int)y);
+
+ // measure it to advance x
+ x += mainFont.mMetrics.charsWidth(text, i, charCount);
+
+ // and move to the next chars.
+ i += charCount;
+ }
+ }
+ }
+ }
+ });
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawText(int nativeCanvas, String text,
+ int start, int end, float x,
+ float y, int flags, int paint) {
+ int count = end - start;
+ char[] buffer = TemporaryBuffer.obtain(count);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ native_drawText(nativeCanvas, buffer, 0, count, x, y, flags, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextRun(int nativeCanvas, String text,
+ int start, int end, int contextStart, int contextEnd,
+ float x, float y, int flags, int paint) {
+ int count = end - start;
+ char[] buffer = TemporaryBuffer.obtain(count);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ native_drawText(nativeCanvas, buffer, start, end, x, y, flags, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextRun(int nativeCanvas, char[] text,
+ int start, int count, int contextStart, int contextCount,
+ float x, float y, int flags, int paint) {
+ native_drawText(nativeCanvas, text, start, count, x, y, flags, paint);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPosText(int nativeCanvas,
+ char[] text, int index,
+ int count, float[] pos,
+ int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPosText is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPosText(int nativeCanvas,
+ String text, float[] pos,
+ int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPosText is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+ char[] text, int index,
+ int count, int path,
+ float hOffset,
+ float vOffset, int bidiFlags,
+ int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawTextOnPath(int nativeCanvas,
+ String text, int path,
+ float hOffset,
+ float vOffset,
+ int flags, int paint) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawTextOnPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_drawPicture(int nativeCanvas,
+ int nativePicture) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Canvas.drawPicture is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int nativeCanvas) {
+ // get the delegate from the native int so that it can be disposed.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.dispose();
+
+ // remove it from the manager.
+ sManager.removeJavaReferenceFor(nativeCanvas);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /**
+ * Executes a {@link GcSnapshot.Drawable} with a given canvas and paint.
+ * <p>Note that the drawable may actually be executed several times if there are
+ * layers involved (see {@link #saveLayer(RectF, int, int)}.
+ */
+ private static void draw(int nCanvas, int nPaint, boolean compositeOnly, boolean forceSrcMode,
+ GcSnapshot.Drawable drawable) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the paint which can be null if nPaint is 0;
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nPaint);
+
+ canvasDelegate.getSnapshot().draw(drawable, paintDelegate, compositeOnly, forceSrcMode);
+ }
+
+ /**
+ * Executes a {@link GcSnapshot.Drawable} with a given canvas. No paint object will be provided
+ * to {@link GcSnapshot.Drawable#draw(Graphics2D, Paint_Delegate)}.
+ * <p>Note that the drawable may actually be executed several times if there are
+ * layers involved (see {@link #saveLayer(RectF, int, int)}.
+ */
+ private static void draw(int nCanvas, GcSnapshot.Drawable drawable) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ canvasDelegate.mSnapshot.draw(drawable);
+ }
+
+ private Canvas_Delegate(Bitmap_Delegate bitmap) {
+ mSnapshot = GcSnapshot.createDefaultSnapshot(mBitmap = bitmap);
+ }
+
+ private Canvas_Delegate() {
+ mSnapshot = GcSnapshot.createDefaultSnapshot(null /*image*/);
+ }
+
+ /**
+ * Disposes of the {@link Graphics2D} stack.
+ */
+ private void dispose() {
+ mSnapshot.dispose();
+ }
+
+ private int save(int saveFlags) {
+ // get the current save count
+ int count = mSnapshot.size();
+
+ mSnapshot = mSnapshot.save(saveFlags);
+
+ // return the old save count
+ return count;
+ }
+
+ private int saveLayerAlpha(RectF rect, int alpha, int saveFlags) {
+ Paint_Delegate paint = new Paint_Delegate();
+ paint.setAlpha(alpha);
+ return saveLayer(rect, paint, saveFlags);
+ }
+
+ private int saveLayer(RectF rect, Paint_Delegate paint, int saveFlags) {
+ // get the current save count
+ int count = mSnapshot.size();
+
+ mSnapshot = mSnapshot.saveLayer(rect, paint, saveFlags);
+
+ // return the old save count
+ return count;
+ }
+
+ /**
+ * Restores the {@link GcSnapshot} to <var>saveCount</var>
+ * @param saveCount the saveCount
+ */
+ private void restoreTo(int saveCount) {
+ mSnapshot = mSnapshot.restoreTo(saveCount);
+ }
+
+ /**
+ * Restores the {@link GcSnapshot} to <var>saveCount</var>
+ * @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(Bitmap_Delegate bitmap) {
+ mBitmap = bitmap;
+ assert mSnapshot.size() == 1;
+ mSnapshot.setBitmap(mBitmap);
+ }
+
+ private static void drawBitmap(
+ int nativeCanvas,
+ Bitmap_Delegate bitmap,
+ int nativePaintOrZero,
+ final int sleft, final int stop, final int sright, final int sbottom,
+ final int dleft, final int dtop, final int dright, final int dbottom) {
+ // get the delegate from the native int.
+ Canvas_Delegate canvasDelegate = sManager.getDelegate(nativeCanvas);
+ if (canvasDelegate == null) {
+ return;
+ }
+
+ // get the paint, which could be null if the int is 0
+ Paint_Delegate paintDelegate = Paint_Delegate.getDelegate(nativePaintOrZero);
+
+ final BufferedImage image = getImageToDraw(bitmap, paintDelegate, sBoolOut);
+
+ draw(nativeCanvas, nativePaintOrZero, true /*compositeOnly*/, sBoolOut[0],
+ new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ if (paint != null && paint.isFilterBitmap()) {
+ graphics.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
+ RenderingHints.VALUE_INTERPOLATION_BILINEAR);
+ }
+
+ //FIXME add support for canvas, screen and bitmap densities.
+ graphics.drawImage(image, dleft, dtop, dright, dbottom,
+ sleft, stop, sright, sbottom, null);
+ }
+ });
+ }
+
+
+ /**
+ * Returns a BufferedImage ready for drawing, based on the bitmap and paint delegate.
+ * The image returns, through a 1-size boolean array, whether the drawing code should
+ * use a SRC composite no matter what the paint says.
+ *
+ * @param bitmap the bitmap
+ * @param paint the paint that will be used to draw
+ * @param forceSrcMode whether the composite will have to be SRC
+ * @return the image to draw
+ */
+ private static BufferedImage getImageToDraw(Bitmap_Delegate bitmap, Paint_Delegate paint,
+ boolean[] forceSrcMode) {
+ BufferedImage image = bitmap.getImage();
+ forceSrcMode[0] = false;
+
+ // if the bitmap config is alpha_8, then we erase all color value from it
+ // before drawing it.
+ if (bitmap.getConfig() == Bitmap.Config.ALPHA_8) {
+ fixAlpha8Bitmap(image);
+ } else if (bitmap.hasAlpha() == false) {
+ // hasAlpha is merely a rendering hint. There can in fact be alpha values
+ // in the bitmap but it should be ignored at drawing time.
+ // There is two ways to do this:
+ // - override the composite to be SRC. This can only be used if the composite
+ // was going to be SRC or SRC_OVER in the first place
+ // - Create a different bitmap to draw in which all the alpha channel values is set
+ // to 0xFF.
+ if (paint != null) {
+ Xfermode_Delegate xfermodeDelegate = paint.getXfermode();
+ if (xfermodeDelegate instanceof PorterDuffXfermode_Delegate) {
+ PorterDuff.Mode mode =
+ ((PorterDuffXfermode_Delegate)xfermodeDelegate).getMode();
+
+ forceSrcMode[0] = mode == PorterDuff.Mode.SRC_OVER ||
+ mode == PorterDuff.Mode.SRC;
+ }
+ }
+
+ // if we can't force SRC mode, then create a temp bitmap of TYPE_RGB
+ if (forceSrcMode[0] == false) {
+ image = Bitmap_Delegate.createCopy(image, BufferedImage.TYPE_INT_RGB, 0xFF);
+ }
+ }
+
+ return image;
+ }
+
+ private static void fixAlpha8Bitmap(final BufferedImage image) {
+ int w = image.getWidth();
+ int h = image.getHeight();
+ int[] argb = new int[w * h];
+ image.getRGB(0, 0, image.getWidth(), image.getHeight(), argb, 0, image.getWidth());
+
+ final int length = argb.length;
+ for (int i = 0 ; i < length; i++) {
+ argb[i] &= 0xFF000000;
+ }
+ image.setRGB(0, 0, w, h, argb, 0, w);
+ }
+}
+
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
new file mode 100644
index 0000000..e5a7ab6
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of ColorFilter 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 ColorFilter class.
+ *
+ * This also serve as a base class for all ColorFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class ColorFilter_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<ColorFilter_Delegate> sManager =
+ new DelegateManager<ColorFilter_Delegate>(ColorFilter_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static ColorFilter_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance, int nativeColorFilter) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
new file mode 100644
index 0000000..2de344b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ColorMatrixColorFilter_Delegate.java
@@ -0,0 +1,70 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ColorMatrixColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of ColorMatrixColorFilter 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 ColorMatrixColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class ColorMatrixColorFilter_Delegate extends ColorFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "ColorMatrix Color Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeColorMatrixFilter(float[] array) {
+ ColorMatrixColorFilter_Delegate newDelegate = new ColorMatrixColorFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nColorMatrixFilter(int nativeFilter, float[] array) {
+ // pass
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
new file mode 100644
index 0000000..7c04a87
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposePathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ComposePathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of ComposePathEffect 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 ComposePathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class ComposePathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Compose Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int outerpe, int innerpe) {
+ ComposePathEffect_Delegate newDelegate = new ComposePathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader.java
deleted file mode 100644
index 863d64a..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/ComposeShader.java
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2008 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 java.awt.Paint;
-
-/** A subclass of shader that returns the composition of two other shaders, combined by
- an {@link android.graphics.Xfermode} subclass.
-*/
-public class ComposeShader extends Shader {
- /** Create a new compose shader, given shaders A, B, and a combining mode.
- When the mode is applied, it will be given the result from shader A as its
- "dst", and the result of from shader B as its "src".
- @param shaderA The colors from this shader are seen as the "dst" by the mode
- @param shaderB The colors from this shader are seen as the "src" by the mode
- @param mode The mode that combines the colors from the two shaders. If mode
- is null, then SRC_OVER is assumed.
- */
- public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) {
- // FIXME Implement shader
- }
-
- /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
- When the mode is applied, it will be given the result from shader A as its
- "dst", and the result of from shader B as its "src".
- @param shaderA The colors from this shader are seen as the "dst" by the mode
- @param shaderB The colors from this shader are seen as the "src" by the mode
- @param mode The PorterDuff mode that combines the colors from the two shaders.
- */
- public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) {
- // FIXME Implement shader
- }
-
- @Override
- Paint getJavaPaint() {
- return null;
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
new file mode 100644
index 0000000..f6e1d00
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/ComposeShader_Delegate.java
@@ -0,0 +1,97 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Paint;
+
+/**
+ * Delegate implementing the native methods of android.graphics.ComposeShader
+ *
+ * Through the layoutlib_create tool, the original native methods of ComposeShader 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 ComposeShader class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class ComposeShader_Delegate extends Shader_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Paint getJavaPaint() {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Compose Shaders are not supported in Layout Preview mode.";
+ }
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(int native_shaderA, int native_shaderB,
+ int native_mode) {
+ // FIXME not supported yet.
+ ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(int native_shaderA, int native_shaderB,
+ int porterDuffMode) {
+ // FIXME not supported yet.
+ ComposeShader_Delegate newDelegate = new ComposeShader_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(int native_shader, int native_skiaShaderA,
+ int native_skiaShaderB, int native_mode) {
+ // pass, not needed.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(int native_shader, int native_skiaShaderA,
+ int native_skiaShaderB, int porterDuffMode) {
+ // pass, not needed.
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
new file mode 100644
index 0000000..b0f8168
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/CornerPathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.CornerPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of CornerPathEffect 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 CornerPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class CornerPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Corner Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(float radius) {
+ CornerPathEffect_Delegate newDelegate = new CornerPathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java
deleted file mode 100644
index 46d4c70..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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;
-
-public class DashPathEffect extends PathEffect {
-
- private final float[] mIntervals;
- private final float mPhase;
-
- /**
- * The intervals array must contain an even number of entries (>=2), with
- * the even indices specifying the "on" intervals, and the odd indices
- * specifying the "off" intervals. phase is an offset into the intervals
- * array (mod the sum of all of the intervals). The intervals array
- * controls the length of the dashes. The paint's strokeWidth controls the
- * thickness of the dashes.
- * Note: this patheffect only affects drawing with the paint's style is set
- * to STROKE or STROKE_AND_FILL. It is ignored if the drawing is done with
- * style == FILL.
- * @param intervals array of ON and OFF distances
- * @param phase offset into the intervals array
- */
- public DashPathEffect(float intervals[], float phase) {
- if (intervals.length < 2) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- mIntervals = intervals;
- mPhase = phase;
- }
-
- public float[] getIntervals() {
- return mIntervals;
- }
-
- public float getPhase() {
- return mPhase;
- }
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
new file mode 100644
index 0000000..d97c2ec
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/DashPathEffect_Delegate.java
@@ -0,0 +1,89 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.BasicStroke;
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.DashPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of DashPathEffect 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 DashPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public final class DashPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ private final float[] mIntervals;
+ private final float mPhase;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ return new BasicStroke(
+ paint.getStrokeWidth(),
+ paint.getJavaCap(),
+ paint.getJavaJoin(),
+ paint.getJavaStrokeMiter(),
+ mIntervals,
+ mPhase);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // no message since isSupported returns true;
+ return null;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(float intervals[], float phase) {
+ DashPathEffect_Delegate newDelegate = new DashPathEffect_Delegate(intervals, phase);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private DashPathEffect_Delegate(float intervals[], float phase) {
+ mIntervals = new float[intervals.length];
+ System.arraycopy(intervals, 0, mIntervals, 0, intervals.length);
+ mPhase = phase;
+ }
+}
+
diff --git a/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
new file mode 100644
index 0000000..ec4a810
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/DiscretePathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.DiscretePathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of DiscretePathEffect 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 DiscretePathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class DiscretePathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Discrete Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(float length, float deviation) {
+ DiscretePathEffect_Delegate newDelegate = new DiscretePathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
new file mode 100644
index 0000000..870c46b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/DrawFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.DrawFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of DrawFilter 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 DrawFilter class.
+ *
+ * This also serve as a base class for all DrawFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class DrawFilter_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<DrawFilter_Delegate> sManager =
+ new DelegateManager<DrawFilter_Delegate>(DrawFilter_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static DrawFilter_Delegate getDelegate(int nativeDrawFilter) {
+ return sManager.getDelegate(nativeDrawFilter);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int nativeDrawFilter) {
+ sManager.removeJavaReferenceFor(nativeDrawFilter);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
new file mode 100644
index 0000000..ebc1c1d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/EmbossMaskFilter_Delegate.java
@@ -0,0 +1,65 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.EmbossMaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of EmbossMaskFilter 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 EmbossMaskFilter class.
+ *
+ * Because this extends {@link MaskFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link MaskFilter_Delegate}.
+ *
+ * @see MaskFilter_Delegate
+ *
+ */
+public class EmbossMaskFilter_Delegate extends MaskFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Emboss Mask Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor(float[] direction, float ambient,
+ float specular, float blurRadius) {
+ EmbossMaskFilter_Delegate newDelegate = new EmbossMaskFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/GradientShader.java b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
index 8c5a2a4..38c092d 100644
--- a/tools/layoutlib/bridge/src/android/graphics/GradientShader.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Gradient_Delegate.java
@@ -16,23 +16,28 @@
package android.graphics;
+import android.graphics.Shader.TileMode;
/**
- * Base class for Gradient shader. This is not a standard android class and is just used
- * as a base class for the re-implemented gradient classes.
- *
- * It also provides a base class to handle common code between the different shaders'
- * implementations of {@link java.awt.Paint}.
- *
- * @see LinearGradient
- * @see RadialGradient
- * @see SweepGradient
+ * Base class for true Gradient shader delegate.
*/
-public abstract class GradientShader extends Shader {
+public abstract class Gradient_Delegate extends Shader_Delegate {
protected final int[] mColors;
protected final float[] mPositions;
+ @Override
+ public boolean isSupported() {
+ // all gradient shaders are supported.
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // all gradient shaders are supported, no need for a gradient support
+ return null;
+ }
+
/**
* Creates the base shader and do some basic test on the parameters.
*
@@ -41,7 +46,7 @@ public abstract class GradientShader extends Shader {
* corresponding color in the colors array. If this is null, the
* the colors are distributed evenly along the gradient line.
*/
- protected GradientShader(int colors[], float positions[]) {
+ protected Gradient_Delegate(int colors[], float positions[]) {
if (colors.length < 2) {
throw new IllegalArgumentException("needs >= 2 number of colors");
}
@@ -90,7 +95,7 @@ public abstract class GradientShader extends Shader {
* Pre-computes the colors for the gradient. This must be called once before any call
* to {@link #getGradientColor(float)}
*/
- protected synchronized void precomputeGradientColors() {
+ protected void precomputeGradientColors() {
if (mGradient == null) {
// actually create an array with an extra size, so that we can really go
// from 0 to SIZE (100%), or currentPos in the loop below will never equal 1.0
@@ -126,20 +131,23 @@ public abstract class GradientShader extends Shader {
pos = 0.f;
break;
case REPEAT:
- // remove the integer part to stay in the [0,1] range
- // careful: this is a negative value, so use ceil instead of floor
- pos = pos - (float)Math.ceil(pos);
+ // remove the integer part to stay in the [0,1] range.
+ // we also need to invert the value from [-1,0] to [0, 1]
+ pos = pos - (float)Math.floor(pos);
break;
case MIRROR:
+ // this is the same as the positive side, just make the value positive
+ // first.
+ pos = Math.abs(pos);
+
// get the integer and the decimal part
- // careful: this is a negative value, so use ceil instead of floor
- int intPart = (int)Math.ceil(pos);
+ int intPart = (int)Math.floor(pos);
pos = pos - intPart;
- // 0 -> -1 : mirrored order
- // -1 -> -2: normal order
+ // 0 -> 1 : normal order
+ // 1 -> 2: mirrored
// etc..
- // this means if the intpart is even we invert
- if ((intPart % 2) == 0) {
+ // this means if the intpart is odd we invert
+ if ((intPart % 2) == 1) {
pos = 1.f - pos;
}
break;
@@ -199,7 +207,5 @@ public abstract class GradientShader extends Shader {
private int computeChannel(int c1, int c2, float percent) {
return c1 + (int)((percent * (c2-c1)) + .5);
}
-
-
}
}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
new file mode 100644
index 0000000..51e0576
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LayerRasterizer_Delegate.java
@@ -0,0 +1,69 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LayerRasterizer
+ *
+ * Through the layoutlib_create tool, the original native methods of LayerRasterizer 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 LayerRasterizer class.
+ *
+ * Because this extends {@link Rasterizer_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link Rasterizer_Delegate}.
+ *
+ * @see Rasterizer_Delegate
+ *
+ */
+public class LayerRasterizer_Delegate extends Rasterizer_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Layer Rasterizers are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor() {
+ LayerRasterizer_Delegate newDelegate = new LayerRasterizer_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeAddLayer(int native_layer, int native_paint, float dx, float dy) {
+
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
new file mode 100644
index 0000000..0ee883d
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LightingColorFilter_Delegate.java
@@ -0,0 +1,70 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LightingColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of LightingColorFilter 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 LightingColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class LightingColorFilter_Delegate extends ColorFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Lighting Color Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int native_CreateLightingFilter(int mul, int add) {
+ LightingColorFilter_Delegate newDelegate = new LightingColorFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nCreateLightingFilter(int nativeFilter, int mul, int add) {
+ // pass
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient.java
deleted file mode 100644
index 10c4a5e..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/LinearGradient.java
+++ /dev/null
@@ -1,173 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-public class LinearGradient extends GradientShader {
-
- private java.awt.Paint mJavaPaint;
-
- /**
- * Create a shader that draws a linear gradient along a line.
- *
- * @param x0 The x-coordinate for the start of the gradient line
- * @param y0 The y-coordinate for the start of the gradient line
- * @param x1 The x-coordinate for the end of the gradient line
- * @param y1 The y-coordinate for the end of the gradient line
- * @param colors The colors to be distributed along the gradient line
- * @param positions May be null. The relative positions [0..1] of each
- * corresponding color in the colors array. If this is null, the
- * the colors are distributed evenly along the gradient line.
- * @param tile The Shader tiling mode
- */
- public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
- TileMode tile) {
- super(colors, positions);
- mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
- }
-
- /**
- * Create a shader that draws a linear gradient along a line.
- *
- * @param x0 The x-coordinate for the start of the gradient line
- * @param y0 The y-coordinate for the start of the gradient line
- * @param x1 The x-coordinate for the end of the gradient line
- * @param y1 The y-coordinate for the end of the gradient line
- * @param color0 The color at the start of the gradient line.
- * @param color1 The color at the end of the gradient line.
- * @param tile The Shader tiling mode
- */
- public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1,
- TileMode tile) {
- this(x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/, tile);
- }
-
- // ---------- Custom Methods
-
- @Override
- java.awt.Paint getJavaPaint() {
- return mJavaPaint;
- }
-
- /**
- * Linear Gradient (Java) Paint able to handle more than 2 points, as
- * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
- * modes.
- */
- private static class LinearGradientPaint extends GradientPaint {
-
- private final float mX0;
- private final float mY0;
- private final float mDx;
- private final float mDy;
- private final float mDSize2;
-
- public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[],
- float positions[], TileMode tile) {
- super(colors, positions, tile);
- mX0 = x0;
- mY0 = y0;
- mDx = x1 - x0;
- mDy = y1 - y0;
- mDSize2 = mDx * mDx + mDy * mDy;
- }
-
- public java.awt.PaintContext createContext(
- java.awt.image.ColorModel colorModel,
- java.awt.Rectangle deviceBounds,
- java.awt.geom.Rectangle2D userBounds,
- java.awt.geom.AffineTransform xform,
- java.awt.RenderingHints hints) {
- precomputeGradientColors();
- return new LinearGradientPaintContext(colorModel);
- }
-
- private class LinearGradientPaintContext implements java.awt.PaintContext {
-
- private final java.awt.image.ColorModel mColorModel;
-
- public LinearGradientPaintContext(java.awt.image.ColorModel colorModel) {
- mColorModel = colorModel;
- // FIXME: so far all this is always the same rect gotten in getRaster with an indentity matrix?
- }
-
- public void dispose() {
- }
-
- public java.awt.image.ColorModel getColorModel() {
- return mColorModel;
- }
-
- public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
-
- int[] data = new int[w*h];
-
- if (mDx == 0) { // vertical gradient
- // compute first column and copy to all other columns
- int index = 0;
- for (int iy = 0 ; iy < h ; iy++) {
- int color = getColor(iy + y, mY0, mDy);
- for (int ix = 0 ; ix < w ; ix++) {
- data[index++] = color;
- }
- }
- } else if (mDy == 0) { // horizontal
- // compute first line in a tmp array and copy to all lines
- int[] line = new int[w];
- for (int ix = 0 ; ix < w ; ix++) {
- line[ix] = getColor(ix + x, mX0, mDx);
- }
-
- for (int iy = 0 ; iy < h ; iy++) {
- System.arraycopy(line, 0, data, iy*w, line.length);
- }
- } else {
- int index = 0;
- for (int iy = 0 ; iy < h ; iy++) {
- for (int ix = 0 ; ix < w ; ix++) {
- data[index++] = getColor(ix + x, iy + y);
- }
- }
- }
-
- image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
-
- return image.getRaster();
- }
- }
-
- /** Returns a color for the easy vertical/horizontal mode */
- private int getColor(float absPos, float refPos, float refSize) {
- float pos = (absPos - refPos) / refSize;
-
- return getGradientColor(pos);
- }
-
- /**
- * Returns a color for an arbitrary point.
- */
- private int getColor(float x, float y) {
- // find the x position on the gradient vector.
- float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2;
- // from it get the position relative to the vector
- float pos = (float) ((_x - mX0) / mDx);
-
- return getGradientColor(pos);
- }
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
new file mode 100644
index 0000000..a2ba758
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/LinearGradient_Delegate.java
@@ -0,0 +1,236 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.LinearGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of LinearGradient 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 LinearGradient class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public final class LinearGradient_Delegate extends Gradient_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(LinearGradient thisGradient,
+ float x0, float y0, float x1, float y1,
+ int colors[], float positions[], int tileMode) {
+ LinearGradient_Delegate newDelegate = new LinearGradient_Delegate(x0, y0, x1, y1,
+ colors, positions, Shader_Delegate.getTileMode(tileMode));
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(LinearGradient thisGradient,
+ float x0, float y0, float x1, float y1,
+ int color0, int color1, int tileMode) {
+ return nativeCreate1(thisGradient,
+ x0, y0, x1, y1, new int[] { color0, color1}, null /*positions*/,
+ tileMode);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(LinearGradient thisGradient,
+ int native_shader, float x0, float y0, float x1, float y1,
+ int colors[], float positions[], int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(LinearGradient thisGradient,
+ int native_shader, float x0, float y0, float x1, float y1,
+ int color0, int color1, int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /**
+ * Create a shader that draws a linear gradient along a line.
+ *
+ * @param x0 The x-coordinate for the start of the gradient line
+ * @param y0 The y-coordinate for the start of the gradient line
+ * @param x1 The x-coordinate for the end of the gradient line
+ * @param y1 The y-coordinate for the end of the gradient line
+ * @param colors The colors to be distributed along the gradient line
+ * @param positions May be null. The relative positions [0..1] of each
+ * corresponding color in the colors array. If this is null, the
+ * the colors are distributed evenly along the gradient line.
+ * @param tile The Shader tiling mode
+ */
+ private LinearGradient_Delegate(float x0, float y0, float x1, float y1,
+ int colors[], float positions[], TileMode tile) {
+ super(colors, positions);
+ mJavaPaint = new LinearGradientPaint(x0, y0, x1, y1, mColors, mPositions, tile);
+ }
+
+ // ---- Custom Java Paint ----
+ /**
+ * Linear Gradient (Java) Paint able to handle more than 2 points, as
+ * {@link java.awt.GradientPaint} only supports 2 points and does not support Android's tile
+ * modes.
+ */
+ private class LinearGradientPaint extends GradientPaint {
+
+ private final float mX0;
+ private final float mY0;
+ private final float mDx;
+ private final float mDy;
+ private final float mDSize2;
+
+ public LinearGradientPaint(float x0, float y0, float x1, float y1, int colors[],
+ float positions[], TileMode tile) {
+ super(colors, positions, tile);
+ mX0 = x0;
+ mY0 = y0;
+ mDx = x1 - x0;
+ mDy = y1 - y0;
+ mDSize2 = mDx * mDx + mDy * mDy;
+ }
+
+ public java.awt.PaintContext createContext(
+ java.awt.image.ColorModel colorModel,
+ java.awt.Rectangle deviceBounds,
+ java.awt.geom.Rectangle2D userBounds,
+ java.awt.geom.AffineTransform xform,
+ java.awt.RenderingHints hints) {
+ precomputeGradientColors();
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in LinearGradient", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in LinearGradient", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new LinearGradientPaintContext(canvasMatrix, localMatrix, colorModel);
+ }
+
+ private class LinearGradientPaintContext implements java.awt.PaintContext {
+
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
+ private final java.awt.image.ColorModel mColorModel;
+
+ private LinearGradientPaintContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
+ mColorModel = colorModel;
+ }
+
+ public void dispose() {
+ }
+
+ public java.awt.image.ColorModel getColorModel() {
+ return mColorModel;
+ }
+
+ public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
+ java.awt.image.BufferedImage.TYPE_INT_ARGB);
+
+ int[] data = new int[w*h];
+
+ int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
+ for (int iy = 0 ; iy < h ; iy++) {
+ for (int ix = 0 ; ix < w ; ix++) {
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix.
+ pt1[0] = pt2[0];
+ pt1[1] = pt2[1];
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ data[index++] = getColor(pt2[0], pt2[1]);
+ }
+ }
+
+ image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+ return image.getRaster();
+ }
+ }
+
+ /**
+ * Returns a color for an arbitrary point.
+ */
+ private int getColor(float x, float y) {
+ float pos;
+ if (mDx == 0) {
+ pos = (y - mY0) / mDy;
+ } else if (mDy == 0) {
+ pos = (x - mX0) / mDx;
+ } else {
+ // find the x position on the gradient vector.
+ float _x = (mDx*mDy*(y-mY0) + mDy*mDy*mX0 + mDx*mDx*x) / mDSize2;
+ // from it get the position relative to the vector
+ pos = (_x - mX0) / mDx;
+ }
+
+ return getGradientColor(pos);
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
new file mode 100644
index 0000000..c2f27e4
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/MaskFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.MaskFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of MaskFilter 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 MaskFilter class.
+ *
+ * This also serve as a base class for all MaskFilter delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class MaskFilter_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<MaskFilter_Delegate> sManager =
+ new DelegateManager<MaskFilter_Delegate>(MaskFilter_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static MaskFilter_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_filter) {
+ sManager.removeJavaReferenceFor(native_filter);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix.java b/tools/layoutlib/bridge/src/android/graphics/Matrix.java
deleted file mode 100644
index 9e30671..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Matrix.java
+++ /dev/null
@@ -1,1032 +0,0 @@
-/*
- * Copyright (C) 2008 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 java.awt.geom.AffineTransform;
-import java.awt.geom.NoninvertibleTransformException;
-
-
-/**
- * A matrix implementation overridden by the LayoutLib bridge.
- */
-public class Matrix extends _Original_Matrix {
-
- float mValues[] = new float[9];
-
- /**
- * Create an identity matrix
- */
- public Matrix() {
- reset();
- }
-
- /**
- * Create a matrix that is a (deep) copy of src
- * @param src The matrix to copy into this matrix
- */
- public Matrix(Matrix src) {
- set(src);
- }
-
- /**
- * Creates a Matrix object from the float array. The array becomes the internal storage
- * of the object.
- * @param data
- */
- private Matrix(float[] data) {
- assert data.length != 9;
- mValues = data;
- }
-
- //---------- Custom Methods
-
- /**
- * Adds the given transformation to the current Matrix
- * <p/>This in effect does this = this*matrix
- * @param matrix
- */
- private void addTransform(float[] matrix) {
- float[] tmp = new float[9];
-
- // first row
- tmp[0] = matrix[0] * mValues[0] + matrix[1] * mValues[3] + matrix[2] * mValues[6];
- tmp[1] = matrix[0] * mValues[1] + matrix[1] * mValues[4] + matrix[2] * mValues[7];
- tmp[2] = matrix[0] * mValues[2] + matrix[1] * mValues[5] + matrix[2] * mValues[8];
-
- // 2nd row
- tmp[3] = matrix[3] * mValues[0] + matrix[4] * mValues[3] + matrix[5] * mValues[6];
- tmp[4] = matrix[3] * mValues[1] + matrix[4] * mValues[4] + matrix[5] * mValues[7];
- tmp[5] = matrix[3] * mValues[2] + matrix[4] * mValues[5] + matrix[5] * mValues[8];
-
- // 3rd row
- tmp[6] = matrix[6] * mValues[0] + matrix[7] * mValues[3] + matrix[8] * mValues[6];
- tmp[7] = matrix[6] * mValues[1] + matrix[7] * mValues[4] + matrix[8] * mValues[7];
- tmp[8] = matrix[6] * mValues[2] + matrix[7] * mValues[5] + matrix[8] * mValues[8];
-
- // copy the result over to mValues
- mValues = tmp;
- }
-
- public AffineTransform getTransform() {
- // the AffineTransform constructor takes the value in a different order
- // for a matrix [ 0 1 2 ]
- // [ 3 4 5 ]
- // the order is 0, 3, 1, 4, 2, 5...
- return new AffineTransform(mValues[0], mValues[3], mValues[1],
- mValues[4], mValues[2], mValues[5]);
- }
-
- public boolean hasPerspective() {
- return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
- }
-
- //----------
-
- /**
- * Returns true if the matrix is identity.
- * This maybe faster than testing if (getType() == 0)
- */
- @Override
- public boolean isIdentity() {
- for (int i = 0, k = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++, k++) {
- if (mValues[k] != ((i==j) ? 1 : 0)) {
- return false;
- }
- }
- }
-
- return true;
- }
-
- /**
- * Returns true if will map a rectangle to another rectangle. This can be
- * true if the matrix is identity, scale-only, or rotates a multiple of 90
- * degrees.
- */
- @Override
- public boolean rectStaysRect() {
- return (computeTypeMask() & kRectStaysRect_Mask) != 0;
- }
-
- /**
- * (deep) copy the src matrix into this matrix. If src is null, reset this
- * matrix to the identity matrix.
- */
- public void set(Matrix src) {
- if (src == null) {
- reset();
- } else {
- System.arraycopy(src.mValues, 0, mValues, 0, mValues.length);
- }
- }
-
- @Override
- public void set(_Original_Matrix src) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /** Returns true if obj is a Matrix and its values equal our values.
- */
- @Override
- public boolean equals(Object obj) {
- if (obj != null && obj instanceof Matrix) {
- Matrix matrix = (Matrix)obj;
- for (int i = 0 ; i < 9 ; i++) {
- if (mValues[i] != matrix.mValues[i]) {
- return false;
- }
- }
-
- return true;
- }
-
- return false;
- }
-
- /** Set the matrix to identity */
- @Override
- public void reset() {
- for (int i = 0, k = 0; i < 3; i++) {
- for (int j = 0; j < 3; j++, k++) {
- mValues[k] = ((i==j) ? 1 : 0);
- }
- }
- }
-
- /** Set the matrix to translate by (dx, dy). */
- @Override
- public void setTranslate(float dx, float dy) {
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = dx;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = dy;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to scale by sx and sy, with a pivot point at (px, py).
- * The pivot point is the coordinate that should remain unchanged by the
- * specified transformation.
- */
- @Override
- public void setScale(float sx, float sy, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /** Set the matrix to scale by sx and sy. */
- @Override
- public void setScale(float sx, float sy) {
- mValues[0] = sx;
- mValues[1] = 0;
- mValues[2] = 0;
- mValues[3] = 0;
- mValues[4] = sy;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to rotate by the specified number of degrees, with a pivot
- * point at (px, py). The pivot point is the coordinate that should remain
- * unchanged by the specified transformation.
- */
- @Override
- public void setRotate(float degrees, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
- addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /**
- * Set the matrix to rotate about (0,0) by the specified number of degrees.
- */
- @Override
- public void setRotate(float degrees) {
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
-
- mValues[0] = cos;
- mValues[1] = -sin;
- mValues[2] = 0;
- mValues[3] = sin;
- mValues[4] = cos;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to rotate by the specified sine and cosine values, with a
- * pivot point at (px, py). The pivot point is the coordinate that should
- * remain unchanged by the specified transformation.
- */
- @Override
- public void setSinCos(float sinValue, float cosValue, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- addTransform(new float[] { cosValue, -sinValue, 0, sinValue, cosValue, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /** Set the matrix to rotate by the specified sine and cosine values. */
- @Override
- public void setSinCos(float sinValue, float cosValue) {
- mValues[0] = cosValue;
- mValues[1] = -sinValue;
- mValues[2] = 0;
- mValues[3] = sinValue;
- mValues[4] = cosValue;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to skew by sx and sy, with a pivot point at (px, py).
- * The pivot point is the coordinate that should remain unchanged by the
- * specified transformation.
- */
- @Override
- public void setSkew(float kx, float ky, float px, float py) {
- // TODO: do it in one pass
-
- // translate so that the pivot is in 0,0
- mValues[0] = 1;
- mValues[1] = 0;
- mValues[2] = -px;
- mValues[3] = 0;
- mValues[4] = 1;
- mValues[5] = -py;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
-
- // scale
- addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
- }
-
- /** Set the matrix to skew by sx and sy. */
- @Override
- public void setSkew(float kx, float ky) {
- mValues[0] = 1;
- mValues[1] = kx;
- mValues[2] = -0;
- mValues[3] = ky;
- mValues[4] = 1;
- mValues[5] = 0;
- mValues[6] = 0;
- mValues[7] = 0;
- mValues[8] = 1;
- }
-
- /**
- * Set the matrix to the concatenation of the two specified matrices,
- * returning true if the the result can be represented. Either of the two
- * matrices may also be the target matrix. this = a * b
- */
- public boolean setConcat(Matrix a, Matrix b) {
- if (a == this) {
- preConcat(b);
- } else if (b == this) {
- postConcat(b);
- } else {
- Matrix tmp = new Matrix(b);
- tmp.addTransform(a.mValues);
- set(tmp);
- }
-
- return true;
- }
-
- @Override
- public boolean setConcat(_Original_Matrix a, _Original_Matrix b) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Preconcats the matrix with the specified translation.
- * M' = M * T(dx, dy)
- */
- @Override
- public boolean preTranslate(float dx, float dy) {
- // create a matrix that will be multiply by this
- Matrix m = new Matrix(new float[] { 1, 0, dx, 0, 1, dy, 0, 0, 1 });
- m.addTransform(this.mValues);
-
- System.arraycopy(m.mValues, 0, mValues, 0, 9);
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified scale.
- * M' = M * S(sx, sy, px, py)
- */
- @Override
- public boolean preScale(float sx, float sy, float px, float py) {
- Matrix m = new Matrix();
- m.setScale(sx, sy, px, py);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified scale.
- * M' = M * S(sx, sy)
- */
- @Override
- public boolean preScale(float sx, float sy) {
- Matrix m = new Matrix();
- m.setScale(sx, sy);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified rotation.
- * M' = M * R(degrees, px, py)
- */
- @Override
- public boolean preRotate(float degrees, float px, float py) {
- Matrix m = new Matrix();
- m.setRotate(degrees, px, py);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified rotation.
- * M' = M * R(degrees)
- */
- @Override
- public boolean preRotate(float degrees) {
- Matrix m = new Matrix();
- m.setRotate(degrees);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified skew.
- * M' = M * K(kx, ky, px, py)
- */
- @Override
- public boolean preSkew(float kx, float ky, float px, float py) {
- Matrix m = new Matrix();
- m.setSkew(kx, ky, px, py);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified skew.
- * M' = M * K(kx, ky)
- */
- @Override
- public boolean preSkew(float kx, float ky) {
- Matrix m = new Matrix();
- m.setSkew(kx, ky);
- m.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- /**
- * Preconcats the matrix with the specified matrix.
- * M' = M * other
- */
- public boolean preConcat(Matrix other) {
- Matrix m = new Matrix(other);
- other.addTransform(mValues);
- set(m);
-
- return true;
- }
-
- @Override
- public boolean preConcat(_Original_Matrix other) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Postconcats the matrix with the specified translation.
- * M' = T(dx, dy) * M
- */
- @Override
- public boolean postTranslate(float dx, float dy) {
- addTransform(new float[] { 1, 0, dx, 0, 1, dy, 0, 0, 1 });
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified scale.
- * M' = S(sx, sy, px, py) * M
- */
- @Override
- public boolean postScale(float sx, float sy, float px, float py) {
- // TODO: do it in one pass
- // translate so that the pivot is in 0,0
- addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 });
- // scale
- addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified scale.
- * M' = S(sx, sy) * M
- */
- @Override
- public boolean postScale(float sx, float sy) {
- addTransform(new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 });
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified rotation.
- * M' = R(degrees, px, py) * M
- */
- @Override
- public boolean postRotate(float degrees, float px, float py) {
- // TODO: do it in one pass
- // translate so that the pivot is in 0,0
- addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 });
- // scale
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
- addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified rotation.
- * M' = R(degrees) * M
- */
- @Override
- public boolean postRotate(float degrees) {
- double rad = Math.toRadians(degrees);
- float cos = (float)Math.cos(rad);
- float sin = (float)Math.sin(rad);
- addTransform(new float[] { cos, -sin, 0, sin, cos, 0, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified skew.
- * M' = K(kx, ky, px, py) * M
- */
- @Override
- public boolean postSkew(float kx, float ky, float px, float py) {
- // TODO: do it in one pass
- // translate so that the pivot is in 0,0
- addTransform(new float[] { 1, 0, -px, 0, 1, py, 0, 0, 1 });
- // scale
- addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
- // translate back the pivot
- addTransform(new float[] { 1, 0, px, 0, 1, py, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified skew.
- * M' = K(kx, ky) * M
- */
- @Override
- public boolean postSkew(float kx, float ky) {
- addTransform(new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
-
- return true;
- }
-
- /**
- * Postconcats the matrix with the specified matrix.
- * M' = other * M
- */
- public boolean postConcat(Matrix other) {
- addTransform(other.mValues);
-
- return true;
- }
-
- @Override
- public boolean postConcat(_Original_Matrix other) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /** Controlls how the src rect should align into the dst rect for
- setRectToRect().
- */
- public enum ScaleToFit {
- /**
- * Scale in X and Y independently, so that src matches dst exactly.
- * This may change the aspect ratio of the src.
- */
- FILL (0),
- /**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. START aligns the result to the
- * left and top edges of dst.
- */
- START (1),
- /**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. The result is centered inside dst.
- */
- CENTER (2),
- /**
- * Compute a scale that will maintain the original src aspect ratio,
- * but will also ensure that src fits entirely inside dst. At least one
- * axis (X or Y) will fit exactly. END aligns the result to the
- * right and bottom edges of dst.
- */
- END (3);
-
- // the native values must match those in SkMatrix.h
- ScaleToFit(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- /**
- * Set the matrix to the scale and translate values that map the source
- * rectangle to the destination rectangle, returning true if the result
- * can be represented.
- *
- * @param src the source rectangle to map from.
- * @param dst the destination rectangle to map to.
- * @param stf the ScaleToFit option
- * @return true if the matrix can be represented by the rectangle mapping.
- */
- public boolean setRectToRect(RectF src, RectF dst, ScaleToFit stf) {
- if (dst == null || src == null) {
- throw new NullPointerException();
- }
-
- if (src.isEmpty()) {
- reset();
- return false;
- }
-
- if (dst.isEmpty()) {
- mValues[0] = mValues[1] = mValues[2] = mValues[3] = mValues[4] = mValues[5]
- = mValues[6] = mValues[7] = 0;
- mValues[8] = 1;
- } else {
- float tx, sx = dst.width() / src.width();
- float ty, sy = dst.height() / src.height();
- boolean xLarger = false;
-
- if (stf != ScaleToFit.FILL) {
- if (sx > sy) {
- xLarger = true;
- sx = sy;
- } else {
- sy = sx;
- }
- }
-
- tx = dst.left - src.left * sx;
- ty = dst.top - src.top * sy;
- if (stf == ScaleToFit.CENTER || stf == ScaleToFit.END) {
- float diff;
-
- if (xLarger) {
- diff = dst.width() - src.width() * sy;
- } else {
- diff = dst.height() - src.height() * sy;
- }
-
- if (stf == ScaleToFit.CENTER) {
- diff = diff / 2;
- }
-
- if (xLarger) {
- tx += diff;
- } else {
- ty += diff;
- }
- }
-
- mValues[0] = sx;
- mValues[4] = sy;
- mValues[2] = tx;
- mValues[5] = ty;
- mValues[1] = mValues[3] = mValues[6] = mValues[7] = 0;
-
- }
- // shared cleanup
- mValues[8] = 1;
- return true;
- }
-
- @Override
- public boolean setRectToRect(RectF src, RectF dst, _Original_Matrix.ScaleToFit stf) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Set the matrix such that the specified src points would map to the
- * specified dst points. The "points" are represented as an array of floats,
- * order [x0, y0, x1, y1, ...], where each "point" is 2 float values.
- *
- * @param src The array of src [x,y] pairs (points)
- * @param srcIndex Index of the first pair of src values
- * @param dst The array of dst [x,y] pairs (points)
- * @param dstIndex Index of the first pair of dst values
- * @param pointCount The number of pairs/points to be used. Must be [0..4]
- * @return true if the matrix was set to the specified transformation
- */
- @Override
- public boolean setPolyToPoly(float[] src, int srcIndex,
- float[] dst, int dstIndex,
- int pointCount) {
- if (pointCount > 4) {
- throw new IllegalArgumentException();
- }
- checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
- throw new UnsupportedOperationException("STUB NEEDED");
- }
-
- /**
- * If this matrix can be inverted, return true and if inverse is not null,
- * set inverse to be the inverse of this matrix. If this matrix cannot be
- * inverted, ignore inverse and return false.
- */
- public boolean invert(Matrix inverse) {
- if (inverse == null) {
- return false;
- }
-
- try {
- AffineTransform affineTransform = getTransform();
- AffineTransform inverseTransform = affineTransform.createInverse();
- inverse.mValues[0] = (float)inverseTransform.getScaleX();
- inverse.mValues[1] = (float)inverseTransform.getShearX();
- inverse.mValues[2] = (float)inverseTransform.getTranslateX();
- inverse.mValues[3] = (float)inverseTransform.getScaleX();
- inverse.mValues[4] = (float)inverseTransform.getShearY();
- inverse.mValues[5] = (float)inverseTransform.getTranslateY();
-
- return true;
- } catch (NoninvertibleTransformException e) {
- return false;
- }
- }
-
- @Override
- public boolean invert(_Original_Matrix inverse) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- /**
- * Apply this matrix to the array of 2D points specified by src, and write
- * the transformed points into the array of points specified by dst. The
- * two arrays represent their "points" as pairs of floats [x, y].
- *
- * @param dst The array of dst points (x,y pairs)
- * @param dstIndex The index of the first [x,y] pair of dst floats
- * @param src The array of src points (x,y pairs)
- * @param srcIndex The index of the first [x,y] pair of src floats
- * @param pointCount The number of points (x,y pairs) to transform
- */
- @Override
- public void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
- int pointCount) {
- checkPointArrays(src, srcIndex, dst, dstIndex, pointCount);
-
- for (int i = 0 ; i < pointCount ; i++) {
- // just in case we are doing in place, we better put this in temp vars
- float x = mValues[0] * src[i + srcIndex] +
- mValues[1] * src[i + srcIndex + 1] +
- mValues[2];
- float y = mValues[3] * src[i + srcIndex] +
- mValues[4] * src[i + srcIndex + 1] +
- mValues[5];
-
- dst[i + dstIndex] = x;
- dst[i + dstIndex + 1] = y;
- }
- }
-
- /**
- * Apply this matrix to the array of 2D vectors specified by src, and write
- * the transformed vectors into the array of vectors specified by dst. The
- * two arrays represent their "vectors" as pairs of floats [x, y].
- *
- * @param dst The array of dst vectors (x,y pairs)
- * @param dstIndex The index of the first [x,y] pair of dst floats
- * @param src The array of src vectors (x,y pairs)
- * @param srcIndex The index of the first [x,y] pair of src floats
- * @param vectorCount The number of vectors (x,y pairs) to transform
- */
- @Override
- public void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex,
- int vectorCount) {
- checkPointArrays(src, srcIndex, dst, dstIndex, vectorCount);
- throw new UnsupportedOperationException("STUB NEEDED");
- }
-
- /**
- * Apply this matrix to the array of 2D points specified by src, and write
- * the transformed points into the array of points specified by dst. The
- * two arrays represent their "points" as pairs of floats [x, y].
- *
- * @param dst The array of dst points (x,y pairs)
- * @param src The array of src points (x,y pairs)
- */
- @Override
- public void mapPoints(float[] dst, float[] src) {
- if (dst.length != src.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- mapPoints(dst, 0, src, 0, dst.length >> 1);
- }
-
- /**
- * Apply this matrix to the array of 2D vectors specified by src, and write
- * the transformed vectors into the array of vectors specified by dst. The
- * two arrays represent their "vectors" as pairs of floats [x, y].
- *
- * @param dst The array of dst vectors (x,y pairs)
- * @param src The array of src vectors (x,y pairs)
- */
- @Override
- public void mapVectors(float[] dst, float[] src) {
- if (dst.length != src.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- mapVectors(dst, 0, src, 0, dst.length >> 1);
- }
-
- /**
- * Apply this matrix to the array of 2D points, and write the transformed
- * points back into the array
- *
- * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
- */
- @Override
- public void mapPoints(float[] pts) {
- mapPoints(pts, 0, pts, 0, pts.length >> 1);
- }
-
- /**
- * Apply this matrix to the array of 2D vectors, and write the transformed
- * vectors back into the array.
- * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform.
- */
- @Override
- public void mapVectors(float[] vecs) {
- mapVectors(vecs, 0, vecs, 0, vecs.length >> 1);
- }
-
- /**
- * Apply this matrix to the src rectangle, and write the transformed
- * rectangle into dst. This is accomplished by transforming the 4 corners of
- * src, and then setting dst to the bounds of those points.
- *
- * @param dst Where the transformed rectangle is written.
- * @param src The original rectangle to be transformed.
- * @return the result of calling rectStaysRect()
- */
- @Override
- public boolean mapRect(RectF dst, RectF src) {
- if (dst == null || src == null) {
- throw new NullPointerException();
- }
-
- // array with 4 corners
- float[] corners = new float[] {
- src.left, src.top,
- src.right, src.top,
- src.right, src.bottom,
- src.left, src.bottom,
- };
-
- // apply the transform to them.
- mapPoints(corners);
-
- // now put the result in the rect. We take the min/max of Xs and min/max of Ys
- dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
- dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
-
- dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
- dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
-
- return rectStaysRect();
- }
-
- /**
- * Apply this matrix to the rectangle, and write the transformed rectangle
- * back into it. This is accomplished by transforming the 4 corners of rect,
- * and then setting it to the bounds of those points
- *
- * @param rect The rectangle to transform.
- * @return the result of calling rectStaysRect()
- */
- @Override
- public boolean mapRect(RectF rect) {
- return mapRect(rect, rect);
- }
-
- /**
- * Return the mean radius of a circle after it has been mapped by
- * this matrix. NOTE: in perspective this value assumes the circle
- * has its center at the origin.
- */
- @Override
- public float mapRadius(float radius) {
- throw new UnsupportedOperationException("STUB NEEDED");
- }
-
- /** Copy 9 values from the matrix into the array.
- */
- @Override
- public void getValues(float[] values) {
- if (values.length < 9) {
- throw new ArrayIndexOutOfBoundsException();
- }
- System.arraycopy(mValues, 0, values, 0, mValues.length);
- }
-
- /** Copy 9 values from the array into the matrix.
- Depending on the implementation of Matrix, these may be
- transformed into 16.16 integers in the Matrix, such that
- a subsequent call to getValues() will not yield exactly
- the same values.
- */
- @Override
- public void setValues(float[] values) {
- if (values.length < 9) {
- throw new ArrayIndexOutOfBoundsException();
- }
- System.arraycopy(values, 0, mValues, 0, mValues.length);
- }
-
- @SuppressWarnings("unused")
- private final static int kIdentity_Mask = 0;
- private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation
- private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale
- private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates
- private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective
- private final static int kRectStaysRect_Mask = 0x10;
- @SuppressWarnings("unused")
- private final static int kUnknown_Mask = 0x80;
-
- @SuppressWarnings("unused")
- private final static int kAllMasks = kTranslate_Mask |
- kScale_Mask |
- kAffine_Mask |
- kPerspective_Mask |
- kRectStaysRect_Mask;
-
- // these guys align with the masks, so we can compute a mask from a variable 0/1
- @SuppressWarnings("unused")
- private final static int kTranslate_Shift = 0;
- @SuppressWarnings("unused")
- private final static int kScale_Shift = 1;
- @SuppressWarnings("unused")
- private final static int kAffine_Shift = 2;
- @SuppressWarnings("unused")
- private final static int kPerspective_Shift = 3;
- private final static int kRectStaysRect_Shift = 4;
-
- private int computeTypeMask() {
- int mask = 0;
-
- if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) {
- mask |= kPerspective_Mask;
- }
-
- if (mValues[2] != 0. || mValues[5] != 0.) {
- mask |= kTranslate_Mask;
- }
-
- float m00 = mValues[0];
- float m01 = mValues[1];
- float m10 = mValues[3];
- float m11 = mValues[4];
-
- if (m01 != 0. || m10 != 0.) {
- mask |= kAffine_Mask;
- }
-
- if (m00 != 1. || m11 != 1.) {
- mask |= kScale_Mask;
- }
-
- if ((mask & kPerspective_Mask) == 0) {
- // map non-zero to 1
- int im00 = m00 != 0 ? 1 : 0;
- int im01 = m01 != 0 ? 1 : 0;
- int im10 = m10 != 0 ? 1 : 0;
- int im11 = m11 != 0 ? 1 : 0;
-
- // record if the (p)rimary and (s)econdary diagonals are all 0 or
- // all non-zero (answer is 0 or 1)
- int dp0 = (im00 | im11) ^ 1; // true if both are 0
- int dp1 = im00 & im11; // true if both are 1
- int ds0 = (im01 | im10) ^ 1; // true if both are 0
- int ds1 = im01 & im10; // true if both are 1
-
- // return 1 if primary is 1 and secondary is 0 or
- // primary is 0 and secondary is 1
- mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
- }
-
- return mask;
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
new file mode 100644
index 0000000..451edd2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Matrix_Delegate.java
@@ -0,0 +1,1129 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Matrix.ScaleToFit;
+
+import java.awt.geom.AffineTransform;
+import java.awt.geom.NoninvertibleTransformException;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Matrix
+ *
+ * Through the layoutlib_create tool, the original native methods of Matrix 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 Matrix class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Matrix_Delegate {
+
+ private final static int MATRIX_SIZE = 9;
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Matrix_Delegate> sManager =
+ new DelegateManager<Matrix_Delegate>(Matrix_Delegate.class);
+
+ // ---- delegate data ----
+ private float mValues[] = new float[MATRIX_SIZE];
+
+ // ---- Public Helper methods ----
+
+ public static Matrix_Delegate getDelegate(int native_instance) {
+ return sManager.getDelegate(native_instance);
+ }
+
+ /**
+ * Returns an {@link AffineTransform} matching the given Matrix.
+ */
+ public static AffineTransform getAffineTransform(Matrix m) {
+ Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
+ if (delegate == null) {
+ return null;
+ }
+
+ return delegate.getAffineTransform();
+ }
+
+ public static boolean hasPerspective(Matrix m) {
+ Matrix_Delegate delegate = sManager.getDelegate(m.native_instance);
+ if (delegate == null) {
+ return false;
+ }
+
+ return delegate.hasPerspective();
+ }
+
+ /**
+ * Sets the content of the matrix with the content of another matrix.
+ */
+ public void set(Matrix_Delegate matrix) {
+ System.arraycopy(matrix.mValues, 0, mValues, 0, MATRIX_SIZE);
+ }
+
+ /**
+ * Sets the content of the matrix with the content of another matrix represented as an array
+ * of values.
+ */
+ public void set(float[] values) {
+ System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
+ }
+
+ /**
+ * Resets the matrix to be the identity matrix.
+ */
+ public void reset() {
+ reset(mValues);
+ }
+
+ /**
+ * Returns whether or not the matrix is identity.
+ */
+ public boolean isIdentity() {
+ for (int i = 0, k = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++, k++) {
+ if (mValues[k] != ((i==j) ? 1 : 0)) {
+ return false;
+ }
+ }
+ }
+
+ return true;
+ }
+
+ public static float[] makeValues(AffineTransform matrix) {
+ float[] values = new float[MATRIX_SIZE];
+ values[0] = (float) matrix.getScaleX();
+ values[1] = (float) matrix.getShearX();
+ values[2] = (float) matrix.getTranslateX();
+ values[3] = (float) matrix.getShearY();
+ values[4] = (float) matrix.getScaleY();
+ values[5] = (float) matrix.getTranslateY();
+ values[6] = 0.f;
+ values[7] = 0.f;
+ values[8] = 1.f;
+
+ return values;
+ }
+
+ public static Matrix_Delegate make(AffineTransform matrix) {
+ return new Matrix_Delegate(makeValues(matrix));
+ }
+
+ public boolean mapRect(RectF dst, RectF src) {
+ // array with 4 corners
+ float[] corners = new float[] {
+ src.left, src.top,
+ src.right, src.top,
+ src.right, src.bottom,
+ src.left, src.bottom,
+ };
+
+ // apply the transform to them.
+ mapPoints(corners);
+
+ // now put the result in the rect. We take the min/max of Xs and min/max of Ys
+ dst.left = Math.min(Math.min(corners[0], corners[2]), Math.min(corners[4], corners[6]));
+ dst.right = Math.max(Math.max(corners[0], corners[2]), Math.max(corners[4], corners[6]));
+
+ dst.top = Math.min(Math.min(corners[1], corners[3]), Math.min(corners[5], corners[7]));
+ dst.bottom = Math.max(Math.max(corners[1], corners[3]), Math.max(corners[5], corners[7]));
+
+
+ return (computeTypeMask() & kRectStaysRect_Mask) != 0;
+ }
+
+
+ /**
+ * Returns an {@link AffineTransform} matching the matrix.
+ */
+ public AffineTransform getAffineTransform() {
+ return getAffineTransform(mValues);
+ }
+
+ public boolean hasPerspective() {
+ return (mValues[6] != 0 || mValues[7] != 0 || mValues[8] != 1);
+ }
+
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int native_create(int native_src_or_zero) {
+ // create the delegate
+ Matrix_Delegate newDelegate = new Matrix_Delegate();
+
+ // copy from values if needed.
+ if (native_src_or_zero > 0) {
+ Matrix_Delegate oldDelegate = sManager.getDelegate(native_src_or_zero);
+ if (oldDelegate != null) {
+ System.arraycopy(
+ oldDelegate.mValues, 0,
+ newDelegate.mValues, 0,
+ MATRIX_SIZE);
+ }
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_isIdentity(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ return d.isIdentity();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_rectStaysRect(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return true;
+ }
+
+ return (d.computeTypeMask() & kRectStaysRect_Mask) != 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_reset(int native_object) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ reset(d.mValues);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_set(int native_object, int other) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ Matrix_Delegate src = sManager.getDelegate(other);
+ if (src == null) {
+ return;
+ }
+
+ System.arraycopy(src.mValues, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ setTranslate(d.mValues, dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*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) {
+ return;
+ }
+
+ d.mValues = getScale(sx, sy, px, py);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues[0] = sx;
+ d.mValues[1] = 0;
+ d.mValues[2] = 0;
+ d.mValues[3] = 0;
+ d.mValues[4] = sy;
+ d.mValues[5] = 0;
+ d.mValues[6] = 0;
+ d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setRotate(int native_object, float degrees, float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues = getRotate(degrees, px, py);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ setRotate(d.mValues, degrees);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(d.mValues, -px, -py);
+
+ // scale
+ d.postTransform(getRotate(sinValue, cosValue));
+ // translate back the pivot
+ d.postTransform(getTranslate(px, py));
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setSinCos(int native_object, float sinValue, float cosValue) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ setRotate(d.mValues, sinValue, cosValue);
+ }
+
+ @LayoutlibDelegate
+ /*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) {
+ return;
+ }
+
+ d.mValues = getSkew(kx, ky, px, py);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ d.mValues[0] = 1;
+ d.mValues[1] = kx;
+ d.mValues[2] = -0;
+ d.mValues[3] = ky;
+ d.mValues[4] = 1;
+ d.mValues[5] = 0;
+ d.mValues[6] = 0;
+ d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_setConcat(int native_object, int a, int b) {
+ if (a == native_object) {
+ return native_preConcat(native_object, b);
+ } else if (b == native_object) {
+ return native_postConcat(native_object, a);
+ }
+
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate a_mtx = sManager.getDelegate(a);
+ if (a_mtx == null) {
+ return false;
+ }
+
+ Matrix_Delegate b_mtx = sManager.getDelegate(b);
+ if (b_mtx == null) {
+ return false;
+ }
+
+ multiply(d.mValues, a_mtx.mValues, b_mtx.mValues);
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getTranslate(dx, dy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preScale(int native_object, float sx, float sy,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getScale(sx, sy, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getScale(sx, sy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preRotate(int native_object, float degrees,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getRotate(degrees, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ d.preTransform(getRotate(sin, cos));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preSkew(int native_object, float kx, float ky,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getSkew(kx, ky, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(getSkew(kx, ky));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_preConcat(int native_object, int other_matrix) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate other = sManager.getDelegate(other_matrix);
+ if (d == null) {
+ return false;
+ }
+
+ d.preTransform(other.mValues);
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postTranslate(int native_object, float dx, float dy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getTranslate(dx, dy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postScale(int native_object, float sx, float sy,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getScale(sx, sy, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postScale(int native_object, float sx, float sy) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getScale(sx, sy));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postRotate(int native_object, float degrees,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getRotate(degrees, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postRotate(int native_object, float degrees) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getRotate(degrees));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postSkew(int native_object, float kx, float ky,
+ float px, float py) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getSkew(kx, ky, px, py));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postSkew(int native_object, float kx, float ky) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(getSkew(kx, ky));
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_postConcat(int native_object, int other_matrix) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate other = sManager.getDelegate(other_matrix);
+ if (d == null) {
+ return false;
+ }
+
+ d.postTransform(other.mValues);
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_setRectToRect(int native_object, RectF src,
+ RectF dst, int stf) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ if (src.isEmpty()) {
+ reset(d.mValues);
+ return false;
+ }
+
+ if (dst.isEmpty()) {
+ d.mValues[0] = d.mValues[1] = d.mValues[2] = d.mValues[3] = d.mValues[4] = d.mValues[5]
+ = d.mValues[6] = d.mValues[7] = 0;
+ d.mValues[8] = 1;
+ } else {
+ float tx, sx = dst.width() / src.width();
+ float ty, sy = dst.height() / src.height();
+ boolean xLarger = false;
+
+ if (stf != ScaleToFit.FILL.nativeInt) {
+ if (sx > sy) {
+ xLarger = true;
+ sx = sy;
+ } else {
+ sy = sx;
+ }
+ }
+
+ tx = dst.left - src.left * sx;
+ ty = dst.top - src.top * sy;
+ if (stf == ScaleToFit.CENTER.nativeInt || stf == ScaleToFit.END.nativeInt) {
+ float diff;
+
+ if (xLarger) {
+ diff = dst.width() - src.width() * sy;
+ } else {
+ diff = dst.height() - src.height() * sy;
+ }
+
+ if (stf == ScaleToFit.CENTER.nativeInt) {
+ diff = diff / 2;
+ }
+
+ if (xLarger) {
+ tx += diff;
+ } else {
+ ty += diff;
+ }
+ }
+
+ d.mValues[0] = sx;
+ d.mValues[4] = sy;
+ d.mValues[2] = tx;
+ d.mValues[5] = ty;
+ d.mValues[1] = d.mValues[3] = d.mValues[6] = d.mValues[7] = 0;
+
+ }
+ // shared cleanup
+ d.mValues[8] = 1;
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_setPolyToPoly(int native_object, float[] src, int srcIndex,
+ float[] dst, int dstIndex, int pointCount) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Matrix.setPolyToPoly is not supported.",
+ null, null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_invert(int native_object, int inverse) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ Matrix_Delegate inv_mtx = sManager.getDelegate(inverse);
+ if (inv_mtx == null) {
+ return false;
+ }
+
+ try {
+ AffineTransform affineTransform = d.getAffineTransform();
+ AffineTransform inverseTransform = affineTransform.createInverse();
+ inv_mtx.mValues[0] = (float)inverseTransform.getScaleX();
+ inv_mtx.mValues[1] = (float)inverseTransform.getShearX();
+ inv_mtx.mValues[2] = (float)inverseTransform.getTranslateX();
+ inv_mtx.mValues[3] = (float)inverseTransform.getScaleX();
+ inv_mtx.mValues[4] = (float)inverseTransform.getShearY();
+ inv_mtx.mValues[5] = (float)inverseTransform.getTranslateY();
+
+ return true;
+ } catch (NoninvertibleTransformException e) {
+ return false;
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_mapPoints(int native_object, float[] dst, int dstIndex,
+ float[] src, int srcIndex, int ptCount, boolean isPts) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ if (isPts) {
+ d.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+ } else {
+ d.mapVectors(dst, dstIndex, src, srcIndex, ptCount);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_mapRect(int native_object, RectF dst, RectF src) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return false;
+ }
+
+ return d.mapRect(dst, src);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_mapRadius(int native_object, float radius) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return 0.f;
+ }
+
+ float[] src = new float[] { radius, 0.f, 0.f, radius };
+ d.mapVectors(src, 0, src, 0, 2);
+
+ float l1 = getPointLength(src, 0);
+ float l2 = getPointLength(src, 2);
+
+ return (float) Math.sqrt(l1 * l2);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getValues(int native_object, float[] values) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ System.arraycopy(d.mValues, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setValues(int native_object, float[] values) {
+ Matrix_Delegate d = sManager.getDelegate(native_object);
+ if (d == null) {
+ return;
+ }
+
+ System.arraycopy(values, 0, d.mValues, 0, MATRIX_SIZE);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_equals(int native_a, int native_b) {
+ Matrix_Delegate a = sManager.getDelegate(native_a);
+ if (a == null) {
+ return false;
+ }
+
+ Matrix_Delegate b = sManager.getDelegate(native_b);
+ if (b == null) {
+ return false;
+ }
+
+ for (int i = 0 ; i < MATRIX_SIZE ; i++) {
+ if (a.mValues[i] != b.mValues[i]) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private helper methods ----
+
+ /*package*/ static AffineTransform getAffineTransform(float[] matrix) {
+ // the AffineTransform constructor takes the value in a different order
+ // for a matrix [ 0 1 2 ]
+ // [ 3 4 5 ]
+ // the order is 0, 3, 1, 4, 2, 5...
+ return new AffineTransform(
+ matrix[0], matrix[3], matrix[1],
+ matrix[4], matrix[2], matrix[5]);
+ }
+
+ /**
+ * Reset a matrix to the identity
+ */
+ private static void reset(float[] mtx) {
+ for (int i = 0, k = 0; i < 3; i++) {
+ for (int j = 0; j < 3; j++, k++) {
+ mtx[k] = ((i==j) ? 1 : 0);
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private final static int kIdentity_Mask = 0;
+ private final static int kTranslate_Mask = 0x01; //!< set if the matrix has translation
+ private final static int kScale_Mask = 0x02; //!< set if the matrix has X or Y scale
+ private final static int kAffine_Mask = 0x04; //!< set if the matrix skews or rotates
+ private final static int kPerspective_Mask = 0x08; //!< set if the matrix is in perspective
+ private final static int kRectStaysRect_Mask = 0x10;
+ @SuppressWarnings("unused")
+ private final static int kUnknown_Mask = 0x80;
+
+ @SuppressWarnings("unused")
+ private final static int kAllMasks = kTranslate_Mask |
+ kScale_Mask |
+ kAffine_Mask |
+ kPerspective_Mask |
+ kRectStaysRect_Mask;
+
+ // these guys align with the masks, so we can compute a mask from a variable 0/1
+ @SuppressWarnings("unused")
+ private final static int kTranslate_Shift = 0;
+ @SuppressWarnings("unused")
+ private final static int kScale_Shift = 1;
+ @SuppressWarnings("unused")
+ private final static int kAffine_Shift = 2;
+ @SuppressWarnings("unused")
+ private final static int kPerspective_Shift = 3;
+ private final static int kRectStaysRect_Shift = 4;
+
+ private int computeTypeMask() {
+ int mask = 0;
+
+ if (mValues[6] != 0. || mValues[7] != 0. || mValues[8] != 1.) {
+ mask |= kPerspective_Mask;
+ }
+
+ if (mValues[2] != 0. || mValues[5] != 0.) {
+ mask |= kTranslate_Mask;
+ }
+
+ float m00 = mValues[0];
+ float m01 = mValues[1];
+ float m10 = mValues[3];
+ float m11 = mValues[4];
+
+ if (m01 != 0. || m10 != 0.) {
+ mask |= kAffine_Mask;
+ }
+
+ if (m00 != 1. || m11 != 1.) {
+ mask |= kScale_Mask;
+ }
+
+ if ((mask & kPerspective_Mask) == 0) {
+ // map non-zero to 1
+ int im00 = m00 != 0 ? 1 : 0;
+ int im01 = m01 != 0 ? 1 : 0;
+ int im10 = m10 != 0 ? 1 : 0;
+ int im11 = m11 != 0 ? 1 : 0;
+
+ // record if the (p)rimary and (s)econdary diagonals are all 0 or
+ // all non-zero (answer is 0 or 1)
+ int dp0 = (im00 | im11) ^ 1; // true if both are 0
+ int dp1 = im00 & im11; // true if both are 1
+ int ds0 = (im01 | im10) ^ 1; // true if both are 0
+ int ds1 = im01 & im10; // true if both are 1
+
+ // return 1 if primary is 1 and secondary is 0 or
+ // primary is 0 and secondary is 1
+ mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
+ }
+
+ return mask;
+ }
+
+ private Matrix_Delegate() {
+ reset();
+ }
+
+ private Matrix_Delegate(float[] values) {
+ System.arraycopy(values, 0, mValues, 0, MATRIX_SIZE);
+ }
+
+ /**
+ * Adds the given transformation to the current Matrix
+ * <p/>This in effect does this = this*matrix
+ * @param matrix
+ */
+ private void postTransform(float[] matrix) {
+ float[] tmp = new float[9];
+ multiply(tmp, mValues, matrix);
+ mValues = tmp;
+ }
+
+ /**
+ * Adds the given transformation to the current Matrix
+ * <p/>This in effect does this = matrix*this
+ * @param matrix
+ */
+ private void preTransform(float[] matrix) {
+ float[] tmp = new float[9];
+ multiply(tmp, matrix, mValues);
+ mValues = tmp;
+ }
+
+ /**
+ * Apply this matrix to the array of 2D points specified by src, and write
+ * the transformed points into the array of points specified by dst. The
+ * two arrays represent their "points" as pairs of floats [x, y].
+ *
+ * @param dst The array of dst points (x,y pairs)
+ * @param dstIndex The index of the first [x,y] pair of dst floats
+ * @param src The array of src points (x,y pairs)
+ * @param srcIndex The index of the first [x,y] pair of src floats
+ * @param pointCount The number of points (x,y pairs) to transform
+ */
+
+ private void mapPoints(float[] dst, int dstIndex, float[] src, int srcIndex,
+ int pointCount) {
+ final int count = pointCount * 2;
+
+ float[] tmpDest = dst;
+ boolean inPlace = dst == src;
+ if (inPlace) {
+ tmpDest = new float[dstIndex + count];
+ }
+
+ for (int i = 0 ; i < count ; i += 2) {
+ // just in case we are doing in place, we better put this in temp vars
+ float x = mValues[0] * src[i + srcIndex] +
+ mValues[1] * src[i + srcIndex + 1] +
+ mValues[2];
+ float y = mValues[3] * src[i + srcIndex] +
+ mValues[4] * src[i + srcIndex + 1] +
+ mValues[5];
+
+ tmpDest[i + dstIndex] = x;
+ tmpDest[i + dstIndex + 1] = y;
+ }
+
+ if (inPlace) {
+ System.arraycopy(tmpDest, dstIndex, dst, dstIndex, count);
+ }
+ }
+
+ /**
+ * Apply this matrix to the array of 2D points, and write the transformed
+ * points back into the array
+ *
+ * @param pts The array [x0, y0, x1, y1, ...] of points to transform.
+ */
+
+ private void mapPoints(float[] pts) {
+ mapPoints(pts, 0, pts, 0, pts.length >> 1);
+ }
+
+ private void mapVectors(float[] dst, int dstIndex, float[] src, int srcIndex, int ptCount) {
+ if (hasPerspective()) {
+ // transform the (0,0) point
+ float[] origin = new float[] { 0.f, 0.f};
+ mapPoints(origin);
+
+ // translate the vector data as points
+ mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+
+ // then substract the transformed origin.
+ final int count = ptCount * 2;
+ for (int i = 0 ; i < count ; i += 2) {
+ dst[dstIndex + i] = dst[dstIndex + i] - origin[0];
+ dst[dstIndex + i + 1] = dst[dstIndex + i + 1] - origin[1];
+ }
+ } else {
+ // make a copy of the matrix
+ Matrix_Delegate copy = new Matrix_Delegate(mValues);
+
+ // remove the translation
+ setTranslate(copy.mValues, 0, 0);
+
+ // map the content as points.
+ copy.mapPoints(dst, dstIndex, src, srcIndex, ptCount);
+ }
+ }
+
+ private static float getPointLength(float[] src, int index) {
+ return (float) Math.sqrt(src[index] * src[index] + src[index + 1] * src[index + 1]);
+ }
+
+ /**
+ * multiply two matrices and store them in a 3rd.
+ * <p/>This in effect does dest = a*b
+ * dest cannot be the same as a or b.
+ */
+ /*package*/ static void multiply(float dest[], float[] a, float[] b) {
+ // first row
+ dest[0] = b[0] * a[0] + b[1] * a[3] + b[2] * a[6];
+ dest[1] = b[0] * a[1] + b[1] * a[4] + b[2] * a[7];
+ dest[2] = b[0] * a[2] + b[1] * a[5] + b[2] * a[8];
+
+ // 2nd row
+ dest[3] = b[3] * a[0] + b[4] * a[3] + b[5] * a[6];
+ dest[4] = b[3] * a[1] + b[4] * a[4] + b[5] * a[7];
+ dest[5] = b[3] * a[2] + b[4] * a[5] + b[5] * a[8];
+
+ // 3rd row
+ dest[6] = b[6] * a[0] + b[7] * a[3] + b[8] * a[6];
+ dest[7] = b[6] * a[1] + b[7] * a[4] + b[8] * a[7];
+ dest[8] = b[6] * a[2] + b[7] * a[5] + b[8] * a[8];
+ }
+
+ /**
+ * Returns a matrix that represents a given translate
+ * @param dx
+ * @param dy
+ * @return
+ */
+ /*package*/ static float[] getTranslate(float dx, float dy) {
+ return setTranslate(new float[9], dx, dy);
+ }
+
+ /*package*/ static float[] setTranslate(float[] dest, float dx, float dy) {
+ dest[0] = 1;
+ dest[1] = 0;
+ dest[2] = dx;
+ dest[3] = 0;
+ dest[4] = 1;
+ dest[5] = dy;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 1;
+ return dest;
+ }
+
+ /*package*/ static float[] getScale(float sx, float sy) {
+ return new float[] { sx, 0, 0, 0, sy, 0, 0, 0, 1 };
+ }
+
+ /**
+ * Returns a matrix that represents the given scale info.
+ * @param sx
+ * @param sy
+ * @param px
+ * @param py
+ */
+ /*package*/ static float[] getScale(float sx, float sy, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate tmp so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // scale into tmp2
+ multiply(tmp2, tmp, getScale(sx, sy));
+
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+
+
+ /*package*/ static float[] getRotate(float degrees) {
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ return getRotate(sin, cos);
+ }
+
+ /*package*/ static float[] getRotate(float sin, float cos) {
+ return setRotate(new float[9], sin, cos);
+ }
+
+ /*package*/ static float[] setRotate(float[] dest, float degrees) {
+ double rad = Math.toRadians(degrees);
+ float sin = (float)Math.sin(rad);
+ float cos = (float)Math.cos(rad);
+
+ return setRotate(dest, sin, cos);
+ }
+
+ /*package*/ static float[] setRotate(float[] dest, float sin, float cos) {
+ dest[0] = cos;
+ dest[1] = -sin;
+ dest[2] = 0;
+ dest[3] = sin;
+ dest[4] = cos;
+ dest[5] = 0;
+ dest[6] = 0;
+ dest[7] = 0;
+ dest[8] = 1;
+ return dest;
+ }
+
+ /*package*/ static float[] getRotate(float degrees, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // rotate into tmp2
+ double rad = Math.toRadians(degrees);
+ float cos = (float)Math.cos(rad);
+ float sin = (float)Math.sin(rad);
+ multiply(tmp2, tmp, getRotate(sin, cos));
+
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+
+ /*package*/ static float[] getSkew(float kx, float ky) {
+ return new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 };
+ }
+
+ /*package*/ static float[] getSkew(float kx, float ky, float px, float py) {
+ float[] tmp = new float[9];
+ float[] tmp2 = new float[9];
+
+ // TODO: do it in one pass
+
+ // translate so that the pivot is in 0,0
+ setTranslate(tmp, -px, -py);
+
+ // skew into tmp2
+ multiply(tmp2, tmp, new float[] { 1, kx, 0, ky, 1, 0, 0, 0, 1 });
+ // translate back the pivot back into tmp
+ multiply(tmp, tmp2, getTranslate(px, py));
+
+ return tmp;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
new file mode 100644
index 0000000..5e882ce
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/NinePatch_Delegate.java
@@ -0,0 +1,225 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.GcSnapshot;
+import com.android.ninepatch.NinePatchChunk;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.drawable.NinePatchDrawable;
+
+import java.awt.Graphics2D;
+import java.awt.image.BufferedImage;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.ref.SoftReference;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Delegate implementing the native methods of android.graphics.NinePatch
+ *
+ * Through the layoutlib_create tool, the original native methods of NinePatch have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+public final class NinePatch_Delegate {
+
+ /**
+ * Cache map for {@link NinePatchChunk}.
+ * When the chunks are created they are serialized into a byte[], and both are put
+ * in the cache, using a {@link SoftReference} for the chunk. The default Java classes
+ * for {@link NinePatch} and {@link NinePatchDrawable} only reference to the byte[] data, and
+ * provide this for drawing.
+ * Using the cache map allows us to not have to deserialize the byte[] back into a
+ * {@link NinePatchChunk} every time a rendering is done.
+ */
+ private final static Map<byte[], SoftReference<NinePatchChunk>> sChunkCache =
+ new HashMap<byte[], SoftReference<NinePatchChunk>>();
+
+ // ---- Public Helper methods ----
+
+ /**
+ * Serializes the given chunk.
+ *
+ * @return the serialized data for the chunk.
+ */
+ public static byte[] serialize(NinePatchChunk chunk) {
+ // serialize the chunk to get a byte[]
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
+ ObjectOutputStream oos = null;
+ try {
+ oos = new ObjectOutputStream(baos);
+ oos.writeObject(chunk);
+ } catch (IOException e) {
+ Bridge.getLog().error(null, "Failed to serialize NinePatchChunk.", e, null /*data*/);
+ return null;
+ } finally {
+ if (oos != null) {
+ try {
+ oos.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+
+ // get the array and add it to the cache
+ byte[] array = baos.toByteArray();
+ sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
+ return array;
+ }
+
+ /**
+ * Returns a {@link NinePatchChunk} object for the given serialized representation.
+ *
+ * If the chunk is present in the cache then the object from the cache is returned, otherwise
+ * the array is deserialized into a {@link NinePatchChunk} object.
+ *
+ * @param array the serialized representation of the chunk.
+ * @return the NinePatchChunk or null if deserialization failed.
+ */
+ public static NinePatchChunk getChunk(byte[] array) {
+ SoftReference<NinePatchChunk> chunkRef = sChunkCache.get(array);
+ NinePatchChunk chunk = chunkRef.get();
+ if (chunk == null) {
+ ByteArrayInputStream bais = new ByteArrayInputStream(array);
+ ObjectInputStream ois = null;
+ try {
+ ois = new ObjectInputStream(bais);
+ chunk = (NinePatchChunk) ois.readObject();
+
+ // put back the chunk in the cache
+ if (chunk != null) {
+ sChunkCache.put(array, new SoftReference<NinePatchChunk>(chunk));
+ }
+ } catch (IOException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to deserialize NinePatchChunk content.", e, null /*data*/);
+ return null;
+ } catch (ClassNotFoundException e) {
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ "Failed to deserialize NinePatchChunk class.", e, null /*data*/);
+ return null;
+ } finally {
+ if (ois != null) {
+ try {
+ ois.close();
+ } catch (IOException e) {
+ }
+ }
+ }
+ }
+
+ return chunk;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isNinePatchChunk(byte[] chunk) {
+ NinePatchChunk chunkObject = getChunk(chunk);
+ if (chunkObject != null) {
+ return true;
+ }
+
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void validateNinePatchChunk(int bitmap, byte[] chunk) {
+ // the default JNI implementation only checks that the byte[] has the same
+ // size as the C struct it represent. Since we cannot do the same check (serialization
+ // will return different size depending on content), we do nothing.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance,
+ byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
+ draw(canvas_instance,
+ (int) loc.left, (int) loc.top, (int) loc.width(), (int) loc.height(),
+ bitmap_instance, c, paint_instance_or_null,
+ destDensity, srcDensity);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDraw(int canvas_instance, Rect loc, int bitmap_instance,
+ byte[] c, int paint_instance_or_null, int destDensity, int srcDensity) {
+ draw(canvas_instance,
+ loc.left, loc.top, loc.width(), loc.height(),
+ bitmap_instance, c, paint_instance_or_null,
+ destDensity, srcDensity);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeGetTransparentRegion(int bitmap, byte[] chunk, Rect location) {
+ return 0;
+ }
+
+ // ---- Private Helper methods ----
+
+ private static void draw(int canvas_instance,
+ final int left, final int top, final int right, final int bottom,
+ int bitmap_instance, byte[] c, int paint_instance_or_null,
+ final int destDensity, final int srcDensity) {
+ // get the delegate from the native int.
+ final Bitmap_Delegate bitmap_delegate = Bitmap_Delegate.getDelegate(bitmap_instance);
+ if (bitmap_delegate == null) {
+ return;
+ }
+
+ if (c == null) {
+ // not a 9-patch?
+ BufferedImage image = bitmap_delegate.getImage();
+ Canvas_Delegate.native_drawBitmap(canvas_instance, bitmap_instance,
+ new Rect(0, 0, image.getWidth(), image.getHeight()),
+ new Rect(left, top, right, bottom),
+ paint_instance_or_null, destDensity, srcDensity);
+ return;
+ }
+
+ final NinePatchChunk chunkObject = getChunk(c);
+ assert chunkObject != null;
+ if (chunkObject == null) {
+ return;
+ }
+
+ Canvas_Delegate canvas_delegate = Canvas_Delegate.getDelegate(canvas_instance);
+ if (canvas_delegate == null) {
+ return;
+ }
+
+ // this one can be null
+ Paint_Delegate paint_delegate = Paint_Delegate.getDelegate(paint_instance_or_null);
+
+ canvas_delegate.getSnapshot().draw(new GcSnapshot.Drawable() {
+ public void draw(Graphics2D graphics, Paint_Delegate paint) {
+ chunkObject.draw(bitmap_delegate.getImage(), graphics,
+ left, top, right - left, bottom - top, destDensity, srcDensity);
+ }
+ }, paint_delegate, true /*compositeOnly*/, false /*forceSrcMode*/);
+
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint.java b/tools/layoutlib/bridge/src/android/graphics/Paint.java
deleted file mode 100644
index d13b5fe..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Paint.java
+++ /dev/null
@@ -1,1211 +0,0 @@
-/*
- * Copyright (C) 2008 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 android.text.SpannableString;
-import android.text.SpannableStringBuilder;
-import android.text.SpannedString;
-import android.text.TextUtils;
-
-import java.awt.BasicStroke;
-import java.awt.Font;
-import java.awt.Toolkit;
-import java.awt.font.FontRenderContext;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Rectangle2D;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * A paint implementation overridden by the LayoutLib bridge.
- */
-public class Paint extends _Original_Paint {
-
- private int mColor = 0xFFFFFFFF;
- private float mStrokeWidth = 1.f;
- private float mTextSize = 20;
- private float mScaleX = 1;
- private float mSkewX = 0;
- private Align mAlign = Align.LEFT;
- private Style mStyle = Style.FILL;
- private float mStrokeMiter = 4.0f;
- private Cap mCap = Cap.BUTT;
- private Join mJoin = Join.MITER;
- private int mFlags = 0;
-
- /**
- * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
- */
- public static final class FontInfo {
- Font mFont;
- java.awt.FontMetrics mMetrics;
- }
-
- private List<FontInfo> mFonts;
- private final FontRenderContext mFontContext = new FontRenderContext(
- new AffineTransform(), true, true);
-
- public static final int ANTI_ALIAS_FLAG = _Original_Paint.ANTI_ALIAS_FLAG;
- public static final int FILTER_BITMAP_FLAG = _Original_Paint.FILTER_BITMAP_FLAG;
- public static final int DITHER_FLAG = _Original_Paint.DITHER_FLAG;
- public static final int UNDERLINE_TEXT_FLAG = _Original_Paint.UNDERLINE_TEXT_FLAG;
- public static final int STRIKE_THRU_TEXT_FLAG = _Original_Paint.STRIKE_THRU_TEXT_FLAG;
- public static final int FAKE_BOLD_TEXT_FLAG = _Original_Paint.FAKE_BOLD_TEXT_FLAG;
- public static final int LINEAR_TEXT_FLAG = _Original_Paint.LINEAR_TEXT_FLAG;
- public static final int SUBPIXEL_TEXT_FLAG = _Original_Paint.SUBPIXEL_TEXT_FLAG;
- public static final int DEV_KERN_TEXT_FLAG = _Original_Paint.DEV_KERN_TEXT_FLAG;
-
- public static class FontMetrics extends _Original_Paint.FontMetrics {
- }
-
- public static class FontMetricsInt extends _Original_Paint.FontMetricsInt {
- }
-
- /**
- * The Style specifies if the primitive being drawn is filled,
- * stroked, or both (in the same color). The default is FILL.
- */
- public enum Style {
- /**
- * Geometry and text drawn with this style will be filled, ignoring all
- * stroke-related settings in the paint.
- */
- FILL (0),
- /**
- * Geometry and text drawn with this style will be stroked, respecting
- * the stroke-related fields on the paint.
- */
- STROKE (1),
- /**
- * Geometry and text drawn with this style will be both filled and
- * stroked at the same time, respecting the stroke-related fields on
- * the paint.
- */
- FILL_AND_STROKE (2);
-
- Style(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- /**
- * The Cap specifies the treatment for the beginning and ending of
- * stroked lines and paths. The default is BUTT.
- */
- public enum Cap {
- /**
- * The stroke ends with the path, and does not project beyond it.
- */
- BUTT (0),
- /**
- * The stroke projects out as a square, with the center at the end
- * of the path.
- */
- ROUND (1),
- /**
- * The stroke projects out as a semicircle, with the center at the
- * end of the path.
- */
- SQUARE (2);
-
- private Cap(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
-
- /** custom for layoutlib */
- public int getJavaCap() {
- switch (this) {
- case BUTT:
- return BasicStroke.CAP_BUTT;
- case ROUND:
- return BasicStroke.CAP_ROUND;
- default:
- case SQUARE:
- return BasicStroke.CAP_SQUARE;
- }
- }
- }
-
- /**
- * The Join specifies the treatment where lines and curve segments
- * join on a stroked path. The default is MITER.
- */
- public enum Join {
- /**
- * The outer edges of a join meet at a sharp angle
- */
- MITER (0),
- /**
- * The outer edges of a join meet in a circular arc.
- */
- ROUND (1),
- /**
- * The outer edges of a join meet with a straight line
- */
- BEVEL (2);
-
- private Join(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
-
- /** custom for layoutlib */
- public int getJavaJoin() {
- switch (this) {
- default:
- case MITER:
- return BasicStroke.JOIN_MITER;
- case ROUND:
- return BasicStroke.JOIN_ROUND;
- case BEVEL:
- return BasicStroke.JOIN_BEVEL;
- }
- }
- }
-
- /**
- * Align specifies how drawText aligns its text relative to the
- * [x,y] coordinates. The default is LEFT.
- */
- public enum Align {
- /**
- * The text is drawn to the right of the x,y origin
- */
- LEFT (0),
- /**
- * The text is drawn centered horizontally on the x,y origin
- */
- CENTER (1),
- /**
- * The text is drawn to the left of the x,y origin
- */
- RIGHT (2);
-
- private Align(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- public Paint() {
- this(0);
- }
-
- /*
- * Do not remove or com.android.layoutlib.bridge.TestClassReplacement fails.
- */
- @Override
- public void finalize() { }
-
- public Paint(int flags) {
- setFlags(flags | DEFAULT_PAINT_FLAGS);
- initFont();
- }
-
- public Paint(Paint paint) {
- set(paint);
- initFont();
- }
-
- @Override
- public void reset() {
- super.reset();
- }
-
- /**
- * Returns the list of {@link Font} objects. The first item is the main font, the rest
- * are fall backs for characters not present in the main font.
- */
- public List<FontInfo> getFonts() {
- return mFonts;
- }
-
- private void initFont() {
- mTypeface = Typeface.DEFAULT;
- updateFontObject();
- }
-
- /**
- * Update the {@link Font} object from the typeface, text size and scaling
- */
- @SuppressWarnings("deprecation")
- private void updateFontObject() {
- if (mTypeface != null) {
- // Get the fonts from the TypeFace object.
- List<Font> fonts = mTypeface.getFonts();
-
- // create new font objects as well as FontMetrics, based on the current text size
- // and skew info.
- ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
- for (Font font : fonts) {
- FontInfo info = new FontInfo();
- info.mFont = font.deriveFont(mTextSize);
- if (mScaleX != 1.0 || mSkewX != 0) {
- // TODO: support skew
- info.mFont = info.mFont.deriveFont(new AffineTransform(
- mScaleX, mSkewX, 0, 0, 1, 0));
- }
- info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
-
- infoList.add(info);
- }
-
- mFonts = Collections.unmodifiableList(infoList);
- }
- }
-
- //----------------------------------------
-
- public void set(Paint src) {
- if (this != src) {
- mColor = src.mColor;
- mTextSize = src.mTextSize;
- mScaleX = src.mScaleX;
- mSkewX = src.mSkewX;
- mAlign = src.mAlign;
- mStyle = src.mStyle;
- mFlags = src.mFlags;
-
- updateFontObject();
-
- super.set(src);
- }
- }
-
- @Override
- public void setCompatibilityScaling(float factor) {
- super.setCompatibilityScaling(factor);
- }
-
- @Override
- public int getFlags() {
- return mFlags;
- }
-
- @Override
- public void setFlags(int flags) {
- mFlags = flags;
- }
-
- @Override
- public boolean isAntiAlias() {
- return super.isAntiAlias();
- }
-
- @Override
- public boolean isDither() {
- return super.isDither();
- }
-
- @Override
- public boolean isLinearText() {
- return super.isLinearText();
- }
-
- @Override
- public boolean isStrikeThruText() {
- return super.isStrikeThruText();
- }
-
- @Override
- public boolean isUnderlineText() {
- return super.isUnderlineText();
- }
-
- @Override
- public boolean isFakeBoldText() {
- return super.isFakeBoldText();
- }
-
- @Override
- public boolean isSubpixelText() {
- return super.isSubpixelText();
- }
-
- @Override
- public boolean isFilterBitmap() {
- return super.isFilterBitmap();
- }
-
- /**
- * Return the font's recommended interline spacing, given the Paint's
- * settings for typeface, textSize, etc. If metrics is not null, return the
- * fontmetric values in it.
- *
- * @param metrics If this object is not null, its fields are filled with
- * the appropriate values given the paint's text attributes.
- * @return the font's recommended interline spacing.
- */
- public float getFontMetrics(FontMetrics metrics) {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- if (metrics != null) {
- // Android expects negative ascent so we invert the value from Java.
- metrics.top = - javaMetrics.getMaxAscent();
- metrics.ascent = - javaMetrics.getAscent();
- metrics.descent = javaMetrics.getDescent();
- metrics.bottom = javaMetrics.getMaxDescent();
- metrics.leading = javaMetrics.getLeading();
- }
-
- return javaMetrics.getHeight();
- }
-
- return 0;
- }
-
- public int getFontMetricsInt(FontMetricsInt metrics) {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- if (metrics != null) {
- // Android expects negative ascent so we invert the value from Java.
- metrics.top = - javaMetrics.getMaxAscent();
- metrics.ascent = - javaMetrics.getAscent();
- metrics.descent = javaMetrics.getDescent();
- metrics.bottom = javaMetrics.getMaxDescent();
- metrics.leading = javaMetrics.getLeading();
- }
-
- return javaMetrics.getHeight();
- }
-
- return 0;
- }
-
- /**
- * Reimplemented to return Paint.FontMetrics instead of _Original_Paint.FontMetrics
- */
- public FontMetrics getFontMetrics() {
- FontMetrics fm = new FontMetrics();
- getFontMetrics(fm);
- return fm;
- }
-
- /**
- * Reimplemented to return Paint.FontMetricsInt instead of _Original_Paint.FontMetricsInt
- */
- public FontMetricsInt getFontMetricsInt() {
- FontMetricsInt fm = new FontMetricsInt();
- getFontMetricsInt(fm);
- return fm;
- }
-
-
-
- @Override
- public float getFontMetrics(_Original_Paint.FontMetrics metrics) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- @Override
- public int getFontMetricsInt(_Original_Paint.FontMetricsInt metrics) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- @Override
- public Typeface setTypeface(Typeface typeface) {
- if (typeface != null) {
- mTypeface = typeface;
- } else {
- mTypeface = Typeface.DEFAULT;
- }
-
- updateFontObject();
-
- return typeface;
- }
-
- @Override
- public Typeface getTypeface() {
- return super.getTypeface();
- }
-
- @Override
- public int getColor() {
- return mColor;
- }
-
- @Override
- public void setColor(int color) {
- mColor = color;
- }
-
- @Override
- public void setARGB(int a, int r, int g, int b) {
- super.setARGB(a, r, g, b);
- }
-
- @Override
- public void setAlpha(int alpha) {
- mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
- }
-
- @Override
- public int getAlpha() {
- return mColor >>> 24;
- }
-
- /**
- * Set or clear the shader object.
- * <p />
- * Pass null to clear any previous shader.
- * As a convenience, the parameter passed is also returned.
- *
- * @param shader May be null. the new shader to be installed in the paint
- * @return shader
- */
- @Override
- public Shader setShader(Shader shader) {
- return mShader = shader;
- }
-
- @Override
- public Shader getShader() {
- return super.getShader();
- }
-
- /**
- * Set or clear the paint's colorfilter, returning the parameter.
- *
- * @param filter May be null. The new filter to be installed in the paint
- * @return filter
- */
- @Override
- public ColorFilter setColorFilter(ColorFilter filter) {
- mColorFilter = filter;
- return filter;
- }
-
- @Override
- public ColorFilter getColorFilter() {
- return super.getColorFilter();
- }
-
- /**
- * Set or clear the xfermode object.
- * <p />
- * Pass null to clear any previous xfermode.
- * As a convenience, the parameter passed is also returned.
- *
- * @param xfermode May be null. The xfermode to be installed in the paint
- * @return xfermode
- */
- @Override
- public Xfermode setXfermode(Xfermode xfermode) {
- return mXfermode = xfermode;
- }
-
- @Override
- public Xfermode getXfermode() {
- return super.getXfermode();
- }
-
- @Override
- public Rasterizer setRasterizer(Rasterizer rasterizer) {
- mRasterizer = rasterizer;
- return rasterizer;
- }
-
- @Override
- public Rasterizer getRasterizer() {
- return super.getRasterizer();
- }
-
- @Override
- public void setShadowLayer(float radius, float dx, float dy, int color) {
- // TODO Auto-generated method stub
- }
-
- @Override
- public void clearShadowLayer() {
- super.clearShadowLayer();
- }
-
- public void setTextAlign(Align align) {
- mAlign = align;
- }
-
- @Override
- public void setTextAlign(android.graphics._Original_Paint.Align align) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public Align getTextAlign() {
- return mAlign;
- }
-
- public void setStyle(Style style) {
- mStyle = style;
- }
-
- @Override
- public void setStyle(android.graphics._Original_Paint.Style style) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public Style getStyle() {
- return mStyle;
- }
-
- @Override
- public void setDither(boolean dither) {
- mFlags |= dither ? DITHER_FLAG : ~DITHER_FLAG;
- }
-
- @Override
- public void setAntiAlias(boolean aa) {
- mFlags |= aa ? ANTI_ALIAS_FLAG : ~ANTI_ALIAS_FLAG;
- }
-
- @Override
- public void setFakeBoldText(boolean flag) {
- mFlags |= flag ? FAKE_BOLD_TEXT_FLAG : ~FAKE_BOLD_TEXT_FLAG;
- }
-
- @Override
- public void setLinearText(boolean flag) {
- mFlags |= flag ? LINEAR_TEXT_FLAG : ~LINEAR_TEXT_FLAG;
- }
-
- @Override
- public void setSubpixelText(boolean flag) {
- mFlags |= flag ? SUBPIXEL_TEXT_FLAG : ~SUBPIXEL_TEXT_FLAG;
- }
-
- @Override
- public void setUnderlineText(boolean flag) {
- mFlags |= flag ? UNDERLINE_TEXT_FLAG : ~UNDERLINE_TEXT_FLAG;
- }
-
- @Override
- public void setStrikeThruText(boolean flag) {
- mFlags |= flag ? STRIKE_THRU_TEXT_FLAG : ~STRIKE_THRU_TEXT_FLAG;
- }
-
- @Override
- public void setFilterBitmap(boolean flag) {
- mFlags |= flag ? FILTER_BITMAP_FLAG : ~FILTER_BITMAP_FLAG;
- }
-
- @Override
- public float getStrokeWidth() {
- return mStrokeWidth;
- }
-
- @Override
- public void setStrokeWidth(float width) {
- mStrokeWidth = width;
- }
-
- @Override
- public float getStrokeMiter() {
- return mStrokeMiter;
- }
-
- @Override
- public void setStrokeMiter(float miter) {
- mStrokeMiter = miter;
- }
-
- @Override
- public void setStrokeCap(android.graphics._Original_Paint.Cap cap) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public void setStrokeCap(Cap cap) {
- mCap = cap;
- }
-
- public Cap getStrokeCap() {
- return mCap;
- }
-
- @Override
- public void setStrokeJoin(android.graphics._Original_Paint.Join join) {
- throw new UnsupportedOperationException("CALL TO PARENT FORBIDDEN");
- }
-
- public void setStrokeJoin(Join join) {
- mJoin = join;
- }
-
- public Join getStrokeJoin() {
- return mJoin;
- }
-
- @Override
- public boolean getFillPath(Path src, Path dst) {
- return super.getFillPath(src, dst);
- }
-
- @Override
- public PathEffect setPathEffect(PathEffect effect) {
- mPathEffect = effect;
- return effect;
- }
-
- @Override
- public PathEffect getPathEffect() {
- return super.getPathEffect();
- }
-
- @Override
- public MaskFilter setMaskFilter(MaskFilter maskfilter) {
- mMaskFilter = maskfilter;
- return maskfilter;
- }
-
- @Override
- public MaskFilter getMaskFilter() {
- return super.getMaskFilter();
- }
-
- /**
- * Return the paint's text size.
- *
- * @return the paint's text size.
- */
- @Override
- public float getTextSize() {
- return mTextSize;
- }
-
- /**
- * Set the paint's text size. This value must be > 0
- *
- * @param textSize set the paint's text size.
- */
- @Override
- public void setTextSize(float textSize) {
- mTextSize = textSize;
-
- updateFontObject();
- }
-
- /**
- * Return the paint's horizontal scale factor for text. The default value
- * is 1.0.
- *
- * @return the paint's scale factor in X for drawing/measuring text
- */
- @Override
- public float getTextScaleX() {
- return mScaleX;
- }
-
- /**
- * Set the paint's horizontal scale factor for text. The default value
- * is 1.0. Values > 1.0 will stretch the text wider. Values < 1.0 will
- * stretch the text narrower.
- *
- * @param scaleX set the paint's scale in X for drawing/measuring text.
- */
- @Override
- public void setTextScaleX(float scaleX) {
- mScaleX = scaleX;
-
- updateFontObject();
- }
-
- /**
- * Return the paint's horizontal skew factor for text. The default value
- * is 0.
- *
- * @return the paint's skew factor in X for drawing text.
- */
- @Override
- public float getTextSkewX() {
- return mSkewX;
- }
-
- /**
- * Set the paint's horizontal skew factor for text. The default value
- * is 0. For approximating oblique text, use values around -0.25.
- *
- * @param skewX set the paint's skew factor in X for drawing text.
- */
- @Override
- public void setTextSkewX(float skewX) {
- mSkewX = skewX;
-
- updateFontObject();
- }
-
- @Override
- public float getFontSpacing() {
- return super.getFontSpacing();
- }
-
- /**
- * Return the distance above (negative) the baseline (ascent) based on the
- * current typeface and text size.
- *
- * @return the distance above (negative) the baseline (ascent) based on the
- * current typeface and text size.
- */
- @Override
- public float ascent() {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- // Android expects negative ascent so we invert the value from Java.
- return - javaMetrics.getAscent();
- }
-
- return 0;
- }
-
- /**
- * Return the distance below (positive) the baseline (descent) based on the
- * current typeface and text size.
- *
- * @return the distance below (positive) the baseline (descent) based on
- * the current typeface and text size.
- */
- @Override
- public float descent() {
- if (mFonts.size() > 0) {
- java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
- return javaMetrics.getDescent();
- }
-
- return 0;
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @param index The index of the first character to start measuring
- * @param count THe number of characters to measure, beginning with start
- * @return The width of the text
- */
- @Override
- public float measureText(char[] text, int index, int count) {
- // WARNING: the logic in this method is similar to Canvas.drawText.
- // Any change to this method should be reflected in Canvas.drawText
- if (mFonts.size() > 0) {
- FontInfo mainFont = mFonts.get(0);
- int i = index;
- int lastIndex = index + count;
- float total = 0f;
- while (i < lastIndex) {
- // always start with the main font.
- int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
- if (upTo == -1) {
- // shortcut to exit
- return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
- } else if (upTo > 0) {
- total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
- i = upTo;
- // don't call continue at this point. Since it is certain the main font
- // cannot display the font a index upTo (now ==i), we move on to the
- // fallback fonts directly.
- }
-
- // no char supported, attempt to read the next char(s) with the
- // fallback font. In this case we only test the first character
- // and then go back to test with the main font.
- // Special test for 2-char characters.
- boolean foundFont = false;
- for (int f = 1 ; f < mFonts.size() ; f++) {
- FontInfo fontInfo = mFonts.get(f);
-
- // need to check that the font can display the character. We test
- // differently if the char is a high surrogate.
- int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
- upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
- if (upTo == -1) {
- total += fontInfo.mMetrics.charsWidth(text, i, charCount);
- i += charCount;
- foundFont = true;
- break;
-
- }
- }
-
- // in case no font can display the char, measure it with the main font.
- if (foundFont == false) {
- int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
- total += mainFont.mMetrics.charsWidth(text, i, size);
- i += size;
- }
- }
- }
-
- return 0;
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @param start The index of the first character to start measuring
- * @param end 1 beyond the index of the last character to measure
- * @return The width of the text
- */
- @Override
- public float measureText(String text, int start, int end) {
- return measureText(text.toCharArray(), start, end - start);
- }
-
- /**
- * Return the width of the text.
- *
- * @param text The text to measure
- * @return The width of the text
- */
- @Override
- public float measureText(String text) {
- return measureText(text.toCharArray(), 0, text.length());
- }
-
- /*
- * re-implement to call SpannableStringBuilder.measureText with a Paint object
- * instead of an _Original_Paint
- */
- @Override
- public float measureText(CharSequence text, int start, int end) {
- if (text instanceof String) {
- return measureText((String)text, start, end);
- }
- if (text instanceof SpannedString ||
- text instanceof SpannableString) {
- return measureText(text.toString(), start, end);
- }
- if (text instanceof SpannableStringBuilder) {
- return ((SpannableStringBuilder)text).measureText(start, end, this);
- }
-
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- float result = measureText(buf, 0, end - start);
- TemporaryBuffer.recycle(buf);
- return result;
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param index The offset into text to begin measuring at
- * @param count The number of maximum number of entries to measure. If count
- * is negative, then the characters before index are measured
- * in reverse order. This allows for measuring the end of
- * string.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(count).
- */
- @Override
- public int breakText(char[] text, int index, int count,
- float maxWidth, float[] measuredWidth) {
- int inc = count > 0 ? 1 : -1;
-
- int measureIndex = 0;
- float measureAcc = 0;
- for (int i = index ; i != index + count ; i += inc, measureIndex++) {
- int start, end;
- if (i < index) {
- start = i;
- end = index;
- } else {
- start = index;
- end = i;
- }
-
- // measure from start to end
- float res = measureText(text, start, end - start + 1);
-
- if (measuredWidth != null) {
- measuredWidth[measureIndex] = res;
- }
-
- measureAcc += res;
- if (res > maxWidth) {
- // we should not return this char index, but since it's 0-based and we need
- // to return a count, we simply return measureIndex;
- return measureIndex;
- }
-
- }
-
- return measureIndex;
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param measureForwards If true, measure forwards, starting at index.
- * Otherwise, measure backwards, starting with the
- * last character in the string.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(count).
- */
- @Override
- public int breakText(String text, boolean measureForwards,
- float maxWidth, float[] measuredWidth) {
- return breakText(text,
- 0 /* start */, text.length() /* end */,
- measureForwards, maxWidth, measuredWidth);
- }
-
- /**
- * Measure the text, stopping early if the measured width exceeds maxWidth.
- * Return the number of chars that were measured, and if measuredWidth is
- * not null, return in it the actual width measured.
- *
- * @param text The text to measure
- * @param start The offset into text to begin measuring at
- * @param end The end of the text slice to measure.
- * @param measureForwards If true, measure forwards, starting at start.
- * Otherwise, measure backwards, starting with end.
- * @param maxWidth The maximum width to accumulate.
- * @param measuredWidth Optional. If not null, returns the actual width
- * measured.
- * @return The number of chars that were measured. Will always be <=
- * abs(end - start).
- */
- @Override
- public int breakText(CharSequence text, int start, int end, boolean measureForwards,
- float maxWidth, float[] measuredWidth) {
- char[] buf = new char[end - start];
- int result;
-
- TextUtils.getChars(text, start, end, buf, 0);
-
- if (measureForwards) {
- result = breakText(buf, 0, end - start, maxWidth, measuredWidth);
- } else {
- result = breakText(buf, 0, -(end - start), maxWidth, measuredWidth);
- }
-
- return result;
- }
-
- /**
- * Return the advance widths for the characters in the string.
- *
- * @param text The text to measure
- * @param index The index of the first char to to measure
- * @param count The number of chars starting with index to measure
- * @param widths array to receive the advance widths of the characters.
- * Must be at least a large as count.
- * @return the actual number of widths returned.
- */
- @Override
- public int getTextWidths(char[] text, int index, int count,
- float[] widths) {
- if (mFonts.size() > 0) {
- if ((index | count) < 0 || index + count > text.length
- || count > widths.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // FIXME: handle multi-char characters.
- // Need to figure out if the lengths of the width array takes into account
- // multi-char characters.
- for (int i = 0; i < count; i++) {
- char c = text[i + index];
- boolean found = false;
- for (FontInfo info : mFonts) {
- if (info.mFont.canDisplay(c)) {
- widths[i] = info.mMetrics.charWidth(c);
- found = true;
- break;
- }
- }
-
- if (found == false) {
- // we stop there.
- return i;
- }
- }
-
- return count;
- }
-
- return 0;
- }
-
- /**
- * Return the advance widths for the characters in the string.
- *
- * @param text The text to measure
- * @param start The index of the first char to to measure
- * @param end The end of the text slice to measure
- * @param widths array to receive the advance widths of the characters.
- * Must be at least a large as the text.
- * @return the number of unichars in the specified text.
- */
- @Override
- public int getTextWidths(String text, int start, int end, float[] widths) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (end - start > widths.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- return getTextWidths(text.toCharArray(), start, end - start, widths);
- }
-
- /*
- * re-implement to call SpannableStringBuilder.getTextWidths with a Paint object
- * instead of an _Original_Paint
- */
- @Override
- public int getTextWidths(CharSequence text, int start, int end, float[] widths) {
- if (text instanceof String) {
- return getTextWidths((String)text, start, end, widths);
- }
- if (text instanceof SpannedString || text instanceof SpannableString) {
- return getTextWidths(text.toString(), start, end, widths);
- }
- if (text instanceof SpannableStringBuilder) {
- return ((SpannableStringBuilder)text).getTextWidths(start, end, widths, this);
- }
-
- char[] buf = TemporaryBuffer.obtain(end - start);
- TextUtils.getChars(text, start, end, buf, 0);
- int result = getTextWidths(buf, 0, end - start, widths);
- TemporaryBuffer.recycle(buf);
- return result;
- }
-
- @Override
- public int getTextWidths(String text, float[] widths) {
- return super.getTextWidths(text, widths);
- }
-
- /**
- * Return the path (outline) for the specified text.
- * Note: just like Canvas.drawText, this will respect the Align setting in
- * the paint.
- *
- * @param text The text to retrieve the path from
- * @param index The index of the first character in text
- * @param count The number of characterss starting with index
- * @param x The x coordinate of the text's origin
- * @param y The y coordinate of the text's origin
- * @param path The path to receive the data describing the text. Must
- * be allocated by the caller.
- */
- @Override
- public void getTextPath(char[] text, int index, int count,
- float x, float y, Path path) {
-
- // TODO this is the ORIGINAL implementation. REPLACE AS NEEDED OR REMOVE
-
- if ((index | count) < 0 || index + count > text.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
-
- // TODO native_getTextPath(mNativePaint, text, index, count, x, y, path.ni());
-
- throw new UnsupportedOperationException("IMPLEMENT AS NEEDED");
- }
-
- /**
- * Return the path (outline) for the specified text.
- * Note: just like Canvas.drawText, this will respect the Align setting
- * in the paint.
- *
- * @param text The text to retrieve the path from
- * @param start The first character in the text
- * @param end 1 past the last charcter in the text
- * @param x The x coordinate of the text's origin
- * @param y The y coordinate of the text's origin
- * @param path The path to receive the data describing the text. Must
- * be allocated by the caller.
- */
- @Override
- public void getTextPath(String text, int start, int end,
- float x, float y, Path path) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
-
- getTextPath(text.toCharArray(), start, end - start, x, y, path);
- }
-
- /**
- * Return in bounds (allocated by the caller) the smallest rectangle that
- * encloses all of the characters, with an implied origin at (0,0).
- *
- * @param text String to measure and return its bounds
- * @param start Index of the first char in the string to measure
- * @param end 1 past the last char in the string measure
- * @param bounds Returns the unioned bounds of all the text. Must be
- * allocated by the caller.
- */
- @Override
- public void getTextBounds(String text, int start, int end, Rect bounds) {
- if ((start | end | (end - start) | (text.length() - end)) < 0) {
- throw new IndexOutOfBoundsException();
- }
- if (bounds == null) {
- throw new NullPointerException("need bounds Rect");
- }
-
- getTextBounds(text.toCharArray(), start, end - start, bounds);
- }
-
- /**
- * Return in bounds (allocated by the caller) the smallest rectangle that
- * encloses all of the characters, with an implied origin at (0,0).
- *
- * @param text Array of chars to measure and return their unioned bounds
- * @param index Index of the first char in the array to measure
- * @param count The number of chars, beginning at index, to measure
- * @param bounds Returns the unioned bounds of all the text. Must be
- * allocated by the caller.
- */
- @Override
- public void getTextBounds(char[] text, int index, int count, Rect bounds) {
- // FIXME
- if (mFonts.size() > 0) {
- if ((index | count) < 0 || index + count > text.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- if (bounds == null) {
- throw new NullPointerException("need bounds Rect");
- }
-
- FontInfo mainInfo = mFonts.get(0);
-
- Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count, mFontContext);
- bounds.set(0, 0, (int)rect.getWidth(), (int)rect.getHeight());
- }
- }
-
- public static void finalizer(int foo) {
- // pass
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
new file mode 100644
index 0000000..71d346a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PaintFlagsDrawFilter_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PaintFlagsDrawFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of PaintFlagsDrawFilter 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 PaintFlagsDrawFilter class.
+ *
+ * Because this extends {@link DrawFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the DrawFilter classes will be added to the manager owned by
+ * {@link DrawFilter_Delegate}.
+ *
+ * @see DrawFilter_Delegate
+ *
+ */
+public class PaintFlagsDrawFilter_Delegate extends DrawFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Paint Flags Draw Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor(int clearBits, int setBits) {
+ PaintFlagsDrawFilter_Delegate newDelegate = new PaintFlagsDrawFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
new file mode 100644
index 0000000..373f482
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -0,0 +1,1240 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Paint.FontMetrics;
+import android.graphics.Paint.FontMetricsInt;
+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;
+import java.awt.geom.Rectangle2D;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Paint
+ *
+ * Through the layoutlib_create tool, the original native methods of Paint 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 Paint class.
+ *
+ * @see DelegateManager
+ *
+ */
+public class Paint_Delegate {
+
+ /**
+ * Class associating a {@link Font} and it's {@link java.awt.FontMetrics}.
+ */
+ /*package*/ static final class FontInfo {
+ Font mFont;
+ java.awt.FontMetrics mMetrics;
+ }
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Paint_Delegate> sManager =
+ new DelegateManager<Paint_Delegate>(Paint_Delegate.class);
+
+ // ---- delegate helper data ----
+ private List<FontInfo> mFonts;
+ private final FontRenderContext mFontContext = new FontRenderContext(
+ new AffineTransform(), true, true);
+
+ // ---- delegate data ----
+ private int mFlags;
+ private int mColor;
+ private int mStyle;
+ private int mCap;
+ private int mJoin;
+ private int mTextAlign;
+ private Typeface_Delegate mTypeface;
+ private float mStrokeWidth;
+ private float mStrokeMiter;
+ private float mTextSize;
+ private float mTextScaleX;
+ private float mTextSkewX;
+
+ private Xfermode_Delegate mXfermode;
+ private ColorFilter_Delegate mColorFilter;
+ private Shader_Delegate mShader;
+ private PathEffect_Delegate mPathEffect;
+ private MaskFilter_Delegate mMaskFilter;
+ private Rasterizer_Delegate mRasterizer;
+
+
+ // ---- Public Helper methods ----
+
+ public static Paint_Delegate getDelegate(int native_paint) {
+ return sManager.getDelegate(native_paint);
+ }
+
+ /**
+ * Returns the list of {@link Font} objects. The first item is the main font, the rest
+ * are fall backs for characters not present in the main font.
+ */
+ public List<FontInfo> getFonts() {
+ return mFonts;
+ }
+
+ public boolean isAntiAliased() {
+ return (mFlags & Paint.ANTI_ALIAS_FLAG) != 0;
+ }
+
+ public boolean isFilterBitmap() {
+ return (mFlags & Paint.FILTER_BITMAP_FLAG) != 0;
+ }
+
+ public int getStyle() {
+ return mStyle;
+ }
+
+ public int getColor() {
+ return mColor;
+ }
+
+ public int getAlpha() {
+ return mColor >>> 24;
+ }
+
+ public void setAlpha(int alpha) {
+ mColor = (alpha << 24) | (mColor & 0x00FFFFFF);
+ }
+
+ public int getTextAlign() {
+ return mTextAlign;
+ }
+
+ public float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ /**
+ * returns the value of stroke miter needed by the java api.
+ */
+ public float getJavaStrokeMiter() {
+ float miter = mStrokeMiter * mStrokeWidth;
+ if (miter < 1.f) {
+ miter = 1.f;
+ }
+ return miter;
+ }
+
+ public int getJavaCap() {
+ switch (Paint.sCapArray[mCap]) {
+ case BUTT:
+ return BasicStroke.CAP_BUTT;
+ case ROUND:
+ return BasicStroke.CAP_ROUND;
+ default:
+ case SQUARE:
+ return BasicStroke.CAP_SQUARE;
+ }
+ }
+
+ public int getJavaJoin() {
+ switch (Paint.sJoinArray[mJoin]) {
+ default:
+ case MITER:
+ return BasicStroke.JOIN_MITER;
+ case ROUND:
+ return BasicStroke.JOIN_ROUND;
+ case BEVEL:
+ return BasicStroke.JOIN_BEVEL;
+ }
+ }
+
+ public Stroke getJavaStroke() {
+ if (mPathEffect != null) {
+ if (mPathEffect.isSupported()) {
+ Stroke stroke = mPathEffect.getStroke(this);
+ assert stroke != null;
+ if (stroke != null) {
+ return stroke;
+ }
+ } else {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_PATHEFFECT,
+ mPathEffect.getSupportMessage(),
+ null, null /*data*/);
+ }
+ }
+
+ // 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
+ *
+ * @return the delegate or null.
+ */
+ public Xfermode_Delegate getXfermode() {
+ return mXfermode;
+ }
+
+ /**
+ * Returns the {@link ColorFilter} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public ColorFilter_Delegate getColorFilter() {
+ return mColorFilter;
+ }
+
+ /**
+ * Returns the {@link Shader} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public Shader_Delegate getShader() {
+ return mShader;
+ }
+
+ /**
+ * Returns the {@link MaskFilter} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public MaskFilter_Delegate getMaskFilter() {
+ return mMaskFilter;
+ }
+
+ /**
+ * Returns the {@link Rasterizer} delegate or null if none have been set
+ *
+ * @return the delegate or null.
+ */
+ public Rasterizer_Delegate getRasterizer() {
+ return mRasterizer;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int getFlags(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mFlags;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setFlags(Paint thisPaint, int flags) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mFlags = flags;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setFilterBitmap(Paint thisPaint, boolean filter) {
+ setFlag(thisPaint, Paint.FILTER_BITMAP_FLAG, filter);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setAntiAlias(Paint thisPaint, boolean aa) {
+ setFlag(thisPaint, Paint.ANTI_ALIAS_FLAG, aa);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setSubpixelText(Paint thisPaint, boolean subpixelText) {
+ setFlag(thisPaint, Paint.SUBPIXEL_TEXT_FLAG, subpixelText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setUnderlineText(Paint thisPaint, boolean underlineText) {
+ setFlag(thisPaint, Paint.UNDERLINE_TEXT_FLAG, underlineText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setStrikeThruText(Paint thisPaint, boolean strikeThruText) {
+ setFlag(thisPaint, Paint.STRIKE_THRU_TEXT_FLAG, strikeThruText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setFakeBoldText(Paint thisPaint, boolean fakeBoldText) {
+ setFlag(thisPaint, Paint.FAKE_BOLD_TEXT_FLAG, fakeBoldText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setDither(Paint thisPaint, boolean dither) {
+ setFlag(thisPaint, Paint.DITHER_FLAG, dither);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setLinearText(Paint thisPaint, boolean linearText) {
+ setFlag(thisPaint, Paint.LINEAR_TEXT_FLAG, linearText);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getColor(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mColor;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setColor(Paint thisPaint, int color) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mColor = color;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getAlpha(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.getAlpha();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setAlpha(Paint thisPaint, int a) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.setAlpha(a);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getStrokeWidth(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mStrokeWidth;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setStrokeWidth(Paint thisPaint, float width) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mStrokeWidth = width;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getStrokeMiter(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mStrokeMiter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setStrokeMiter(Paint thisPaint, float miter) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mStrokeMiter = miter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nSetShadowLayer(Paint thisPaint, float radius, float dx, float dy,
+ int color) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.setShadowLayer is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getTextSize(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mTextSize;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setTextSize(Paint thisPaint, float textSize) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextSize = textSize;
+ delegate.updateFontObject();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getTextScaleX(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mTextScaleX;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setTextScaleX(Paint thisPaint, float scaleX) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextScaleX = scaleX;
+ delegate.updateFontObject();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getTextSkewX(Paint thisPaint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 1.f;
+ }
+
+ return delegate.mTextSkewX;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setTextSkewX(Paint thisPaint, float skewX) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextSkewX = skewX;
+ delegate.updateFontObject();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float ascent(Paint thisPaint) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ // Android expects negative ascent so we invert the value from Java.
+ return - javaMetrics.getAscent();
+ }
+
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float descent(Paint thisPaint) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ return javaMetrics.getDescent();
+ }
+
+ return 0;
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float getFontMetrics(Paint thisPaint, FontMetrics metrics) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.getFontMetrics(metrics);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int getFontMetricsInt(Paint thisPaint, FontMetricsInt fmi) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = delegate.mFonts.get(0).mMetrics;
+ if (fmi != null) {
+ // Android expects negative ascent so we invert the value from Java.
+ fmi.top = - javaMetrics.getMaxAscent();
+ fmi.ascent = - javaMetrics.getAscent();
+ fmi.descent = javaMetrics.getDescent();
+ fmi.bottom = javaMetrics.getMaxDescent();
+ fmi.leading = javaMetrics.getLeading();
+ }
+
+ return javaMetrics.getHeight();
+ }
+
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_measureText(Paint thisPaint, char[] text, int index,
+ int count) {
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.measureText(text, index, count);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_measureText(Paint thisPaint, String text, int start, int end) {
+ return native_measureText(thisPaint, text.toCharArray(), start, end - start);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_measureText(Paint thisPaint, String text) {
+ return native_measureText(thisPaint, text.toCharArray(), 0, text.length());
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_breakText(Paint thisPaint, char[] text, int index, int count,
+ float maxWidth, float[] measuredWidth) {
+
+ // get the delegate
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ int inc = count > 0 ? 1 : -1;
+
+ int measureIndex = 0;
+ float measureAcc = 0;
+ for (int i = index; i != index + count; i += inc, measureIndex++) {
+ int start, end;
+ if (i < index) {
+ start = i;
+ end = index;
+ } else {
+ start = index;
+ end = i;
+ }
+
+ // measure from start to end
+ float res = delegate.measureText(text, start, end - start + 1);
+
+ if (measuredWidth != null) {
+ measuredWidth[measureIndex] = res;
+ }
+
+ measureAcc += res;
+ if (res > maxWidth) {
+ // we should not return this char index, but since it's 0-based
+ // and we need to return a count, we simply return measureIndex;
+ return measureIndex;
+ }
+
+ }
+
+ return measureIndex;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_breakText(Paint thisPaint, String text, boolean measureForwards,
+ float maxWidth, float[] measuredWidth) {
+ return native_breakText(thisPaint, text.toCharArray(), 0, text.length(), maxWidth,
+ measuredWidth);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_init() {
+ Paint_Delegate newDelegate = new Paint_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_initWithPaint(int paint) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(paint);
+ if (delegate == null) {
+ return 0;
+ }
+
+ Paint_Delegate newDelegate = new Paint_Delegate(delegate);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_reset(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.reset();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_set(int native_dst, int native_src) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate_dst = sManager.getDelegate(native_dst);
+ if (delegate_dst == null) {
+ return;
+ }
+
+ // get the delegate from the native int.
+ Paint_Delegate delegate_src = sManager.getDelegate(native_src);
+ if (delegate_src == null) {
+ return;
+ }
+
+ delegate_dst.set(delegate_src);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getStyle(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mStyle;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setStyle(int native_object, int style) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mStyle = style;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getStrokeCap(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mCap;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setStrokeCap(int native_object, int cap) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mCap = cap;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getStrokeJoin(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mJoin;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setStrokeJoin(int native_object, int join) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mJoin = join;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_getFillPath(int native_object, int src, int dst) {
+ 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;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setShader(int native_object, int shader) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return shader;
+ }
+
+ delegate.mShader = Shader_Delegate.getDelegate(shader);
+
+ return shader;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setColorFilter(int native_object, int filter) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return filter;
+ }
+
+ delegate.mColorFilter = ColorFilter_Delegate.getDelegate(filter);;
+
+ // since none of those are supported, display a fidelity warning right away
+ if (delegate.mColorFilter != null && delegate.mColorFilter.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_COLORFILTER,
+ delegate.mColorFilter.getSupportMessage(), null, null /*data*/);
+ }
+
+ return filter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setXfermode(int native_object, int xfermode) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return xfermode;
+ }
+
+ delegate.mXfermode = Xfermode_Delegate.getDelegate(xfermode);
+
+ return xfermode;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setPathEffect(int native_object, int effect) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return effect;
+ }
+
+ delegate.mPathEffect = PathEffect_Delegate.getDelegate(effect);
+
+ return effect;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setMaskFilter(int native_object, int maskfilter) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return maskfilter;
+ }
+
+ delegate.mMaskFilter = MaskFilter_Delegate.getDelegate(maskfilter);
+
+ // since none of those are supported, display a fidelity warning right away
+ if (delegate.mMaskFilter != null && delegate.mMaskFilter.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MASKFILTER,
+ delegate.mMaskFilter.getSupportMessage(), null, null /*data*/);
+ }
+
+ return maskfilter;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setTypeface(int native_object, int typeface) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
+ delegate.updateFontObject();
+ return typeface;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_setRasterizer(int native_object, int rasterizer) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return rasterizer;
+ }
+
+ delegate.mRasterizer = Rasterizer_Delegate.getDelegate(rasterizer);
+
+ // since none of those are supported, display a fidelity warning right away
+ if (delegate.mRasterizer != null && delegate.mRasterizer.isSupported() == false) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_RASTERIZER,
+ delegate.mRasterizer.getSupportMessage(), null, null /*data*/);
+ }
+
+ return rasterizer;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextAlign(int native_object) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mTextAlign;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setTextAlign(int native_object, int align) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return;
+ }
+
+ delegate.mTextAlign = align;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_getFontMetrics(int native_paint, FontMetrics metrics) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_paint);
+ if (delegate == null) {
+ return 0.f;
+ }
+
+ return delegate.getFontMetrics(metrics);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextWidths(int native_object, char[] text, int index,
+ int count, float[] widths) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ // FIXME: handle multi-char characters (see measureText)
+ float totalAdvance = 0;
+ for (int i = 0; i < count; i++) {
+ char c = text[i + index];
+ boolean found = false;
+ for (FontInfo info : delegate.mFonts) {
+ if (info.mFont.canDisplay(c)) {
+ float adv = info.mMetrics.charWidth(c);
+ totalAdvance += adv;
+ if (widths != null) {
+ widths[i] = adv;
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ // no advance for this char.
+ if (widths != null) {
+ widths[i] = 0.f;
+ }
+ }
+ }
+
+ return (int) totalAdvance;
+ }
+
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextWidths(int native_object, String text, int start,
+ int end, float[] widths) {
+ return native_getTextWidths(native_object, text.toCharArray(), start, end - start, widths);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_getTextRunAdvances(int native_object,
+ char[] text, int index, int count, int contextIndex, int contextCount,
+ int flags, float[] advances, int advancesIndex) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(native_object);
+ if (delegate == null) {
+ return 0.f;
+ }
+
+ if (delegate.mFonts.size() > 0) {
+ // FIXME: handle multi-char characters (see measureText)
+ float totalAdvance = 0;
+ for (int i = 0; i < count; i++) {
+ char c = text[i + index];
+ boolean found = false;
+ for (FontInfo info : delegate.mFonts) {
+ if (info.mFont.canDisplay(c)) {
+ float adv = info.mMetrics.charWidth(c);
+ totalAdvance += adv;
+ if (advances != null) {
+ advances[i] = adv;
+ }
+
+ found = true;
+ break;
+ }
+ }
+
+ if (found == false) {
+ // no advance for this char.
+ if (advances != null) {
+ advances[i] = 0.f;
+ }
+ }
+ }
+
+ return totalAdvance;
+ }
+
+ return 0;
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static float native_getTextRunAdvances(int native_object,
+ String text, int start, int end, int contextStart, int contextEnd,
+ int flags, float[] advances, int advancesIndex) {
+ // FIXME: support contextStart, contextEnd and direction flag
+ int count = end - start;
+ char[] buffer = TemporaryBuffer.obtain(count);
+ TextUtils.getChars(text, start, end, buffer, 0);
+
+ return native_getTextRunAdvances(native_object, buffer, 0, count, contextStart,
+ contextEnd - contextStart, flags, advances, advancesIndex);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, char[] text,
+ int contextStart, int contextLength, int flags, int offset, int cursorOpt) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getTextRunCursor(Paint thisPaint, int native_object, String text,
+ int contextStart, int contextEnd, int flags, int offset, int cursorOpt) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextRunCursor is not supported.", null, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
+ char[] text, int index, int count, float x, float y, int path) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_getTextPath(int native_object, int bidiFlags,
+ String text, int start, int end, float x, float y, int path) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Paint.getTextPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeGetStringBounds(int nativePaint, String text, int start,
+ int end, Rect bounds) {
+ nativeGetCharArrayBounds(nativePaint, text.toCharArray(), start, end - start, bounds);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeGetCharArrayBounds(int nativePaint, char[] text, int index,
+ int count, Rect bounds) {
+
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(nativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ // FIXME should test if the main font can display all those characters.
+ // See MeasureText
+ if (delegate.mFonts.size() > 0) {
+ FontInfo mainInfo = delegate.mFonts.get(0);
+
+ Rectangle2D rect = mainInfo.mFont.getStringBounds(text, index, index + count,
+ delegate.mFontContext);
+ bounds.set(0, 0, (int) rect.getWidth(), (int) rect.getHeight());
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int nativePaint) {
+ sManager.removeJavaReferenceFor(nativePaint);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /*package*/ Paint_Delegate() {
+ reset();
+ }
+
+ private Paint_Delegate(Paint_Delegate paint) {
+ set(paint);
+ }
+
+ private void set(Paint_Delegate paint) {
+ mFlags = paint.mFlags;
+ mColor = paint.mColor;
+ mStyle = paint.mStyle;
+ mCap = paint.mCap;
+ mJoin = paint.mJoin;
+ mTextAlign = paint.mTextAlign;
+ mTypeface = paint.mTypeface;
+ mStrokeWidth = paint.mStrokeWidth;
+ mStrokeMiter = paint.mStrokeMiter;
+ mTextSize = paint.mTextSize;
+ mTextScaleX = paint.mTextScaleX;
+ mTextSkewX = paint.mTextSkewX;
+ mXfermode = paint.mXfermode;
+ mColorFilter = paint.mColorFilter;
+ mShader = paint.mShader;
+ mPathEffect = paint.mPathEffect;
+ mMaskFilter = paint.mMaskFilter;
+ mRasterizer = paint.mRasterizer;
+ updateFontObject();
+ }
+
+ private void reset() {
+ mFlags = Paint.DEFAULT_PAINT_FLAGS;
+ mColor = 0xFF000000;
+ mStyle = Paint.Style.FILL.nativeInt;
+ mCap = Paint.Cap.BUTT.nativeInt;
+ mJoin = Paint.Join.MITER.nativeInt;
+ mTextAlign = 0;
+ mTypeface = Typeface_Delegate.getDelegate(Typeface.sDefaults[0].native_instance);
+ mStrokeWidth = 1.f;
+ mStrokeMiter = 4.f;
+ mTextSize = 20.f;
+ mTextScaleX = 1.f;
+ mTextSkewX = 0.f;
+ mXfermode = null;
+ mColorFilter = null;
+ mShader = null;
+ mPathEffect = null;
+ mMaskFilter = null;
+ mRasterizer = null;
+ updateFontObject();
+ }
+
+ /**
+ * Update the {@link Font} object from the typeface, text size and scaling
+ */
+ @SuppressWarnings("deprecation")
+ private void updateFontObject() {
+ if (mTypeface != null) {
+ // Get the fonts from the TypeFace object.
+ List<Font> fonts = mTypeface.getFonts();
+
+ // create new font objects as well as FontMetrics, based on the current text size
+ // and skew info.
+ ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
+ for (Font font : fonts) {
+ FontInfo info = new FontInfo();
+ info.mFont = font.deriveFont(mTextSize);
+ if (mTextScaleX != 1.0 || mTextSkewX != 0) {
+ // TODO: support skew
+ info.mFont = info.mFont.deriveFont(new AffineTransform(
+ mTextScaleX, mTextSkewX, 0, 0, 1, 0));
+ }
+ info.mMetrics = Toolkit.getDefaultToolkit().getFontMetrics(info.mFont);
+
+ infoList.add(info);
+ }
+
+ mFonts = Collections.unmodifiableList(infoList);
+ }
+ }
+
+ /*package*/ float measureText(char[] text, int index, int count) {
+
+ // WARNING: the logic in this method is similar to Canvas_Delegate.native_drawText
+ // Any change to this method should be reflected there as well
+
+ if (mFonts.size() > 0) {
+ FontInfo mainFont = mFonts.get(0);
+ int i = index;
+ int lastIndex = index + count;
+ float total = 0f;
+ while (i < lastIndex) {
+ // always start with the main font.
+ int upTo = mainFont.mFont.canDisplayUpTo(text, i, lastIndex);
+ if (upTo == -1) {
+ // shortcut to exit
+ return total + mainFont.mMetrics.charsWidth(text, i, lastIndex - i);
+ } else if (upTo > 0) {
+ total += mainFont.mMetrics.charsWidth(text, i, upTo - i);
+ i = upTo;
+ // don't call continue at this point. Since it is certain the main font
+ // cannot display the font a index upTo (now ==i), we move on to the
+ // fallback fonts directly.
+ }
+
+ // no char supported, attempt to read the next char(s) with the
+ // fallback font. In this case we only test the first character
+ // and then go back to test with the main font.
+ // Special test for 2-char characters.
+ boolean foundFont = false;
+ for (int f = 1 ; f < mFonts.size() ; f++) {
+ FontInfo fontInfo = mFonts.get(f);
+
+ // need to check that the font can display the character. We test
+ // differently if the char is a high surrogate.
+ int charCount = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ upTo = fontInfo.mFont.canDisplayUpTo(text, i, i + charCount);
+ if (upTo == -1) {
+ total += fontInfo.mMetrics.charsWidth(text, i, charCount);
+ i += charCount;
+ foundFont = true;
+ break;
+
+ }
+ }
+
+ // in case no font can display the char, measure it with the main font.
+ if (foundFont == false) {
+ int size = Character.isHighSurrogate(text[i]) ? 2 : 1;
+ total += mainFont.mMetrics.charsWidth(text, i, size);
+ i += size;
+ }
+ }
+
+ return total;
+ }
+
+ return 0;
+ }
+
+ private float getFontMetrics(FontMetrics metrics) {
+ if (mFonts.size() > 0) {
+ java.awt.FontMetrics javaMetrics = mFonts.get(0).mMetrics;
+ if (metrics != null) {
+ // Android expects negative ascent so we invert the value from Java.
+ metrics.top = - javaMetrics.getMaxAscent();
+ metrics.ascent = - javaMetrics.getAscent();
+ metrics.descent = javaMetrics.getDescent();
+ metrics.bottom = javaMetrics.getMaxDescent();
+ metrics.leading = javaMetrics.getLeading();
+ }
+
+ return javaMetrics.getHeight();
+ }
+
+ return 0;
+ }
+
+
+
+ private static void setFlag(Paint thisPaint, int flagMask, boolean flagValue) {
+ // get the delegate from the native int.
+ Paint_Delegate delegate = sManager.getDelegate(thisPaint.mNativePaint);
+ if (delegate == null) {
+ return;
+ }
+
+ if (flagValue) {
+ delegate.mFlags |= flagMask;
+ } else {
+ delegate.mFlags &= ~flagMask;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path.java b/tools/layoutlib/bridge/src/android/graphics/Path.java
deleted file mode 100644
index 12d2cde..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Path.java
+++ /dev/null
@@ -1,611 +0,0 @@
-/*
- * Copyright (C) 2006 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 java.awt.Shape;
-import java.awt.geom.AffineTransform;
-import java.awt.geom.Ellipse2D;
-import java.awt.geom.GeneralPath;
-import java.awt.geom.PathIterator;
-import java.awt.geom.Rectangle2D;
-
-/**
- * The Path class encapsulates compound (multiple contour) geometric paths
- * consisting of straight line segments, quadratic curves, and cubic curves.
- * It can be drawn with canvas.drawPath(path, paint), either filled or stroked
- * (based on the paint's Style), or it can be used for clipping or to draw
- * text on a path.
- */
-public class Path {
-
- private FillType mFillType = FillType.WINDING;
- private GeneralPath mPath = new GeneralPath();
-
- private float mLastX = 0;
- private float mLastY = 0;
-
- //---------- Custom methods ----------
-
- public Shape getAwtShape() {
- return mPath;
- }
-
- //----------
-
- /**
- * Create an empty path
- */
- public Path() {
- }
-
- /**
- * Create a new path, copying the contents from the src path.
- *
- * @param src The path to copy from when initializing the new path
- */
- public Path(Path src) {
- mPath.append(src.mPath, false /* connect */);
- }
-
- /**
- * Clear any lines and curves from the path, making it empty.
- * This does NOT change the fill-type setting.
- */
- public void reset() {
- mPath = new GeneralPath();
- }
-
- /**
- * Rewinds the path: clears any lines and curves from the path but
- * keeps the internal data structure for faster reuse.
- */
- public void rewind() {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /** Replace the contents of this with the contents of src.
- */
- public void set(Path src) {
- mPath.append(src.mPath, false /* connect */);
- }
-
- /** Enum for the ways a path may be filled
- */
- public enum FillType {
- // these must match the values in SkPath.h
- WINDING (GeneralPath.WIND_NON_ZERO, false),
- EVEN_ODD (GeneralPath.WIND_EVEN_ODD, false),
- INVERSE_WINDING (GeneralPath.WIND_NON_ZERO, true),
- INVERSE_EVEN_ODD(GeneralPath.WIND_EVEN_ODD, true);
-
- FillType(int rule, boolean inverse) {
- this.rule = rule;
- this.inverse = inverse;
- }
-
- final int rule;
- final boolean inverse;
- }
-
- /**
- * Return the path's fill type. This defines how "inside" is
- * computed. The default value is WINDING.
- *
- * @return the path's fill type
- */
- public FillType getFillType() {
- return mFillType;
- }
-
- /**
- * Set the path's fill type. This defines how "inside" is computed.
- *
- * @param ft The new fill type for this path
- */
- public void setFillType(FillType ft) {
- mFillType = ft;
- mPath.setWindingRule(ft.rule);
- }
-
- /**
- * Returns true if the filltype is one of the INVERSE variants
- *
- * @return true if the filltype is one of the INVERSE variants
- */
- public boolean isInverseFillType() {
- return mFillType.inverse;
- }
-
- /**
- * Toggles the INVERSE state of the filltype
- */
- public void toggleInverseFillType() {
- switch (mFillType) {
- case WINDING:
- mFillType = FillType.INVERSE_WINDING;
- break;
- case EVEN_ODD:
- mFillType = FillType.INVERSE_EVEN_ODD;
- break;
- case INVERSE_WINDING:
- mFillType = FillType.WINDING;
- break;
- case INVERSE_EVEN_ODD:
- mFillType = FillType.EVEN_ODD;
- break;
- }
- }
-
- /**
- * Returns true if the path is empty (contains no lines or curves)
- *
- * @return true if the path is empty (contains no lines or curves)
- */
- public boolean isEmpty() {
- return mPath.getCurrentPoint() == null;
- }
-
- /**
- * Returns true if the path specifies a rectangle. If so, and if rect is
- * not null, set rect to the bounds of the path. If the path does not
- * specify a rectangle, return false and ignore rect.
- *
- * @param rect If not null, returns the bounds of the path if it specifies
- * a rectangle
- * @return true if the path specifies a rectangle
- */
- public boolean isRect(RectF rect) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Compute the bounds of the path, and write the answer into bounds. If the
- * path contains 0 or 1 points, the bounds is set to (0,0,0,0)
- *
- * @param bounds Returns the computed bounds of the path
- * @param exact If true, return the exact (but slower) bounds, else return
- * just the bounds of all control points
- */
- public void computeBounds(RectF bounds, boolean exact) {
- Rectangle2D rect = mPath.getBounds2D();
- bounds.left = (float)rect.getMinX();
- bounds.right = (float)rect.getMaxX();
- bounds.top = (float)rect.getMinY();
- bounds.bottom = (float)rect.getMaxY();
- }
-
- /**
- * Hint to the path to prepare for adding more points. This can allow the
- * path to more efficiently allocate its storage.
- *
- * @param extraPtCount The number of extra points that may be added to this
- * path
- */
- public void incReserve(int extraPtCount) {
- // pass
- }
-
- /**
- * Set the beginning of the next contour to the point (x,y).
- *
- * @param x The x-coordinate of the start of a new contour
- * @param y The y-coordinate of the start of a new contour
- */
- public void moveTo(float x, float y) {
- mPath.moveTo(mLastX = x, mLastY = y);
- }
-
- /**
- * Set the beginning of the next contour relative to the last point on the
- * previous contour. If there is no previous contour, this is treated the
- * same as moveTo().
- *
- * @param dx The amount to add to the x-coordinate of the end of the
- * previous contour, to specify the start of a new contour
- * @param dy The amount to add to the y-coordinate of the end of the
- * previous contour, to specify the start of a new contour
- */
- public void rMoveTo(float dx, float dy) {
- dx += mLastX;
- dy += mLastY;
- mPath.moveTo(mLastX = dx, mLastY = dy);
- }
-
- /**
- * Add a line from the last point to the specified point (x,y).
- * If no moveTo() call has been made for this contour, the first point is
- * automatically set to (0,0).
- *
- * @param x The x-coordinate of the end of a line
- * @param y The y-coordinate of the end of a line
- */
- public void lineTo(float x, float y) {
- mPath.lineTo(mLastX = x, mLastY = y);
- }
-
- /**
- * Same as lineTo, but the coordinates are considered relative to the last
- * point on this contour. If there is no previous point, then a moveTo(0,0)
- * is inserted automatically.
- *
- * @param dx The amount to add to the x-coordinate of the previous point on
- * this contour, to specify a line
- * @param dy The amount to add to the y-coordinate of the previous point on
- * this contour, to specify a line
- */
- public void rLineTo(float dx, float dy) {
- if (isEmpty()) {
- mPath.moveTo(mLastX = 0, mLastY = 0);
- }
- dx += mLastX;
- dy += mLastY;
- mPath.lineTo(mLastX = dx, mLastY = dy);
- }
-
- /**
- * Add a quadratic bezier from the last point, approaching control point
- * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
- * this contour, the first point is automatically set to (0,0).
- *
- * @param x1 The x-coordinate of the control point on a quadratic curve
- * @param y1 The y-coordinate of the control point on a quadratic curve
- * @param x2 The x-coordinate of the end point on a quadratic curve
- * @param y2 The y-coordinate of the end point on a quadratic curve
- */
- public void quadTo(float x1, float y1, float x2, float y2) {
- mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
- }
-
- /**
- * Same as quadTo, but the coordinates are considered relative to the last
- * point on this contour. If there is no previous point, then a moveTo(0,0)
- * is inserted automatically.
- *
- * @param dx1 The amount to add to the x-coordinate of the last point on
- * this contour, for the control point of a quadratic curve
- * @param dy1 The amount to add to the y-coordinate of the last point on
- * this contour, for the control point of a quadratic curve
- * @param dx2 The amount to add to the x-coordinate of the last point on
- * this contour, for the end point of a quadratic curve
- * @param dy2 The amount to add to the y-coordinate of the last point on
- * this contour, for the end point of a quadratic curve
- */
- public void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
- if (isEmpty()) {
- mPath.moveTo(mLastX = 0, mLastY = 0);
- }
- dx1 += mLastX;
- dy1 += mLastY;
- dx2 += mLastX;
- dy2 += mLastY;
- mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2);
- }
-
- /**
- * Add a cubic bezier from the last point, approaching control points
- * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
- * made for this contour, the first point is automatically set to (0,0).
- *
- * @param x1 The x-coordinate of the 1st control point on a cubic curve
- * @param y1 The y-coordinate of the 1st control point on a cubic curve
- * @param x2 The x-coordinate of the 2nd control point on a cubic curve
- * @param y2 The y-coordinate of the 2nd control point on a cubic curve
- * @param x3 The x-coordinate of the end point on a cubic curve
- * @param y3 The y-coordinate of the end point on a cubic curve
- */
- public void cubicTo(float x1, float y1, float x2, float y2,
- float x3, float y3) {
- mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
- }
-
- /**
- * Same as cubicTo, but the coordinates are considered relative to the
- * current point on this contour. If there is no previous point, then a
- * moveTo(0,0) is inserted automatically.
- */
- public void rCubicTo(float dx1, float dy1, float dx2, float dy2,
- float dx3, float dy3) {
- if (isEmpty()) {
- mPath.moveTo(mLastX = 0, mLastY = 0);
- }
- dx1 += mLastX;
- dy1 += mLastY;
- dx2 += mLastX;
- dy2 += mLastY;
- dx3 += mLastX;
- dy3 += mLastY;
- mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3);
- }
-
- /**
- * Append the specified arc to the path as a new contour. If the start of
- * the path is different from the path's current last point, then an
- * automatic lineTo() is added to connect the current contour to the
- * start of the arc. However, if the path is empty, then we call moveTo()
- * with the first point of the arc. The sweep angle is tread mod 360.
- *
- * @param oval The bounds of oval defining shape and size of the arc
- * @param startAngle Starting angle (in degrees) where the arc begins
- * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
- * mod 360.
- * @param forceMoveTo If true, always begin a new contour with the arc
- */
- public void arcTo(RectF oval, float startAngle, float sweepAngle,
- boolean forceMoveTo) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Append the specified arc to the path as a new contour. If the start of
- * the path is different from the path's current last point, then an
- * automatic lineTo() is added to connect the current contour to the
- * start of the arc. However, if the path is empty, then we call moveTo()
- * with the first point of the arc.
- *
- * @param oval The bounds of oval defining shape and size of the arc
- * @param startAngle Starting angle (in degrees) where the arc begins
- * @param sweepAngle Sweep angle (in degrees) measured clockwise
- */
- public void arcTo(RectF oval, float startAngle, float sweepAngle) {
- throw new UnsupportedOperationException();
- }
-
- /**
- * Close the current contour. If the current point is not equal to the
- * first point of the contour, a line segment is automatically added.
- */
- public void close() {
- mPath.closePath();
- }
-
- /**
- * Specifies how closed shapes (e.g. rects, ovals) are oriented when they
- * are added to a path.
- */
- public enum Direction {
- /** clockwise */
- CW (0), // must match enum in SkPath.h
- /** counter-clockwise */
- CCW (1); // must match enum in SkPath.h
-
- Direction(int ni) {
- nativeInt = ni;
- }
- final int nativeInt;
- }
-
- /**
- * Add a closed rectangle contour to the path
- *
- * @param rect The rectangle to add as a closed contour to the path
- * @param dir The direction to wind the rectangle's contour
- */
- public void addRect(RectF rect, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
-
- addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
- }
-
- /**
- * Add a closed rectangle contour to the path
- *
- * @param left The left side of a rectangle to add to the path
- * @param top The top of a rectangle to add to the path
- * @param right The right side of a rectangle to add to the path
- * @param bottom The bottom of a rectangle to add to the path
- * @param dir The direction to wind the rectangle's contour
- */
- public void addRect(float left, float top, float right, float bottom,
- Direction dir) {
- moveTo(left, top);
-
- switch (dir) {
- case CW:
- lineTo(right, top);
- lineTo(right, bottom);
- lineTo(left, bottom);
- break;
- case CCW:
- lineTo(left, bottom);
- lineTo(right, bottom);
- lineTo(right, top);
- break;
- }
-
- close();
- }
-
- /**
- * Add a closed oval contour to the path
- *
- * @param oval The bounds of the oval to add as a closed contour to the path
- * @param dir The direction to wind the oval's contour
- */
- public void addOval(RectF oval, Direction dir) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
-
- // FIXME Need to support direction
- Ellipse2D ovalShape = new Ellipse2D.Float(oval.left, oval.top, oval.width(), oval.height());
-
- mPath.append(ovalShape, false /* connect */);
- }
-
- /**
- * Add a closed circle contour to the path
- *
- * @param x The x-coordinate of the center of a circle to add to the path
- * @param y The y-coordinate of the center of a circle to add to the path
- * @param radius The radius of a circle to add to the path
- * @param dir The direction to wind the circle's contour
- */
- public void addCircle(float x, float y, float radius, Direction dir) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add the specified arc to the path as a new contour.
- *
- * @param oval The bounds of oval defining the shape and size of the arc
- * @param startAngle Starting angle (in degrees) where the arc begins
- * @param sweepAngle Sweep angle (in degrees) measured clockwise
- */
- public void addArc(RectF oval, float startAngle, float sweepAngle) {
- if (oval == null) {
- throw new NullPointerException("need oval parameter");
- }
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add a closed round-rectangle contour to the path
- *
- * @param rect The bounds of a round-rectangle to add to the path
- * @param rx The x-radius of the rounded corners on the round-rectangle
- * @param ry The y-radius of the rounded corners on the round-rectangle
- * @param dir The direction to wind the round-rectangle's contour
- */
- public void addRoundRect(RectF rect, float rx, float ry, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add a closed round-rectangle contour to the path. Each corner receives
- * two radius values [X, Y]. The corners are ordered top-left, top-right,
- * bottom-right, bottom-left
- *
- * @param rect The bounds of a round-rectangle to add to the path
- * @param radii Array of 8 values, 4 pairs of [X,Y] radii
- * @param dir The direction to wind the round-rectangle's contour
- */
- public void addRoundRect(RectF rect, float[] radii, Direction dir) {
- if (rect == null) {
- throw new NullPointerException("need rect parameter");
- }
- if (radii.length < 8) {
- throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
- }
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Add a copy of src to the path, offset by (dx,dy)
- *
- * @param src The path to add as a new contour
- * @param dx The amount to translate the path in X as it is added
- */
- public void addPath(Path src, float dx, float dy) {
- PathIterator iterator = src.mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
- mPath.append(iterator, false /* connect */);
- }
-
- /**
- * Add a copy of src to the path
- *
- * @param src The path that is appended to the current path
- */
- public void addPath(Path src) {
- addPath(src, 0, 0);
- }
-
- /**
- * Add a copy of src to the path, transformed by matrix
- *
- * @param src The path to add as a new contour
- */
- public void addPath(Path src, Matrix matrix) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Offset the path by (dx,dy), returning true on success
- *
- * @param dx The amount in the X direction to offset the entire path
- * @param dy The amount in the Y direction to offset the entire path
- * @param dst The translated path is written here. If this is null, then
- * the original path is modified.
- */
- public void offset(float dx, float dy, Path dst) {
- GeneralPath newPath = new GeneralPath();
-
- PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
-
- newPath.append(iterator, false /* connect */);
-
- if (dst != null) {
- dst.mPath = newPath;
- } else {
- mPath = newPath;
- }
- }
-
- /**
- * Offset the path by (dx,dy), returning true on success
- *
- * @param dx The amount in the X direction to offset the entire path
- * @param dy The amount in the Y direction to offset the entire path
- */
- public void offset(float dx, float dy) {
- offset(dx, dy, null /* dst */);
- }
-
- /**
- * Sets the last point of the path.
- *
- * @param dx The new X coordinate for the last point
- * @param dy The new Y coordinate for the last point
- */
- public void setLastPoint(float dx, float dy) {
- mLastX = dx;
- mLastY = dy;
- }
-
- /**
- * Transform the points in this path by matrix, and write the answer
- * into dst. If dst is null, then the the original path is modified.
- *
- * @param matrix The matrix to apply to the path
- * @param dst The transformed path is written here. If dst is null,
- * then the the original path is modified
- */
- public void transform(Matrix matrix, Path dst) {
- // FIXME
- throw new UnsupportedOperationException();
- }
-
- /**
- * Transform the points in this path by matrix.
- *
- * @param matrix The matrix to apply to the path
- */
- public void transform(Matrix matrix) {
- transform(matrix, null /* dst */);
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
new file mode 100644
index 0000000..c448f0e
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PathDashPathEffect_Delegate.java
@@ -0,0 +1,72 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PathDashPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of PathDashPathEffect 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 PathDashPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class PathDashPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Path Dash Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int native_path, float advance, float phase,
+ int native_style) {
+ PathDashPathEffect_Delegate newDelegate = new PathDashPathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
new file mode 100644
index 0000000..bd2b6de
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PathEffect_Delegate.java
@@ -0,0 +1,69 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of PathEffect 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 PathEffect class.
+ *
+ * This also serve as a base class for all PathEffect delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class PathEffect_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<PathEffect_Delegate> sManager =
+ new DelegateManager<PathEffect_Delegate>(PathEffect_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static PathEffect_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract Stroke getStroke(Paint_Delegate paint);
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_patheffect) {
+ sManager.removeJavaReferenceFor(native_patheffect);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
new file mode 100644
index 0000000..6c9f48f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Path_Delegate.java
@@ -0,0 +1,761 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Path.Direction;
+import android.graphics.Path.FillType;
+
+import java.awt.Shape;
+import java.awt.geom.AffineTransform;
+import java.awt.geom.Arc2D;
+import java.awt.geom.Area;
+import java.awt.geom.GeneralPath;
+import java.awt.geom.PathIterator;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Path
+ *
+ * Through the layoutlib_create tool, the original native methods of Path 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 Path class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Path_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Path_Delegate> sManager =
+ new DelegateManager<Path_Delegate>(Path_Delegate.class);
+
+ // ---- delegate data ----
+ private FillType mFillType = FillType.WINDING;
+ private GeneralPath mPath = new GeneralPath();
+
+ private float mLastX = 0;
+ private float mLastY = 0;
+
+ // ---- Public Helper methods ----
+
+ public static Path_Delegate getDelegate(int nPath) {
+ return sManager.getDelegate(nPath);
+ }
+
+ public Shape getJavaShape() {
+ 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 ----
+
+ @LayoutlibDelegate
+ /*package*/ static int init1() {
+ // create the delegate
+ Path_Delegate newDelegate = new Path_Delegate();
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int init2(int nPath) {
+ // create the delegate
+ Path_Delegate newDelegate = new Path_Delegate();
+
+ // get the delegate to copy, which could be null if nPath is 0
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate != null) {
+ newDelegate.set(pathDelegate);
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_reset(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mPath.reset();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rewind(int nPath) {
+ // call out to reset since there's nothing to optimize in
+ // terms of data structs.
+ native_reset(nPath);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_set(int native_dst, int native_src) {
+ Path_Delegate pathDstDelegate = sManager.getDelegate(native_dst);
+ if (pathDstDelegate == null) {
+ return;
+ }
+
+ Path_Delegate pathSrcDelegate = sManager.getDelegate(native_src);
+ if (pathSrcDelegate == null) {
+ return;
+ }
+
+ pathDstDelegate.set(pathSrcDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int native_getFillType(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return 0;
+ }
+
+ return pathDelegate.mFillType.nativeInt;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setFillType(int nPath, int ft) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mFillType = Path.sFillTypeArray[ft];
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_isEmpty(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return true;
+ }
+
+ return pathDelegate.isEmpty();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean native_isRect(int nPath, RectF rect) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return false;
+ }
+
+ // create an Area that can test if the path is a rect
+ Area area = new Area(pathDelegate.mPath);
+ if (area.isRectangular()) {
+ if (rect != null) {
+ pathDelegate.fillBounds(rect);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_computeBounds(int nPath, RectF bounds) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.fillBounds(bounds);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_incReserve(int nPath, int extraPtCount) {
+ // since we use a java2D path, there's no way to pre-allocate new points,
+ // so we do nothing.
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_moveTo(int nPath, float x, float y) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.moveTo(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rMoveTo(int nPath, float dx, float dy) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rMoveTo(dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_lineTo(int nPath, float x, float y) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.lineTo(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rLineTo(int nPath, float dx, float dy) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rLineTo(dx, dy);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_quadTo(int nPath, float x1, float y1, float x2, float y2) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.quadTo(x1, y1, x2, y2);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rQuadTo(int nPath, float dx1, float dy1, float dx2, float dy2) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rQuadTo(dx1, dy1, dx2, dy2);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_cubicTo(int nPath, float x1, float y1,
+ float x2, float y2, float x3, float y3) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.cubicTo(x1, y1, x2, y2, x3, y3);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_rCubicTo(int nPath, float x1, float y1,
+ float x2, float y2, float x3, float y3) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.rCubicTo(x1, y1, x2, y2, x3, y3);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_arcTo(int nPath, RectF oval,
+ float startAngle, float sweepAngle, boolean forceMoveTo) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.arcTo(oval, startAngle, sweepAngle, forceMoveTo);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_close(int nPath) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.close();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRect(int nPath, RectF rect, int dir) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.addRect(rect.left, rect.top, rect.right, rect.bottom, dir);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRect(int nPath,
+ float left, float top, float right, float bottom, int dir) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.addRect(left, top, right, bottom, dir);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addOval(int nPath, RectF oval, int dir) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addOval is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addCircle(int nPath, float x, float y, float radius, int dir) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addCircle is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addArc(int nPath, RectF oval,
+ float startAngle, float sweepAngle) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addArc is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRoundRect(int nPath, RectF rect,
+ float rx, float ry, int dir) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addRoundRect is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addRoundRect(int nPath, RectF r, float[] radii, int dir) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addRoundRect is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addPath(int nPath, int src, float dx, float dy) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addPath(int nPath, int src) {
+ native_addPath(nPath, src, 0, 0);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_addPath(int nPath, int src, int matrix) {
+ // FIXME
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Path.addPath is not supported.", null, null /*data*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_offset(int nPath, float dx, float dy, int dst_path) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ // could be null if the int is 0;
+ Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
+
+ pathDelegate.offset(dx, dy, dstDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_offset(int nPath, float dx, float dy) {
+ native_offset(nPath, dx, dy, 0);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_setLastPoint(int nPath, float dx, float dy) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ pathDelegate.mLastX = dx;
+ pathDelegate.mLastY = dy;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_transform(int nPath, int matrix,
+ int dst_path) {
+ Path_Delegate pathDelegate = sManager.getDelegate(nPath);
+ if (pathDelegate == null) {
+ return;
+ }
+
+ Matrix_Delegate matrixDelegate = Matrix_Delegate.getDelegate(matrix);
+ if (matrixDelegate == null) {
+ return;
+ }
+
+ // this can be null if dst_path is 0
+ Path_Delegate dstDelegate = sManager.getDelegate(dst_path);
+
+ pathDelegate.transform(matrixDelegate, dstDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void native_transform(int nPath, int matrix) {
+ native_transform(nPath, matrix, 0);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int nPath) {
+ sManager.removeJavaReferenceFor(nPath);
+ }
+
+
+ // ---- Private helper methods ----
+
+ private void set(Path_Delegate delegate) {
+ mPath.reset();
+ setFillType(delegate.mFillType);
+ mPath.append(delegate.mPath, false /*connect*/);
+ }
+
+ private void setFillType(FillType fillType) {
+ mFillType = fillType;
+ mPath.setWindingRule(getWindingRule(fillType));
+ }
+
+ /**
+ * Returns the Java2D winding rules matching a given Android {@link FillType}.
+ * @param type the android fill type
+ * @return the matching java2d winding rule.
+ */
+ private static int getWindingRule(FillType type) {
+ switch (type) {
+ case WINDING:
+ case INVERSE_WINDING:
+ return GeneralPath.WIND_NON_ZERO;
+ case EVEN_ODD:
+ case INVERSE_EVEN_ODD:
+ return GeneralPath.WIND_EVEN_ODD;
+ }
+
+ assert false;
+ throw new IllegalArgumentException();
+ }
+
+ private static Direction getDirection(int direction) {
+ for (Direction d : Direction.values()) {
+ if (direction == d.nativeInt) {
+ return d;
+ }
+ }
+
+ assert false;
+ return null;
+ }
+
+ /**
+ * Returns whether the path is empty.
+ * @return true if the path is empty.
+ */
+ private boolean isEmpty() {
+ return mPath.getCurrentPoint() == null;
+ }
+
+ /**
+ * Fills the given {@link RectF} with the path bounds.
+ * @param bounds the RectF to be filled.
+ */
+ private void fillBounds(RectF bounds) {
+ Rectangle2D rect = mPath.getBounds2D();
+ bounds.left = (float)rect.getMinX();
+ bounds.right = (float)rect.getMaxX();
+ bounds.top = (float)rect.getMinY();
+ bounds.bottom = (float)rect.getMaxY();
+ }
+
+ /**
+ * Set the beginning of the next contour to the point (x,y).
+ *
+ * @param x The x-coordinate of the start of a new contour
+ * @param y The y-coordinate of the start of a new contour
+ */
+ private void moveTo(float x, float y) {
+ mPath.moveTo(mLastX = x, mLastY = y);
+ }
+
+ /**
+ * Set the beginning of the next contour relative to the last point on the
+ * previous contour. If there is no previous contour, this is treated the
+ * same as moveTo().
+ *
+ * @param dx The amount to add to the x-coordinate of the end of the
+ * previous contour, to specify the start of a new contour
+ * @param dy The amount to add to the y-coordinate of the end of the
+ * previous contour, to specify the start of a new contour
+ */
+ private void rMoveTo(float dx, float dy) {
+ dx += mLastX;
+ dy += mLastY;
+ mPath.moveTo(mLastX = dx, mLastY = dy);
+ }
+
+ /**
+ * Add a line from the last point to the specified point (x,y).
+ * If no moveTo() call has been made for this contour, the first point is
+ * automatically set to (0,0).
+ *
+ * @param x The x-coordinate of the end of a line
+ * @param y The y-coordinate of the end of a line
+ */
+ private void lineTo(float x, float y) {
+ mPath.lineTo(mLastX = x, mLastY = y);
+ }
+
+ /**
+ * Same as lineTo, but the coordinates are considered relative to the last
+ * point on this contour. If there is no previous point, then a moveTo(0,0)
+ * is inserted automatically.
+ *
+ * @param dx The amount to add to the x-coordinate of the previous point on
+ * this contour, to specify a line
+ * @param dy The amount to add to the y-coordinate of the previous point on
+ * this contour, to specify a line
+ */
+ private void rLineTo(float dx, float dy) {
+ if (isEmpty()) {
+ mPath.moveTo(mLastX = 0, mLastY = 0);
+ }
+ dx += mLastX;
+ dy += mLastY;
+ mPath.lineTo(mLastX = dx, mLastY = dy);
+ }
+
+ /**
+ * Add a quadratic bezier from the last point, approaching control point
+ * (x1,y1), and ending at (x2,y2). If no moveTo() call has been made for
+ * this contour, the first point is automatically set to (0,0).
+ *
+ * @param x1 The x-coordinate of the control point on a quadratic curve
+ * @param y1 The y-coordinate of the control point on a quadratic curve
+ * @param x2 The x-coordinate of the end point on a quadratic curve
+ * @param y2 The y-coordinate of the end point on a quadratic curve
+ */
+ private void quadTo(float x1, float y1, float x2, float y2) {
+ mPath.quadTo(x1, y1, mLastX = x2, mLastY = y2);
+ }
+
+ /**
+ * Same as quadTo, but the coordinates are considered relative to the last
+ * point on this contour. If there is no previous point, then a moveTo(0,0)
+ * is inserted automatically.
+ *
+ * @param dx1 The amount to add to the x-coordinate of the last point on
+ * this contour, for the control point of a quadratic curve
+ * @param dy1 The amount to add to the y-coordinate of the last point on
+ * this contour, for the control point of a quadratic curve
+ * @param dx2 The amount to add to the x-coordinate of the last point on
+ * this contour, for the end point of a quadratic curve
+ * @param dy2 The amount to add to the y-coordinate of the last point on
+ * this contour, for the end point of a quadratic curve
+ */
+ private void rQuadTo(float dx1, float dy1, float dx2, float dy2) {
+ if (isEmpty()) {
+ mPath.moveTo(mLastX = 0, mLastY = 0);
+ }
+ dx1 += mLastX;
+ dy1 += mLastY;
+ dx2 += mLastX;
+ dy2 += mLastY;
+ mPath.quadTo(dx1, dy1, mLastX = dx2, mLastY = dy2);
+ }
+
+ /**
+ * Add a cubic bezier from the last point, approaching control points
+ * (x1,y1) and (x2,y2), and ending at (x3,y3). If no moveTo() call has been
+ * made for this contour, the first point is automatically set to (0,0).
+ *
+ * @param x1 The x-coordinate of the 1st control point on a cubic curve
+ * @param y1 The y-coordinate of the 1st control point on a cubic curve
+ * @param x2 The x-coordinate of the 2nd control point on a cubic curve
+ * @param y2 The y-coordinate of the 2nd control point on a cubic curve
+ * @param x3 The x-coordinate of the end point on a cubic curve
+ * @param y3 The y-coordinate of the end point on a cubic curve
+ */
+ private void cubicTo(float x1, float y1, float x2, float y2,
+ float x3, float y3) {
+ mPath.curveTo(x1, y1, x2, y2, mLastX = x3, mLastY = y3);
+ }
+
+ /**
+ * Same as cubicTo, but the coordinates are considered relative to the
+ * current point on this contour. If there is no previous point, then a
+ * moveTo(0,0) is inserted automatically.
+ */
+ private void rCubicTo(float dx1, float dy1, float dx2, float dy2,
+ float dx3, float dy3) {
+ if (isEmpty()) {
+ mPath.moveTo(mLastX = 0, mLastY = 0);
+ }
+ dx1 += mLastX;
+ dy1 += mLastY;
+ dx2 += mLastX;
+ dy2 += mLastY;
+ dx3 += mLastX;
+ dy3 += mLastY;
+ mPath.curveTo(dx1, dy1, dx2, dy2, mLastX = dx3, mLastY = dy3);
+ }
+
+ /**
+ * Append the specified arc to the path as a new contour. If the start of
+ * the path is different from the path's current last point, then an
+ * automatic lineTo() is added to connect the current contour to the
+ * start of the arc. However, if the path is empty, then we call moveTo()
+ * with the first point of the arc. The sweep angle is tread mod 360.
+ *
+ * @param oval The bounds of oval defining shape and size of the arc
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise, treated
+ * mod 360.
+ * @param forceMoveTo If true, always begin a new contour with the arc
+ */
+ private void arcTo(RectF oval, float startAngle, float sweepAngle,
+ boolean forceMoveTo) {
+ Arc2D arc = new Arc2D.Float(oval.left, oval.top, oval.width(), oval.height(), startAngle,
+ sweepAngle, Arc2D.OPEN);
+ mPath.append(arc, true /*connect*/);
+
+ resetLastPointFromPath();
+ }
+
+ /**
+ * Close the current contour. If the current point is not equal to the
+ * first point of the contour, a line segment is automatically added.
+ */
+ private void close() {
+ mPath.closePath();
+ }
+
+ private void resetLastPointFromPath() {
+ Point2D last = mPath.getCurrentPoint();
+ mLastX = (float) last.getX();
+ mLastY = (float) last.getY();
+ }
+
+ /**
+ * Add a closed rectangle contour to the path
+ *
+ * @param left The left side of a rectangle to add to the path
+ * @param top The top of a rectangle to add to the path
+ * @param right The right side of a rectangle to add to the path
+ * @param bottom The bottom of a rectangle to add to the path
+ * @param dir The direction to wind the rectangle's contour
+ */
+ private void addRect(float left, float top, float right, float bottom,
+ int dir) {
+ moveTo(left, top);
+
+ Direction direction = getDirection(dir);
+
+ switch (direction) {
+ case CW:
+ lineTo(right, top);
+ lineTo(right, bottom);
+ lineTo(left, bottom);
+ break;
+ case CCW:
+ lineTo(left, bottom);
+ lineTo(right, bottom);
+ lineTo(right, top);
+ break;
+ }
+
+ close();
+
+ resetLastPointFromPath();
+ }
+
+ /**
+ * Offset the path by (dx,dy), returning true on success
+ *
+ * @param dx The amount in the X direction to offset the entire path
+ * @param dy The amount in the Y direction to offset the entire path
+ * @param dst The translated path is written here. If this is null, then
+ * the original path is modified.
+ */
+ public void offset(float dx, float dy, Path_Delegate dst) {
+ GeneralPath newPath = new GeneralPath();
+
+ PathIterator iterator = mPath.getPathIterator(new AffineTransform(0, 0, dx, 0, 0, dy));
+
+ newPath.append(iterator, false /*connect*/);
+
+ if (dst != null) {
+ dst.mPath = newPath;
+ } else {
+ mPath = newPath;
+ }
+ }
+
+ /**
+ * Transform the points in this path by matrix, and write the answer
+ * into dst. If dst is null, then the the original path is modified.
+ *
+ * @param matrix The matrix to apply to the path
+ * @param dst The transformed path is written here. If dst is null,
+ * then the the original path is modified
+ */
+ public void transform(Matrix_Delegate matrix, Path_Delegate dst) {
+ if (matrix.hasPerspective()) {
+ assert false;
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_AFFINE,
+ "android.graphics.Path#transform() only " +
+ "supports affine transformations.", null, null /*data*/);
+ }
+
+ GeneralPath newPath = new GeneralPath();
+
+ PathIterator iterator = mPath.getPathIterator(matrix.getAffineTransform());
+
+ newPath.append(iterator, false /*connect*/);
+
+ if (dst != null) {
+ dst.mPath = newPath;
+ } else {
+ mPath = newPath;
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
new file mode 100644
index 0000000..4ab044b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PixelXorXfermode_Delegate.java
@@ -0,0 +1,70 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PixelXorXfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of PixelXorXfermode 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 PixelXorXfermode class.
+ *
+ * Because this extends {@link Xfermode_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link Xfermode_Delegate}.
+ *
+ * @see Xfermode_Delegate
+ */
+public class PixelXorXfermode_Delegate extends Xfermode_Delegate {
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Composite getComposite(int alpha) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Pixel XOR Xfermodes are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int opColor) {
+ PixelXorXfermode_Delegate newDelegate = new PixelXorXfermode_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
new file mode 100644
index 0000000..c45dbaa
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffColorFilter_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PorterDuffColorFilter
+ *
+ * Through the layoutlib_create tool, the original native methods of PorterDuffColorFilter 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 PorterDuffColorFilter class.
+ *
+ * Because this extends {@link ColorFilter_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the Shader classes will be added to the manager
+ * owned by {@link ColorFilter_Delegate}.
+ *
+ * @see ColorFilter_Delegate
+ *
+ */
+public class PorterDuffColorFilter_Delegate extends ColorFilter_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "PorterDuff Color Filters are not supported.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode) {
+ PorterDuffColorFilter_Delegate newDelegate = new PorterDuffColorFilter_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nCreatePorterDuffFilter(int nativeFilter, int srcColor,
+ int porterDuffMode) {
+ // pass
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
new file mode 100644
index 0000000..4301c1a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode_Delegate.java
@@ -0,0 +1,140 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.AlphaComposite;
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.PorterDuffXfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of PorterDuffXfermode 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 PorterDuffXfermode class.
+ *
+ * Because this extends {@link Xfermode_Delegate}, there's no need to use a
+ * {@link DelegateManager}, as all the PathEffect classes will be added to the manager owned by
+ * {@link Xfermode_Delegate}.
+ *
+ */
+public class PorterDuffXfermode_Delegate extends Xfermode_Delegate {
+
+ // ---- delegate data ----
+
+ private final int mMode;
+
+ // ---- Public Helper methods ----
+
+ public PorterDuff.Mode getMode() {
+ return getPorterDuffMode(mMode);
+ }
+
+ @Override
+ public Composite getComposite(int alpha) {
+ return getComposite(getPorterDuffMode(mMode), alpha);
+ }
+
+ @Override
+ public boolean isSupported() {
+ return true;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ // no message since isSupported returns true;
+ return null;
+ }
+
+ public static PorterDuff.Mode getPorterDuffMode(int mode) {
+ for (PorterDuff.Mode m : PorterDuff.Mode.values()) {
+ if (m.nativeInt == mode) {
+ return m;
+ }
+ }
+
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN,
+ String.format("Unknown PorterDuff.Mode: %d", mode), null /*data*/);
+ assert false;
+ return PorterDuff.Mode.SRC_OVER;
+ }
+
+ public static Composite getComposite(PorterDuff.Mode mode, int alpha) {
+ float falpha = alpha != 0xFF ? (float)alpha / 255.f : 1.f;
+ switch (mode) {
+ case CLEAR:
+ return AlphaComposite.getInstance(AlphaComposite.CLEAR, falpha);
+ case DARKEN:
+ break;
+ case DST:
+ return AlphaComposite.getInstance(AlphaComposite.DST, falpha);
+ case DST_ATOP:
+ return AlphaComposite.getInstance(AlphaComposite.DST_ATOP, falpha);
+ case DST_IN:
+ return AlphaComposite.getInstance(AlphaComposite.DST_IN, falpha);
+ case DST_OUT:
+ return AlphaComposite.getInstance(AlphaComposite.DST_OUT, falpha);
+ case DST_OVER:
+ return AlphaComposite.getInstance(AlphaComposite.DST_OVER, falpha);
+ case LIGHTEN:
+ break;
+ case MULTIPLY:
+ break;
+ case SCREEN:
+ break;
+ case SRC:
+ return AlphaComposite.getInstance(AlphaComposite.SRC, falpha);
+ case SRC_ATOP:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_ATOP, falpha);
+ case SRC_IN:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_IN, falpha);
+ case SRC_OUT:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_OUT, falpha);
+ case SRC_OVER:
+ return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha);
+ case XOR:
+ return AlphaComposite.getInstance(AlphaComposite.XOR, falpha);
+ }
+
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_BROKEN,
+ String.format("Unsupported PorterDuff Mode: %s", mode.name()),
+ null, null /*data*/);
+
+ return AlphaComposite.getInstance(AlphaComposite.SRC_OVER, falpha);
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreateXfermode(int mode) {
+ PorterDuffXfermode_Delegate newDelegate = new PorterDuffXfermode_Delegate(mode);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private PorterDuffXfermode_Delegate(int mode) {
+ mMode = mode;
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient.java
deleted file mode 100644
index 4409a80..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/RadialGradient.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-public class RadialGradient extends GradientShader {
-
- private RadialGradientPaint mPaint;
-
- /**
- * Create a shader that draws a radial gradient given the center and radius.
- *
- * @param x The x-coordinate of the center of the radius
- * @param y The y-coordinate of the center of the radius
- * @param radius Must be positive. The radius of the circle for this
- * gradient
- * @param colors The colors to be distributed between the center and edge of
- * the circle
- * @param positions May be NULL. The relative position of each corresponding
- * color in the colors array. If this is NULL, the the colors are
- * distributed evenly between the center and edge of the circle.
- * @param tile The Shader tiling mode
- */
- public RadialGradient(float x, float y, float radius, int colors[], float positions[],
- TileMode tile) {
- super(colors, positions);
- if (radius <= 0) {
- throw new IllegalArgumentException("radius must be > 0");
- }
-
- mPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
- }
-
- /**
- * Create a shader that draws a radial gradient given the center and radius.
- *
- * @param x The x-coordinate of the center of the radius
- * @param y The y-coordinate of the center of the radius
- * @param radius Must be positive. The radius of the circle for this
- * gradient
- * @param color0 The color at the center of the circle.
- * @param color1 The color at the edge of the circle.
- * @param tile The Shader tiling mode
- */
- public RadialGradient(float x, float y, float radius, int color0, int color1, TileMode tile) {
- this(x, y, radius, new int[] { color0, color1 }, null /* positions */, tile);
- }
-
- @Override
- java.awt.Paint getJavaPaint() {
- return mPaint;
- }
-
- private static class RadialGradientPaint extends GradientPaint {
-
- private final float mX;
- private final float mY;
- private final float mRadius;
-
- public RadialGradientPaint(float x, float y, float radius, int[] colors, float[] positions, TileMode mode) {
- super(colors, positions, mode);
- mX = x;
- mY = y;
- mRadius = radius;
- }
-
- public java.awt.PaintContext createContext(
- java.awt.image.ColorModel colorModel,
- java.awt.Rectangle deviceBounds,
- java.awt.geom.Rectangle2D userBounds,
- java.awt.geom.AffineTransform xform,
- java.awt.RenderingHints hints) {
- precomputeGradientColors();
- return new RadialGradientPaintContext(colorModel);
- }
-
- private class RadialGradientPaintContext implements java.awt.PaintContext {
-
- private final java.awt.image.ColorModel mColorModel;
-
- public RadialGradientPaintContext(java.awt.image.ColorModel colorModel) {
- mColorModel = colorModel;
- }
-
- public void dispose() {
- }
-
- public java.awt.image.ColorModel getColorModel() {
- return mColorModel;
- }
-
- public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
-
- int[] data = new int[w*h];
-
- // compute distance from each point to the center, and figure out the distance from
- // it.
- int index = 0;
- for (int iy = 0 ; iy < h ; iy++) {
- for (int ix = 0 ; ix < w ; ix++) {
- float _x = x + ix - mX;
- float _y = y + iy - mY;
- float distance = (float) Math.sqrt(_x * _x + _y * _y);
-
- data[index++] = getGradientColor(distance / mRadius);
- }
- }
-
- image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
-
- return image.getRaster();
- }
-
- }
- }
-
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
new file mode 100644
index 0000000..9bf78b4
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/RadialGradient_Delegate.java
@@ -0,0 +1,211 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.RadialGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of RadialGradient 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 RadialGradient class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class RadialGradient_Delegate extends Gradient_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(float x, float y, float radius,
+ int colors[], float positions[], int tileMode) {
+ RadialGradient_Delegate newDelegate = new RadialGradient_Delegate(x, y, radius,
+ colors, positions, Shader_Delegate.getTileMode(tileMode));
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(float x, float y, float radius,
+ int color0, int color1, int tileMode) {
+ return nativeCreate1(x, y, radius, new int[] { color0, color1 }, null /*positions*/,
+ tileMode);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(int native_shader, float x, float y, float radius,
+ int colors[], float positions[], int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(int native_shader, float x, float y, float radius,
+ int color0, int color1, int tileMode) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /**
+ * Create a shader that draws a radial gradient given the center and radius.
+ *
+ * @param x The x-coordinate of the center of the radius
+ * @param y The y-coordinate of the center of the radius
+ * @param radius Must be positive. The radius of the circle for this
+ * gradient
+ * @param colors The colors to be distributed between the center and edge of
+ * the circle
+ * @param positions May be NULL. The relative position of each corresponding
+ * color in the colors array. If this is NULL, the the colors are
+ * distributed evenly between the center and edge of the circle.
+ * @param tile The Shader tiling mode
+ */
+ private RadialGradient_Delegate(float x, float y, float radius, int colors[], float positions[],
+ TileMode tile) {
+ super(colors, positions);
+ mJavaPaint = new RadialGradientPaint(x, y, radius, mColors, mPositions, tile);
+ }
+
+ private class RadialGradientPaint extends GradientPaint {
+
+ private final float mX;
+ private final float mY;
+ private final float mRadius;
+
+ public RadialGradientPaint(float x, float y, float radius,
+ int[] colors, float[] positions, TileMode mode) {
+ super(colors, positions, mode);
+ mX = x;
+ mY = y;
+ mRadius = radius;
+ }
+
+ public java.awt.PaintContext createContext(
+ java.awt.image.ColorModel colorModel,
+ java.awt.Rectangle deviceBounds,
+ java.awt.geom.Rectangle2D userBounds,
+ java.awt.geom.AffineTransform xform,
+ java.awt.RenderingHints hints) {
+ precomputeGradientColors();
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in RadialGradient", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in RadialGradient", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new RadialGradientPaintContext(canvasMatrix, localMatrix, colorModel);
+ }
+
+ private class RadialGradientPaintContext implements java.awt.PaintContext {
+
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
+ private final java.awt.image.ColorModel mColorModel;
+
+ public RadialGradientPaintContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
+ mColorModel = colorModel;
+ }
+
+ public void dispose() {
+ }
+
+ public java.awt.image.ColorModel getColorModel() {
+ return mColorModel;
+ }
+
+ public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
+ java.awt.image.BufferedImage.TYPE_INT_ARGB);
+
+ int[] data = new int[w*h];
+
+ // compute distance from each point to the center, and figure out the distance from
+ // it.
+ int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
+ for (int iy = 0 ; iy < h ; iy++) {
+ for (int ix = 0 ; ix < w ; ix++) {
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix
+ pt1[0] = pt2[0] - mX;
+ pt1[1] = pt2[1] - mY;
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ float _x = pt2[0];
+ float _y = pt2[1];
+ float distance = (float) Math.sqrt(_x * _x + _y * _y);
+
+ data[index++] = getGradientColor(distance / mRadius);
+ }
+ }
+
+ image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+ return image.getRaster();
+ }
+
+ }
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
new file mode 100644
index 0000000..2812b6b
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Rasterizer_Delegate.java
@@ -0,0 +1,64 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Rasterizer
+ *
+ * Through the layoutlib_create tool, the original native methods of Rasterizer 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 Rasterizer class.
+ *
+ * This also serve as a base class for all Rasterizer delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Rasterizer_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<Rasterizer_Delegate> sManager =
+ new DelegateManager<Rasterizer_Delegate>(Rasterizer_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static Rasterizer_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
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..cb31b8f
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Region_Delegate.java
@@ -0,0 +1,484 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+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>(Region_Delegate.class);
+
+ // ---- 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 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);
+
+ if (shape1 != null) {
+ result.subtract(shape1 instanceof Area ? (Area) shape1 : new Area(shape1));
+ }
+
+ return result;
+ }
+
+ return null;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isEmpty(Region thisRegion) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return true;
+ }
+
+ return regionDelegate.mArea.isEmpty();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isRect(Region thisRegion) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return true;
+ }
+
+ return regionDelegate.mArea.isRectangular();
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean isComplex(Region thisRegion) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return true;
+ }
+
+ return regionDelegate.mArea.isSingular() == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean contains(Region thisRegion, int x, int y) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.contains(x, y);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean quickContains(Region thisRegion,
+ int left, int top, int right, int bottom) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.isRectangular() &&
+ regionDelegate.mArea.contains(left, top, right - left, bottom - top);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean quickReject(Region thisRegion,
+ int left, int top, int right, int bottom) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.isEmpty() ||
+ regionDelegate.mArea.intersects(left, top, right - left, bottom - top) == false;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static boolean quickReject(Region thisRegion, Region rgn) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return false;
+ }
+
+ Region_Delegate targetRegionDelegate = sManager.getDelegate(rgn.mNativeRegion);
+ if (targetRegionDelegate == null) {
+ return false;
+ }
+
+ return regionDelegate.mArea.isEmpty() ||
+ regionDelegate.mArea.getBounds().intersects(
+ targetRegionDelegate.mArea.getBounds()) == false;
+
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void translate(Region thisRegion, int dx, int dy, Region dst) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return;
+ }
+
+ Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
+ if (targetRegionDelegate == null) {
+ return;
+ }
+
+ if (regionDelegate.mArea.isEmpty()) {
+ targetRegionDelegate.mArea = new Area();
+ } else {
+ targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
+ AffineTransform mtx = new AffineTransform();
+ mtx.translate(dx, dy);
+ targetRegionDelegate.mArea.transform(mtx);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void scale(Region thisRegion, float scale, Region dst) {
+ Region_Delegate regionDelegate = sManager.getDelegate(thisRegion.mNativeRegion);
+ if (regionDelegate == null) {
+ return;
+ }
+
+ Region_Delegate targetRegionDelegate = sManager.getDelegate(dst.mNativeRegion);
+ if (targetRegionDelegate == null) {
+ return;
+ }
+
+ if (regionDelegate.mArea.isEmpty()) {
+ targetRegionDelegate.mArea = new Area();
+ } else {
+ targetRegionDelegate.mArea = new Area(regionDelegate.mArea);
+ AffineTransform mtx = new AffineTransform();
+ mtx.scale(scale, scale);
+ targetRegionDelegate.mArea.transform(mtx);
+ }
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeConstructor() {
+ Region_Delegate newDelegate = new Region_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_region) {
+ sManager.removeJavaReferenceFor(native_region);
+ }
+
+ @LayoutlibDelegate
+ /*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;
+ }
+
+ @LayoutlibDelegate
+ /*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;
+ }
+
+ @LayoutlibDelegate
+ /*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;
+ }
+
+ @LayoutlibDelegate
+ /*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;
+ }
+
+ @LayoutlibDelegate
+ /*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;
+ }
+
+ @LayoutlibDelegate
+ /*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;
+ }
+
+ @LayoutlibDelegate
+ /*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;
+ }
+
+ @LayoutlibDelegate
+ /*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;
+
+ }
+
+ @LayoutlibDelegate
+ /*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(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Regions cannot be created from parcels.",
+ null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*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(LayoutLog.TAG_UNSUPPORTED,
+ "AIDL is not suppored, and therefore Regions cannot be written to parcels.",
+ null /*data*/);
+ return false;
+ }
+
+ @LayoutlibDelegate
+ /*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);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static String nativeToString(int native_region) {
+ Region_Delegate region = sManager.getDelegate(native_region);
+ if (region == null) {
+ return "not found";
+ }
+
+ return region.mArea.toString();
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader.java b/tools/layoutlib/bridge/src/android/graphics/Shader.java
deleted file mode 100644
index 0cc5940..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Shader.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-
-
-/**
- * Shader is the based class for objects that return horizontal spans of colors
- * during drawing. A subclass of Shader is installed in a Paint calling
- * paint.setShader(shader). After that any object (other than a bitmap) that is
- * drawn with that paint will get its color(s) from the shader.
- */
-public abstract class Shader {
-
- private final Matrix mMatrix = new Matrix();
-
- public enum TileMode {
- /**
- * replicate the edge color if the shader draws outside of its
- * original bounds
- */
- CLAMP (0),
- /**
- * repeat the shader's image horizontally and vertically
- */
- REPEAT (1),
- /**
- * repeat the shader's image horizontally and vertically, alternating
- * mirror images so that adjacent images always seam
- */
- MIRROR (2);
-
- TileMode(int nativeInt) {
- this.nativeInt = nativeInt;
- }
- final int nativeInt;
- }
-
- /**
- * Return true if the shader has a non-identity local matrix.
- * @param localM If not null, it is set to the shader's local matrix.
- * @return true if the shader has a non-identity local matrix
- */
- public boolean getLocalMatrix(Matrix localM) {
- if (localM != null) {
- localM.set(mMatrix);
- }
-
- return !mMatrix.isIdentity();
- }
-
- /**
- * Set the shader's local matrix. Passing null will reset the shader's
- * matrix to identity
- * @param localM The shader's new local matrix, or null to specify identity
- */
- public void setLocalMatrix(Matrix localM) {
- if (localM != null) {
- mMatrix.set(localM);
- } else {
- mMatrix.reset();
- }
- }
-
- /**
- * Returns a java.awt.Paint object matching this shader.
- */
- abstract java.awt.Paint getJavaPaint();
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
new file mode 100644
index 0000000..368c0384
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Shader_Delegate.java
@@ -0,0 +1,105 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.graphics.Shader.TileMode;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Shader
+ *
+ * Through the layoutlib_create tool, the original native methods of Shader 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 Shader class.
+ *
+ * This also serve as a base class for all Shader delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Shader_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<Shader_Delegate> sManager =
+ new DelegateManager<Shader_Delegate>(Shader_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+ private Matrix_Delegate mLocalMatrix = null;
+
+ // ---- Public Helper methods ----
+
+ public static Shader_Delegate getDelegate(int nativeShader) {
+ return sManager.getDelegate(nativeShader);
+ }
+
+ /**
+ * Returns the {@link TileMode} matching the given int.
+ * @param tileMode the tile mode int value
+ * @return the TileMode enum.
+ */
+ public static TileMode getTileMode(int tileMode) {
+ for (TileMode tm : TileMode.values()) {
+ if (tm.nativeInt == tileMode) {
+ return tm;
+ }
+ }
+
+ assert false;
+ return TileMode.CLAMP;
+ }
+
+ public abstract java.awt.Paint getJavaPaint();
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeDestructor(int native_shader, int native_skiaShader) {
+ sManager.removeJavaReferenceFor(native_shader);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeSetLocalMatrix(int native_shader, int native_skiaShader,
+ int matrix_instance) {
+ // get the delegate from the native int.
+ Shader_Delegate shaderDelegate = sManager.getDelegate(native_shader);
+ if (shaderDelegate == null) {
+ return;
+ }
+
+ shaderDelegate.mLocalMatrix = Matrix_Delegate.getDelegate(matrix_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ protected java.awt.geom.AffineTransform getLocalMatrix() {
+ if (mLocalMatrix != null) {
+ return mLocalMatrix.getAffineTransform();
+ }
+
+ return new java.awt.geom.AffineTransform();
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
new file mode 100644
index 0000000..410df0c
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/SumPathEffect_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Stroke;
+
+/**
+ * Delegate implementing the native methods of android.graphics.SumPathEffect
+ *
+ * Through the layoutlib_create tool, the original native methods of SumPathEffect 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 SumPathEffect class.
+ *
+ * Because this extends {@link PathEffect_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link PathEffect_Delegate}.
+ *
+ * @see PathEffect_Delegate
+ *
+ */
+public class SumPathEffect_Delegate extends PathEffect_Delegate {
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public Stroke getStroke(Paint_Delegate paint) {
+ // FIXME
+ return null;
+ }
+
+ @Override
+ public boolean isSupported() {
+ return false;
+ }
+
+ @Override
+ public String getSupportMessage() {
+ return "Sum Path Effects are not supported in Layout Preview mode.";
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate(int first, int second) {
+ SumPathEffect_Delegate newDelegate = new SumPathEffect_Delegate();
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ // ---- Private delegate/helper methods ----
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient.java
deleted file mode 100644
index 87036ed..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/SweepGradient.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2008 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;
-
-public class SweepGradient extends GradientShader {
-
- private SweepGradientPaint mPaint;
-
- /**
- * A subclass of Shader that draws a sweep gradient around a center point.
- *
- * @param cx The x-coordinate of the center
- * @param cy The y-coordinate of the center
- * @param colors The colors to be distributed between around the center.
- * There must be at least 2 colors in the array.
- * @param positions May be NULL. The relative position of
- * each corresponding color in the colors array, beginning
- * with 0 and ending with 1.0. If the values are not
- * monotonic, the drawing may produce unexpected results.
- * If positions is NULL, then the colors are automatically
- * spaced evenly.
- */
- public SweepGradient(float cx, float cy,
- int colors[], float positions[]) {
- super(colors, positions);
-
- mPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
- }
-
- /**
- * A subclass of Shader that draws a sweep gradient around a center point.
- *
- * @param cx The x-coordinate of the center
- * @param cy The y-coordinate of the center
- * @param color0 The color to use at the start of the sweep
- * @param color1 The color to use at the end of the sweep
- */
- public SweepGradient(float cx, float cy, int color0, int color1) {
- this(cx, cy, new int[] { color0, color1}, null /*positions*/);
- }
-
- @Override
- java.awt.Paint getJavaPaint() {
- return mPaint;
- }
-
- private static class SweepGradientPaint extends GradientPaint {
-
- private final float mCx;
- private final float mCy;
-
- public SweepGradientPaint(float cx, float cy, int[] colors, float[] positions) {
- super(colors, positions, null /*tileMode*/);
- mCx = cx;
- mCy = cy;
- }
-
- public java.awt.PaintContext createContext(
- java.awt.image.ColorModel colorModel,
- java.awt.Rectangle deviceBounds,
- java.awt.geom.Rectangle2D userBounds,
- java.awt.geom.AffineTransform xform,
- java.awt.RenderingHints hints) {
- precomputeGradientColors();
- return new SweepGradientPaintContext(colorModel);
- }
-
- private class SweepGradientPaintContext implements java.awt.PaintContext {
-
- private final java.awt.image.ColorModel mColorModel;
-
- public SweepGradientPaintContext(java.awt.image.ColorModel colorModel) {
- mColorModel = colorModel;
- }
-
- public void dispose() {
- }
-
- public java.awt.image.ColorModel getColorModel() {
- return mColorModel;
- }
-
- public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
- java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
- java.awt.image.BufferedImage.TYPE_INT_ARGB);
-
- int[] data = new int[w*h];
-
- // compute angle from each point to the center, and figure out the distance from
- // it.
- int index = 0;
- for (int iy = 0 ; iy < h ; iy++) {
- for (int ix = 0 ; ix < w ; ix++) {
- float dx = x + ix - mCx;
- float dy = y + iy - mCy;
- float angle;
- if (dx == 0) {
- angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
- } else if (dy == 0) {
- angle = (float) (dx < 0 ? Math.PI : 0);
- } else {
- angle = (float) Math.atan(dy / dx);
- if (dx > 0) {
- if (dy < 0) {
- angle += Math.PI * 2;
- }
- } else {
- angle += Math.PI;
- }
- }
-
- // convert to 0-1. value and get color
- data[index++] = getGradientColor((float) (angle / (2 * Math.PI)));
- }
- }
-
- image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
-
- return image.getRaster();
- }
-
- }
- }
-
-}
-
diff --git a/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
new file mode 100644
index 0000000..966e06e
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/SweepGradient_Delegate.java
@@ -0,0 +1,218 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.graphics.SweepGradient
+ *
+ * Through the layoutlib_create tool, the original native methods of SweepGradient 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 SweepGradient class.
+ *
+ * Because this extends {@link Shader_Delegate}, there's no need to use a {@link DelegateManager},
+ * as all the Shader classes will be added to the manager owned by {@link Shader_Delegate}.
+ *
+ * @see Shader_Delegate
+ *
+ */
+public class SweepGradient_Delegate extends Gradient_Delegate {
+
+ // ---- delegate data ----
+ private java.awt.Paint mJavaPaint;
+
+ // ---- Public Helper methods ----
+
+ @Override
+ public java.awt.Paint getJavaPaint() {
+ return mJavaPaint;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate1(float x, float y, int colors[], float positions[]) {
+ SweepGradient_Delegate newDelegate = new SweepGradient_Delegate(x, y, colors, positions);
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeCreate2(float x, float y, int color0, int color1) {
+ return nativeCreate1(x, y, new int[] { color0, color1 }, null /*positions*/);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate1(int native_shader, float cx, float cy,
+ int[] colors, float[] positions) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativePostCreate2(int native_shader, float cx, float cy,
+ int color0, int color1) {
+ // nothing to be done here.
+ return 0;
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ /**
+ * A subclass of Shader that draws a sweep gradient around a center point.
+ *
+ * @param cx The x-coordinate of the center
+ * @param cy The y-coordinate of the center
+ * @param colors The colors to be distributed between around the center.
+ * There must be at least 2 colors in the array.
+ * @param positions May be NULL. The relative position of
+ * each corresponding color in the colors array, beginning
+ * with 0 and ending with 1.0. If the values are not
+ * monotonic, the drawing may produce unexpected results.
+ * If positions is NULL, then the colors are automatically
+ * spaced evenly.
+ */
+ private SweepGradient_Delegate(float cx, float cy,
+ int colors[], float positions[]) {
+ super(colors, positions);
+ mJavaPaint = new SweepGradientPaint(cx, cy, mColors, mPositions);
+ }
+
+ private class SweepGradientPaint extends GradientPaint {
+
+ private final float mCx;
+ private final float mCy;
+
+ public SweepGradientPaint(float cx, float cy, int[] colors,
+ float[] positions) {
+ super(colors, positions, null /*tileMode*/);
+ mCx = cx;
+ mCy = cy;
+ }
+
+ public java.awt.PaintContext createContext(
+ java.awt.image.ColorModel colorModel,
+ java.awt.Rectangle deviceBounds,
+ java.awt.geom.Rectangle2D userBounds,
+ java.awt.geom.AffineTransform xform,
+ java.awt.RenderingHints hints) {
+ precomputeGradientColors();
+
+ java.awt.geom.AffineTransform canvasMatrix;
+ try {
+ canvasMatrix = xform.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in SweepGradient", e, null /*data*/);
+ canvasMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ java.awt.geom.AffineTransform localMatrix = getLocalMatrix();
+ try {
+ localMatrix = localMatrix.createInverse();
+ } catch (java.awt.geom.NoninvertibleTransformException e) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_MATRIX_INVERSE,
+ "Unable to inverse matrix in SweepGradient", e, null /*data*/);
+ localMatrix = new java.awt.geom.AffineTransform();
+ }
+
+ return new SweepGradientPaintContext(canvasMatrix, localMatrix, colorModel);
+ }
+
+ private class SweepGradientPaintContext implements java.awt.PaintContext {
+
+ private final java.awt.geom.AffineTransform mCanvasMatrix;
+ private final java.awt.geom.AffineTransform mLocalMatrix;
+ private final java.awt.image.ColorModel mColorModel;
+
+ public SweepGradientPaintContext(
+ java.awt.geom.AffineTransform canvasMatrix,
+ java.awt.geom.AffineTransform localMatrix,
+ java.awt.image.ColorModel colorModel) {
+ mCanvasMatrix = canvasMatrix;
+ mLocalMatrix = localMatrix;
+ mColorModel = colorModel;
+ }
+
+ public void dispose() {
+ }
+
+ public java.awt.image.ColorModel getColorModel() {
+ return mColorModel;
+ }
+
+ public java.awt.image.Raster getRaster(int x, int y, int w, int h) {
+ java.awt.image.BufferedImage image = new java.awt.image.BufferedImage(w, h,
+ java.awt.image.BufferedImage.TYPE_INT_ARGB);
+
+ int[] data = new int[w*h];
+
+ // compute angle from each point to the center, and figure out the distance from
+ // it.
+ int index = 0;
+ float[] pt1 = new float[2];
+ float[] pt2 = new float[2];
+ for (int iy = 0 ; iy < h ; iy++) {
+ for (int ix = 0 ; ix < w ; ix++) {
+ // handle the canvas transform
+ pt1[0] = x + ix;
+ pt1[1] = y + iy;
+ mCanvasMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ // handle the local matrix
+ pt1[0] = pt2[0] - mCx;
+ pt1[1] = pt2[1] - mCy;
+ mLocalMatrix.transform(pt1, 0, pt2, 0, 1);
+
+ float dx = pt2[0];
+ float dy = pt2[1];
+
+ float angle;
+ if (dx == 0) {
+ angle = (float) (dy < 0 ? 3 * Math.PI / 2 : Math.PI / 2);
+ } else if (dy == 0) {
+ angle = (float) (dx < 0 ? Math.PI : 0);
+ } else {
+ angle = (float) Math.atan(dy / dx);
+ if (dx > 0) {
+ if (dy < 0) {
+ angle += Math.PI * 2;
+ }
+ } else {
+ angle += Math.PI;
+ }
+ }
+
+ // convert to 0-1. value and get color
+ data[index++] = getGradientColor((float) (angle / (2 * Math.PI)));
+ }
+ }
+
+ image.setRGB(0 /*startX*/, 0 /*startY*/, w, h, data, 0 /*offset*/, w /*scansize*/);
+
+ return image.getRaster();
+ }
+
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface.java b/tools/layoutlib/bridge/src/android/graphics/Typeface.java
deleted file mode 100644
index af3adb5..0000000
--- a/tools/layoutlib/bridge/src/android/graphics/Typeface.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * Copyright (C) 2008 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.FontLoader;
-
-import android.content.res.AssetManager;
-
-import java.awt.Font;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-/**
- * Re-implementation of Typeface over java.awt
- */
-public class Typeface {
- private static final String DEFAULT_FAMILY = "sans-serif";
- private static final int[] styleBuffer = new int[1];
-
- /** The default NORMAL typeface object */
- public static Typeface DEFAULT;
- /**
- * The default BOLD typeface object. Note: this may be not actually be
- * bold, depending on what fonts are installed. Call getStyle() to know
- * for sure.
- */
- public static Typeface DEFAULT_BOLD;
- /** The NORMAL style of the default sans serif typeface. */
- public static Typeface SANS_SERIF;
- /** The NORMAL style of the default serif typeface. */
- public static Typeface SERIF;
- /** The NORMAL style of the default monospace typeface. */
- public static Typeface MONOSPACE;
-
- private static Typeface[] sDefaults;
- private static FontLoader mFontLoader;
-
- private final int mStyle;
- private final List<Font> mFonts;
- private final String mFamily;
-
- // Style
- public static final int NORMAL = _Original_Typeface.NORMAL;
- public static final int BOLD = _Original_Typeface.BOLD;
- public static final int ITALIC = _Original_Typeface.ITALIC;
- public static final int BOLD_ITALIC = _Original_Typeface.BOLD_ITALIC;
-
- /**
- * Returns the underlying {@link Font} objects. The first item in the list is the real
- * font. Any other items are fallback fonts for characters not found in the first one.
- */
- public List<Font> getFonts() {
- return mFonts;
- }
-
- /** Returns the typeface's intrinsic style attributes */
- public int getStyle() {
- return mStyle;
- }
-
- /** Returns true if getStyle() has the BOLD bit set. */
- public final boolean isBold() {
- return (getStyle() & BOLD) != 0;
- }
-
- /** Returns true if getStyle() has the ITALIC bit set. */
- public final boolean isItalic() {
- return (getStyle() & ITALIC) != 0;
- }
-
- /**
- * Create a typeface object given a family name, and option style information.
- * If null is passed for the name, then the "default" font will be chosen.
- * The resulting typeface object can be queried (getStyle()) to discover what
- * its "real" style characteristics are.
- *
- * @param familyName May be null. The name of the font family.
- * @param style The style (normal, bold, italic) of the typeface.
- * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
- * @return The best matching typeface.
- */
- public static Typeface create(String familyName, int style) {
- styleBuffer[0] = style;
- Font font = mFontLoader.getFont(familyName, styleBuffer);
- if (font != null) {
- ArrayList<Font> list = new ArrayList<Font>();
- list.add(font);
- list.addAll(mFontLoader.getFallBackFonts());
- return new Typeface(familyName, styleBuffer[0], list);
- }
-
- return null;
- }
-
- /**
- * Create a typeface object that best matches the specified existing
- * typeface and the specified Style. Use this call if you want to pick a new
- * style from the same family of an existing typeface object. If family is
- * null, this selects from the default font's family.
- *
- * @param family May be null. The name of the existing type face.
- * @param style The style (normal, bold, italic) of the typeface.
- * e.g. NORMAL, BOLD, ITALIC, BOLD_ITALIC
- * @return The best matching typeface.
- */
- public static Typeface create(Typeface family, int style) {
- styleBuffer[0] = style;
- Font font = mFontLoader.getFont(family.mFamily, styleBuffer);
- if (font != null) {
- ArrayList<Font> list = new ArrayList<Font>();
- list.add(font);
- list.addAll(mFontLoader.getFallBackFonts());
- return new Typeface(family.mFamily, styleBuffer[0], list);
- }
-
- return null;
- }
-
- /**
- * Returns one of the default typeface objects, based on the specified style
- *
- * @return the default typeface that corresponds to the style
- */
- public static Typeface defaultFromStyle(int style) {
- return sDefaults[style];
- }
-
- /**
- * Create a new typeface from the specified font data.
- * @param mgr The application's asset manager
- * @param path The file name of the font data in the assets directory
- * @return The new typeface.
- */
- public static Typeface createFromAsset(AssetManager mgr, String path) {
- return null;
- //return new Typeface(nativeCreateFromAsset(mgr, path));
- }
-
- // don't allow clients to call this directly
- private Typeface(String family, int style, List<Font> fonts) {
- mFamily = family;
- mFonts = Collections.unmodifiableList(fonts);
- mStyle = style;
- }
-
- public static void init(FontLoader fontLoader) {
- mFontLoader = fontLoader;
-
- DEFAULT = create(DEFAULT_FAMILY, NORMAL);
- DEFAULT_BOLD = create(DEFAULT_FAMILY, BOLD);
- SANS_SERIF = create("sans-serif", NORMAL);
- SERIF = create("serif", NORMAL);
- MONOSPACE = create("monospace", NORMAL);
- sDefaults = new Typeface[] {
- DEFAULT,
- DEFAULT_BOLD,
- create(DEFAULT_FAMILY, ITALIC),
- create(DEFAULT_FAMILY, BOLD_ITALIC),
- };
-
- /*
- DEFAULT = create((String)null, 0);
- DEFAULT_BOLD = create((String)null, Typeface.BOLD);
- SANS_SERIF = create("sans-serif", 0);
- SERIF = create("serif", 0);
- MONOSPACE = create("monospace", 0);
-
- sDefaults = new Typeface[] {
- DEFAULT,
- DEFAULT_BOLD,
- create((String)null, Typeface.ITALIC),
- create((String)null, Typeface.BOLD_ITALIC),
- };*/
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
new file mode 100644
index 0000000..0f084f7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Typeface_Delegate.java
@@ -0,0 +1,191 @@
+/*
+ * 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.ide.common.rendering.api.LayoutLog;
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.layoutlib.bridge.impl.FontLoader;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import android.content.res.AssetManager;
+
+import java.awt.Font;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Typeface
+ *
+ * Through the layoutlib_create tool, the original native methods of Typeface 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 Typeface class.
+ *
+ * @see DelegateManager
+ *
+ */
+public final class Typeface_Delegate {
+
+ // ---- delegate manager ----
+ private static final DelegateManager<Typeface_Delegate> sManager =
+ new DelegateManager<Typeface_Delegate>(Typeface_Delegate.class);
+
+ // ---- delegate helper data ----
+ private static final String DEFAULT_FAMILY = "sans-serif";
+ private static final int[] STYLE_BUFFER = new int[1];
+
+ private static FontLoader sFontLoader;
+ private static final List<Typeface_Delegate> sPostInitDelegate =
+ new ArrayList<Typeface_Delegate>();
+
+ // ---- delegate data ----
+
+ private final String mFamily;
+ private int mStyle;
+ private List<Font> mFonts;
+
+
+ // ---- Public Helper methods ----
+
+ public static synchronized void init(FontLoader fontLoader) {
+ sFontLoader = fontLoader;
+
+ for (Typeface_Delegate delegate : sPostInitDelegate) {
+ delegate.init();
+ }
+ sPostInitDelegate.clear();
+ }
+
+ public static Typeface_Delegate getDelegate(int nativeTypeface) {
+ return sManager.getDelegate(nativeTypeface);
+ }
+
+ public static List<Font> getFonts(Typeface typeface) {
+ return getFonts(typeface.native_instance);
+ }
+
+ public static List<Font> getFonts(int native_int) {
+ Typeface_Delegate delegate = sManager.getDelegate(native_int);
+ if (delegate == null) {
+ return null;
+ }
+
+ return delegate.getFonts();
+ }
+
+ public List<Font> getFonts() {
+ return mFonts;
+ }
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreate(String familyName, int style) {
+ if (familyName == null) {
+ familyName = DEFAULT_FAMILY;
+ }
+
+ Typeface_Delegate newDelegate = new Typeface_Delegate(familyName, style);
+ if (sFontLoader != null) {
+ newDelegate.init();
+ } else {
+ // font loader has not been initialized yet, add the delegate to a list of delegates
+ // to init when the font loader is initialized.
+ // There won't be any rendering before this happens anyway.
+ sPostInitDelegate.add(newDelegate);
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreateFromTypeface(int native_instance, int style) {
+ Typeface_Delegate delegate = sManager.getDelegate(native_instance);
+ if (delegate == null) {
+ return 0;
+ }
+
+ Typeface_Delegate newDelegate = new Typeface_Delegate(delegate.mFamily, style);
+ if (sFontLoader != null) {
+ newDelegate.init();
+ } else {
+ // font loader has not been initialized yet, add the delegate to a list of delegates
+ // to init when the font loader is initialized.
+ // There won't be any rendering before this happens anyway.
+ sPostInitDelegate.add(newDelegate);
+ }
+
+ return sManager.addNewDelegate(newDelegate);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreateFromAsset(AssetManager mgr, String path) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Typeface.createFromAsset() is not supported.", null /*throwable*/, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static synchronized int nativeCreateFromFile(String path) {
+ Bridge.getLog().fidelityWarning(LayoutLog.TAG_UNSUPPORTED,
+ "Typeface.createFromFile() is not supported.", null /*throwable*/, null /*data*/);
+ return 0;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void nativeUnref(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static int nativeGetStyle(int native_instance) {
+ Typeface_Delegate delegate = sManager.getDelegate(native_instance);
+ if (delegate == null) {
+ return 0;
+ }
+
+ return delegate.mStyle;
+ }
+
+ @LayoutlibDelegate
+ /*package*/ static void setGammaForText(float blackGamma, float whiteGamma) {
+ // This is for device testing only: pass
+ }
+
+ // ---- Private delegate/helper methods ----
+
+ private Typeface_Delegate(String family, int style) {
+ mFamily = family;
+ mStyle = style;
+ }
+
+ private void init() {
+ STYLE_BUFFER[0] = mStyle;
+ Font font = sFontLoader.getFont(mFamily, STYLE_BUFFER);
+ if (font != null) {
+ List<Font> list = new ArrayList<Font>();
+ list.add(font);
+ list.addAll(sFontLoader.getFallBackFonts());
+ mFonts = Collections.unmodifiableList(list);
+ mStyle = STYLE_BUFFER[0];
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
new file mode 100644
index 0000000..962d69c
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/graphics/Xfermode_Delegate.java
@@ -0,0 +1,69 @@
+/*
+ * 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.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.awt.Composite;
+
+/**
+ * Delegate implementing the native methods of android.graphics.Xfermode
+ *
+ * Through the layoutlib_create tool, the original native methods of Xfermode 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 Xfermode class.
+ *
+ * This also serve as a base class for all Xfermode delegate classes.
+ *
+ * @see DelegateManager
+ *
+ */
+public abstract class Xfermode_Delegate {
+
+ // ---- delegate manager ----
+ protected static final DelegateManager<Xfermode_Delegate> sManager =
+ new DelegateManager<Xfermode_Delegate>(Xfermode_Delegate.class);
+
+ // ---- delegate helper data ----
+
+ // ---- delegate data ----
+
+ // ---- Public Helper methods ----
+
+ public static Xfermode_Delegate getDelegate(int native_instance) {
+ return sManager.getDelegate(native_instance);
+ }
+
+ public abstract Composite getComposite(int alpha);
+ public abstract boolean isSupported();
+ public abstract String getSupportMessage();
+
+
+ // ---- native methods ----
+
+ @LayoutlibDelegate
+ /*package*/ static void finalizer(int native_instance) {
+ sManager.removeJavaReferenceFor(native_instance);
+ }
+
+ // ---- Private delegate/helper methods ----
+
+}
diff --git a/tools/layoutlib/bridge/src/android/os/Build_Delegate.java b/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
new file mode 100644
index 0000000..ff82a5e
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/Build_Delegate.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2011 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.os;
+
+import com.android.layoutlib.bridge.Bridge;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import java.util.Map;
+
+/**
+ * Delegate implementing the native methods of android.os.Build
+ *
+ * Through the layoutlib_create tool, the original native methods of Build have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+public class Build_Delegate {
+
+ @LayoutlibDelegate
+ /*package*/ static String getString(String property) {
+ Map<String, String> properties = Bridge.getPlatformProperties();
+ String value = properties.get(property);
+ if (value != null) {
+ return value;
+ }
+
+ return Build.UNKNOWN;
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
new file mode 100644
index 0000000..2152c8a
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/Handler_Delegate.java
@@ -0,0 +1,57 @@
+/*
+ * 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.os;
+
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+
+/**
+ * Delegate overriding selected methods of android.os.Handler
+ *
+ * Through the layoutlib_create tool, selected methods of Handler have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ *
+ */
+public class Handler_Delegate {
+
+ // -------- Delegate methods
+
+ @LayoutlibDelegate
+ /*package*/ static boolean sendMessageAtTime(Handler handler, Message msg, long uptimeMillis) {
+ // get the callback
+ IHandlerCallback callback = sCallbacks.get();
+ if (callback != null) {
+ callback.sendMessageAtTime(handler, msg, uptimeMillis);
+ }
+ return true;
+ }
+
+ // -------- Delegate implementation
+
+ public interface IHandlerCallback {
+ void sendMessageAtTime(Handler handler, Message msg, long uptimeMillis);
+ }
+
+ private final static ThreadLocal<IHandlerCallback> sCallbacks =
+ new ThreadLocal<IHandlerCallback>();
+
+ public static void setCallback(IHandlerCallback callback) {
+ sCallbacks.set(callback);
+ }
+
+}
diff --git a/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
new file mode 100644
index 0000000..63711a7
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/os/SystemClock_Delegate.java
@@ -0,0 +1,71 @@
+/*
+ * 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.os;
+
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+/**
+ * Delegate implementing the native methods of android.os.SystemClock
+ *
+ * Through the layoutlib_create tool, the original native methods of SystemClock have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
+ *
+ */
+public class SystemClock_Delegate {
+ private static long sBootTime = System.currentTimeMillis();
+
+ @LayoutlibDelegate
+ /*package*/ static boolean setCurrentTimeMillis(long millis) {
+ return true;
+ }
+
+ /**
+ * Returns milliseconds since boot, not counting time spent in deep sleep.
+ * <b>Note:</b> This value may get reset occasionally (before it would
+ * otherwise wrap around).
+ *
+ * @return milliseconds of non-sleep uptime since boot.
+ */
+ @LayoutlibDelegate
+ /*package*/ static long uptimeMillis() {
+ return System.currentTimeMillis() - sBootTime;
+ }
+
+ /**
+ * Returns milliseconds since boot, including time spent in sleep.
+ *
+ * @return elapsed milliseconds since boot.
+ */
+ @LayoutlibDelegate
+ /*package*/ static long elapsedRealtime() {
+ return System.currentTimeMillis() - sBootTime;
+ }
+
+ /**
+ * Returns milliseconds running in the current thread.
+ *
+ * @return elapsed milliseconds in the thread
+ */
+ @LayoutlibDelegate
+ /*package*/ static long currentThreadTimeMillis() {
+ return System.currentTimeMillis();
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/util/FloatMath.java b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
index aae44f2..1df78c2 100644
--- a/tools/layoutlib/bridge/src/android/util/FloatMath.java
+++ b/tools/layoutlib/bridge/src/android/util/FloatMath_Delegate.java
@@ -16,20 +16,23 @@
package android.util;
+import com.android.layoutlib.bridge.impl.DelegateManager;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
/**
- * Reimplements _Original_FloatMath with the standard libraries.
- *
- * Math routines similar to those found in {@link java.lang.Math}. Performs
- * computations on {@code float} values directly without incurring the overhead
- * of conversions to and from {@code double}.
+ * Delegate implementing the native methods of android.util.FloatMath
+ *
+ * Through the layoutlib_create tool, the original native methods of FloatMath have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ * Because it's a stateless class to start with, there's no need to keep a {@link DelegateManager}
+ * around to map int to instance of the delegate.
*
- * <p>On one platform, {@code FloatMath.sqrt(100)} executes in one third of the
- * time required by {@code java.lang.Math.sqrt(100)}.</p>
*/
-public class FloatMath {
+/*package*/ final class FloatMath_Delegate {
/** Prevents instantiation. */
- private FloatMath() {}
+ private FloatMath_Delegate() {}
/**
* Returns the float conversion of the most positive (i.e. closest to
@@ -38,7 +41,8 @@ public class FloatMath {
* @param value to be converted
* @return the floor of value
*/
- public static float floor(float value) {
+ @LayoutlibDelegate
+ /*package*/ static float floor(float value) {
return (float)Math.floor(value);
}
@@ -49,7 +53,8 @@ public class FloatMath {
* @param value to be converted
* @return the ceiling of value
*/
- public static float ceil(float value) {
+ @LayoutlibDelegate
+ /*package*/ static float ceil(float value) {
return (float)Math.ceil(value);
}
@@ -59,7 +64,8 @@ public class FloatMath {
* @param angle to compute the cosine of, in radians
* @return the sine of angle
*/
- public static float sin(float angle) {
+ @LayoutlibDelegate
+ /*package*/ static float sin(float angle) {
return (float)Math.sin(angle);
}
@@ -69,7 +75,8 @@ public class FloatMath {
* @param angle to compute the cosine of, in radians
* @return the cosine of angle
*/
- public static float cos(float angle) {
+ @LayoutlibDelegate
+ /*package*/ static float cos(float angle) {
return (float)Math.cos(angle);
}
@@ -80,7 +87,8 @@ public class FloatMath {
* @param value to compute sqrt of
* @return the square root of value
*/
- public static float sqrt(float value) {
+ @LayoutlibDelegate
+ /*package*/ static float sqrt(float value) {
return (float)Math.sqrt(value);
}
}
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
deleted file mode 100644
index 0910d79..0000000
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * Copyright (C) 2008 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.view;
-
-import com.android.layoutlib.api.IProjectCallback;
-import com.android.layoutlib.api.IResourceValue;
-import com.android.layoutlib.bridge.Bridge;
-import com.android.layoutlib.bridge.BridgeConstants;
-import com.android.layoutlib.bridge.BridgeContext;
-import com.android.layoutlib.bridge.BridgeXmlBlockParser;
-
-import org.kxml2.io.KXmlParser;
-import org.xmlpull.v1.XmlPullParser;
-
-import android.content.Context;
-import android.util.AttributeSet;
-
-import java.io.File;
-import java.io.FileReader;
-
-/**
- * Custom implementation of {@link LayoutInflater} to handle custom views.
- */
-public final class BridgeInflater extends LayoutInflater {
-
- private final IProjectCallback mProjectCallback;
-
- /**
- * List of class prefixes which are tried first by default.
- * <p/>
- * This should match the list in com.android.internal.policy.impl.PhoneLayoutInflater.
- */
- private static final String[] sClassPrefixList = {
- "android.widget.",
- "android.webkit."
- };
-
- protected BridgeInflater(LayoutInflater original, Context newContext) {
- super(original, newContext);
- mProjectCallback = null;
- }
-
- /**
- * Instantiate a new BridgeInflater with an {@link IProjectCallback} object.
- *
- * @param context The Android application context.
- * @param projectCallback the {@link IProjectCallback} object.
- */
- public BridgeInflater(Context context, IProjectCallback projectCallback) {
- super(context);
- mProjectCallback = projectCallback;
- mConstructorArgs[0] = context;
- }
-
- @Override
- public View onCreateView(String name, AttributeSet attrs) throws ClassNotFoundException {
- View view = null;
-
- try {
- // First try to find a class using the default Android prefixes
- for (String prefix : sClassPrefixList) {
- try {
- view = createView(name, prefix, attrs);
- if (view != null) {
- break;
- }
- } catch (ClassNotFoundException e) {
- // Ignore. We'll try again using the base class below.
- }
- }
-
- // Next try using the parent loader. This will most likely only work for
- // fully-qualified class names.
- try {
- if (view == null) {
- view = super.onCreateView(name, attrs);
- }
- } catch (ClassNotFoundException e) {
- // Ignore. We'll try again using the custom view loader below.
- }
-
- // Finally try again using the custom view loader
- try {
- if (view == null) {
- view = loadCustomView(name, attrs);
- }
- } catch (ClassNotFoundException e) {
- // If the class was not found, we throw the exception directly, because this
- // method is already expected to throw it.
- throw e;
- }
- } catch (Exception e) {
- // Wrap the real exception in a ClassNotFoundException, so that the calling method
- // can deal with it.
- ClassNotFoundException exception = new ClassNotFoundException("onCreateView", e);
- throw exception;
- }
-
- setupViewInContext(view, attrs);
-
- return view;
- }
-
- @Override
- public View createViewFromTag(String name, AttributeSet attrs) {
- View view = null;
- try {
- view = super.createViewFromTag(name, attrs);
- } catch (InflateException e) {
- // try to load the class from using the custom view loader
- try {
- view = loadCustomView(name, attrs);
- } catch (Exception e2) {
- // Wrap the real exception in an InflateException so that the calling
- // method can deal with it.
- InflateException exception = new InflateException();
- if (e2.getClass().equals(ClassNotFoundException.class) == false) {
- exception.initCause(e2);
- } else {
- exception.initCause(e);
- }
- throw exception;
- }
- }
-
- setupViewInContext(view, attrs);
-
- return view;
- }
-
- @Override
- public View inflate(int resource, ViewGroup root) {
- Context context = getContext();
- if (context instanceof BridgeContext) {
- BridgeContext bridgeContext = (BridgeContext)context;
-
- IResourceValue value = null;
-
- String[] layoutInfo = Bridge.resolveResourceValue(resource);
- if (layoutInfo != null) {
- value = bridgeContext.getFrameworkResource(BridgeConstants.RES_LAYOUT,
- layoutInfo[0]);
- } else {
- layoutInfo = mProjectCallback.resolveResourceValue(resource);
-
- if (layoutInfo != null) {
- value = bridgeContext.getProjectResource(BridgeConstants.RES_LAYOUT,
- layoutInfo[0]);
- }
- }
-
- if (value != null) {
- File f = new File(value.getValue());
- if (f.isFile()) {
- try {
- KXmlParser parser = new KXmlParser();
- parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
- parser.setInput(new FileReader(f));
-
- BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
- parser, bridgeContext, false);
-
- return inflate(bridgeParser, root);
- } catch (Exception e) {
- bridgeContext.getLogger().error(e);
- // return null below.
- }
- }
- }
- }
- return null;
- }
-
- private View loadCustomView(String name, AttributeSet attrs) throws ClassNotFoundException,
- Exception{
- if (mProjectCallback != null) {
- // first get the classname in case it's not the node name
- if (name.equals("view")) {
- name = attrs.getAttributeValue(null, "class");
- }
-
- mConstructorArgs[1] = attrs;
-
- Object customView = mProjectCallback.loadView(name, mConstructorSignature,
- mConstructorArgs);
-
- if (customView instanceof View) {
- return (View)customView;
- }
- }
-
- return null;
- }
-
-
-
- private void setupViewInContext(View view, AttributeSet attrs) {
- if (getContext() instanceof BridgeContext) {
- BridgeContext bc = (BridgeContext) getContext();
- if (attrs instanceof BridgeXmlBlockParser) {
- Object viewKey = ((BridgeXmlBlockParser) attrs).getViewKey();
- if (viewKey != null) {
- bc.addViewKey(view, viewKey);
- }
- }
- }
- }
-
- @Override
- public LayoutInflater cloneInContext(Context newContext) {
- return new BridgeInflater(this, newContext);
- }
-}
diff --git a/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
new file mode 100644
index 0000000..0f3cf57
--- /dev/null
+++ b/tools/layoutlib/bridge/src/android/view/LayoutInflater_Delegate.java
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2011 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.view;
+
+import com.android.layoutlib.bridge.android.BridgeInflater;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.util.AttributeSet;
+
+import java.io.IOException;
+
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link LayoutInflater}
+ *
+ * Through the layoutlib_create tool, the original methods of LayoutInflater have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class LayoutInflater_Delegate {
+
+ /**
+ * Recursive method used to descend down the xml hierarchy and instantiate
+ * views, instantiate their children, and then call onFinishInflate().
+ */
+ @LayoutlibDelegate
+ /*package*/ static void rInflate(LayoutInflater thisInflater,
+ XmlPullParser parser, View parent, final AttributeSet attrs,
+ boolean finishInflate) throws XmlPullParserException, IOException {
+
+ if (finishInflate == false) {
+ // this is a merge rInflate!
+ if (thisInflater instanceof BridgeInflater) {
+ ((BridgeInflater) thisInflater).setIsInMerge(true);
+ }
+ }
+
+ // ---- START DEFAULT IMPLEMENTATION.
+
+ final int depth = parser.getDepth();
+ int type;
+
+ while (((type = parser.next()) != XmlPullParser.END_TAG ||
+ parser.getDepth() > depth) && type != XmlPullParser.END_DOCUMENT) {
+
+ if (type != XmlPullParser.START_TAG) {
+ continue;
+ }
+
+ final String name = parser.getName();
+
+ if (LayoutInflater.TAG_REQUEST_FOCUS.equals(name)) {
+ thisInflater.parseRequestFocus(parser, parent);
+ } else if (LayoutInflater.TAG_INCLUDE.equals(name)) {
+ if (parser.getDepth() == 0) {
+ throw new InflateException("<include /> cannot be the root element");
+ }
+ thisInflater.parseInclude(parser, parent, attrs);
+ } else if (LayoutInflater.TAG_MERGE.equals(name)) {
+ throw new InflateException("<merge /> must be the root element");
+ } else {
+ final View view = thisInflater.createViewFromTag(parent, name, attrs);
+ final ViewGroup viewGroup = (ViewGroup) parent;
+ final ViewGroup.LayoutParams params = viewGroup.generateLayoutParams(attrs);
+ thisInflater.rInflate(parser, view, attrs, true);
+ viewGroup.addView(view, params);
+ }
+ }
+
+ if (finishInflate) parent.onFinishInflate();
+
+ // ---- END DEFAULT IMPLEMENTATION.
+
+ if (finishInflate == false) {
+ // this is a merge rInflate!
+ if (thisInflater instanceof BridgeInflater) {
+ ((BridgeInflater) thisInflater).setIsInMerge(false);
+ }
+ }
+ }
+}
diff --git a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode.java b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
index 974ae49..8215f7c 100644
--- a/tools/layoutlib/bridge/src/android/graphics/PorterDuffXfermode.java
+++ b/tools/layoutlib/bridge/src/android/view/View_Delegate.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2008 The Android Open Source Project
+ * 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.
@@ -14,27 +14,21 @@
* limitations under the License.
*/
-package android.graphics;
+package android.view;
-import android.graphics.PorterDuff.Mode;
+import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
-public class PorterDuffXfermode extends Xfermode {
- private final Mode mMode;
+/**
+ * Delegate used to provide new implementation of a select few methods of {@link View}
+ *
+ * Through the layoutlib_create tool, the original methods of View have been replaced
+ * by calls to methods of the same name in this delegate class.
+ *
+ */
+public class View_Delegate {
- /**
- * Create an xfermode that uses the specified porter-duff mode.
- *
- * @param mode The porter-duff mode that is applied
- */
- public PorterDuffXfermode(PorterDuff.Mode mode) {
- mMode = mode;
- }
-
- //---------- Custom Methods
-
- public PorterDuff.Mode getMode() {
- return mMode;
+ @LayoutlibDelegate
+ /*package*/ static boolean isInEditMode(View thisView) {
+ return true;
}
-
- //----------
}