Fixes a bug introduced in I3c3316377874e89fccc85afb864bc038b0ef3890.
CreateLocalMatrixShader combines the existing matrix with the new
matrix, which is not what we want. Keep track of the original
SkShader at all times, and always create the local matrix shader
with the original. Store the SkShader with a local matrix as
Shader.native_with_local_matrix.
Make Shader.native_instance private. Instead of allowing direct
access, add an init() method which sets it, and getNativeInstance(),
which returns either native_instance or native_with_local_matrix,
as appropriate.
Make Shader subclasses call init(), instead of setting native_instance
directly.
Pass native_with_local_matrix pointer to nativeSetLocalMatrix and
nativeDestructor, which unrefs it (if not null).
Since nativeSetLocalMatrix no longer replaces the original, do not
unref it.
Add a comment to Shader.updateLocalMatrix that it does not affect
ComposeShaders created with this Shader. (This should have been a
part of I3c3316377874e89fccc85afb864bc038b0ef3890.)
BUG:
16293121
Change-Id: Ieb31c7e1fe99081f6b81493178f4a18d3c5df643
///////////////////////////////////////////////////////////////////////////////////////////////
-static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle)
+static void Shader_destructor(JNIEnv* env, jobject o, jlong shaderHandle, jlong shaderWithLMHandle)
{
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
SkSafeUnref(shader);
+ SkShader* shaderWithLM = reinterpret_cast<SkShader*>(shaderWithLMHandle);
+ SkSafeUnref(shaderWithLM);
}
static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle,
- jlong matrixHandle)
+ jlong oldLocalMatrixShaderHandle, jlong matrixHandle)
{
+ // The old shader with local matrix is no longer needed, so unref it.
+ SkSafeUnref(reinterpret_cast<SkShader*>(oldLocalMatrixShaderHandle));
+
SkShader* shader = reinterpret_cast<SkShader*>(shaderHandle);
const SkMatrix* matrix = reinterpret_cast<SkMatrix*>(matrixHandle);
if (shader) {
matrix = &SkMatrix::I();
}
SkShader* newShader = SkShader::CreateLocalMatrixShader(shader, *matrix);
- shader->unref();
shader = newShader;
}
return reinterpret_cast<jlong>(shader);
};
static JNINativeMethod gShaderMethods[] = {
- { "nativeDestructor", "(J)V", (void*)Shader_destructor },
- { "nativeSetLocalMatrix", "(JJ)J", (void*)Shader_setLocalMatrix }
+ { "nativeDestructor", "(JJ)V", (void*)Shader_destructor },
+ { "nativeSetLocalMatrix", "(JJJ)J", (void*)Shader_setLocalMatrix }
};
static JNINativeMethod gBitmapShaderMethods[] = {
mTileX = tileX;
mTileY = tileY;
final long b = bitmap.ni();
- native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
+ init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
}
/**
mShaderA = shaderA;
mShaderB = shaderB;
mXferMode = mode;
- native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance,
- (mode != null) ? mode.native_instance : 0);
+ init(nativeCreate1(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
+ (mode != null) ? mode.native_instance : 0));
}
/** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode.
mShaderA = shaderA;
mShaderB = shaderB;
mPorterDuffMode = mode;
- native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance,
- mode.nativeInt);
+ init(nativeCreate2(shaderA.getNativeInstance(), shaderB.getNativeInstance(),
+ mode.nativeInt));
}
/**
mColors = colors;
mPositions = positions;
mTileMode = tile;
- native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt);
+ init(nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt));
}
/** Create a shader that draws a linear gradient along a line.
mColor0 = color0;
mColor1 = color1;
mTileMode = tile;
- native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt);
+ init(nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt));
}
/**
public Shader setShader(Shader shader) {
long shaderNative = 0;
if (shader != null)
- shaderNative = shader.native_instance;
+ shaderNative = shader.getNativeInstance();
native_setShader(mNativePaint, shaderNative);
mShader = shader;
return shader;
mColors = colors;
mPositions = positions;
mTileMode = tile;
- native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
+ init(nativeCreate1(x, y, radius, colors, positions, tile.nativeInt));
}
/** Create a shader that draws a radial gradient given the center and radius.
mColor0 = color0;
mColor1 = color1;
mTileMode = tile;
- native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
+ init(nativeCreate2(x, y, radius, color0, color1, tile.nativeInt));
}
/**
public class Shader {
/**
* This is set by subclasses, but don't make it public.
- *
- * @hide
*/
- public long native_instance;
+ private long native_instance;
+
+ private long native_with_local_matrix;
+
+ /**
+ * Initialization step that should be called by subclasses in their
+ * constructors. Calling again may result in memory leaks.
+ * @hide
+ */
+ protected void init(long ni) {
+ native_instance = ni;
+ }
private Matrix mLocalMatrix;
*
* Starting with {@link android.os.Build.VERSION_CODES#L}, this does not
* modify any Paints which use this Shader. In order to modify the Paint,
- * you need to call {@link Paint#setShader} again.
+ * you need to call {@link Paint#setShader} again. Further, any {@link ComposeShader}s
+ * created with this Shader will be unaffected.
*
* @param localM The shader's new local matrix, or null to specify identity
*/
public void setLocalMatrix(Matrix localM) {
mLocalMatrix = localM;
- native_instance = nativeSetLocalMatrix(native_instance,
- localM == null ? 0 : localM.native_instance);
+ native_with_local_matrix = nativeSetLocalMatrix(native_instance,
+ native_with_local_matrix, localM == null ? 0 : localM.native_instance);
}
protected void finalize() throws Throwable {
try {
super.finalize();
} finally {
- nativeDestructor(native_instance);
+ nativeDestructor(native_instance, native_with_local_matrix);
}
}
}
}
- private static native void nativeDestructor(long native_shader);
+ /* package */ long getNativeInstance() {
+ if (native_with_local_matrix != 0) {
+ return native_with_local_matrix;
+ }
+ return native_instance;
+ }
+
+ private static native void nativeDestructor(long native_shader, long native_with_local_matrix);
private static native long nativeSetLocalMatrix(long native_shader,
- long matrix_instance);
+ long native_with_local_matrix, long matrix_instance);
}
mCy = cy;
mColors = colors;
mPositions = positions;
- native_instance = nativeCreate1(cx, cy, colors, positions);
+ init(nativeCreate1(cx, cy, colors, positions));
}
/**
mCy = cy;
mColor0 = color0;
mColor1 = color1;
- native_instance = nativeCreate2(cx, cy, color0, color1);
+ init(nativeCreate2(cx, cy, color0, color1));
}
/**