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