OSDN Git Service

Make updateLocalMatrix replace the current Matrix.
authorLeon Scroggins III <scroggo@google.com>
Tue, 22 Jul 2014 21:25:22 +0000 (17:25 -0400)
committerLeon Scroggins III <scroggo@google.com>
Thu, 24 Jul 2014 13:30:23 +0000 (09:30 -0400)
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

core/jni/android/graphics/Shader.cpp
graphics/java/android/graphics/BitmapShader.java
graphics/java/android/graphics/ComposeShader.java
graphics/java/android/graphics/LinearGradient.java
graphics/java/android/graphics/Paint.java
graphics/java/android/graphics/RadialGradient.java
graphics/java/android/graphics/Shader.java
graphics/java/android/graphics/SweepGradient.java

index c71f226..fbb243a 100644 (file)
@@ -50,15 +50,20 @@ static jint Color_HSVToColor(JNIEnv* env, jobject, jint alpha, jfloatArray hsvAr
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-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) {
@@ -66,7 +71,6 @@ static jlong Shader_setLocalMatrix(JNIEnv* env, jobject o, jlong shaderHandle,
             matrix = &SkMatrix::I();
         }
         SkShader* newShader = SkShader::CreateLocalMatrixShader(shader, *matrix);
-        shader->unref();
         shader = newShader;
     }
     return reinterpret_cast<jlong>(shader);
@@ -239,8 +243,8 @@ static JNINativeMethod gColorMethods[] = {
 };
 
 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[] = {
index 3ab57c1..5e004a3 100644 (file)
@@ -43,7 +43,7 @@ public class BitmapShader extends Shader {
         mTileX = tileX;
         mTileY = tileY;
         final long b = bitmap.ni();
-        native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt);
+        init(nativeCreate(b, tileX.nativeInt, tileY.nativeInt));
     }
 
     /**
index d7b2071..b2adcf6 100644 (file)
@@ -53,8 +53,8 @@ public class ComposeShader extends Shader {
         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.
@@ -69,8 +69,8 @@ public class ComposeShader extends Shader {
         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));
     }
 
     /**
index 90cb217..7b1145c 100644 (file)
@@ -65,7 +65,7 @@ public class LinearGradient extends Shader {
         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.
@@ -87,7 +87,7 @@ public class LinearGradient extends Shader {
         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));
     }
 
     /**
index 72e39bb..3f73a03 100644 (file)
@@ -919,7 +919,7 @@ public class Paint {
     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;
index 75c951a..9d015f7 100644 (file)
@@ -65,7 +65,7 @@ public class RadialGradient extends 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.
@@ -88,7 +88,7 @@ public class RadialGradient extends Shader {
         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));
     }
 
     /**
index 936fe0c..265a564 100644 (file)
@@ -25,10 +25,19 @@ package android.graphics;
 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;
 
@@ -73,21 +82,22 @@ public class Shader {
      *
      * 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);
         }
     }
 
@@ -113,7 +123,14 @@ public class Shader {
         }
     }
 
-    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);
 }
index 18a748f..008891d 100644 (file)
@@ -62,7 +62,7 @@ public class SweepGradient extends Shader {
         mCy = cy;
         mColors = colors;
         mPositions = positions;
-        native_instance = nativeCreate1(cx, cy, colors, positions);
+        init(nativeCreate1(cx, cy, colors, positions));
     }
 
     /**
@@ -79,7 +79,7 @@ public class SweepGradient extends Shader {
         mCy = cy;
         mColor0 = color0;
         mColor1 = color1;
-        native_instance = nativeCreate2(cx, cy, color0, color1);
+        init(nativeCreate2(cx, cy, color0, color1));
     }
 
     /**