Expose color filter mutate methods

Bug: 36025103
Test: cts-tradefed run singleCommand cts-dev --module CtsGraphicsTestCases

Now, similar to Shaders, we defer native creation until Paint is being
used, and ensure that we have an up to date filter when drawing.

Also implements ColorMatrix#equals to behave like Matrix#equals.

Change-Id: I5f74addd97f5662800802e6f660fead58d518725
This commit is contained in:
Chris Craik
2017-03-08 10:55:30 -08:00
parent 849008cc56
commit 6097eca721
13 changed files with 188 additions and 105 deletions

View File

@@ -12757,7 +12757,7 @@ package android.graphics {
}
public class ColorFilter {
ctor public ColorFilter();
ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -12781,6 +12781,9 @@ package android.graphics {
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
method public void getColorMatrix(android.graphics.ColorMatrix);
method public void setColorMatrix(android.graphics.ColorMatrix);
method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13004,6 +13007,10 @@ package android.graphics {
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
method public int getColorAdd();
method public int getColorMultiply();
method public void setColorAdd(int);
method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -13520,6 +13527,10 @@ package android.graphics {
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
method public int getColor();
method public android.graphics.PorterDuff.Mode getMode();
method public void setColor(int);
method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -45423,7 +45434,7 @@ package android.view {
method public void setActivated(boolean);
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHint(java.lang.String[]);
method public void setAutofillHint(java.lang.String...);
method public void setAutofillMode(int);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);

View File

@@ -13495,7 +13495,7 @@ package android.graphics {
}
public class ColorFilter {
ctor public ColorFilter();
ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -13519,6 +13519,9 @@ package android.graphics {
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
method public void getColorMatrix(android.graphics.ColorMatrix);
method public void setColorMatrix(android.graphics.ColorMatrix);
method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13742,6 +13745,10 @@ package android.graphics {
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
method public int getColorAdd();
method public int getColorMultiply();
method public void setColorAdd(int);
method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -14258,6 +14265,10 @@ package android.graphics {
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
method public int getColor();
method public android.graphics.PorterDuff.Mode getMode();
method public void setColor(int);
method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -48889,7 +48900,7 @@ package android.view {
method public void setActivated(boolean);
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHint(java.lang.String[]);
method public void setAutofillHint(java.lang.String...);
method public void setAutofillMode(int);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);

View File

@@ -12795,7 +12795,7 @@ package android.graphics {
}
public class ColorFilter {
ctor public ColorFilter();
ctor public deprecated ColorFilter();
}
public class ColorMatrix {
@@ -12819,6 +12819,9 @@ package android.graphics {
public class ColorMatrixColorFilter extends android.graphics.ColorFilter {
ctor public ColorMatrixColorFilter(android.graphics.ColorMatrix);
ctor public ColorMatrixColorFilter(float[]);
method public void getColorMatrix(android.graphics.ColorMatrix);
method public void setColorMatrix(android.graphics.ColorMatrix);
method public void setColorMatrixArray(float[]);
}
public abstract class ColorSpace {
@@ -13042,6 +13045,10 @@ package android.graphics {
public class LightingColorFilter extends android.graphics.ColorFilter {
ctor public LightingColorFilter(int, int);
method public int getColorAdd();
method public int getColorMultiply();
method public void setColorAdd(int);
method public void setColorMultiply(int);
}
public class LinearGradient extends android.graphics.Shader {
@@ -13558,6 +13565,10 @@ package android.graphics {
public class PorterDuffColorFilter extends android.graphics.ColorFilter {
ctor public PorterDuffColorFilter(int, android.graphics.PorterDuff.Mode);
method public int getColor();
method public android.graphics.PorterDuff.Mode getMode();
method public void setColor(int);
method public void setMode(android.graphics.PorterDuff.Mode);
}
public class PorterDuffXfermode extends android.graphics.Xfermode {
@@ -45786,7 +45797,7 @@ package android.view {
method public void setActivated(boolean);
method public void setAlpha(float);
method public void setAnimation(android.view.animation.Animation);
method public void setAutofillHint(java.lang.String[]);
method public void setAutofillHint(java.lang.String...);
method public void setAutofillMode(int);
method public void setBackground(android.graphics.drawable.Drawable);
method public void setBackgroundColor(int);

View File

@@ -30,7 +30,7 @@ using namespace uirenderer;
class SkColorFilterGlue {
public:
static void finalizer(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
static void SafeUnref(JNIEnv* env, jobject clazz, jlong skFilterHandle) {
SkColorFilter* filter = reinterpret_cast<SkColorFilter *>(skFilterHandle);
SkSafeUnref(filter);
}
@@ -57,19 +57,19 @@ public:
};
static const JNINativeMethod colorfilter_methods[] = {
{"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
{"nSafeUnref", "(J)V", (void*) SkColorFilterGlue::SafeUnref}
};
static const JNINativeMethod porterduff_methods[] = {
{ "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
{ "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter },
};
static const JNINativeMethod lighting_methods[] = {
{ "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
{ "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter },
};
static const JNINativeMethod colormatrix_methods[] = {
{ "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
{ "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter },
};
int register_android_graphics_ColorFilter(JNIEnv* env) {

View File

@@ -28,21 +28,51 @@ package android.graphics;
*/
public class ColorFilter {
/**
* Holds the pointer to the native SkColorFilter instance.
*
* @hide
* @deprecated Use subclass constructors directly instead.
*/
public long native_instance;
@Deprecated
public ColorFilter() {}
/**
* Holds the pointer to the native SkColorFilter instance.
*/
private long mNativeInstance;
long createNativeInstance() {
return 0;
}
void discardNativeInstance() {
if (mNativeInstance != 0) {
nSafeUnref(mNativeInstance);
mNativeInstance = 0;
}
}
@Override
protected void finalize() throws Throwable {
try {
super.finalize();
if (mNativeInstance != 0) {
nSafeUnref(mNativeInstance);
}
mNativeInstance = -1;
} finally {
destroyFilter(native_instance);
native_instance = 0;
super.finalize();
}
}
static native void destroyFilter(long native_instance);
/** @hide */
public long getNativeInstance() {
if (mNativeInstance == -1) {
throw new IllegalStateException("attempting to use a finalized ColorFilter");
}
if (mNativeInstance == 0) {
mNativeInstance = createNativeInstance();
}
return mNativeInstance;
}
static native void nSafeUnref(long native_instance);
}

View File

@@ -268,4 +268,21 @@ public class ColorMatrix {
m[5] = 1; m[6] = -0.34414f; m[7] = -0.71414f;
m[10] = 1; m[11] = 1.772f; m[12] = 0;
}
@Override
public boolean equals(Object obj) {
// if (obj == this) return true; -- NaN value would mean matrix != itself
if (!(obj instanceof ColorMatrix)) {
return false;
}
// we don't use Arrays.equals(), since that considers NaN == NaN
final float[] other = ((ColorMatrix) obj).mArray;
for (int i = 0; i < 20; i++) {
if (other[i] != mArray[i]) {
return false;
}
}
return true;
}
}

View File

@@ -16,6 +16,9 @@
package android.graphics;
import android.annotation.NonNull;
import android.annotation.Nullable;
/**
* A color filter that transforms colors through a 4x5 color matrix. This filter
* can be used to change the saturation of pixels, convert from YUV to RGB, etc.
@@ -32,9 +35,8 @@ public class ColorMatrixColorFilter extends ColorFilter {
* the filter, so changes made to the matrix after the filter
* is constructed will not be reflected in the filter.
*/
public ColorMatrixColorFilter(ColorMatrix matrix) {
public ColorMatrixColorFilter(@NonNull ColorMatrix matrix) {
mMatrix.set(matrix);
update();
}
/**
@@ -44,84 +46,76 @@ public class ColorMatrixColorFilter extends ColorFilter {
* matrix. The first 20 entries of the array are copied into
* the filter. See ColorMatrix.
*/
public ColorMatrixColorFilter(float[] array) {
public ColorMatrixColorFilter(@NonNull float[] array) {
if (array.length < 20) {
throw new ArrayIndexOutOfBoundsException();
}
mMatrix.set(array);
update();
}
/**
* Returns the {@link ColorMatrix} used by this filter. The returned
* value is never null. Modifying the returned matrix does not have
* any effect until you call {@link #setColorMatrix(ColorMatrix)}.
* Copies the ColorMatrix from the filter into the passed ColorMatrix.
*
* @see #setColorMatrix(ColorMatrix)
*
* @hide
* @param colorMatrix Set to the current value of the filter's ColorMatrix.
*/
public ColorMatrix getColorMatrix() {
return mMatrix;
public void getColorMatrix(ColorMatrix colorMatrix) {
colorMatrix.set(mMatrix);
}
/**
* Specifies the color matrix used by this filter. If the specified
* color matrix is null, this filter's color matrix will be reset to
* the identity matrix.
* Copies the provided color matrix to be used by this filter.
*
* If the specified color matrix is null, this filter's color matrix will be reset to the
* identity matrix.
*
* @param matrix A {@link ColorMatrix} or null
*
* @see #getColorMatrix()
* @see android.graphics.ColorMatrix#reset()
* @see #setColorMatrix(float[])
*
* @hide
* @see #getColorMatrix(ColorMatrix)
* @see #setColorMatrixArray(float[])
* @see ColorMatrix#reset()
*/
public void setColorMatrix(ColorMatrix matrix) {
public void setColorMatrix(@Nullable ColorMatrix matrix) {
discardNativeInstance();
if (matrix == null) {
mMatrix.reset();
} else if (matrix != mMatrix) {
} else {
mMatrix.set(matrix);
}
update();
}
/**
* Specifies the color matrix used by this filter. If the specified
* color matrix is null, this filter's color matrix will be reset to
* the identity matrix.
* Copies the provided color matrix to be used by this filter.
*
* If the specified color matrix is null, this filter's color matrix will be reset to the
* identity matrix.
*
* @param array Array of floats used to transform colors, treated as a 4x5
* matrix. The first 20 entries of the array are copied into
* the filter. See {@link ColorMatrix}.
*
* @see #getColorMatrix()
* @see android.graphics.ColorMatrix#reset()
* @see #getColorMatrix(ColorMatrix)
* @see #setColorMatrix(ColorMatrix)
* @see ColorMatrix#reset()
*
* @throws ArrayIndexOutOfBoundsException if the specified array's
* length is < 20
*
* @hide
*/
public void setColorMatrix(float[] array) {
public void setColorMatrixArray(@Nullable float[] array) {
// called '...Array' so that passing null isn't ambiguous
discardNativeInstance();
if (array == null) {
mMatrix.reset();
} else {
if (array.length < 20) {
throw new ArrayIndexOutOfBoundsException();
}
mMatrix.set(array);
}
update();
}
private void update() {
final float[] colorMatrix = mMatrix.getArray();
destroyFilter(native_instance);
native_instance = nativeColorMatrixFilter(colorMatrix);
@Override
long createNativeInstance() {
return nativeColorMatrixFilter(mMatrix.getArray());
}
private static native long nativeColorMatrixFilter(float[] array);

View File

@@ -21,6 +21,8 @@
package android.graphics;
import android.annotation.ColorInt;
/**
* A color filter that can be used to simulate simple lighting effects.
* A <code>LightingColorFilter</code> is defined by two parameters, one
@@ -37,7 +39,9 @@ package android.graphics;
* The result is pinned to the <code>[0..255]</code> range for each channel.
*/
public class LightingColorFilter extends ColorFilter {
@ColorInt
private int mMul;
@ColorInt
private int mAdd;
/**
@@ -45,10 +49,9 @@ public class LightingColorFilter extends ColorFilter {
* and then adds a second color. The alpha components of the mul and add
* arguments are ignored.
*/
public LightingColorFilter(int mul, int add) {
public LightingColorFilter(@ColorInt int mul, @ColorInt int add) {
mMul = mul;
mAdd = add;
update();
}
/**
@@ -56,9 +59,8 @@ public class LightingColorFilter extends ColorFilter {
* color filter is applied.
*
* @see #setColorMultiply(int)
*
* @hide
*/
@ColorInt
public int getColorMultiply() {
return mMul;
}
@@ -69,12 +71,12 @@ public class LightingColorFilter extends ColorFilter {
* The alpha channel of this color is ignored.
*
* @see #getColorMultiply()
*
* @hide
*/
public void setColorMultiply(int mul) {
mMul = mul;
update();
public void setColorMultiply(@ColorInt int mul) {
if (mMul != mul) {
mMul = mul;
discardNativeInstance();
}
}
/**
@@ -82,9 +84,8 @@ public class LightingColorFilter extends ColorFilter {
* when the color filter is applied.
*
* @see #setColorAdd(int)
*
* @hide
*/
@ColorInt
public int getColorAdd() {
return mAdd;
}
@@ -95,17 +96,17 @@ public class LightingColorFilter extends ColorFilter {
* The alpha channel of this color is ignored.
*
* @see #getColorAdd()
*
* @hide
*/
public void setColorAdd(int add) {
mAdd = add;
update();
public void setColorAdd(@ColorInt int add) {
if (mAdd != add) {
mAdd = add;
discardNativeInstance();
}
}
private void update() {
destroyFilter(native_instance);
native_instance = native_CreateLightingFilter(mMul, mAdd);
@Override
long createNativeInstance() {
return native_CreateLightingFilter(mMul, mAdd);
}
private static native long native_CreateLightingFilter(int mul, int add);

View File

@@ -42,7 +42,8 @@ import libcore.util.NativeAllocationRegistry;
public class Paint {
private long mNativePaint;
private long mNativeShader = 0;
private long mNativeShader;
private long mNativeColorFilter;
// The approximate size of a native paint object.
private static final long NATIVE_PAINT_SIZE = 98;
@@ -584,6 +585,11 @@ public class Paint {
mNativeShader = newNativeShader;
nSetShader(mNativePaint, mNativeShader);
}
long newNativeColorFilter = mColorFilter == null ? 0 : mColorFilter.getNativeInstance();
if (newNativeColorFilter != mNativeColorFilter) {
mNativeColorFilter = newNativeColorFilter;
nSetColorFilter(mNativePaint, mNativeColorFilter);
}
return mNativePaint;
}
@@ -1044,10 +1050,13 @@ public class Paint {
* @return filter
*/
public ColorFilter setColorFilter(ColorFilter filter) {
long filterNative = 0;
if (filter != null)
filterNative = filter.native_instance;
nSetColorFilter(mNativePaint, filterNative);
// If mColorFilter changes, cached value of native shader aren't valid, since
// old shader's pointer may be reused by another shader allocation later
if (mColorFilter != filter) {
mNativeColorFilter = -1;
}
// Defer setting the filter natively until getNativeInstance() is called
mColorFilter = filter;
return filter;
}

View File

@@ -24,6 +24,7 @@ import android.annotation.NonNull;
* color and a specific {@link PorterDuff Porter-Duff composite mode}.
*/
public class PorterDuffColorFilter extends ColorFilter {
@ColorInt
private int mColor;
private PorterDuff.Mode mMode;
@@ -40,7 +41,6 @@ public class PorterDuffColorFilter extends ColorFilter {
public PorterDuffColorFilter(@ColorInt int color, @NonNull PorterDuff.Mode mode) {
mColor = color;
mMode = mode;
update();
}
/**
@@ -49,9 +49,8 @@ public class PorterDuffColorFilter extends ColorFilter {
*
* @see Color
* @see #setColor(int)
*
* @hide
*/
@ColorInt
public int getColor() {
return mColor;
}
@@ -65,12 +64,12 @@ public class PorterDuffColorFilter extends ColorFilter {
* @see Color
* @see #getColor()
* @see #getMode()
*
* @hide
*/
public void setColor(int color) {
mColor = color;
update();
public void setColor(@ColorInt int color) {
if (mColor != color) {
mColor = color;
discardNativeInstance();
}
}
/**
@@ -79,8 +78,6 @@ public class PorterDuffColorFilter extends ColorFilter {
*
* @see PorterDuff
* @see #setMode(android.graphics.PorterDuff.Mode)
*
* @hide
*/
public PorterDuff.Mode getMode() {
return mMode;
@@ -93,17 +90,18 @@ public class PorterDuffColorFilter extends ColorFilter {
* @see PorterDuff
* @see #getMode()
* @see #getColor()
*
* @hide
*/
public void setMode(@NonNull PorterDuff.Mode mode) {
if (mode == null) {
throw new IllegalArgumentException("mode must be non-null");
}
mMode = mode;
update();
discardNativeInstance();
}
private void update() {
destroyFilter(native_instance);
native_instance = native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
@Override
long createNativeInstance() {
return native_CreatePorterDuffFilter(mColor, mMode.nativeInt);
}
@Override
@@ -115,10 +113,7 @@ public class PorterDuffColorFilter extends ColorFilter {
return false;
}
final PorterDuffColorFilter other = (PorterDuffColorFilter) object;
if (mColor != other.mColor || mMode != other.mMode) {
return false;
}
return true;
return (mColor == other.mColor && mMode.nativeInt == other.mMode.nativeInt);
}
@Override

View File

@@ -106,8 +106,10 @@ public class Shader {
}
void discardNativeInstance() {
nativeSafeUnref(mNativeInstance);
mNativeInstance = 0;
if (mNativeInstance != 0) {
nativeSafeUnref(mNativeInstance);
mNativeInstance = 0;
}
}
/**
@@ -120,7 +122,9 @@ public class Shader {
@Override
protected void finalize() throws Throwable {
try {
nativeSafeUnref(mNativeInstance);
if (mNativeInstance != 0) {
nativeSafeUnref(mNativeInstance);
}
mNativeInstance = -1;
} finally {
super.finalize();

View File

@@ -333,7 +333,7 @@ public class VectorDrawable extends Drawable {
// Color filters always override tint filters.
final ColorFilter colorFilter = (mColorFilter == null ? mTintFilter : mColorFilter);
final long colorFilterNativeInstance = colorFilter == null ? 0 :
colorFilter.native_instance;
colorFilter.getNativeInstance();
boolean canReuseCache = mVectorState.canReuseCache();
int pixelCount = nDraw(mVectorState.getNativeRenderer(), canvas.getNativeCanvasWrapper(),
colorFilterNativeInstance, mTmpBounds, needMirroring(),

View File

@@ -138,7 +138,7 @@ public class ColorFiltersMutateActivity extends Activity {
mSaturation = saturation;
final ColorMatrixColorFilter filter =
(ColorMatrixColorFilter) mColorMatrixPaint.getColorFilter();
final ColorMatrix m = filter.getColorMatrix();
final ColorMatrix m = new ColorMatrix();
m.setSaturation(saturation);
filter.setColorMatrix(m);
invalidate();