diff options
Diffstat (limited to 'graphics')
17 files changed, 371 insertions, 200 deletions
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index 150f195..48afcbf 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -45,6 +45,8 @@ import javax.microedition.khronos.opengles.GL; * Canvas and Drawables</a> developer guide.</p></div> */ public class Canvas { + /** @hide */ + public static boolean sCompatibilityRestore = false; /** * Should only be assigned in constructors (or setBitmap if software canvas), @@ -557,7 +559,8 @@ public class Canvas { * an error to call restore() more times than save() was called. */ public void restore() { - native_restore(mNativeCanvasWrapper); + boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated(); + native_restore(mNativeCanvasWrapper, throwOnUnderflow); } /** @@ -582,7 +585,8 @@ public class Canvas { * @param saveCount The save level to restore to. */ public void restoreToCount(int saveCount) { - native_restoreToCount(mNativeCanvasWrapper, saveCount); + boolean throwOnUnderflow = !sCompatibilityRestore || !isHardwareAccelerated(); + native_restoreToCount(mNativeCanvasWrapper, saveCount, throwOnUnderflow); } /** @@ -1988,9 +1992,10 @@ public class Canvas { 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_restore(long canvasHandle, boolean tolerateUnderflow); private static native void native_restoreToCount(long canvasHandle, - int saveCount); + int saveCount, + boolean tolerateUnderflow); private static native int native_getSaveCount(long canvasHandle); private static native void native_translate(long canvasHandle, diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 1da198c..cd5f59d 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -2120,9 +2120,9 @@ public class Paint { int contextLen = contextEnd - contextStart; char[] buf = TemporaryBuffer.obtain(contextLen); TextUtils.getChars(text, contextStart, contextEnd, buf, 0); - int result = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt); + int relPos = getTextRunCursor(buf, 0, contextLen, dir, offset - contextStart, cursorOpt); TemporaryBuffer.recycle(buf); - return result; + return (relPos == -1) ? -1 : relPos + contextStart; } /** @@ -2249,6 +2249,26 @@ public class Paint { bounds); } + /** + * Determine whether the typeface set on the paint has a glyph supporting the string. The + * simplest case is when the string contains a single character, in which this method + * determines whether the font has the character. In the case of multiple characters, the + * method returns true if there is a single glyph representing the ligature. For example, if + * the input is a pair of regional indicator symbols, determine whether there is an emoji flag + * for the pair. + * + * Finally, if the string contains a variation selector, the method only returns true if + * the fonts contains a glyph specific to that variation. + * + * Checking is done on the entire fallback chain, not just the immediate font referenced. + * + * @param string the string to test whether there is glyph support + * @return true if the typeface has a glyph for the string + */ + public boolean hasGlyph(String string) { + return native_hasGlyph(mNativePaint, mNativeTypeface, mBidiFlags, string); + } + @Override protected void finalize() throws Throwable { try { @@ -2334,4 +2354,6 @@ public class Paint { String settings); private static native int native_getHyphenEdit(long native_object); private static native void native_setHyphenEdit(long native_object, int hyphen); + private static native boolean native_hasGlyph(long native_object, long native_typeface, + int bidiFlags, String string); } diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java index a56e87e..28c26ff 100644 --- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java @@ -173,7 +173,7 @@ public class AnimatedVectorDrawable extends Drawable implements Animatable { @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() | mAnimatedVectorState.mChangingConfigurations; + return super.getChangingConfigurations() | mAnimatedVectorState.getChangingConfigurations(); } @Override diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index dc10a81..6fe6b56 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -454,7 +454,7 @@ public class BitmapDrawable extends Drawable { @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() | mBitmapState.mChangingConfigurations; + return super.getChangingConfigurations() | mBitmapState.getChangingConfigurations(); } private boolean needMirroring() { @@ -834,7 +834,7 @@ public class BitmapDrawable extends Drawable { // Apply theme to contained color state list. if (state.mTint != null && state.mTint.canApplyTheme()) { - state.mTint.applyTheme(t); + state.mTint = state.mTint.obtainForTheme(t); } // Update local properties. @@ -882,7 +882,7 @@ public class BitmapDrawable extends Drawable { @Override public final ConstantState getConstantState() { - mBitmapState.mChangingConfigurations = getChangingConfigurations(); + mBitmapState.mChangingConfigurations |= getChangingConfigurations(); return mBitmapState; } @@ -950,7 +950,8 @@ public class BitmapDrawable extends Drawable { @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations + | (mTint != null ? mTint.getChangingConfigurations() : 0); } } diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index f75ab36..8e91621 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -276,7 +276,7 @@ public class ColorDrawable extends Drawable { } if (state.mTint != null && state.mTint.canApplyTheme()) { - state.mTint.applyTheme(t); + state.mTint = state.mTint.obtainForTheme(t); } updateLocalState(t.getResources()); @@ -327,7 +327,8 @@ public class ColorDrawable extends Drawable { @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations + | (mTint != null ? mTint.getChangingConfigurations() : 0); } } diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index e8b8c77..22ff3e7 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -572,7 +572,7 @@ public abstract class Drawable { * Specifies a tint blending mode for this drawable. * <p> * Defines how this drawable's tint color should be blended into the drawable - * before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#MULTIPLY}. + * before it is drawn to screen. Default tint mode is {@link PorterDuff.Mode#SRC_IN}. * </p> * <p class="note"><strong>Note:</strong> Setting a color filter via * {@link #setColorFilter(ColorFilter)} or diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index ddcb48b..b03fe3a 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -87,8 +87,7 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override public int getChangingConfigurations() { return super.getChangingConfigurations() - | mDrawableContainerState.mChangingConfigurations - | mDrawableContainerState.mChildrenChangingConfigurations; + | mDrawableContainerState.getChangingConfigurations(); } private boolean needsMirroring() { @@ -865,6 +864,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { for (int i = 0; i < N; i++) { if (drawables[i] != null && drawables[i].canApplyTheme()) { drawables[i].applyTheme(theme); + + // Update cached mask of child changing configurations. + mChildrenChangingConfigurations |= drawables[i].getChangingConfigurations(); } } } diff --git a/graphics/java/android/graphics/drawable/DrawableWrapper.java b/graphics/java/android/graphics/drawable/DrawableWrapper.java index 1d6c60f..0da4275 100644 --- a/graphics/java/android/graphics/drawable/DrawableWrapper.java +++ b/graphics/java/android/graphics/drawable/DrawableWrapper.java @@ -180,8 +180,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb @Override public int getChangingConfigurations() { return super.getChangingConfigurations() - | (mState != null ? mState.mChangingConfigurations : 0) - | mDrawable.getChangingConfigurations(); + | (mState != null ? mState.getChangingConfigurations() : 0); } @Override @@ -433,7 +432,7 @@ public abstract class DrawableWrapper extends Drawable implements Drawable.Callb @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations | mDrawableState.getChangingConfigurations(); } public boolean canConstantState() { diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index eff152c..4c2817c 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -491,19 +491,21 @@ public class GradientDrawable extends Drawable { } /** - * <p>Sets the colors used to draw the gradient. Each color is specified as an - * ARGB integer and the array must contain at least 2 colors.</p> - * <p><strong>Note</strong>: changing colors will affect all instances - * of a drawable loaded from a resource. It is recommended to invoke - * {@link #mutate()} before changing the colors.</p> - * - * @param colors 2 or more ARGB colors + * Sets the colors used to draw the gradient. + * <p> + * Each color is specified as an ARGB integer and the array must contain at + * least 2 colors. + * <p> + * <strong>Note</strong>: changing colors will affect all instances of a + * drawable loaded from a resource. It is recommended to invoke + * {@link #mutate()} before changing the colors. * + * @param colors an array containing 2 or more ARGB colors * @see #mutate() * @see #setColor(int) */ public void setColors(@ColorInt int[] colors) { - mGradientState.setColors(colors); + mGradientState.setGradientColors(colors); mGradientIsDirty = true; invalidateSelf(); } @@ -568,7 +570,7 @@ public class GradientDrawable extends Drawable { mFillPaint.setAlpha(currFillAlpha); mFillPaint.setDither(st.mDither); mFillPaint.setColorFilter(colorFilter); - if (colorFilter != null && st.mColorStateList == null) { + if (colorFilter != null && st.mSolidColors == null) { mFillPaint.setColor(mAlpha << 24); } if (haveStroke) { @@ -715,7 +717,7 @@ public class GradientDrawable extends Drawable { * @see #setColors(int[]) */ public void setColor(@ColorInt int argb) { - mGradientState.setColorStateList(ColorStateList.valueOf(argb)); + mGradientState.setSolidColors(ColorStateList.valueOf(argb)); mFillPaint.setColor(argb); invalidateSelf(); } @@ -734,7 +736,7 @@ public class GradientDrawable extends Drawable { * @see #mutate() */ public void setColor(ColorStateList colorStateList) { - mGradientState.setColorStateList(colorStateList); + mGradientState.setSolidColors(colorStateList); final int color; if (colorStateList == null) { color = Color.TRANSPARENT; @@ -751,9 +753,9 @@ public class GradientDrawable extends Drawable { boolean invalidateSelf = false; final GradientState s = mGradientState; - final ColorStateList stateList = s.mColorStateList; - if (stateList != null) { - final int newColor = stateList.getColorForState(stateSet, 0); + final ColorStateList solidColors = s.mSolidColors; + if (solidColors != null) { + final int newColor = solidColors.getColorForState(stateSet, 0); final int oldColor = mFillPaint.getColor(); if (oldColor != newColor) { mFillPaint.setColor(newColor); @@ -763,12 +765,12 @@ public class GradientDrawable extends Drawable { final Paint strokePaint = mStrokePaint; if (strokePaint != null) { - final ColorStateList strokeStateList = s.mStrokeColorStateList; - if (strokeStateList != null) { - final int newStrokeColor = strokeStateList.getColorForState(stateSet, 0); - final int oldStrokeColor = strokePaint.getColor(); - if (oldStrokeColor != newStrokeColor) { - strokePaint.setColor(newStrokeColor); + final ColorStateList strokeColors = s.mStrokeColors; + if (strokeColors != null) { + final int newColor = strokeColors.getColorForState(stateSet, 0); + final int oldColor = strokePaint.getColor(); + if (oldColor != newColor) { + strokePaint.setColor(newColor); invalidateSelf = true; } } @@ -791,14 +793,14 @@ public class GradientDrawable extends Drawable { public boolean isStateful() { final GradientState s = mGradientState; return super.isStateful() - || (s.mColorStateList != null && s.mColorStateList.isStateful()) - || (s.mStrokeColorStateList != null && s.mStrokeColorStateList.isStateful()) + || (s.mSolidColors != null && s.mSolidColors.isStateful()) + || (s.mStrokeColors != null && s.mStrokeColors.isStateful()) || (s.mTint != null && s.mTint.isStateful()); } @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() | mGradientState.mChangingConfigurations; + return super.getChangingConfigurations() | mGradientState.getChangingConfigurations(); } @Override @@ -899,10 +901,10 @@ public class GradientDrawable extends Drawable { mRect.set(bounds.left + inset, bounds.top + inset, bounds.right - inset, bounds.bottom - inset); - final int[] colors = st.mColors; - if (colors != null) { - RectF r = mRect; - float x0, x1, y0, y1; + final int[] gradientColors = st.mGradientColors; + if (gradientColors != null) { + final RectF r = mRect; + final float x0, x1, y0, y1; if (st.mGradient == LINEAR_GRADIENT) { final float level = st.mUseLevel ? getLevel() / 10000.0f : 1.0f; @@ -942,7 +944,7 @@ public class GradientDrawable extends Drawable { } mFillPaint.setShader(new LinearGradient(x0, y0, x1, y1, - colors, st.mPositions, Shader.TileMode.CLAMP)); + gradientColors, st.mPositions, Shader.TileMode.CLAMP)); } else if (st.mGradient == RADIAL_GRADIENT) { x0 = r.left + (r.right - r.left) * st.mCenterX; y0 = r.top + (r.bottom - r.top) * st.mCenterY; @@ -971,22 +973,22 @@ public class GradientDrawable extends Drawable { } mFillPaint.setShader(new RadialGradient( - x0, y0, radius, colors, null, Shader.TileMode.CLAMP)); + x0, y0, radius, gradientColors, null, Shader.TileMode.CLAMP)); } else if (st.mGradient == SWEEP_GRADIENT) { x0 = r.left + (r.right - r.left) * st.mCenterX; y0 = r.top + (r.bottom - r.top) * st.mCenterY; - int[] tempColors = colors; + int[] tempColors = gradientColors; float[] tempPositions = null; if (st.mUseLevel) { tempColors = st.mTempColors; - final int length = colors.length; + final int length = gradientColors.length; if (tempColors == null || tempColors.length != length + 1) { tempColors = st.mTempColors = new int[length + 1]; } - System.arraycopy(colors, 0, tempColors, 0, length); - tempColors[length] = colors[length - 1]; + System.arraycopy(gradientColors, 0, tempColors, 0, length); + tempColors[length] = gradientColors[length - 1]; tempPositions = st.mTempPositions; final float fraction = 1.0f / (length - 1); @@ -1006,7 +1008,7 @@ public class GradientDrawable extends Drawable { // If we don't have a solid color, the alpha channel must be // maxed out so that alpha modulation works correctly. - if (st.mColorStateList == null) { + if (st.mSolidColors == null) { mFillPaint.setColor(Color.BLACK); } } @@ -1044,15 +1046,15 @@ public class GradientDrawable extends Drawable { } if (state.mTint != null && state.mTint.canApplyTheme()) { - state.mTint.applyTheme(t); + state.mTint = state.mTint.obtainForTheme(t); } - if (state.mColorStateList != null && state.mColorStateList.canApplyTheme()) { - state.mColorStateList.applyTheme(t); + if (state.mSolidColors != null && state.mSolidColors.canApplyTheme()) { + state.mSolidColors = state.mSolidColors.obtainForTheme(t); } - if (state.mStrokeColorStateList != null && state.mStrokeColorStateList.canApplyTheme()) { - state.mStrokeColorStateList.applyTheme(t); + if (state.mStrokeColors != null && state.mStrokeColors.canApplyTheme()) { + state.mStrokeColors = state.mStrokeColors.obtainForTheme(t); } applyThemeChildElements(t); @@ -1288,7 +1290,7 @@ public class GradientDrawable extends Drawable { ColorStateList colorStateList = a.getColorStateList( R.styleable.GradientDrawableStroke_color); if (colorStateList == null) { - colorStateList = st.mStrokeColorStateList; + colorStateList = st.mStrokeColors; } if (dashWidth != 0.0f) { @@ -1346,10 +1348,10 @@ public class GradientDrawable extends Drawable { R.styleable.GradientDrawableGradient_endColor, 0); if (hasCenterColor) { - st.mColors = new int[3]; - st.mColors[0] = startColor; - st.mColors[1] = centerColor; - st.mColors[2] = endColor; + st.mGradientColors = new int[3]; + st.mGradientColors[0] = startColor; + st.mGradientColors[1] = centerColor; + st.mGradientColors[2] = endColor; st.mPositions = new float[3]; st.mPositions[0] = 0.0f; @@ -1357,9 +1359,9 @@ public class GradientDrawable extends Drawable { st.mPositions[1] = st.mCenterX != 0.5f ? st.mCenterX : st.mCenterY; st.mPositions[2] = 1f; } else { - st.mColors = new int[2]; - st.mColors[0] = startColor; - st.mColors[1] = endColor; + st.mGradientColors = new int[2]; + st.mGradientColors[0] = startColor; + st.mGradientColors[1] = endColor; } if (st.mGradient == LINEAR_GRADIENT) { @@ -1552,9 +1554,9 @@ public class GradientDrawable extends Drawable { public int mGradient = LINEAR_GRADIENT; public int mAngle = 0; public Orientation mOrientation; - public ColorStateList mColorStateList; - public ColorStateList mStrokeColorStateList; - public int[] mColors; + public ColorStateList mSolidColors; + public ColorStateList mStrokeColors; + public int[] mGradientColors; public int[] mTempColors; // no need to copy public float[] mTempPositions; // no need to copy public float[] mPositions; @@ -1593,9 +1595,9 @@ public class GradientDrawable extends Drawable { int[] mAttrCorners; int[] mAttrPadding; - public GradientState(Orientation orientation, int[] colors) { + public GradientState(Orientation orientation, int[] gradientColors) { mOrientation = orientation; - setColors(colors); + setGradientColors(gradientColors); } public GradientState(GradientState state) { @@ -1604,14 +1606,14 @@ public class GradientDrawable extends Drawable { mGradient = state.mGradient; mAngle = state.mAngle; mOrientation = state.mOrientation; - mColorStateList = state.mColorStateList; - if (state.mColors != null) { - mColors = state.mColors.clone(); + mSolidColors = state.mSolidColors; + if (state.mGradientColors != null) { + mGradientColors = state.mGradientColors.clone(); } if (state.mPositions != null) { mPositions = state.mPositions.clone(); } - mStrokeColorStateList = state.mStrokeColorStateList; + mStrokeColors = state.mStrokeColors; mStrokeWidth = state.mStrokeWidth; mStrokeDashWidth = state.mStrokeDashWidth; mStrokeDashGap = state.mStrokeDashGap; @@ -1655,8 +1657,8 @@ public class GradientDrawable extends Drawable { || mAttrSolid != null || mAttrStroke != null || mAttrCorners != null || mAttrPadding != null || (mTint != null && mTint.canApplyTheme()) - || (mStrokeColorStateList != null && mStrokeColorStateList.canApplyTheme()) - || (mColorStateList != null && mColorStateList.canApplyTheme()) + || (mStrokeColors != null && mStrokeColors.canApplyTheme()) + || (mSolidColors != null && mSolidColors.canApplyTheme()) || super.canApplyTheme(); } @@ -1672,7 +1674,10 @@ public class GradientDrawable extends Drawable { @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations + | (mStrokeColors != null ? mStrokeColors.getChangingConfigurations() : 0) + | (mSolidColors != null ? mSolidColors.getChangingConfigurations() : 0) + | (mTint != null ? mTint.getChangingConfigurations() : 0); } public void setShape(int shape) { @@ -1689,15 +1694,15 @@ public class GradientDrawable extends Drawable { mCenterY = y; } - public void setColors(int[] colors) { - mColors = colors; - mColorStateList = null; + public void setGradientColors(int[] colors) { + mGradientColors = colors; + mSolidColors = null; computeOpacity(); } - public void setColorStateList(ColorStateList colorStateList) { - mColors = null; - mColorStateList = colorStateList; + public void setSolidColors(ColorStateList colors) { + mGradientColors = null; + mSolidColors = colors; computeOpacity(); } @@ -1705,16 +1710,16 @@ public class GradientDrawable extends Drawable { mOpaqueOverBounds = false; mOpaqueOverShape = false; - if (mColors != null) { - for (int i = 0; i < mColors.length; i++) { - if (!isOpaque(mColors[i])) { + if (mGradientColors != null) { + for (int i = 0; i < mGradientColors.length; i++) { + if (!isOpaque(mGradientColors[i])) { return; } } } // An unfilled shape is not opaque over bounds or shape - if (mColors == null && mColorStateList == null) { + if (mGradientColors == null && mSolidColors == null) { return; } @@ -1726,10 +1731,9 @@ public class GradientDrawable extends Drawable { && mRadiusArray == null; } - public void setStroke( - int width, ColorStateList colorStateList, float dashWidth, float dashGap) { + public void setStroke(int width, ColorStateList colors, float dashWidth, float dashGap) { mStrokeWidth = width; - mStrokeColorStateList = colorStateList; + mStrokeColors = colors; mStrokeDashWidth = dashWidth; mStrokeDashGap = dashGap; computeOpacity(); @@ -1781,11 +1785,11 @@ public class GradientDrawable extends Drawable { private void updateLocalState(Resources res) { final GradientState state = mGradientState; - if (state.mColorStateList != null) { + if (state.mSolidColors != null) { final int[] currentState = getState(); - final int stateColor = state.mColorStateList.getColorForState(currentState, 0); + final int stateColor = state.mSolidColors.getColorForState(currentState, 0); mFillPaint.setColor(stateColor); - } else if (state.mColors == null) { + } else if (state.mGradientColors == null) { // If we don't have a solid color and we don't have a gradient, // the app is stroking the shape, set the color to the default // value of state.mSolidColor @@ -1802,9 +1806,9 @@ public class GradientDrawable extends Drawable { mStrokePaint.setStyle(Paint.Style.STROKE); mStrokePaint.setStrokeWidth(state.mStrokeWidth); - if (state.mStrokeColorStateList != null) { + if (state.mStrokeColors != null) { final int[] currentState = getState(); - final int strokeStateColor = state.mStrokeColorStateList.getColorForState( + final int strokeStateColor = state.mStrokeColors.getColorForState( currentState, 0); mStrokePaint.setColor(strokeStateColor); } diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 97f7105..e1ebdbb 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -242,26 +242,12 @@ public class InsetDrawable extends DrawableWrapper { } @Override - public ConstantState getConstantState() { - if (mState.canConstantState()) { - mState.mChangingConfigurations = getChangingConfigurations(); - return mState; - } - return null; - } - - @Override DrawableWrapperState mutateConstantState() { mState = new InsetState(mState); return mState; } static final class InsetState extends DrawableWrapper.DrawableWrapperState { - int[] mThemeAttrs; - int mChangingConfigurations; - - ConstantState mDrawableState; - int mInsetLeft = 0; int mInsetTop = 0; int mInsetRight = 0; diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 30fbe16..8468d9e 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -163,7 +163,6 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { inflateLayers(r, parser, attrs, theme); ensurePadding(); - onStateChange(getState()); } /** @@ -211,7 +210,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { updateLayerFromTypedArray(layer, a); a.recycle(); - if (layer.mDrawable == null) { + // If the layer doesn't have a drawable or unresolved theme + // attribute for a drawable, attempt to parse one from the child + // element. + if (layer.mDrawable == null && (layer.mThemeAttrs == null || + layer.mThemeAttrs[R.styleable.LayerDrawableItem_drawable] == 0)) { while ((type = parser.next()) == XmlPullParser.TEXT) { } if (type != XmlPullParser.START_TAG) { @@ -294,13 +297,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } final Drawable d = layer.mDrawable; - if (d.canApplyTheme()) { + if (d != null && d.canApplyTheme()) { d.applyTheme(t); + + // Update cached mask of child changing configurations. + state.mChildrenChangingConfigurations |= d.getChangingConfigurations(); } } ensurePadding(); - onStateChange(getState()); } @Override @@ -876,15 +881,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.draw(canvas); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.draw(canvas); + } } } @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() - | mLayerState.mChangingConfigurations - | mLayerState.mChildrenChangingConfigurations; + return super.getChangingConfigurations() | mLayerState.getChangingConfigurations(); } @Override @@ -943,13 +949,15 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ @Override public void getOutline(@NonNull Outline outline) { - final LayerState state = mLayerState; - final ChildDrawable[] children = state.mChildren; - final int N = state.mNum; + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - children[i].mDrawable.getOutline(outline); - if (!outline.isEmpty()) { - return; + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.getOutline(outline); + if (!outline.isEmpty()) { + return; + } } } } @@ -959,7 +967,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setHotspot(x, y); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setHotspot(x, y); + } } } @@ -968,7 +979,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setHotspotBounds(left, top, right, bottom); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setHotspotBounds(left, top, right, bottom); + } } if (mHotspotBounds == null) { @@ -993,7 +1007,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setVisible(visible, restart); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setVisible(visible, restart); + } } return changed; @@ -1004,17 +1021,18 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setDither(dither); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setDither(dither); + } } } @Override public boolean getDither() { - final ChildDrawable[] array = mLayerState.mChildren; - if (mLayerState.mNum > 0) { - // All layers should have the same dither set on them - just return - // the first one - return array[0].mDrawable.getDither(); + final Drawable dr = getFirstNonNullDrawable(); + if (dr != null) { + return dr.getDither(); } else { return super.getDither(); } @@ -1025,17 +1043,18 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setAlpha(alpha); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setAlpha(alpha); + } } } @Override public int getAlpha() { - final ChildDrawable[] array = mLayerState.mChildren; - if (mLayerState.mNum > 0) { - // All layers should have the same alpha set on them - just return - // the first one - return array[0].mDrawable.getAlpha(); + final Drawable dr = getFirstNonNullDrawable(); + if (dr != null) { + return dr.getAlpha(); } else { return super.getAlpha(); } @@ -1046,7 +1065,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setColorFilter(colorFilter); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setColorFilter(colorFilter); + } } } @@ -1055,7 +1077,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setTintList(tint); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setTintList(tint); + } } } @@ -1064,8 +1089,23 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setTintMode(tintMode); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setTintMode(tintMode); + } + } + } + + private Drawable getFirstNonNullDrawable() { + final ChildDrawable[] array = mLayerState.mChildren; + final int N = mLayerState.mNum; + for (int i = 0; i < N; i++) { + final Drawable dr = array[i].mDrawable; + if (dr != null) { + return dr; + } } + return null; } /** @@ -1098,7 +1138,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.setAutoMirrored(mirrored); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.setAutoMirrored(mirrored); + } } } @@ -1119,9 +1162,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - final ChildDrawable r = array[i]; - if (r.mDrawable.isStateful() && r.mDrawable.setState(state)) { - refreshChildPadding(i, r); + final Drawable dr = array[i].mDrawable; + if (dr != null && dr.isStateful() && dr.setState(state)) { + refreshChildPadding(i, array[i]); changed = true; } } @@ -1140,9 +1183,9 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - final ChildDrawable r = array[i]; - if (r.mDrawable.setLevel(level)) { - refreshChildPadding(i, r); + final Drawable dr = array[i].mDrawable; + if (dr != null && dr.setLevel(level)) { + refreshChildPadding(i, array[i]); changed = true; } } @@ -1173,6 +1216,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; final Drawable d = r.mDrawable; + if (d == null) { + continue; + } + final Rect container = mTmpContainer; container.set(d.getBounds()); @@ -1254,6 +1301,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; + if (r.mDrawable == null) { + continue; + } + final int minWidth = r.mWidth < 0 ? r.mDrawable.getIntrinsicWidth() : r.mWidth; final int w = minWidth + r.mInsetL + r.mInsetR + padL + padR; if (w > width) { @@ -1280,6 +1331,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { final ChildDrawable r = array[i]; + if (r.mDrawable == null) { + continue; + } + final int minHeight = r.mHeight < 0 ? r.mDrawable.getIntrinsicHeight() : r.mHeight; final int h = minHeight + r.mInsetT + r.mInsetB + padT + padB; if (h > height) { @@ -1301,15 +1356,17 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { * @return true if the child's padding has changed */ private boolean refreshChildPadding(int i, ChildDrawable r) { - final Rect rect = mTmpRect; - r.mDrawable.getPadding(rect); - if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || - rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) { - mPaddingL[i] = rect.left; - mPaddingT[i] = rect.top; - mPaddingR[i] = rect.right; - mPaddingB[i] = rect.bottom; - return true; + if (r.mDrawable != null) { + final Rect rect = mTmpRect; + r.mDrawable.getPadding(rect); + if (rect.left != mPaddingL[i] || rect.top != mPaddingT[i] || + rect.right != mPaddingR[i] || rect.bottom != mPaddingB[i]) { + mPaddingL[i] = rect.left; + mPaddingT[i] = rect.top; + mPaddingR[i] = rect.right; + mPaddingB[i] = rect.bottom; + return true; + } } return false; } @@ -1345,7 +1402,10 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.mutate(); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.mutate(); + } } mMutated = true; } @@ -1357,10 +1417,14 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ public void clearMutated() { super.clearMutated(); + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - array[i].mDrawable.clearMutated(); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + dr.clearMutated(); + } } mMutated = false; } @@ -1368,11 +1432,16 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public boolean onLayoutDirectionChange(int layoutDirection) { boolean changed = false; + final ChildDrawable[] array = mLayerState.mChildren; final int N = mLayerState.mNum; for (int i = 0; i < N; i++) { - changed |= array[i].mDrawable.setLayoutDirection(layoutDirection); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + changed |= dr.setLayoutDirection(layoutDirection); + } } + updateLayerBounds(getBounds()); return changed; } @@ -1393,15 +1462,24 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { } ChildDrawable(ChildDrawable orig, LayerDrawable owner, Resources res) { - if (res != null) { - mDrawable = orig.mDrawable.getConstantState().newDrawable(res); + final Drawable dr = orig.mDrawable; + final Drawable clone; + if (dr != null) { + final ConstantState cs = dr.getConstantState(); + if (res != null) { + clone = cs.newDrawable(res); + } else { + clone = cs.newDrawable(); + } + clone.setCallback(owner); + clone.setLayoutDirection(dr.getLayoutDirection()); + clone.setBounds(dr.getBounds()); + clone.setLevel(dr.getLevel()); } else { - mDrawable = orig.mDrawable.getConstantState().newDrawable(); + clone = null; } - mDrawable.setCallback(owner); - mDrawable.setLayoutDirection(orig.mDrawable.getLayoutDirection()); - mDrawable.setBounds(orig.mDrawable.getBounds()); - mDrawable.setLevel(orig.mDrawable.getLevel()); + + mDrawable = clone; mThemeAttrs = orig.mThemeAttrs; mInsetL = orig.mInsetL; mInsetT = orig.mInsetT; @@ -1414,6 +1492,11 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { mGravity = orig.mGravity; mId = orig.mId; } + + public boolean canApplyTheme() { + return mThemeAttrs != null + || (mDrawable != null && mDrawable.canApplyTheme()); + } } static class LayerState extends ConstantState { @@ -1473,7 +1556,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mNum; for (int i = 0; i < N; i++) { final ChildDrawable layer = array[i]; - if (layer.mThemeAttrs != null || layer.mDrawable.canApplyTheme()) { + if (layer.canApplyTheme()) { return true; } } @@ -1493,7 +1576,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations + | mChildrenChangingConfigurations; } public final int getOpacity() { @@ -1503,9 +1587,29 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mChildren; final int N = mNum; - int op = N > 0 ? array[0].mDrawable.getOpacity() : PixelFormat.TRANSPARENT; - for (int i = 1; i < N; i++) { - op = Drawable.resolveOpacity(op, array[i].mDrawable.getOpacity()); + + // Seek to the first non-null drawable. + int firstIndex = -1; + for (int i = 0; i < N; i++) { + if (array[i].mDrawable != null) { + firstIndex = i; + break; + } + } + + int op; + if (firstIndex >= 0) { + op = array[firstIndex].mDrawable.getOpacity(); + } else { + op = PixelFormat.TRANSPARENT; + } + + // Merge all remaining non-null drawables. + for (int i = firstIndex + 1; i < N; i++) { + final Drawable dr = array[i].mDrawable; + if (dr != null) { + op = Drawable.resolveOpacity(op, dr.getOpacity()); + } } mOpacity = op; @@ -1522,7 +1626,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mNum; boolean isStateful = false; for (int i = 0; i < N; i++) { - if (array[i].mDrawable.isStateful()) { + final Drawable dr = array[i].mDrawable; + if (dr != null && dr.isStateful()) { isStateful = true; break; } @@ -1537,7 +1642,8 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final ChildDrawable[] array = mChildren; final int N = mNum; for (int i = 0; i < N; i++) { - if (array[i].mDrawable.getConstantState() == null) { + final Drawable dr = array[i].mDrawable; + if (dr != null && dr.getConstantState() == null) { return false; } } @@ -1557,9 +1663,12 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { final int N = mNum; int pixelCount = 0; for (int i = 0; i < N; i++) { - final ConstantState state = array[i].mDrawable.getConstantState(); - if (state != null) { - pixelCount += state.addAtlasableBitmaps(atlasList); + final Drawable dr = array[i].mDrawable; + if (dr != null) { + final ConstantState state = dr.getConstantState(); + if (state != null) { + pixelCount += state.addAtlasableBitmaps(atlasList); + } } } return pixelCount; diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 487162e..9bf33cf 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -266,7 +266,7 @@ public class NinePatchDrawable extends Drawable { @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() | mNinePatchState.mChangingConfigurations; + return super.getChangingConfigurations() | mNinePatchState.getChangingConfigurations(); } @Override @@ -498,7 +498,7 @@ public class NinePatchDrawable extends Drawable { } if (state.mTint != null && state.mTint.canApplyTheme()) { - state.mTint.applyTheme(t); + state.mTint = state.mTint.obtainForTheme(t); } updateLocalState(t.getResources()); @@ -680,7 +680,8 @@ public class NinePatchDrawable extends Drawable { @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations + | (mTint != null ? mTint.getChangingConfigurations() : 0); } } diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java index 23f93fd..6731a17 100644 --- a/graphics/java/android/graphics/drawable/RippleDrawable.java +++ b/graphics/java/android/graphics/drawable/RippleDrawable.java @@ -479,7 +479,7 @@ public class RippleDrawable extends LayerDrawable { } if (state.mColor != null && state.mColor.canApplyTheme()) { - state.mColor.applyTheme(t); + state.mColor = state.mColor.obtainForTheme(t); } updateLocalState(); @@ -955,6 +955,12 @@ public class RippleDrawable extends LayerDrawable { public Drawable newDrawable(Resources res) { return new RippleDrawable(this, res); } + + @Override + public int getChangingConfigurations() { + return super.getChangingConfigurations() + | (mColor != null ? mColor.getChangingConfigurations() : 0); + } } private RippleDrawable(RippleState state, Resources res) { diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index 15e16f1..036a078 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -89,9 +89,6 @@ public class RotateDrawable extends DrawableWrapper { final RotateState state = mState; - // Account for any configuration changes. - state.mChangingConfigurations |= a.getChangingConfigurations(); - // Extract the theme attributes, if any. state.mThemeAttrs = a.extractThemeAttrs(); diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index fc88c15..334b3bd 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -53,9 +53,9 @@ import java.io.IOException; * For more information about how to use ShapeDrawable, read the <a * href="{@docRoot}guide/topics/graphics/2d-graphics.html#shape-drawable"> * Canvas and Drawables</a> document. For more information about defining a - * ShapeDrawable in XML, read the <a href="{@docRoot} - * guide/topics/resources/drawable-resource.html#Shape">Drawable Resources</a> - * document. + * ShapeDrawable in XML, read the + * <a href="{@docRoot}guide/topics/resources/drawable-resource.html#Shape"> + * Drawable Resources</a> document. * </p> * </div> * @@ -261,8 +261,7 @@ public class ShapeDrawable extends Drawable { @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() - | mShapeState.mChangingConfigurations; + return super.getChangingConfigurations() | mShapeState.getChangingConfigurations(); } /** @@ -427,7 +426,7 @@ public class ShapeDrawable extends Drawable { // Apply theme to contained color state list. if (state.mTint != null && state.mTint.canApplyTheme()) { - state.mTint.applyTheme(t); + state.mTint = state.mTint.obtainForTheme(t); } // Update local properties. @@ -578,7 +577,8 @@ public class ShapeDrawable extends Drawable { @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations + | (mTint != null ? mTint.getChangingConfigurations() : 0); } } diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java index b827682..f4df14e 100644 --- a/graphics/java/android/graphics/drawable/VectorDrawable.java +++ b/graphics/java/android/graphics/drawable/VectorDrawable.java @@ -36,6 +36,7 @@ import android.util.ArrayMap; import android.util.AttributeSet; import android.util.LayoutDirection; import android.util.Log; +import android.util.MathUtils; import android.util.PathParser; import android.util.Xml; @@ -389,7 +390,7 @@ public class VectorDrawable extends Drawable { // Apply theme to contained color state list. if (state.mTint != null && state.mTint.canApplyTheme()) { - state.mTint.applyTheme(t); + state.mTint = state.mTint.obtainForTheme(t); } final VPathRenderer path = state.mVPathRenderer; @@ -625,7 +626,7 @@ public class VectorDrawable extends Drawable { @Override public int getChangingConfigurations() { - return super.getChangingConfigurations() | mVectorState.mChangingConfigurations; + return super.getChangingConfigurations() | mVectorState.getChangingConfigurations(); } void setAllowCaching(boolean allowCaching) { @@ -784,7 +785,8 @@ public class VectorDrawable extends Drawable { @Override public int getChangingConfigurations() { - return mChangingConfigurations; + return mChangingConfigurations + | (mTint != null ? mTint.getChangingConfigurations() : 0); } } @@ -955,10 +957,16 @@ public class VectorDrawable extends Drawable { final float scaleX = w / mViewportWidth; final float scaleY = h / mViewportHeight; final float minScale = Math.min(scaleX, scaleY); + final Matrix groupStackedMatrix = vGroup.mStackedMatrix; - mFinalPathMatrix.set(vGroup.mStackedMatrix); + mFinalPathMatrix.set(groupStackedMatrix); mFinalPathMatrix.postScale(scaleX, scaleY); + final float matrixScale = getMatrixScale(groupStackedMatrix); + if (matrixScale == 0) { + // When either x or y is scaled to 0, we don't need to draw anything. + return; + } vPath.toPath(mPath); final Path path = mPath; @@ -966,7 +974,7 @@ public class VectorDrawable extends Drawable { if (vPath.isClipPath()) { mRenderPath.addPath(path, mFinalPathMatrix); - canvas.clipPath(mRenderPath, Region.Op.REPLACE); + canvas.clipPath(mRenderPath); } else { VFullPath fullPath = (VFullPath) vPath; if (fullPath.mTrimPathStart != 0.0f || fullPath.mTrimPathEnd != 1.0f) { @@ -1024,11 +1032,41 @@ public class VectorDrawable extends Drawable { strokePaint.setStrokeMiter(fullPath.mStrokeMiterlimit); strokePaint.setColor(applyAlpha(fullPath.mStrokeColor, fullPath.mStrokeAlpha)); strokePaint.setColorFilter(filter); - strokePaint.setStrokeWidth(fullPath.mStrokeWidth * minScale); + final float finalStrokeScale = minScale * matrixScale; + strokePaint.setStrokeWidth(fullPath.mStrokeWidth * finalStrokeScale); canvas.drawPath(mRenderPath, strokePaint); } } } + + private float getMatrixScale(Matrix groupStackedMatrix) { + // Given unit vectors A = (0, 1) and B = (1, 0). + // After matrix mapping, we got A' and B'. Let theta = the angel b/t A' and B'. + // Therefore, the final scale we want is min(|A'| * sin(theta), |B'| * sin(theta)), + // which is (|A'| * |B'| * sin(theta)) / max (|A'|, |B'|); + // If max (|A'|, |B'|) = 0, that means either x or y has a scale of 0. + // + // For non-skew case, which is most of the cases, matrix scale is computing exactly the + // scale on x and y axis, and take the minimal of these two. + // For skew case, an unit square will mapped to a parallelogram. And this function will + // return the minimal height of the 2 bases. + float[] unitVectors = new float[] {0, 1, 1, 0}; + groupStackedMatrix.mapVectors(unitVectors); + float scaleX = MathUtils.mag(unitVectors[0], unitVectors[1]); + float scaleY = MathUtils.mag(unitVectors[2], unitVectors[3]); + float crossProduct = MathUtils.cross(unitVectors[0], unitVectors[1], + unitVectors[2], unitVectors[3]); + float maxScale = MathUtils.max(scaleX, scaleY); + + float matrixScale = 0; + if (maxScale > 0) { + matrixScale = MathUtils.abs(crossProduct) / maxScale; + } + if (DBG_VECTOR_DRAWABLE) { + Log.d(LOGTAG, "Scale x " + scaleX + " y " + scaleY + " final " + matrixScale); + } + return matrixScale; + } } private static class VGroup { diff --git a/graphics/java/android/graphics/pdf/PdfRenderer.java b/graphics/java/android/graphics/pdf/PdfRenderer.java index b32dcc6..feb8052 100644 --- a/graphics/java/android/graphics/pdf/PdfRenderer.java +++ b/graphics/java/android/graphics/pdf/PdfRenderer.java @@ -380,7 +380,7 @@ public final class PdfRenderer implements AutoCloseable { final long transformPtr = (transform != null) ? transform.native_instance : 0; - nativeRenderPage(mNativeDocument, mNativePage, destination.getSkBitmap(), contentLeft, + nativeRenderPage(mNativeDocument, mNativePage, destination, contentLeft, contentTop, contentRight, contentBottom, transformPtr, renderMode); } @@ -425,7 +425,7 @@ public final class PdfRenderer implements AutoCloseable { private static native void nativeClose(long documentPtr); private static native int nativeGetPageCount(long documentPtr); private static native boolean nativeScaleForPrinting(long documentPtr); - private static native void nativeRenderPage(long documentPtr, long pagePtr, long destPtr, + private static native void nativeRenderPage(long documentPtr, long pagePtr, Bitmap dest, int destLeft, int destTop, int destRight, int destBottom, long matrixPtr, int renderMode); private static native long nativeOpenPageAndGetSize(long documentPtr, int pageIndex, Point outSize); |
