• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
PropertyChangedListener(bool * dirty,bool * stagingDirty)76     PropertyChangedListener(bool* dirty, bool* stagingDirty)
77             : mDirty(dirty), mStagingDirty(stagingDirty) {}
onPropertyChanged()78     void onPropertyChanged() {
79             *mDirty = true;
80     }
onStagingPropertyChanged()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:
Properties(Node * node)93         Properties(Node* node) : mNode(node) {}
onPropertyChanged()94         inline void onPropertyChanged() {
95             mNode->onPropertyChanged(this);
96         }
97     private:
98         Node* mNode;
99     };
Node(const Node & node)100     Node(const Node& node) {
101         mName = node.mName;
102     }
Node()103     Node() {}
104     virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
105             float scaleX, float scaleY, bool useStagingData) = 0;
106     virtual void dump() = 0;
setName(const char * name)107     void setName(const char* name) {
108         mName = name;
109     }
setPropertyChangedListener(PropertyChangedListener * listener)110     virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
111         mPropertyChangedListener = listener;
112     }
113     virtual void onPropertyChanged(Properties* properties) = 0;
~Node()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:
PathProperties(Node * node)135         PathProperties(Node* node) : Properties(node) {}
syncProperties(const PathProperties & prop)136         void syncProperties(const PathProperties& prop) {
137             mData = prop.mData;
138             onPropertyChanged();
139         }
setData(const Data & data)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         }
getData()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);
Path()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;
onPropertyChanged(Properties * prop)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     }
mutateStagingProperties()181     PathProperties* mutateStagingProperties() { return &mStagingProperties; }
stagingProperties()182     const PathProperties* stagingProperties() { return &mStagingProperties; }
183 
184     // This should only be called from animations on RT
mutateProperties()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         };
FullPathProperties(Node * mNode)221         FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
~FullPathProperties()222         ~FullPathProperties() {
223             SkSafeUnref(fillGradient);
224             SkSafeUnref(strokeGradient);
225         }
syncProperties(const FullPathProperties & prop)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         }
setFillGradient(SkShader * gradient)233         void setFillGradient(SkShader* gradient) {
234             if(UPDATE_SKPROP(fillGradient, gradient)) {
235                 onPropertyChanged();
236             }
237         }
setStrokeGradient(SkShader * gradient)238         void setStrokeGradient(SkShader* gradient) {
239             if(UPDATE_SKPROP(strokeGradient, gradient)) {
240                 onPropertyChanged();
241             }
242         }
getFillGradient()243         SkShader* getFillGradient() const {
244             return fillGradient;
245         }
getStrokeGradient()246         SkShader* getStrokeGradient() const {
247             return strokeGradient;
248         }
getStrokeWidth()249         float getStrokeWidth() const{
250             return mPrimitiveFields.strokeWidth;
251         }
setStrokeWidth(float strokeWidth)252         void setStrokeWidth(float strokeWidth) {
253             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
254         }
getStrokeColor()255         SkColor getStrokeColor() const{
256             return mPrimitiveFields.strokeColor;
257         }
setStrokeColor(SkColor strokeColor)258         void setStrokeColor(SkColor strokeColor) {
259             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
260         }
getStrokeAlpha()261         float getStrokeAlpha() const{
262             return mPrimitiveFields.strokeAlpha;
263         }
setStrokeAlpha(float strokeAlpha)264         void setStrokeAlpha(float strokeAlpha) {
265             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
266         }
getFillColor()267         SkColor getFillColor() const {
268             return mPrimitiveFields.fillColor;
269         }
setFillColor(SkColor fillColor)270         void setFillColor(SkColor fillColor) {
271             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
272         }
getFillAlpha()273         float getFillAlpha() const{
274             return mPrimitiveFields.fillAlpha;
275         }
setFillAlpha(float fillAlpha)276         void setFillAlpha(float fillAlpha) {
277             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
278         }
getTrimPathStart()279         float getTrimPathStart() const{
280             return mPrimitiveFields.trimPathStart;
281         }
setTrimPathStart(float trimPathStart)282         void setTrimPathStart(float trimPathStart) {
283             VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
284         }
getTrimPathEnd()285         float getTrimPathEnd() const{
286             return mPrimitiveFields.trimPathEnd;
287         }
setTrimPathEnd(float trimPathEnd)288         void setTrimPathEnd(float trimPathEnd) {
289             VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
290         }
getTrimPathOffset()291         float getTrimPathOffset() const{
292             return mPrimitiveFields.trimPathOffset;
293         }
setTrimPathOffset(float trimPathOffset)294         void setTrimPathOffset(float trimPathOffset) {
295             VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
296         }
297 
getStrokeMiterLimit()298         float getStrokeMiterLimit() const {
299             return mPrimitiveFields.strokeMiterLimit;
300         }
getStrokeLineCap()301         float getStrokeLineCap() const {
302             return mPrimitiveFields.strokeLineCap;
303         }
getStrokeLineJoin()304         float getStrokeLineJoin() const {
305             return mPrimitiveFields.strokeLineJoin;
306         }
getFillType()307         float getFillType() const {
308             return mPrimitiveFields.fillType;
309         }
310         bool copyProperties(int8_t* outProperties, int length) const;
updateProperties(float strokeWidth,SkColor strokeColor,float strokeAlpha,SkColor fillColor,float fillAlpha,float trimPathStart,float trimPathEnd,float trimPathOffset,float strokeMiterLimit,int strokeLineCap,int strokeLineJoin,int fillType)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
FullPath(const char * path,size_t strLength)357     FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
FullPath()358     FullPath() : Path() {}
359     void dump() override;
mutateStagingProperties()360     FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
stagingProperties()361     const FullPathProperties* stagingProperties() { return &mStagingProperties; }
362 
363     // This should only be called from animations on RT
mutateProperties()364     FullPathProperties* mutateProperties() { return &mProperties; }
365 
366     virtual void syncProperties() override;
onPropertyChanged(Properties * properties)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:
ClipPath(const ClipPath & path)399     ClipPath(const ClipPath& path) : Path(path) {}
ClipPath(const char * path,size_t strLength)400     ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
ClipPath()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:
GroupProperties(Node * mNode)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;
syncProperties(const GroupProperties & prop)422         void syncProperties(const GroupProperties& prop) {
423             mPrimitiveFields = prop.mPrimitiveFields;
424             onPropertyChanged();
425         }
getRotation()426         float getRotation() const {
427             return mPrimitiveFields.rotate;
428         }
setRotation(float rotation)429         void setRotation(float rotation) {
430             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
431         }
getPivotX()432         float getPivotX() const {
433             return mPrimitiveFields.pivotX;
434         }
setPivotX(float pivotX)435         void setPivotX(float pivotX) {
436             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
437         }
getPivotY()438         float getPivotY() const {
439             return mPrimitiveFields.pivotY;
440         }
setPivotY(float pivotY)441         void setPivotY(float pivotY) {
442             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
443         }
getScaleX()444         float getScaleX() const {
445             return mPrimitiveFields.scaleX;
446         }
setScaleX(float scaleX)447         void setScaleX(float scaleX) {
448             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
449         }
getScaleY()450         float getScaleY() const {
451             return mPrimitiveFields.scaleY;
452         }
setScaleY(float scaleY)453         void setScaleY(float scaleY) {
454             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
455         }
getTranslateX()456         float getTranslateX() const {
457             return mPrimitiveFields.translateX;
458         }
setTranslateX(float translateX)459         void setTranslateX(float translateX) {
460             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
461         }
getTranslateY()462         float getTranslateY() const {
463             return mPrimitiveFields.translateY;
464         }
setTranslateY(float translateY)465         void setTranslateY(float translateY) {
466             VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
467         }
updateProperties(float rotate,float pivotX,float pivotY,float scaleX,float scaleY,float translateX,float translateY)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);
Group()498     Group() {}
499     void addChild(Node* child);
setPropertyChangedListener(PropertyChangedListener * listener)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;
mutateStagingProperties()507     GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
stagingProperties()508     const GroupProperties* stagingProperties() { return &mStagingProperties; }
509 
510     // This should only be called from animations on RT
mutateProperties()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 
onPropertyChanged(Properties * properties)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:
Tree(Group * rootNode)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
Tree(const Tree * copy,Group * rootNode)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();
setAllowCaching(bool allowCaching)558     void setAllowCaching(bool allowCaching) {
559         mAllowCaching = allowCaching;
560     }
561     SkPaint* getPaint();
syncProperties()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:
TreeProperties(Tree * tree)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;
~NonAnimatablePropertiesNonAnimatableProperties589             ~NonAnimatableProperties() {
590                 SkSafeUnref(colorFilter);
591             }
592         } mNonAnimatableProperties;
593         bool mNonAnimatablePropertiesDirty = true;
594 
595         float mRootAlpha = 1.0f;
596         bool mAnimatablePropertiesDirty = true;
597 
syncNonAnimatableProperties(const TreeProperties & prop)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 
setViewportSize(float width,float height)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         }
setBounds(const SkRect & bounds)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 
setScaledSize(int width,int height)624         void setScaledSize(int width, int height) {
625             // If the requested size is bigger than what the bitmap was, then
626             // we increase the bitmap size to match. The width and height
627             // are bound by MAX_CACHED_BITMAP_SIZE.
628             if (mNonAnimatableProperties.scaledWidth < width
629                     || mNonAnimatableProperties.scaledHeight < height) {
630                 mNonAnimatableProperties.scaledWidth = std::max(width,
631                         mNonAnimatableProperties.scaledWidth);
632                 mNonAnimatableProperties.scaledHeight = std::max(height,
633                         mNonAnimatableProperties.scaledHeight);
634                 mNonAnimatablePropertiesDirty = true;
635                 mTree->onPropertyChanged(this);
636             }
637         }
setColorFilter(SkColorFilter * filter)638         void setColorFilter(SkColorFilter* filter) {
639             if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
640                 mNonAnimatablePropertiesDirty = true;
641                 mTree->onPropertyChanged(this);
642             }
643         }
getColorFilter()644         SkColorFilter* getColorFilter() const{
645             return mNonAnimatableProperties.colorFilter;
646         }
647 
getViewportWidth()648         float getViewportWidth() const {
649             return mNonAnimatableProperties.viewportWidth;
650         }
getViewportHeight()651         float getViewportHeight() const {
652             return mNonAnimatableProperties.viewportHeight;
653         }
getScaledWidth()654         float getScaledWidth() const {
655             return mNonAnimatableProperties.scaledWidth;
656         }
getScaledHeight()657         float getScaledHeight() const {
658             return mNonAnimatableProperties.scaledHeight;
659         }
syncAnimatableProperties(const TreeProperties & prop)660         void syncAnimatableProperties(const TreeProperties& prop) {
661             mRootAlpha = prop.mRootAlpha;
662         }
setRootAlpha(float rootAlpha)663         bool setRootAlpha(float rootAlpha) {
664             if (rootAlpha != mRootAlpha) {
665                 mAnimatablePropertiesDirty = true;
666                 mRootAlpha = rootAlpha;
667                 mTree->onPropertyChanged(this);
668                 return true;
669             }
670             return false;
671         }
getRootAlpha()672         float getRootAlpha() const { return mRootAlpha;}
getBounds()673         const SkRect& getBounds() const {
674             return mNonAnimatableProperties.bounds;
675         }
676         Tree* mTree;
677     };
678     void onPropertyChanged(TreeProperties* prop);
mutateStagingProperties()679     TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
stagingProperties()680     const TreeProperties* stagingProperties() const { return &mStagingProperties; }
681 
682     // This should only be called from animations on RT
mutateProperties()683     TreeProperties* mutateProperties() { return &mProperties; }
684 
685     // This should always be called from RT.
markDirty()686     void markDirty() { mCache.dirty = true; }
isDirty()687     bool isDirty() const { return mCache.dirty; }
getPropertyChangeWillBeConsumed()688     bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
setPropertyChangeWillBeConsumed(bool willBeConsumed)689     void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
690 
691 private:
692 
693     SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
694     bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
695     bool canReuseBitmap(const SkBitmap&, int width, int height);
696     void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
697     // Cap the bitmap size, such that it won't hurt the performance too much
698     // and it won't crash due to a very large scale.
699     // The drawable will look blurry above this size.
700     const static int MAX_CACHED_BITMAP_SIZE;
701 
702     bool mAllowCaching = true;
703     std::unique_ptr<Group> mRootNode;
704 
705     TreeProperties mProperties = TreeProperties(this);
706     TreeProperties mStagingProperties = TreeProperties(this);
707 
708     SkPaint mPaint;
709     struct Cache {
710         SkBitmap bitmap;
711         bool dirty = true;
712     };
713 
714     Cache mStagingCache;
715     Cache mCache;
716 
717     PropertyChangedListener mPropertyChangedListener
718             = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
719 
720     mutable bool mWillBeConsumed = false;
721 };
722 
723 } // namespace VectorDrawable
724 
725 typedef VectorDrawable::Path::Data PathData;
726 } // namespace uirenderer
727 } // namespace android
728 
729 #endif // ANDROID_HWUI_VPATH_H
730