Merge "Add 3D transforms support to all gradients."
diff --git a/libs/hwui/ProgramCache.cpp b/libs/hwui/ProgramCache.cpp
index d1a1b45..439e6fb 100644
--- a/libs/hwui/ProgramCache.cpp
+++ b/libs/hwui/ProgramCache.cpp
@@ -37,12 +37,8 @@
         // Linear
         "uniform mat4 screenSpace;\n",
         // Circular
-        "uniform vec2 gradientStart;\n"
-        "uniform mat4 gradientMatrix;\n"
         "uniform mat4 screenSpace;\n",
         // Sweep
-        "uniform vec2 gradientStart;\n"
-        "uniform mat4 gradientMatrix;\n"
         "uniform mat4 screenSpace;\n"
 };
 const char* gVS_Header_Uniforms_HasBitmap =
@@ -68,11 +64,9 @@
         // Linear
         "    index = (screenSpace * position).x;\n",
         // Circular
-        "    vec4 location = screenSpace * position;\n"
-        "    circular = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n",
+        "    circular = (screenSpace * position).xy;\n",
         // Sweep
-        "    vec4 location = screenSpace * position;\n"
-        "    sweep = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n"
+        "    sweep = (screenSpace * position).xy;\n"
 };
 const char* gVS_Main_OutBitmapTexCoords =
         "    vec4 bitmapCoords = textureTransform * position;\n"
@@ -98,7 +92,6 @@
         // Linear
         "uniform sampler2D gradientSampler;\n",
         // Circular
-        "uniform float gradientRadius;\n"
         "uniform sampler2D gradientSampler;\n",
         // Sweep
         "uniform sampler2D gradientSampler;\n"
@@ -130,7 +123,7 @@
         // Linear
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
         // Circular
-        "    float index = length(circular) * gradientRadius;\n"
+        "    float index = length(circular);\n"
         "    vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
         // Sweep
         "    float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
diff --git a/libs/hwui/SkiaShader.cpp b/libs/hwui/SkiaShader.cpp
index 83de2b2..fa85d20 100644
--- a/libs/hwui/SkiaShader.cpp
+++ b/libs/hwui/SkiaShader.cpp
@@ -49,7 +49,8 @@
 
 SkiaShader::SkiaShader(Type type, SkShader* key, SkShader::TileMode tileX,
         SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
-        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mMatrix(matrix), mBlend(blend) {
+        mType(type), mKey(key), mTileX(tileX), mTileY(tileY), mBlend(blend) {
+    setMatrix(matrix);
 }
 
 SkiaShader::~SkiaShader() {
@@ -69,6 +70,11 @@
     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapT);
 }
 
+void SkiaShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
+    screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
+    screenSpace.multiply(modelView);
+}
+
 ///////////////////////////////////////////////////////////////////////////////
 // Bitmap shader
 ///////////////////////////////////////////////////////////////////////////////
@@ -76,6 +82,7 @@
 SkiaBitmapShader::SkiaBitmapShader(SkBitmap* bitmap, SkShader* key, SkShader::TileMode tileX,
         SkShader::TileMode tileY, SkMatrix* matrix, bool blend):
         SkiaShader(kBitmap, key, tileX, tileY, matrix, blend), mBitmap(bitmap), mTexture(NULL) {
+    updateLocalMatrix(matrix);
 }
 
 void SkiaBitmapShader::describe(ProgramDescription& description, const Extensions& extensions) {
@@ -116,14 +123,7 @@
     const float height = texture->height;
 
     mat4 textureTransform;
-    if (mMatrix) {
-        SkMatrix inverse;
-        mMatrix->invert(&inverse);
-        textureTransform.load(inverse);
-        textureTransform.multiply(modelView);
-    } else {
-        textureTransform.load(modelView);
-    }
+    computeScreenSpaceMatrix(textureTransform, modelView);
 
     // Uniforms
     bindTexture(texture->id, mWrapS, mWrapT, textureSlot);
@@ -136,15 +136,7 @@
 void SkiaBitmapShader::updateTransforms(Program* program, const mat4& modelView,
         const Snapshot& snapshot) {
     mat4 textureTransform;
-    if (mMatrix) {
-        SkMatrix inverse;
-        mMatrix->invert(&inverse);
-        textureTransform.load(inverse);
-        textureTransform.multiply(modelView);
-    } else {
-        textureTransform.load(modelView);
-    }
-
+    computeScreenSpaceMatrix(textureTransform, modelView);
     glUniformMatrix4fv(program->getUniform("textureTransform"), 1,
             GL_FALSE, &textureTransform.data[0]);
 }
@@ -192,23 +184,6 @@
     description.gradientType = ProgramDescription::kGradientLinear;
 }
 
