Gradient for VectorDrawable's fill and stroke

Add ComplexColor interface for both GradientColor and ColorStateList.
Set up constant state, factory, theme attrs for GradientColor, while
refactoring the ColorStateList's similar code. (Functionality in CSL should
be the same).

Support themeing in both the root and item level in GradientColor.
For example, both startColor in <gradient> tag or color in <item> tag can
have theme color.
Add tests for both simple and complex cases with themeing etc.

Hook up the native VectorDrawable implementation using 2 extra JNI calls for
simplicity. Such calls only happen at inflate and applyTheme call.

b/22564318

Change-Id: Ibdc564ddb4a7ee0133c6141c4784782f0c93ce0e
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 1d31c9e..4d4acb9 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -18,6 +18,7 @@
 
 #include "PathParser.h"
 #include "SkImageInfo.h"
+#include "SkShader.h"
 #include <utils/Log.h>
 #include "utils/Macros.h"
 #include "utils/VectorDrawableUtils.h"
@@ -49,7 +50,7 @@
 
     float minScale = fmin(scaleX, scaleY);
     float strokeScale = minScale * matrixScale;
-    drawPath(outCanvas, renderPath, strokeScale);
+    drawPath(outCanvas, renderPath, strokeScale, pathMatrix);
 }
 
 void Path::setPathData(const Data& data) {
@@ -148,6 +149,9 @@
     mStrokeMiterLimit = path.mStrokeMiterLimit;
     mStrokeLineCap = path.mStrokeLineCap;
     mStrokeLineJoin = path.mStrokeLineJoin;
+
+    SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
+    SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
 }
 
 const SkPath& FullPath::getUpdatedPath() {
@@ -186,22 +190,44 @@
     return SkColorSetA(color, alphaBytes * alpha);
 }
 
-void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale){
-    // Draw path's fill, if fill color isn't transparent.
-    if (mFillColor != SK_ColorTRANSPARENT) {
-        mPaint.setStyle(SkPaint::Style::kFill_Style);
-        mPaint.setAntiAlias(true);
+void FullPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath, float strokeScale,
+                        const SkMatrix& matrix){
+    // Draw path's fill, if fill color or gradient is valid
+    bool needsFill = false;
+    if (mFillGradient != nullptr) {
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mFillAlpha));
+        SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
+        mPaint.setShader(newShader);
+        needsFill = true;
+    } else if (mFillColor != SK_ColorTRANSPARENT) {
         mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
         outCanvas->drawPath(renderPath, mPaint);
+        needsFill = true;
     }
-    // Draw path's stroke, if stroke color isn't transparent
-    if (mStrokeColor != SK_ColorTRANSPARENT) {
+
+    if (needsFill) {
+        mPaint.setStyle(SkPaint::Style::kFill_Style);
+        mPaint.setAntiAlias(true);
+        outCanvas->drawPath(renderPath, mPaint);
+    }
+
+    // Draw path's stroke, if stroke color or gradient is valid
+    bool needsStroke = false;
+    if (mStrokeGradient != nullptr) {
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mStrokeAlpha));
+        SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
+        mPaint.setShader(newShader);
+        needsStroke = true;
+    } else if (mStrokeColor != SK_ColorTRANSPARENT) {
+        mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+        needsStroke = true;
+    }
+    if (needsStroke) {
         mPaint.setStyle(SkPaint::Style::kStroke_Style);
         mPaint.setAntiAlias(true);
         mPaint.setStrokeJoin(mStrokeLineJoin);
         mPaint.setStrokeCap(mStrokeLineCap);
         mPaint.setStrokeMiter(mStrokeMiterLimit);
-        mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
         mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
         outCanvas->drawPath(renderPath, mPaint);
     }
@@ -288,7 +314,7 @@
 }
 
 void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
-        float strokeScale){
+        float strokeScale, const SkMatrix& matrix){
     outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
 }