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