OSDN Git Service

DO NOT MERGE. Grant MMS Uri permissions as the calling UID.
[android-x86/frameworks-base.git] / libs / hwui / VectorDrawable.h
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