• 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 (mNonAnimatableProperties.scaledWidth != width
626                     || mNonAnimatableProperties.scaledHeight != height) {
627                 mNonAnimatableProperties.scaledWidth = width;
628                 mNonAnimatableProperties.scaledHeight = height;
629                 mNonAnimatablePropertiesDirty = true;
630                 mTree->onPropertyChanged(this);
631             }
632         }
setColorFilter(SkColorFilter * filter)633         void setColorFilter(SkColorFilter* filter) {
634             if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
635                 mNonAnimatablePropertiesDirty = true;
636                 mTree->onPropertyChanged(this);
637             }
638         }
getColorFilter()639         SkColorFilter* getColorFilter() const{
640             return mNonAnimatableProperties.colorFilter;
641         }
642 
getViewportWidth()643         float getViewportWidth() const {
644             return mNonAnimatableProperties.viewportWidth;
645         }
getViewportHeight()646         float getViewportHeight() const {
647             return mNonAnimatableProperties.viewportHeight;
648         }
getScaledWidth()649         float getScaledWidth() const {
650             return mNonAnimatableProperties.scaledWidth;
651         }
getScaledHeight()652         float getScaledHeight() const {
653             return mNonAnimatableProperties.scaledHeight;
654         }
syncAnimatableProperties(const TreeProperties & prop)655         void syncAnimatableProperties(const TreeProperties& prop) {
656             mRootAlpha = prop.mRootAlpha;
657         }
setRootAlpha(float rootAlpha)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         }
getRootAlpha()667         float getRootAlpha() const { return mRootAlpha;}
getBounds()668         const SkRect& getBounds() const {
669             return mNonAnimatableProperties.bounds;
670         }
671         Tree* mTree;
672     };
673     void onPropertyChanged(TreeProperties* prop);
mutateStagingProperties()674     TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
stagingProperties()675     const TreeProperties* stagingProperties() const { return &mStagingProperties; }
getFunctor()676     PushStagingFunctor* getFunctor() { return &mFunctor;}
677 
678     // This should only be called from animations on RT
mutateProperties()679     TreeProperties* mutateProperties() { return &mProperties; }
680 
681 private:
682     class VectorDrawableFunctor : public PushStagingFunctor {
683     public:
VectorDrawableFunctor(Tree * tree)684         VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
operator()685         virtual void operator ()() {
686             mTree->syncProperties();
687         }
688     private:
689         Tree* mTree;
690     };
691 
692     SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
693     bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
694     bool canReuseBitmap(const SkBitmap&, int width, int height);
695     void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
696     // Cap the bitmap size, such that it won't hurt the performance too much
697     // and it won't crash due to a very large scale.
698     // The drawable will look blurry above this size.
699     const static int MAX_CACHED_BITMAP_SIZE;
700 
701     bool mAllowCaching = true;
702     std::unique_ptr<Group> mRootNode;
703 
704     TreeProperties mProperties = TreeProperties(this);
705     TreeProperties mStagingProperties = TreeProperties(this);
706 
707     VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
708 
709     SkPaint mPaint;
710     struct Cache {
711         SkBitmap bitmap;
712         bool dirty = true;
713     };
714 
715     Cache mStagingCache;
716     Cache mCache;
717 
718     PropertyChangedListener mPropertyChangedListener
719             = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
720 };
721 
722 } // namespace VectorDrawable
723 
724 typedef VectorDrawable::Path::Data PathData;
725 } // namespace uirenderer
726 } // namespace android
727 
728 #endif // ANDROID_HWUI_VPATH_H
729