Revert "Revert "VectorDrawable native rendering - Step 4 of MANY""

This reverts commit 5a11e8d0ba21624025b89ac63bbd18befa55be0e.

Change-Id: I7a48b59c4f930dad65ddc8590c25a12636244ea2
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 1cf15ac..541c799 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -138,18 +138,7 @@
 }
 
 FullPath::FullPath(const FullPath& path) : Path(path) {
-    mStrokeWidth = path.mStrokeWidth;
-    mStrokeColor = path.mStrokeColor;
-    mStrokeAlpha = path.mStrokeAlpha;
-    mFillColor = path.mFillColor;
-    mFillAlpha = path.mFillAlpha;
-    mTrimPathStart = path.mTrimPathStart;
-    mTrimPathEnd = path.mTrimPathEnd;
-    mTrimPathOffset = path.mTrimPathOffset;
-    mStrokeMiterLimit = path.mStrokeMiterLimit;
-    mStrokeLineCap = path.mStrokeLineCap;
-    mStrokeLineJoin = path.mStrokeLineJoin;
-
+    mProperties = path.mProperties;
     SkRefCnt_SafeAssign(mStrokeGradient, path.mStrokeGradient);
     SkRefCnt_SafeAssign(mFillGradient, path.mFillGradient);
 }
@@ -159,7 +148,7 @@
         return mTrimmedSkPath;
     }
     Path::getUpdatedPath();
-    if (mTrimPathStart != 0.0f || mTrimPathEnd != 1.0f) {
+    if (mProperties.trimPathStart != 0.0f || mProperties.trimPathEnd != 1.0f) {
         applyTrim();
         return mTrimmedSkPath;
     } else {
@@ -170,14 +159,14 @@
 void FullPath::updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
         SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
         float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin) {
-    mStrokeWidth = strokeWidth;
-    mStrokeColor = strokeColor;
-    mStrokeAlpha = strokeAlpha;
-    mFillColor = fillColor;
-    mFillAlpha = fillAlpha;
-    mStrokeMiterLimit = strokeMiterLimit;
-    mStrokeLineCap = SkPaint::Cap(strokeLineCap);
-    mStrokeLineJoin = SkPaint::Join(strokeLineJoin);
+    mProperties.strokeWidth = strokeWidth;
+    mProperties.strokeColor = strokeColor;
+    mProperties.strokeAlpha = strokeAlpha;
+    mProperties.fillColor = fillColor;
+    mProperties.fillAlpha = fillAlpha;
+    mProperties.strokeMiterLimit = strokeMiterLimit;
+    mProperties.strokeLineCap = strokeLineCap;
+    mProperties.strokeLineJoin = strokeLineJoin;
 
     // If any trim property changes, mark trim dirty and update the trim path
     setTrimPathStart(trimPathStart);
@@ -195,12 +184,12 @@
     // Draw path's fill, if fill color or gradient is valid
     bool needsFill = false;
     if (mFillGradient != nullptr) {
-        mPaint.setColor(applyAlpha(SK_ColorBLACK, mFillAlpha));
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.fillAlpha));
         SkShader* newShader = mFillGradient->newWithLocalMatrix(matrix);
         mPaint.setShader(newShader);
         needsFill = true;
-    } else if (mFillColor != SK_ColorTRANSPARENT) {
-        mPaint.setColor(applyAlpha(mFillColor, mFillAlpha));
+    } else if (mProperties.fillColor != SK_ColorTRANSPARENT) {
+        mPaint.setColor(applyAlpha(mProperties.fillColor, mProperties.fillAlpha));
         needsFill = true;
     }
 
