blob: b867dbc597141f21b467aed6ef28ea8b9c63c6f3 [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
42namespace VectorDrawable {
Doris Liu32d7cda2016-04-08 13:48:47 -070043#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
44#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
45#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
Doris Liu1d8e1942016-03-02 15:16:28 -080046 onPropertyChanged(); retVal;})
Doris Liu32d7cda2016-04-08 13:48:47 -070047#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
Doris Liu4bbc2932015-12-01 17:59:40 -080048
49/* A VectorDrawable is composed of a tree of nodes.
50 * Each node can be a group node, or a path.
51 * A group node can have groups or paths as children, but a path node has
52 * no children.
53 * One example can be:
54 * Root Group
55 * / | \
56 * Group Path Group
57 * / \ |
58 * Path Path Path
59 *
Doris Liu1d8e1942016-03-02 15:16:28 -080060 * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
61 * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
62 * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
63 * Each cache has their own generation id to track whether they are up to date with the latest
64 * change in the tree.
65 *
66 * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
67 * all the properties, and viewport change, etc.) are only modifying the staging properties. The
68 * staging properties will then be marked dirty and will be pushed over to render thread properties
69 * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
70 * staging properties with render thread properties to reflect the latest animation value.
71 *
Doris Liu4bbc2932015-12-01 17:59:40 -080072 */
Doris Liu1d8e1942016-03-02 15:16:28 -080073
74class PropertyChangedListener {
75public:
76 PropertyChangedListener(bool* dirty, bool* stagingDirty)
77 : mDirty(dirty), mStagingDirty(stagingDirty) {}
78 void onPropertyChanged() {
79 *mDirty = true;
80 }
81 void onStagingPropertyChanged() {
82 *mStagingDirty = true;
83 }
84private:
85 bool* mDirty;
86 bool* mStagingDirty;
87};
88
Doris Liu4bbc2932015-12-01 17:59:40 -080089class ANDROID_API Node {
90public:
Doris Liu1d8e1942016-03-02 15:16:28 -080091 class Properties {
92 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -070093 explicit Properties(Node* node) : mNode(node) {}
Doris Liu1d8e1942016-03-02 15:16:28 -080094 inline void onPropertyChanged() {
95 mNode->onPropertyChanged(this);
96 }
97 private:
98 Node* mNode;
99 };
Doris Liu4bbc2932015-12-01 17:59:40 -0800100 Node(const Node& node) {
101 mName = node.mName;
102 }
103 Node() {}
Doris Liuc2de46f2016-01-21 12:55:54 -0800104 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
Doris Liu1d8e1942016-03-02 15:16:28 -0800105 float scaleX, float scaleY, bool useStagingData) = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800106 virtual void dump() = 0;
107 void setName(const char* name) {
108 mName = name;
109 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800110 virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
111 mPropertyChangedListener = listener;
112 }
113 virtual void onPropertyChanged(Properties* properties) = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800114 virtual ~Node(){}
Doris Liu1d8e1942016-03-02 15:16:28 -0800115 virtual void syncProperties() = 0;
Doris Liu4bbc2932015-12-01 17:59:40 -0800116protected:
117 std::string mName;
Doris Liu1d8e1942016-03-02 15:16:28 -0800118 PropertyChangedListener* mPropertyChangedListener = nullptr;
Doris Liu4bbc2932015-12-01 17:59:40 -0800119};
120
121class ANDROID_API Path : public Node {
122public:
123 struct ANDROID_API Data {
124 std::vector<char> verbs;
125 std::vector<size_t> verbSizes;
126 std::vector<float> points;
127 bool operator==(const Data& data) const {
128 return verbs == data.verbs && verbSizes == data.verbSizes
129 && points == data.points;
130 }
131 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800132
133 class PathProperties : public Properties {
134 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700135 explicit PathProperties(Node* node) : Properties(node) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800136 void syncProperties(const PathProperties& prop) {
137 mData = prop.mData;
138 onPropertyChanged();
139 }
140 void setData(const Data& data) {
141 // Updates the path data. Note that we don't generate a new Skia path right away
142 // because there are cases where the animation is changing the path data, but the view
143 // that hosts the VD has gone off screen, in which case we won't even draw. So we
144 // postpone the Skia path generation to the draw time.
145 if (data == mData) {
146 return;
147 }
148 mData = data;
149 onPropertyChanged();
150
151 }
152 const Data& getData() const {
153 return mData;
154 }
155 private:
156 Data mData;
157 };
158
Doris Liu4bbc2932015-12-01 17:59:40 -0800159 Path(const Path& path);
160 Path(const char* path, size_t strLength);
161 Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800162
Doris Liu4bbc2932015-12-01 17:59:40 -0800163 void dump() override;
Doris Liuc2de46f2016-01-21 12:55:54 -0800164 void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix,
Doris Liu1d8e1942016-03-02 15:16:28 -0800165 float scaleX, float scaleY, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800166 static float getMatrixScale(const SkMatrix& groupStackedMatrix);
Doris Liu1d8e1942016-03-02 15:16:28 -0800167 virtual void syncProperties() override;
168 virtual void onPropertyChanged(Properties* prop) override {
169 if (prop == &mStagingProperties) {
170 mStagingPropertiesDirty = true;
171 if (mPropertyChangedListener) {
172 mPropertyChangedListener->onStagingPropertyChanged();
173 }
174 } else if (prop == &mProperties){
175 mSkPathDirty = true;
176 if (mPropertyChangedListener) {
177 mPropertyChangedListener->onPropertyChanged();
178 }
179 }
180 }
181 PathProperties* mutateStagingProperties() { return &mStagingProperties; }
182 const PathProperties* stagingProperties() { return &mStagingProperties; }
183
184 // This should only be called from animations on RT
185 PathProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800186
187protected:
188 virtual const SkPath& getUpdatedPath();
Doris Liu1d8e1942016-03-02 15:16:28 -0800189 virtual void getStagingPath(SkPath* outPath);
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700190 virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800191 float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0;
192
193 // Internal data, render thread only.
Doris Liu4bbc2932015-12-01 17:59:40 -0800194 bool mSkPathDirty = true;
Doris Liu1d8e1942016-03-02 15:16:28 -0800195 SkPath mSkPath;
196
197private:
198 PathProperties mProperties = PathProperties(this);
199 PathProperties mStagingProperties = PathProperties(this);
200 bool mStagingPropertiesDirty = true;
Doris Liu4bbc2932015-12-01 17:59:40 -0800201};
202
203class ANDROID_API FullPath: public Path {
204public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800205 class FullPathProperties : public Properties {
206 public:
207 struct PrimitiveFields {
208 float strokeWidth = 0;
209 SkColor strokeColor = SK_ColorTRANSPARENT;
210 float strokeAlpha = 1;
211 SkColor fillColor = SK_ColorTRANSPARENT;
212 float fillAlpha = 1;
213 float trimPathStart = 0;
214 float trimPathEnd = 1;
215 float trimPathOffset = 0;
216 int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
217 int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
218 float strokeMiterLimit = 4;
219 int fillType = 0; /* non-zero or kWinding_FillType in Skia */
220 };
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700221 explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
Doris Liuad21fe22016-04-14 18:13:36 -0700222 ~FullPathProperties() {
223 SkSafeUnref(fillGradient);
224 SkSafeUnref(strokeGradient);
225 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800226 void syncProperties(const FullPathProperties& prop) {
227 mPrimitiveFields = prop.mPrimitiveFields;
228 mTrimDirty = true;
Doris Liuad21fe22016-04-14 18:13:36 -0700229 UPDATE_SKPROP(fillGradient, prop.fillGradient);
230 UPDATE_SKPROP(strokeGradient, prop.strokeGradient);
Doris Liu1d8e1942016-03-02 15:16:28 -0800231 onPropertyChanged();
232 }
233 void setFillGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700234 if(UPDATE_SKPROP(fillGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800235 onPropertyChanged();
236 }
237 }
238 void setStrokeGradient(SkShader* gradient) {
Doris Liuad21fe22016-04-14 18:13:36 -0700239 if(UPDATE_SKPROP(strokeGradient, gradient)) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800240 onPropertyChanged();
241 }
242 }
243 SkShader* getFillGradient() const {
244 return fillGradient;
245 }
246 SkShader* getStrokeGradient() const {
247 return strokeGradient;
248 }
249 float getStrokeWidth() const{
250 return mPrimitiveFields.strokeWidth;
251 }
252 void setStrokeWidth(float strokeWidth) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700253 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
Doris Liu1d8e1942016-03-02 15:16:28 -0800254 }
255 SkColor getStrokeColor() const{
256 return mPrimitiveFields.strokeColor;
257 }
258 void setStrokeColor(SkColor strokeColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700259 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800260 }
261 float getStrokeAlpha() const{
262 return mPrimitiveFields.strokeAlpha;
263 }
264 void setStrokeAlpha(float strokeAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700265 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800266 }
267 SkColor getFillColor() const {
268 return mPrimitiveFields.fillColor;
269 }
270 void setFillColor(SkColor fillColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700271 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800272 }
273 float getFillAlpha() const{
274 return mPrimitiveFields.fillAlpha;
275 }
276 void setFillAlpha(float fillAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700277 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800278 }
279 float getTrimPathStart() const{
280 return mPrimitiveFields.trimPathStart;
281 }
282 void setTrimPathStart(float trimPathStart) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700283 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800284 }
285 float getTrimPathEnd() const{
286 return mPrimitiveFields.trimPathEnd;
287 }
288 void setTrimPathEnd(float trimPathEnd) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700289 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800290 }
291 float getTrimPathOffset() const{
292 return mPrimitiveFields.trimPathOffset;
293 }
294 void setTrimPathOffset(float trimPathOffset) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700295 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800296 }
Doris Liu766431a2016-02-04 22:17:11 +0000297
Doris Liu1d8e1942016-03-02 15:16:28 -0800298 float getStrokeMiterLimit() const {
299 return mPrimitiveFields.strokeMiterLimit;
300 }
301 float getStrokeLineCap() const {
302 return mPrimitiveFields.strokeLineCap;
303 }
304 float getStrokeLineJoin() const {
305 return mPrimitiveFields.strokeLineJoin;
306 }
307 float getFillType() const {
308 return mPrimitiveFields.fillType;
309 }
310 bool copyProperties(int8_t* outProperties, int length) const;
311 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
312 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
313 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
314 int fillType) {
315 mPrimitiveFields.strokeWidth = strokeWidth;
316 mPrimitiveFields.strokeColor = strokeColor;
317 mPrimitiveFields.strokeAlpha = strokeAlpha;
318 mPrimitiveFields.fillColor = fillColor;
319 mPrimitiveFields.fillAlpha = fillAlpha;
320 mPrimitiveFields.trimPathStart = trimPathStart;
321 mPrimitiveFields.trimPathEnd = trimPathEnd;
322 mPrimitiveFields.trimPathOffset = trimPathOffset;
323 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
324 mPrimitiveFields.strokeLineCap = strokeLineCap;
325 mPrimitiveFields.strokeLineJoin = strokeLineJoin;
326 mPrimitiveFields.fillType = fillType;
327 mTrimDirty = true;
328 onPropertyChanged();
329 }
330 // Set property values during animation
331 void setColorPropertyValue(int propertyId, int32_t value);
332 void setPropertyValue(int propertyId, float value);
333 bool mTrimDirty;
334 private:
335 enum class Property {
336 strokeWidth = 0,
337 strokeColor,
338 strokeAlpha,
339 fillColor,
340 fillAlpha,
341 trimPathStart,
342 trimPathEnd,
343 trimPathOffset,
344 strokeLineCap,
345 strokeLineJoin,
346 strokeMiterLimit,
347 fillType,
348 count,
349 };
350 PrimitiveFields mPrimitiveFields;
Doris Liuad21fe22016-04-14 18:13:36 -0700351 SkShader* fillGradient = nullptr;
352 SkShader* strokeGradient = nullptr;
Doris Liu1d8e1942016-03-02 15:16:28 -0800353 };
Doris Liu766431a2016-02-04 22:17:11 +0000354
Doris Liu1d8e1942016-03-02 15:16:28 -0800355 // Called from UI thread
Doris Liu4bbc2932015-12-01 17:59:40 -0800356 FullPath(const FullPath& path); // for cloning
357 FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
358 FullPath() : Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800359 void dump() override;
360 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
361 const FullPathProperties* stagingProperties() { return &mStagingProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800362
Doris Liu1d8e1942016-03-02 15:16:28 -0800363 // This should only be called from animations on RT
364 FullPathProperties* mutateProperties() { return &mProperties; }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800365
Doris Liu1d8e1942016-03-02 15:16:28 -0800366 virtual void syncProperties() override;
367 virtual void onPropertyChanged(Properties* properties) override {
368 Path::onPropertyChanged(properties);
369 if (properties == &mStagingProperties) {
370 mStagingPropertiesDirty = true;
371 if (mPropertyChangedListener) {
372 mPropertyChangedListener->onStagingPropertyChanged();
373 }
374 } else if (properties == &mProperties) {
375 if (mPropertyChangedListener) {
376 mPropertyChangedListener->onPropertyChanged();
377 }
378 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800379 }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800380
Doris Liu4bbc2932015-12-01 17:59:40 -0800381protected:
382 const SkPath& getUpdatedPath() override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800383 void getStagingPath(SkPath* outPath) override;
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700384 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800385 float strokeScale, const SkMatrix& matrix, bool useStagingData) 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() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800402
403protected:
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700404 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800405 float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800406};
407
408class ANDROID_API Group: public Node {
409public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800410 class GroupProperties : public Properties {
411 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700412 explicit GroupProperties(Node* mNode) : Properties(mNode) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800413 struct PrimitiveFields {
414 float rotate = 0;
415 float pivotX = 0;
416 float pivotY = 0;
417 float scaleX = 1;
418 float scaleY = 1;
419 float translateX = 0;
420 float translateY = 0;
421 } mPrimitiveFields;
422 void syncProperties(const GroupProperties& prop) {
423 mPrimitiveFields = prop.mPrimitiveFields;
424 onPropertyChanged();
425 }
426 float getRotation() const {
427 return mPrimitiveFields.rotate;
428 }
429 void setRotation(float rotation) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700430 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
Doris Liu1d8e1942016-03-02 15:16:28 -0800431 }
432 float getPivotX() const {
433 return mPrimitiveFields.pivotX;
434 }
435 void setPivotX(float pivotX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700436 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800437 }
438 float getPivotY() const {
439 return mPrimitiveFields.pivotY;
440 }
441 void setPivotY(float pivotY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700442 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800443 }
444 float getScaleX() const {
445 return mPrimitiveFields.scaleX;
446 }
447 void setScaleX(float scaleX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700448 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800449 }
450 float getScaleY() const {
451 return mPrimitiveFields.scaleY;
452 }
453 void setScaleY(float scaleY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700454 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800455 }
456 float getTranslateX() const {
457 return mPrimitiveFields.translateX;
458 }
459 void setTranslateX(float translateX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700460 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800461 }
462 float getTranslateY() const {
463 return mPrimitiveFields.translateY;
464 }
465 void setTranslateY(float translateY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700466 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800467 }
468 void updateProperties(float rotate, float pivotX, float pivotY,
469 float scaleX, float scaleY, float translateX, float translateY) {
470 mPrimitiveFields.rotate = rotate;
471 mPrimitiveFields.pivotX = pivotX;
472 mPrimitiveFields.pivotY = pivotY;
473 mPrimitiveFields.scaleX = scaleX;
474 mPrimitiveFields.scaleY = scaleY;
475 mPrimitiveFields.translateX = translateX;
476 mPrimitiveFields.translateY = translateY;
477 onPropertyChanged();
478 }
479 void setPropertyValue(int propertyId, float value);
480 float getPropertyValue(int propertyId) const;
481 bool copyProperties(float* outProperties, int length) const;
482 static bool isValidProperty(int propertyId);
483 private:
484 enum class Property {
485 rotate = 0,
486 pivotX,
487 pivotY,
488 scaleX,
489 scaleY,
490 translateX,
491 translateY,
492 // Count of the properties, must be at the end.
493 count,
494 };
Doris Liu766431a2016-02-04 22:17:11 +0000495 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800496
Doris Liu4bbc2932015-12-01 17:59:40 -0800497 Group(const Group& group);
498 Group() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800499 void addChild(Node* child);
Doris Liu1d8e1942016-03-02 15:16:28 -0800500 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
501 Node::setPropertyChangedListener(listener);
502 for (auto& child : mChildren) {
503 child->setPropertyChangedListener(listener);
504 }
505 }
506 virtual void syncProperties() override;
507 GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
508 const GroupProperties* stagingProperties() { return &mStagingProperties; }
509
510 // This should only be called from animations on RT
511 GroupProperties* mutateProperties() { return &mProperties; }
512
513 // Methods below could be called from either UI thread or Render Thread.
514 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
515 float scaleX, float scaleY, bool useStagingData) override;
516 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
Doris Liu4bbc2932015-12-01 17:59:40 -0800517 void dump() override;
Doris Liu766431a2016-02-04 22:17:11 +0000518 static bool isValidProperty(int propertyId);
Doris Liu4bbc2932015-12-01 17:59:40 -0800519
Doris Liu1d8e1942016-03-02 15:16:28 -0800520 virtual void onPropertyChanged(Properties* properties) override {
521 if (properties == &mStagingProperties) {
522 mStagingPropertiesDirty = true;
523 if (mPropertyChangedListener) {
524 mPropertyChangedListener->onStagingPropertyChanged();
525 }
526 } else {
527 if (mPropertyChangedListener) {
528 mPropertyChangedListener->onPropertyChanged();
529 }
530 }
531 }
532
Doris Liu4bbc2932015-12-01 17:59:40 -0800533private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800534 GroupProperties mProperties = GroupProperties(this);
535 GroupProperties mStagingProperties = GroupProperties(this);
536 bool mStagingPropertiesDirty = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800537 std::vector< std::unique_ptr<Node> > mChildren;
Doris Liu4bbc2932015-12-01 17:59:40 -0800538};
539
Doris Liu766431a2016-02-04 22:17:11 +0000540class ANDROID_API Tree : public VirtualLightRefBase {
Doris Liu4bbc2932015-12-01 17:59:40 -0800541public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700542 explicit Tree(Group* rootNode) : mRootNode(rootNode) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800543 mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
544 }
Doris Liu02802972016-05-26 15:19:15 -0700545
546 // Copy properties from the tree and use the give node as the root node
547 Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
548 mStagingProperties.syncAnimatableProperties(*copy->stagingProperties());
549 mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties());
550 }
Doris Liuf8d131c2016-04-29 18:41:29 -0700551 // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
552 // canvas. Returns the number of pixels needed for the bitmap cache.
553 int draw(Canvas* outCanvas, SkColorFilter* colorFilter,
Doris Liu4bbc2932015-12-01 17:59:40 -0800554 const SkRect& bounds, bool needsMirroring, bool canReuseCache);
Doris Liu1d8e1942016-03-02 15:16:28 -0800555 void drawStaging(Canvas* canvas);
Doris Liu4bbc2932015-12-01 17:59:40 -0800556
Doris Liu766431a2016-02-04 22:17:11 +0000557 const SkBitmap& getBitmapUpdateIfDirty();
Doris Liu4bbc2932015-12-01 17:59:40 -0800558 void setAllowCaching(bool allowCaching) {
559 mAllowCaching = allowCaching;
560 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800561 SkPaint* getPaint();
562 void syncProperties() {
563 if (mStagingProperties.mNonAnimatablePropertiesDirty) {
564 mProperties.syncNonAnimatableProperties(mStagingProperties);
565 mStagingProperties.mNonAnimatablePropertiesDirty = false;
566 }
567
568 if (mStagingProperties.mAnimatablePropertiesDirty) {
569 mProperties.syncAnimatableProperties(mStagingProperties);
570 } else {
571 mStagingProperties.syncAnimatableProperties(mProperties);
572 }
573 mStagingProperties.mAnimatablePropertiesDirty = false;
574 mRootNode->syncProperties();
Doris Liu4bbc2932015-12-01 17:59:40 -0800575 }
576
Doris Liu1d8e1942016-03-02 15:16:28 -0800577 class TreeProperties {
578 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700579 explicit TreeProperties(Tree* tree) : mTree(tree) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800580 // Properties that can only be modified by UI thread, therefore sync should
581 // only go from UI to RT
582 struct NonAnimatableProperties {
583 float viewportWidth = 0;
584 float viewportHeight = 0;
585 SkRect bounds;
586 int scaledWidth = 0;
587 int scaledHeight = 0;
588 SkColorFilter* colorFilter = nullptr;
589 ~NonAnimatableProperties() {
590 SkSafeUnref(colorFilter);
591 }
592 } mNonAnimatableProperties;
593 bool mNonAnimatablePropertiesDirty = true;
594
595 float mRootAlpha = 1.0f;
596 bool mAnimatablePropertiesDirty = true;
597
598 void syncNonAnimatableProperties(const TreeProperties& prop) {
599 // Copy over the data that can only be changed in UI thread
600 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
601 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
602 prop.mNonAnimatableProperties.colorFilter);
603 }
604 mNonAnimatableProperties = prop.mNonAnimatableProperties;
605 }
606
607 void setViewportSize(float width, float height) {
608 if (mNonAnimatableProperties.viewportWidth != width
609 || mNonAnimatableProperties.viewportHeight != height) {
610 mNonAnimatablePropertiesDirty = true;
611 mNonAnimatableProperties.viewportWidth = width;
612 mNonAnimatableProperties.viewportHeight = height;
613 mTree->onPropertyChanged(this);
614 }
615 }
616 void setBounds(const SkRect& bounds) {
617 if (mNonAnimatableProperties.bounds != bounds) {
618 mNonAnimatableProperties.bounds = bounds;
619 mNonAnimatablePropertiesDirty = true;
620 mTree->onPropertyChanged(this);
621 }
622 }
623
624 void setScaledSize(int width, int height) {
Teng-Hui Zhu17f40b82016-11-16 10:29:39 -0800625 // If the requested size is bigger than what the bitmap was, then
626 // we increase the bitmap size to match. The width and height
627 // are bound by MAX_CACHED_BITMAP_SIZE.
628 if (mNonAnimatableProperties.scaledWidth < width
629 || mNonAnimatableProperties.scaledHeight < height) {
630 mNonAnimatableProperties.scaledWidth = std::max(width,
631 mNonAnimatableProperties.scaledWidth);
632 mNonAnimatableProperties.scaledHeight = std::max(height,
633 mNonAnimatableProperties.scaledHeight);
Doris Liu1d8e1942016-03-02 15:16:28 -0800634 mNonAnimatablePropertiesDirty = true;
635 mTree->onPropertyChanged(this);
636 }
637 }
638 void setColorFilter(SkColorFilter* filter) {
639 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
640 mNonAnimatablePropertiesDirty = true;
641 mTree->onPropertyChanged(this);
642 }
643 }
644 SkColorFilter* getColorFilter() const{
645 return mNonAnimatableProperties.colorFilter;
646 }
647
648 float getViewportWidth() const {
649 return mNonAnimatableProperties.viewportWidth;
650 }
651 float getViewportHeight() const {
652 return mNonAnimatableProperties.viewportHeight;
653 }
654 float getScaledWidth() const {
655 return mNonAnimatableProperties.scaledWidth;
656 }
657 float getScaledHeight() const {
658 return mNonAnimatableProperties.scaledHeight;
659 }
660 void syncAnimatableProperties(const TreeProperties& prop) {
661 mRootAlpha = prop.mRootAlpha;
662 }
663 bool setRootAlpha(float rootAlpha) {
664 if (rootAlpha != mRootAlpha) {
665 mAnimatablePropertiesDirty = true;
666 mRootAlpha = rootAlpha;
667 mTree->onPropertyChanged(this);
668 return true;
669 }
670 return false;
671 }
672 float getRootAlpha() const { return mRootAlpha;}
673 const SkRect& getBounds() const {
674 return mNonAnimatableProperties.bounds;
675 }
676 Tree* mTree;
677 };
678 void onPropertyChanged(TreeProperties* prop);
679 TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
Doris Liu02802972016-05-26 15:19:15 -0700680 const TreeProperties* stagingProperties() const { return &mStagingProperties; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800681
682 // This should only be called from animations on RT
683 TreeProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800684
Doris Liu718cd3e2016-05-17 16:50:31 -0700685 // This should always be called from RT.
Doris Liu7c7052d2016-07-25 17:19:24 -0700686 void markDirty() { mCache.dirty = true; }
Doris Liu718cd3e2016-05-17 16:50:31 -0700687 bool isDirty() const { return mCache.dirty; }
688 bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
689 void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
690
Doris Liu4bbc2932015-12-01 17:59:40 -0800691private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800692
693 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
694 bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
695 bool canReuseBitmap(const SkBitmap&, int width, int height);
696 void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
Doris Liu4bbc2932015-12-01 17:59:40 -0800697 // Cap the bitmap size, such that it won't hurt the performance too much
698 // and it won't crash due to a very large scale.
699 // The drawable will look blurry above this size.
700 const static int MAX_CACHED_BITMAP_SIZE;
701
Doris Liu4bbc2932015-12-01 17:59:40 -0800702 bool mAllowCaching = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800703 std::unique_ptr<Group> mRootNode;
Doris Liu4bbc2932015-12-01 17:59:40 -0800704
Doris Liu1d8e1942016-03-02 15:16:28 -0800705 TreeProperties mProperties = TreeProperties(this);
706 TreeProperties mStagingProperties = TreeProperties(this);
707
Doris Liu1d8e1942016-03-02 15:16:28 -0800708 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 Liu718cd3e2016-05-17 16:50:31 -0700719
720 mutable bool mWillBeConsumed = false;
Doris Liu4bbc2932015-12-01 17:59:40 -0800721};
722
723} // namespace VectorDrawable
724
725typedef VectorDrawable::Path::Data PathData;
726} // namespace uirenderer
727} // namespace android
728
729#endif // ANDROID_HWUI_VPATH_H