summaryrefslogtreecommitdiffstats
path: root/graphics
diff options
context:
space:
mode:
Diffstat (limited to 'graphics')
-rw-r--r--graphics/java/android/graphics/Bitmap.java11
-rw-r--r--graphics/java/android/graphics/BitmapFactory.java20
-rw-r--r--graphics/java/android/graphics/Camera.java2
-rw-r--r--graphics/java/android/graphics/Canvas.java672
-rw-r--r--graphics/java/android/graphics/NinePatch.java4
-rw-r--r--graphics/java/android/graphics/Paint.java167
-rw-r--r--graphics/java/android/graphics/Path.java105
-rw-r--r--graphics/java/android/graphics/Picture.java95
-rw-r--r--graphics/java/android/graphics/drawable/Animatable.java2
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java52
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java1
-rw-r--r--graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java331
-rw-r--r--graphics/java/android/graphics/drawable/AnimationDrawable.java47
-rw-r--r--graphics/java/android/graphics/drawable/BitmapDrawable.java73
-rw-r--r--graphics/java/android/graphics/drawable/ClipDrawable.java14
-rw-r--r--graphics/java/android/graphics/drawable/ColorDrawable.java70
-rw-r--r--graphics/java/android/graphics/drawable/Drawable.java64
-rw-r--r--graphics/java/android/graphics/drawable/DrawableContainer.java45
-rw-r--r--graphics/java/android/graphics/drawable/GradientDrawable.java51
-rw-r--r--graphics/java/android/graphics/drawable/InsetDrawable.java33
-rw-r--r--graphics/java/android/graphics/drawable/LayerDrawable.java11
-rw-r--r--graphics/java/android/graphics/drawable/MaterialProgressDrawable.java34
-rw-r--r--graphics/java/android/graphics/drawable/NinePatchDrawable.java38
-rw-r--r--graphics/java/android/graphics/drawable/PaintDrawable.java8
-rw-r--r--graphics/java/android/graphics/drawable/PictureDrawable.java16
-rw-r--r--graphics/java/android/graphics/drawable/Ripple.java10
-rw-r--r--graphics/java/android/graphics/drawable/RippleDrawable.java40
-rw-r--r--graphics/java/android/graphics/drawable/RotateDrawable.java7
-rw-r--r--graphics/java/android/graphics/drawable/ScaleDrawable.java7
-rw-r--r--graphics/java/android/graphics/drawable/ShapeDrawable.java166
-rw-r--r--graphics/java/android/graphics/drawable/StateListDrawable.java6
-rw-r--r--graphics/java/android/graphics/drawable/TransitionDrawable.java18
-rw-r--r--graphics/java/android/graphics/drawable/VectorDrawable.java1376
-rw-r--r--graphics/java/android/graphics/pdf/PdfRenderer.java2
34 files changed, 2113 insertions, 1485 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index 06cf253..ef0a411 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -194,6 +194,11 @@ public final class Bitmap implements Parcelable {
* while {@link #getAllocationByteCount()} will reflect that of the initial
* configuration.</p>
*
+ * <p>Note: This may change this result of hasAlpha(). When converting to 565,
+ * the new bitmap will always be considered opaque. When converting from 565,
+ * the new bitmap will be considered non-opaque, and will respect the value
+ * set by setPremultiplied().</p>
+ *
* <p>WARNING: This method should NOT be called on a bitmap currently used
* by the view system. It does not make guarantees about how the underlying
* pixel buffer is remapped to the new config, just that the allocation is
@@ -217,7 +222,8 @@ public final class Bitmap implements Parcelable {
throw new IllegalStateException("native-backed bitmaps may not be reconfigured");
}
- nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length);
+ nativeReconfigure(mNativeBitmap, width, height, config.nativeInt, mBuffer.length,
+ mIsPremultiplied);
mWidth = width;
mHeight = height;
}
@@ -1586,7 +1592,8 @@ public final class Bitmap implements Parcelable {
private static native void nativeDestructor(long nativeBitmap);
private static native boolean nativeRecycle(long nativeBitmap);
private static native void nativeReconfigure(long nativeBitmap, int width, int height,
- int config, int allocSize);
+ int config, int allocSize,
+ boolean isPremultiplied);
private static native boolean nativeCompress(long nativeBitmap, int format,
int quality, OutputStream stream,
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index c20502f..bc20ea5 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -260,7 +260,11 @@ public class BitmapFactory {
public boolean inScaled;
/**
- * If this is set to true, then the resulting bitmap will allocate its
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#L}, this is
+ * ignored.
+ *
+ * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, 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
@@ -287,14 +291,20 @@ public class BitmapFactory {
* android.graphics.BitmapFactory.Options)} or {@link #decodeFile(String,
* android.graphics.BitmapFactory.Options)}.</p>
*/
+ @Deprecated
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.
+ * @deprecated As of {@link android.os.Build.VERSION_CODES#L}, this is
+ * ignored.
+ *
+ * In {@link android.os.Build.VERSION_CODES#KITKAT} and below, 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.
*/
+ @Deprecated
public boolean inInputShareable;
/**
diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java
index a40085b..57e0f27 100644
--- a/graphics/java/android/graphics/Camera.java
+++ b/graphics/java/android/graphics/Camera.java
@@ -154,7 +154,7 @@ public class Camera {
getMatrix(mMatrix);
canvas.concat(mMatrix);
} else {
- nativeApplyToCanvas(canvas.getNativeCanvas());
+ nativeApplyToCanvas(canvas.getNativeCanvasWrapper());
}
}
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d4ea7a9..99596ef 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -16,11 +16,17 @@
package android.graphics;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.text.GraphicsOperations;
import android.text.SpannableString;
import android.text.SpannedString;
import android.text.TextUtils;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
import javax.microedition.khronos.opengles.GL;
/**
@@ -39,11 +45,11 @@ import javax.microedition.khronos.opengles.GL;
public class Canvas {
// assigned in constructors or setBitmap, freed in finalizer
- private long mNativeCanvas;
+ private long mNativeCanvasWrapper;
/** @hide */
- public long getNativeCanvas() {
- return mNativeCanvas;
+ public long getNativeCanvasWrapper() {
+ return mNativeCanvasWrapper;
}
// may be null
@@ -59,11 +65,11 @@ public class Canvas {
/**
* Used to determine when compatibility scaling is in effect.
- *
+ *
* @hide
*/
protected int mScreenDensity = Bitmap.DENSITY_NONE;
-
+
// Used by native code
@SuppressWarnings("UnusedDeclaration")
private int mSurfaceFormat;
@@ -73,7 +79,7 @@ public class Canvas {
* @hide
*/
public static final int DIRECTION_LTR = 0;
-
+
/**
* Flag for drawTextRun indicating right-to-left run direction.
* @hide
@@ -88,10 +94,10 @@ public class Canvas {
private final CanvasFinalizer mFinalizer;
private static final class CanvasFinalizer {
- private long mNativeCanvas;
+ private long mNativeCanvasWrapper;
public CanvasFinalizer(long nativeCanvas) {
- mNativeCanvas = nativeCanvas;
+ mNativeCanvasWrapper = nativeCanvas;
}
@Override
@@ -104,9 +110,9 @@ public class Canvas {
}
public void dispose() {
- if (mNativeCanvas != 0) {
- finalizer(mNativeCanvas);
- mNativeCanvas = 0;
+ if (mNativeCanvasWrapper != 0) {
+ finalizer(mNativeCanvasWrapper);
+ mNativeCanvasWrapper = 0;
}
}
}
@@ -120,8 +126,8 @@ public class Canvas {
public Canvas() {
if (!isHardwareAccelerated()) {
// 0 means no native bitmap
- mNativeCanvas = initRaster(0);
- mFinalizer = new CanvasFinalizer(mNativeCanvas);
+ mNativeCanvasWrapper = initRaster(0);
+ mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
} else {
mFinalizer = null;
}
@@ -130,19 +136,19 @@ public class Canvas {
/**
* Construct a canvas with the specified bitmap to draw into. The bitmap
* must be mutable.
- *
+ *
* <p>The initial target density of the canvas is the same as the given
* bitmap's density.
*
* @param bitmap Specifies a mutable bitmap for the canvas to draw into.
*/
- public Canvas(Bitmap bitmap) {
+ public Canvas(@NonNull Bitmap bitmap) {
if (!bitmap.isMutable()) {
throw new IllegalStateException("Immutable bitmap passed to Canvas constructor");
}
throwIfCannotDraw(bitmap);
- mNativeCanvas = initRaster(bitmap.ni());
- mFinalizer = new CanvasFinalizer(mNativeCanvas);
+ mNativeCanvasWrapper = initRaster(bitmap.ni());
+ mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
mBitmap = bitmap;
mDensity = bitmap.mDensity;
}
@@ -152,26 +158,12 @@ public class Canvas {
if (nativeCanvas == 0) {
throw new IllegalStateException();
}
- mNativeCanvas = nativeCanvas;
- mFinalizer = new CanvasFinalizer(mNativeCanvas);
+ mNativeCanvasWrapper = initCanvas(nativeCanvas);
+ mFinalizer = new CanvasFinalizer(mNativeCanvasWrapper);
mDensity = Bitmap.getDefaultDensity();
}
/**
- * Replace existing canvas while ensuring that the swap has occurred before
- * the previous native canvas is unreferenced.
- */
- private void safeCanvasSwap(long nativeCanvas, boolean copyState) {
- final long oldCanvas = mNativeCanvas;
- mNativeCanvas = nativeCanvas;
- mFinalizer.mNativeCanvas = nativeCanvas;
- if (copyState) {
- copyNativeCanvasState(oldCanvas, mNativeCanvas);
- }
- finalizer(oldCanvas);
- }
-
- /**
* Returns null.
*
* @deprecated This method is not supported and should not be invoked.
@@ -185,10 +177,10 @@ public class Canvas {
/**
* Indicates whether this Canvas uses hardware acceleration.
- *
+ *
* Note that this method does not define what type of hardware acceleration
* may or may not be used.
- *
+ *
* @return True if drawing operations are hardware accelerated,
* false otherwise.
*/
@@ -197,7 +189,7 @@ public class Canvas {
}
/**
- * Specify a bitmap for the canvas to draw into. All canvas state such as
+ * Specify a bitmap for the canvas to draw into. All canvas state such as
* layers, filters, and the save/restore stack are reset with the exception
* of the current matrix and clip stack. Additionally, as a side-effect
* the canvas' target density is updated to match that of the bitmap.
@@ -206,13 +198,13 @@ public class Canvas {
* @see #setDensity(int)
* @see #getDensity()
*/
- public void setBitmap(Bitmap bitmap) {
+ public void setBitmap(@Nullable Bitmap bitmap) {
if (isHardwareAccelerated()) {
throw new RuntimeException("Can't set a bitmap device on a GL canvas");
}
if (bitmap == null) {
- safeCanvasSwap(initRaster(0), false);
+ native_setBitmap(mNativeCanvasWrapper, 0, false);
mDensity = Bitmap.DENSITY_NONE;
} else {
if (!bitmap.isMutable()) {
@@ -220,7 +212,7 @@ public class Canvas {
}
throwIfCannotDraw(bitmap);
- safeCanvasSwap(initRaster(bitmap.ni()), true);
+ native_setBitmap(mNativeCanvasWrapper, bitmap.ni(), true);
mDensity = bitmap.mDensity;
}
@@ -228,6 +220,13 @@ public class Canvas {
}
/**
+ * setBitmap() variant for native callers with a raw bitmap handle.
+ */
+ private void setNativeBitmap(long bitmapHandle) {
+ native_setBitmap(mNativeCanvasWrapper, bitmapHandle, false);
+ }
+
+ /**
* Set the viewport dimensions if this canvas is GL based. If it is not,
* this method is ignored and no exception is thrown.
*
@@ -249,21 +248,27 @@ public class Canvas {
*
* @return true if the device that the current layer draws into is opaque
*/
- public native boolean isOpaque();
+ public boolean isOpaque() {
+ return native_isOpaque(mNativeCanvasWrapper);
+ }
/**
* Returns the width of the current drawing layer
*
* @return the width of the current drawing layer
*/
- public native int getWidth();
+ public int getWidth() {
+ return native_getWidth(mNativeCanvasWrapper);
+ }
/**
* Returns the height of the current drawing layer
*
* @return the height of the current drawing layer
*/
- public native int getHeight();
+ public int getHeight() {
+ return native_getHeight(mNativeCanvasWrapper);
+ }
/**
* <p>Returns the target density of the canvas. The default density is
@@ -274,7 +279,7 @@ public class Canvas {
* to determine the scaling factor when drawing a bitmap into it.
*
* @see #setDensity(int)
- * @see Bitmap#getDensity()
+ * @see Bitmap#getDensity()
*/
public int getDensity() {
return mDensity;
@@ -290,7 +295,7 @@ public class Canvas {
* {@link Bitmap#DENSITY_NONE} to disable bitmap scaling.
*
* @see #getDensity()
- * @see Bitmap#setDensity(int)
+ * @see Bitmap#setDensity(int)
*/
public void setDensity(int density) {
if (mBitmap != null) {
@@ -308,19 +313,19 @@ public class Canvas {
* Returns the maximum allowed width for bitmaps drawn with this canvas.
* Attempting to draw with a bitmap wider than this value will result
* in an error.
- *
- * @see #getMaximumBitmapHeight()
+ *
+ * @see #getMaximumBitmapHeight()
*/
public int getMaximumBitmapWidth() {
return MAXMIMUM_BITMAP_SIZE;
}
-
+
/**
* Returns the maximum allowed height for bitmaps drawn with this canvas.
* Attempting to draw with a bitmap taller than this value will result
* in an error.
- *
- * @see #getMaximumBitmapWidth()
+ *
+ * @see #getMaximumBitmapWidth()
*/
public int getMaximumBitmapHeight() {
return MAXMIMUM_BITMAP_SIZE;
@@ -328,6 +333,19 @@ public class Canvas {
// the SAVE_FLAG constants must match their native equivalents
+ /** @hide */
+ @IntDef(flag = true,
+ value = {
+ MATRIX_SAVE_FLAG,
+ CLIP_SAVE_FLAG,
+ HAS_ALPHA_LAYER_SAVE_FLAG,
+ FULL_COLOR_LAYER_SAVE_FLAG,
+ CLIP_TO_LAYER_SAVE_FLAG,
+ ALL_SAVE_FLAG
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface Saveflags {}
+
/** restore the current matrix when restore() is called */
public static final int MATRIX_SAVE_FLAG = 0x01;
/** restore the current clip when restore() is called */
@@ -339,8 +357,8 @@ public class Canvas {
/** clip against the layer's bounds */
public static final int CLIP_TO_LAYER_SAVE_FLAG = 0x10;
/** restore everything when restore() is called */
- public static final int ALL_SAVE_FLAG = 0x1F;
-
+ public static final int ALL_SAVE_FLAG = 0x1F;
+
/**
* Saves the current matrix and clip onto a private stack. Subsequent
* calls to translate,scale,rotate,skew,concat or clipRect,clipPath
@@ -350,8 +368,10 @@ public class Canvas {
*
* @return The value to pass to restoreToCount() to balance this save()
*/
- public native int save();
-
+ public int save() {
+ return native_save(mNativeCanvasWrapper, MATRIX_SAVE_FLAG | CLIP_SAVE_FLAG);
+ }
+
/**
* Based on saveFlags, can save the current matrix and clip onto a private
* stack. Subsequent calls to translate,scale,rotate,skew,concat or
@@ -363,7 +383,9 @@ public class Canvas {
* to save/restore
* @return The value to pass to restoreToCount() to balance this save()
*/
- public native int save(int saveFlags);
+ public int save(@Saveflags int saveFlags) {
+ return native_save(mNativeCanvasWrapper, saveFlags);
+ }
/**
* This behaves the same as save(), but in addition it allocates an
@@ -381,8 +403,9 @@ public class Canvas {
* @param saveFlags see _SAVE_FLAG constants
* @return value to pass to restoreToCount() to balance this save()
*/
- public int saveLayer(RectF bounds, Paint paint, int saveFlags) {
- return native_saveLayer(mNativeCanvas, bounds,
+ public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint, @Saveflags int saveFlags) {
+ return native_saveLayer(mNativeCanvasWrapper,
+ bounds.left, bounds.top, bounds.right, bounds.bottom,
paint != null ? paint.mNativePaint : 0,
saveFlags);
}
@@ -390,16 +413,16 @@ public class Canvas {
/**
* Convenience for saveLayer(bounds, paint, {@link #ALL_SAVE_FLAG})
*/
- public int saveLayer(RectF bounds, Paint paint) {
+ public int saveLayer(@Nullable RectF bounds, @Nullable Paint paint) {
return saveLayer(bounds, paint, ALL_SAVE_FLAG);
}
/**
* Helper version of saveLayer() that takes 4 values rather than a RectF.
*/
- public int saveLayer(float left, float top, float right, float bottom, Paint paint,
- int saveFlags) {
- return native_saveLayer(mNativeCanvas, left, top, right, bottom,
+ public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint,
+ @Saveflags int saveFlags) {
+ return native_saveLayer(mNativeCanvasWrapper, left, top, right, bottom,
paint != null ? paint.mNativePaint : 0,
saveFlags);
}
@@ -407,7 +430,7 @@ public class Canvas {
/**
* Convenience for saveLayer(left, top, right, bottom, paint, {@link #ALL_SAVE_FLAG})
*/
- public int saveLayer(float left, float top, float right, float bottom, Paint paint) {
+ public int saveLayer(float left, float top, float right, float bottom, @Nullable Paint paint) {
return saveLayer(left, top, right, bottom, paint, ALL_SAVE_FLAG);
}
@@ -427,15 +450,17 @@ public class Canvas {
* @param saveFlags see _SAVE_FLAG constants
* @return value to pass to restoreToCount() to balance this call
*/
- public int saveLayerAlpha(RectF bounds, int alpha, int saveFlags) {
+ public int saveLayerAlpha(@NonNull RectF bounds, int alpha, @Saveflags int saveFlags) {
alpha = Math.min(255, Math.max(0, alpha));
- return native_saveLayerAlpha(mNativeCanvas, bounds, alpha, saveFlags);
+ return native_saveLayerAlpha(mNativeCanvasWrapper,
+ bounds.left, bounds.top, bounds.right, bounds.bottom,
+ alpha, saveFlags);
}
/**
* Convenience for saveLayerAlpha(bounds, alpha, {@link #ALL_SAVE_FLAG})
*/
- public int saveLayerAlpha(RectF bounds, int alpha) {
+ public int saveLayerAlpha(@NonNull RectF bounds, int alpha) {
return saveLayerAlpha(bounds, alpha, ALL_SAVE_FLAG);
}
@@ -443,8 +468,8 @@ public class Canvas {
* Helper for saveLayerAlpha() that takes 4 values instead of a RectF.
*/
public int saveLayerAlpha(float left, float top, float right, float bottom, int alpha,
- int saveFlags) {
- return native_saveLayerAlpha(mNativeCanvas, left, top, right, bottom,
+ @Saveflags int saveFlags) {
+ return native_saveLayerAlpha(mNativeCanvasWrapper, left, top, right, bottom,
alpha, saveFlags);
}
@@ -460,13 +485,17 @@ public class Canvas {
* modifications to the matrix/clip state since the last save call. It is
* an error to call restore() more times than save() was called.
*/
- public native void restore();
+ public void restore() {
+ native_restore(mNativeCanvasWrapper);
+ }
/**
* Returns the number of matrix/clip states on the Canvas' private stack.
* This will equal # save() calls - # restore() calls.
*/
- public native int getSaveCount();
+ public int getSaveCount() {
+ return native_getSaveCount(mNativeCanvasWrapper);
+ }
/**
* Efficient way to pop any calls to save() that happened after the save
@@ -481,7 +510,9 @@ public class Canvas {
*
* @param saveCount The save level to restore to.
*/
- public native void restoreToCount(int saveCount);
+ public void restoreToCount(int saveCount) {
+ native_restoreToCount(mNativeCanvasWrapper, saveCount);
+ }
/**
* Preconcat the current matrix with the specified translation
@@ -489,7 +520,9 @@ public class Canvas {
* @param dx The distance to translate in X
* @param dy The distance to translate in Y
*/
- public native void translate(float dx, float dy);
+ public void translate(float dx, float dy) {
+ native_translate(mNativeCanvasWrapper, dx, dy);
+ }
/**
* Preconcat the current matrix with the specified scale.
@@ -497,7 +530,9 @@ public class Canvas {
* @param sx The amount to scale in X
* @param sy The amount to scale in Y
*/
- public native void scale(float sx, float sy);
+ public void scale(float sx, float sy) {
+ native_scale(mNativeCanvasWrapper, sx, sy);
+ }
/**
* Preconcat the current matrix with the specified scale.
@@ -518,7 +553,9 @@ public class Canvas {
*
* @param degrees The amount to rotate, in degrees
*/
- public native void rotate(float degrees);
+ public void rotate(float degrees) {
+ native_rotate(mNativeCanvasWrapper, degrees);
+ }
/**
* Preconcat the current matrix with the specified rotation.
@@ -539,7 +576,9 @@ public class Canvas {
* @param sx The amount to skew in X
* @param sy The amount to skew in Y
*/
- public native void skew(float sx, float sy);
+ public void skew(float sx, float sy) {
+ native_skew(mNativeCanvasWrapper, sx, sy);
+ }
/**
* Preconcat the current matrix with the specified matrix. If the specified
@@ -547,35 +586,35 @@ public class Canvas {
*
* @param matrix The matrix to preconcatenate with the current matrix
*/
- public void concat(Matrix matrix) {
- if (matrix != null) native_concat(mNativeCanvas, matrix.native_instance);
+ public void concat(@Nullable Matrix matrix) {
+ if (matrix != null) native_concat(mNativeCanvasWrapper, matrix.native_instance);
}
-
+
/**
* Completely replace the current matrix with the specified matrix. If the
* matrix parameter is null, then the current matrix is reset to identity.
- *
+ *
* <strong>Note:</strong> it is recommended to use {@link #concat(Matrix)},
* {@link #scale(float, float)}, {@link #translate(float, float)} and
* {@link #rotate(float)} instead of this method.
*
* @param matrix The matrix to replace the current matrix with. If it is
* null, set the current matrix to identity.
- *
- * @see #concat(Matrix)
+ *
+ * @see #concat(Matrix)
*/
- public void setMatrix(Matrix matrix) {
- native_setMatrix(mNativeCanvas,
+ public void setMatrix(@Nullable Matrix matrix) {
+ native_setMatrix(mNativeCanvasWrapper,
matrix == null ? 0 : matrix.native_instance);
}
-
+
/**
* Return, in ctm, the current transformation matrix. This does not alter
* the matrix in the canvas, but just returns a copy of it.
*/
@Deprecated
- public void getMatrix(Matrix ctm) {
- native_getCTM(mNativeCanvas, ctm.native_instance);
+ public void getMatrix(@NonNull Matrix ctm) {
+ native_getCTM(mNativeCanvasWrapper, ctm.native_instance);
}
/**
@@ -583,13 +622,13 @@ public class Canvas {
* matrix.
*/
@Deprecated
- public final Matrix getMatrix() {
+ public final @NonNull Matrix getMatrix() {
Matrix m = new Matrix();
//noinspection deprecation
getMatrix(m);
return m;
}
-
+
/**
* Modify the current clip with the specified rectangle.
*
@@ -597,8 +636,8 @@ public class Canvas {
* @param op How the clip is modified
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(RectF rect, Region.Op op) {
- return native_clipRect(mNativeCanvas, rect.left, rect.top, rect.right, rect.bottom,
+ public boolean clipRect(@NonNull RectF rect, @NonNull Region.Op op) {
+ return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
op.nativeInt);
}
@@ -610,8 +649,8 @@ public class Canvas {
* @param op How the clip is modified
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(Rect rect, Region.Op op) {
- return native_clipRect(mNativeCanvas, rect.left, rect.top, rect.right, rect.bottom,
+ public boolean clipRect(@NonNull Rect rect, @NonNull Region.Op op) {
+ return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
op.nativeInt);
}
@@ -622,8 +661,11 @@ public class Canvas {
* @param rect The rectangle to intersect with the current clip.
* @return true if the resulting clip is non-empty
*/
- public native boolean clipRect(RectF rect);
-
+ public boolean clipRect(@NonNull RectF rect) {
+ return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
+ Region.Op.INTERSECT.nativeInt);
+ }
+
/**
* Intersect the current clip with the specified rectangle, which is
* expressed in local coordinates.
@@ -631,8 +673,11 @@ public class Canvas {
* @param rect The rectangle to intersect with the current clip.
* @return true if the resulting clip is non-empty
*/
- public native boolean clipRect(Rect rect);
-
+ public boolean clipRect(@NonNull Rect rect) {
+ return native_clipRect(mNativeCanvasWrapper, rect.left, rect.top, rect.right, rect.bottom,
+ Region.Op.INTERSECT.nativeInt);
+ }
+
/**
* Modify the current clip with the specified rectangle, which is
* expressed in local coordinates.
@@ -648,8 +693,9 @@ public class Canvas {
* @param op How the clip is modified
* @return true if the resulting clip is non-empty
*/
- public boolean clipRect(float left, float top, float right, float bottom, Region.Op op) {
- return native_clipRect(mNativeCanvas, left, top, right, bottom, op.nativeInt);
+ public boolean clipRect(float left, float top, float right, float bottom,
+ @NonNull Region.Op op) {
+ return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom, op.nativeInt);
}
/**
@@ -665,7 +711,10 @@ public class Canvas {
* clip
* @return true if the resulting clip is non-empty
*/
- public native boolean clipRect(float left, float top, float right, float bottom);
+ public boolean clipRect(float left, float top, float right, float bottom) {
+ return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom,
+ Region.Op.INTERSECT.nativeInt);
+ }
/**
* Intersect the current clip with the specified rectangle, which is
@@ -680,7 +729,10 @@ public class Canvas {
* clip
* @return true if the resulting clip is non-empty
*/
- public native boolean clipRect(int left, int top, int right, int bottom);
+ public boolean clipRect(int left, int top, int right, int bottom) {
+ return native_clipRect(mNativeCanvasWrapper, left, top, right, bottom,
+ Region.Op.INTERSECT.nativeInt);
+ }
/**
* Modify the current clip with the specified path.
@@ -689,20 +741,20 @@ public class Canvas {
* @param op How the clip is modified
* @return true if the resulting is non-empty
*/
- public boolean clipPath(Path path, Region.Op op) {
- return native_clipPath(mNativeCanvas, path.ni(), op.nativeInt);
+ public boolean clipPath(@NonNull Path path, @NonNull Region.Op op) {
+ return native_clipPath(mNativeCanvasWrapper, path.ni(), op.nativeInt);
}
-
+
/**
* Intersect the current clip with the specified path.
*
* @param path The path to intersect with the current clip
* @return true if the resulting is non-empty
*/
- public boolean clipPath(Path path) {
+ public boolean clipPath(@NonNull Path path) {
return clipPath(path, Region.Op.INTERSECT);
}
-
+
/**
* Modify the current clip with the specified region. Note that unlike
* clipRect() and clipPath() which transform their arguments by the
@@ -713,9 +765,12 @@ public class Canvas {
* @param region The region to operate on the current clip, based on op
* @param op How the clip is modified
* @return true if the resulting is non-empty
+ *
+ * @deprecated Unlike all other clip calls this API does not respect the
+ * current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
- public boolean clipRegion(Region region, Region.Op op) {
- return native_clipRegion(mNativeCanvas, region.ni(), op.nativeInt);
+ public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
+ return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
}
/**
@@ -727,22 +782,25 @@ public class Canvas {
*
* @param region The region to operate on the current clip, based on op
* @return true if the resulting is non-empty
+ *
+ * @deprecated Unlike all other clip calls this API does not respect the
+ * current matrix. Use {@link #clipRect(Rect)} as an alternative.
*/
- public boolean clipRegion(Region region) {
+ public boolean clipRegion(@NonNull Region region) {
return clipRegion(region, Region.Op.INTERSECT);
}
-
- public DrawFilter getDrawFilter() {
+
+ public @Nullable DrawFilter getDrawFilter() {
return mDrawFilter;
}
-
- public void setDrawFilter(DrawFilter filter) {
+
+ public void setDrawFilter(@Nullable DrawFilter filter) {
long nativeFilter = 0;
if (filter != null) {
nativeFilter = filter.mNativeInt;
}
mDrawFilter = filter;
- nativeSetDrawFilter(mNativeCanvas, nativeFilter);
+ nativeSetDrawFilter(mNativeCanvasWrapper, nativeFilter);
}
public enum EdgeType {
@@ -756,7 +814,7 @@ public class Canvas {
* Antialiased: Treat edges by rounding-out, since they may be antialiased
*/
AA(1);
-
+
EdgeType(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -780,8 +838,9 @@ public class Canvas {
* @return true if the rect (transformed by the canvas' matrix)
* does not intersect with the canvas' clip
*/
- public boolean quickReject(RectF rect, EdgeType type) {
- return native_quickReject(mNativeCanvas, rect);
+ public boolean quickReject(@NonNull RectF rect, @NonNull EdgeType type) {
+ return native_quickReject(mNativeCanvasWrapper,
+ rect.left, rect.top, rect.right, rect.bottom);
}
/**
@@ -799,8 +858,8 @@ public class Canvas {
* @return true if the path (transformed by the canvas' matrix)
* does not intersect with the canvas' clip
*/
- public boolean quickReject(Path path, EdgeType type) {
- return native_quickReject(mNativeCanvas, path.ni());
+ public boolean quickReject(@NonNull Path path, @NonNull EdgeType type) {
+ return native_quickReject(mNativeCanvasWrapper, path.ni());
}
/**
@@ -824,8 +883,8 @@ public class Canvas {
* does not intersect with the canvas' clip
*/
public boolean quickReject(float left, float top, float right, float bottom,
- EdgeType type) {
- return native_quickReject(mNativeCanvas, left, top, right, bottom);
+ @NonNull EdgeType type) {
+ return native_quickReject(mNativeCanvasWrapper, left, top, right, bottom);
}
/**
@@ -838,21 +897,21 @@ public class Canvas {
* still return true if the current clip is non-empty.
* @return true if the current clip is non-empty.
*/
- public boolean getClipBounds(Rect bounds) {
- return native_getClipBounds(mNativeCanvas, bounds);
+ public boolean getClipBounds(@Nullable Rect bounds) {
+ return native_getClipBounds(mNativeCanvasWrapper, bounds);
}
-
+
/**
* Retrieve the bounds of the current clip (in local coordinates).
*
* @return the clip bounds, or [0, 0, 0, 0] if the clip is empty.
*/
- public final Rect getClipBounds() {
+ public final @NonNull Rect getClipBounds() {
Rect r = new Rect();
getClipBounds(r);
return r;
}
-
+
/**
* Fill the entire canvas' bitmap (restricted to the current clip) with the
* specified RGB color, using srcover porterduff mode.
@@ -862,7 +921,7 @@ public class Canvas {
* @param b blue component (0..255) of the color to draw onto the canvas
*/
public void drawRGB(int r, int g, int b) {
- native_drawRGB(mNativeCanvas, r, g, b);
+ native_drawRGB(mNativeCanvasWrapper, r, g, b);
}
/**
@@ -875,7 +934,7 @@ public class Canvas {
* @param b blue component (0..255) of the color to draw onto the canvas
*/
public void drawARGB(int a, int r, int g, int b) {
- native_drawARGB(mNativeCanvas, a, r, g, b);
+ native_drawARGB(mNativeCanvasWrapper, a, r, g, b);
}
/**
@@ -885,7 +944,7 @@ public class Canvas {
* @param color the color to draw onto the canvas
*/
public void drawColor(int color) {
- native_drawColor(mNativeCanvas, color);
+ native_drawColor(mNativeCanvasWrapper, color);
}
/**
@@ -895,8 +954,8 @@ public class Canvas {
* @param color the color to draw with
* @param mode the porter-duff mode to apply to the color
*/
- public void drawColor(int color, PorterDuff.Mode mode) {
- native_drawColor(mNativeCanvas, color, mode.nativeInt);
+ public void drawColor(int color, @NonNull PorterDuff.Mode mode) {
+ native_drawColor(mNativeCanvasWrapper, color, mode.nativeInt);
}
/**
@@ -906,10 +965,10 @@ public class Canvas {
*
* @param paint The paint used to draw onto the canvas
*/
- public void drawPaint(Paint paint) {
- native_drawPaint(mNativeCanvas, paint.mNativePaint);
+ public void drawPaint(@NonNull Paint paint) {
+ native_drawPaint(mNativeCanvasWrapper, paint.mNativePaint);
}
-
+
/**
* Draw a series of points. Each point is centered at the coordinate
* specified by pts[], and its diameter is specified by the paint's stroke
@@ -926,19 +985,23 @@ public class Canvas {
* "points" that are drawn is really (count >> 1).
* @param paint The paint used to draw the points
*/
- public native void drawPoints(float[] pts, int offset, int count, Paint paint);
+ public void drawPoints(float[] pts, int offset, int count, @NonNull Paint paint) {
+ native_drawPoints(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint);
+ }
/**
* Helper for drawPoints() that assumes you want to draw the entire array
*/
- public void drawPoints(float[] pts, Paint paint) {
+ public void drawPoints(@NonNull float[] pts, @NonNull Paint paint) {
drawPoints(pts, 0, pts.length, paint);
}
/**
* Helper for drawPoints() for drawing a single point.
*/
- public native void drawPoint(float x, float y, Paint paint);
+ public void drawPoint(float x, float y, @NonNull Paint paint) {
+ native_drawPoint(mNativeCanvasWrapper, x, y, paint.mNativePaint);
+ }
/**
* Draw a line segment with the specified start and stop x,y coordinates,
@@ -952,8 +1015,9 @@ public class Canvas {
* @param startY The y-coordinate of the start point of the line
* @param paint The paint used to draw the line
*/
- public void drawLine(float startX, float startY, float stopX, float stopY, Paint paint) {
- native_drawLine(mNativeCanvas, startX, startY, stopX, stopY, paint.mNativePaint);
+ public void drawLine(float startX, float startY, float stopX, float stopY,
+ @NonNull Paint paint) {
+ native_drawLine(mNativeCanvasWrapper, startX, startY, stopX, stopY, paint.mNativePaint);
}
/**
@@ -971,9 +1035,11 @@ public class Canvas {
* (count >> 2).
* @param paint The paint used to draw the points
*/
- public native void drawLines(float[] pts, int offset, int count, Paint paint);
+ public void drawLines(float[] pts, int offset, int count, Paint paint) {
+ native_drawLines(mNativeCanvasWrapper, pts, offset, count, paint.mNativePaint);
+ }
- public void drawLines(float[] pts, Paint paint) {
+ public void drawLines(@NonNull float[] pts, @NonNull Paint paint) {
drawLines(pts, 0, pts.length, paint);
}
@@ -984,8 +1050,9 @@ public class Canvas {
* @param rect The rect to be drawn
* @param paint The paint used to draw the rect
*/
- public void drawRect(RectF rect, Paint paint) {
- native_drawRect(mNativeCanvas, rect, paint.mNativePaint);
+ public void drawRect(@NonNull RectF rect, @NonNull Paint paint) {
+ native_drawRect(mNativeCanvasWrapper,
+ rect.left, rect.top, rect.right, rect.bottom, paint.mNativePaint);
}
/**
@@ -995,10 +1062,10 @@ public class Canvas {
* @param r The rectangle to be drawn.
* @param paint The paint used to draw the rectangle
*/
- public void drawRect(Rect r, Paint paint) {
+ public void drawRect(@NonNull Rect r, @NonNull Paint paint) {
drawRect(r.left, r.top, r.right, r.bottom, paint);
}
-
+
/**
* Draw the specified Rect using the specified paint. The rectangle will
@@ -1010,8 +1077,8 @@ public class Canvas {
* @param bottom The bottom side of the rectangle to be drawn
* @param paint The paint used to draw the rect
*/
- public void drawRect(float left, float top, float right, float bottom, Paint paint) {
- native_drawRect(mNativeCanvas, left, top, right, bottom, paint.mNativePaint);
+ public void drawRect(float left, float top, float right, float bottom, @NonNull Paint paint) {
+ native_drawRect(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint);
}
/**
@@ -1020,11 +1087,19 @@ public class Canvas {
*
* @param oval The rectangle bounds of the oval to be drawn
*/
- public void drawOval(RectF oval, Paint paint) {
+ public void drawOval(@NonNull RectF oval, @NonNull Paint paint) {
if (oval == null) {
throw new NullPointerException();
}
- native_drawOval(mNativeCanvas, oval, paint.mNativePaint);
+ drawOval(oval.left, oval.top, oval.right, oval.bottom, paint);
+ }
+
+ /**
+ * Draw the specified oval using the specified paint. The oval will be
+ * filled or framed based on the Style in the paint.
+ */
+ public void drawOval(float left, float top, float right, float bottom, @NonNull Paint paint) {
+ native_drawOval(mNativeCanvasWrapper, left, top, right, bottom, paint.mNativePaint);
}
/**
@@ -1037,22 +1112,22 @@ public class Canvas {
* @param radius The radius of the cirle to be drawn
* @param paint The paint used to draw the circle
*/
- public void drawCircle(float cx, float cy, float radius, Paint paint) {
- native_drawCircle(mNativeCanvas, cx, cy, radius, paint.mNativePaint);
+ public void drawCircle(float cx, float cy, float radius, @NonNull Paint paint) {
+ native_drawCircle(mNativeCanvasWrapper, cx, cy, radius, paint.mNativePaint);
}
/**
* <p>Draw the specified arc, which will be scaled to fit inside the
* specified oval.</p>
- *
+ *
* <p>If the start angle is negative or >= 360, the start angle is treated
* as start angle modulo 360.</p>
- *
+ *
* <p>If the sweep angle is >= 360, then the oval is drawn
* completely. Note that this differs slightly from SkPath::arcTo, which
* treats the sweep angle modulo 360. If the sweep angle is negative,
* the sweep angle is treated as sweep angle modulo 360</p>
- *
+ *
* <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
* geometric angle of 0 degrees (3 o'clock on a watch.)</p>
*
@@ -1064,12 +1139,36 @@ public class Canvas {
close it if it is being stroked. This will draw a wedge
* @param paint The paint used to draw the arc
*/
- public void drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter,
- Paint paint) {
- if (oval == null) {
- throw new NullPointerException();
- }
- native_drawArc(mNativeCanvas, oval, startAngle, sweepAngle,
+ public void drawArc(@NonNull RectF oval, float startAngle, float sweepAngle, boolean useCenter,
+ @NonNull Paint paint) {
+ drawArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, useCenter,
+ paint);
+ }
+
+ /**
+ * <p>Draw the specified arc, which will be scaled to fit inside the
+ * specified oval.</p>
+ *
+ * <p>If the start angle is negative or >= 360, the start angle is treated
+ * as start angle modulo 360.</p>
+ *
+ * <p>If the sweep angle is >= 360, then the oval is drawn
+ * completely. Note that this differs slightly from SkPath::arcTo, which
+ * treats the sweep angle modulo 360. If the sweep angle is negative,
+ * the sweep angle is treated as sweep angle modulo 360</p>
+ *
+ * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the
+ * geometric angle of 0 degrees (3 o'clock on a watch.)</p>
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ * @param useCenter If true, include the center of the oval in the arc, and
+ close it if it is being stroked. This will draw a wedge
+ * @param paint The paint used to draw the arc
+ */
+ public void drawArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, boolean useCenter, @NonNull Paint paint) {
+ native_drawArc(mNativeCanvasWrapper, left, top, right, bottom, startAngle, sweepAngle,
useCenter, paint.mNativePaint);
}
@@ -1082,7 +1181,7 @@ public class Canvas {
* @param ry The y-radius of the oval used to round the corners
* @param paint The paint used to draw the roundRect
*/
- public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
+ public void drawRoundRect(@NonNull RectF rect, float rx, float ry, @NonNull Paint paint) {
drawRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, paint);
}
@@ -1095,8 +1194,8 @@ public class Canvas {
* @param paint The paint used to draw the roundRect
*/
public void drawRoundRect(float left, float top, float right, float bottom, float rx, float ry,
- Paint paint) {
- native_drawRoundRect(mNativeCanvas, left, top, right, bottom, rx, ry, paint.mNativePaint);
+ @NonNull Paint paint) {
+ native_drawRoundRect(mNativeCanvasWrapper, left, top, right, bottom, rx, ry, paint.mNativePaint);
}
/**
@@ -1106,8 +1205,8 @@ public class Canvas {
* @param path The path to be drawn
* @param paint The paint used to draw the path
*/
- public void drawPath(Path path, Paint paint) {
- native_drawPath(mNativeCanvas, path.ni(), paint.mNativePaint);
+ public void drawPath(@NonNull Path path, @NonNull Paint paint) {
+ native_drawPath(mNativeCanvasWrapper, path.ni(), paint.mNativePaint);
}
/**
@@ -1130,10 +1229,10 @@ public class Canvas {
* @param patch The ninepatch object to render
* @param dst The destination rectangle.
* @param paint The paint to draw the bitmap with. may be null
- *
+ *
* @hide
*/
- public void drawPatch(NinePatch patch, Rect dst, Paint paint) {
+ public void drawPatch(@NonNull NinePatch patch, @NonNull Rect dst, @Nullable Paint paint) {
patch.drawSoftware(this, dst, paint);
}
@@ -1146,14 +1245,14 @@ public class Canvas {
*
* @hide
*/
- public void drawPatch(NinePatch patch, RectF dst, Paint paint) {
+ public void drawPatch(@NonNull NinePatch patch, @NonNull RectF dst, @Nullable Paint paint) {
patch.drawSoftware(this, dst, paint);
}
/**
* Draw the specified bitmap, with its top/left corner at (x,y), using
* the specified paint, transformed by the current matrix.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1163,15 +1262,15 @@ public class Canvas {
* <p>If the bitmap and canvas have different densities, this function
* will take care of automatically scaling the bitmap to draw at the
* same density as the canvas.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param left The position of the left side of the bitmap being drawn
* @param top The position of the top side of the bitmap being drawn
* @param paint The paint used to draw the bitmap (may be null)
*/
- public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
+ public void drawBitmap(@NonNull Bitmap bitmap, float left, float top, @Nullable Paint paint) {
throwIfCannotDraw(bitmap);
- native_drawBitmap(mNativeCanvas, bitmap.ni(), left, top,
+ native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), left, top,
paint != null ? paint.mNativePaint : 0, mDensity, mScreenDensity, bitmap.mDensity);
}
@@ -1179,7 +1278,7 @@ public class Canvas {
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1190,19 +1289,20 @@ public class Canvas {
* This is because the source and destination rectangle coordinate
* spaces are in their respective densities, so must already have the
* appropriate scaling factor applied.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
* to fit into
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
+ public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull RectF dst,
+ @Nullable Paint paint) {
if (dst == null) {
throw new NullPointerException();
}
throwIfCannotDraw(bitmap);
- native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
+ native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), src, dst,
paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
}
@@ -1210,7 +1310,7 @@ public class Canvas {
* Draw the specified bitmap, scaling/translating automatically to fill
* the destination rectangle. If the source rectangle is not null, it
* specifies the subset of the bitmap to draw.
- *
+ *
* <p>Note: if the paint contains a maskfilter that generates a mask which
* extends beyond the bitmap's original width/height (e.g. BlurMaskFilter),
* then the bitmap will be drawn as if it were in a Shader with CLAMP mode.
@@ -1221,22 +1321,23 @@ public class Canvas {
* This is because the source and destination rectangle coordinate
* spaces are in their respective densities, so must already have the
* appropriate scaling factor applied.
- *
+ *
* @param bitmap The bitmap to be drawn
* @param src May be null. The subset of the bitmap to be drawn
* @param dst The rectangle that the bitmap will be scaled/translated
* to fit into
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
+ public void drawBitmap(@NonNull Bitmap bitmap, @Nullable Rect src, @NonNull Rect dst,
+ @Nullable Paint paint) {
if (dst == null) {
throw new NullPointerException();
}
throwIfCannotDraw(bitmap);
- native_drawBitmap(mNativeCanvas, bitmap.ni(), src, dst,
+ native_drawBitmap(mNativeCanvasWrapper, bitmap.ni(), src, dst,
paint != null ? paint.mNativePaint : 0, mScreenDensity, bitmap.mDensity);
}
-
+
/**
* Treat the specified array of colors as a bitmap, and draw it. This gives
* the same result as first creating a bitmap from the array, and then
@@ -1262,8 +1363,8 @@ public class Canvas {
* and copies of pixel data.
*/
@Deprecated
- public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
- int width, int height, boolean hasAlpha, Paint paint) {
+ public void drawBitmap(@NonNull int[] colors, int offset, int stride, float x, float y,
+ int width, int height, boolean hasAlpha, @Nullable Paint paint) {
// check for valid input
if (width < 0) {
throw new IllegalArgumentException("width must be >= 0");
@@ -1285,7 +1386,7 @@ public class Canvas {
return;
}
// punch down to native for the actual draw
- native_drawBitmap(mNativeCanvas, colors, offset, stride, x, y, width, height, hasAlpha,
+ native_drawBitmap(mNativeCanvasWrapper, colors, offset, stride, x, y, width, height, hasAlpha,
paint != null ? paint.mNativePaint : 0);
}
@@ -1298,8 +1399,8 @@ public class Canvas {
* and copies of pixel data.
*/
@Deprecated
- public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
- int width, int height, boolean hasAlpha, Paint paint) {
+ public void drawBitmap(@NonNull int[] colors, int offset, int stride, int x, int y,
+ int width, int height, boolean hasAlpha, @Nullable Paint paint) {
// call through to the common float version
drawBitmap(colors, offset, stride, (float)x, (float)y, width, height,
hasAlpha, paint);
@@ -1312,8 +1413,8 @@ public class Canvas {
* @param matrix The matrix used to transform the bitmap when it is drawn
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
- nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(),
+ public void drawBitmap(@NonNull Bitmap bitmap, @NonNull Matrix matrix, @Nullable Paint paint) {
+ nativeDrawBitmapMatrix(mNativeCanvasWrapper, bitmap.ni(), matrix.ni(),
paint != null ? paint.mNativePaint : 0);
}
@@ -1325,7 +1426,7 @@ public class Canvas {
throw new ArrayIndexOutOfBoundsException();
}
}
-
+
/**
* Draw the bitmap through the mesh, where mesh vertices are evenly
* distributed across the bitmap. There are meshWidth+1 vertices across, and
@@ -1352,8 +1453,9 @@ public class Canvas {
* @param colorOffset Number of color elements to skip before drawing
* @param paint May be null. The paint used to draw the bitmap
*/
- public void drawBitmapMesh(Bitmap bitmap, int meshWidth, int meshHeight,
- float[] verts, int vertOffset, int[] colors, int colorOffset, Paint paint) {
+ public void drawBitmapMesh(@NonNull Bitmap bitmap, int meshWidth, int meshHeight,
+ @NonNull float[] verts, int vertOffset, @Nullable int[] colors, int colorOffset,
+ @Nullable Paint paint) {
if ((meshWidth | meshHeight | vertOffset | colorOffset) < 0) {
throw new ArrayIndexOutOfBoundsException();
}
@@ -1367,7 +1469,7 @@ public class Canvas {
// no mul by 2, since we need only 1 color per vertex
checkRange(colors.length, colorOffset, count);
}
- nativeDrawBitmapMesh(mNativeCanvas, bitmap.ni(), meshWidth, meshHeight,
+ nativeDrawBitmapMesh(mNativeCanvasWrapper, bitmap.ni(), meshWidth, meshHeight,
verts, vertOffset, colors, colorOffset,
paint != null ? paint.mNativePaint : 0);
}
@@ -1376,7 +1478,7 @@ public class Canvas {
TRIANGLES(0),
TRIANGLE_STRIP(1),
TRIANGLE_FAN(2);
-
+
VertexMode(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -1386,7 +1488,7 @@ public class Canvas {
*/
public final int nativeInt;
}
-
+
/**
* Draw the array of vertices, interpreted as triangles (based on mode). The
* verts array is required, and specifies the x,y pairs for each vertex. If
@@ -1415,11 +1517,12 @@ public class Canvas {
* @param indices If not null, array of indices to reference into the
* vertex (texs, colors) array.
* @param indexCount number of entries in the indices array (if not null).
- * @param paint Specifies the shader to use if the texs array is non-null.
+ * @param paint Specifies the shader to use if the texs array is non-null.
*/
- 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) {
+ public void drawVertices(@NonNull VertexMode mode, int vertexCount, @NonNull float[] verts,
+ int vertOffset, @Nullable float[] texs, int texOffset, @Nullable int[] colors,
+ int colorOffset, @Nullable short[] indices, int indexOffset, int indexCount,
+ @NonNull Paint paint) {
checkRange(verts.length, vertOffset, vertexCount);
if (texs != null) {
checkRange(texs.length, texOffset, vertexCount);
@@ -1430,7 +1533,7 @@ public class Canvas {
if (indices != null) {
checkRange(indices.length, indexOffset, indexCount);
}
- nativeDrawVertices(mNativeCanvas, mode.nativeInt, vertexCount, verts,
+ nativeDrawVertices(mNativeCanvasWrapper, mode.nativeInt, vertexCount, verts,
vertOffset, texs, texOffset, colors, colorOffset,
indices, indexOffset, indexCount, paint.mNativePaint);
}
@@ -1444,12 +1547,13 @@ public class Canvas {
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(char[] text, int index, int count, float x, float y, Paint paint) {
+ public void drawText(@NonNull char[] text, int index, int count, float x, float y,
+ @NonNull Paint paint) {
if ((index | count | (index + count) |
(text.length - index - count)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags,
+ native_drawText(mNativeCanvasWrapper, text, index, count, x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
}
@@ -1462,8 +1566,8 @@ public class Canvas {
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(String text, float x, float y, Paint paint) {
- native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags,
+ public void drawText(@NonNull String text, float x, float y, @NonNull Paint paint) {
+ native_drawText(mNativeCanvasWrapper, text, 0, text.length(), x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
}
@@ -1478,11 +1582,12 @@ public class Canvas {
* @param y The y-coordinate of the origin of the text being drawn
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(String text, int start, int end, float x, float y, Paint paint) {
+ public void drawText(@NonNull String text, int start, int end, float x, float y,
+ @NonNull Paint paint) {
if ((start | end | (end - start) | (text.length() - end)) < 0) {
throw new IndexOutOfBoundsException();
}
- native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags,
+ native_drawText(mNativeCanvasWrapper, text, start, end, x, y, paint.mBidiFlags,
paint.mNativePaint, paint.mNativeTypeface);
}
@@ -1499,10 +1604,11 @@ public class Canvas {
* @param y The y-coordinate of origin for where to draw the text
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawText(CharSequence text, int start, int end, float x, float y, Paint paint) {
+ public void drawText(@NonNull CharSequence text, int start, int end, float x, float y,
+ @NonNull Paint paint) {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
- native_drawText(mNativeCanvas, text.toString(), start, end, x, y,
+ native_drawText(mNativeCanvasWrapper, text.toString(), start, end, x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawText(this, start, end, x, y,
@@ -1510,7 +1616,7 @@ public class Canvas {
} else {
char[] buf = TemporaryBuffer.obtain(end - start);
TextUtils.getChars(text, start, end, buf, 0);
- native_drawText(mNativeCanvas, buf, 0, end - start, x, y,
+ native_drawText(mNativeCanvasWrapper, buf, 0, end - start, x, y,
paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
@@ -1521,7 +1627,7 @@ public class Canvas {
* bidi on the provided text, but renders it as a uniform right-to-left or
* left-to-right run, as indicated by dir. Alignment of the text is as
* determined by the Paint's TextAlign value.
- *
+ *
* @param text the text to render
* @param index the start of the text to render
* @param count the count of chars to render
@@ -1532,13 +1638,12 @@ public class Canvas {
* + count.
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
- * @param dir the run direction, either {@link #DIRECTION_LTR} or
- * {@link #DIRECTION_RTL}.
+ * @param isRtl whether the run is in RTL direction
* @param paint the paint
* @hide
*/
- public void drawTextRun(char[] text, int index, int count, int contextIndex, int contextCount,
- float x, float y, int dir, Paint paint) {
+ public void drawTextRun(@NonNull char[] text, int index, int count, int contextIndex,
+ int contextCount, float x, float y, boolean isRtl, @NonNull Paint paint) {
if (text == null) {
throw new NullPointerException("text is null");
@@ -1549,12 +1654,9 @@ public class Canvas {
if ((index | count | text.length - index - count) < 0) {
throw new IndexOutOfBoundsException();
}
- if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown dir: " + dir);
- }
- native_drawTextRun(mNativeCanvas, text, index, count,
- contextIndex, contextCount, x, y, dir, paint.mNativePaint, paint.mNativeTypeface);
+ native_drawTextRun(mNativeCanvasWrapper, text, index, count,
+ contextIndex, contextCount, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
}
/**
@@ -1570,12 +1672,12 @@ public class Canvas {
* position can be used for shaping context.
* @param x the x position at which to draw the text
* @param y the y position at which to draw the text
- * @param dir the run direction, either 0 for LTR or 1 for RTL.
+ * @param isRtl whether the run is in RTL direction
* @param paint the paint
* @hide
*/
- public void drawTextRun(CharSequence text, int start, int end, int contextStart, int contextEnd,
- float x, float y, int dir, Paint paint) {
+ public void drawTextRun(@NonNull CharSequence text, int start, int end, int contextStart,
+ int contextEnd, float x, float y, boolean isRtl, @NonNull Paint paint) {
if (text == null) {
throw new NullPointerException("text is null");
@@ -1587,22 +1689,20 @@ public class Canvas {
throw new IndexOutOfBoundsException();
}
- int flags = dir == 0 ? 0 : 1;
-
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
- native_drawTextRun(mNativeCanvas, text.toString(), start, end,
- contextStart, contextEnd, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ native_drawTextRun(mNativeCanvasWrapper, text.toString(), start, end,
+ contextStart, contextEnd, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
} else if (text instanceof GraphicsOperations) {
((GraphicsOperations) text).drawTextRun(this, start, end,
- contextStart, contextEnd, x, y, flags, paint);
+ contextStart, contextEnd, x, y, isRtl, paint);
} else {
int contextLen = contextEnd - contextStart;
int len = end - start;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
- native_drawTextRun(mNativeCanvas, buf, start - contextStart, len,
- 0, contextLen, x, y, flags, paint.mNativePaint, paint.mNativeTypeface);
+ native_drawTextRun(mNativeCanvasWrapper, buf, start - contextStart, len,
+ 0, contextLen, x, y, isRtl, paint.mNativePaint, paint.mNativeTypeface);
TemporaryBuffer.recycle(buf);
}
}
@@ -1610,9 +1710,10 @@ public class Canvas {
/**
* Draw the text in the array, with each character's origin specified by
* the pos array.
- *
+ *
* This method does not support glyph composition and decomposition and
- * should therefore not be used to render complex scripts.
+ * should therefore not be used to render complex scripts. It also doesn't
+ * handle supplementary characters (eg emoji).
*
* @param text The text to be drawn
* @param index The index of the first character to draw
@@ -1622,31 +1723,31 @@ public class Canvas {
* @param paint The paint used for the text (e.g. color, size, style)
*/
@Deprecated
- public void drawPosText(char[] text, int index, int count, float[] pos, Paint paint) {
+ public void drawPosText(@NonNull char[] text, int index, int count, @NonNull float[] pos,
+ @NonNull Paint paint) {
if (index < 0 || index + count > text.length || count*2 > pos.length) {
throw new IndexOutOfBoundsException();
}
- native_drawPosText(mNativeCanvas, text, index, count, pos,
- paint.mNativePaint);
+ for (int i = 0; i < count; i++) {
+ drawText(text, index + i, 1, pos[i * 2], pos[i * 2 + 1], paint);
+ }
}
/**
* Draw the text in the array, with each character's origin specified by
* the pos array.
- *
+ *
* This method does not support glyph composition and decomposition and
- * should therefore not be used to render complex scripts.
+ * should therefore not be used to render complex scripts. It also doesn't
+ * handle supplementary characters (eg emoji).
*
* @param text The text to be drawn
* @param pos Array of [x,y] positions, used to position each character
* @param paint The paint used for the text (e.g. color, size, style)
*/
@Deprecated
- public void drawPosText(String text, float[] pos, Paint paint) {
- if (text.length()*2 > pos.length) {
- throw new ArrayIndexOutOfBoundsException();
- }
- native_drawPosText(mNativeCanvas, text, pos, paint.mNativePaint);
+ public void drawPosText(@NonNull String text, @NonNull float[] pos, @NonNull Paint paint) {
+ drawPosText(text.toCharArray(), 0, text.length(), pos, paint);
}
/**
@@ -1662,14 +1763,14 @@ public class Canvas {
* the text
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawTextOnPath(char[] text, int index, int count, Path path,
- float hOffset, float vOffset, Paint paint) {
+ public void drawTextOnPath(@NonNull char[] text, int index, int count, @NonNull Path path,
+ float hOffset, float vOffset, @NonNull Paint paint) {
if (index < 0 || index + count > text.length) {
throw new ArrayIndexOutOfBoundsException();
}
- native_drawTextOnPath(mNativeCanvas, text, index, count,
+ native_drawTextOnPath(mNativeCanvasWrapper, text, index, count,
path.ni(), hOffset, vOffset,
- paint.mBidiFlags, paint.mNativePaint);
+ paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
/**
@@ -1685,10 +1786,11 @@ public class Canvas {
* the text
* @param paint The paint used for the text (e.g. color, size, style)
*/
- public void drawTextOnPath(String text, Path path, float hOffset, float vOffset, Paint paint) {
+ public void drawTextOnPath(@NonNull String text, @NonNull Path path, float hOffset,
+ float vOffset, @NonNull Paint paint) {
if (text.length() > 0) {
- native_drawTextOnPath(mNativeCanvas, text, path.ni(), hOffset, vOffset,
- paint.mBidiFlags, paint.mNativePaint);
+ native_drawTextOnPath(mNativeCanvasWrapper, text, path.ni(), hOffset, vOffset,
+ paint.mBidiFlags, paint.mNativePaint, paint.mNativeTypeface);
}
}
@@ -1700,20 +1802,20 @@ public class Canvas {
* <p>
* <strong>Note:</strong> This forces the picture to internally call
* {@link Picture#endRecording} in order to prepare for playback.
- *
+ *
* @param picture The picture to be drawn
*/
- public void drawPicture(Picture picture) {
+ public void drawPicture(@NonNull Picture picture) {
picture.endRecording();
int restoreCount = save();
picture.draw(this);
restoreToCount(restoreCount);
}
-
+
/**
* Draw the picture, stretched to fit into the dst rectangle.
*/
- public void drawPicture(Picture picture, RectF dst) {
+ public void drawPicture(@NonNull Picture picture, @NonNull RectF dst) {
save();
translate(dst.left, dst.top);
if (picture.getWidth() > 0 && picture.getHeight() > 0) {
@@ -1722,11 +1824,11 @@ public class Canvas {
drawPicture(picture);
restore();
}
-
+
/**
* Draw the picture, stretched to fit into the dst rectangle.
*/
- public void drawPicture(Picture picture, Rect dst) {
+ public void drawPicture(@NonNull Picture picture, @NonNull Rect dst) {
save();
translate(dst.left, dst.top);
if (picture.getWidth() > 0 && picture.getHeight() > 0) {
@@ -1761,23 +1863,34 @@ public class Canvas {
public static native void freeTextLayoutCaches();
private static native long initRaster(long nativeBitmapOrZero);
- private static native void copyNativeCanvasState(long nativeSrcCanvas,
- long nativeDstCanvas);
- private static native int native_saveLayer(long nativeCanvas,
- RectF bounds,
- long nativePaint,
- int layerFlags);
+ private static native long initCanvas(long canvasHandle);
+ private static native void native_setBitmap(long canvasHandle,
+ long bitmapHandle,
+ boolean copyState);
+ private static native boolean native_isOpaque(long canvasHandle);
+ private static native int native_getWidth(long canvasHandle);
+ private static native int native_getHeight(long canvasHandle);
+
+ private static native int native_save(long canvasHandle, int saveFlags);
private static native int native_saveLayer(long nativeCanvas, float l,
float t, float r, float b,
long nativePaint,
int layerFlags);
- private static native int native_saveLayerAlpha(long nativeCanvas,
- RectF bounds, int alpha,
- int layerFlags);
private static native int native_saveLayerAlpha(long nativeCanvas, float l,
float t, float r, float b,
int alpha, int layerFlags);
-
+ private static native void native_restore(long canvasHandle);
+ private static native void native_restoreToCount(long canvasHandle,
+ int saveCount);
+ private static native int native_getSaveCount(long canvasHandle);
+
+ private static native void native_translate(long canvasHandle,
+ float dx, float dy);
+ private static native void native_scale(long canvasHandle,
+ float sx, float sy);
+ private static native void native_rotate(long canvasHandle, float degrees);
+ private static native void native_skew(long canvasHandle,
+ float sx, float sy);
private static native void native_concat(long nativeCanvas,
long nativeMatrix);
private static native void native_setMatrix(long nativeCanvas,
@@ -1799,8 +1912,6 @@ public class Canvas {
private static native void native_getCTM(long nativeCanvas,
long nativeMatrix);
private static native boolean native_quickReject(long nativeCanvas,
- RectF rect);
- private static native boolean native_quickReject(long nativeCanvas,
long nativePath);
private static native boolean native_quickReject(long nativeCanvas,
float left, float top,
@@ -1814,23 +1925,29 @@ public class Canvas {
int mode);
private static native void native_drawPaint(long nativeCanvas,
long nativePaint);
+ private static native void native_drawPoint(long canvasHandle, float x, float y,
+ long paintHandle);
+ private static native void native_drawPoints(long canvasHandle, float[] pts,
+ int offset, int count,
+ long paintHandle);
private static native void native_drawLine(long nativeCanvas, float startX,
float startY, float stopX,
float stopY, long nativePaint);
- private static native void native_drawRect(long nativeCanvas, RectF rect,
- long nativePaint);
+ private static native void native_drawLines(long canvasHandle, float[] pts,
+ int offset, int count,
+ long paintHandle);
private static native void native_drawRect(long nativeCanvas, float left,
float top, float right,
float bottom,
long nativePaint);
- private static native void native_drawOval(long nativeCanvas, RectF oval,
- long nativePaint);
+ private static native void native_drawOval(long nativeCanvas, float left, float top,
+ float right, float bottom, long nativePaint);
private static native void native_drawCircle(long nativeCanvas, float cx,
float cy, float radius,
long nativePaint);
- private static native void native_drawArc(long nativeCanvas, RectF oval,
- float startAngle, float sweep,
- boolean useCenter,
+ private static native void native_drawArc(long nativeCanvas, float left, float top,
+ float right, float bottom,
+ float startAngle, float sweep, boolean useCenter,
long nativePaint);
private static native void native_drawRoundRect(long nativeCanvas,
float left, float top, float right, float bottom,
@@ -1886,29 +2003,22 @@ public class Canvas {
private static native void native_drawTextRun(long nativeCanvas, String text,
int start, int end, int contextStart, int contextEnd,
- float x, float y, int flags, long nativePaint, long nativeTypeface);
+ float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
private static native void native_drawTextRun(long nativeCanvas, char[] text,
int start, int count, int contextStart, int contextCount,
- float x, float y, int flags, long nativePaint, long nativeTypeface);
-
- private static native void native_drawPosText(long nativeCanvas,
- char[] text, int index,
- int count, float[] pos,
- long nativePaint);
- private static native void native_drawPosText(long nativeCanvas,
- String text, float[] pos,
- long nativePaint);
+ float x, float y, boolean isRtl, long nativePaint, long nativeTypeface);
+
private static native void native_drawTextOnPath(long nativeCanvas,
char[] text, int index,
int count, long nativePath,
float hOffset,
float vOffset, int bidiFlags,
- long nativePaint);
+ long nativePaint, long nativeTypeface);
private static native void native_drawTextOnPath(long nativeCanvas,
String text, long nativePath,
float hOffset,
float vOffset,
- int flags, long nativePaint);
+ int flags, long nativePaint, long nativeTypeface);
private static native void finalizer(long nativeCanvas);
}
diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java
index 6ff5f4f..befac92 100644
--- a/graphics/java/android/graphics/NinePatch.java
+++ b/graphics/java/android/graphics/NinePatch.java
@@ -164,12 +164,12 @@ public class NinePatch {
}
void drawSoftware(Canvas canvas, RectF location, Paint paint) {
- nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
}
void drawSoftware(Canvas canvas, Rect location, Paint paint) {
- nativeDraw(canvas.getNativeCanvas(), location, mBitmap.ni(), mNativeChunk,
+ nativeDraw(canvas.getNativeCanvasWrapper(), location, mBitmap.ni(), mNativeChunk,
paint != null ? paint.mNativePaint : 0, canvas.mDensity, mBitmap.mDensity);
}
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 4268a24..17ce026 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -56,7 +56,7 @@ public class Paint {
* @hide
*/
public int mBidiFlags = BIDI_DEFAULT_LTR;
-
+
static final Style[] sStyleArray = {
Style.FILL, Style.STROKE, Style.FILL_AND_STROKE
};
@@ -202,14 +202,14 @@ public class Paint {
/**
* Bidi flag to set LTR paragraph direction.
- *
+ *
* @hide
*/
public static final int BIDI_LTR = 0x0;
/**
* Bidi flag to set RTL paragraph direction.
- *
+ *
* @hide
*/
public static final int BIDI_RTL = 0x1;
@@ -217,7 +217,7 @@ public class Paint {
/**
* Bidi flag to detect paragraph direction via heuristics, defaulting to
* LTR.
- *
+ *
* @hide
*/
public static final int BIDI_DEFAULT_LTR = 0x2;
@@ -225,21 +225,21 @@ public class Paint {
/**
* Bidi flag to detect paragraph direction via heuristics, defaulting to
* RTL.
- *
+ *
* @hide
*/
public static final int BIDI_DEFAULT_RTL = 0x3;
/**
* Bidi flag to override direction to all LTR (ignore bidi).
- *
+ *
* @hide
*/
public static final int BIDI_FORCE_LTR = 0x4;
/**
* Bidi flag to override direction to all RTL (ignore bidi).
- *
+ *
* @hide
*/
public static final int BIDI_FORCE_RTL = 0x5;
@@ -331,7 +331,7 @@ public class Paint {
* either FILL or STROKE.
*/
FILL_AND_STROKE (2);
-
+
Style(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -357,7 +357,7 @@ public class Paint {
* of the path.
*/
SQUARE (2);
-
+
private Cap(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -381,7 +381,7 @@ public class Paint {
* The outer edges of a join meet with a straight line
*/
BEVEL (2);
-
+
private Join(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -405,7 +405,7 @@ public class Paint {
* The text is drawn to the left of the x,y origin
*/
RIGHT (2);
-
+
private Align(int nativeInt) {
this.nativeInt = nativeInt;
}
@@ -418,7 +418,7 @@ public class Paint {
public Paint() {
this(0);
}
-
+
/**
* Create a new paint with the specified flags. Use setFlags() to change
* these after the paint is created.
@@ -475,7 +475,7 @@ public class Paint {
setTextLocale(Locale.getDefault());
setElegantTextHeight(false);
}
-
+
/**
* Copy the fields from src into this paint. This is equivalent to calling
* get() on all of the src fields, and calling the corresponding set()
@@ -529,7 +529,7 @@ public class Paint {
/**
* Return the bidi flags on the paint.
- *
+ *
* @return the bidi flags on the paint
* @hide
*/
@@ -552,7 +552,7 @@ public class Paint {
/**
* Return the paint's flags. Use the Flag enum to test flag values.
- *
+ *
* @return the paint's flags (see enums ending in _Flag for bit masks)
*/
public native int getFlags();
@@ -587,7 +587,7 @@ public class Paint {
public final boolean isAntiAlias() {
return (getFlags() & ANTI_ALIAS_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the ANTI_ALIAS_FLAG bit
* AntiAliasing smooths out the edges of what is being drawn, but is has
@@ -597,7 +597,7 @@ public class Paint {
* @param aa true to set the antialias bit in the flags, false to clear it
*/
public native void setAntiAlias(boolean aa);
-
+
/**
* Helper for getFlags(), returning true if DITHER_FLAG bit is set
* Dithering affects how colors that are higher precision than the device
@@ -611,7 +611,7 @@ public class Paint {
public final boolean isDither() {
return (getFlags() & DITHER_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the DITHER_FLAG bit
* Dithering affects how colors that are higher precision than the device
@@ -623,7 +623,7 @@ public class Paint {
* @param dither true to set the dithering bit in flags, false to clear it
*/
public native void setDither(boolean dither);
-
+
/**
* Helper for getFlags(), returning true if LINEAR_TEXT_FLAG bit is set
*
@@ -649,7 +649,7 @@ public class Paint {
public final boolean isSubpixelText() {
return (getFlags() & SUBPIXEL_TEXT_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the SUBPIXEL_TEXT_FLAG bit
*
@@ -657,7 +657,7 @@ public class Paint {
* flags, false to clear it.
*/
public native void setSubpixelText(boolean subpixelText);
-
+
/**
* Helper for getFlags(), returning true if UNDERLINE_TEXT_FLAG bit is set
*
@@ -708,7 +708,7 @@ public class Paint {
* flags, false to clear it.
*/
public native void setFakeBoldText(boolean fakeBoldText);
-
+
/**
* Whether or not the bitmap filter is activated.
* Filtering affects the sampling of bitmaps when they are transformed.
@@ -720,13 +720,13 @@ public class Paint {
public final boolean isFilterBitmap() {
return (getFlags() & FILTER_BITMAP_FLAG) != 0;
}
-
+
/**
* Helper for setFlags(), setting or clearing the FILTER_BITMAP_FLAG bit.
* Filtering affects the sampling of bitmaps when they are transformed.
* Filtering does not affect how the colors in the bitmap are converted into
* device pixels. That is dependent on dithering and xfermodes.
- *
+ *
* @param filter true to set the FILTER_BITMAP_FLAG bit in the paint's
* flags, false to clear it.
*/
@@ -773,7 +773,7 @@ public class Paint {
* @param color The new color (including alpha) to set in the paint.
*/
public native void setColor(int color);
-
+
/**
* Helper to getColor() that just returns the color's alpha value. This is
* the same as calling getColor() >>> 24. It always returns a value between
@@ -1285,7 +1285,7 @@ public class Paint {
*/
public static class FontMetrics {
/**
- * The maximum distance above the baseline for the tallest glyph in
+ * The maximum distance above the baseline for the tallest glyph in
* the font at a given text size.
*/
public float top;
@@ -1298,7 +1298,7 @@ public class Paint {
*/
public float descent;
/**
- * The maximum distance below the baseline for the lowest glyph in
+ * The maximum distance below the baseline for the lowest glyph in
* the font at a given text size.
*/
public float bottom;
@@ -1307,7 +1307,7 @@ public class Paint {
*/
public float leading;
}
-
+
/**
* Return the font's recommended interline spacing, given the Paint's
* settings for typeface, textSize, etc. If metrics is not null, return the
@@ -1318,7 +1318,7 @@ public class Paint {
* @return the font's recommended interline spacing.
*/
public native float getFontMetrics(FontMetrics metrics);
-
+
/**
* Allocates a new FontMetrics object, and then calls getFontMetrics(fm)
* with it, returning the object.
@@ -1328,7 +1328,7 @@ public class Paint {
getFontMetrics(fm);
return fm;
}
-
+
/**
* Convenience method for callers that want to have FontMetrics values as
* integers.
@@ -1339,7 +1339,7 @@ public class Paint {
public int descent;
public int bottom;
public int leading;
-
+
@Override public String toString() {
return "FontMetricsInt: top=" + top + " ascent=" + ascent +
" descent=" + descent + " bottom=" + bottom +
@@ -1364,7 +1364,7 @@ public class Paint {
getFontMetricsInt(fm);
return fm;
}
-
+
/**
* Return the recommend line spacing based on the current typeface and
* text size.
@@ -1407,7 +1407,7 @@ public class Paint {
}
private native float native_measureText(char[] text, int index, int count, int bidiFlags);
-
+
/**
* Return the width of the text.
*
@@ -1439,7 +1439,7 @@ public class Paint {
}
private native float native_measureText(String text, int start, int end, int bidiFlags);
-
+
/**
* Return the width of the text.
*
@@ -1466,7 +1466,7 @@ public class Paint {
}
private native float native_measureText(String text, int bidiFlags);
-
+
/**
* Return the width of the text.
*
@@ -1503,7 +1503,7 @@ public class Paint {
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
@@ -1532,20 +1532,22 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(text, index, count, maxWidth, mBidiFlags, measuredWidth);
+ return native_breakText(mNativePaint, mNativeTypeface, text, index, count, maxWidth,
+ mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
- setTextSize(oldSize*mCompatScaling);
- int res = native_breakText(text, index, count, maxWidth*mCompatScaling, mBidiFlags,
- measuredWidth);
+ setTextSize(oldSize * mCompatScaling);
+ int res = native_breakText(mNativePaint, mNativeTypeface, text, index, count,
+ maxWidth * mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private native int native_breakText(char[] text, int index, int count,
- float maxWidth, int bidiFlags, float[] measuredWidth);
+ private static native int native_breakText(long native_object, long native_typeface,
+ char[] text, int index, int count,
+ float maxWidth, int bidiFlags, float[] measuredWidth);
/**
* Measure the text, stopping early if the measured width exceeds maxWidth.
@@ -1622,19 +1624,21 @@ public class Paint {
return 0;
}
if (!mHasCompatScaling) {
- return native_breakText(text, measureForwards, maxWidth, mBidiFlags, measuredWidth);
+ return native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ maxWidth, mBidiFlags, measuredWidth);
}
final float oldSize = getTextSize();
setTextSize(oldSize*mCompatScaling);
- int res = native_breakText(text, measureForwards, maxWidth*mCompatScaling, mBidiFlags,
- measuredWidth);
+ int res = native_breakText(mNativePaint, mNativeTypeface, text, measureForwards,
+ maxWidth*mCompatScaling, mBidiFlags, measuredWidth);
setTextSize(oldSize);
if (measuredWidth != null) measuredWidth[0] *= mInvCompatScaling;
return res;
}
- private native int native_breakText(String text, boolean measureForwards,
+ private static native int native_breakText(long native_object, long native_typeface,
+ String text, boolean measureForwards,
float maxWidth, int bidiFlags, float[] measuredWidth);
/**
@@ -1738,7 +1742,7 @@ public class Paint {
if (end - start > widths.length) {
throw new ArrayIndexOutOfBoundsException();
}
-
+
if (text.length() == 0 || start == end) {
return 0;
}
@@ -1755,7 +1759,7 @@ public class Paint {
}
return res;
}
-
+
/**
* Return the advance widths for the characters in the string.
*
@@ -1816,15 +1820,12 @@ public class Paint {
* @hide
*/
public float getTextRunAdvances(char[] chars, int index, int count,
- int contextIndex, int contextCount, int flags, float[] advances,
+ int contextIndex, int contextCount, boolean isRtl, float[] advances,
int advancesIndex) {
if (chars == null) {
throw new IllegalArgumentException("text cannot be null");
}
- if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown flags value: " + flags);
- }
if ((index | count | contextIndex | contextCount | advancesIndex
| (index - contextIndex) | (contextCount - count)
| ((contextIndex + contextCount) - (index + count))
@@ -1839,13 +1840,13 @@ public class Paint {
}
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
+ contextIndex, contextCount, isRtl, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
- contextIndex, contextCount, flags, advances, advancesIndex);
+ contextIndex, contextCount, isRtl, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -1864,7 +1865,7 @@ public class Paint {
* @hide
*/
public float getTextRunAdvances(CharSequence text, int start, int end,
- int contextStart, int contextEnd, int flags, float[] advances,
+ int contextStart, int contextEnd, boolean isRtl, float[] advances,
int advancesIndex) {
if (text == null) {
@@ -1880,16 +1881,16 @@ public class Paint {
if (text instanceof String) {
return getTextRunAdvances((String) text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
}
if (text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunAdvances(text.toString(), start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunAdvances(start, end,
- contextStart, contextEnd, flags, advances, advancesIndex, this);
+ contextStart, contextEnd, isRtl, advances, advancesIndex, this);
}
if (text.length() == 0 || end == start) {
return 0f;
@@ -1900,7 +1901,7 @@ public class Paint {
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
float result = getTextRunAdvances(buf, start - contextStart, len,
- 0, contextLen, flags, advances, advancesIndex);
+ 0, contextLen, isRtl, advances, advancesIndex);
TemporaryBuffer.recycle(buf);
return result;
}
@@ -1937,8 +1938,7 @@ public class Paint {
* must be <= start
* @param contextEnd the index past the last character to use for shaping context,
* must be >= end
- * @param flags the flags to control the advances, either {@link #DIRECTION_LTR}
- * or {@link #DIRECTION_RTL}
+ * @param isRtl whether the run is in RTL direction
* @param advances array to receive the advances, must have room for all advances,
* can be null if only total advance is needed
* @param advancesIndex the position in advances at which to put the
@@ -1948,14 +1948,11 @@ public class Paint {
* @hide
*/
public float getTextRunAdvances(String text, int start, int end, int contextStart,
- int contextEnd, int flags, float[] advances, int advancesIndex) {
+ int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
if (text == null) {
throw new IllegalArgumentException("text cannot be null");
}
- if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) {
- throw new IllegalArgumentException("unknown flags value: " + flags);
- }
if ((start | end | contextStart | contextEnd | advancesIndex | (end - start)
| (start - contextStart) | (contextEnd - end)
| (text.length() - contextEnd)
@@ -1970,13 +1967,13 @@ public class Paint {
if (!mHasCompatScaling) {
return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
}
final float oldSize = getTextSize();
setTextSize(oldSize * mCompatScaling);
float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
- contextStart, contextEnd, flags, advances, advancesIndex);
+ contextStart, contextEnd, isRtl, advances, advancesIndex);
setTextSize(oldSize);
if (advances != null) {
@@ -2005,7 +2002,7 @@ public class Paint {
* @param text the text
* @param contextStart the start of the context
* @param contextLength the length of the context
- * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+ * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2014,7 +2011,7 @@ public class Paint {
* @hide
*/
public int getTextRunCursor(char[] text, int contextStart, int contextLength,
- int flags, int offset, int cursorOpt) {
+ int dir, int offset, int cursorOpt) {
int contextEnd = contextStart + contextLength;
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
| (offset - contextStart) | (contextEnd - offset)
@@ -2024,7 +2021,7 @@ public class Paint {
}
return native_getTextRunCursor(mNativePaint, text,
- contextStart, contextLength, flags, offset, cursorOpt);
+ contextStart, contextLength, dir, offset, cursorOpt);
}
/**
@@ -2045,7 +2042,7 @@ public class Paint {
* @param text the text
* @param contextStart the start of the context
* @param contextEnd the end of the context
- * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+ * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2054,22 +2051,22 @@ public class Paint {
* @hide
*/
public int getTextRunCursor(CharSequence text, int contextStart,
- int contextEnd, int flags, int offset, int cursorOpt) {
+ int contextEnd, int dir, int offset, int cursorOpt) {
if (text instanceof String || text instanceof SpannedString ||
text instanceof SpannableString) {
return getTextRunCursor(text.toString(), contextStart, contextEnd,
- flags, offset, cursorOpt);
+ dir, offset, cursorOpt);
}
if (text instanceof GraphicsOperations) {
return ((GraphicsOperations) text).getTextRunCursor(
- contextStart, contextEnd, flags, offset, cursorOpt, this);
+ contextStart, contextEnd, dir, offset, cursorOpt, this);
}
int contextLen = contextEnd - contextStart;
char[] buf = TemporaryBuffer.obtain(contextLen);
TextUtils.getChars(text, contextStart, contextEnd, buf, 0);
- int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt);
+ int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt);
TemporaryBuffer.recycle(buf);
return result;
}
@@ -2092,7 +2089,7 @@ public class Paint {
* @param text the text
* @param contextStart the start of the context
* @param contextEnd the end of the context
- * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
+ * @param dir either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR}
* @param offset the cursor position to move from
* @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER},
* {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE},
@@ -2101,7 +2098,7 @@ public class Paint {
* @hide
*/
public int getTextRunCursor(String text, int contextStart, int contextEnd,
- int flags, int offset, int cursorOpt) {
+ int dir, int offset, int cursorOpt) {
if (((contextStart | contextEnd | offset | (contextEnd - contextStart)
| (offset - contextStart) | (contextEnd - offset)
| (text.length() - contextEnd) | cursorOpt) < 0)
@@ -2110,7 +2107,7 @@ public class Paint {
}
return native_getTextRunCursor(mNativePaint, text,
- contextStart, contextEnd, flags, offset, cursorOpt);
+ contextStart, contextEnd, dir, offset, cursorOpt);
}
/**
@@ -2156,7 +2153,7 @@ public class Paint {
native_getTextPath(mNativePaint, mNativeTypeface, mBidiFlags, text, start, end, x, y,
path.ni());
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -2176,7 +2173,7 @@ public class Paint {
}
nativeGetStringBounds(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, bounds);
}
-
+
/**
* Return in bounds (allocated by the caller) the smallest rectangle that
* encloses all of the characters, with an implied origin at (0,0).
@@ -2197,7 +2194,7 @@ public class Paint {
nativeGetCharArrayBounds(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags,
bounds);
}
-
+
@Override
protected void finalize() throws Throwable {
try {
@@ -2252,15 +2249,15 @@ public class Paint {
private static native float native_getTextRunAdvances(long native_object, long native_typeface,
char[] text, int index, int count, int contextIndex, int contextCount,
- int flags, float[] advances, int advancesIndex);
+ boolean isRtl, float[] advances, int advancesIndex);
private static native float native_getTextRunAdvances(long native_object, long native_typeface,
String text, int start, int end, int contextStart, int contextEnd,
- int flags, float[] advances, int advancesIndex);
+ boolean isRtl, float[] advances, int advancesIndex);
private native int native_getTextRunCursor(long native_object, char[] text,
- int contextStart, int contextLength, int flags, int offset, int cursorOpt);
+ int contextStart, int contextLength, int dir, int offset, int cursorOpt);
private native int native_getTextRunCursor(long native_object, String text,
- int contextStart, int contextEnd, int flags, int offset, int cursorOpt);
+ int contextStart, int contextEnd, int dir, int offset, int cursorOpt);
private static native void native_getTextPath(long native_object, long native_typeface,
int bidiFlags, char[] text, int index, int count, float x, float y, long path);
diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java
index c600f47..c40a66d 100644
--- a/graphics/java/android/graphics/Path.java
+++ b/graphics/java/android/graphics/Path.java
@@ -62,7 +62,7 @@ public class Path {
}
mNativePath = init2(valNative);
}
-
+
/**
* Clear any lines and curves from the path, making it empty.
* This does NOT change the fill-type setting.
@@ -205,7 +205,7 @@ public class Path {
* Same as {@link #EVEN_ODD}, but draws outside of the path, rather than inside.
*/
INVERSE_EVEN_ODD(3);
-
+
FillType(int ni) {
nativeInt = ni;
}
@@ -425,7 +425,7 @@ public class Path {
* 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.
+ * 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
@@ -435,10 +435,9 @@ public class Path {
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle,
boolean forceMoveTo) {
- isSimplePath = false;
- native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo);
+ arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, forceMoveTo);
}
-
+
/**
* 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
@@ -451,10 +450,27 @@ public class Path {
* @param sweepAngle Sweep angle (in degrees) measured clockwise
*/
public void arcTo(RectF oval, float startAngle, float sweepAngle) {
+ arcTo(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle, false);
+ }
+
+ /**
+ * 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 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(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle, boolean forceMoveTo) {
isSimplePath = false;
- native_arcTo(mNativePath, oval, startAngle, sweepAngle, false);
+ native_arcTo(mNativePath, left, top, right, bottom, startAngle, sweepAngle, forceMoveTo);
}
-
+
/**
* Close the current contour. If the current point is not equal to the
* first point of the contour, a line segment is automatically added.
@@ -473,13 +489,13 @@ public class Path {
CW (1), // must match enum in SkPath.h
/** counter-clockwise */
CCW (2); // must match enum in SkPath.h
-
+
Direction(int ni) {
nativeInt = ni;
}
final int nativeInt;
}
-
+
private void detectSimplePath(float left, float top, float right, float bottom, Direction dir) {
if (mLastDirection == null) {
mLastDirection = dir;
@@ -557,11 +573,19 @@ public class Path {
* @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");
- }
+ addArc(oval.left, oval.top, oval.right, oval.bottom, startAngle, sweepAngle);
+ }
+
+ /**
+ * Add the specified arc to the path as a new contour.
+ *
+ * @param startAngle Starting angle (in degrees) where the arc begins
+ * @param sweepAngle Sweep angle (in degrees) measured clockwise
+ */
+ public void addArc(float left, float top, float right, float bottom, float startAngle,
+ float sweepAngle) {
isSimplePath = false;
- native_addArc(mNativePath, oval, startAngle, sweepAngle);
+ native_addArc(mNativePath, left, top, right, bottom, startAngle, sweepAngle);
}
/**
@@ -573,13 +597,22 @@ public class Path {
* @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");
- }
+ addRoundRect(rect.left, rect.top, rect.right, rect.bottom, rx, ry, dir);
+ }
+
+ /**
+ * Add a closed round-rectangle contour 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(float left, float top, float right, float bottom, float rx, float ry,
+ Direction dir) {
isSimplePath = false;
- native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt);
+ native_addRoundRect(mNativePath, left, top, right, bottom, rx, ry, dir.nativeInt);
}
-
+
/**
* 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,
@@ -593,13 +626,26 @@ public class Path {
if (rect == null) {
throw new NullPointerException("need rect parameter");
}
+ addRoundRect(rect.left, rect.top, rect.right, rect.bottom, radii, dir);
+ }
+
+ /**
+ * 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 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(float left, float top, float right, float bottom, float[] radii,
+ Direction dir) {
if (radii.length < 8) {
throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values");
}
isSimplePath = false;
- native_addRoundRect(mNativePath, rect, radii, dir.nativeInt);
+ native_addRoundRect(mNativePath, left, top, right, bottom, radii, dir.nativeInt);
}
-
+
/**
* Add a copy of src to the path, offset by (dx,dy)
*
@@ -755,19 +801,24 @@ public class Path {
float x2, float y2, float x3, float y3);
private static native void native_rCubicTo(long nPath, float x1, float y1,
float x2, float y2, float x3, float y3);
- private static native void native_arcTo(long nPath, RectF oval,
- float startAngle, float sweepAngle, boolean forceMoveTo);
+ private static native void native_arcTo(long nPath, float left, float top,
+ float right, float bottom, float startAngle,
+ float sweepAngle, boolean forceMoveTo);
private static native void native_close(long nPath);
private static native void native_addRect(long nPath, float left, float top,
float right, float bottom, int dir);
private static native void native_addOval(long nPath, float left, float top,
float right, float bottom, int dir);
private static native void native_addCircle(long nPath, float x, float y, float radius, int dir);
- private static native void native_addArc(long nPath, RectF oval,
- float startAngle, float sweepAngle);
- private static native void native_addRoundRect(long nPath, RectF rect,
+ private static native void native_addArc(long nPath, float left, float top,
+ float right, float bottom,
+ float startAngle, float sweepAngle);
+ private static native void native_addRoundRect(long nPath, float left, float top,
+ float right, float bottom,
float rx, float ry, int dir);
- private static native void native_addRoundRect(long nPath, RectF r, float[] radii, int dir);
+ private static native void native_addRoundRect(long nPath, float left, float top,
+ float right, float bottom,
+ float[] radii, int dir);
private static native void native_addPath(long nPath, long src, float dx, float dy);
private static native void native_addPath(long nPath, long src);
private static native void native_addPath(long nPath, long src, long matrix);
diff --git a/graphics/java/android/graphics/Picture.java b/graphics/java/android/graphics/Picture.java
index a16c099..5aa7c6a 100644
--- a/graphics/java/android/graphics/Picture.java
+++ b/graphics/java/android/graphics/Picture.java
@@ -31,18 +31,13 @@ public class Picture {
private Canvas mRecordingCanvas;
private final long mNativePicture;
- /**
- * @hide
- */
- public final boolean createdFromStream;
-
private static final int WORKING_STREAM_STORAGE = 16 * 1024;
/**
* Creates an empty picture that is ready to record.
*/
public Picture() {
- this(nativeConstructor(0), false);
+ this(nativeConstructor(0));
}
/**
@@ -51,9 +46,25 @@ public class Picture {
* changes will not be reflected in this picture.
*/
public Picture(Picture src) {
- this(nativeConstructor(src != null ? src.mNativePicture : 0), false);
+ this(nativeConstructor(src != null ? src.mNativePicture : 0));
+ }
+
+ private Picture(long nativePicture) {
+ if (nativePicture == 0) {
+ throw new RuntimeException();
+ }
+ mNativePicture = nativePicture;
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ nativeDestructor(mNativePicture);
+ } finally {
+ super.finalize();
+ }
}
-
+
/**
* To record a picture, call beginRecording() and then draw into the Canvas
* that is returned. Nothing we appear on screen, but all of the draw
@@ -67,7 +78,7 @@ public class Picture {
mRecordingCanvas = new RecordingCanvas(this, ni);
return mRecordingCanvas;
}
-
+
/**
* Call endRecording when the picture is built. After this call, the picture
* may be drawn, but the canvas that was returned by beginRecording must not
@@ -85,29 +96,36 @@ public class Picture {
* Get the width of the picture as passed to beginRecording. This
* does not reflect (per se) the content of the picture.
*/
- public native int getWidth();
+ public int getWidth() {
+ return nativeGetWidth(mNativePicture);
+ }
/**
* Get the height of the picture as passed to beginRecording. This
* does not reflect (per se) the content of the picture.
*/
- public native int getHeight();
-
+ public int getHeight() {
+ return nativeGetHeight(mNativePicture);
+ }
+
/**
- * Draw this picture on the canvas. The picture may have the side effect
- * of changing the matrix and clip of the canvas.
- *
+ * Draw this picture on the canvas.
+ * <p>
+ * Prior to {@link android.os.Build.VERSION_CODES#L}, this call could
+ * have the side effect of changing the matrix and clip of the canvas
+ * if this picture had imbalanced saves/restores.
+ *
* <p>
* <strong>Note:</strong> This forces the picture to internally call
* {@link Picture#endRecording()} in order to prepare for playback.
*
- * @param canvas The picture is drawn to this canvas
+ * @param canvas The picture is drawn to this canvas
*/
public void draw(Canvas canvas) {
if (mRecordingCanvas != null) {
endRecording();
}
- nativeDraw(canvas.getNativeCanvas(), mNativePicture);
+ nativeDraw(canvas.getNativeCanvasWrapper(), mNativePicture);
}
/**
@@ -119,7 +137,7 @@ public class Picture {
* <p>
* <strong>Note:</strong> a picture created from an input stream cannot be
* replayed on a hardware accelerated canvas.
- *
+ *
* @see #writeToStream(java.io.OutputStream)
* @deprecated The recommended alternative is to not use writeToStream and
* instead draw the picture into a Bitmap from which you can persist it as
@@ -127,7 +145,7 @@ public class Picture {
*/
@Deprecated
public static Picture createFromStream(InputStream stream) {
- return new Picture(nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]), true);
+ return new Picture(nativeCreateFromStream(stream, new byte[WORKING_STREAM_STORAGE]));
}
/**
@@ -156,38 +174,18 @@ public class Picture {
}
}
- protected void finalize() throws Throwable {
- try {
- nativeDestructor(mNativePicture);
- } finally {
- super.finalize();
- }
- }
-
- final long ni() {
- return mNativePicture;
- }
-
- private Picture(long nativePicture, boolean fromStream) {
- if (nativePicture == 0) {
- throw new RuntimeException();
- }
- mNativePicture = nativePicture;
- createdFromStream = fromStream;
- }
-
// return empty picture if src is 0, or a copy of the native src
private static native long nativeConstructor(long nativeSrcOr0);
- private static native long nativeCreateFromStream(InputStream stream,
- byte[] storage);
- private static native long nativeBeginRecording(long nativeCanvas,
- int w, int h);
+ private static native long nativeCreateFromStream(InputStream stream, byte[] storage);
+ private static native int nativeGetWidth(long nativePicture);
+ private static native int nativeGetHeight(long nativePicture);
+ private static native long nativeBeginRecording(long nativeCanvas, int w, int h);
private static native void nativeEndRecording(long nativeCanvas);
private static native void nativeDraw(long nativeCanvas, long nativePicture);
private static native boolean nativeWriteToStream(long nativePicture,
OutputStream stream, byte[] storage);
private static native void nativeDestructor(long nativePicture);
-
+
private static class RecordingCanvas extends Canvas {
private final Picture mPicture;
@@ -195,21 +193,18 @@ public class Picture {
super(nativeCanvas);
mPicture = pict;
}
-
+
@Override
public void setBitmap(Bitmap bitmap) {
- throw new RuntimeException(
- "Cannot call setBitmap on a picture canvas");
+ throw new RuntimeException("Cannot call setBitmap on a picture canvas");
}
@Override
public void drawPicture(Picture picture) {
if (mPicture == picture) {
- throw new RuntimeException(
- "Cannot draw a picture into its recording canvas");
+ throw new RuntimeException("Cannot draw a picture into its recording canvas");
}
super.drawPicture(picture);
}
}
}
-
diff --git a/graphics/java/android/graphics/drawable/Animatable.java b/graphics/java/android/graphics/drawable/Animatable.java
index 9dc62c3..4edfad4 100644
--- a/graphics/java/android/graphics/drawable/Animatable.java
+++ b/graphics/java/android/graphics/drawable/Animatable.java
@@ -32,7 +32,7 @@ public interface Animatable {
/**
* Indicates whether the animation is running.
- *
+ *
* @return True if the animation is running, false otherwise.
*/
boolean isRunning();
diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
index e8024f7..0fd4423 100644
--- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java
@@ -19,6 +19,8 @@ package android.graphics.drawable;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.ColorFilter;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
@@ -88,6 +90,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
canvas.restoreToCount(saveCount);
}
+ @Override
public void start() {
if (!mRunning) {
mRunning = true;
@@ -95,11 +98,13 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
}
+ @Override
public void stop() {
mRunning = false;
unscheduleSelf(this);
}
+ @Override
public boolean isRunning() {
return mRunning;
}
@@ -108,10 +113,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
unscheduleSelf(this);
scheduleSelf(this, SystemClock.uptimeMillis() + mState.mFrameDuration);
}
-
+
+ @Override
public void run() {
// TODO: This should be computed in draw(Canvas), based on the amount
- // of time since the last frame drawn
+ // of time since the last frame drawn
mCurrentDegrees += mIncrement;
if (mCurrentDegrees > (360.0f - mIncrement)) {
mCurrentDegrees = 0.0f;
@@ -119,7 +125,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
invalidateSelf();
nextFrame();
}
-
+
@Override
public boolean setVisible(boolean visible, boolean restart) {
mState.mDrawable.setVisible(visible, restart);
@@ -133,8 +139,8 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
unscheduleSelf(this);
}
return changed;
- }
-
+ }
+
/**
* Returns the drawable rotated by this RotateDrawable.
*/
@@ -148,7 +154,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
| mState.mChangingConfigurations
| mState.mDrawable.getChangingConfigurations();
}
-
+
@Override
public void setAlpha(int alpha) {
mState.mDrawable.setAlpha(alpha);
@@ -165,10 +171,16 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mState.mDrawable.getOpacity();
}
+ @Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
if (callback != null) {
@@ -176,6 +188,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
}
+ @Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
@@ -183,6 +196,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
}
+ @Override
public void unscheduleDrawable(Drawable who, Runnable what) {
final Callback callback = getCallback();
if (callback != null) {
@@ -194,7 +208,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
public boolean getPadding(Rect padding) {
return mState.mDrawable.getPadding(padding);
}
-
+
@Override
public boolean isStateful() {
return mState.mDrawable.isStateful();
@@ -206,6 +220,16 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
@Override
+ protected boolean onLevelChange(int level) {
+ return mState.mDrawable.setLevel(level);
+ }
+
+ @Override
+ protected boolean onStateChange(int[] state) {
+ return mState.mDrawable.setState(state);
+ }
+
+ @Override
public int getIntrinsicWidth() {
return mState.mDrawable.getIntrinsicWidth();
}
@@ -231,11 +255,11 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
final TypedArray a = r.obtainAttributes(attrs, R.styleable.AnimatedRotateDrawable);
super.inflateWithAttributes(r, parser, a, R.styleable.AnimatedRotateDrawable_visible);
-
+
TypedValue tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotX);
final boolean pivotXRel = tv.type == TypedValue.TYPE_FRACTION;
final float pivotX = pivotXRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
-
+
tv = a.peekValue(R.styleable.AnimatedRotateDrawable_pivotY);
final boolean pivotYRel = tv.type == TypedValue.TYPE_FRACTION;
final float pivotY = pivotYRel ? tv.getFraction(1.0f, 1.0f) : tv.getFloat();
@@ -250,7 +274,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
}
a.recycle();
-
+
int outerDepth = parser.getDepth();
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT &&
@@ -306,7 +330,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
Drawable mDrawable;
int mChangingConfigurations;
-
+
boolean mPivotXRel;
float mPivotX;
boolean mPivotYRel;
@@ -315,7 +339,7 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
int mFramesCount;
private boolean mCanConstantState;
- private boolean mCheckedConstantState;
+ private boolean mCheckedConstantState;
public AnimatedRotateState(AnimatedRotateState source, AnimatedRotateDrawable owner,
Resources res) {
@@ -341,12 +365,12 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac
public Drawable newDrawable() {
return new AnimatedRotateDrawable(this, null);
}
-
+
@Override
public Drawable newDrawable(Resources res) {
return new AnimatedRotateDrawable(this, res);
}
-
+
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
index a5a074c..e1dec9d 100644
--- a/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedStateListDrawable.java
@@ -537,4 +537,3 @@ public class AnimatedStateListDrawable extends StateListDrawable {
}
}
}
-
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
new file mode 100644
index 0000000..c787fb0
--- /dev/null
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2014 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.drawable;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.content.res.Resources;
+import android.content.res.Resources.Theme;
+import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.ColorFilter;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.util.Log;
+
+import com.android.internal.R;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+
+/**
+ * This class uses {@link android.animation.ObjectAnimator} and
+ * {@link android.animation.AnimatorSet} to animate the properties of a
+ * {@link android.graphics.drawable.VectorDrawable} to create an animated drawable.
+ * <p>
+ * AnimatedVectorDrawable are normally defined as 3 separate XML files.
+ * </p>
+ * <p>
+ * First is the XML file for {@link android.graphics.drawable.VectorDrawable}.
+ * Note that we allow the animation happen on the group's attributes and path's
+ * attributes, which requires they are uniquely named in this xml file. Groups
+ * and paths without animations do not need names.
+ * </p>
+ * <li>Here is a simple VectorDrawable in this vectordrawable.xml file.
+ * <pre>
+ * &lt;vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot; &gt;
+ * &lt;size
+ * android:height=&quot;64dp&quot;
+ * android:width=&quot;64dp&quot; /&gt;
+ * &lt;viewport
+ * android:viewportHeight=&quot;600&quot;
+ * android:viewportWidth=&quot;600&quot; /&gt;
+ * &lt;group
+ * android:name=&quot;rotationGroup&quot;
+ * android:pivotX=&quot;300.0&quot;
+ * android:pivotY=&quot;300.0&quot;
+ * android:rotation=&quot;45.0&quot; &gt;
+ * &lt;path
+ * android:name=&quot;v&quot;
+ * android:fill=&quot;#000000&quot;
+ * android:pathData=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot; /&gt;
+ * &lt;/group&gt;
+ * &lt;/vector&gt;
+ * </pre></li>
+ * <p>
+ * Second is the AnimatedVectorDrawable's xml file, which defines the target
+ * VectorDrawable, the target paths and groups to animate, the properties of the
+ * path and group to animate and the animations defined as the ObjectAnimators
+ * or AnimatorSets.
+ * </p>
+ * <li>Here is a simple AnimatedVectorDrawable defined in this avd.xml file.
+ * Note how we use the names to refer to the groups and paths in the vectordrawable.xml.
+ * <pre>
+ * &lt;animated-vector xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;
+ * android:drawable=&quot;@drawable/vectordrawable&quot; &gt;
+ * &lt;target
+ * android:name=&quot;rotationGroup&quot;
+ * android:animation=&quot;@anim/rotation&quot; /&gt;
+ * &lt;target
+ * android:name=&quot;v&quot;
+ * android:animation=&quot;@anim/path_morph&quot; /&gt;
+ * &lt;/animated-vector&gt;
+ * </pre></li>
+ * <p>
+ * Last is the Animator xml file, which is the same as a normal ObjectAnimator
+ * or AnimatorSet.
+ * To complete this example, here are the 2 animator files used in avd.xml:
+ * rotation.xml and path_morph.xml.
+ * </p>
+ * <li>Here is the rotation.xml, which will rotate the target group for 360 degrees.
+ * <pre>
+ * &lt;objectAnimator
+ * android:duration=&quot;6000&quot;
+ * android:propertyName=&quot;rotation&quot;
+ * android:valueFrom=&quot;0&quot;
+ * android:valueTo=&quot;360&quot; /&gt;
+ * </pre></li>
+ * <li>Here is the path_morph.xml, which will morph the path from one shape to
+ * the other. Note that the paths must be compatible for morphing.
+ * In more details, the paths should have exact same length of commands , and
+ * exact same length of parameters for each commands.
+ * Note that the path string are better stored in strings.xml for reusing.
+ * <pre>
+ * &lt;set xmlns:android=&quot;http://schemas.android.com/apk/res/android&quot;&gt;
+ * &lt;objectAnimator
+ * android:duration=&quot;3000&quot;
+ * android:propertyName=&quot;pathData&quot;
+ * android:valueFrom=&quot;M300,70 l 0,-70 70,70 0,0 -70,70z&quot;
+ * android:valueTo=&quot;M300,70 l 0,-70 70,0 0,140 -70,0 z&quot;
+ * android:valueType=&quot;pathType&quot;/&gt;
+ * &lt;/set&gt;
+ * </pre></li>
+ *
+ * @attr ref android.R.styleable#AnimatedVectorDrawable_drawable
+ * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_name
+ * @attr ref android.R.styleable#AnimatedVectorDrawableTarget_animation
+ */
+public class AnimatedVectorDrawable extends Drawable implements Animatable {
+ private static final String LOGTAG = AnimatedVectorDrawable.class.getSimpleName();
+
+ private static final String ANIMATED_VECTOR = "animated-vector";
+ private static final String TARGET = "target";
+
+ private static final boolean DBG_ANIMATION_VECTOR_DRAWABLE = false;
+
+ private final AnimatedVectorDrawableState mAnimatedVectorState;
+
+
+ public AnimatedVectorDrawable() {
+ mAnimatedVectorState = new AnimatedVectorDrawableState(
+ new AnimatedVectorDrawableState(null));
+ }
+
+ private AnimatedVectorDrawable(AnimatedVectorDrawableState state, Resources res,
+ Theme theme) {
+ // TODO: Correctly handle the constant state for AVD.
+ mAnimatedVectorState = new AnimatedVectorDrawableState(state);
+ if (theme != null && canApplyTheme()) {
+ applyTheme(theme);
+ }
+ }
+
+ @Override
+ public ConstantState getConstantState() {
+ return null;
+ }
+
+ @Override
+ public void draw(Canvas canvas) {
+ mAnimatedVectorState.mVectorDrawable.draw(canvas);
+ if (isRunning()) {
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected void onBoundsChange(Rect bounds) {
+ mAnimatedVectorState.mVectorDrawable.setBounds(bounds);
+ }
+
+ @Override
+ public int getAlpha() {
+ return mAnimatedVectorState.mVectorDrawable.getAlpha();
+ }
+
+ @Override
+ public void setAlpha(int alpha) {
+ mAnimatedVectorState.mVectorDrawable.setAlpha(alpha);
+ }
+
+ @Override
+ public void setColorFilter(ColorFilter colorFilter) {
+ mAnimatedVectorState.mVectorDrawable.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public int getOpacity() {
+ return mAnimatedVectorState.mVectorDrawable.getOpacity();
+ }
+
+ @Override
+ public int getIntrinsicWidth() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicWidth();
+ }
+
+ @Override
+ public int getIntrinsicHeight() {
+ return mAnimatedVectorState.mVectorDrawable.getIntrinsicHeight();
+ }
+
+ @Override
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+
+ int eventType = parser.getEventType();
+ while (eventType != XmlPullParser.END_DOCUMENT) {
+ if (eventType == XmlPullParser.START_TAG) {
+ final String tagName = parser.getName();
+ if (ANIMATED_VECTOR.equals(tagName)) {
+ final TypedArray a = obtainAttributes(res, theme, attrs,
+ R.styleable.AnimatedVectorDrawable);
+ int drawableRes = a.getResourceId(
+ R.styleable.AnimatedVectorDrawable_drawable, 0);
+ if (drawableRes != 0) {
+ mAnimatedVectorState.mVectorDrawable = (VectorDrawable) res.getDrawable(
+ drawableRes);
+ }
+ a.recycle();
+ } else if (TARGET.equals(tagName)) {
+ final TypedArray a = obtainAttributes(res, theme, attrs,
+ R.styleable.AnimatedVectorDrawableTarget);
+ final String target = a.getString(
+ R.styleable.AnimatedVectorDrawableTarget_name);
+
+ int id = a.getResourceId(
+ R.styleable.AnimatedVectorDrawableTarget_animation, 0);
+ if (id != 0) {
+ Animator objectAnimator = AnimatorInflater.loadAnimator(res, theme, id);
+ setupAnimatorsForTarget(target, objectAnimator);
+ }
+ a.recycle();
+ }
+ }
+
+ eventType = parser.next();
+ }
+ }
+
+ @Override
+ public boolean canApplyTheme() {
+ return super.canApplyTheme() || mAnimatedVectorState != null
+ && mAnimatedVectorState.canApplyTheme();
+ }
+
+ @Override
+ public void applyTheme(Theme t) {
+ super.applyTheme(t);
+
+ final VectorDrawable vectorDrawable = mAnimatedVectorState.mVectorDrawable;
+ if (vectorDrawable != null && vectorDrawable.canApplyTheme()) {
+ vectorDrawable.applyTheme(t);
+ }
+ }
+
+ private static class AnimatedVectorDrawableState extends ConstantState {
+ int mChangingConfigurations;
+ VectorDrawable mVectorDrawable;
+ ArrayList<Animator> mAnimators;
+
+ public AnimatedVectorDrawableState(AnimatedVectorDrawableState copy) {
+ if (copy != null) {
+ mChangingConfigurations = copy.mChangingConfigurations;
+ // TODO: Make sure the constant state are handled correctly.
+ mVectorDrawable = new VectorDrawable();
+ mAnimators = new ArrayList<Animator>();
+ }
+ }
+
+ @Override
+ public Drawable newDrawable() {
+ return new AnimatedVectorDrawable(this, null, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res) {
+ return new AnimatedVectorDrawable(this, res, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res, Theme theme) {
+ return new AnimatedVectorDrawable(this, res, theme);
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return mChangingConfigurations;
+ }
+ }
+
+ private void setupAnimatorsForTarget(String name, Animator animator) {
+ Object target = mAnimatedVectorState.mVectorDrawable.getTargetByName(name);
+ animator.setTarget(target);
+ mAnimatedVectorState.mAnimators.add(animator);
+ if (DBG_ANIMATION_VECTOR_DRAWABLE) {
+ Log.v(LOGTAG, "add animator for target " + name + " " + animator);
+ }
+ }
+
+ @Override
+ public boolean isRunning() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ if (animator.isRunning()) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void start() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ if (animator.isPaused()) {
+ animator.resume();
+ } else if (!animator.isRunning()) {
+ animator.start();
+ }
+ }
+ invalidateSelf();
+ }
+
+ @Override
+ public void stop() {
+ final ArrayList<Animator> animators = mAnimatedVectorState.mAnimators;
+ final int size = animators.size();
+ for (int i = 0; i < size; i++) {
+ final Animator animator = animators.get(i);
+ animator.pause();
+ }
+ }
+}
diff --git a/graphics/java/android/graphics/drawable/AnimationDrawable.java b/graphics/java/android/graphics/drawable/AnimationDrawable.java
index 16548d0..0740761 100644
--- a/graphics/java/android/graphics/drawable/AnimationDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimationDrawable.java
@@ -28,7 +28,6 @@ import android.os.SystemClock;
import android.util.AttributeSet;
/**
- *
* An object used to create frame-by-frame animations, defined by a series of Drawable objects,
* which can be used as a View object's background.
* <p>
@@ -91,10 +90,10 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
@Override
public boolean setVisible(boolean visible, boolean restart) {
- boolean changed = super.setVisible(visible, restart);
+ final boolean changed = super.setVisible(visible, restart);
if (visible) {
if (changed || restart) {
- setFrame(0, true, restart || mCurFrame >= 0);
+ setFrame(0, true, mAnimating);
}
} else {
unscheduleSelf(this);
@@ -114,6 +113,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
* @see #isRunning()
* @see #stop()
*/
+ @Override
public void start() {
if (!isRunning()) {
run();
@@ -127,6 +127,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
* @see #isRunning()
* @see #start()
*/
+ @Override
public void stop() {
if (isRunning()) {
unscheduleSelf(this);
@@ -138,6 +139,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
*
* @return true if the animation is running, false otherwise
*/
+ @Override
public boolean isRunning() {
return mAnimating;
}
@@ -148,6 +150,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
*
* @see #start()
*/
+ @Override
public void run() {
nextFrame(false);
}
@@ -165,41 +168,41 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
public int getNumberOfFrames() {
return mAnimationState.getChildCount();
}
-
+
/**
* @return The Drawable at the specified frame index
*/
public Drawable getFrame(int index) {
return mAnimationState.getChild(index);
}
-
+
/**
- * @return The duration in milliseconds of the frame at the
+ * @return The duration in milliseconds of the frame at the
* specified index
*/
public int getDuration(int i) {
return mAnimationState.mDurations[i];
}
-
+
/**
* @return True of the animation will play once, false otherwise
*/
public boolean isOneShot() {
return mAnimationState.mOneShot;
}
-
+
/**
* Sets whether the animation should play once or repeat.
- *
+ *
* @param oneShot Pass true if the animation should only play once
*/
public void setOneShot(boolean oneShot) {
mAnimationState.mOneShot = oneShot;
}
-
+
/**
* Add a frame to the animation
- *
+ *
* @param frame The frame to add
* @param duration How long in milliseconds the frame should appear
*/
@@ -209,7 +212,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
setFrame(0, true, false);
}
}
-
+
private void nextFrame(boolean unschedule) {
int next = mCurFrame+1;
final int N = mAnimationState.getChildCount();
@@ -239,21 +242,21 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
@Override
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
-
+
TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.AnimationDrawable);
super.inflateWithAttributes(r, parser, a,
com.android.internal.R.styleable.AnimationDrawable_visible);
-
+
mAnimationState.setVariablePadding(a.getBoolean(
com.android.internal.R.styleable.AnimationDrawable_variablePadding, false));
-
+
mAnimationState.mOneShot = a.getBoolean(
com.android.internal.R.styleable.AnimationDrawable_oneshot, false);
-
+
a.recycle();
-
+
int type;
final int innerDepth = parser.getDepth()+1;
@@ -267,7 +270,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
if (depth > innerDepth || !parser.getName().equals("item")) {
continue;
}
-
+
a = r.obtainAttributes(attrs, com.android.internal.R.styleable.AnimationDrawableItem);
int duration = a.getInt(
com.android.internal.R.styleable.AnimationDrawableItem_duration, -1);
@@ -278,9 +281,9 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
}
int drawableRes = a.getResourceId(
com.android.internal.R.styleable.AnimationDrawableItem_drawable, 0);
-
+
a.recycle();
-
+
Drawable dr;
if (drawableRes != 0) {
dr = r.getDrawable(drawableRes);
@@ -295,7 +298,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
}
dr = Drawable.createFromXmlInner(r, parser, attrs, theme);
}
-
+
mAnimationState.addFrame(dr, duration);
if (dr != null) {
dr.setCallback(this);
@@ -342,7 +345,7 @@ public class AnimationDrawable extends DrawableContainer implements Runnable, An
}
public void addFrame(Drawable dr, int dur) {
- // Do not combine the following. The array index must be evaluated before
+ // Do not combine the following. The array index must be evaluated before
// the array is accessed because super.addChild(dr) has a side effect on mDurations.
int pos = super.addChild(dr);
mDurations[pos] = dur;
diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java
index ef6c085..e080375 100644
--- a/graphics/java/android/graphics/drawable/BitmapDrawable.java
+++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java
@@ -31,6 +31,7 @@ import android.graphics.Paint;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
+import android.graphics.drawable.ColorDrawable.ColorState;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Shader;
@@ -618,9 +619,11 @@ public class BitmapDrawable extends Drawable {
@Override
public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
- mBitmapState.mTint = tint;
- mBitmapState.mTintMode = tintMode;
- computeTintFilter();
+ final BitmapState state = mBitmapState;
+ state.mTint = tint;
+ state.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
invalidateSelf();
}
@@ -638,21 +641,6 @@ public class BitmapDrawable extends Drawable {
return mBitmapState.mTintMode;
}
- private void computeTintFilter() {
- final BitmapState state = mBitmapState;
- if (state.mTint != null && state.mTintMode != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- if (mTintFilter != null) {
- mTintFilter.setColor(color);
- mTintFilter.setMode(state.mTintMode);
- } else {
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- } else {
- mTintFilter = null;
- }
- }
-
/**
* @hide Candidate for future API inclusion
*/
@@ -679,17 +667,11 @@ public class BitmapDrawable extends Drawable {
@Override
protected boolean onStateChange(int[] stateSet) {
- final ColorStateList tint = mBitmapState.mTint;
- if (tint != null) {
- final int newColor = tint.getColorForState(stateSet, 0);
- final int oldColor = mTintFilter.getColor();
- if (oldColor != newColor) {
- mTintFilter.setColor(newColor);
- invalidateSelf();
- return true;
- }
+ final BitmapState state = mBitmapState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
}
-
return false;
}
@@ -775,7 +757,18 @@ public class BitmapDrawable extends Drawable {
final int tileMode = a.getInt(R.styleable.BitmapDrawable_tileMode, TILE_MODE_UNDEFINED);
if (tileMode != TILE_MODE_UNDEFINED) {
- setTileModeInternal(tileMode);
+ final Shader.TileMode mode = parseTileMode(tileMode);
+ setTileModeXY(mode, mode);
+ }
+
+ final int tileModeX = a.getInt(R.styleable.BitmapDrawable_tileModeX, TILE_MODE_UNDEFINED);
+ if (tileModeX != TILE_MODE_UNDEFINED) {
+ setTileModeX(parseTileMode(tileModeX));
+ }
+
+ final int tileModeY = a.getInt(R.styleable.BitmapDrawable_tileModeY, TILE_MODE_UNDEFINED);
+ if (tileModeY != TILE_MODE_UNDEFINED) {
+ setTileModeY(parseTileMode(tileModeY));
}
// Update local properties.
@@ -801,20 +794,16 @@ public class BitmapDrawable extends Drawable {
}
}
- private void setTileModeInternal(final int tileMode) {
+ private static Shader.TileMode parseTileMode(int tileMode) {
switch (tileMode) {
- case TILE_MODE_DISABLED:
- setTileModeXY(null, null);
- break;
case TILE_MODE_CLAMP:
- setTileModeXY(Shader.TileMode.CLAMP, Shader.TileMode.CLAMP);
- break;
+ return Shader.TileMode.CLAMP;
case TILE_MODE_REPEAT:
- setTileModeXY(Shader.TileMode.REPEAT, Shader.TileMode.REPEAT);
- break;
+ return Shader.TileMode.REPEAT;
case TILE_MODE_MIRROR:
- setTileModeXY(Shader.TileMode.MIRROR, Shader.TileMode.MIRROR);
- break;
+ return Shader.TileMode.MIRROR;
+ default:
+ return null;
}
}
@@ -937,7 +926,9 @@ public class BitmapDrawable extends Drawable {
}
/**
- * Initializes local dynamic properties from state.
+ * Initializes local dynamic properties from state. This should be called
+ * after significant state changes, e.g. from the One True Constructor and
+ * after inflating or applying a theme.
*/
private void initializeWithState(BitmapState state, Resources res) {
if (res != null) {
@@ -946,7 +937,7 @@ public class BitmapDrawable extends Drawable {
mTargetDensity = state.mTargetDensity;
}
- computeTintFilter();
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
computeBitmapSize();
}
}
diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java
index 3ac9972..174de3a 100644
--- a/graphics/java/android/graphics/drawable/ClipDrawable.java
+++ b/graphics/java/android/graphics/drawable/ClipDrawable.java
@@ -19,10 +19,12 @@ package android.graphics.drawable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
import android.view.Gravity;
import android.util.AttributeSet;
@@ -52,7 +54,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
public static final int HORIZONTAL = 1;
public static final int VERTICAL = 2;
-
+
ClipDrawable() {
this(null, null);
}
@@ -111,6 +113,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
// overrides from Drawable.Callback
+ @Override
public void invalidateDrawable(Drawable who) {
final Callback callback = getCallback();
if (callback != null) {
@@ -118,6 +121,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
}
}
+ @Override
public void scheduleDrawable(Drawable who, Runnable what, long when) {
final Callback callback = getCallback();
if (callback != null) {
@@ -125,6 +129,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
}
}
+ @Override
public void unscheduleDrawable(Drawable who, Runnable what) {
final Callback callback = getCallback();
if (callback != null) {
@@ -169,6 +174,11 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mClipState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mClipState.mDrawable.getOpacity();
}
@@ -197,7 +207,7 @@ public class ClipDrawable extends Drawable implements Drawable.Callback {
@Override
public void draw(Canvas canvas) {
-
+
if (mClipState.mDrawable.getLevel() == 0) {
return;
}
diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java
index df5ca33..3716182 100644
--- a/graphics/java/android/graphics/drawable/ColorDrawable.java
+++ b/graphics/java/android/graphics/drawable/ColorDrawable.java
@@ -17,6 +17,8 @@
package android.graphics.drawable;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
@@ -39,9 +41,13 @@ import java.io.IOException;
* @attr ref android.R.styleable#ColorDrawable_color
*/
public class ColorDrawable extends Drawable {
+ private final Paint mPaint = new Paint();
+
@ViewDebug.ExportedProperty(deepExport = true, prefix = "state_")
private ColorState mColorState;
- private final Paint mPaint = new Paint();
+ private ColorStateList mTint;
+ private PorterDuffColorFilter mTintFilter;
+
private boolean mMutated;
/**
@@ -84,9 +90,17 @@ public class ColorDrawable extends Drawable {
@Override
public void draw(Canvas canvas) {
- if ((mColorState.mUseColor >>> 24) != 0) {
+ final ColorFilter colorFilter = mPaint.getColorFilter();
+ if ((mColorState.mUseColor >>> 24) != 0 || colorFilter != null || mTintFilter != null) {
+ if (colorFilter == null) {
+ mPaint.setColorFilter(mTintFilter);
+ }
+
mPaint.setColor(mColorState.mUseColor);
canvas.drawRect(getBounds(), mPaint);
+
+ // Restore original color filter.
+ mPaint.setColorFilter(colorFilter);
}
}
@@ -141,16 +155,51 @@ public class ColorDrawable extends Drawable {
}
/**
- * Setting a color filter on a ColorDrawable has no effect.
+ * Sets the color filter applied to this color.
+ * <p>
+ * Only supported on version {@link android.os.Build.VERSION_CODES#L} and
+ * above. Calling this method has no effect on earlier versions.
*
- * @param colorFilter Ignore.
+ * @see android.graphics.drawable.Drawable#setColorFilter(ColorFilter)
*/
@Override
public void setColorFilter(ColorFilter colorFilter) {
+ mPaint.setColorFilter(colorFilter);
+ }
+
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ final ColorState state = mColorState;
+ if (state.mTint != tint || state.mTintMode != tintMode) {
+ state.mTint = tint;
+ state.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
+ }
+ }
+
+ @Override
+ protected boolean onStateChange(int[] stateSet) {
+ final ColorState state = mColorState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public boolean isStateful() {
+ return mTint != null && mTint.isStateful();
}
@Override
public int getOpacity() {
+ if (mTintFilter != null || mPaint.getColorFilter() != null) {
+ return PixelFormat.TRANSLUCENT;
+ }
+
switch (mColorState.mUseColor >>> 24) {
case 255:
return PixelFormat.OPAQUE;
@@ -165,8 +214,7 @@ public class ColorDrawable extends Drawable {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
- final TypedArray a = obtainAttributes(
- r, theme, attrs, R.styleable.ColorDrawable);
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ColorDrawable);
inflateStateFromTypedArray(a);
a.recycle();
}
@@ -225,21 +273,25 @@ public class ColorDrawable extends Drawable {
}
final static class ColorState extends ConstantState {
+ int[] mThemeAttrs;
int mBaseColor; // base color, independent of setAlpha()
@ViewDebug.ExportedProperty
int mUseColor; // basecolor modulated by setAlpha()
int mChangingConfigurations;
- int[] mThemeAttrs;
+ ColorStateList mTint;
+ Mode mTintMode;
ColorState() {
// Empty constructor.
}
ColorState(ColorState state) {
+ mThemeAttrs = state.mThemeAttrs;
mBaseColor = state.mBaseColor;
mUseColor = state.mUseColor;
mChangingConfigurations = state.mChangingConfigurations;
- mThemeAttrs = state.mThemeAttrs;
+ mTint = state.mTint;
+ mTintMode = state.mTintMode;
}
@Override
@@ -276,6 +328,6 @@ public class ColorDrawable extends Drawable {
mColorState = state;
}
- // No local properties to initialize.
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
}
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 18e8e52..40b55a7 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -17,13 +17,6 @@
package android.graphics.drawable;
import android.annotation.NonNull;
-import android.graphics.Insets;
-import android.graphics.Xfermode;
-import android.os.Trace;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
@@ -31,15 +24,19 @@ import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
+import android.graphics.Insets;
import android.graphics.NinePatch;
import android.graphics.Outline;
import android.graphics.PixelFormat;
import android.graphics.PorterDuff;
+import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Region;
-import android.graphics.PorterDuff.Mode;
+import android.graphics.Xfermode;
+import android.os.Trace;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.StateSet;
@@ -47,6 +44,9 @@ import android.util.TypedValue;
import android.util.Xml;
import android.view.View;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
@@ -209,7 +209,7 @@ public abstract class Drawable {
* stored bounds of this drawable.
*
* @see #copyBounds()
- * @see #copyBounds(android.graphics.Rect)
+ * @see #copyBounds(android.graphics.Rect)
*/
public final Rect getBounds() {
if (mBounds == ZERO_BOUNDS_RECT) {
@@ -328,8 +328,8 @@ public abstract class Drawable {
* that want to support animated drawables.
*
* @param cb The client's Callback implementation.
- *
- * @see #getCallback()
+ *
+ * @see #getCallback()
*/
public final void setCallback(Callback cb) {
mCallback = new WeakReference<Callback>(cb);
@@ -338,10 +338,10 @@ public abstract class Drawable {
/**
* Return the current {@link Callback} implementation attached to this
* Drawable.
- *
+ *
* @return A {@link Callback} instance or null if no callback was set.
- *
- * @see #setCallback(android.graphics.drawable.Drawable.Callback)
+ *
+ * @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public Callback getCallback() {
if (mCallback != null) {
@@ -349,15 +349,15 @@ public abstract class Drawable {
}
return null;
}
-
+
/**
* Use the current {@link Callback} implementation to have this Drawable
* redrawn. Does nothing if there is no Callback attached to the
* Drawable.
*
* @see Callback#invalidateDrawable
- * @see #getCallback()
- * @see #setCallback(android.graphics.drawable.Drawable.Callback)
+ * @see #getCallback()
+ * @see #setCallback(android.graphics.drawable.Drawable.Callback)
*/
public void invalidateSelf() {
final Callback callback = getCallback();
@@ -931,7 +931,7 @@ public abstract class Drawable {
Rects only to drop them on the floor.
*/
Rect pad = new Rect();
-
+
// Special stuff for compatibility mode: if the target density is not
// the same as the display density, but the resource -is- the same as
// the display density, then don't scale it down to the target density.
@@ -1040,6 +1040,8 @@ public abstract class Drawable {
drawable = new GradientDrawable();
} else if (name.equals("vector")) {
drawable = new VectorDrawable();
+ } else if (name.equals("animated-vector")) {
+ drawable = new AnimatedVectorDrawable();
} else if (name.equals("scale")) {
drawable = new ScaleDrawable();
} else if (name.equals("clip")) {
@@ -1047,7 +1049,7 @@ public abstract class Drawable {
} else if (name.equals("rotate")) {
drawable = new RotateDrawable();
} else if (name.equals("animated-rotate")) {
- drawable = new AnimatedRotateDrawable();
+ drawable = new AnimatedRotateDrawable();
} else if (name.equals("animation-list")) {
drawable = new AnimationDrawable();
} else if (name.equals("inset")) {
@@ -1224,6 +1226,26 @@ public abstract class Drawable {
}
/**
+ * Ensures the tint filter is consistent with the current tint color and
+ * mode.
+ */
+ PorterDuffColorFilter updateTintFilter(PorterDuffColorFilter tintFilter, ColorStateList tint,
+ PorterDuff.Mode tintMode) {
+ if (tint == null || tintMode == null) {
+ return null;
+ }
+
+ final int color = tint.getColorForState(getState(), Color.TRANSPARENT);
+ if (tintFilter == null) {
+ return new PorterDuffColorFilter(color, tintMode);
+ }
+
+ tintFilter.setColor(color);
+ tintFilter.setMode(tintMode);
+ return tintFilter;
+ }
+
+ /**
* Obtains styled attributes from the theme, if available, or unstyled
* resources if the theme is null.
*/
@@ -1238,8 +1260,10 @@ public abstract class Drawable {
/**
* Parses a {@link android.graphics.PorterDuff.Mode} from a tintMode
* attribute's enum value.
+ *
+ * @hide
*/
- static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
+ public static PorterDuff.Mode parseTintMode(int value, Mode defaultMode) {
switch (value) {
case 3: return Mode.SRC_OVER;
case 5: return Mode.SRC_IN;
diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java
index 2aef39f..38b8aaf 100644
--- a/graphics/java/android/graphics/drawable/DrawableContainer.java
+++ b/graphics/java/android/graphics/drawable/DrawableContainer.java
@@ -16,6 +16,7 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.graphics.Canvas;
@@ -23,6 +24,7 @@ import android.graphics.ColorFilter;
import android.graphics.Insets;
import android.graphics.PixelFormat;
import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
import android.os.SystemClock;
import android.util.LayoutDirection;
import android.util.SparseArray;
@@ -63,8 +65,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
private long mExitAnimationEnd;
private Drawable mLastDrawable;
- private Insets mInsets = Insets.NONE;
-
// overrides from Drawable
@Override
@@ -116,7 +116,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
*/
@Override
public Insets getOpticalInsets() {
- return mInsets;
+ if (mCurrDrawable != null) {
+ return mCurrDrawable.getOpticalInsets();
+ }
+ return Insets.NONE;
}
@Override
@@ -151,7 +154,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
@Override
public void setColorFilter(ColorFilter cf) {
- mDrawableContainerState.mHasColorFilter = true;
+ mDrawableContainerState.mHasColorFilter = (cf != null);
if (mDrawableContainerState.mColorFilter != cf) {
mDrawableContainerState.mColorFilter = cf;
@@ -162,6 +165,20 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
}
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mDrawableContainerState.mHasTint = (tint != null && tintMode != null);
+
+ if (mDrawableContainerState.mTint != tint || mDrawableContainerState.mTintMode != tintMode) {
+ mDrawableContainerState.mTint = tint;
+ mDrawableContainerState.mTintMode = tintMode;
+
+ if (mCurrDrawable != null) {
+ mCurrDrawable.mutate().setTint(tint, tintMode);
+ }
+ }
+ }
+
/**
* Change the global fade duration when a new drawable is entering
* the scene.
@@ -187,9 +204,6 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
}
if (mCurrDrawable != null) {
mCurrDrawable.setBounds(bounds);
-
- // Must obtain optical insets after setting bounds.
- mInsets = mCurrDrawable.getOpticalInsets();
}
}
@@ -396,6 +410,8 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
}
if (mDrawableContainerState.mHasColorFilter) {
d.setColorFilter(mDrawableContainerState.mColorFilter);
+ } else if (mDrawableContainerState.mHasTint) {
+ d.setTint(mDrawableContainerState.mTint, mDrawableContainerState.mTintMode);
}
d.setVisible(isVisible(), true);
d.setDither(mDrawableContainerState.mDither);
@@ -404,15 +420,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
d.setBounds(getBounds());
d.setLayoutDirection(getLayoutDirection());
d.setAutoMirrored(mDrawableContainerState.mAutoMirrored);
-
- // Must obtain optical insets after setting bounds.
- mInsets = d.getOpticalInsets();
- } else {
- mInsets = Insets.NONE;
}
} else {
mCurrDrawable = null;
- mInsets = Insets.NONE;
mCurIndex = -1;
}
@@ -566,6 +576,10 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
ColorFilter mColorFilter;
boolean mHasColorFilter;
+ ColorStateList mTint;
+ Mode mTintMode;
+ boolean mHasTint;
+
DrawableContainerState(DrawableContainerState orig, DrawableContainer owner,
Resources res) {
mOwner = owner;
@@ -588,6 +602,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
mAutoMirrored = orig.mAutoMirrored;
mColorFilter = orig.mColorFilter;
mHasColorFilter = orig.mHasColorFilter;
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
+ mHasTint = orig.mHasTint;
// Cloning the following values may require creating futures.
mConstantPadding = orig.getConstantPadding();
@@ -741,7 +758,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback {
final int N = mNumChildren;
final Drawable[] drawables = mDrawables;
for (int i = 0; i < N; i++) {
- final Drawable d = drawables[i];
+ final Drawable d = drawables[i];
if (d != null) {
if (d.canApplyTheme()) {
return true;
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 005b8ef..0ccce93 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -135,18 +135,17 @@ public class GradientDrawable extends Drawable {
private Paint mStrokePaint; // optional, set by the caller
private ColorFilter mColorFilter; // optional, set by the caller
private int mAlpha = 0xFF; // modified by the caller
- private boolean mDither;
private final Path mPath = new Path();
private final RectF mRect = new RectF();
private Paint mLayerPaint; // internal, used if we use saveLayer()
- private boolean mRectIsDirty; // internal state
+ private boolean mGradientIsDirty; // internal state
private boolean mMutated;
private Path mRingPath;
private boolean mPathIsDirty = true;
- /** Current gradient radius, valid when {@link #mRectIsDirty} is false. */
+ /** Current gradient radius, valid when {@link #mGradientIsDirty} is false. */
private float mGradientRadius;
/**
@@ -384,7 +383,7 @@ public class GradientDrawable extends Drawable {
*/
public void setGradientType(int gradient) {
mGradientState.setGradientType(gradient);
- mRectIsDirty = true;
+ mGradientIsDirty = true;
invalidateSelf();
}
@@ -403,7 +402,7 @@ public class GradientDrawable extends Drawable {
*/
public void setGradientCenter(float x, float y) {
mGradientState.setGradientCenter(x, y);
- mRectIsDirty = true;
+ mGradientIsDirty = true;
invalidateSelf();
}
@@ -421,7 +420,7 @@ public class GradientDrawable extends Drawable {
*/
public void setGradientRadius(float gradientRadius) {
mGradientState.setGradientRadius(gradientRadius, TypedValue.COMPLEX_UNIT_PX);
- mRectIsDirty = true;
+ mGradientIsDirty = true;
invalidateSelf();
}
@@ -455,7 +454,7 @@ public class GradientDrawable extends Drawable {
*/
public void setUseLevel(boolean useLevel) {
mGradientState.mUseLevel = useLevel;
- mRectIsDirty = true;
+ mGradientIsDirty = true;
invalidateSelf();
}
@@ -483,7 +482,7 @@ public class GradientDrawable extends Drawable {
*/
public void setOrientation(Orientation orientation) {
mGradientState.mOrientation = orientation;
- mRectIsDirty = true;
+ mGradientIsDirty = true;
invalidateSelf();
}
@@ -501,7 +500,7 @@ public class GradientDrawable extends Drawable {
*/
public void setColors(int[] colors) {
mGradientState.setColors(colors);
- mRectIsDirty = true;
+ mGradientIsDirty = true;
invalidateSelf();
}
@@ -543,7 +542,7 @@ public class GradientDrawable extends Drawable {
if (mLayerPaint == null) {
mLayerPaint = new Paint();
}
- mLayerPaint.setDither(mDither);
+ mLayerPaint.setDither(st.mDither);
mLayerPaint.setAlpha(mAlpha);
mLayerPaint.setColorFilter(mColorFilter);
@@ -561,14 +560,14 @@ public class GradientDrawable extends Drawable {
individual paints
*/
mFillPaint.setAlpha(currFillAlpha);
- mFillPaint.setDither(mDither);
+ mFillPaint.setDither(st.mDither);
mFillPaint.setColorFilter(mColorFilter);
- if (mColorFilter != null && mGradientState.mColorStateList == null) {
+ if (mColorFilter != null && st.mColorStateList == null) {
mFillPaint.setColor(mAlpha << 24);
}
if (haveStroke) {
mStrokePaint.setAlpha(currStrokeAlpha);
- mStrokePaint.setDither(mDither);
+ mStrokePaint.setDither(st.mDither);
mStrokePaint.setColorFilter(mColorFilter);
}
}
@@ -638,10 +637,11 @@ public class GradientDrawable extends Drawable {
private void buildPathIfDirty() {
final GradientState st = mGradientState;
- if (mPathIsDirty || mRectIsDirty) {
+ if (mPathIsDirty) {
+ ensureValidRect();
mPath.reset();
mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
- mPathIsDirty = mRectIsDirty = false;
+ mPathIsDirty = false;
}
}
@@ -804,8 +804,8 @@ public class GradientDrawable extends Drawable {
@Override
public void setDither(boolean dither) {
- if (dither != mDither) {
- mDither = dither;
+ if (dither != mGradientState.mDither) {
+ mGradientState.mDither = dither;
invalidateSelf();
}
}
@@ -829,27 +829,27 @@ public class GradientDrawable extends Drawable {
super.onBoundsChange(r);
mRingPath = null;
mPathIsDirty = true;
- mRectIsDirty = true;
+ mGradientIsDirty = true;
}
@Override
protected boolean onLevelChange(int level) {
super.onLevelChange(level);
- mRectIsDirty = true;
+ mGradientIsDirty = true;
mPathIsDirty = true;
invalidateSelf();
return true;
}
/**
- * This checks mRectIsDirty, and if it is true, recomputes both our drawing
+ * This checks mGradientIsDirty, and if it is true, recomputes both our drawing
* rectangle (mRect) and the gradient itself, since it depends on our
* rectangle too.
* @return true if the resulting rectangle is not empty, false otherwise
*/
private boolean ensureValidRect() {
- if (mRectIsDirty) {
- mRectIsDirty = false;
+ if (mGradientIsDirty) {
+ mGradientIsDirty = false;
Rect bounds = getBounds();
float inset = 0;
@@ -1015,7 +1015,7 @@ public class GradientDrawable extends Drawable {
state.mThemeAttrs = a.extractThemeAttrs();
state.mShape = a.getInt(R.styleable.GradientDrawable_shape, state.mShape);
- mDither = a.getBoolean(R.styleable.GradientDrawable_dither, mDither);
+ state.mDither = a.getBoolean(R.styleable.GradientDrawable_dither, state.mDither);
if (state.mShape == RING) {
state.mInnerRadius = a.getDimensionPixelSize(
@@ -1459,6 +1459,8 @@ public class GradientDrawable extends Drawable {
public float mThicknessRatio = DEFAULT_THICKNESS_RATIO;
public int mInnerRadius = -1;
public int mThickness = -1;
+ public boolean mDither = false;
+
private float mCenterX = 0.5f;
private float mCenterY = 0.5f;
private float mGradientRadius = 0.5f;
@@ -1510,6 +1512,7 @@ public class GradientDrawable extends Drawable {
mThicknessRatio = state.mThicknessRatio;
mInnerRadius = state.mInnerRadius;
mThickness = state.mThickness;
+ mDither = state.mDither;
mCenterX = state.mCenterX;
mCenterY = state.mCenterY;
mGradientRadius = state.mGradientRadius;
@@ -1672,7 +1675,7 @@ public class GradientDrawable extends Drawable {
initializeWithState(state);
- mRectIsDirty = true;
+ mGradientIsDirty = true;
mMutated = false;
}
diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java
index 9e0ab86..220e81c 100644
--- a/graphics/java/android/graphics/drawable/InsetDrawable.java
+++ b/graphics/java/android/graphics/drawable/InsetDrawable.java
@@ -19,10 +19,12 @@ package android.graphics.drawable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
import android.util.AttributeSet;
import android.util.Log;
@@ -44,8 +46,7 @@ import java.io.IOException;
* @attr ref android.R.styleable#InsetDrawable_insetTop
* @attr ref android.R.styleable#InsetDrawable_insetBottom
*/
-public class InsetDrawable extends Drawable implements Drawable.Callback
-{
+public class InsetDrawable extends Drawable implements Drawable.Callback {
// Most of this is copied from ScaleDrawable.
private InsetState mInsetState;
private final Rect mTmpRect = new Rect();
@@ -62,13 +63,13 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
public InsetDrawable(Drawable drawable, int insetLeft, int insetTop,
int insetRight, int insetBottom) {
this(null, null);
-
+
mInsetState.mDrawable = drawable;
mInsetState.mInsetLeft = insetLeft;
mInsetState.mInsetTop = insetTop;
mInsetState.mInsetRight = insetRight;
mInsetState.mInsetBottom = insetBottom;
-
+
if (drawable != null) {
drawable.setCallback(this);
}
@@ -78,7 +79,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs, Theme theme)
throws XmlPullParserException, IOException {
int type;
-
+
TypedArray a = r.obtainAttributes(attrs,
com.android.internal.R.styleable.InsetDrawable);
@@ -168,7 +169,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
| mInsetState.mChangingConfigurations
| mInsetState.mDrawable.getChangingConfigurations();
}
-
+
@Override
public boolean getPadding(Rect padding) {
boolean pad = mInsetState.mDrawable.getPadding(padding);
@@ -178,7 +179,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
padding.top += mInsetState.mInsetTop;
padding.bottom += mInsetState.mInsetBottom;
- if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
+ if (pad || (mInsetState.mInsetLeft | mInsetState.mInsetRight |
mInsetState.mInsetTop | mInsetState.mInsetBottom) != 0) {
return true;
} else {
@@ -217,6 +218,11 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
mInsetState.mDrawable.setColorFilter(cf);
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mInsetState.mDrawable.setTint(tint, tintMode);
+ }
+
/** {@hide} */
@Override
public void setLayoutDirection(int layoutDirection) {
@@ -227,7 +233,7 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
public int getOpacity() {
return mInsetState.mDrawable.getOpacity();
}
-
+
@Override
public boolean isStateful() {
return mInsetState.mDrawable.isStateful();
@@ -239,7 +245,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
onBoundsChange(getBounds());
return changed;
}
-
+
+ @Override
+ protected boolean onLevelChange(int level) {
+ return mInsetState.mDrawable.setLevel(level);
+ }
+
@Override
protected void onBoundsChange(Rect bounds) {
final Rect r = mTmpRect;
@@ -321,12 +332,12 @@ public class InsetDrawable extends Drawable implements Drawable.Callback
public Drawable newDrawable() {
return new InsetDrawable(this, null);
}
-
+
@Override
public Drawable newDrawable(Resources res) {
return new InsetDrawable(this, res);
}
-
+
@Override
public int getChangingConfigurations() {
return mChangingConfigurations;
diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java
index 27f0a9d..5cea7c9 100644
--- a/graphics/java/android/graphics/drawable/LayerDrawable.java
+++ b/graphics/java/android/graphics/drawable/LayerDrawable.java
@@ -16,12 +16,14 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff.Mode;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.View;
@@ -630,6 +632,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback {
}
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ final ChildDrawable[] array = mLayerState.mChildren;
+ final int N = mLayerState.mNum;
+ for (int i = 0; i < N; i++) {
+ array[i].mDrawable.setTint(tint, tintMode);
+ }
+ }
+
/**
* Sets the opacity of this drawable directly, instead of collecting the
* states from the layers
diff --git a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
index 9e56f67..c484094 100644
--- a/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
+++ b/graphics/java/android/graphics/drawable/MaterialProgressDrawable.java
@@ -27,8 +27,10 @@ import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Paint;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Paint.Cap;
import android.graphics.Paint.Style;
+import android.graphics.PorterDuff.Mode;
import android.graphics.PixelFormat;
import android.graphics.Rect;
import android.graphics.RectF;
@@ -67,6 +69,7 @@ class MaterialProgressDrawable extends Drawable implements Animatable {
private final Ring mRing;
private MaterialProgressState mState;
+ private PorterDuffColorFilter mTintFilter;
/** Canvas rotation in degrees. */
private float mRotation;
@@ -106,6 +109,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable {
float insets = minEdge / 2.0f - state.mInnerRadius;
ring.setInsets(insets);
}
+
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
}
@Override
@@ -118,15 +123,21 @@ class MaterialProgressDrawable extends Drawable implements Animatable {
}
@Override
- protected boolean onStateChange(int[] state) {
- boolean changed = super.onStateChange(state);
+ protected boolean onStateChange(int[] stateSet) {
+ boolean changed = super.onStateChange(stateSet);
- final int color = mState.mColor.getColorForState(state, Color.TRANSPARENT);
+ final MaterialProgressState state = mState;
+ final int color = state.mColor.getColorForState(stateSet, Color.TRANSPARENT);
if (color != mRing.getColor()) {
mRing.setColor(color);
changed = true;
}
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ changed = true;
+ }
+
return changed;
}
@@ -223,11 +234,24 @@ class MaterialProgressDrawable extends Drawable implements Animatable {
return mRing.getColorFilter();
}
+ @Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ if (mState.mTint != tint || mState.mTintMode != tintMode) {
+ mState.mTint = tint;
+ mState.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
+ }
+ }
+
+ @SuppressWarnings("unused")
private void setRotation(float rotation) {
mRotation = rotation;
invalidateSelf();
}
+ @SuppressWarnings("unused")
private float getRotation() {
return mRotation;
}
@@ -331,6 +355,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable {
private int mWidth = -1;
private int mHeight = -1;
private ColorStateList mColor = ColorStateList.valueOf(Color.TRANSPARENT);
+ private ColorStateList mTint = null;
+ private Mode mTintMode = null;
public MaterialProgressState(MaterialProgressState orig) {
if (orig != null) {
@@ -340,6 +366,8 @@ class MaterialProgressDrawable extends Drawable implements Animatable {
mWidth = orig.mWidth;
mHeight = orig.mHeight;
mColor = orig.mColor;
+ mTint = orig.mTint;
+ mTintMode = orig.mTintMode;
}
}
diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
index fea68ee..28335ea 100644
--- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java
+++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java
@@ -327,25 +327,12 @@ public class NinePatchDrawable extends Drawable {
@Override
public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
- mNinePatchState.mTint = tint;
- mNinePatchState.mTintMode = tintMode;
- computeTintFilter();
- invalidateSelf();
- }
-
- private void computeTintFilter() {
final NinePatchState state = mNinePatchState;
- if (state.mTint != null && state.mTintMode != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- if (mTintFilter != null) {
- mTintFilter.setColor(color);
- mTintFilter.setMode(state.mTintMode);
- } else {
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- } else {
- mTintFilter = null;
- }
+ state.mTint = tint;
+ state.mTintMode = tintMode;
+
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
}
@Override
@@ -549,15 +536,10 @@ public class NinePatchDrawable extends Drawable {
@Override
protected boolean onStateChange(int[] stateSet) {
- final ColorStateList tint = mNinePatchState.mTint;
- if (tint != null) {
- final int newColor = tint.getColorForState(stateSet, 0);
- final int oldColor = mTintFilter.getColor();
- if (oldColor != newColor) {
- mTintFilter.setColor(newColor);
- invalidateSelf();
- return true;
- }
+ final NinePatchState state = mNinePatchState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
}
return false;
@@ -689,7 +671,7 @@ public class NinePatchDrawable extends Drawable {
mPadding = new Rect(state.mPadding);
}
- computeTintFilter();
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
setNinePatch(state.mNinePatch);
}
}
diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java
index c71cda1..a82e7b9 100644
--- a/graphics/java/android/graphics/drawable/PaintDrawable.java
+++ b/graphics/java/android/graphics/drawable/PaintDrawable.java
@@ -35,7 +35,7 @@ public class PaintDrawable extends ShapeDrawable {
public PaintDrawable(int color) {
getPaint().setColor(color);
}
-
+
/**
* Specify radius for the corners of the rectangle. If this is > 0, then the
* drawable is drawn in a round-rectangle, rather than a rectangle.
@@ -51,7 +51,7 @@ public class PaintDrawable extends ShapeDrawable {
}
setCornerRadii(radii);
}
-
+
/**
* Specify radii for each of the 4 corners. For each corner, the array
* contains 2 values, [X_radius, Y_radius]. The corners are ordered
@@ -78,9 +78,9 @@ public class PaintDrawable extends ShapeDrawable {
int radius = a.getDimensionPixelSize(
com.android.internal.R.styleable.DrawableCorners_radius, 0);
setCornerRadius(radius);
-
+
// now check of they have any per-corner radii
-
+
int topLeftRadius = a.getDimensionPixelSize(
com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius);
int topRightRadius = a.getDimensionPixelSize(
diff --git a/graphics/java/android/graphics/drawable/PictureDrawable.java b/graphics/java/android/graphics/drawable/PictureDrawable.java
index cb2d8f6..6dcda1f 100644
--- a/graphics/java/android/graphics/drawable/PictureDrawable.java
+++ b/graphics/java/android/graphics/drawable/PictureDrawable.java
@@ -25,7 +25,7 @@ import android.graphics.Rect;
/**
* Drawable subclass that wraps a Picture, allowing the picture to be used
- * whereever a Drawable is supported.
+ * wherever a Drawable is supported.
*/
public class PictureDrawable extends Drawable {
@@ -40,7 +40,7 @@ public class PictureDrawable extends Drawable {
public PictureDrawable(Picture picture) {
mPicture = picture;
}
-
+
/**
* Return the picture associated with the drawable. May be null.
*
@@ -49,7 +49,7 @@ public class PictureDrawable extends Drawable {
public Picture getPicture() {
return mPicture;
}
-
+
/**
* Associate a picture with this drawable. The picture may be null.
*
@@ -58,7 +58,7 @@ public class PictureDrawable extends Drawable {
public void setPicture(Picture picture) {
mPicture = picture;
}
-
+
@Override
public void draw(Canvas canvas) {
if (mPicture != null) {
@@ -86,16 +86,16 @@ public class PictureDrawable extends Drawable {
// not sure, so be safe
return PixelFormat.TRANSLUCENT;
}
-
+
@Override
public void setFilterBitmap(boolean filter) {}
-
+
@Override
public void setDither(boolean dither) {}
-
+
@Override
public void setColorFilter(ColorFilter colorFilter) {}
-
+
@Override
public void setAlpha(int alpha) {}
}
diff --git a/graphics/java/android/graphics/drawable/Ripple.java b/graphics/java/android/graphics/drawable/Ripple.java
index 345400e..2d49365 100644
--- a/graphics/java/android/graphics/drawable/Ripple.java
+++ b/graphics/java/android/graphics/drawable/Ripple.java
@@ -142,14 +142,16 @@ class Ripple {
}
private void clampStartingPosition() {
- final float dX = mStartingX - mBounds.exactCenterX();
- final float dY = mStartingY - mBounds.exactCenterY();
+ final float cX = mBounds.exactCenterX();
+ final float cY = mBounds.exactCenterY();
+ final float dX = mStartingX - cX;
+ final float dY = mStartingY - cY;
final float r = mOuterRadius;
if (dX * dX + dY * dY > r * r) {
// Point is outside the circle, clamp to the circumference.
final double angle = Math.atan2(dY, dX);
- mClampedStartingX = (float) (Math.cos(angle) * r);
- mClampedStartingY = (float) (Math.sin(angle) * r);
+ mClampedStartingX = cX + (float) (Math.cos(angle) * r);
+ mClampedStartingY = cY + (float) (Math.sin(angle) * r);
} else {
mClampedStartingX = mStartingX;
mClampedStartingY = mStartingY;
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 0512ecc..f2e75a5 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -645,25 +645,29 @@ public class RippleDrawable extends LayerDrawable {
@Override
public Rect getDirtyBounds() {
- final Rect drawingBounds = mDrawingBounds;
- final Rect dirtyBounds = mDirtyBounds;
- dirtyBounds.set(drawingBounds);
- drawingBounds.setEmpty();
-
- final int cX = (int) mHotspotBounds.exactCenterX();
- final int cY = (int) mHotspotBounds.exactCenterY();
- final Rect rippleBounds = mTempRect;
- final Ripple[] activeRipples = mAnimatingRipples;
- final int N = mAnimatingRipplesCount;
- for (int i = 0; i < N; i++) {
- activeRipples[i].getBounds(rippleBounds);
- rippleBounds.offset(cX, cY);
- drawingBounds.union(rippleBounds);
- }
+ if (isProjected()) {
+ final Rect drawingBounds = mDrawingBounds;
+ final Rect dirtyBounds = mDirtyBounds;
+ dirtyBounds.set(drawingBounds);
+ drawingBounds.setEmpty();
+
+ final int cX = (int) mHotspotBounds.exactCenterX();
+ final int cY = (int) mHotspotBounds.exactCenterY();
+ final Rect rippleBounds = mTempRect;
+ final Ripple[] activeRipples = mAnimatingRipples;
+ final int N = mAnimatingRipplesCount;
+ for (int i = 0; i < N; i++) {
+ activeRipples[i].getBounds(rippleBounds);
+ rippleBounds.offset(cX, cY);
+ drawingBounds.union(rippleBounds);
+ }
- dirtyBounds.union(drawingBounds);
- dirtyBounds.union(super.getDirtyBounds());
- return dirtyBounds;
+ dirtyBounds.union(drawingBounds);
+ dirtyBounds.union(super.getDirtyBounds());
+ return dirtyBounds;
+ } else {
+ return getBounds();
+ }
}
@Override
diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java
index 06aeb98..8f8fa98 100644
--- a/graphics/java/android/graphics/drawable/RotateDrawable.java
+++ b/graphics/java/android/graphics/drawable/RotateDrawable.java
@@ -22,6 +22,8 @@ import org.xmlpull.v1.XmlPullParserException;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Rect;
+import android.graphics.PorterDuff.Mode;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
@@ -137,6 +139,11 @@ public class RotateDrawable extends Drawable implements Drawable.Callback {
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mState.mDrawable.getOpacity();
}
diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java
index f090c11..46c92fe 100644
--- a/graphics/java/android/graphics/drawable/ScaleDrawable.java
+++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java
@@ -19,10 +19,12 @@ package android.graphics.drawable;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.Resources.Theme;
import android.graphics.*;
+import android.graphics.PorterDuff.Mode;
import android.view.Gravity;
import android.util.AttributeSet;
@@ -188,6 +190,11 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback {
}
@Override
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ mScaleState.mDrawable.setTint(tint, tintMode);
+ }
+
+ @Override
public int getOpacity() {
return mScaleState.mDrawable.getOpacity();
}
diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java
index 024f77c..86765dd 100644
--- a/graphics/java/android/graphics/drawable/ShapeDrawable.java
+++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java
@@ -24,6 +24,7 @@ import android.graphics.ColorFilter;
import android.graphics.Outline;
import android.graphics.Paint;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
@@ -32,6 +33,7 @@ import android.graphics.drawable.shapes.Shape;
import android.content.res.Resources.Theme;
import android.util.AttributeSet;
+import com.android.internal.R;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -74,7 +76,7 @@ public class ShapeDrawable extends Drawable {
* ShapeDrawable constructor.
*/
public ShapeDrawable() {
- this((ShapeState) null);
+ this(new ShapeState(null), null, null);
}
/**
@@ -83,20 +85,11 @@ public class ShapeDrawable extends Drawable {
* @param s the Shape that this ShapeDrawable should be
*/
public ShapeDrawable(Shape s) {
- this((ShapeState) null);
+ this(new ShapeState(null), null, null);
mShapeState.mShape = s;
}
- private ShapeDrawable(ShapeState state) {
- mShapeState = new ShapeState(state);
-
- if (state != null && state.mTint != null) {
- final int color = state.mTint.getColorForState(getState(), 0);
- mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
- }
- }
-
/**
* Returns the Shape of this ShapeDrawable.
*/
@@ -292,31 +285,13 @@ public class ShapeDrawable extends Drawable {
}
@Override
- public void setTint(ColorStateList tint, Mode tintMode) {
- if (mShapeState.mTint != tint || mShapeState.mTintMode != tintMode) {
- mShapeState.mTint = tint;
- mShapeState.mTintMode = tintMode;
- updateTintFilter();
- invalidateSelf();
- }
- }
+ public void setTint(ColorStateList tint, PorterDuff.Mode tintMode) {
+ final ShapeState state = mShapeState;
+ state.mTint = tint;
+ state.mTintMode = tintMode;
- /**
- * Ensures the tint filter is consistent with the current tint color and
- * mode.
- */
- private void updateTintFilter() {
- final ColorStateList tint = mShapeState.mTint;
- final Mode tintMode = mShapeState.mTintMode;
- if (tint != null && tintMode != null) {
- if (mTintFilter == null) {
- mTintFilter = new PorterDuffColorFilter(0, tintMode);
- } else {
- mTintFilter.setMode(tintMode);
- }
- } else {
- mTintFilter = null;
- }
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ invalidateSelf();
}
@Override
@@ -357,17 +332,11 @@ public class ShapeDrawable extends Drawable {
@Override
protected boolean onStateChange(int[] stateSet) {
- final ColorStateList tint = mShapeState.mTint;
- if (tint != null) {
- final int newColor = tint.getColorForState(stateSet, 0);
- final int oldColor = mTintFilter.getColor();
- if (oldColor != newColor) {
- mTintFilter.setColor(newColor);
- invalidateSelf();
- return true;
- }
+ final ShapeState state = mShapeState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ return true;
}
-
return false;
}
@@ -408,20 +377,8 @@ public class ShapeDrawable extends Drawable {
throws XmlPullParserException, IOException {
super.inflate(r, parser, attrs, theme);
- TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawable);
-
- int color = mShapeState.mPaint.getColor();
- color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color);
- mShapeState.mPaint.setColor(color);
-
- boolean dither = a.getBoolean(com.android.internal.R.styleable.ShapeDrawable_dither, false);
- mShapeState.mPaint.setDither(dither);
-
- setIntrinsicWidth((int)
- a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f));
- setIntrinsicHeight((int)
- a.getDimension(com.android.internal.R.styleable.ShapeDrawable_height, 0f));
-
+ final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.ShapeDrawable);
+ updateStateFromTypedArray(a);
a.recycle();
int type;
@@ -439,6 +396,57 @@ public class ShapeDrawable extends Drawable {
" for ShapeDrawable " + this);
}
}
+
+ // Update local properties.
+ initializeWithState(mShapeState, r);
+ }
+
+ @Override
+ public void applyTheme(Theme t) {
+ super.applyTheme(t);
+
+ final ShapeState state = mShapeState;
+ if (state == null || state.mThemeAttrs == null) {
+ return;
+ }
+
+ final TypedArray a = t.resolveAttributes(state.mThemeAttrs, R.styleable.ShapeDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+
+ // Update local properties.
+ initializeWithState(state, t.getResources());
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) {
+ final ShapeState state = mShapeState;
+ final Paint paint = state.mPaint;
+
+ // Extract the theme attributes, if any.
+ state.mThemeAttrs = a.extractThemeAttrs();
+
+ int color = paint.getColor();
+ color = a.getColor(R.styleable.ShapeDrawable_color, color);
+ paint.setColor(color);
+
+ boolean dither = paint.isDither();
+ dither = a.getBoolean(R.styleable.ShapeDrawable_dither, dither);
+ paint.setDither(dither);
+
+ setIntrinsicWidth((int) a.getDimension(
+ R.styleable.ShapeDrawable_width, state.mIntrinsicWidth));
+ setIntrinsicHeight((int) a.getDimension(
+ R.styleable.ShapeDrawable_height, state.mIntrinsicHeight));
+
+ final int tintMode = a.getInt(R.styleable.ShapeDrawable_tintMode, -1);
+ if (tintMode != -1) {
+ state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+ }
+
+ final ColorStateList tint = a.getColorStateList(R.styleable.ShapeDrawable_tint);
+ if (tint != null) {
+ state.mTint = tint;
+ }
}
private void updateShape() {
@@ -498,6 +506,7 @@ public class ShapeDrawable extends Drawable {
* Defines the intrinsic properties of this ShapeDrawable's Shape.
*/
final static class ShapeState extends ConstantState {
+ int[] mThemeAttrs;
int mChangingConfigurations;
Paint mPaint;
Shape mShape;
@@ -511,6 +520,7 @@ public class ShapeDrawable extends Drawable {
ShapeState(ShapeState orig) {
if (orig != null) {
+ mThemeAttrs = orig.mThemeAttrs;
mPaint = orig.mPaint;
mShape = orig.mShape;
mTint = orig.mTint;
@@ -526,13 +536,23 @@ public class ShapeDrawable extends Drawable {
}
@Override
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null;
+ }
+
+ @Override
public Drawable newDrawable() {
- return new ShapeDrawable(this);
+ return new ShapeDrawable(this, null, null);
}
@Override
public Drawable newDrawable(Resources res) {
- return new ShapeDrawable(this);
+ return new ShapeDrawable(this, res, null);
+ }
+
+ @Override
+ public Drawable newDrawable(Resources res, Theme theme) {
+ return new ShapeDrawable(this, res, theme);
}
@Override
@@ -542,6 +562,30 @@ public class ShapeDrawable extends Drawable {
}
/**
+ * The one constructor to rule them all. This is called by all public
+ * constructors to set the state and initialize local properties.
+ */
+ private ShapeDrawable(ShapeState state, Resources res, Theme theme) {
+ if (theme != null && state.canApplyTheme()) {
+ mShapeState = new ShapeState(state);
+ applyTheme(theme);
+ } else {
+ mShapeState = state;
+ }
+
+ initializeWithState(state, res);
+ }
+
+ /**
+ * Initializes local dynamic properties from state. This should be called
+ * after significant state changes, e.g. from the One True Constructor and
+ * after inflating or applying a theme.
+ */
+ private void initializeWithState(ShapeState state, Resources res) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ }
+
+ /**
* Base class defines a factory object that is called each time the drawable
* is resized (has a new width or height). Its resize() method returns a
* corresponding shader, or null. Implement this class if you'd like your
diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java
index b2fac9b..f359fdd 100644
--- a/graphics/java/android/graphics/drawable/StateListDrawable.java
+++ b/graphics/java/android/graphics/drawable/StateListDrawable.java
@@ -235,10 +235,10 @@ public class StateListDrawable extends DrawableContainer {
public Drawable getStateDrawable(int index) {
return mStateListState.getChild(index);
}
-
+
/**
* Gets the index of the drawable with the provided state set.
- *
+ *
* @param stateSet the state set to look up
* @return the index of the provided state set, or -1 if not found
* @hide pending API council
@@ -248,7 +248,7 @@ public class StateListDrawable extends DrawableContainer {
public int getStateDrawableIndex(int[] stateSet) {
return mStateListState.indexOfStateSet(stateSet);
}
-
+
@Override
public Drawable mutate() {
if (!mMutated && super.mutate() == this) {
diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java
index 622e90b..4380ca4 100644
--- a/graphics/java/android/graphics/drawable/TransitionDrawable.java
+++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java
@@ -42,20 +42,20 @@ import android.os.SystemClock;
public class TransitionDrawable extends LayerDrawable implements Drawable.Callback {
/**
- * A transition is about to start.
+ * A transition is about to start.
*/
private static final int TRANSITION_STARTING = 0;
-
+
/**
* The transition has started and the animation is in progress
*/
private static final int TRANSITION_RUNNING = 1;
-
+
/**
* No transition will be applied
*/
private static final int TRANSITION_NONE = 2;
-
+
/**
* The current state of the transition. One of {@link #TRANSITION_STARTING},
* {@link #TRANSITION_RUNNING} and {@link #TRANSITION_NONE}
@@ -101,10 +101,10 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
LayerState createConstantState(LayerState state, Resources res) {
return new TransitionState((TransitionState) state, this, res);
}
-
+
/**
* Begin the second layer on top of the first layer.
- *
+ *
* @param durationMillis The length of the transition in milliseconds
*/
public void startTransition(int durationMillis) {
@@ -116,7 +116,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
mTransitionState = TRANSITION_STARTING;
invalidateSelf();
}
-
+
/**
* Show only the first layer.
*/
@@ -184,7 +184,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
}
break;
}
-
+
final int alpha = mAlpha;
final boolean crossFade = mCrossFade;
final ChildDrawable[] array = mLayerState.mChildren;
@@ -217,7 +217,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba
d.draw(canvas);
d.setAlpha(0xFF);
}
-
+
if (!done) {
invalidateSelf();
}
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index 9a63fa3..c98f2a1 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -14,20 +14,26 @@
package android.graphics.drawable;
+import android.content.res.ColorStateList;
import android.content.res.Resources;
import android.content.res.Resources.Theme;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.Color;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathMeasure;
import android.graphics.PixelFormat;
+import android.graphics.PorterDuffColorFilter;
import android.graphics.Rect;
import android.graphics.Region;
+import android.graphics.PorterDuff.Mode;
+import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
+import android.util.PathParser;
import android.util.Xml;
import com.android.internal.R;
@@ -39,8 +45,7 @@ import org.xmlpull.v1.XmlPullParserFactory;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.HashMap;
+import java.util.Stack;
/**
* This lets you create a drawable based on an XML vector graphic It can be
@@ -58,9 +63,26 @@ import java.util.HashMap;
* <dd>Used to defined the size of the virtual canvas the paths are drawn on.
* The size is defined using the attributes <code>android:viewportHeight</code>
* <code>android:viewportWidth</code></dd>
+ * <dt><code>&lt;group></code></dt>
+ * <dd>Defines a group of paths or subgroups, plus transformation information.
+ * The transformations are defined in the same coordinates as the viewport.
+ * And the transformations are applied in the order of scale, rotate then translate. </dd>
+ * <dt><code>android:rotation</code>
+ * <dd>The degrees of rotation of the group.</dd></dt>
+ * <dt><code>android:pivotX</code>
+ * <dd>The X coordinate of the pivot for the scale and rotation of the group</dd></dt>
+ * <dt><code>android:pivotY</code>
+ * <dd>The Y coordinate of the pivot for the scale and rotation of the group</dd></dt>
+ * <dt><code>android:scaleX</code>
+ * <dd>The amount of scale on the X Coordinate</dd></dt>
+ * <dt><code>android:scaleY</code>
+ * <dd>The amount of scale on the Y coordinate</dd></dt>
+ * <dt><code>android:translateX</code>
+ * <dd>The amount of translation on the X coordinate</dd></dt>
+ * <dt><code>android:translateY</code>
+ * <dd>The amount of translation on the Y coordinate</dd></dt>
* <dt><code>&lt;path></code></dt>
- * <dd>Defines paths to be drawn. Multiple paths can be defined in one xml file.
- * The paths are drawn in the order of their definition order.
+ * <dd>Defines paths to be drawn.
* <dl>
* <dt><code>android:name</code>
* <dd>Defines the name of the path.</dd></dt>
@@ -76,12 +98,6 @@ import java.util.HashMap;
* <dd>The width a path stroke</dd></dt>
* <dt><code>android:strokeOpacity</code>
* <dd>The opacity of a path stroke</dd></dt>
- * <dt><code>android:rotation</code>
- * <dd>The amount to rotation the path stroke.</dd></dt>
- * <dt><code>android:pivotX</code>
- * <dd>The X coordinate of the center of rotation of a path</dd></dt>
- * <dt><code>android:pivotY</code>
- * <dd>The Y coordinate of the center of rotation of a path</dd></dt>
* <dt><code>android:fillOpacity</code>
* <dd>The opacity to fill the path with</dd></dt>
* <dt><code>android:trimPathStart</code>
@@ -101,13 +117,13 @@ import java.util.HashMap;
* <dd>Sets the Miter limit for a stroked path</dd></dt>
* </dl>
* </dd>
- * @hide
*/
public class VectorDrawable extends Drawable {
private static final String LOGTAG = VectorDrawable.class.getSimpleName();
private static final String SHAPE_SIZE = "size";
private static final String SHAPE_VIEWPORT = "viewport";
+ private static final String SHAPE_GROUP = "group";
private static final String SHAPE_PATH = "path";
private static final String SHAPE_VECTOR = "vector";
@@ -119,20 +135,33 @@ public class VectorDrawable extends Drawable {
private static final int LINEJOIN_ROUND = 1;
private static final int LINEJOIN_BEVEL = 2;
+ private static final boolean DBG_VECTOR_DRAWABLE = false;
+
private final VectorDrawableState mVectorState;
- private int mAlpha = 0xFF;
+ private final ArrayMap<String, Object> mVGTargetsMap = new ArrayMap<String, Object>();
+
+ private PorterDuffColorFilter mTintFilter;
public VectorDrawable() {
mVectorState = new VectorDrawableState(null);
}
private VectorDrawable(VectorDrawableState state, Resources res, Theme theme) {
- mVectorState = new VectorDrawableState(state);
-
- if (theme != null && canApplyTheme()) {
+ if (theme != null && state.canApplyTheme()) {
+ // If we need to apply a theme, implicitly mutate.
+ mVectorState = new VectorDrawableState(state);
applyTheme(theme);
+ } else {
+ mVectorState = state;
}
+
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+ }
+
+ Object getTargetByName(String name) {
+ return mVGTargetsMap.get(name);
}
@Override
@@ -150,78 +179,72 @@ public class VectorDrawable extends Drawable {
}
@Override
+ public int getAlpha() {
+ return mVectorState.mVPathRenderer.getRootAlpha();
+ }
+
+ @Override
public void setAlpha(int alpha) {
- // TODO correct handling of transparent
- if (mAlpha != alpha) {
- mAlpha = alpha;
+ if (mVectorState.mVPathRenderer.getRootAlpha() != alpha) {
+ mVectorState.mVPathRenderer.setRootAlpha(alpha);
invalidateSelf();
}
}
@Override
public void setColorFilter(ColorFilter colorFilter) {
- mVectorState.mVPathRenderer.setColorFilter(colorFilter);
+ final VectorDrawableState state = mVectorState;
+ if (colorFilter != null) {
+ // Color filter overrides tint.
+ mTintFilter = null;
+ } else if (state.mTint != null && state.mTintMode != null) {
+ // Restore the tint filter, if we need one.
+ final int color = state.mTint.getColorForState(getState(), Color.TRANSPARENT);
+ mTintFilter = new PorterDuffColorFilter(color, state.mTintMode);
+ colorFilter = mTintFilter;
+ }
+
+ state.mVPathRenderer.setColorFilter(colorFilter);
invalidateSelf();
}
@Override
- public int getOpacity() {
- return PixelFormat.TRANSLUCENT;
- }
-
- /**
- * Sets padding for this shape, defined by a Rect object. Define the padding
- * in the Rect object as: left, top, right, bottom.
- */
- public void setPadding(Rect padding) {
- setPadding(padding.left, padding.top, padding.right, padding.bottom);
- }
+ public void setTint(ColorStateList tint, Mode tintMode) {
+ final VectorDrawableState state = mVectorState;
+ if (state.mTint != tint || state.mTintMode != tintMode) {
+ state.mTint = tint;
+ state.mTintMode = tintMode;
- /**
- * Sets padding for the shape.
- *
- * @param left padding for the left side (in pixels)
- * @param top padding for the top (in pixels)
- * @param right padding for the right side (in pixels)
- * @param bottom padding for the bottom (in pixels)
- */
- public void setPadding(int left, int top, int right, int bottom) {
- if ((left | top | right | bottom) == 0) {
- mVectorState.mPadding = null;
- } else {
- if (mVectorState.mPadding == null) {
- mVectorState.mPadding = new Rect();
- }
- mVectorState.mPadding.set(left, top, right, bottom);
+ mTintFilter = updateTintFilter(mTintFilter, tint, tintMode);
+ mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+ invalidateSelf();
}
- invalidateSelf();
}
@Override
- public int getIntrinsicWidth() {
- return (int) mVectorState.mVPathRenderer.mBaseWidth;
+ protected boolean onStateChange(int[] stateSet) {
+ final VectorDrawableState state = mVectorState;
+ if (state.mTint != null && state.mTintMode != null) {
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ mVectorState.mVPathRenderer.setColorFilter(mTintFilter);
+ return true;
+ }
+ return false;
}
@Override
- public int getIntrinsicHeight() {
- return (int) mVectorState.mVPathRenderer.mBaseHeight;
+ public int getOpacity() {
+ return PixelFormat.TRANSLUCENT;
}
@Override
- public boolean getPadding(Rect padding) {
- if (mVectorState.mPadding != null) {
- padding.set(mVectorState.mPadding);
- return true;
- } else {
- return super.getPadding(padding);
- }
+ public int getIntrinsicWidth() {
+ return (int) mVectorState.mVPathRenderer.mBaseWidth;
}
@Override
- public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
- throws XmlPullParserException, IOException {
- final VPathRenderer p = inflateInternal(res, parser, attrs, theme);
- setPathRenderer(p);
+ public int getIntrinsicHeight() {
+ return (int) mVectorState.mVPathRenderer.mBaseHeight;
}
@Override
@@ -260,24 +283,71 @@ public class VectorDrawable extends Drawable {
return null;
}
- private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs,
- Theme theme) throws XmlPullParserException, IOException {
+ private static int applyAlpha(int color, float alpha) {
+ int alphaBytes = Color.alpha(color);
+ color &= 0x00FFFFFF;
+ color |= ((int) (alphaBytes * alpha)) << 24;
+ return color;
+ }
+
+
+ @Override
+ public void inflate(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
+ final TypedArray a = obtainAttributes(res, theme, attrs,R.styleable.VectorDrawable);
+ updateStateFromTypedArray(a);
+ a.recycle();
+
+ final VectorDrawableState state = mVectorState;
+ state.mVPathRenderer = inflateInternal(res, parser, attrs, theme);
+
+ mTintFilter = updateTintFilter(mTintFilter, state.mTint, state.mTintMode);
+ state.mVPathRenderer.setColorFilter(mTintFilter);
+ }
+
+ private void updateStateFromTypedArray(TypedArray a) {
+ final VectorDrawableState state = mVectorState;
+
+ // Extract the theme attributes, if any.
+ state.mThemeAttrs = a.extractThemeAttrs();
+
+ final int tintMode = a.getInt(R.styleable.VectorDrawable_tintMode, -1);
+ if (tintMode != -1) {
+ state.mTintMode = Drawable.parseTintMode(tintMode, Mode.SRC_IN);
+ }
+
+ final ColorStateList tint = a.getColorStateList(R.styleable.VectorDrawable_tint);
+ if (tint != null) {
+ state.mTint = tint;
+ }
+ }
+
+ private VPathRenderer inflateInternal(Resources res, XmlPullParser parser, AttributeSet attrs, Theme theme)
+ throws XmlPullParserException, IOException {
final VPathRenderer pathRenderer = new VPathRenderer();
boolean noSizeTag = true;
boolean noViewportTag = true;
boolean noPathTag = true;
- VGroup currentGroup = new VGroup();
+ // Use a stack to help to build the group tree.
+ // The top of the stack is always the current group.
+ final Stack<VGroup> groupStack = new Stack<VGroup>();
+ groupStack.push(pathRenderer.mRootGroup);
int eventType = parser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
if (eventType == XmlPullParser.START_TAG) {
final String tagName = parser.getName();
+ final VGroup currentGroup = groupStack.peek();
+
if (SHAPE_PATH.equals(tagName)) {
final VPath path = new VPath();
path.inflate(res, attrs, theme);
currentGroup.add(path);
+ if (path.getPathName() != null) {
+ mVGTargetsMap.put(path.getPathName(), path);
+ }
noPathTag = false;
} else if (SHAPE_SIZE.equals(tagName)) {
pathRenderer.parseSize(res, attrs);
@@ -285,12 +355,29 @@ public class VectorDrawable extends Drawable {
} else if (SHAPE_VIEWPORT.equals(tagName)) {
pathRenderer.parseViewport(res, attrs);
noViewportTag = false;
+ } else if (SHAPE_GROUP.equals(tagName)) {
+ VGroup newChildGroup = new VGroup();
+ newChildGroup.inflate(res, attrs, theme);
+ currentGroup.mChildGroupList.add(newChildGroup);
+ groupStack.push(newChildGroup);
+ if (newChildGroup.getGroupName() != null) {
+ mVGTargetsMap.put(newChildGroup.getGroupName(), newChildGroup);
+ }
+ }
+ } else if (eventType == XmlPullParser.END_TAG) {
+ final String tagName = parser.getName();
+ if (SHAPE_GROUP.equals(tagName)) {
+ groupStack.pop();
}
}
-
eventType = parser.next();
}
+ // Print the tree out for debug.
+ if (DBG_VECTOR_DRAWABLE) {
+ printGroupTree(pathRenderer.mRootGroup, 0);
+ }
+
if (noSizeTag || noViewportTag || noPathTag) {
final StringBuffer tag = new StringBuffer();
@@ -315,26 +402,39 @@ public class VectorDrawable extends Drawable {
throw new XmlPullParserException("no " + tag + " defined");
}
- pathRenderer.mCurrentGroup = currentGroup;
- // post parse cleanup
- pathRenderer.parseFinish();
return pathRenderer;
}
- private void setPathRenderer(VPathRenderer pathRenderer) {
- mVectorState.mVPathRenderer = pathRenderer;
+ private void printGroupTree(VGroup currentGroup, int level) {
+ String indent = "";
+ for (int i = 0 ; i < level ; i++) {
+ indent += " ";
+ }
+ // Print the current node
+ Log.v(LOGTAG, indent + "current group is :" + currentGroup.getGroupName()
+ + " rotation is " + currentGroup.mRotate);
+ Log.v(LOGTAG, indent + "matrix is :" + currentGroup.getLocalMatrix().toString());
+ // Then print all the children
+ for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
+ printGroupTree(currentGroup.mChildGroupList.get(i), level + 1);
+ }
}
private static class VectorDrawableState extends ConstantState {
+ int[] mThemeAttrs;
int mChangingConfigurations;
VPathRenderer mVPathRenderer;
- Rect mPadding;
+ ColorStateList mTint;
+ Mode mTintMode;
public VectorDrawableState(VectorDrawableState copy) {
if (copy != null) {
+ mThemeAttrs = copy.mThemeAttrs;
mChangingConfigurations = copy.mChangingConfigurations;
+ // TODO: Make sure the constant state are handled correctly.
mVPathRenderer = new VPathRenderer(copy.mVPathRenderer);
- mPadding = new Rect(copy.mPadding);
+ mTint = copy.mTint;
+ mTintMode = copy.mTintMode;
}
}
@@ -360,35 +460,51 @@ public class VectorDrawable extends Drawable {
}
private static class VPathRenderer {
+ /* Right now the internal data structure is organized as a tree.
+ * Each node can be a group node, or a path.
+ * A group node can have groups or paths as children, but a path node has
+ * no children.
+ * One example can be:
+ * Root Group
+ * / | \
+ * Group Path Group
+ * / \ |
+ * Path Path Path
+ *
+ */
+ private final VGroup mRootGroup;
+
private final Path mPath = new Path();
private final Path mRenderPath = new Path();
- private final Matrix mMatrix = new Matrix();
+ private static final Matrix IDENTITY_MATRIX = new Matrix();
- private VPath[] mCurrentPaths;
private Paint mStrokePaint;
private Paint mFillPaint;
private ColorFilter mColorFilter;
private PathMeasure mPathMeasure;
- private VGroup mCurrentGroup = new VGroup();
+ private float mBaseWidth = 0;
+ private float mBaseHeight = 0;
+ private float mViewportWidth = 0;
+ private float mViewportHeight = 0;
+ private int mRootAlpha = 0xFF;
- float mBaseWidth = 0;
- float mBaseHeight = 0;
- float mViewportWidth = 0;
- float mViewportHeight = 0;
+ private final Matrix mFinalPathMatrix = new Matrix();
public VPathRenderer() {
+ mRootGroup = new VGroup();
}
- public VPathRenderer(VPathRenderer copy) {
- mCurrentGroup = copy.mCurrentGroup;
- if (copy.mCurrentPaths != null) {
- mCurrentPaths = new VPath[copy.mCurrentPaths.length];
- for (int i = 0; i < mCurrentPaths.length; i++) {
- mCurrentPaths[i] = new VPath(copy.mCurrentPaths[i]);
- }
- }
+ public void setRootAlpha(int alpha) {
+ mRootAlpha = alpha;
+ }
+
+ public int getRootAlpha() {
+ return mRootAlpha;
+ }
+ public VPathRenderer(VPathRenderer copy) {
+ mRootGroup = copy.mRootGroup;
mBaseWidth = copy.mBaseWidth;
mBaseHeight = copy.mBaseHeight;
mViewportWidth = copy.mViewportHeight;
@@ -396,24 +512,59 @@ public class VectorDrawable extends Drawable {
}
public boolean canApplyTheme() {
- final ArrayList<VPath> paths = mCurrentGroup.mVGList;
+ // If one of the paths can apply theme, then return true;
+ return recursiveCanApplyTheme(mRootGroup);
+ }
+
+ private boolean recursiveCanApplyTheme(VGroup currentGroup) {
+ // We can do a tree traverse here, if there is one path return true,
+ // then we return true for the whole tree.
+ final ArrayList<VPath> paths = currentGroup.mPathList;
for (int j = paths.size() - 1; j >= 0; j--) {
final VPath path = paths.get(j);
if (path.canApplyTheme()) {
return true;
}
}
+
+ final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
+
+ for (int i = 0; i < childGroups.size(); i++) {
+ VGroup childGroup = childGroups.get(i);
+ if (childGroup.canApplyTheme()
+ || recursiveCanApplyTheme(childGroup)) {
+ return true;
+ }
+ }
return false;
}
public void applyTheme(Theme t) {
- final ArrayList<VPath> paths = mCurrentGroup.mVGList;
+ // Apply theme to every path of the tree.
+ recursiveApplyTheme(mRootGroup, t);
+ }
+
+ private void recursiveApplyTheme(VGroup currentGroup, Theme t) {
+ // We can do a tree traverse here, apply theme to all paths which
+ // can apply theme.
+ final ArrayList<VPath> paths = currentGroup.mPathList;
for (int j = paths.size() - 1; j >= 0; j--) {
final VPath path = paths.get(j);
if (path.canApplyTheme()) {
path.applyTheme(t);
}
}
+
+ final ArrayList<VGroup> childGroups = currentGroup.mChildGroupList;
+
+ for (int i = 0; i < childGroups.size(); i++) {
+ VGroup childGroup = childGroups.get(i);
+ if (childGroup.canApplyTheme()) {
+ childGroup.applyTheme(t);
+ }
+ recursiveApplyTheme(childGroup, t);
+ }
+
}
public void setColorFilter(ColorFilter colorFilter) {
@@ -426,107 +577,110 @@ public class VectorDrawable extends Drawable {
if (mStrokePaint != null) {
mStrokePaint.setColorFilter(colorFilter);
}
+
}
- public void draw(Canvas canvas, int w, int h) {
- if (mCurrentPaths == null) {
- Log.e(LOGTAG,"mCurrentPaths == null");
- return;
+ private void drawGroupTree(VGroup currentGroup, Matrix currentMatrix,
+ float currentAlpha, Canvas canvas, int w, int h) {
+ // Calculate current group's matrix by preConcat the parent's and
+ // and the current one on the top of the stack.
+ // Basically the Mfinal = Mviewport * M0 * M1 * M2;
+ // Mi the local matrix at level i of the group tree.
+ currentGroup.mStackedMatrix.set(currentMatrix);
+
+ currentGroup.mStackedMatrix.preConcat(currentGroup.mLocalMatrix);
+
+ float stackedAlpha = currentAlpha * currentGroup.mGroupAlpha;
+ drawPath(currentGroup, stackedAlpha, canvas, w, h);
+ // Draw the group tree in post order.
+ for (int i = 0 ; i < currentGroup.mChildGroupList.size(); i++) {
+ drawGroupTree(currentGroup.mChildGroupList.get(i),
+ currentGroup.mStackedMatrix, stackedAlpha, canvas, w, h);
}
+ }
- for (int i = 0; i < mCurrentPaths.length; i++) {
- if (mCurrentPaths[i] != null) {
- drawPath(mCurrentPaths[i], canvas, w, h);
- }
- }
+ public void draw(Canvas canvas, int w, int h) {
+ // Travese the tree in pre-order to draw.
+ drawGroupTree(mRootGroup, IDENTITY_MATRIX, ((float) mRootAlpha) / 0xFF, canvas, w, h);
}
- private void drawPath(VPath vPath, Canvas canvas, int w, int h) {
+ private void drawPath(VGroup vGroup, float stackedAlpha, Canvas canvas, int w, int h) {
final float scale = Math.min(h / mViewportHeight, w / mViewportWidth);
- vPath.toPath(mPath);
- final Path path = mPath;
+ mFinalPathMatrix.set(vGroup.mStackedMatrix);
+ mFinalPathMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
+ mFinalPathMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
- if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
- float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
- float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
+ ArrayList<VPath> paths = vGroup.getPaths();
+ for (int i = 0; i < paths.size(); i++) {
+ VPath vPath = paths.get(i);
+ vPath.toPath(mPath);
+ final Path path = mPath;
- if (mPathMeasure == null) {
- mPathMeasure = new PathMeasure();
- }
- mPathMeasure.setPath(mPath, false);
-
- float len = mPathMeasure.getLength();
- start = start * len;
- end = end * len;
- path.reset();
- if (start > end) {
- mPathMeasure.getSegment(start, len, path, true);
- mPathMeasure.getSegment(0f, end, path, true);
- } else {
- mPathMeasure.getSegment(start, end, path, true);
- }
- path.rLineTo(0, 0); // fix bug in measure
- }
+ if (vPath.mTrimPathStart != 0.0f || vPath.mTrimPathEnd != 1.0f) {
+ float start = (vPath.mTrimPathStart + vPath.mTrimPathOffset) % 1.0f;
+ float end = (vPath.mTrimPathEnd + vPath.mTrimPathOffset) % 1.0f;
- mRenderPath.reset();
- mMatrix.reset();
+ if (mPathMeasure == null) {
+ mPathMeasure = new PathMeasure();
+ }
+ mPathMeasure.setPath(mPath, false);
+
+ float len = mPathMeasure.getLength();
+ start = start * len;
+ end = end * len;
+ path.reset();
+ if (start > end) {
+ mPathMeasure.getSegment(start, len, path, true);
+ mPathMeasure.getSegment(0f, end, path, true);
+ } else {
+ mPathMeasure.getSegment(start, end, path, true);
+ }
+ path.rLineTo(0, 0); // fix bug in measure
+ }
- mMatrix.postRotate(vPath.mRotate, vPath.mPivotX, vPath.mPivotY);
- mMatrix.postScale(scale, scale, mViewportWidth / 2f, mViewportHeight / 2f);
- mMatrix.postTranslate(w / 2f - mViewportWidth / 2f, h / 2f - mViewportHeight / 2f);
+ mRenderPath.reset();
- mRenderPath.addPath(path, mMatrix);
+ mRenderPath.addPath(path, mFinalPathMatrix);
- if (vPath.mClip) {
- canvas.clipPath(mRenderPath, Region.Op.REPLACE);
- }
+ if (vPath.mClip) {
+ canvas.clipPath(mRenderPath, Region.Op.REPLACE);
+ } else {
+ if (vPath.mFillColor != 0) {
+ if (mFillPaint == null) {
+ mFillPaint = new Paint();
+ mFillPaint.setColorFilter(mColorFilter);
+ mFillPaint.setStyle(Paint.Style.FILL);
+ mFillPaint.setAntiAlias(true);
+ }
+ mFillPaint.setColor(applyAlpha(vPath.mFillColor, stackedAlpha));
+ canvas.drawPath(mRenderPath, mFillPaint);
+ }
- if (vPath.mFillColor != 0) {
- if (mFillPaint == null) {
- mFillPaint = new Paint();
- mFillPaint.setColorFilter(mColorFilter);
- mFillPaint.setStyle(Paint.Style.FILL);
- mFillPaint.setAntiAlias(true);
- }
+ if (vPath.mStrokeColor != 0) {
+ if (mStrokePaint == null) {
+ mStrokePaint = new Paint();
+ mStrokePaint.setColorFilter(mColorFilter);
+ mStrokePaint.setStyle(Paint.Style.STROKE);
+ mStrokePaint.setAntiAlias(true);
+ }
- mFillPaint.setColor(vPath.mFillColor);
- canvas.drawPath(mRenderPath, mFillPaint);
- }
+ final Paint strokePaint = mStrokePaint;
+ if (vPath.mStrokeLineJoin != null) {
+ strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
+ }
- if (vPath.mStrokeColor != 0) {
- if (mStrokePaint == null) {
- mStrokePaint = new Paint();
- mStrokePaint.setColorFilter(mColorFilter);
- mStrokePaint.setStyle(Paint.Style.STROKE);
- mStrokePaint.setAntiAlias(true);
- }
+ if (vPath.mStrokeLineCap != null) {
+ strokePaint.setStrokeCap(vPath.mStrokeLineCap);
+ }
- final Paint strokePaint = mStrokePaint;
- if (vPath.mStrokeLineJoin != null) {
- strokePaint.setStrokeJoin(vPath.mStrokeLineJoin);
- }
+ strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
- if (vPath.mStrokeLineCap != null) {
- strokePaint.setStrokeCap(vPath.mStrokeLineCap);
+ strokePaint.setColor(applyAlpha(vPath.mStrokeColor, stackedAlpha));
+ strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
+ canvas.drawPath(mRenderPath, strokePaint);
+ }
}
-
- strokePaint.setStrokeMiter(vPath.mStrokeMiterlimit * scale);
- strokePaint.setColor(vPath.mStrokeColor);
- strokePaint.setStrokeWidth(vPath.mStrokeWidth * scale);
- canvas.drawPath(mRenderPath, strokePaint);
- }
- }
-
- /**
- * Build the "current" path based on the current group
- * TODO: improve memory use & performance or move to C++
- */
- public void parseFinish() {
- final Collection<VPath> paths = mCurrentGroup.getPaths();
- mCurrentPaths = paths.toArray(new VPath[paths.size()]);
- for (int i = 0; i < mCurrentPaths.length; i++) {
- mCurrentPaths[i] = new VPath(mCurrentPaths[i]);
}
}
@@ -566,43 +720,233 @@ public class VectorDrawable extends Drawable {
}
- private static class VGroup {
- private final HashMap<String, VPath> mVGPathMap = new HashMap<String, VPath>();
- private final ArrayList<VPath> mVGList = new ArrayList<VPath>();
+ static class VGroup {
+ private final ArrayList<VPath> mPathList = new ArrayList<VPath>();
+ private final ArrayList<VGroup> mChildGroupList = new ArrayList<VGroup>();
+
+ private float mRotate = 0;
+ private float mPivotX = 0;
+ private float mPivotY = 0;
+ private float mScaleX = 1;
+ private float mScaleY = 1;
+ private float mTranslateX = 0;
+ private float mTranslateY = 0;
+ private float mGroupAlpha = 1;
+
+ // mLocalMatrix is parsed from the XML.
+ private final Matrix mLocalMatrix = new Matrix();
+ // mStackedMatrix is only used when drawing, it combines all the
+ // parents' local matrices with the current one.
+ private final Matrix mStackedMatrix = new Matrix();
+
+ private int[] mThemeAttrs;
+
+ private String mGroupName = null;
+
+ /* Getter and Setter */
+ public float getRotation() {
+ return mRotate;
+ }
+
+ public void setRotation(float rotation) {
+ if (rotation != mRotate) {
+ mRotate = rotation;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getPivotX() {
+ return mPivotX;
+ }
+
+ public void setPivotX(float pivotX) {
+ if (pivotX != mPivotX) {
+ mPivotX = pivotX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getPivotY() {
+ return mPivotY;
+ }
+
+ public void setPivotY(float pivotY) {
+ if (pivotY != mPivotY) {
+ mPivotY = pivotY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getScaleX() {
+ return mScaleX;
+ }
+
+ public void setScaleX(float scaleX) {
+ if (scaleX != mScaleX) {
+ mScaleX = scaleX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getScaleY() {
+ return mScaleY;
+ }
+
+ public void setScaleY(float scaleY) {
+ if (scaleY != mScaleY) {
+ mScaleY = scaleY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getTranslateX() {
+ return mTranslateX;
+ }
+
+ public void setTranslateX(float translateX) {
+ if (translateX != mTranslateX) {
+ mTranslateX = translateX;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getTranslateY() {
+ return mTranslateY;
+ }
+
+ public void setTranslateY(float translateY) {
+ if (translateY != mTranslateY) {
+ mTranslateY = translateY;
+ updateLocalMatrix();
+ }
+ }
+
+ public float getAlpha() {
+ return mGroupAlpha;
+ }
+
+ public void setAlpha(float groupAlpha) {
+ if (groupAlpha != mGroupAlpha) {
+ mGroupAlpha = groupAlpha;
+ }
+ }
+
+ public String getGroupName() {
+ return mGroupName;
+ }
+
+ public Matrix getLocalMatrix() {
+ return mLocalMatrix;
+ }
public void add(VPath path) {
- String id = path.getID();
- mVGPathMap.put(id, path);
- mVGList.add(path);
+ mPathList.add(path);
}
+ public boolean canApplyTheme() {
+ return mThemeAttrs != null;
+ }
+
+ public void applyTheme(Theme t) {
+ if (mThemeAttrs == null) {
+ return;
+ }
+
+ final TypedArray a = t.resolveAttributes(
+ mThemeAttrs, R.styleable.VectorDrawablePath);
+
+ mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
+ mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
+ mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
+ mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
+ mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
+ mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
+ mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+ mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
+ updateLocalMatrix();
+ if (a.hasValue(R.styleable.VectorDrawableGroup_name)) {
+ mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
+ }
+ a.recycle();
+ }
+
+ public void inflate(Resources res, AttributeSet attrs, Theme theme) {
+ final TypedArray a = obtainAttributes(res, theme, attrs, R.styleable.VectorDrawableGroup);
+ final int[] themeAttrs = a.extractThemeAttrs();
+
+ mThemeAttrs = themeAttrs;
+ // NOTE: The set of attributes loaded here MUST match the
+ // set of attributes loaded in applyTheme.
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_rotation] == 0) {
+ mRotate = a.getFloat(R.styleable.VectorDrawableGroup_rotation, mRotate);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotX] == 0) {
+ mPivotX = a.getFloat(R.styleable.VectorDrawableGroup_pivotX, mPivotX);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_pivotY] == 0) {
+ mPivotY = a.getFloat(R.styleable.VectorDrawableGroup_pivotY, mPivotY);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleX] == 0) {
+ mScaleX = a.getFloat(R.styleable.VectorDrawableGroup_scaleX, mScaleX);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_scaleY] == 0) {
+ mScaleY = a.getFloat(R.styleable.VectorDrawableGroup_scaleY, mScaleY);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateX] == 0) {
+ mTranslateX = a.getFloat(R.styleable.VectorDrawableGroup_translateX, mTranslateX);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_translateY] == 0) {
+ mTranslateY = a.getFloat(R.styleable.VectorDrawableGroup_translateY, mTranslateY);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_name] == 0) {
+ mGroupName = a.getString(R.styleable.VectorDrawableGroup_name);
+ }
+
+ if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawableGroup_alpha] == 0) {
+ mGroupAlpha = a.getFloat(R.styleable.VectorDrawableGroup_alpha, mGroupAlpha);
+ }
+
+ updateLocalMatrix();
+ a.recycle();
+ }
+
+ private void updateLocalMatrix() {
+ // The order we apply is the same as the
+ // RenderNode.cpp::applyViewPropertyTransforms().
+ mLocalMatrix.reset();
+ mLocalMatrix.postTranslate(-mPivotX, -mPivotY);
+ mLocalMatrix.postScale(mScaleX, mScaleY);
+ mLocalMatrix.postRotate(mRotate, 0, 0);
+ mLocalMatrix.postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+ }
+
/**
* Must return in order of adding
* @return ordered list of paths
*/
- public Collection<VPath> getPaths() {
- return mVGList;
+ public ArrayList<VPath> getPaths() {
+ return mPathList;
}
}
private static class VPath {
- private static final int MAX_STATES = 10;
-
private int[] mThemeAttrs;
int mStrokeColor = 0;
float mStrokeWidth = 0;
float mStrokeOpacity = Float.NaN;
-
- int mFillColor = 0;
+ int mFillColor = Color.BLACK;
int mFillRule;
float mFillOpacity = Float.NaN;
-
- float mRotate = 0;
- float mPivotX = 0;
- float mPivotY = 0;
-
float mTrimPathStart = 0;
float mTrimPathEnd = 1;
float mTrimPathOffset = 0;
@@ -612,29 +956,22 @@ public class VectorDrawable extends Drawable {
Paint.Join mStrokeLineJoin = Paint.Join.MITER;
float mStrokeMiterlimit = 4;
- private VNode[] mNode = null;
- private String mId;
- private int[] mCheckState = new int[MAX_STATES];
- private boolean[] mCheckValue = new boolean[MAX_STATES];
- private int mNumberOfStates = 0;
+ private PathParser.PathDataNode[] mNode = null;
+ private String mPathName;
public VPath() {
// Empty constructor.
}
- public VPath(VPath p) {
- copyFrom(p);
- }
-
public void toPath(Path path) {
path.reset();
if (mNode != null) {
- VNode.createPath(mNode, path);
+ PathParser.PathDataNode.nodesToPath(mNode, path);
}
}
- public String getID() {
- return mId;
+ public String getPathName() {
+ return mPathName;
}
private Paint.Cap getStrokeLineCap(int id, Paint.Cap defValue) {
@@ -663,6 +1000,102 @@ public class VectorDrawable extends Drawable {
}
}
+ /* Setters and Getters, mostly used by animator from AnimatedVectorDrawable. */
+ @SuppressWarnings("unused")
+ public PathParser.PathDataNode[] getPathData() {
+ return mNode;
+ }
+
+ @SuppressWarnings("unused")
+ public void setPathData(PathParser.PathDataNode[] node) {
+ if (!PathParser.canMorph(mNode, node)) {
+ // This should not happen in the middle of animation.
+ mNode = PathParser.deepCopyNodes(node);
+ } else {
+ PathParser.updateNodes(mNode, node);
+ }
+ }
+
+ @SuppressWarnings("unused")
+ int getStroke() {
+ return mStrokeColor;
+ }
+
+ @SuppressWarnings("unused")
+ void setStroke(int strokeColor) {
+ mStrokeColor = strokeColor;
+ }
+
+ @SuppressWarnings("unused")
+ float getStrokeWidth() {
+ return mStrokeWidth;
+ }
+
+ @SuppressWarnings("unused")
+ void setStrokeWidth(float strokeWidth) {
+ mStrokeWidth = strokeWidth;
+ }
+
+ @SuppressWarnings("unused")
+ float getStrokeOpacity() {
+ return mStrokeOpacity;
+ }
+
+ @SuppressWarnings("unused")
+ void setStrokeOpacity(float strokeOpacity) {
+ mStrokeOpacity = strokeOpacity;
+ }
+
+ @SuppressWarnings("unused")
+ int getFill() {
+ return mFillColor;
+ }
+
+ @SuppressWarnings("unused")
+ void setFill(int fillColor) {
+ mFillColor = fillColor;
+ }
+
+ @SuppressWarnings("unused")
+ float getFillOpacity() {
+ return mFillOpacity;
+ }
+
+ @SuppressWarnings("unused")
+ void setFillOpacity(float fillOpacity) {
+ mFillOpacity = fillOpacity;
+ }
+
+ @SuppressWarnings("unused")
+ float getTrimPathStart() {
+ return mTrimPathStart;
+ }
+
+ @SuppressWarnings("unused")
+ void setTrimPathStart(float trimPathStart) {
+ mTrimPathStart = trimPathStart;
+ }
+
+ @SuppressWarnings("unused")
+ float getTrimPathEnd() {
+ return mTrimPathEnd;
+ }
+
+ @SuppressWarnings("unused")
+ void setTrimPathEnd(float trimPathEnd) {
+ mTrimPathEnd = trimPathEnd;
+ }
+
+ @SuppressWarnings("unused")
+ float getTrimPathOffset() {
+ return mTrimPathOffset;
+ }
+
+ @SuppressWarnings("unused")
+ void setTrimPathOffset(float trimPathOffset) {
+ mTrimPathOffset = trimPathOffset;
+ }
+
public void inflate(Resources r, AttributeSet attrs, Theme theme) {
final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawablePath);
final int[] themeAttrs = a.extractThemeAttrs();
@@ -675,11 +1108,12 @@ public class VectorDrawable extends Drawable {
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_name] == 0) {
- mId = a.getString(R.styleable.VectorDrawablePath_name);
+ mPathName = a.getString(R.styleable.VectorDrawablePath_name);
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pathData] == 0) {
- mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
+ mNode = PathParser.createNodesFromPathData(a.getString(
+ R.styleable.VectorDrawablePath_pathData));
}
if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_fill] == 0) {
@@ -690,18 +1124,6 @@ public class VectorDrawable extends Drawable {
mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
}
- if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_rotation] == 0) {
- mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotX] == 0) {
- mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
- }
-
- if (themeAttrs == null || themeAttrs[R.styleable.VectorDrawablePath_pivotY] == 0) {
- mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
- }
-
if (themeAttrs == null
|| themeAttrs[R.styleable.VectorDrawablePath_strokeLineCap] == 0) {
mStrokeLineCap = getStrokeLineCap(
@@ -770,20 +1192,17 @@ public class VectorDrawable extends Drawable {
mClip = a.getBoolean(R.styleable.VectorDrawablePath_clipToPath, mClip);
if (a.hasValue(R.styleable.VectorDrawablePath_name)) {
- mId = a.getString(R.styleable.VectorDrawablePath_name);
+ mPathName = a.getString(R.styleable.VectorDrawablePath_name);
}
if (a.hasValue(R.styleable.VectorDrawablePath_pathData)) {
- mNode = parsePath(a.getString(R.styleable.VectorDrawablePath_pathData));
+ mNode = PathParser.createNodesFromPathData(a.getString(
+ R.styleable.VectorDrawablePath_pathData));
}
mFillColor = a.getColor(R.styleable.VectorDrawablePath_fill, mFillColor);
mFillOpacity = a.getFloat(R.styleable.VectorDrawablePath_fillOpacity, mFillOpacity);
- mRotate = a.getFloat(R.styleable.VectorDrawablePath_rotation, mRotate);
- mPivotX = a.getFloat(R.styleable.VectorDrawablePath_pivotX, mPivotX);
- mPivotY = a.getFloat(R.styleable.VectorDrawablePath_pivotY, mPivotY);
-
mStrokeLineCap = getStrokeLineCap(a.getInt(
R.styleable.VectorDrawablePath_strokeLineCap, -1), mStrokeLineCap);
mStrokeLineJoin = getStrokeLineJoin(a.getInt(
@@ -802,528 +1221,17 @@ public class VectorDrawable extends Drawable {
R.styleable.VectorDrawablePath_trimPathStart, mTrimPathStart);
updateColorAlphas();
+ a.recycle();
}
private void updateColorAlphas() {
if (!Float.isNaN(mFillOpacity)) {
- mFillColor &= 0x00FFFFFF;
- mFillColor |= ((int) (0xFF * mFillOpacity)) << 24;
+ mFillColor = applyAlpha(mFillColor, mFillOpacity);
}
if (!Float.isNaN(mStrokeOpacity)) {
- mStrokeColor &= 0x00FFFFFF;
- mStrokeColor |= ((int) (0xFF * mStrokeOpacity)) << 24;
- }
- }
-
- private static int nextStart(String s, int end) {
- char c;
-
- while (end < s.length()) {
- c = s.charAt(end);
- if (((c - 'A') * (c - 'Z') <= 0) || (((c - 'a') * (c - 'z') <= 0))) {
- return end;
- }
- end++;
- }
- return end;
- }
-
- private void addNode(ArrayList<VectorDrawable.VNode> list, char cmd, float[] val) {
- list.add(new VectorDrawable.VNode(cmd, val));
- }
-
- /**
- * parse the floats in the string
- * this is an optimized version of
- * parseFloat(s.split(",|\\s"));
- *
- * @param s the string containing a command and list of floats
- * @return array of floats
- */
- private static float[] getFloats(String s) {
- if (s.charAt(0) == 'z' | s.charAt(0) == 'Z') {
- return new float[0];
- }
- try {
- float[] tmp = new float[s.length()];
- int count = 0;
- int pos = 1, end;
- while ((end = extract(s, pos)) >= 0) {
- if (pos < end) {
- tmp[count++] = Float.parseFloat(s.substring(pos, end));
- }
- pos = end + 1;
- }
- // handle the final float if there is one
- if (pos < s.length()) {
- tmp[count++] = Float.parseFloat(s.substring(pos, s.length()));
- }
- return Arrays.copyOf(tmp, count);
- } catch (NumberFormatException e){
- Log.e(LOGTAG,"error in parsing \""+s+"\"");
- throw e;
- }
- }
-
- /**
- * calculate the position of the next comma or space
- * @param s the string to search
- * @param start the position to start searching
- * @return the position of the next comma or space or -1 if none found
- */
- private static int extract(String s, int start) {
- int space = s.indexOf(' ', start);
- int comma = s.indexOf(',', start);
- if (space == -1) {
- return comma;
- }
- if (comma == -1) {
- return space;
+ mStrokeColor = applyAlpha(mStrokeColor, mStrokeOpacity);
}
- return (comma > space) ? space : comma;
}
-
- private VectorDrawable.VNode[] parsePath(String value) {
- int start = 0;
- int end = 1;
-
- ArrayList<VectorDrawable.VNode> list = new ArrayList<VectorDrawable.VNode>();
- while (end < value.length()) {
- end = nextStart(value, end);
- String s = value.substring(start, end);
- float[] val = getFloats(s);
- addNode(list, s.charAt(0), val);
-
- start = end;
- end++;
- }
- if ((end - start) == 1 && start < value.length()) {
-
- addNode(list, value.charAt(start), new float[0]);
- }
- return list.toArray(new VectorDrawable.VNode[list.size()]);
- }
-
- public void copyFrom(VPath p1) {
- mNode = new VNode[p1.mNode.length];
- for (int i = 0; i < mNode.length; i++) {
- mNode[i] = new VNode(p1.mNode[i]);
- }
- mId = p1.mId;
- mStrokeColor = p1.mStrokeColor;
- mFillColor = p1.mFillColor;
- mStrokeWidth = p1.mStrokeWidth;
- mRotate = p1.mRotate;
- mPivotX = p1.mPivotX;
- mPivotY = p1.mPivotY;
- mTrimPathStart = p1.mTrimPathStart;
- mTrimPathEnd = p1.mTrimPathEnd;
- mTrimPathOffset = p1.mTrimPathOffset;
- mStrokeLineCap = p1.mStrokeLineCap;
- mStrokeLineJoin = p1.mStrokeLineJoin;
- mStrokeMiterlimit = p1.mStrokeMiterlimit;
- mNumberOfStates = p1.mNumberOfStates;
- for (int i = 0; i < mNumberOfStates; i++) {
- mCheckState[i] = p1.mCheckState[i];
- mCheckValue[i] = p1.mCheckValue[i];
- }
-
- mFillRule = p1.mFillRule;
- }
- }
-
- private static class VNode {
- private char mType;
- private float[] mParams;
-
- public VNode(char type, float[] params) {
- mType = type;
- mParams = params;
- }
-
- public VNode(VNode n) {
- mType = n.mType;
- mParams = Arrays.copyOf(n.mParams, n.mParams.length);
- }
-
- public static void createPath(VNode[] node, Path path) {
- float[] current = new float[4];
- char previousCommand = 'm';
- for (int i = 0; i < node.length; i++) {
- addCommand(path, current, previousCommand, node[i].mType, node[i].mParams);
- previousCommand = node[i].mType;
- }
- }
-
- private static void addCommand(Path path, float[] current,
- char previousCmd, char cmd, float[] val) {
-
- int incr = 2;
- float currentX = current[0];
- float currentY = current[1];
- float ctrlPointX = current[2];
- float ctrlPointY = current[3];
- float reflectiveCtrlPointX;
- float reflectiveCtrlPointY;
-
- switch (cmd) {
- case 'z':
- case 'Z':
- path.close();
- return;
- case 'm':
- case 'M':
- case 'l':
- case 'L':
- case 't':
- case 'T':
- incr = 2;
- break;
- case 'h':
- case 'H':
- case 'v':
- case 'V':
- incr = 1;
- break;
- case 'c':
- case 'C':
- incr = 6;
- break;
- case 's':
- case 'S':
- case 'q':
- case 'Q':
- incr = 4;
- break;
- case 'a':
- case 'A':
- incr = 7;
- break;
- }
- for (int k = 0; k < val.length; k += incr) {
- switch (cmd) {
- case 'm': // moveto - Start a new sub-path (relative)
- path.rMoveTo(val[k + 0], val[k + 1]);
- currentX += val[k + 0];
- currentY += val[k + 1];
- break;
- case 'M': // moveto - Start a new sub-path
- path.moveTo(val[k + 0], val[k + 1]);
- currentX = val[k + 0];
- currentY = val[k + 1];
- break;
- case 'l': // lineto - Draw a line from the current point (relative)
- path.rLineTo(val[k + 0], val[k + 1]);
- currentX += val[k + 0];
- currentY += val[k + 1];
- break;
- case 'L': // lineto - Draw a line from the current point
- path.lineTo(val[k + 0], val[k + 1]);
- currentX = val[k + 0];
- currentY = val[k + 1];
- break;
- case 'z': // closepath - Close the current subpath
- case 'Z': // closepath - Close the current subpath
- path.close();
- break;
- case 'h': // horizontal lineto - Draws a horizontal line (relative)
- path.rLineTo(val[k + 0], 0);
- currentX += val[k + 0];
- break;
- case 'H': // horizontal lineto - Draws a horizontal line
- path.lineTo(val[k + 0], currentY);
- currentX = val[k + 0];
- break;
- case 'v': // vertical lineto - Draws a vertical line from the current point (r)
- path.rLineTo(0, val[k + 0]);
- currentY += val[k + 0];
- break;
- case 'V': // vertical lineto - Draws a vertical line from the current point
- path.lineTo(currentX, val[k + 0]);
- currentY = val[k + 0];
- break;
- case 'c': // curveto - Draws a cubic Bézier curve (relative)
- path.rCubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
- val[k + 4], val[k + 5]);
-
- ctrlPointX = currentX + val[k + 2];
- ctrlPointY = currentY + val[k + 3];
- currentX += val[k + 4];
- currentY += val[k + 5];
-
- break;
- case 'C': // curveto - Draws a cubic Bézier curve
- path.cubicTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3],
- val[k + 4], val[k + 5]);
- currentX = val[k + 4];
- currentY = val[k + 5];
- ctrlPointX = val[k + 2];
- ctrlPointY = val[k + 3];
- break;
- case 's': // smooth curveto - Draws a cubic Bézier curve (reflective cp)
- reflectiveCtrlPointX = 0;
- reflectiveCtrlPointY = 0;
- if (previousCmd == 'c' || previousCmd == 's'
- || previousCmd == 'C' || previousCmd == 'S') {
- reflectiveCtrlPointX = currentX - ctrlPointX;
- reflectiveCtrlPointY = currentY - ctrlPointY;
- }
- path.rCubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- val[k + 0], val[k + 1],
- val[k + 2], val[k + 3]);
-
- ctrlPointX = currentX + val[k + 0];
- ctrlPointY = currentY + val[k + 1];
- currentX += val[k + 2];
- currentY += val[k + 3];
- break;
- case 'S': // shorthand/smooth curveto Draws a cubic Bézier curve(reflective cp)
- reflectiveCtrlPointX = currentX;
- reflectiveCtrlPointY = currentY;
- if (previousCmd == 'c' || previousCmd == 's'
- || previousCmd == 'C' || previousCmd == 'S') {
- reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
- reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
- }
- path.cubicTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
- ctrlPointX = val[k + 0];
- ctrlPointY = val[k + 1];
- currentX = val[k + 2];
- currentY = val[k + 3];
- break;
- case 'q': // Draws a quadratic Bézier (relative)
- path.rQuadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
- ctrlPointX = currentX + val[k + 0];
- ctrlPointY = currentY + val[k + 1];
- currentX += val[k + 2];
- currentY += val[k + 3];
- break;
- case 'Q': // Draws a quadratic Bézier
- path.quadTo(val[k + 0], val[k + 1], val[k + 2], val[k + 3]);
- ctrlPointX = val[k + 0];
- ctrlPointY = val[k + 1];
- currentX = val[k + 2];
- currentY = val[k + 3];
- break;
- case 't': // Draws a quadratic Bézier curve(reflective control point)(relative)
- reflectiveCtrlPointX = 0;
- reflectiveCtrlPointY = 0;
- if (previousCmd == 'q' || previousCmd == 't'
- || previousCmd == 'Q' || previousCmd == 'T') {
- reflectiveCtrlPointX = currentX - ctrlPointX;
- reflectiveCtrlPointY = currentY - ctrlPointY;
- }
- path.rQuadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- val[k + 0], val[k + 1]);
- ctrlPointX = currentX + reflectiveCtrlPointX;
- ctrlPointY = currentY + reflectiveCtrlPointY;
- currentX += val[k + 0];
- currentY += val[k + 1];
- break;
- case 'T': // Draws a quadratic Bézier curve (reflective control point)
- reflectiveCtrlPointX = currentX;
- reflectiveCtrlPointY = currentY;
- if (previousCmd == 'q' || previousCmd == 't'
- || previousCmd == 'Q' || previousCmd == 'T') {
- reflectiveCtrlPointX = 2 * currentX - ctrlPointX;
- reflectiveCtrlPointY = 2 * currentY - ctrlPointY;
- }
- path.quadTo(reflectiveCtrlPointX, reflectiveCtrlPointY,
- val[k + 0], val[k + 1]);
- ctrlPointX = reflectiveCtrlPointX;
- ctrlPointY = reflectiveCtrlPointY;
- currentX = val[k + 0];
- currentY = val[k + 1];
- break;
- case 'a': // Draws an elliptical arc
- // (rx ry x-axis-rotation large-arc-flag sweep-flag x y)
- drawArc(path,
- currentX,
- currentY,
- val[k + 5] + currentX,
- val[k + 6] + currentY,
- val[k + 0],
- val[k + 1],
- val[k + 2],
- val[k + 3] != 0,
- val[k + 4] != 0);
- currentX += val[k + 5];
- currentY += val[k + 6];
- ctrlPointX = currentX;
- ctrlPointY = currentY;
- break;
- case 'A': // Draws an elliptical arc
- drawArc(path,
- currentX,
- currentY,
- val[k + 5],
- val[k + 6],
- val[k + 0],
- val[k + 1],
- val[k + 2],
- val[k + 3] != 0,
- val[k + 4] != 0);
- currentX = val[k + 5];
- currentY = val[k + 6];
- ctrlPointX = currentX;
- ctrlPointY = currentY;
- break;
- }
- previousCmd = cmd;
- }
- current[0] = currentX;
- current[1] = currentY;
- current[2] = ctrlPointX;
- current[3] = ctrlPointY;
- }
-
- private static void drawArc(Path p,
- float x0,
- float y0,
- float x1,
- float y1,
- float a,
- float b,
- float theta,
- boolean isMoreThanHalf,
- boolean isPositiveArc) {
-
- /* Convert rotation angle from degrees to radians */
- double thetaD = Math.toRadians(theta);
- /* Pre-compute rotation matrix entries */
- double cosTheta = Math.cos(thetaD);
- double sinTheta = Math.sin(thetaD);
- /* Transform (x0, y0) and (x1, y1) into unit space */
- /* using (inverse) rotation, followed by (inverse) scale */
- double x0p = (x0 * cosTheta + y0 * sinTheta) / a;
- double y0p = (-x0 * sinTheta + y0 * cosTheta) / b;
- double x1p = (x1 * cosTheta + y1 * sinTheta) / a;
- double y1p = (-x1 * sinTheta + y1 * cosTheta) / b;
-
- /* Compute differences and averages */
- double dx = x0p - x1p;
- double dy = y0p - y1p;
- double xm = (x0p + x1p) / 2;
- double ym = (y0p + y1p) / 2;
- /* Solve for intersecting unit circles */
- double dsq = dx * dx + dy * dy;
- if (dsq == 0.0) {
- Log.w(LOGTAG, " Points are coincident");
- return; /* Points are coincident */
- }
- double disc = 1.0 / dsq - 1.0 / 4.0;
- if (disc < 0.0) {
- Log.w(LOGTAG, "Points are too far apart " + dsq);
- float adjust = (float) (Math.sqrt(dsq) / 1.99999);
- drawArc(p, x0, y0, x1, y1, a * adjust,
- b * adjust, theta, isMoreThanHalf, isPositiveArc);
- return; /* Points are too far apart */
- }
- double s = Math.sqrt(disc);
- double sdx = s * dx;
- double sdy = s * dy;
- double cx;
- double cy;
- if (isMoreThanHalf == isPositiveArc) {
- cx = xm - sdy;
- cy = ym + sdx;
- } else {
- cx = xm + sdy;
- cy = ym - sdx;
- }
-
- double eta0 = Math.atan2((y0p - cy), (x0p - cx));
-
- double eta1 = Math.atan2((y1p - cy), (x1p - cx));
-
- double sweep = (eta1 - eta0);
- if (isPositiveArc != (sweep >= 0)) {
- if (sweep > 0) {
- sweep -= 2 * Math.PI;
- } else {
- sweep += 2 * Math.PI;
- }
- }
-
- cx *= a;
- cy *= b;
- double tcx = cx;
- cx = cx * cosTheta - cy * sinTheta;
- cy = tcx * sinTheta + cy * cosTheta;
-
- arcToBezier(p, cx, cy, a, b, x0, y0, thetaD, eta0, sweep);
- }
-
- /**
- * Converts an arc to cubic Bezier segments and records them in p.
- *
- * @param p The target for the cubic Bezier segments
- * @param cx The x coordinate center of the ellipse
- * @param cy The y coordinate center of the ellipse
- * @param a The radius of the ellipse in the horizontal direction
- * @param b The radius of the ellipse in the vertical direction
- * @param e1x E(eta1) x coordinate of the starting point of the arc
- * @param e1y E(eta2) y coordinate of the starting point of the arc
- * @param theta The angle that the ellipse bounding rectangle makes with horizontal plane
- * @param start The start angle of the arc on the ellipse
- * @param sweep The angle (positive or negative) of the sweep of the arc on the ellipse
- */
- private static void arcToBezier(Path p,
- double cx,
- double cy,
- double a,
- double b,
- double e1x,
- double e1y,
- double theta,
- double start,
- double sweep) {
- // Taken from equations at: http://spaceroots.org/documents/ellipse/node8.html
- // and http://www.spaceroots.org/documents/ellipse/node22.html
-
- // Maximum of 45 degrees per cubic Bezier segment
- int numSegments = Math.abs((int) Math.ceil(sweep * 4 / Math.PI));
-
- double eta1 = start;
- double cosTheta = Math.cos(theta);
- double sinTheta = Math.sin(theta);
- double cosEta1 = Math.cos(eta1);
- double sinEta1 = Math.sin(eta1);
- double ep1x = (-a * cosTheta * sinEta1) - (b * sinTheta * cosEta1);
- double ep1y = (-a * sinTheta * sinEta1) + (b * cosTheta * cosEta1);
-
- double anglePerSegment = sweep / numSegments;
- for (int i = 0; i < numSegments; i++) {
- double eta2 = eta1 + anglePerSegment;
- double sinEta2 = Math.sin(eta2);
- double cosEta2 = Math.cos(eta2);
- double e2x = cx + (a * cosTheta * cosEta2) - (b * sinTheta * sinEta2);
- double e2y = cy + (a * sinTheta * cosEta2) + (b * cosTheta * sinEta2);
- double ep2x = -a * cosTheta * sinEta2 - b * sinTheta * cosEta2;
- double ep2y = -a * sinTheta * sinEta2 + b * cosTheta * cosEta2;
- double tanDiff2 = Math.tan((eta2 - eta1) / 2);
- double alpha =
- Math.sin(eta2 - eta1) * (Math.sqrt(4 + (3 * tanDiff2 * tanDiff2)) - 1) / 3;
- double q1x = e1x + alpha * ep1x;
- double q1y = e1y + alpha * ep1y;
- double q2x = e2x - alpha * ep2x;
- double q2y = e2y - alpha * ep2y;
-
- p.cubicTo((float) q1x,
- (float) q1y,
- (float) q2x,
- (float) q2y,
- (float) e2x,
- (float) e2y);
- eta1 = eta2;
- e1x = e2x;
- e1y = e2y;
- ep1x = ep2x;
- ep1y = ep2y;
- }
- }
-
}
}
diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java
index 39795b5..b63edce 100644
--- a/graphics/java/android/graphics/pdf/PdfRenderer.java
+++ b/graphics/java/android/graphics/pdf/PdfRenderer.java
@@ -188,6 +188,7 @@ public final class PdfRenderer implements AutoCloseable {
private void doClose() {
if (mCurrentPage != null) {
mCurrentPage.close();
+ mCurrentPage = null;
}
nativeClose(mNativeDocument);
try {
@@ -374,7 +375,6 @@ public final class PdfRenderer implements AutoCloseable {
nativeClosePage(mNativePage);
mNativePage = 0;
mCloseGuard.close();
- mCurrentPage = null;
}
private void throwIfClosed() {