@@ -213,21 +202,21 @@
     // Draw path's stroke, if stroke color or gradient is valid
     bool needsStroke = false;
     if (mStrokeGradient != nullptr) {
-        mPaint.setColor(applyAlpha(SK_ColorBLACK, mStrokeAlpha));
+        mPaint.setColor(applyAlpha(SK_ColorBLACK, mProperties.strokeAlpha));
         SkShader* newShader = mStrokeGradient->newWithLocalMatrix(matrix);
         mPaint.setShader(newShader);
         needsStroke = true;
-    } else if (mStrokeColor != SK_ColorTRANSPARENT) {
-        mPaint.setColor(applyAlpha(mStrokeColor, mStrokeAlpha));
+    } else if (mProperties.strokeColor != SK_ColorTRANSPARENT) {
+        mPaint.setColor(applyAlpha(mProperties.strokeColor, mProperties.strokeAlpha));
         needsStroke = true;
     }
     if (needsStroke) {
         mPaint.setStyle(SkPaint::Style::kStroke_Style);
         mPaint.setAntiAlias(true);
-        mPaint.setStrokeJoin(mStrokeLineJoin);
-        mPaint.setStrokeCap(mStrokeLineCap);
-        mPaint.setStrokeMiter(mStrokeMiterLimit);
-        mPaint.setStrokeWidth(mStrokeWidth * strokeScale);
+        mPaint.setStrokeJoin(SkPaint::Join(mProperties.strokeLineJoin));
+        mPaint.setStrokeCap(SkPaint::Cap(mProperties.strokeLineCap));
+        mPaint.setStrokeMiter(mProperties.strokeMiterLimit);
+        mPaint.setStrokeWidth(mProperties.strokeWidth * strokeScale);
         outCanvas->drawPath(renderPath, mPaint);
     }
 }
@@ -236,14 +225,14 @@
  * Applies trimming to the specified path.
  */
 void FullPath::applyTrim() {
-    if (mTrimPathStart == 0.0f && mTrimPathEnd == 1.0f) {
+    if (mProperties.trimPathStart == 0.0f && mProperties.trimPathEnd == 1.0f) {
         // No trimming necessary.
         return;
     }
     SkPathMeasure measure(mSkPath, false);
     float len = SkScalarToFloat(measure.getLength());
-    float start = len * fmod((mTrimPathStart + mTrimPathOffset), 1.0f);
-    float end = len * fmod((mTrimPathEnd + mTrimPathOffset), 1.0f);
+    float start = len * fmod((mProperties.trimPathStart + mProperties.trimPathOffset), 1.0f);
+    float end = len * fmod((mProperties.trimPathEnd + mProperties.trimPathOffset), 1.0f);
 
     mTrimmedSkPath.reset();
     if (start > end) {
@@ -255,76 +244,69 @@
     mTrimDirty = false;
 }
 
-inline int putData(int8_t* outBytes, int startIndex, float value) {
-    int size = sizeof(float);
-    memcpy(&outBytes[startIndex], &value, size);
-    return size;
-}
-
-inline int putData(int8_t* outBytes, int startIndex, int value) {
-    int size = sizeof(int);
-    memcpy(&outBytes[startIndex], &value, size);
-    return size;
-}
-
-struct FullPathProperties {
-    // TODO: Consider storing full path properties in this struct instead of the fields.
-    float strokeWidth;
-    SkColor strokeColor;
-    float strokeAlpha;
-    SkColor fillColor;
-    float fillAlpha;
-    float trimPathStart;
-    float trimPathEnd;
-    float trimPathOffset;
-    int32_t strokeLineCap;
-    int32_t strokeLineJoin;
-    float strokeMiterLimit;
-};
-
-REQUIRE_COMPATIBLE_LAYOUT(FullPathProperties);
+REQUIRE_COMPATIBLE_LAYOUT(FullPath::Properties);
 
 static_assert(sizeof(float) == sizeof(int32_t), "float is not the same size as int32_t");
 static_assert(sizeof(SkColor) == sizeof(int32_t), "SkColor is not the same size as int32_t");
 
 bool FullPath::getProperties(int8_t* outProperties, int length) {
-    int propertyDataSize = sizeof(FullPathProperties);
+    int propertyDataSize = sizeof(Properties);
     if (length != propertyDataSize) {
         LOG_ALWAYS_FATAL("Properties needs exactly %d bytes, a byte array of size %d is provided",
                 propertyDataSize, length);
         return false;
     }
-    // TODO: consider replacing the property fields with a FullPathProperties struct.
-    FullPathProperties properties;
-    properties.strokeWidth = mStrokeWidth;
-    properties.strokeColor = mStrokeColor;
-    properties.strokeAlpha = mStrokeAlpha;
-    properties.fillColor = mFillColor;
-    properties.fillAlpha = mFillAlpha;
-    properties.trimPathStart = mTrimPathStart;
-    properties.trimPathEnd = mTrimPathEnd;
-    properties.trimPathOffset = mTrimPathOffset;
-    properties.strokeLineCap = mStrokeLineCap;
-    properties.strokeLineJoin = mStrokeLineJoin;
-    properties.strokeMiterLimit = mStrokeMiterLimit;
-
-    memcpy(outProperties, &properties, length);
+    Properties* out = reinterpret_cast<Properties*>(outProperties);
+    *out = mProperties;
     return true;
 }
 
+void FullPath::setColorPropertyValue(int propertyId, int32_t value) {
+    Property currentProperty = static_cast<Property>(propertyId);
+    if (currentProperty == Property::StrokeColor) {
+        mProperties.strokeColor = value;
+    } else if (currentProperty == Property::FillColor) {
+        mProperties.fillColor = value;
+    } else {
+        LOG_ALWAYS_FATAL("Error setting color property on FullPath: No valid property with id: %d",
+                propertyId);
+    }
+}
+
+void FullPath::setPropertyValue(int propertyId, float value) {
+    Property property = static_cast<Property>(propertyId);
+    switch (property) {
+    case Property::StrokeWidth:
+        setStrokeWidth(value);
+        break;
+    case Property::StrokeAlpha:
+        setStrokeAlpha(value);
+        break;
+    case Property::FillAlpha:
+        setFillAlpha(value);
+        break;
+    case Property::TrimPathStart:
+        setTrimPathStart(value);
+        break;
+    case Property::TrimPathEnd:
+        setTrimPathEnd(value);
+        break;
+    case Property::TrimPathOffset:
+        setTrimPathOffset(value);
+        break;
+    default:
+        LOG_ALWAYS_FATAL("Invalid property id: %d for animation", propertyId);
+        break;
+    }
+}
+
 void ClipPath::drawPath(SkCanvas* outCanvas, const SkPath& renderPath,
         float strokeScale, const SkMatrix& matrix){
     outCanvas->clipPath(renderPath, SkRegion::kIntersect_Op);
 }
 
 Group::Group(const Group& group) : Node(group) {
-    mRotate = group.mRotate;
-    mPivotX = group.mPivotX;
-    mPivotY = group.mPivotY;
-    mScaleX = group.mScaleX;
-    mScaleY = group.mScaleY;
-    mTranslateX = group.mTranslateX;
-    mTranslateY = group.mTranslateY;
+    mProperties = group.mProperties;
 }
 
 void Group::draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, float scaleX,
@@ -371,10 +353,11 @@
     outMatrix->reset();
     // TODO: use rotate(mRotate, mPivotX, mPivotY) and scale with pivot point, instead of
     // translating to pivot for rotating and scaling, then translating back.
-    outMatrix->postTranslate(-mPivotX, -mPivotY);
-    outMatrix->postScale(mScaleX, mScaleY);
-    outMatrix->postRotate(mRotate, 0, 0);
-    outMatrix->postTranslate(mTranslateX + mPivotX, mTranslateY + mPivotY);
+    outMatrix->postTranslate(-mProperties.pivotX, -mProperties.pivotY);
+    outMatrix->postScale(mProperties.scaleX, mProperties.scaleY);
+    outMatrix->postRotate(mProperties.rotate, 0, 0);
+    outMatrix->postTranslate(mProperties.translateX + mProperties.pivotX,
+            mProperties.translateY + mProperties.pivotY);
 }
 
 void Group::addChild(Node* child) {
@@ -388,38 +371,68 @@
                 propertyCount, length);
         return false;
     }
