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