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