-    for (int i = 0; i < propertyCount; i++) {
-        Property currentProperty = static_cast<Property>(i);
-        switch (currentProperty) {
-        case Property::Rotate_Property:
-            outProperties[i] = mRotate;
-            break;
-        case Property::PivotX_Property:
-            outProperties[i] = mPivotX;
-            break;
-        case Property::PivotY_Property:
-            outProperties[i] = mPivotY;
-            break;
-        case Property::ScaleX_Property:
-            outProperties[i] = mScaleX;
-            break;
-        case Property::ScaleY_Property:
-            outProperties[i] = mScaleY;
-            break;
-        case Property::TranslateX_Property:
-            outProperties[i] = mTranslateX;
-            break;
-        case Property::TranslateY_Property:
-            outProperties[i] = mTranslateY;
-            break;
-        default:
-            LOG_ALWAYS_FATAL("Invalid input index: %d", i);
-            return false;
-        }
-    }
+    Properties* out = reinterpret_cast<Properties*>(outProperties);
+    *out = mProperties;
     return true;
 }
 
+// TODO: Consider animating the properties as float pointers
+float Group::getPropertyValue(int propertyId) const {
+    Property currentProperty = static_cast<Property>(propertyId);
+    switch (currentProperty) {
+    case Property::Rotate:
+        return mProperties.rotate;
+    case Property::PivotX:
+        return mProperties.pivotX;
+    case Property::PivotY:
+        return mProperties.pivotY;
+    case Property::ScaleX:
+        return mProperties.scaleX;
+    case Property::ScaleY:
+        return mProperties.scaleY;
+    case Property::TranslateX:
+        return mProperties.translateX;
+    case Property::TranslateY:
+        return mProperties.translateY;
+    default:
+        LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
+        return 0;
+    }
+}
+
+void Group::setPropertyValue(int propertyId, float value) {
+    Property currentProperty = static_cast<Property>(propertyId);
+    switch (currentProperty) {
+    case Property::Rotate:
+        mProperties.rotate = value;
+        break;
+    case Property::PivotX:
+        mProperties.pivotX = value;
+        break;
+    case Property::PivotY:
+        mProperties.pivotY = value;
+        break;
+    case Property::ScaleX:
+        mProperties.scaleX = value;
+        break;
+    case Property::ScaleY:
+        mProperties.scaleY = value;
+        break;
+    case Property::TranslateX:
+        mProperties.translateX = value;
+        break;
+    case Property::TranslateY:
+        mProperties.translateY = value;
+        break;
+    default:
+        LOG_ALWAYS_FATAL("Invalid property index: %d", propertyId);
+    }
+}
+
+bool Group::isValidProperty(int propertyId) {
+    return propertyId >= 0 && propertyId < static_cast<int>(Property::Count);
+}
+
 void Tree::draw(Canvas* outCanvas, SkColorFilter* colorFilter,
         const SkRect& bounds, bool needsMirroring, bool canReuseCache) {
     // The imageView can scale the canvas in different ways, in order to
@@ -445,6 +458,8 @@
         return;
     }
 
