blob: e9a9c719975a47aa534885d0b62fb4a6c5031f28 [file] [log] [blame]
Doris Liu4bbc2932015-12-01 17:59:40 -08001/*
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
sergeyvdccca442016-03-21 15:38:21 -070020#include "hwui/Canvas.h"
sergeyvfc9999502016-10-17 13:07:38 -070021#include "hwui/Bitmap.h"
Doris Liu1d8e1942016-03-02 15:16:28 -080022#include "DisplayList.h"
Doris Liu766431a2016-02-04 22:17:11 +000023
Doris Liu4bbc2932015-12-01 17:59:40 -080024#include <SkBitmap.h>
25#include <SkColor.h>
Doris Liu1d8e1942016-03-02 15:16:28 -080026#include <SkColorFilter.h>
Doris Liuc2de46f2016-01-21 12:55:54 -080027#include <SkCanvas.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080028#include <SkMatrix.h>
29#include <SkPaint.h>
30#include <SkPath.h>
31#include <SkPathMeasure.h>
32#include <SkRect.h>
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -080033#include <SkShader.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080034
35#include <cutils/compiler.h>
36#include <stddef.h>
37#include <vector>
38#include <string>
39
40namespace android {
41namespace uirenderer {
42
Teng-Hui Zhu85d99522016-04-25 14:23:40 -070043// Debug
44#if DEBUG_VECTOR_DRAWABLE
45 #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
46#else
47 #define VECTOR_DRAWABLE_LOGD(...)
48#endif
49
Doris Liu4bbc2932015-12-01 17:59:40 -080050namespace VectorDrawable {
Doris Liu32d7cda2016-04-08 13:48:47 -070051#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
52#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
53#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
Doris Liu1d8e1942016-03-02 15:16:28 -080054 onPropertyChanged(); retVal;})
Doris Liu32d7cda2016-04-08 13:48:47 -070055#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
Doris Liu4bbc2932015-12-01 17:59:40 -080056
57/* A VectorDrawable is composed of a tree of nodes.
58 * Each node can be a group node, or a path.
59 * A group node can have groups or paths as children, but a path node has
60 * no children.
61 * One example can be:
62 * Root Group
63 * / | \
64 * Group Path Group
65 * / \ |
66 * Path Path Path
67 *
Doris Liu1d8e1942016-03-02 15:16:28 -080068 * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
69 * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
70 * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
71 * Each cache has their own generation id to track whether they are up to date with the latest
72 * change in the tree.
73 *
74 * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
75 * all the properties, and viewport change, etc.) are only modifying the staging properties. The
76 * staging properties will then be marked dirty and will be pushed over to render thread properties
77 * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
78 * staging properties with render thread properties to reflect the latest animation value.
79 *
Doris Liu4bbc2932015-12-01 17:59:40 -080080 */
Doris Liu1d8e1942016-03-02 15:16:28 -080081
82class PropertyChangedListener {
83public:
84 PropertyChangedListener(bool* dirty, bool* stagingDirty)
85 : mDirty(dirty), mStagingDirty(stagingDirty) {}
86 void onPropertyChanged() {
87 *mDirty = true;
88 }
89 void onStagingPropertyChanged() {
90 *mStagingDirty = true;
91 }
92private:
93 bool* mDirty;
94 bool* mStagingDirty;
95};
96
Doris Liu4bbc2932015-12-01 17:59:40 -080097class ANDROID_API Node {
98public:
Doris Liu1d8e1942016-03-02 15:16:28 -080099 class Properties {
100 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700101 explicit Properties(Node* node) : mNode(node) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800102 inline void onPropertyChanged() {
103 mNode->onPropertyChanged(this);
104 }
105 private:
106 Node* mNode;
107 };
Doris Liu4bbc2932015-12-01 17:59:40 -0800108 Node(const Node& node) {
109 mName = node.mName;
110 }
111 Node() {}
Doris Liuc2de46f2016-01-21 12:55:54 -0800112 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
Doris Liu1d8e1942016-03-02 15:16:28 -0800113 float scaleX, float scaleY, bool useStagingData) = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800114 virtual void dump() = 0;
115 void setName(const char* name) {
116 mName = name;
117 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800118 virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
119 mPropertyChangedListener = listener;
120 }
121 virtual void onPropertyChanged(Properties* properties) = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800122 virtual ~Node(){}
Doris Liu1d8e1942016-03-02 15:16:28 -0800123 virtual void syncProperties() = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800124protected:
125 std::string mName;
Doris Liu1d8e1942016-03-02 15:16:28 -0800126 PropertyChangedListener* mPropertyChangedListener = nullptr;
Doris Liu4bbc2932015-12-01 17:59:40 -0800127};
128
129class ANDROID_API Path : public Node {
130public:
131 struct ANDROID_API Data {
132 std::vector<char> verbs;
133 std::vector<size_t> verbSizes;
134 std::vector<float> points;
135 bool operator==(const Data& data) const {
136 return verbs == data.verbs && verbSizes == data.verbSizes
137 && points == data.points;
138 }
139 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800140
141 class PathProperties : public Properties {
142 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700143 explicit PathProperties(Node* node) : Properties(node) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800144 void syncProperties(const PathProperties& prop) {
145 mData = prop.mData;
146 onPropertyChanged();
147 }
148 void setData(const Data& data) {
149 // Updates the path data. Note that we don't generate a new Skia path right away
150 // because there are cases where the animation is changing the path data, but the view
151 // that hosts the VD has gone off screen, in which case we won't even draw. So we
152 // postpone the Skia path generation to the draw time.
153 if (data == mData) {
154 return;
155 }
156 mData = data;
157 onPropertyChanged();
158
159 }
160 const Data& getData() const {
161 return mData;
162 }
163 private:
164 Data mData;
165 };
166
Doris Liu4bbc2932015-12-01 17:59:40 -0800167 Path(const Path& path);
168 Path(const char* path, size_t strLength);
169 Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800170
Doris Liu4bbc2932015-12-01 17:59:40 -0800171 void dump() override;
Doris Liuc2de46f2016-01-21 12:55:54 -0800172 void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
Doris Liu1d8e1942016-03-02 15:16:28 -0800173 float scaleX, float scaleY, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800174 static float getMatrixScale(const SkMatrix& groupStackedMatrix);
Doris Liu1d8e1942016-03-02 15:16:28 -0800175 virtual void syncProperties() override;
176 virtual void onPropertyChanged(Properties* prop) override {
177 if (prop == &mStagingProperties) {
178 mStagingPropertiesDirty = true;
179 if (mPropertyChangedListener) {
180 mPropertyChangedListener->onStagingPropertyChanged();
181 }
182 } else if (prop == &mProperties){
183 mSkPathDirty = true;
184 if (mPropertyChangedListener) {
185 mPropertyChangedListener->onPropertyChanged();
186 }
187 }
188 }
189 PathProperties* mutateStagingProperties() { return &mStagingProperties; }
190 const PathProperties* stagingProperties() { return &mStagingProperties; }
191
192 // This should only be called from animations on RT
193 PathProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800194
195protected:
196 virtual const SkPath& getUpdatedPath();
Doris Liu1d8e1942016-03-02 15:16:28 -0800197 virtual void getStagingPath(SkPath* outPath);
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700198 virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800199 float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
200
201 // Internal data, render thread only.
Doris Liu4bbc2932015-12-01 17:59:40 -0800202 bool mSkPathDirty = true;
Doris Liu1d8e1942016-03-02 15:16:28 -0800203 SkPath mSkPath;
204
205private:
206 PathProperties mProperties = PathProperties(this);
207 PathProperties mStagingProperties = PathProperties(this);
208 bool mStagingPropertiesDirty = true;
Doris Liu4bbc2932015-12-01 17:59:40 -0800209};
210
211class ANDROID_API FullPath: public Path {
212public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800213 class FullPathProperties : public Properties {
214 public:
215 struct PrimitiveFields {
216 float strokeWidth = 0;
217 SkColor strokeColor = SK_ColorTRANSPARENT;
218 float strokeAlpha = 1;
219 SkColor fillColor = SK_ColorTRANSPARENT;
220 float fillAlpha = 1;
221 float trimPathStart = 0;
222 float trimPathEnd = 1;
223 float trimPathOffset = 0;
224 int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
225 int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
226 float strokeMiterLimit = 4;
227 int fillType = 0; /* non-zero or kWinding_FillType in Skia */
228 };
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700229 explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
Doris Liuad21fe22016-04-14 18:13:36 -0700230 ~FullPathProperties() {
231 SkSafeUnref(fillGradient);
232 SkSafeUnref(strokeGradient);
233 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800234 void syncProperties(const FullPathProperties& prop) {
235 mPrimitiveFields = prop.mPrimitiveFields;
236 mTrimDirty = true;
Doris Liuad21fe22016-04-14 18:13:36 -0700237 UPDATE_SKPROP(fillGradient, prop.fillGradient);
238 UPDATE_SKPROP(strokeGradient, prop.strokeGradient);
Doris Liu1d8e1942016-03-02 15:16:28 -0800239 onPropertyChanged();
240 }
241 void setFillGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700242 if(UPDATE_SKPROP(fillGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800243 onPropertyChanged();
244 }
245 }
246 void setStrokeGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700247 if(UPDATE_SKPROP(strokeGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800248 onPropertyChanged();
249 }
250 }
251 SkShader* getFillGradient() const {
252 return fillGradient;
253 }
254 SkShader* getStrokeGradient() const {
255 return strokeGradient;
256 }
257 float getStrokeWidth() const{
258 return mPrimitiveFields.strokeWidth;
259 }
260 void setStrokeWidth(float strokeWidth) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700261 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
Doris Liu1d8e1942016-03-02 15:16:28 -0800262 }
263 SkColor getStrokeColor() const{
264 return mPrimitiveFields.strokeColor;
265 }
266 void setStrokeColor(SkColor strokeColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700267 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800268 }
269 float getStrokeAlpha() const{
270 return mPrimitiveFields.strokeAlpha;
271 }
272 void setStrokeAlpha(float strokeAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700273 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800274 }
275 SkColor getFillColor() const {
276 return mPrimitiveFields.fillColor;
277 }
278 void setFillColor(SkColor fillColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700279 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800280 }
281 float getFillAlpha() const{
282 return mPrimitiveFields.fillAlpha;
283 }
284 void setFillAlpha(float fillAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700285 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800286 }
287 float getTrimPathStart() const{
288 return mPrimitiveFields.trimPathStart;
289 }
290 void setTrimPathStart(float trimPathStart) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700291 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800292 }
293 float getTrimPathEnd() const{
294 return mPrimitiveFields.trimPathEnd;
295 }
296 void setTrimPathEnd(float trimPathEnd) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700297 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800298 }
299 float getTrimPathOffset() const{
300 return mPrimitiveFields.trimPathOffset;
301 }
302 void setTrimPathOffset(float trimPathOffset) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700303 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800304 }
Doris Liu766431a2016-02-04 22:17:11 +0000305
Doris Liu1d8e1942016-03-02 15:16:28 -0800306 float getStrokeMiterLimit() const {
307 return mPrimitiveFields.strokeMiterLimit;
308 }
309 float getStrokeLineCap() const {
310 return mPrimitiveFields.strokeLineCap;
311 }
312 float getStrokeLineJoin() const {
313 return mPrimitiveFields.strokeLineJoin;
314 }
315 float getFillType() const {
316 return mPrimitiveFields.fillType;
317 }
318 bool copyProperties(int8_t* outProperties, int length) const;
319 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
320 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
321 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
322 int fillType) {
323 mPrimitiveFields.strokeWidth = strokeWidth;
324 mPrimitiveFields.strokeColor = strokeColor;
325 mPrimitiveFields.strokeAlpha = strokeAlpha;
326 mPrimitiveFields.fillColor = fillColor;
327 mPrimitiveFields.fillAlpha = fillAlpha;
328 mPrimitiveFields.trimPathStart = trimPathStart;
329 mPrimitiveFields.trimPathEnd = trimPathEnd;
330 mPrimitiveFields.trimPathOffset = trimPathOffset;
331 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
332 mPrimitiveFields.strokeLineCap = strokeLineCap;
333 mPrimitiveFields.strokeLineJoin = strokeLineJoin;
334 mPrimitiveFields.fillType = fillType;
335 mTrimDirty = true;
336 onPropertyChanged();
337 }
338 // Set property values during animation
339 void setColorPropertyValue(int propertyId, int32_t value);
340 void setPropertyValue(int propertyId, float value);
341 bool mTrimDirty;
342 private:
343 enum class Property {
344 strokeWidth = 0,
345 strokeColor,
346 strokeAlpha,
347 fillColor,
348 fillAlpha,
349 trimPathStart,
350 trimPathEnd,
351 trimPathOffset,
352 strokeLineCap,
353 strokeLineJoin,
354 strokeMiterLimit,
355 fillType,
356 count,
357 };
358 PrimitiveFields mPrimitiveFields;
Doris Liuad21fe22016-04-14 18:13:36 -0700359 SkShader* fillGradient = nullptr;
360 SkShader* strokeGradient = nullptr;
Doris Liu1d8e1942016-03-02 15:16:28 -0800361 };
Doris Liu766431a2016-02-04 22:17:11 +0000362
Doris Liu1d8e1942016-03-02 15:16:28 -0800363 // Called from UI thread
Doris Liu4bbc2932015-12-01 17:59:40 -0800364 FullPath(const FullPath& path); // for cloning
365 FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
366 FullPath() : Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800367 void dump() override;
368 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
369 const FullPathProperties* stagingProperties() { return &mStagingProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800370
Doris Liu1d8e1942016-03-02 15:16:28 -0800371 // This should only be called from animations on RT
372 FullPathProperties* mutateProperties() { return &mProperties; }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800373
Doris Liu1d8e1942016-03-02 15:16:28 -0800374 virtual void syncProperties() override;
375 virtual void onPropertyChanged(Properties* properties) override {
376 Path::onPropertyChanged(properties);
377 if (properties == &mStagingProperties) {
378 mStagingPropertiesDirty = true;
379 if (mPropertyChangedListener) {
380 mPropertyChangedListener->onStagingPropertyChanged();
381 }
382 } else if (properties == &mProperties) {
383 if (mPropertyChangedListener) {
384 mPropertyChangedListener->onPropertyChanged();
385 }
386 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800387 }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800388
Doris Liu4bbc2932015-12-01 17:59:40 -0800389protected:
390 const SkPath& getUpdatedPath() override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800391 void getStagingPath(SkPath* outPath) override;
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700392 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800393 float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800394private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800395
396 FullPathProperties mProperties = FullPathProperties(this);
397 FullPathProperties mStagingProperties = FullPathProperties(this);
398 bool mStagingPropertiesDirty = true;
399
400 // Intermediate data for drawing, render thread only
Doris Liu5a11e8d2016-02-04 20:04:10 +0000401 SkPath mTrimmedSkPath;
Doris Liu1d8e1942016-03-02 15:16:28 -0800402
Doris Liu4bbc2932015-12-01 17:59:40 -0800403};
404
405class ANDROID_API ClipPath: public Path {
406public:
407 ClipPath(const ClipPath& path) : Path(path) {}
408 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
409 ClipPath() : Path() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800410
411protected:
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700412 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800413 float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800414};
415
416class ANDROID_API Group: public Node {
417public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800418 class GroupProperties : public Properties {
419 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700420 explicit GroupProperties(Node* mNode) : Properties(mNode) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800421 struct PrimitiveFields {
422 float rotate = 0;
423 float pivotX = 0;
424 float pivotY = 0;
425 float scaleX = 1;
426 float scaleY = 1;
427 float translateX = 0;
428 float translateY = 0;
429 } mPrimitiveFields;
430 void syncProperties(const GroupProperties& prop) {
431 mPrimitiveFields = prop.mPrimitiveFields;
432 onPropertyChanged();
433 }
434 float getRotation() const {
435 return mPrimitiveFields.rotate;
436 }
437 void setRotation(float rotation) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700438 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
Doris Liu1d8e1942016-03-02 15:16:28 -0800439 }
440 float getPivotX() const {
441 return mPrimitiveFields.pivotX;
442 }
443 void setPivotX(float pivotX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700444 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800445 }
446 float getPivotY() const {
447 return mPrimitiveFields.pivotY;
448 }
449 void setPivotY(float pivotY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700450 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800451 }
452 float getScaleX() const {
453 return mPrimitiveFields.scaleX;
454 }
455 void setScaleX(float scaleX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700456 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800457 }
458 float getScaleY() const {
459 return mPrimitiveFields.scaleY;
460 }
461 void setScaleY(float scaleY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700462 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800463 }
464 float getTranslateX() const {
465 return mPrimitiveFields.translateX;
466 }
467 void setTranslateX(float translateX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700468 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800469 }
470 float getTranslateY() const {
471 return mPrimitiveFields.translateY;
472 }
473 void setTranslateY(float translateY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700474 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800475 }
476 void updateProperties(float rotate, float pivotX, float pivotY,
477 float scaleX, float scaleY, float translateX, float translateY) {
478 mPrimitiveFields.rotate = rotate;
479 mPrimitiveFields.pivotX = pivotX;
480 mPrimitiveFields.pivotY = pivotY;
481 mPrimitiveFields.scaleX = scaleX;
482 mPrimitiveFields.scaleY = scaleY;
483 mPrimitiveFields.translateX = translateX;
484 mPrimitiveFields.translateY = translateY;
485 onPropertyChanged();
486 }
487 void setPropertyValue(int propertyId, float value);
488 float getPropertyValue(int propertyId) const;
489 bool copyProperties(float* outProperties, int length) const;
490 static bool isValidProperty(int propertyId);
491 private:
492 enum class Property {
493 rotate = 0,
494 pivotX,
495 pivotY,
496 scaleX,
497 scaleY,
498 translateX,
499 translateY,
500 // Count of the properties, must be at the end.
501 count,
502 };
Doris Liu766431a2016-02-04 22:17:11 +0000503 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800504
Doris Liu4bbc2932015-12-01 17:59:40 -0800505 Group(const Group& group);
506 Group() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800507 void addChild(Node* child);
Doris Liu1d8e1942016-03-02 15:16:28 -0800508 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
509 Node::setPropertyChangedListener(listener);
510 for (auto& child : mChildren) {
511 child->setPropertyChangedListener(listener);
512 }
513 }
514 virtual void syncProperties() override;
515 GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
516 const GroupProperties* stagingProperties() { return &mStagingProperties; }
517
518 // This should only be called from animations on RT
519 GroupProperties* mutateProperties() { return &mProperties; }
520
521 // Methods below could be called from either UI thread or Render Thread.
522 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
523 float scaleX, float scaleY, bool useStagingData) override;
524 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
Doris Liu4bbc2932015-12-01 17:59:40 -0800525 void dump() override;
Doris Liu766431a2016-02-04 22:17:11 +0000526 static bool isValidProperty(int propertyId);
Doris Liu4bbc2932015-12-01 17:59:40 -0800527
Doris Liu1d8e1942016-03-02 15:16:28 -0800528 virtual void onPropertyChanged(Properties* properties) override {
529 if (properties == &mStagingProperties) {
530 mStagingPropertiesDirty = true;
531 if (mPropertyChangedListener) {
532 mPropertyChangedListener->onStagingPropertyChanged();
533 }
534 } else {
535 if (mPropertyChangedListener) {
536 mPropertyChangedListener->onPropertyChanged();
537 }
538 }
539 }
540
Doris Liu4bbc2932015-12-01 17:59:40 -0800541private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800542 GroupProperties mProperties = GroupProperties(this);
543 GroupProperties mStagingProperties = GroupProperties(this);
544 bool mStagingPropertiesDirty = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800545 std::vector< std::unique_ptr<Node> > mChildren;
Doris Liu4bbc2932015-12-01 17:59:40 -0800546};
547
Doris Liu766431a2016-02-04 22:17:11 +0000548class ANDROID_API Tree : public VirtualLightRefBase {
Doris Liu4bbc2932015-12-01 17:59:40 -0800549public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700550 explicit Tree(Group* rootNode) : mRootNode(rootNode) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800551 mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
552 }
Doris Liu335d7d12016-05-26 15:19:15 -0700553
554 // Copy properties from the tree and use the give node as the root node
555 Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
556 mStagingProperties.syncAnimatableProperties(*copy->stagingProperties());
557 mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties());
558 }
Doris Liuf8d131c2016-04-29 18:41:29 -0700559 // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
560 // canvas. Returns the number of pixels needed for the bitmap cache.
561 int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
Doris Liu4bbc2932015-12-01 17:59:40 -0800562 const SkRect& bounds, bool needsMirroring, bool canReuseCache);
Doris Liu1d8e1942016-03-02 15:16:28 -0800563 void drawStaging(Canvas* canvas);
Doris Liu4bbc2932015-12-01 17:59:40 -0800564
sergeyvfc9999502016-10-17 13:07:38 -0700565 Bitmap& getBitmapUpdateIfDirty();
Doris Liu4bbc2932015-12-01 17:59:40 -0800566 void setAllowCaching(bool allowCaching) {
567 mAllowCaching = allowCaching;
568 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800569 SkPaint* getPaint();
570 void syncProperties() {
571 if (mStagingProperties.mNonAnimatablePropertiesDirty) {
572 mProperties.syncNonAnimatableProperties(mStagingProperties);
573 mStagingProperties.mNonAnimatablePropertiesDirty = false;
574 }
575
576 if (mStagingProperties.mAnimatablePropertiesDirty) {
577 mProperties.syncAnimatableProperties(mStagingProperties);
578 } else {
579 mStagingProperties.syncAnimatableProperties(mProperties);
580 }
581 mStagingProperties.mAnimatablePropertiesDirty = false;
582 mRootNode->syncProperties();
Doris Liu4bbc2932015-12-01 17:59:40 -0800583 }
584
Doris Liu1d8e1942016-03-02 15:16:28 -0800585 class TreeProperties {
586 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700587 explicit TreeProperties(Tree* tree) : mTree(tree) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800588 // Properties that can only be modified by UI thread, therefore sync should
589 // only go from UI to RT
590 struct NonAnimatableProperties {
591 float viewportWidth = 0;
592 float viewportHeight = 0;
593 SkRect bounds;
594 int scaledWidth = 0;
595 int scaledHeight = 0;
596 SkColorFilter* colorFilter = nullptr;
597 ~NonAnimatableProperties() {
598 SkSafeUnref(colorFilter);
599 }
600 } mNonAnimatableProperties;
601 bool mNonAnimatablePropertiesDirty = true;
602
603 float mRootAlpha = 1.0f;
604 bool mAnimatablePropertiesDirty = true;
605
606 void syncNonAnimatableProperties(const TreeProperties& prop) {
607 // Copy over the data that can only be changed in UI thread
608 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
609 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
610 prop.mNonAnimatableProperties.colorFilter);
611 }
612 mNonAnimatableProperties = prop.mNonAnimatableProperties;
613 }
614
615 void setViewportSize(float width, float height) {
616 if (mNonAnimatableProperties.viewportWidth != width
617 || mNonAnimatableProperties.viewportHeight != height) {
618 mNonAnimatablePropertiesDirty = true;
619 mNonAnimatableProperties.viewportWidth = width;
620 mNonAnimatableProperties.viewportHeight = height;
621 mTree->onPropertyChanged(this);
622 }
623 }
624 void setBounds(const SkRect& bounds) {
625 if (mNonAnimatableProperties.bounds != bounds) {
626 mNonAnimatableProperties.bounds = bounds;
627 mNonAnimatablePropertiesDirty = true;
628 mTree->onPropertyChanged(this);
629 }
630 }
631
632 void setScaledSize(int width, int height) {
633 if (mNonAnimatableProperties.scaledWidth != width
634 || mNonAnimatableProperties.scaledHeight != height) {
635 mNonAnimatableProperties.scaledWidth = width;
636 mNonAnimatableProperties.scaledHeight = height;
637 mNonAnimatablePropertiesDirty = true;
638 mTree->onPropertyChanged(this);
639 }
640 }
641 void setColorFilter(SkColorFilter* filter) {
642 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
643 mNonAnimatablePropertiesDirty = true;
644 mTree->onPropertyChanged(this);
645 }
646 }
647 SkColorFilter* getColorFilter() const{
648 return mNonAnimatableProperties.colorFilter;
649 }
650
651 float getViewportWidth() const {
652 return mNonAnimatableProperties.viewportWidth;
653 }
654 float getViewportHeight() const {
655 return mNonAnimatableProperties.viewportHeight;
656 }
657 float getScaledWidth() const {
658 return mNonAnimatableProperties.scaledWidth;
659 }
660 float getScaledHeight() const {
661 return mNonAnimatableProperties.scaledHeight;
662 }
663 void syncAnimatableProperties(const TreeProperties& prop) {
664 mRootAlpha = prop.mRootAlpha;
665 }
666 bool setRootAlpha(float rootAlpha) {
667 if (rootAlpha != mRootAlpha) {
668 mAnimatablePropertiesDirty = true;
669 mRootAlpha = rootAlpha;
670 mTree->onPropertyChanged(this);
671 return true;
672 }
673 return false;
674 }
675 float getRootAlpha() const { return mRootAlpha;}
676 const SkRect& getBounds() const {
677 return mNonAnimatableProperties.bounds;
678 }
679 Tree* mTree;
680 };
681 void onPropertyChanged(TreeProperties* prop);
682 TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
Doris Liu335d7d12016-05-26 15:19:15 -0700683 const TreeProperties* stagingProperties() const { return &mStagingProperties; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800684
685 // This should only be called from animations on RT
686 TreeProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800687
Doris Liu67ce99b2016-05-17 16:50:31 -0700688 // This should always be called from RT.
Doris Liu7c7052d2016-07-25 17:19:24 -0700689 void markDirty() { mCache.dirty = true; }
Doris Liu67ce99b2016-05-17 16:50:31 -0700690 bool isDirty() const { return mCache.dirty; }
691 bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
692 void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
693
Doris Liu4bbc2932015-12-01 17:59:40 -0800694private:
sergeyvfc9999502016-10-17 13:07:38 -0700695 struct Cache {
696 sk_sp<Bitmap> bitmap;
697 bool dirty = true;
698 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800699
700 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
sergeyvfc9999502016-10-17 13:07:38 -0700701 bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
702 bool canReuseBitmap(Bitmap*, int width, int height);
703 void updateBitmapCache(Bitmap& outCache, bool useStagingData);
Doris Liu4bbc2932015-12-01 17:59:40 -0800704 // Cap the bitmap size, such that it won't hurt the performance too much
705 // and it won't crash due to a very large scale.
706 // The drawable will look blurry above this size.
707 const static int MAX_CACHED_BITMAP_SIZE;
708
Doris Liu4bbc2932015-12-01 17:59:40 -0800709 bool mAllowCaching = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800710 std::unique_ptr<Group> mRootNode;
Doris Liu4bbc2932015-12-01 17:59:40 -0800711
Doris Liu1d8e1942016-03-02 15:16:28 -0800712 TreeProperties mProperties = TreeProperties(this);
713 TreeProperties mStagingProperties = TreeProperties(this);
714
Doris Liu1d8e1942016-03-02 15:16:28 -0800715 SkPaint mPaint;
Doris Liu1d8e1942016-03-02 15:16:28 -0800716
717 Cache mStagingCache;
718 Cache mCache;
719
720 PropertyChangedListener mPropertyChangedListener
721 = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
Doris Liu67ce99b2016-05-17 16:50:31 -0700722
723 mutable bool mWillBeConsumed = false;
Doris Liu4bbc2932015-12-01 17:59:40 -0800724};
725
726} // namespace VectorDrawable
727
728typedef VectorDrawable::Path::Data PathData;
729} // namespace uirenderer
730} // namespace android
731
732#endif // ANDROID_HWUI_VPATH_H