Home | History | Annotate | Download | only in hwui
      1 /*
      2  * Copyright (C) 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ANDROID_HWUI_VPATH_H
     18 #define ANDROID_HWUI_VPATH_H
     19 
     20 #include "hwui/Canvas.h"
     21 #include "hwui/Bitmap.h"
     22 #include "renderthread/CacheManager.h"
     23 #include "DisplayList.h"
     24 
     25 #include <SkBitmap.h>
     26 #include <SkColor.h>
     27 #include <SkColorFilter.h>
     28 #include <SkCanvas.h>
     29 #include <SkMatrix.h>
     30 #include <SkPaint.h>
     31 #include <SkPath.h>
     32 #include <SkPathMeasure.h>
     33 #include <SkRect.h>
     34 #include <SkShader.h>
     35 #include <SkSurface.h>
     36 
     37 #include <cutils/compiler.h>
     38 #include <stddef.h>
     39 #include <vector>
     40 #include <string>
     41 
     42 namespace android {
     43 namespace uirenderer {
     44 
     45 // Debug
     46 #if DEBUG_VECTOR_DRAWABLE
     47     #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
     48 #else
     49     #define VECTOR_DRAWABLE_LOGD(...)
     50 #endif
     51 
     52 namespace VectorDrawable {
     53 #define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
     54 #define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
     55 #define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
     56     onPropertyChanged(); retVal;})
     57 #define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
     58 
     59 /* A VectorDrawable is composed of a tree of nodes.
     60  * Each node can be a group node, or a path.
     61  * A group node can have groups or paths as children, but a path node has
     62  * no children.
     63  * One example can be:
     64  *                 Root Group
     65  *                /    |     \
     66  *           Group    Path    Group
     67  *          /     \             |
     68  *         Path   Path         Path
     69  *
     70  * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
     71  * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
     72  * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
     73  * Each cache has their own generation id to track whether they are up to date with the latest
     74  * change in the tree.
     75  *
     76  * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
     77  * all the properties, and viewport change, etc.) are only modifying the staging properties. The
     78  * staging properties will then be marked dirty and will be pushed over to render thread properties
     79  * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
     80  * staging properties with render thread properties to reflect the latest animation value.
     81  *
     82  */
     83 
     84 class PropertyChangedListener {
     85 public:
     86     PropertyChangedListener(bool* dirty, bool* stagingDirty)
     87             : mDirty(dirty), mStagingDirty(stagingDirty) {}
     88     void onPropertyChanged() {
     89             *mDirty = true;
     90     }
     91     void onStagingPropertyChanged() {
     92             *mStagingDirty = true;
     93     }
     94 private:
     95     bool* mDirty;
     96     bool* mStagingDirty;
     97 };
     98 
     99 class ANDROID_API Node {
    100 public:
    101     class Properties {
    102     public:
    103         explicit Properties(Node* node) : mNode(node) {}
    104         inline void onPropertyChanged() {
    105             mNode->onPropertyChanged(this);
    106         }
    107     private:
    108         Node* mNode;
    109     };
    110     Node(const Node& node) {
    111         mName = node.mName;
    112     }
    113     Node() {}
    114     virtual void draw(SkCanvas* outCanvas, bool useStagingData) = 0;
    115     virtual void dump() = 0;
    116     void setName(const char* name) {
    117         mName = name;
    118     }
    119     virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
    120         mPropertyChangedListener = listener;
    121     }
    122     virtual void onPropertyChanged(Properties* properties) = 0;
    123     virtual ~Node(){}
    124     virtual void syncProperties() = 0;
    125 protected:
    126     std::string mName;
    127     PropertyChangedListener* mPropertyChangedListener = nullptr;
    128 };
    129 
    130 class ANDROID_API Path : public Node {
    131 public:
    132     struct ANDROID_API Data {
    133         std::vector<char> verbs;
    134         std::vector<size_t> verbSizes;
    135         std::vector<float> points;
    136         bool operator==(const Data& data) const {
    137             return verbs == data.verbs && verbSizes == data.verbSizes
    138                     && points == data.points;
    139         }
    140     };
    141 
    142     class PathProperties : public Properties {
    143     public:
    144         explicit PathProperties(Node* node) : Properties(node) {}
    145         void syncProperties(const PathProperties& prop) {
    146             mData = prop.mData;
    147             onPropertyChanged();
    148         }
    149         void setData(const Data& data) {
    150             // Updates the path data. Note that we don't generate a new Skia path right away
    151             // because there are cases where the animation is changing the path data, but the view
    152             // that hosts the VD has gone off screen, in which case we won't even draw. So we
    153             // postpone the Skia path generation to the draw time.
    154             if (data == mData) {
    155                 return;
    156             }
    157             mData = data;
    158             onPropertyChanged();
    159 
    160         }
    161         const Data& getData() const {
    162             return mData;
    163         }
    164     private:
    165         Data mData;
    166     };
    167 
    168     Path(const Path& path);
    169     Path(const char* path, size_t strLength);
    170     Path() {}
    171 
    172     void dump() override;
    173     virtual void syncProperties() override;
    174     virtual void onPropertyChanged(Properties* prop) override {
    175         if (prop == &mStagingProperties) {
    176             mStagingPropertiesDirty = true;
    177             if (mPropertyChangedListener) {
    178                 mPropertyChangedListener->onStagingPropertyChanged();
    179             }
    180         } else if (prop == &mProperties){
    181             mSkPathDirty = true;
    182             if (mPropertyChangedListener) {
    183                 mPropertyChangedListener->onPropertyChanged();
    184             }
    185         }
    186     }
    187     PathProperties* mutateStagingProperties() { return &mStagingProperties; }
    188     const PathProperties* stagingProperties() { return &mStagingProperties; }
    189 
    190     // This should only be called from animations on RT
    191     PathProperties* mutateProperties() { return &mProperties; }
    192 
    193 protected:
    194     virtual const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath);
    195 
    196     // Internal data, render thread only.
    197     bool mSkPathDirty = true;
    198     SkPath mSkPath;
    199 
    200 private:
    201     PathProperties mProperties = PathProperties(this);
    202     PathProperties mStagingProperties = PathProperties(this);
    203     bool mStagingPropertiesDirty = true;
    204 };
    205 
    206 class ANDROID_API FullPath: public Path {
    207 public:
    208     class FullPathProperties : public Properties {
    209     public:
    210         struct PrimitiveFields {
    211             float strokeWidth = 0;
    212             SkColor strokeColor = SK_ColorTRANSPARENT;
    213             float strokeAlpha = 1;
    214             SkColor fillColor = SK_ColorTRANSPARENT;
    215             float fillAlpha = 1;
    216             float trimPathStart = 0;
    217             float trimPathEnd = 1;
    218             float trimPathOffset = 0;
    219             int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
    220             int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
    221             float strokeMiterLimit = 4;
    222             int fillType = 0; /* non-zero or kWinding_FillType in Skia */
    223         };
    224         explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
    225         ~FullPathProperties() {
    226             SkSafeUnref(fillGradient);
    227             SkSafeUnref(strokeGradient);
    228         }
    229         void syncProperties(const FullPathProperties& prop) {
    230             mPrimitiveFields = prop.mPrimitiveFields;
    231             mTrimDirty = true;
    232             UPDATE_SKPROP(fillGradient, prop.fillGradient);
    233             UPDATE_SKPROP(strokeGradient, prop.strokeGradient);
    234             onPropertyChanged();
    235         }
    236         void setFillGradient(SkShader* gradient) {
    237             if(UPDATE_SKPROP(fillGradient, gradient)) {
    238                 onPropertyChanged();
    239             }
    240         }
    241         void setStrokeGradient(SkShader* gradient) {
    242             if(UPDATE_SKPROP(strokeGradient, gradient)) {
    243                 onPropertyChanged();
    244             }
    245         }
    246         SkShader* getFillGradient() const {
    247             return fillGradient;
    248         }
    249         SkShader* getStrokeGradient() const {
    250             return strokeGradient;
    251         }
    252         float getStrokeWidth() const{
    253             return mPrimitiveFields.strokeWidth;
    254         }
    255         void setStrokeWidth(float strokeWidth) {
    256             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
    257         }
    258         SkColor getStrokeColor() const{
    259             return mPrimitiveFields.strokeColor;
    260         }
    261         void setStrokeColor(SkColor strokeColor) {
    262             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
    263         }
    264         float getStrokeAlpha() const{
    265             return mPrimitiveFields.strokeAlpha;
    266         }
    267         void setStrokeAlpha(float strokeAlpha) {
    268             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
    269         }
    270         SkColor getFillColor() const {
    271             return mPrimitiveFields.fillColor;
    272         }
    273         void setFillColor(SkColor fillColor) {
    274             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
    275         }
    276         float getFillAlpha() const{
    277             return mPrimitiveFields.fillAlpha;
    278         }
    279         void setFillAlpha(float fillAlpha) {
    280             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
    281         }
    282         float getTrimPathStart() const{
    283             return mPrimitiveFields.trimPathStart;
    284         }
    285         void setTrimPathStart(float trimPathStart) {
    286             VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
    287         }
    288         float getTrimPathEnd() const{
    289             return mPrimitiveFields.trimPathEnd;
    290         }
    291         void setTrimPathEnd(float trimPathEnd) {
    292             VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
    293         }
    294         float getTrimPathOffset() const{
    295             return mPrimitiveFields.trimPathOffset;
    296         }
    297         void setTrimPathOffset(float trimPathOffset) {
    298             VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
    299         }
    300 
    301         float getStrokeMiterLimit() const {
    302             return mPrimitiveFields.strokeMiterLimit;
    303         }
    304         float getStrokeLineCap() const {
    305             return mPrimitiveFields.strokeLineCap;
    306         }
    307         float getStrokeLineJoin() const {
    308             return mPrimitiveFields.strokeLineJoin;
    309         }
    310         float getFillType() const {
    311             return mPrimitiveFields.fillType;
    312         }
    313         bool copyProperties(int8_t* outProperties, int length) const;
    314         void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
    315                 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
    316                 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
    317                 int fillType) {
    318             mPrimitiveFields.strokeWidth = strokeWidth;
    319             mPrimitiveFields.strokeColor = strokeColor;
    320             mPrimitiveFields.strokeAlpha = strokeAlpha;
    321             mPrimitiveFields.fillColor = fillColor;
    322             mPrimitiveFields.fillAlpha = fillAlpha;
    323             mPrimitiveFields.trimPathStart = trimPathStart;
    324             mPrimitiveFields.trimPathEnd = trimPathEnd;
    325             mPrimitiveFields.trimPathOffset = trimPathOffset;
    326             mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
    327             mPrimitiveFields.strokeLineCap = strokeLineCap;
    328             mPrimitiveFields.strokeLineJoin = strokeLineJoin;
    329             mPrimitiveFields.fillType = fillType;
    330             mTrimDirty = true;
    331             onPropertyChanged();
    332         }
    333         // Set property values during animation
    334         void setColorPropertyValue(int propertyId, int32_t value);
    335         void setPropertyValue(int propertyId, float value);
    336         bool mTrimDirty;
    337     private:
    338         enum class Property {
    339             strokeWidth = 0,
    340             strokeColor,
    341             strokeAlpha,
    342             fillColor,
    343             fillAlpha,
    344             trimPathStart,
    345             trimPathEnd,
    346             trimPathOffset,
    347             strokeLineCap,
    348             strokeLineJoin,
    349             strokeMiterLimit,
    350             fillType,
    351             count,
    352         };
    353         PrimitiveFields mPrimitiveFields;
    354         SkShader* fillGradient = nullptr;
    355         SkShader* strokeGradient = nullptr;
    356     };
    357 
    358     // Called from UI thread
    359     FullPath(const FullPath& path); // for cloning
    360     FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
    361     FullPath() : Path() {}
    362     void draw(SkCanvas* outCanvas, bool useStagingData) override;
    363     void dump() override;
    364     FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
    365     const FullPathProperties* stagingProperties() { return &mStagingProperties; }
    366 
    367     // This should only be called from animations on RT
    368     FullPathProperties* mutateProperties() { return &mProperties; }
    369 
    370     virtual void syncProperties() override;
    371     virtual void onPropertyChanged(Properties* properties) override {
    372         Path::onPropertyChanged(properties);
    373         if (properties == &mStagingProperties) {
    374             mStagingPropertiesDirty = true;
    375             if (mPropertyChangedListener) {
    376                 mPropertyChangedListener->onStagingPropertyChanged();
    377             }
    378         } else if (properties == &mProperties) {
    379             if (mPropertyChangedListener) {
    380                 mPropertyChangedListener->onPropertyChanged();
    381             }
    382         }
    383     }
    384 
    385 protected:
    386     const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
    387 private:
    388 
    389     FullPathProperties mProperties = FullPathProperties(this);
    390     FullPathProperties mStagingProperties = FullPathProperties(this);
    391     bool mStagingPropertiesDirty = true;
    392 
    393     // Intermediate data for drawing, render thread only
    394     SkPath mTrimmedSkPath;
    395 
    396 };
    397 
    398 class ANDROID_API ClipPath: public Path {
    399 public:
    400     ClipPath(const ClipPath& path) : Path(path) {}
    401     ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
    402     ClipPath() : Path() {}
    403     void draw(SkCanvas* outCanvas, bool useStagingData) override;
    404 };
    405 
    406 class ANDROID_API Group: public Node {
    407 public:
    408     class GroupProperties : public Properties {
    409     public:
    410         explicit GroupProperties(Node* mNode) : Properties(mNode) {}
    411         struct PrimitiveFields {
    412             float rotate = 0;
    413             float pivotX = 0;
    414             float pivotY = 0;
    415             float scaleX = 1;
    416             float scaleY = 1;
    417             float translateX = 0;
    418             float translateY = 0;
    419         } mPrimitiveFields;
    420         void syncProperties(const GroupProperties& prop) {
    421             mPrimitiveFields = prop.mPrimitiveFields;
    422             onPropertyChanged();
    423         }
    424         float getRotation() const {
    425             return mPrimitiveFields.rotate;
    426         }
    427         void setRotation(float rotation) {
    428             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
    429         }
    430         float getPivotX() const {
    431             return mPrimitiveFields.pivotX;
    432         }
    433         void setPivotX(float pivotX) {
    434             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
    435         }
    436         float getPivotY() const {
    437             return mPrimitiveFields.pivotY;
    438         }
    439         void setPivotY(float pivotY) {
    440             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
    441         }
    442         float getScaleX() const {
    443             return mPrimitiveFields.scaleX;
    444         }
    445         void setScaleX(float scaleX) {
    446             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
    447         }
    448         float getScaleY() const {
    449             return mPrimitiveFields.scaleY;
    450         }
    451         void setScaleY(float scaleY) {
    452             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
    453         }
    454         float getTranslateX() const {
    455             return mPrimitiveFields.translateX;
    456         }
    457         void setTranslateX(float translateX) {
    458             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
    459         }
    460         float getTranslateY() const {
    461             return mPrimitiveFields.translateY;
    462         }
    463         void setTranslateY(float translateY) {
    464             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
    465         }
    466         void updateProperties(float rotate, float pivotX, float pivotY,
    467                 float scaleX, float scaleY, float translateX, float translateY) {
    468             mPrimitiveFields.rotate = rotate;
    469             mPrimitiveFields.pivotX = pivotX;
    470             mPrimitiveFields.pivotY = pivotY;
    471             mPrimitiveFields.scaleX = scaleX;
    472             mPrimitiveFields.scaleY = scaleY;
    473             mPrimitiveFields.translateX = translateX;
    474             mPrimitiveFields.translateY = translateY;
    475             onPropertyChanged();
    476         }
    477         void setPropertyValue(int propertyId, float value);
    478         float getPropertyValue(int propertyId) const;
    479         bool copyProperties(float* outProperties, int length) const;
    480         static bool isValidProperty(int propertyId);
    481     private:
    482         enum class Property {
    483             rotate = 0,
    484             pivotX,
    485             pivotY,
    486             scaleX,
    487             scaleY,
    488             translateX,
    489             translateY,
    490             // Count of the properties, must be at the end.
    491             count,
    492         };
    493     };
    494 
    495     Group(const Group& group);
    496     Group() {}
    497     void addChild(Node* child);
    498     virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
    499         Node::setPropertyChangedListener(listener);
    500         for (auto& child : mChildren) {
    501              child->setPropertyChangedListener(listener);
    502         }
    503     }
    504     virtual void syncProperties() override;
    505     GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
    506     const GroupProperties* stagingProperties() { return &mStagingProperties; }
    507 
    508     // This should only be called from animations on RT
    509     GroupProperties* mutateProperties() { return &mProperties; }
    510 
    511     // Methods below could be called from either UI thread or Render Thread.
    512     virtual void draw(SkCanvas* outCanvas, bool useStagingData) override;
    513     void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
    514     void dump() override;
    515     static bool isValidProperty(int propertyId);
    516 
    517     virtual void onPropertyChanged(Properties* properties) override {
    518         if (properties == &mStagingProperties) {
    519             mStagingPropertiesDirty = true;
    520             if (mPropertyChangedListener) {
    521                 mPropertyChangedListener->onStagingPropertyChanged();
    522             }
    523         } else {
    524             if (mPropertyChangedListener) {
    525                 mPropertyChangedListener->onPropertyChanged();
    526             }
    527         }
    528     }
    529 
    530 private:
    531     GroupProperties mProperties = GroupProperties(this);
    532     GroupProperties mStagingProperties = GroupProperties(this);
    533     bool mStagingPropertiesDirty = true;
    534     std::vector< std::unique_ptr<Node> > mChildren;
    535 };
    536 
    537 class ANDROID_API Tree : public VirtualLightRefBase {
    538 public:
    539     explicit Tree(Group* rootNode) : mRootNode(rootNode) {
    540         mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
    541     }
    542 
    543     // Copy properties from the tree and use the give node as the root node
    544     Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
    545         mStagingProperties.syncAnimatableProperties(*copy->stagingProperties());
    546         mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties());
    547     }
    548     // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
    549     // canvas. Returns the number of pixels needed for the bitmap cache.
    550     int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
    551             const SkRect& bounds, bool needsMirroring, bool canReuseCache);
    552     void drawStaging(Canvas* canvas);
    553 
    554     Bitmap& getBitmapUpdateIfDirty();
    555     void setAllowCaching(bool allowCaching) {
    556         mAllowCaching = allowCaching;
    557     }
    558     SkPaint* getPaint();
    559     void syncProperties() {
    560         if (mStagingProperties.mNonAnimatablePropertiesDirty) {
    561             mProperties.syncNonAnimatableProperties(mStagingProperties);
    562             mStagingProperties.mNonAnimatablePropertiesDirty = false;
    563         }
    564 
    565         if (mStagingProperties.mAnimatablePropertiesDirty) {
    566             mProperties.syncAnimatableProperties(mStagingProperties);
    567         } else {
    568             mStagingProperties.syncAnimatableProperties(mProperties);
    569         }
    570         mStagingProperties.mAnimatablePropertiesDirty = false;
    571         mRootNode->syncProperties();
    572     }
    573 
    574     class TreeProperties {
    575     public:
    576         explicit TreeProperties(Tree* tree) : mTree(tree) {}
    577         // Properties that can only be modified by UI thread, therefore sync should
    578         // only go from UI to RT
    579         struct NonAnimatableProperties {
    580             float viewportWidth = 0;
    581             float viewportHeight = 0;
    582             SkRect bounds;
    583             int scaledWidth = 0;
    584             int scaledHeight = 0;
    585             SkColorFilter* colorFilter = nullptr;
    586             ~NonAnimatableProperties() {
    587                 SkSafeUnref(colorFilter);
    588             }
    589         } mNonAnimatableProperties;
    590         bool mNonAnimatablePropertiesDirty = true;
    591 
    592         float mRootAlpha = 1.0f;
    593         bool mAnimatablePropertiesDirty = true;
    594 
    595         void syncNonAnimatableProperties(const TreeProperties& prop) {
    596             // Copy over the data that can only be changed in UI thread
    597             if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
    598                 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
    599                         prop.mNonAnimatableProperties.colorFilter);
    600             }
    601             mNonAnimatableProperties = prop.mNonAnimatableProperties;
    602         }
    603 
    604         void setViewportSize(float width, float height) {
    605             if (mNonAnimatableProperties.viewportWidth != width
    606                     || mNonAnimatableProperties.viewportHeight != height) {
    607                 mNonAnimatablePropertiesDirty = true;
    608                 mNonAnimatableProperties.viewportWidth = width;
    609                 mNonAnimatableProperties.viewportHeight = height;
    610                 mTree->onPropertyChanged(this);
    611             }
    612         }
    613         void setBounds(const SkRect& bounds) {
    614             if (mNonAnimatableProperties.bounds != bounds) {
    615                 mNonAnimatableProperties.bounds = bounds;
    616                 mNonAnimatablePropertiesDirty = true;
    617                 mTree->onPropertyChanged(this);
    618             }
    619         }
    620 
    621         void setScaledSize(int width, int height) {
    622             // If the requested size is bigger than what the bitmap was, then
    623             // we increase the bitmap size to match. The width and height
    624             // are bound by MAX_CACHED_BITMAP_SIZE.
    625             if (mNonAnimatableProperties.scaledWidth < width
    626                     || mNonAnimatableProperties.scaledHeight < height) {
    627                 mNonAnimatableProperties.scaledWidth = std::max(width,
    628                         mNonAnimatableProperties.scaledWidth);
    629                 mNonAnimatableProperties.scaledHeight = std::max(height,
    630                         mNonAnimatableProperties.scaledHeight);
    631                 mNonAnimatablePropertiesDirty = true;
    632                 mTree->onPropertyChanged(this);
    633             }
    634         }
    635         void setColorFilter(SkColorFilter* filter) {
    636             if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
    637                 mNonAnimatablePropertiesDirty = true;
    638                 mTree->onPropertyChanged(this);
    639             }
    640         }
    641         SkColorFilter* getColorFilter() const{
    642             return mNonAnimatableProperties.colorFilter;
    643         }
    644 
    645         float getViewportWidth() const {
    646             return mNonAnimatableProperties.viewportWidth;
    647         }
    648         float getViewportHeight() const {
    649             return mNonAnimatableProperties.viewportHeight;
    650         }
    651         float getScaledWidth() const {
    652             return mNonAnimatableProperties.scaledWidth;
    653         }
    654         float getScaledHeight() const {
    655             return mNonAnimatableProperties.scaledHeight;
    656         }
    657         void syncAnimatableProperties(const TreeProperties& prop) {
    658             mRootAlpha = prop.mRootAlpha;
    659         }
    660         bool setRootAlpha(float rootAlpha) {
    661             if (rootAlpha != mRootAlpha) {
    662                 mAnimatablePropertiesDirty = true;
    663                 mRootAlpha = rootAlpha;
    664                 mTree->onPropertyChanged(this);
    665                 return true;
    666             }
    667             return false;
    668         }
    669         float getRootAlpha() const { return mRootAlpha;}
    670         const SkRect& getBounds() const {
    671             return mNonAnimatableProperties.bounds;
    672         }
    673         Tree* mTree;
    674     };
    675     void onPropertyChanged(TreeProperties* prop);
    676     TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
    677     const TreeProperties* stagingProperties() const { return &mStagingProperties; }
    678 
    679     // This should only be called from animations on RT
    680     TreeProperties* mutateProperties() { return &mProperties; }
    681 
    682     // called from RT only
    683     const TreeProperties& properties() const { return mProperties; }
    684 
    685     // This should always be called from RT.
    686     void markDirty() { mCache.dirty = true; }
    687     bool isDirty() const { return mCache.dirty; }
    688     bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
    689     void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
    690 
    691     /**
    692      * Draws VD cache into a canvas. This should always be called from RT and it works with Skia
    693      * pipelines only.
    694      */
    695     void draw(SkCanvas* canvas);
    696 
    697     /**
    698      * Draws VD into a GPU backed surface.
    699      * This should always be called from RT and it works with Skia pipeline only.
    700      */
    701     void updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context);
    702 
    703 private:
    704     class Cache {
    705     public:
    706         sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
    707         //TODO: use surface instead of bitmap when drawing in software canvas
    708         bool dirty = true;
    709 
    710         // the rest of the code in Cache is used by Skia pipelines only
    711 
    712         ~Cache() { clear(); }
    713 
    714         /**
    715          * Stores a weak pointer to the atlas and a key.
    716          */
    717         void setAtlas(sp<skiapipeline::VectorDrawableAtlas> atlas,
    718                 skiapipeline::AtlasKey newAtlasKey);
    719 
    720         /**
    721          * Gets a surface and bounds from the atlas.
    722          *
    723          * @return nullptr if the altas has been deleted.
    724          */
    725         sk_sp<SkSurface> getSurface(SkRect* bounds);
    726 
    727         /**
    728          * Releases atlas key from the atlas, which makes it available for reuse.
    729          */
    730         void clear();
    731     private:
    732         wp<skiapipeline::VectorDrawableAtlas> mAtlas;
    733         skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY;
    734     };
    735 
    736     SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
    737     bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
    738     bool canReuseBitmap(Bitmap*, int width, int height);
    739     void updateBitmapCache(Bitmap& outCache, bool useStagingData);
    740 
    741     /**
    742      * Draws the root node into "surface" at a given "dst" position.
    743      */
    744     void draw(SkSurface* surface, const SkRect& dst);
    745 
    746     // Cap the bitmap size, such that it won't hurt the performance too much
    747     // and it won't crash due to a very large scale.
    748     // The drawable will look blurry above this size.
    749     const static int MAX_CACHED_BITMAP_SIZE;
    750 
    751     bool mAllowCaching = true;
    752     std::unique_ptr<Group> mRootNode;
    753 
    754     TreeProperties mProperties = TreeProperties(this);
    755     TreeProperties mStagingProperties = TreeProperties(this);
    756 
    757     SkPaint mPaint;
    758 
    759     Cache mStagingCache;
    760     Cache mCache;
    761 
    762     PropertyChangedListener mPropertyChangedListener
    763             = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
    764 
    765     mutable bool mWillBeConsumed = false;
    766 };
    767 
    768 } // namespace VectorDrawable
    769 
    770 typedef VectorDrawable::Path::Data PathData;
    771 } // namespace uirenderer
    772 } // namespace android
    773 
    774 #endif // ANDROID_HWUI_VPATH_H
    775