+    mPaint.setColorFilter(colorFilter);
+
     int saveCount = outCanvas->save(SaveFlags::MatrixClip);
     outCanvas->translate(mBounds.fLeft, mBounds.fTop);
 
@@ -458,43 +473,33 @@
     // And we use this bound for the destination rect for the drawBitmap, so
     // we offset to (0, 0);
     mBounds.offsetTo(0, 0);
-
     createCachedBitmapIfNeeded(scaledWidth, scaledHeight);
-    if (!mAllowCaching) {
-        updateCachedBitmap(scaledWidth, scaledHeight);
-    } else {
-        if (!canReuseCache || mCacheDirty) {
-            updateCachedBitmap(scaledWidth, scaledHeight);
-        }
-    }
-    drawCachedBitmapWithRootAlpha(outCanvas, colorFilter, mBounds);
+
+    outCanvas->drawVectorDrawable(this);
 
     outCanvas->restoreToCount(saveCount);
 }
 
-void Tree::drawCachedBitmapWithRootAlpha(Canvas* outCanvas, SkColorFilter* filter,
-        const SkRect& originalBounds) {
+SkPaint* Tree::getPaint() {
     SkPaint* paint;
-    if (mRootAlpha == 1.0f && filter == NULL) {
+    if (mRootAlpha == 1.0f && mPaint.getColorFilter() == NULL) {
         paint = NULL;
     } else {
         mPaint.setFilterQuality(kLow_SkFilterQuality);
         mPaint.setAlpha(mRootAlpha * 255);
-        mPaint.setColorFilter(filter);
         paint = &mPaint;
     }
-    outCanvas->drawBitmap(mCachedBitmap, 0, 0, mCachedBitmap.width(), mCachedBitmap.height(),
-            originalBounds.fLeft, originalBounds.fTop, originalBounds.fRight,
-            originalBounds.fBottom, paint);
+    return paint;
 }
 
-void Tree::updateCachedBitmap(int width, int height) {
+const SkBitmap& Tree::getBitmapUpdateIfDirty() {
     mCachedBitmap.eraseColor(SK_ColorTRANSPARENT);
     SkCanvas outCanvas(mCachedBitmap);
-    float scaleX = width / mViewportWidth;
-    float scaleY = height / mViewportHeight;
+    float scaleX = (float) mCachedBitmap.width() / mViewportWidth;
+    float scaleY = (float) mCachedBitmap.height() / mViewportHeight;
     mRootNode->draw(&outCanvas, SkMatrix::I(), scaleX, scaleY);
     mCacheDirty = false;
+    return mCachedBitmap;
 }
 
 void Tree::createCachedBitmapIfNeeded(int width, int height) {