-void SkiaLinearGradientShader::computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView) {
-    screenSpace.loadMultiply(mUnitMatrix, mShaderMatrix);
-    screenSpace.multiply(modelView);
-}
-
-void SkiaLinearGradientShader::updateLocalMatrix(const SkMatrix* matrix) {
-    if (matrix) {
-        mat4 localMatrix(*matrix);
-        mShaderMatrix.loadInverse(localMatrix);
-    }
-}
-
-void SkiaLinearGradientShader::setMatrix(SkMatrix* matrix) {
-    SkiaShader::setMatrix(matrix);
-    updateLocalMatrix(matrix);
-}
-
 void SkiaLinearGradientShader::setupProgram(Program* program, const mat4& modelView,
         const Snapshot& snapshot, GLuint* textureUnit) {
     GLuint textureSlot = (*textureUnit)++;
@@ -239,12 +214,23 @@
 // Circular gradient shader
 ///////////////////////////////////////////////////////////////////////////////
 
+static void toCircularUnitMatrix(const float x, const float y, const float radius,
+        SkMatrix* matrix) {
+    const float inv = 1.0f / radius;
+    matrix->setTranslate(-x, -y);
+    matrix->postScale(inv, inv);
+}
+
 SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
         uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
         SkMatrix* matrix, bool blend):
         SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
-                tileMode, matrix, blend),
-        mRadius(radius) {
+                tileMode, matrix, blend) {
+    SkMatrix unitMatrix;
+    toCircularUnitMatrix(x, y, radius, &unitMatrix);
+    mUnitMatrix.load(unitMatrix);
+
+    updateLocalMatrix(matrix);
 }
 
 void SkiaCircularGradientShader::describe(ProgramDescription& description,
@@ -253,28 +239,31 @@
     description.gradientType = ProgramDescription::kGradientCircular;
 }
 
-void SkiaCircularGradientShader::setupProgram(Program* program, const mat4& modelView,
-        const Snapshot& snapshot, GLuint* textureUnit) {
-    SkiaSweepGradientShader::setupProgram(program, modelView, snapshot, textureUnit);
-    glUniform1f(program->getUniform("gradientRadius"), 1.0f / mRadius);
-}
-
 ///////////////////////////////////////////////////////////////////////////////
 // Sweep gradient shader
 ///////////////////////////////////////////////////////////////////////////////
 
+static void toSweepUnitMatrix(const float x, const float y, SkMatrix* matrix) {
+    matrix->setTranslate(-x, -y);
+}
+
 SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* colors,
         float* positions, int count, SkShader* key, SkMatrix* matrix, bool blend):
         SkiaShader(kSweepGradient, key, SkShader::kClamp_TileMode,
                 SkShader::kClamp_TileMode, matrix, blend),
-        mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
+        mColors(colors), mPositions(positions), mCount(count) {
+    SkMatrix unitMatrix;
+    toSweepUnitMatrix(x, y, &unitMatrix);
+    mUnitMatrix.load(unitMatrix);
+
+    updateLocalMatrix(matrix);
 }
 
 SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
         float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
         SkMatrix* matrix, bool blend):
         SkiaShader(type, key, tileMode, tileMode, matrix, blend),
