blob: 22cfe29d2aa55a93cff62f1296e1aff38ae96878 [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>
Stan Iliev23c38a92017-03-23 00:12:50 -040034#include <SkSurface.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080035
36#include <cutils/compiler.h>
37#include <stddef.h>
38#include <vector>
39#include <string>
40
41namespace android {
42namespace uirenderer {
43
Teng-Hui Zhu85d99522016-04-25 14:23:40 -070044// Debug
45#if DEBUG_VECTOR_DRAWABLE
46 #define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
47#else
48 #define VECTOR_DRAWABLE_LOGD(...)
49#endif
50
Doris Liu4bbc2932015-12-01 17:59:40 -080051namespace VectorDrawable {
Doris Liu32d7cda2016-04-08 13:48:47 -070052#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
53#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
54#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
Doris Liu1d8e1942016-03-02 15:16:28 -080055 onPropertyChanged(); retVal;})
Doris Liu32d7cda2016-04-08 13:48:47 -070056#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
Doris Liu4bbc2932015-12-01 17:59:40 -080057
58/* A VectorDrawable is composed of a tree of nodes.
59 * Each node can be a group node, or a path.
60 * A group node can have groups or paths as children, but a path node has
61 * no children.
62 * One example can be:
63 * Root Group
64 * / | \
65 * Group Path Group
66 * / \ |
67 * Path Path Path
68 *
Doris Liu1d8e1942016-03-02 15:16:28 -080069 * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
70 * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
71 * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
72 * Each cache has their own generation id to track whether they are up to date with the latest
73 * change in the tree.
74 *
75 * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
76 * all the properties, and viewport change, etc.) are only modifying the staging properties. The
77 * staging properties will then be marked dirty and will be pushed over to render thread properties
78 * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
79 * staging properties with render thread properties to reflect the latest animation value.
80 *
Doris Liu4bbc2932015-12-01 17:59:40 -080081 */
Doris Liu1d8e1942016-03-02 15:16:28 -080082
83class PropertyChangedListener {
84public:
85 PropertyChangedListener(bool* dirty, bool* stagingDirty)
86 : mDirty(dirty), mStagingDirty(stagingDirty) {}
87 void onPropertyChanged() {
88 *mDirty = true;
89 }
90 void onStagingPropertyChanged() {
91 *mStagingDirty = true;
92 }
93private:
94 bool* mDirty;
95 bool* mStagingDirty;
96};
97
Doris Liu4bbc2932015-12-01 17:59:40 -080098class ANDROID_API Node {
99public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800100 class Properties {
101 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700102 explicit Properties(Node* node) : mNode(node) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800103 inline void onPropertyChanged() {
104 mNode->onPropertyChanged(this);
105 }
106 private:
107 Node* mNode;
108 };
Doris Liu4bbc2932015-12-01 17:59:40 -0800109 Node(const Node& node) {
110 mName = node.mName;
111 }
112 Node() {}
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400113 virtual void draw(SkCanvas* outCanvas, 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 Liu1d8e1942016-03-02 15:16:28 -0800172 virtual void syncProperties() override;
173 virtual void onPropertyChanged(Properties* prop) override {
174 if (prop == &mStagingProperties) {
175 mStagingPropertiesDirty = true;
176 if (mPropertyChangedListener) {
177 mPropertyChangedListener->onStagingPropertyChanged();
178 }
179 } else if (prop == &mProperties){
180 mSkPathDirty = true;
181 if (mPropertyChangedListener) {
182 mPropertyChangedListener->onPropertyChanged();
183 }
184 }
185 }
186 PathProperties* mutateStagingProperties() { return &mStagingProperties; }
187 const PathProperties* stagingProperties() { return &mStagingProperties; }
188
189 // This should only be called from animations on RT
190 PathProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800191
192protected:
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400193 virtual const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath);
Doris Liu1d8e1942016-03-02 15:16:28 -0800194
195 // Internal data, render thread only.
Doris Liu4bbc2932015-12-01 17:59:40 -0800196 bool mSkPathDirty = true;
Doris Liu1d8e1942016-03-02 15:16:28 -0800197 SkPath mSkPath;
198
199private:
200 PathProperties mProperties = PathProperties(this);
201 PathProperties mStagingProperties = PathProperties(this);
202 bool mStagingPropertiesDirty = true;
Doris Liu4bbc2932015-12-01 17:59:40 -0800203};
204
205class ANDROID_API FullPath: public Path {
206public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800207 class FullPathProperties : public Properties {
208 public:
209 struct PrimitiveFields {
210 float strokeWidth = 0;
211 SkColor strokeColor = SK_ColorTRANSPARENT;
212 float strokeAlpha = 1;
213 SkColor fillColor = SK_ColorTRANSPARENT;
214 float fillAlpha = 1;
215 float trimPathStart = 0;
216 float trimPathEnd = 1;
217 float trimPathOffset = 0;
218 int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
219 int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
220 float strokeMiterLimit = 4;
221 int fillType = 0; /* non-zero or kWinding_FillType in Skia */
222 };
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700223 explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
Doris Liuad21fe22016-04-14 18:13:36 -0700224 ~FullPathProperties() {
225 SkSafeUnref(fillGradient);
226 SkSafeUnref(strokeGradient);
227 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800228 void syncProperties(const FullPathProperties& prop) {
229 mPrimitiveFields = prop.mPrimitiveFields;
230 mTrimDirty = true;
Doris Liuad21fe22016-04-14 18:13:36 -0700231 UPDATE_SKPROP(fillGradient, prop.fillGradient);
232 UPDATE_SKPROP(strokeGradient, prop.strokeGradient);
Doris Liu1d8e1942016-03-02 15:16:28 -0800233 onPropertyChanged();
234 }
235 void setFillGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700236 if(UPDATE_SKPROP(fillGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800237 onPropertyChanged();
238 }
239 }
240 void setStrokeGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700241 if(UPDATE_SKPROP(strokeGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800242 onPropertyChanged();
243 }
244 }
245 SkShader* getFillGradient() const {
246 return fillGradient;
247 }
248 SkShader* getStrokeGradient() const {
249 return strokeGradient;
250 }
251 float getStrokeWidth() const{
252 return mPrimitiveFields.strokeWidth;
253 }
254 void setStrokeWidth(float strokeWidth) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700255 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
Doris Liu1d8e1942016-03-02 15:16:28 -0800256 }
257 SkColor getStrokeColor() const{
258 return mPrimitiveFields.strokeColor;
259 }
260 void setStrokeColor(SkColor strokeColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700261 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800262 }
263 float getStrokeAlpha() const{
264 return mPrimitiveFields.strokeAlpha;
265 }
266 void setStrokeAlpha(float strokeAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700267 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800268 }
269 SkColor getFillColor() const {
270 return mPrimitiveFields.fillColor;
271 }
272 void setFillColor(SkColor fillColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700273 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800274 }
275 float getFillAlpha() const{
276 return mPrimitiveFields.fillAlpha;
277 }
278 void setFillAlpha(float fillAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700279 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800280 }
281 float getTrimPathStart() const{
282 return mPrimitiveFields.trimPathStart;
283 }
284 void setTrimPathStart(float trimPathStart) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700285 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800286 }
287 float getTrimPathEnd() const{
288 return mPrimitiveFields.trimPathEnd;
289 }
290 void setTrimPathEnd(float trimPathEnd) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700291 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800292 }
293 float getTrimPathOffset() const{
294 return mPrimitiveFields.trimPathOffset;
295 }
296 void setTrimPathOffset(float trimPathOffset) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700297 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800298 }
Doris Liu766431a2016-02-04 22:17:11 +0000299
Doris Liu1d8e1942016-03-02 15:16:28 -0800300 float getStrokeMiterLimit() const {
301 return mPrimitiveFields.strokeMiterLimit;
302 }
303 float getStrokeLineCap() const {
304 return mPrimitiveFields.strokeLineCap;
305 }
306 float getStrokeLineJoin() const {
307 return mPrimitiveFields.strokeLineJoin;
308 }
309 float getFillType() const {
310 return mPrimitiveFields.fillType;
311 }
312 bool copyProperties(int8_t* outProperties, int length) const;
313 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
314 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
315 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
316 int fillType) {
317 mPrimitiveFields.strokeWidth = strokeWidth;
318 mPrimitiveFields.strokeColor = strokeColor;
319 mPrimitiveFields.strokeAlpha = strokeAlpha;
320 mPrimitiveFields.fillColor = fillColor;
321 mPrimitiveFields.fillAlpha = fillAlpha;
322 mPrimitiveFields.trimPathStart = trimPathStart;
323 mPrimitiveFields.trimPathEnd = trimPathEnd;
324 mPrimitiveFields.trimPathOffset = trimPathOffset;
325 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
326 mPrimitiveFields.strokeLineCap = strokeLineCap;
327 mPrimitiveFields.strokeLineJoin = strokeLineJoin;
328 mPrimitiveFields.fillType = fillType;
329 mTrimDirty = true;
330 onPropertyChanged();
331 }
332 // Set property values during animation
333 void setColorPropertyValue(int propertyId, int32_t value);
334 void setPropertyValue(int propertyId, float value);
335 bool mTrimDirty;
336 private:
337 enum class Property {
338 strokeWidth = 0,
339 strokeColor,
340 strokeAlpha,
341 fillColor,
342 fillAlpha,
343 trimPathStart,
344 trimPathEnd,
345 trimPathOffset,
346 strokeLineCap,
347 strokeLineJoin,
348 strokeMiterLimit,
349 fillType,
350 count,
351 };
352 PrimitiveFields mPrimitiveFields;
Doris Liuad21fe22016-04-14 18:13:36 -0700353 SkShader* fillGradient = nullptr;
354 SkShader* strokeGradient = nullptr;
Doris Liu1d8e1942016-03-02 15:16:28 -0800355 };
Doris Liu766431a2016-02-04 22:17:11 +0000356
Doris Liu1d8e1942016-03-02 15:16:28 -0800357 // Called from UI thread
Doris Liu4bbc2932015-12-01 17:59:40 -0800358 FullPath(const FullPath& path); // for cloning
359 FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
360 FullPath() : Path() {}
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400361 void draw(SkCanvas* outCanvas, bool useStagingData) override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800362 void dump() override;
363 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
364 const FullPathProperties* stagingProperties() { return &mStagingProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800365
Doris Liu1d8e1942016-03-02 15:16:28 -0800366 // This should only be called from animations on RT
367 FullPathProperties* mutateProperties() { return &mProperties; }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800368
Doris Liu1d8e1942016-03-02 15:16:28 -0800369 virtual void syncProperties() override;
370 virtual void onPropertyChanged(Properties* properties) override {
371 Path::onPropertyChanged(properties);
372 if (properties == &mStagingProperties) {
373 mStagingPropertiesDirty = true;
374 if (mPropertyChangedListener) {
375 mPropertyChangedListener->onStagingPropertyChanged();
376 }
377 } else if (properties == &mProperties) {
378 if (mPropertyChangedListener) {
379 mPropertyChangedListener->onPropertyChanged();
380 }
381 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800382 }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800383
Doris Liu4bbc2932015-12-01 17:59:40 -0800384protected:
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400385 const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800386private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800387
388 FullPathProperties mProperties = FullPathProperties(this);
389 FullPathProperties mStagingProperties = FullPathProperties(this);
390 bool mStagingPropertiesDirty = true;
391
392 // Intermediate data for drawing, render thread only
Doris Liu5a11e8d2016-02-04 20:04:10 +0000393 SkPath mTrimmedSkPath;
Doris Liu1d8e1942016-03-02 15:16:28 -0800394
Doris Liu4bbc2932015-12-01 17:59:40 -0800395};
396
397class ANDROID_API ClipPath: public Path {
398public:
399 ClipPath(const ClipPath& path) : Path(path) {}
400 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
401 ClipPath() : Path() {}
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400402 void draw(SkCanvas* outCanvas, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800403};
404
405class ANDROID_API Group: public Node {
406public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800407 class GroupProperties : public Properties {
408 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700409 explicit GroupProperties(Node* mNode) : Properties(mNode) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800410 struct PrimitiveFields {
411 float rotate = 0;
412 float pivotX = 0;
413 float pivotY = 0;
414 float scaleX = 1;
415 float scaleY = 1;
416 float translateX = 0;
417 float translateY = 0;
418 } mPrimitiveFields;
419 void syncProperties(const GroupProperties& prop) {
420 mPrimitiveFields = prop.mPrimitiveFields;
421 onPropertyChanged();
422 }
423 float getRotation() const {
424 return mPrimitiveFields.rotate;
425 }
426 void setRotation(float rotation) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700427 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
Doris Liu1d8e1942016-03-02 15:16:28 -0800428 }
429 float getPivotX() const {
430 return mPrimitiveFields.pivotX;
431 }
432 void setPivotX(float pivotX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700433 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800434 }
435 float getPivotY() const {
436 return mPrimitiveFields.pivotY;
437 }
438 void setPivotY(float pivotY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700439 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800440 }
441 float getScaleX() const {
442 return mPrimitiveFields.scaleX;
443 }
444 void setScaleX(float scaleX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700445 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800446 }
447 float getScaleY() const {
448 return mPrimitiveFields.scaleY;
449 }
450 void setScaleY(float scaleY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700451 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800452 }
453 float getTranslateX() const {
454 return mPrimitiveFields.translateX;
455 }
456 void setTranslateX(float translateX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700457 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800458 }
459 float getTranslateY() const {
460 return mPrimitiveFields.translateY;
461 }
462 void setTranslateY(float translateY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700463 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800464 }
465 void updateProperties(float rotate, float pivotX, float pivotY,
466 float scaleX, float scaleY, float translateX, float translateY) {
467 mPrimitiveFields.rotate = rotate;
468 mPrimitiveFields.pivotX = pivotX;
469 mPrimitiveFields.pivotY = pivotY;
470 mPrimitiveFields.scaleX = scaleX;
471 mPrimitiveFields.scaleY = scaleY;
472 mPrimitiveFields.translateX = translateX;
473 mPrimitiveFields.translateY = translateY;
474 onPropertyChanged();
475 }
476 void setPropertyValue(int propertyId, float value);
477 float getPropertyValue(int propertyId) const;
478 bool copyProperties(float* outProperties, int length) const;
479 static bool isValidProperty(int propertyId);
480 private:
481 enum class Property {
482 rotate = 0,
483 pivotX,
484 pivotY,
485 scaleX,
486 scaleY,
487 translateX,
488 translateY,
489 // Count of the properties, must be at the end.
490 count,
491 };
Doris Liu766431a2016-02-04 22:17:11 +0000492 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800493
Doris Liu4bbc2932015-12-01 17:59:40 -0800494 Group(const Group& group);
495 Group() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800496 void addChild(Node* child);
Doris Liu1d8e1942016-03-02 15:16:28 -0800497 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
498 Node::setPropertyChangedListener(listener);
499 for (auto& child : mChildren) {
500 child->setPropertyChangedListener(listener);
501 }
502 }
503 virtual void syncProperties() override;
504 GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
505 const GroupProperties* stagingProperties() { return &mStagingProperties; }
506
507 // This should only be called from animations on RT
508 GroupProperties* mutateProperties() { return &mProperties; }
509
510 // Methods below could be called from either UI thread or Render Thread.
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400511 virtual void draw(SkCanvas* outCanvas, bool useStagingData) override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800512 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
Doris Liu4bbc2932015-12-01 17:59:40 -0800513 void dump() override;
Doris Liu766431a2016-02-04 22:17:11 +0000514 static bool isValidProperty(int propertyId);
Doris Liu4bbc2932015-12-01 17:59:40 -0800515
Doris Liu1d8e1942016-03-02 15:16:28 -0800516 virtual void onPropertyChanged(Properties* properties) override {
517 if (properties == &mStagingProperties) {
518 mStagingPropertiesDirty = true;
519 if (mPropertyChangedListener) {
520 mPropertyChangedListener->onStagingPropertyChanged();
521 }
522 } else {
523 if (mPropertyChangedListener) {
524 mPropertyChangedListener->onPropertyChanged();
525 }
526 }
527 }
528
Doris Liu4bbc2932015-12-01 17:59:40 -0800529private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800530 GroupProperties mProperties = GroupProperties(this);
531 GroupProperties mStagingProperties = GroupProperties(this);
532 bool mStagingPropertiesDirty = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800533 std::vector< std::unique_ptr<Node> > mChildren;
Doris Liu4bbc2932015-12-01 17:59:40 -0800534};
535
Doris Liu766431a2016-02-04 22:17:11 +0000536class ANDROID_API Tree : public VirtualLightRefBase {
Doris Liu4bbc2932015-12-01 17:59:40 -0800537public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700538 explicit Tree(Group* rootNode) : mRootNode(rootNode) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800539 mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
540 }
Doris Liu335d7d12016-05-26 15:19:15 -0700541
542 // Copy properties from the tree and use the give node as the root node
543 Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
544 mStagingProperties.syncAnimatableProperties(*copy->stagingProperties());
545 mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties());
546 }
Doris Liuf8d131c2016-04-29 18:41:29 -0700547 // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
548 // canvas. Returns the number of pixels needed for the bitmap cache.
549 int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
Doris Liu4bbc2932015-12-01 17:59:40 -0800550 const SkRect& bounds, bool needsMirroring, bool canReuseCache);
Doris Liu1d8e1942016-03-02 15:16:28 -0800551 void drawStaging(Canvas* canvas);
Doris Liu4bbc2932015-12-01 17:59:40 -0800552
sergeyvfc9999502016-10-17 13:07:38 -0700553 Bitmap& getBitmapUpdateIfDirty();
Doris Liu4bbc2932015-12-01 17:59:40 -0800554 void setAllowCaching(bool allowCaching) {
555 mAllowCaching = allowCaching;
556 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800557 SkPaint* getPaint();
558 void syncProperties() {
559 if (mStagingProperties.mNonAnimatablePropertiesDirty) {
560 mProperties.syncNonAnimatableProperties(mStagingProperties);
561 mStagingProperties.mNonAnimatablePropertiesDirty = false;
562 }
563
564 if (mStagingProperties.mAnimatablePropertiesDirty) {
565 mProperties.syncAnimatableProperties(mStagingProperties);
566 } else {
567 mStagingProperties.syncAnimatableProperties(mProperties);
568 }
569 mStagingProperties.mAnimatablePropertiesDirty = false;
570 mRootNode->syncProperties();
Doris Liu4bbc2932015-12-01 17:59:40 -0800571 }
572
Doris Liu1d8e1942016-03-02 15:16:28 -0800573 class TreeProperties {
574 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700575 explicit TreeProperties(Tree* tree) : mTree(tree) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800576 // Properties that can only be modified by UI thread, therefore sync should
577 // only go from UI to RT
578 struct NonAnimatableProperties {
579 float viewportWidth = 0;
580 float viewportHeight = 0;
581 SkRect bounds;
582 int scaledWidth = 0;
583 int scaledHeight = 0;
584 SkColorFilter* colorFilter = nullptr;
585 ~NonAnimatableProperties() {
586 SkSafeUnref(colorFilter);
587 }
588 } mNonAnimatableProperties;
589 bool mNonAnimatablePropertiesDirty = true;
590
591 float mRootAlpha = 1.0f;
592 bool mAnimatablePropertiesDirty = true;
593
594 void syncNonAnimatableProperties(const TreeProperties& prop) {
595 // Copy over the data that can only be changed in UI thread
596 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
597 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
598 prop.mNonAnimatableProperties.colorFilter);
599 }
600 mNonAnimatableProperties = prop.mNonAnimatableProperties;
601 }
602
603 void setViewportSize(float width, float height) {
604 if (mNonAnimatableProperties.viewportWidth != width
605 || mNonAnimatableProperties.viewportHeight != height) {
606 mNonAnimatablePropertiesDirty = true;
607 mNonAnimatableProperties.viewportWidth = width;
608 mNonAnimatableProperties.viewportHeight = height;
609 mTree->onPropertyChanged(this);
610 }
611 }
612 void setBounds(const SkRect& bounds) {
613 if (mNonAnimatableProperties.bounds != bounds) {
614 mNonAnimatableProperties.bounds = bounds;
615 mNonAnimatablePropertiesDirty = true;
616 mTree->onPropertyChanged(this);
617 }
618 }
619
620 void setScaledSize(int width, int height) {
Teng-Hui Zhu037fc182016-11-16 10:29:39 -0800621 // If the requested size is bigger than what the bitmap was, then
622 // we increase the bitmap size to match. The width and height
623 // are bound by MAX_CACHED_BITMAP_SIZE.
624 if (mNonAnimatableProperties.scaledWidth < width
625 || mNonAnimatableProperties.scaledHeight < height) {
626 mNonAnimatableProperties.scaledWidth = std::max(width,
627 mNonAnimatableProperties.scaledWidth);
628 mNonAnimatableProperties.scaledHeight = std::max(height,
629 mNonAnimatableProperties.scaledHeight);
Doris Liu1d8e1942016-03-02 15:16:28 -0800630 mNonAnimatablePropertiesDirty = true;
631 mTree->onPropertyChanged(this);
632 }
633 }
634 void setColorFilter(SkColorFilter* filter) {
635 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
636 mNonAnimatablePropertiesDirty = true;
637 mTree->onPropertyChanged(this);
638 }
639 }
640 SkColorFilter* getColorFilter() const{
641 return mNonAnimatableProperties.colorFilter;
642 }
643
644 float getViewportWidth() const {
645 return mNonAnimatableProperties.viewportWidth;
646 }
647 float getViewportHeight() const {
648 return mNonAnimatableProperties.viewportHeight;
649 }
650 float getScaledWidth() const {
651 return mNonAnimatableProperties.scaledWidth;
652 }
653 float getScaledHeight() const {
654 return mNonAnimatableProperties.scaledHeight;
655 }
656 void syncAnimatableProperties(const TreeProperties& prop) {
657 mRootAlpha = prop.mRootAlpha;
658 }
659 bool setRootAlpha(float rootAlpha) {
660 if (rootAlpha != mRootAlpha) {
661 mAnimatablePropertiesDirty = true;
662 mRootAlpha = rootAlpha;
663 mTree->onPropertyChanged(this);
664 return true;
665 }
666 return false;
667 }
668 float getRootAlpha() const { return mRootAlpha;}
669 const SkRect& getBounds() const {
670 return mNonAnimatableProperties.bounds;
671 }
672 Tree* mTree;
673 };
674 void onPropertyChanged(TreeProperties* prop);
675 TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
Doris Liu335d7d12016-05-26 15:19:15 -0700676 const TreeProperties* stagingProperties() const { return &mStagingProperties; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800677
678 // This should only be called from animations on RT
679 TreeProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800680
Stan Iliev23c38a92017-03-23 00:12:50 -0400681 // called from RT only
682 const TreeProperties& properties() const { return mProperties; }
683
Doris Liu67ce99b2016-05-17 16:50:31 -0700684 // This should always be called from RT.
Doris Liu7c7052d2016-07-25 17:19:24 -0700685 void markDirty() { mCache.dirty = true; }
Doris Liu67ce99b2016-05-17 16:50:31 -0700686 bool isDirty() const { return mCache.dirty; }
687 bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
688 void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
689
Stan Iliev23c38a92017-03-23 00:12:50 -0400690 // Returns true if VD cache surface is big enough. This should always be called from RT and it
691 // works with Skia pipelines only.
692 bool canReuseSurface() {
693 SkSurface* surface = mCache.surface.get();
694 return surface && surface->width() >= mProperties.getScaledWidth()
695 && surface->height() >= mProperties.getScaledHeight();
696 }
697
698 // Draws VD cache into a canvas. This should always be called from RT and it works with Skia
699 // pipelines only.
700 void draw(SkCanvas* canvas);
701
702 // Draws VD into a GPU backed surface. If canReuseSurface returns false, then "surface" must
703 // contain a new surface. This should always be called from RT and it works with Skia pipelines
704 // only.
705 void updateCache(sk_sp<SkSurface> surface);
706
Doris Liu4bbc2932015-12-01 17:59:40 -0800707private:
sergeyvfc9999502016-10-17 13:07:38 -0700708 struct Cache {
Stan Iliev23c38a92017-03-23 00:12:50 -0400709 sk_sp<Bitmap> bitmap; //used by HWUI pipeline and software
710 //TODO: use surface instead of bitmap when drawing in software canvas
711 sk_sp<SkSurface> surface; //used only by Skia pipelines
sergeyvfc9999502016-10-17 13:07:38 -0700712 bool dirty = true;
713 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800714
715 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
sergeyvfc9999502016-10-17 13:07:38 -0700716 bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
717 bool canReuseBitmap(Bitmap*, int width, int height);
718 void updateBitmapCache(Bitmap& outCache, bool useStagingData);
Doris Liu4bbc2932015-12-01 17:59:40 -0800719 // Cap the bitmap size, such that it won't hurt the performance too much
720 // and it won't crash due to a very large scale.
721 // The drawable will look blurry above this size.
722 const static int MAX_CACHED_BITMAP_SIZE;
723
Doris Liu4bbc2932015-12-01 17:59:40 -0800724 bool mAllowCaching = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800725 std::unique_ptr<Group> mRootNode;
Doris Liu4bbc2932015-12-01 17:59:40 -0800726
Doris Liu1d8e1942016-03-02 15:16:28 -0800727 TreeProperties mProperties = TreeProperties(this);
728 TreeProperties mStagingProperties = TreeProperties(this);
729
Doris Liu1d8e1942016-03-02 15:16:28 -0800730 SkPaint mPaint;
Doris Liu1d8e1942016-03-02 15:16:28 -0800731
732 Cache mStagingCache;
733 Cache mCache;
734
735 PropertyChangedListener mPropertyChangedListener
736 = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
Doris Liu67ce99b2016-05-17 16:50:31 -0700737
738 mutable bool mWillBeConsumed = false;
Doris Liu4bbc2932015-12-01 17:59:40 -0800739};
740
741} // namespace VectorDrawable
742
743typedef VectorDrawable::Path::Data PathData;
744} // namespace uirenderer
745} // namespace android
746
747#endif // ANDROID_HWUI_VPATH_H