blob: 98738c852af739aa19447e68648e4b6fbdd75e8b [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"
Doris Liu1d8e1942016-03-02 15:16:28 -080021#include "DisplayList.h"
Doris Liu766431a2016-02-04 22:17:11 +000022
Doris Liu4bbc2932015-12-01 17:59:40 -080023#include <SkBitmap.h>
24#include <SkColor.h>
Doris Liu1d8e1942016-03-02 15:16:28 -080025#include <SkColorFilter.h>
Doris Liuc2de46f2016-01-21 12:55:54 -080026#include <SkCanvas.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080027#include <SkMatrix.h>
28#include <SkPaint.h>
29#include <SkPath.h>
30#include <SkPathMeasure.h>
31#include <SkRect.h>
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -080032#include <SkShader.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080033
34#include <cutils/compiler.h>
35#include <stddef.h>
36#include <vector>
37#include <string>
38
39namespace android {
40namespace uirenderer {
41
Teng-Hui Zhu85d99522016-04-25 14:23:40 -070042// Debug
43#if DEBUG_VECTOR_DRAWABLE
44 #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
45#else
46 #define VECTOR_DRAWABLE_LOGD(...)
47#endif
48
Doris Liu4bbc2932015-12-01 17:59:40 -080049namespace VectorDrawable {
Doris Liu32d7cda2016-04-08 13:48:47 -070050#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
51#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
52#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
Doris Liu1d8e1942016-03-02 15:16:28 -080053 onPropertyChanged(); retVal;})
Doris Liu32d7cda2016-04-08 13:48:47 -070054#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
Doris Liu4bbc2932015-12-01 17:59:40 -080055
56/* A VectorDrawable is composed of a tree of nodes.
57 * Each node can be a group node, or a path.
58 * A group node can have groups or paths as children, but a path node has
59 * no children.
60 * One example can be:
61 * Root Group
62 * / | \
63 * Group Path Group
64 * / \ |
65 * Path Path Path
66 *
Doris Liu1d8e1942016-03-02 15:16:28 -080067 * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
68 * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
69 * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
70 * Each cache has their own generation id to track whether they are up to date with the latest
71 * change in the tree.
72 *
73 * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
74 * all the properties, and viewport change, etc.) are only modifying the staging properties. The
75 * staging properties will then be marked dirty and will be pushed over to render thread properties
76 * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
77 * staging properties with render thread properties to reflect the latest animation value.
78 *
Doris Liu4bbc2932015-12-01 17:59:40 -080079 */
Doris Liu1d8e1942016-03-02 15:16:28 -080080
81class PropertyChangedListener {
82public:
83 PropertyChangedListener(bool* dirty, bool* stagingDirty)
84 : mDirty(dirty), mStagingDirty(stagingDirty) {}
85 void onPropertyChanged() {
86 *mDirty = true;
87 }
88 void onStagingPropertyChanged() {
89 *mStagingDirty = true;
90 }
91private:
92 bool* mDirty;
93 bool* mStagingDirty;
94};
95
Doris Liu4bbc2932015-12-01 17:59:40 -080096class ANDROID_API Node {
97public:
Doris Liu1d8e1942016-03-02 15:16:28 -080098 class Properties {
99 public:
100 Properties(Node* node) : mNode(node) {}
101 inline void onPropertyChanged() {
102 mNode->onPropertyChanged(this);
103 }
104 private:
105 Node* mNode;
106 };
Doris Liu4bbc2932015-12-01 17:59:40 -0800107 Node(const Node& node) {
108 mName = node.mName;
109 }
110 Node() {}
Doris Liuc2de46f2016-01-21 12:55:54 -0800111 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
Doris Liu1d8e1942016-03-02 15:16:28 -0800112 float scaleX, float scaleY, bool useStagingData) = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800113 virtual void dump() = 0;
114 void setName(const char* name) {
115 mName = name;
116 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800117 virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
118 mPropertyChangedListener = listener;
119 }
120 virtual void onPropertyChanged(Properties* properties) = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800121 virtual ~Node(){}
Doris Liu1d8e1942016-03-02 15:16:28 -0800122 virtual void syncProperties() = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800123protected:
124 std::string mName;
Doris Liu1d8e1942016-03-02 15:16:28 -0800125 PropertyChangedListener* mPropertyChangedListener = nullptr;
Doris Liu4bbc2932015-12-01 17:59:40 -0800126};
127
128class ANDROID_API Path : public Node {
129public:
130 struct ANDROID_API Data {
131 std::vector<char> verbs;
132 std::vector<size_t> verbSizes;
133 std::vector<float> points;
134 bool operator==(const Data& data) const {
135 return verbs == data.verbs && verbSizes == data.verbSizes
136 && points == data.points;
137 }
138 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800139
140 class PathProperties : public Properties {
141 public:
142 PathProperties(Node* node) : Properties(node) {}
143 void syncProperties(const PathProperties& prop) {
144 mData = prop.mData;
145 onPropertyChanged();
146 }
147 void setData(const Data& data) {
148 // Updates the path data. Note that we don't generate a new Skia path right away
149 // because there are cases where the animation is changing the path data, but the view
150 // that hosts the VD has gone off screen, in which case we won't even draw. So we
151 // postpone the Skia path generation to the draw time.
152 if (data == mData) {
153 return;
154 }
155 mData = data;
156 onPropertyChanged();
157
158 }
159 const Data& getData() const {
160 return mData;
161 }
162 private:
163 Data mData;
164 };
165
Doris Liu4bbc2932015-12-01 17:59:40 -0800166 Path(const Path& path);
167 Path(const char* path, size_t strLength);
168 Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800169
Doris Liu4bbc2932015-12-01 17:59:40 -0800170 void dump() override;
Doris Liuc2de46f2016-01-21 12:55:54 -0800171 void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
Doris Liu1d8e1942016-03-02 15:16:28 -0800172 float scaleX, float scaleY, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800173 static float getMatrixScale(const SkMatrix& groupStackedMatrix);
Doris Liu1d8e1942016-03-02 15:16:28 -0800174 virtual void syncProperties() override;
175 virtual void onPropertyChanged(Properties* prop) override {
176 if (prop == &mStagingProperties) {
177 mStagingPropertiesDirty = true;
178 if (mPropertyChangedListener) {
179 mPropertyChangedListener->onStagingPropertyChanged();
180 }
181 } else if (prop == &mProperties){
182 mSkPathDirty = true;
183 if (mPropertyChangedListener) {
184 mPropertyChangedListener->onPropertyChanged();
185 }
186 }
187 }
188 PathProperties* mutateStagingProperties() { return &mStagingProperties; }
189 const PathProperties* stagingProperties() { return &mStagingProperties; }
190
191 // This should only be called from animations on RT
192 PathProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800193
194protected:
195 virtual const SkPath& getUpdatedPath();
Doris Liu1d8e1942016-03-02 15:16:28 -0800196 virtual void getStagingPath(SkPath* outPath);
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700197 virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800198 float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
199
200 // Internal data, render thread only.
Doris Liu4bbc2932015-12-01 17:59:40 -0800201 bool mSkPathDirty = true;
Doris Liu1d8e1942016-03-02 15:16:28 -0800202 SkPath mSkPath;
203
204private:
205 PathProperties mProperties = PathProperties(this);
206 PathProperties mStagingProperties = PathProperties(this);
207 bool mStagingPropertiesDirty = true;
Doris Liu4bbc2932015-12-01 17:59:40 -0800208};
209
210class ANDROID_API FullPath: public Path {
211public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800212 class FullPathProperties : public Properties {
213 public:
214 struct PrimitiveFields {
215 float strokeWidth = 0;
216 SkColor strokeColor = SK_ColorTRANSPARENT;
217 float strokeAlpha = 1;
218 SkColor fillColor = SK_ColorTRANSPARENT;
219 float fillAlpha = 1;
220 float trimPathStart = 0;
221 float trimPathEnd = 1;
222 float trimPathOffset = 0;
223 int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
224 int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
225 float strokeMiterLimit = 4;
226 int fillType = 0; /* non-zero or kWinding_FillType in Skia */
227 };
228 FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
Doris Liuad21fe22016-04-14 18:13:36 -0700229 ~FullPathProperties() {
230 SkSafeUnref(fillGradient);
231 SkSafeUnref(strokeGradient);
232 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800233 void syncProperties(const FullPathProperties& prop) {
234 mPrimitiveFields = prop.mPrimitiveFields;
235 mTrimDirty = true;
Doris Liuad21fe22016-04-14 18:13:36 -0700236 UPDATE_SKPROP(fillGradient, prop.fillGradient);
237 UPDATE_SKPROP(strokeGradient, prop.strokeGradient);
Doris Liu1d8e1942016-03-02 15:16:28 -0800238 onPropertyChanged();
239 }
240 void setFillGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700241 if(UPDATE_SKPROP(fillGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800242 onPropertyChanged();
243 }
244 }
245 void setStrokeGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700246 if(UPDATE_SKPROP(strokeGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800247 onPropertyChanged();
248 }
249 }
250 SkShader* getFillGradient() const {
251 return fillGradient;
252 }
253 SkShader* getStrokeGradient() const {
254 return strokeGradient;
255 }
256 float getStrokeWidth() const{
257 return mPrimitiveFields.strokeWidth;
258 }
259 void setStrokeWidth(float strokeWidth) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700260 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
Doris Liu1d8e1942016-03-02 15:16:28 -0800261 }
262 SkColor getStrokeColor() const{
263 return mPrimitiveFields.strokeColor;
264 }
265 void setStrokeColor(SkColor strokeColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700266 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800267 }
268 float getStrokeAlpha() const{
269 return mPrimitiveFields.strokeAlpha;
270 }
271 void setStrokeAlpha(float strokeAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700272 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800273 }
274 SkColor getFillColor() const {
275 return mPrimitiveFields.fillColor;
276 }
277 void setFillColor(SkColor fillColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700278 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800279 }
280 float getFillAlpha() const{
281 return mPrimitiveFields.fillAlpha;
282 }
283 void setFillAlpha(float fillAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700284 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800285 }
286 float getTrimPathStart() const{
287 return mPrimitiveFields.trimPathStart;
288 }
289 void setTrimPathStart(float trimPathStart) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700290 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800291 }
292 float getTrimPathEnd() const{
293 return mPrimitiveFields.trimPathEnd;
294 }
295 void setTrimPathEnd(float trimPathEnd) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700296 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800297 }
298 float getTrimPathOffset() const{
299 return mPrimitiveFields.trimPathOffset;
300 }
301 void setTrimPathOffset(float trimPathOffset) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700302 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800303 }
Doris Liu766431a2016-02-04 22:17:11 +0000304
Doris Liu1d8e1942016-03-02 15:16:28 -0800305 float getStrokeMiterLimit() const {
306 return mPrimitiveFields.strokeMiterLimit;
307 }
308 float getStrokeLineCap() const {
309 return mPrimitiveFields.strokeLineCap;
310 }
311 float getStrokeLineJoin() const {
312 return mPrimitiveFields.strokeLineJoin;
313 }
314 float getFillType() const {
315 return mPrimitiveFields.fillType;
316 }
317 bool copyProperties(int8_t* outProperties, int length) const;
318 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
319 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
320 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
321 int fillType) {
322 mPrimitiveFields.strokeWidth = strokeWidth;
323 mPrimitiveFields.strokeColor = strokeColor;
324 mPrimitiveFields.strokeAlpha = strokeAlpha;
325 mPrimitiveFields.fillColor = fillColor;
326 mPrimitiveFields.fillAlpha = fillAlpha;
327 mPrimitiveFields.trimPathStart = trimPathStart;
328 mPrimitiveFields.trimPathEnd = trimPathEnd;
329 mPrimitiveFields.trimPathOffset = trimPathOffset;
330 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
331 mPrimitiveFields.strokeLineCap = strokeLineCap;
332 mPrimitiveFields.strokeLineJoin = strokeLineJoin;
333 mPrimitiveFields.fillType = fillType;
334 mTrimDirty = true;
335 onPropertyChanged();
336 }
337 // Set property values during animation
338 void setColorPropertyValue(int propertyId, int32_t value);
339 void setPropertyValue(int propertyId, float value);
340 bool mTrimDirty;
341 private:
342 enum class Property {
343 strokeWidth = 0,
344 strokeColor,
345 strokeAlpha,
346 fillColor,
347 fillAlpha,
348 trimPathStart,
349 trimPathEnd,
350 trimPathOffset,
351 strokeLineCap,
352 strokeLineJoin,
353 strokeMiterLimit,
354 fillType,
355 count,
356 };
357 PrimitiveFields mPrimitiveFields;
Doris Liuad21fe22016-04-14 18:13:36 -0700358 SkShader* fillGradient = nullptr;
359 SkShader* strokeGradient = nullptr;
Doris Liu1d8e1942016-03-02 15:16:28 -0800360 };
Doris Liu766431a2016-02-04 22:17:11 +0000361
Doris Liu1d8e1942016-03-02 15:16:28 -0800362 // Called from UI thread
Doris Liu4bbc2932015-12-01 17:59:40 -0800363 FullPath(const FullPath& path); // for cloning
364 FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
365 FullPath() : Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800366 void dump() override;
367 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
368 const FullPathProperties* stagingProperties() { return &mStagingProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800369
Doris Liu1d8e1942016-03-02 15:16:28 -0800370 // This should only be called from animations on RT
371 FullPathProperties* mutateProperties() { return &mProperties; }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800372
Doris Liu1d8e1942016-03-02 15:16:28 -0800373 virtual void syncProperties() override;
374 virtual void onPropertyChanged(Properties* properties) override {
375 Path::onPropertyChanged(properties);
376 if (properties == &mStagingProperties) {
377 mStagingPropertiesDirty = true;
378 if (mPropertyChangedListener) {
379 mPropertyChangedListener->onStagingPropertyChanged();
380 }
381 } else if (properties == &mProperties) {
382 if (mPropertyChangedListener) {
383 mPropertyChangedListener->onPropertyChanged();
384 }
385 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800386 }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800387
Doris Liu4bbc2932015-12-01 17:59:40 -0800388protected:
389 const SkPath& getUpdatedPath() override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800390 void getStagingPath(SkPath* outPath) override;
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700391 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800392 float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800393private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800394
395 FullPathProperties mProperties = FullPathProperties(this);
396 FullPathProperties mStagingProperties = FullPathProperties(this);
397 bool mStagingPropertiesDirty = true;
398
399 // Intermediate data for drawing, render thread only
Doris Liu5a11e8d2016-02-04 20:04:10 +0000400 SkPath mTrimmedSkPath;
Doris Liu1d8e1942016-03-02 15:16:28 -0800401
Doris Liu4bbc2932015-12-01 17:59:40 -0800402};
403
404class ANDROID_API ClipPath: public Path {
405public:
406 ClipPath(const ClipPath& path) : Path(path) {}
407 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
408 ClipPath() : Path() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800409
410protected:
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700411 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800412 float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800413};
414
415class ANDROID_API Group: public Node {
416public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800417 class GroupProperties : public Properties {
418 public:
419 GroupProperties(Node* mNode) : Properties(mNode) {}
420 struct PrimitiveFields {
421 float rotate = 0;
422 float pivotX = 0;
423 float pivotY = 0;
424 float scaleX = 1;
425 float scaleY = 1;
426 float translateX = 0;
427 float translateY = 0;
428 } mPrimitiveFields;
429 void syncProperties(const GroupProperties& prop) {
430 mPrimitiveFields = prop.mPrimitiveFields;
431 onPropertyChanged();
432 }
433 float getRotation() const {
434 return mPrimitiveFields.rotate;
435 }
436 void setRotation(float rotation) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700437 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
Doris Liu1d8e1942016-03-02 15:16:28 -0800438 }
439 float getPivotX() const {
440 return mPrimitiveFields.pivotX;
441 }
442 void setPivotX(float pivotX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700443 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800444 }
445 float getPivotY() const {
446 return mPrimitiveFields.pivotY;
447 }
448 void setPivotY(float pivotY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700449 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800450 }
451 float getScaleX() const {
452 return mPrimitiveFields.scaleX;
453 }
454 void setScaleX(float scaleX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700455 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800456 }
457 float getScaleY() const {
458 return mPrimitiveFields.scaleY;
459 }
460 void setScaleY(float scaleY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700461 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800462 }
463 float getTranslateX() const {
464 return mPrimitiveFields.translateX;
465 }
466 void setTranslateX(float translateX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700467 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800468 }
469 float getTranslateY() const {
470 return mPrimitiveFields.translateY;
471 }
472 void setTranslateY(float translateY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700473 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800474 }
475 void updateProperties(float rotate, float pivotX, float pivotY,
476 float scaleX, float scaleY, float translateX, float translateY) {
477 mPrimitiveFields.rotate = rotate;
478 mPrimitiveFields.pivotX = pivotX;
479 mPrimitiveFields.pivotY = pivotY;
480 mPrimitiveFields.scaleX = scaleX;
481 mPrimitiveFields.scaleY = scaleY;
482 mPrimitiveFields.translateX = translateX;
483 mPrimitiveFields.translateY = translateY;
484 onPropertyChanged();
485 }
486 void setPropertyValue(int propertyId, float value);
487 float getPropertyValue(int propertyId) const;
488 bool copyProperties(float* outProperties, int length) const;
489 static bool isValidProperty(int propertyId);
490 private:
491 enum class Property {
492 rotate = 0,
493 pivotX,
494 pivotY,
495 scaleX,
496 scaleY,
497 translateX,
498 translateY,
499 // Count of the properties, must be at the end.
500 count,
501 };
Doris Liu766431a2016-02-04 22:17:11 +0000502 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800503
Doris Liu4bbc2932015-12-01 17:59:40 -0800504 Group(const Group& group);
505 Group() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800506 void addChild(Node* child);
Doris Liu1d8e1942016-03-02 15:16:28 -0800507 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
508 Node::setPropertyChangedListener(listener);
509 for (auto& child : mChildren) {
510 child->setPropertyChangedListener(listener);
511 }
512 }
513 virtual void syncProperties() override;
514 GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
515 const GroupProperties* stagingProperties() { return &mStagingProperties; }
516
517 // This should only be called from animations on RT
518 GroupProperties* mutateProperties() { return &mProperties; }
519
520 // Methods below could be called from either UI thread or Render Thread.
521 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
522 float scaleX, float scaleY, bool useStagingData) override;
523 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
Doris Liu4bbc2932015-12-01 17:59:40 -0800524 void dump() override;
Doris Liu766431a2016-02-04 22:17:11 +0000525 static bool isValidProperty(int propertyId);
Doris Liu4bbc2932015-12-01 17:59:40 -0800526
Doris Liu1d8e1942016-03-02 15:16:28 -0800527 virtual void onPropertyChanged(Properties* properties) override {
528 if (properties == &mStagingProperties) {
529 mStagingPropertiesDirty = true;
530 if (mPropertyChangedListener) {
531 mPropertyChangedListener->onStagingPropertyChanged();
532 }
533 } else {
534 if (mPropertyChangedListener) {
535 mPropertyChangedListener->onPropertyChanged();
536 }
537 }
538 }
539
Doris Liu4bbc2932015-12-01 17:59:40 -0800540private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800541 GroupProperties mProperties = GroupProperties(this);
542 GroupProperties mStagingProperties = GroupProperties(this);
543 bool mStagingPropertiesDirty = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800544 std::vector< std::unique_ptr<Node> > mChildren;
Doris Liu4bbc2932015-12-01 17:59:40 -0800545};
546
Doris Liu766431a2016-02-04 22:17:11 +0000547class ANDROID_API Tree : public VirtualLightRefBase {
Doris Liu4bbc2932015-12-01 17:59:40 -0800548public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800549 Tree(Group* rootNode) : mRootNode(rootNode) {
550 mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
551 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800552 void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
553 const SkRect& bounds, bool needsMirroring, bool canReuseCache);
Doris Liu1d8e1942016-03-02 15:16:28 -0800554 void drawStaging(Canvas* canvas);
Doris Liu4bbc2932015-12-01 17:59:40 -0800555
Doris Liu766431a2016-02-04 22:17:11 +0000556 const SkBitmap& getBitmapUpdateIfDirty();
Doris Liu4bbc2932015-12-01 17:59:40 -0800557 void setAllowCaching(bool allowCaching) {
558 mAllowCaching = allowCaching;
559 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800560 SkPaint* getPaint();
561 void syncProperties() {
562 if (mStagingProperties.mNonAnimatablePropertiesDirty) {
563 mProperties.syncNonAnimatableProperties(mStagingProperties);
564 mStagingProperties.mNonAnimatablePropertiesDirty = false;
565 }
566
567 if (mStagingProperties.mAnimatablePropertiesDirty) {
568 mProperties.syncAnimatableProperties(mStagingProperties);
569 } else {
570 mStagingProperties.syncAnimatableProperties(mProperties);
571 }
572 mStagingProperties.mAnimatablePropertiesDirty = false;
573 mRootNode->syncProperties();
Doris Liu4bbc2932015-12-01 17:59:40 -0800574 }
575
Doris Liu1d8e1942016-03-02 15:16:28 -0800576 class TreeProperties {
577 public:
578 TreeProperties(Tree* tree) : mTree(tree) {}
579 // Properties that can only be modified by UI thread, therefore sync should
580 // only go from UI to RT
581 struct NonAnimatableProperties {
582 float viewportWidth = 0;
583 float viewportHeight = 0;
584 SkRect bounds;
585 int scaledWidth = 0;
586 int scaledHeight = 0;
587 SkColorFilter* colorFilter = nullptr;
588 ~NonAnimatableProperties() {
589 SkSafeUnref(colorFilter);
590 }
591 } mNonAnimatableProperties;
592 bool mNonAnimatablePropertiesDirty = true;
593
594 float mRootAlpha = 1.0f;
595 bool mAnimatablePropertiesDirty = true;
596
597 void syncNonAnimatableProperties(const TreeProperties& prop) {
598 // Copy over the data that can only be changed in UI thread
599 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
600 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
601 prop.mNonAnimatableProperties.colorFilter);
602 }
603 mNonAnimatableProperties = prop.mNonAnimatableProperties;
604 }
605
606 void setViewportSize(float width, float height) {
607 if (mNonAnimatableProperties.viewportWidth != width
608 || mNonAnimatableProperties.viewportHeight != height) {
609 mNonAnimatablePropertiesDirty = true;
610 mNonAnimatableProperties.viewportWidth = width;
611 mNonAnimatableProperties.viewportHeight = height;
612 mTree->onPropertyChanged(this);
613 }
614 }
615 void setBounds(const SkRect& bounds) {
616 if (mNonAnimatableProperties.bounds != bounds) {
617 mNonAnimatableProperties.bounds = bounds;
618 mNonAnimatablePropertiesDirty = true;
619 mTree->onPropertyChanged(this);
620 }
621 }
622
623 void setScaledSize(int width, int height) {
624 if (mNonAnimatableProperties.scaledWidth != width
625 || mNonAnimatableProperties.scaledHeight != height) {
626 mNonAnimatableProperties.scaledWidth = width;
627 mNonAnimatableProperties.scaledHeight = height;
628 mNonAnimatablePropertiesDirty = true;
629 mTree->onPropertyChanged(this);
630 }
631 }
632 void setColorFilter(SkColorFilter* filter) {
633 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
634 mNonAnimatablePropertiesDirty = true;
635 mTree->onPropertyChanged(this);
636 }
637 }
638 SkColorFilter* getColorFilter() const{
639 return mNonAnimatableProperties.colorFilter;
640 }
641
642 float getViewportWidth() const {
643 return mNonAnimatableProperties.viewportWidth;
644 }
645 float getViewportHeight() const {
646 return mNonAnimatableProperties.viewportHeight;
647 }
648 float getScaledWidth() const {
649 return mNonAnimatableProperties.scaledWidth;
650 }
651 float getScaledHeight() const {
652 return mNonAnimatableProperties.scaledHeight;
653 }
654 void syncAnimatableProperties(const TreeProperties& prop) {
655 mRootAlpha = prop.mRootAlpha;
656 }
657 bool setRootAlpha(float rootAlpha) {
658 if (rootAlpha != mRootAlpha) {
659 mAnimatablePropertiesDirty = true;
660 mRootAlpha = rootAlpha;
661 mTree->onPropertyChanged(this);
662 return true;
663 }
664 return false;
665 }
666 float getRootAlpha() const { return mRootAlpha;}
667 const SkRect& getBounds() const {
668 return mNonAnimatableProperties.bounds;
669 }
670 Tree* mTree;
671 };
672 void onPropertyChanged(TreeProperties* prop);
673 TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
674 const TreeProperties* stagingProperties() { return &mStagingProperties; }
675 PushStagingFunctor* getFunctor() { return &mFunctor;}
676
677 // This should only be called from animations on RT
678 TreeProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800679
680private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800681 class VectorDrawableFunctor : public PushStagingFunctor {
682 public:
683 VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
684 virtual void operator ()() {
685 mTree->syncProperties();
686 }
687 private:
688 Tree* mTree;
689 };
690
691 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
692 bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
693 bool canReuseBitmap(const SkBitmap&, int width, int height);
694 void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
Doris Liu4bbc2932015-12-01 17:59:40 -0800695 // Cap the bitmap size, such that it won't hurt the performance too much
696 // and it won't crash due to a very large scale.
697 // The drawable will look blurry above this size.
698 const static int MAX_CACHED_BITMAP_SIZE;
699
Doris Liu4bbc2932015-12-01 17:59:40 -0800700 bool mAllowCaching = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800701 std::unique_ptr<Group> mRootNode;
Doris Liu4bbc2932015-12-01 17:59:40 -0800702
Doris Liu1d8e1942016-03-02 15:16:28 -0800703 TreeProperties mProperties = TreeProperties(this);
704 TreeProperties mStagingProperties = TreeProperties(this);
705
706 VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
707
708 SkPaint mPaint;
709 struct Cache {
710 SkBitmap bitmap;
711 bool dirty = true;
712 };
713
714 Cache mStagingCache;
715 Cache mCache;
716
717 PropertyChangedListener mPropertyChangedListener
718 = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
Doris Liu4bbc2932015-12-01 17:59:40 -0800719};
720
721} // namespace VectorDrawable
722
723typedef VectorDrawable::Path::Data PathData;
724} // namespace uirenderer
725} // namespace android
726
727#endif // ANDROID_HWUI_VPATH_H