-        mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
+        mColors(colors), mPositions(positions), mCount(count) {
 }
 
 SkiaSweepGradientShader::~SkiaSweepGradientShader() {
@@ -298,35 +287,19 @@
         texture = mGradientCache->addLinearGradient(mKey, mColors, mPositions, mCount);
     }
 
-    float left = mX;
-    float top = mY;
-
-    mat4 shaderMatrix;
-    if (mMatrix) {
-        shaderMatrix.load(*mMatrix);
-        shaderMatrix.mapPoint(left, top);
-    }
-
-    mat4 copy(shaderMatrix);
-    shaderMatrix.loadInverse(copy);
-
-    snapshot.transform->mapPoint(left, top);
-
-    mat4 screenSpace(*snapshot.transform);
-    screenSpace.multiply(modelView);
+    mat4 screenSpace;
+    computeScreenSpaceMatrix(screenSpace, modelView);
 
     // Uniforms
     bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
     glUniform1i(program->getUniform("gradientSampler"), textureSlot);
-    glUniformMatrix4fv(program->getUniform("gradientMatrix"), 1, GL_FALSE, &shaderMatrix.data[0]);
-    glUniform2f(program->getUniform("gradientStart"), left, top);
     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
 }
 
 void SkiaSweepGradientShader::updateTransforms(Program* program, const mat4& modelView,
         const Snapshot& snapshot) {
-    mat4 screenSpace(*snapshot.transform);
-    screenSpace.multiply(modelView);
+    mat4 screenSpace;
+    computeScreenSpaceMatrix(screenSpace, modelView);
     glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
 }
 
diff --git a/libs/hwui/SkiaShader.h b/libs/hwui/SkiaShader.h
index 2c1eb35..2565e65 100644
--- a/libs/hwui/SkiaShader.h
+++ b/libs/hwui/SkiaShader.h
@@ -77,10 +77,21 @@
             const Snapshot& snapshot) {
     }
 
-    virtual void setMatrix(SkMatrix* matrix) {
-        mMatrix = matrix;
+    void setMatrix(SkMatrix* matrix) {
+        updateLocalMatrix(matrix);
     }
 
+    void updateLocalMatrix(const SkMatrix* matrix) {
+        if (matrix) {
+            mat4 localMatrix(*matrix);
+            mShaderMatrix.loadInverse(localMatrix);
+        } else {
+            mShaderMatrix.loadIdentity();
+        }
+    }
+
+    void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
+
 protected:
     inline void bindTexture(GLuint texture, GLenum wrapS, GLenum wrapT, GLuint textureUnit);
 
@@ -88,11 +99,13 @@
     SkShader* mKey;
     SkShader::TileMode mTileX;
     SkShader::TileMode mTileY;
-    SkMatrix* mMatrix;
     bool mBlend;
 
     TextureCache* mTextureCache;
     GradientCache* mGradientCache;
+
+    mat4 mUnitMatrix;
+    mat4 mShaderMatrix;
 }; // struct SkiaShader
 
 
@@ -139,15 +152,7 @@
             GLuint* textureUnit);
     void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
 
-    void setMatrix(SkMatrix* matrix);
-
 private:
-    void updateLocalMatrix(const SkMatrix* matrix);
-    void computeScreenSpaceMatrix(mat4& screenSpace, const mat4& modelView);
-
-    mat4 mUnitMatrix;
-    mat4 mShaderMatrix;
-
     float* mBounds;
     uint32_t* mColors;
     float* mPositions;
@@ -163,7 +168,7 @@
     ~SkiaSweepGradientShader();
 
     virtual void describe(ProgramDescription& description, const Extensions& extensions);
-    virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
+    void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
             GLuint* textureUnit);
     void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
 
@@ -171,7 +176,6 @@
     SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions,
             int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
 
-    float mX, mY;
     uint32_t* mColors;
     float* mPositions;
     int mCount;
@@ -185,11 +189,6 @@
             int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
 
     void describe(ProgramDescription& description, const Extensions& extensions);
-    void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
-            GLuint* textureUnit);
-
-private:
-    float mRadius;
 }; // struct SkiaCircularGradientShader
 
 /**
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
index 769bfdd..8fa626b 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/GradientsActivity.java
@@ -18,11 +18,16 @@
 
 import android.app.Activity;
 import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapShader;
 import android.graphics.Canvas;
 import android.graphics.LinearGradient;
+import android.graphics.RadialGradient;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Shader;
+import android.graphics.SweepGradient;
 import android.os.Bundle;
 import android.view.Gravity;
 import android.view.View;
@@ -36,8 +41,13 @@
         super.onCreate(savedInstanceState);
 
         final FrameLayout layout = new FrameLayout(this);
+
         final ShadersView shadersView = new ShadersView(this);
         final GradientView gradientView = new GradientView(this);
+        final RadialGradientView radialGradientView = new RadialGradientView(this);
+        final SweepGradientView sweepGradientView = new SweepGradientView(this);
+        final BitmapView bitmapView = new BitmapView(this);
+
         final SeekBar rotateView = new SeekBar(this);
         rotateView.setMax(360);
         rotateView.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@@ -51,13 +61,29 @@
 
             @Override
             public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-                gradientView.setRotationY((float)progress);
+                gradientView.setRotationY((float) progress);
+                radialGradientView.setRotationX((float) progress);
+                sweepGradientView.setRotationY((float) progress);
+                bitmapView.setRotationX((float) progress);
             }
         });
         
         layout.addView(shadersView);
         layout.addView(gradientView, new FrameLayout.LayoutParams(
                 200, 200, Gravity.CENTER));
+
+        FrameLayout.LayoutParams lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER);
+        lp.setMargins(220, 0, 0, 0);
+        layout.addView(radialGradientView, lp);
+
+        lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER);
+        lp.setMargins(440, 0, 0, 0);
+        layout.addView(sweepGradientView, lp);
+
+        lp = new FrameLayout.LayoutParams(200, 200, Gravity.CENTER);
+        lp.setMargins(220, -220, 0, 0);
+        layout.addView(bitmapView, lp);
+
         layout.addView(rotateView, new FrameLayout.LayoutParams(
                 300, FrameLayout.LayoutParams.WRAP_CONTENT,
                 Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM));
@@ -65,6 +91,32 @@
         setContentView(layout);
     }
     
+    static class BitmapView extends View {
+        private final Paint mPaint;
+
+        BitmapView(Context c) {
+            super(c);
+
+            Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
+            BitmapShader shader = new BitmapShader(texture, Shader.TileMode.REPEAT,
+                    Shader.TileMode.REPEAT);
+            mPaint = new Paint();
+            mPaint.setShader(shader);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            setMeasuredDimension(200, 200);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint);
+        }
+    }
+    
     static class GradientView extends View {
         private final Paint mPaint;
 
@@ -90,6 +142,55 @@
         }
     }
 
+    static class RadialGradientView extends View {
+        private final Paint mPaint;
+
+        RadialGradientView(Context c) {
+            super(c);
+
+            RadialGradient gradient = new RadialGradient(0.0f, 0.0f, 100.0f, 0xff000000, 0xffffffff,
+                    Shader.TileMode.MIRROR);
+            mPaint = new Paint();
+            mPaint.setShader(gradient);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            setMeasuredDimension(200, 200);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint);
+        }
+    }
+    
+    static class SweepGradientView extends View {
+        private final Paint mPaint;
+
+        SweepGradientView(Context c) {
+            super(c);
+
+            SweepGradient gradient = new SweepGradient(100.0f, 100.0f, 0xff000000, 0xffffffff);                
+            mPaint = new Paint();
+            mPaint.setShader(gradient);
+        }
+
+        @Override
+        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+            setMeasuredDimension(200, 200);
+        }
+
+        @Override
+        protected void onDraw(Canvas canvas) {
+            super.onDraw(canvas);
+            canvas.drawRect(0.0f, 0.0f, getWidth(), getHeight(), mPaint);
+        }
+    }
+        
     static class ShadersView extends View {
         private final Paint mPaint;
         private final float mDrawWidth;