blob: e4c7ed71f361f7ccc3ef5bdfd308a785bc81c843 [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 Liu1d8e1942016-03-02 15:16:28 -080043#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
Doris Liu4bbc2932015-12-01 17:59:40 -080044#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
Doris Liu1d8e1942016-03-02 15:16:28 -080045#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
46 onPropertyChanged(); retVal;})
47#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:
93 Properties(Node* node) : mNode(node) {}
94 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:
135 PathProperties(Node* node) : Properties(node) {}
136 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 };
221 FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
222 void syncProperties(const FullPathProperties& prop) {
223 mPrimitiveFields = prop.mPrimitiveFields;
224 mTrimDirty = true;
225 fillGradient.reset(prop.fillGradient);
226 strokeGradient.reset(prop.strokeGradient);
227 onPropertyChanged();
228 }
229 void setFillGradient(SkShader* gradient) {
230 if(fillGradient != gradient){
231 fillGradient.reset(gradient);
232 onPropertyChanged();
233 }
234 }
235 void setStrokeGradient(SkShader* gradient) {
236 if(strokeGradient != gradient){
237 strokeGradient.reset(gradient);
238 onPropertyChanged();
239 }
240 }
241 SkShader* getFillGradient() const {
242 return fillGradient;
243 }
244 SkShader* getStrokeGradient() const {
245 return strokeGradient;
246 }
247 float getStrokeWidth() const{
248 return mPrimitiveFields.strokeWidth;
249 }
250 void setStrokeWidth(float strokeWidth) {
251 VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
252 }
253 SkColor getStrokeColor() const{
254 return mPrimitiveFields.strokeColor;
255 }
256 void setStrokeColor(SkColor strokeColor) {
257 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
258 }
259 float getStrokeAlpha() const{
260 return mPrimitiveFields.strokeAlpha;
261 }
262 void setStrokeAlpha(float strokeAlpha) {
263 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
264 }
265 SkColor getFillColor() const {
266 return mPrimitiveFields.fillColor;
267 }
268 void setFillColor(SkColor fillColor) {
269 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
270 }
271 float getFillAlpha() const{
272 return mPrimitiveFields.fillAlpha;
273 }
274 void setFillAlpha(float fillAlpha) {
275 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
276 }
277 float getTrimPathStart() const{
278 return mPrimitiveFields.trimPathStart;
279 }
280 void setTrimPathStart(float trimPathStart) {
281 VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
282 }
283 float getTrimPathEnd() const{
284 return mPrimitiveFields.trimPathEnd;
285 }
286 void setTrimPathEnd(float trimPathEnd) {
287 VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
288 }
289 float getTrimPathOffset() const{
290 return mPrimitiveFields.trimPathOffset;
291 }
292 void setTrimPathOffset(float trimPathOffset) {
293 VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
294 }
Doris Liu766431a2016-02-04 22:17:11 +0000295
Doris Liu1d8e1942016-03-02 15:16:28 -0800296 float getStrokeMiterLimit() const {
297 return mPrimitiveFields.strokeMiterLimit;
298 }
299 float getStrokeLineCap() const {
300 return mPrimitiveFields.strokeLineCap;
301 }
302 float getStrokeLineJoin() const {
303 return mPrimitiveFields.strokeLineJoin;
304 }
305 float getFillType() const {
306 return mPrimitiveFields.fillType;
307 }
308 bool copyProperties(int8_t* outProperties, int length) const;
309 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
310 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd,
311 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin,
312 int fillType) {
313 mPrimitiveFields.strokeWidth = strokeWidth;
314 mPrimitiveFields.strokeColor = strokeColor;
315 mPrimitiveFields.strokeAlpha = strokeAlpha;
316 mPrimitiveFields.fillColor = fillColor;
317 mPrimitiveFields.fillAlpha = fillAlpha;
318 mPrimitiveFields.trimPathStart = trimPathStart;
319 mPrimitiveFields.trimPathEnd = trimPathEnd;
320 mPrimitiveFields.trimPathOffset = trimPathOffset;
321 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
322 mPrimitiveFields.strokeLineCap = strokeLineCap;
323 mPrimitiveFields.strokeLineJoin = strokeLineJoin;
324 mPrimitiveFields.fillType = fillType;
325 mTrimDirty = true;
326 onPropertyChanged();
327 }
328 // Set property values during animation
329 void setColorPropertyValue(int propertyId, int32_t value);
330 void setPropertyValue(int propertyId, float value);
331 bool mTrimDirty;
332 private:
333 enum class Property {
334 strokeWidth = 0,
335 strokeColor,
336 strokeAlpha,
337 fillColor,
338 fillAlpha,
339 trimPathStart,
340 trimPathEnd,
341 trimPathOffset,
342 strokeLineCap,
343 strokeLineJoin,
344 strokeMiterLimit,
345 fillType,
346 count,
347 };
348 PrimitiveFields mPrimitiveFields;
349 SkAutoTUnref<SkShader> fillGradient;
350 SkAutoTUnref<SkShader> strokeGradient;
351 };
Doris Liu766431a2016-02-04 22:17:11 +0000352
Doris Liu1d8e1942016-03-02 15:16:28 -0800353 // Called from UI thread
Doris Liu4bbc2932015-12-01 17:59:40 -0800354 FullPath(const FullPath& path); // for cloning
355 FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
356 FullPath() : Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800357 void dump() override;
358 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
359 const FullPathProperties* stagingProperties() { return &mStagingProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800360
Doris Liu1d8e1942016-03-02 15:16:28 -0800361 // This should only be called from animations on RT
362 FullPathProperties* mutateProperties() { return &mProperties; }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800363
Doris Liu1d8e1942016-03-02 15:16:28 -0800364 virtual void syncProperties() override;
365 virtual void onPropertyChanged(Properties* properties) override {
366 Path::onPropertyChanged(properties);
367 if (properties == &mStagingProperties) {
368 mStagingPropertiesDirty = true;
369 if (mPropertyChangedListener) {
370 mPropertyChangedListener->onStagingPropertyChanged();
371 }
372 } else if (properties == &mProperties) {
373 if (mPropertyChangedListener) {
374 mPropertyChangedListener->onPropertyChanged();
375 }
376 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800377 }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800378
Doris Liu4bbc2932015-12-01 17:59:40 -0800379protected:
380 const SkPath& getUpdatedPath() override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800381 void getStagingPath(SkPath* outPath) override;
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700382 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800383 float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800384private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800385
386 FullPathProperties mProperties = FullPathProperties(this);
387 FullPathProperties mStagingProperties = FullPathProperties(this);
388 bool mStagingPropertiesDirty = true;
389
390 // Intermediate data for drawing, render thread only
Doris Liu5a11e8d2016-02-04 20:04:10 +0000391 SkPath mTrimmedSkPath;
Doris Liu1d8e1942016-03-02 15:16:28 -0800392
Doris Liu4bbc2932015-12-01 17:59:40 -0800393};
394
395class ANDROID_API ClipPath: public Path {
396public:
397 ClipPath(const ClipPath& path) : Path(path) {}
398 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
399 ClipPath() : Path() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800400
401protected:
Teng-Hui Zhu46591f42016-03-15 14:32:16 -0700402 void drawPath(SkCanvas* outCanvas, SkPath& renderPath,
Doris Liu1d8e1942016-03-02 15:16:28 -0800403 float strokeScale, const SkMatrix& matrix, bool useStagingData) override;
Doris Liu4bbc2932015-12-01 17:59:40 -0800404};
405
406class ANDROID_API Group: public Node {
407public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800408 class GroupProperties : public Properties {
409 public:
410 GroupProperties(Node* mNode) : Properties(mNode) {}
411 struct PrimitiveFields {
412 float rotate = 0;
413 float pivotX = 0;
414 float pivotY = 0;
415 float scaleX = 1;
416 float scaleY = 1;
417 float translateX = 0;
418 float translateY = 0;
419 } mPrimitiveFields;
420 void syncProperties(const GroupProperties& prop) {
421 mPrimitiveFields = prop.mPrimitiveFields;
422 onPropertyChanged();
423 }
424 float getRotation() const {
425 return mPrimitiveFields.rotate;
426 }
427 void setRotation(float rotation) {
428 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
429 }
430 float getPivotX() const {
431 return mPrimitiveFields.pivotX;
432 }
433 void setPivotX(float pivotX) {
434 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
435 }
436 float getPivotY() const {
437 return mPrimitiveFields.pivotY;
438 }
439 void setPivotY(float pivotY) {
440 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
441 }
442 float getScaleX() const {
443 return mPrimitiveFields.scaleX;
444 }
445 void setScaleX(float scaleX) {
446 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
447 }
448 float getScaleY() const {
449 return mPrimitiveFields.scaleY;
450 }
451 void setScaleY(float scaleY) {
452 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
453 }
454 float getTranslateX() const {
455 return mPrimitiveFields.translateX;
456 }
457 void setTranslateX(float translateX) {
458 VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
459 }
460 float getTranslateY() const {
461 return mPrimitiveFields.translateY;
462 }
463 void setTranslateY(float translateY) {
464 VD_SET_PROP_AND_NOTIFY(translateY, translateY);
465 }
466 void updateProperties(float rotate, float pivotX, float pivotY,
467 float scaleX, float scaleY, float translateX, float translateY) {
468 mPrimitiveFields.rotate = rotate;
469 mPrimitiveFields.pivotX = pivotX;
470 mPrimitiveFields.pivotY = pivotY;
471 mPrimitiveFields.scaleX = scaleX;
472 mPrimitiveFields.scaleY = scaleY;
473 mPrimitiveFields.translateX = translateX;
474 mPrimitiveFields.translateY = translateY;
475 onPropertyChanged();
476 }
477 void setPropertyValue(int propertyId, float value);
478 float getPropertyValue(int propertyId) const;
479 bool copyProperties(float* outProperties, int length) const;
480 static bool isValidProperty(int propertyId);
481 private:
482 enum class Property {
483 rotate = 0,
484 pivotX,
485 pivotY,
486 scaleX,
487 scaleY,
488 translateX,
489 translateY,
490 // Count of the properties, must be at the end.
491 count,
492 };
Doris Liu766431a2016-02-04 22:17:11 +0000493 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800494
Doris Liu4bbc2932015-12-01 17:59:40 -0800495 Group(const Group& group);
496 Group() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800497 void addChild(Node* child);
Doris Liu1d8e1942016-03-02 15:16:28 -0800498 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
499 Node::setPropertyChangedListener(listener);
500 for (auto& child : mChildren) {
501 child->setPropertyChangedListener(listener);
502 }
503 }
504 virtual void syncProperties() override;
505 GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
506 const GroupProperties* stagingProperties() { return &mStagingProperties; }
507
508 // This should only be called from animations on RT
509 GroupProperties* mutateProperties() { return &mProperties; }
510
511 // Methods below could be called from either UI thread or Render Thread.
512 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix,
513 float scaleX, float scaleY, bool useStagingData) override;
514 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
Doris Liu4bbc2932015-12-01 17:59:40 -0800515 void dump() override;
Doris Liu766431a2016-02-04 22:17:11 +0000516 static bool isValidProperty(int propertyId);
Doris Liu4bbc2932015-12-01 17:59:40 -0800517
Doris Liu1d8e1942016-03-02 15:16:28 -0800518 virtual void onPropertyChanged(Properties* properties) override {
519 if (properties == &mStagingProperties) {
520 mStagingPropertiesDirty = true;
521 if (mPropertyChangedListener) {
522 mPropertyChangedListener->onStagingPropertyChanged();
523 }
524 } else {
525 if (mPropertyChangedListener) {
526 mPropertyChangedListener->onPropertyChanged();
527 }
528 }
529 }
530
Doris Liu4bbc2932015-12-01 17:59:40 -0800531private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800532 GroupProperties mProperties = GroupProperties(this);
533 GroupProperties mStagingProperties = GroupProperties(this);
534 bool mStagingPropertiesDirty = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800535 std::vector< std::unique_ptr<Node> > mChildren;
Doris Liu4bbc2932015-12-01 17:59:40 -0800536};
537
Doris Liu766431a2016-02-04 22:17:11 +0000538class ANDROID_API Tree : public VirtualLightRefBase {
Doris Liu4bbc2932015-12-01 17:59:40 -0800539public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800540 Tree(Group* rootNode) : mRootNode(rootNode) {
541 mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
542 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800543 void draw(Canvas* outCanvas, SkColorFilter* colorFilter,
544 const SkRect& bounds, bool needsMirroring, bool canReuseCache);
Doris Liu1d8e1942016-03-02 15:16:28 -0800545 void drawStaging(Canvas* canvas);
Doris Liu4bbc2932015-12-01 17:59:40 -0800546
Doris Liu766431a2016-02-04 22:17:11 +0000547 const SkBitmap& getBitmapUpdateIfDirty();
Doris Liu4bbc2932015-12-01 17:59:40 -0800548 void setAllowCaching(bool allowCaching) {
549 mAllowCaching = allowCaching;
550 }
Doris Liu1d8e1942016-03-02 15:16:28 -0800551 SkPaint* getPaint();
552 void syncProperties() {
553 if (mStagingProperties.mNonAnimatablePropertiesDirty) {
554 mProperties.syncNonAnimatableProperties(mStagingProperties);
555 mStagingProperties.mNonAnimatablePropertiesDirty = false;
556 }
557
558 if (mStagingProperties.mAnimatablePropertiesDirty) {
559 mProperties.syncAnimatableProperties(mStagingProperties);
560 } else {
561 mStagingProperties.syncAnimatableProperties(mProperties);
562 }
563 mStagingProperties.mAnimatablePropertiesDirty = false;
564 mRootNode->syncProperties();
Doris Liu4bbc2932015-12-01 17:59:40 -0800565 }
566
Doris Liu1d8e1942016-03-02 15:16:28 -0800567 class TreeProperties {
568 public:
569 TreeProperties(Tree* tree) : mTree(tree) {}
570 // Properties that can only be modified by UI thread, therefore sync should
571 // only go from UI to RT
572 struct NonAnimatableProperties {
573 float viewportWidth = 0;
574 float viewportHeight = 0;
575 SkRect bounds;
576 int scaledWidth = 0;
577 int scaledHeight = 0;
578 SkColorFilter* colorFilter = nullptr;
579 ~NonAnimatableProperties() {
580 SkSafeUnref(colorFilter);
581 }
582 } mNonAnimatableProperties;
583 bool mNonAnimatablePropertiesDirty = true;
584
585 float mRootAlpha = 1.0f;
586 bool mAnimatablePropertiesDirty = true;
587
588 void syncNonAnimatableProperties(const TreeProperties& prop) {
589 // Copy over the data that can only be changed in UI thread
590 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
591 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter,
592 prop.mNonAnimatableProperties.colorFilter);
593 }
594 mNonAnimatableProperties = prop.mNonAnimatableProperties;
595 }
596
597 void setViewportSize(float width, float height) {
598 if (mNonAnimatableProperties.viewportWidth != width
599 || mNonAnimatableProperties.viewportHeight != height) {
600 mNonAnimatablePropertiesDirty = true;
601 mNonAnimatableProperties.viewportWidth = width;
602 mNonAnimatableProperties.viewportHeight = height;
603 mTree->onPropertyChanged(this);
604 }
605 }
606 void setBounds(const SkRect& bounds) {
607 if (mNonAnimatableProperties.bounds != bounds) {
608 mNonAnimatableProperties.bounds = bounds;
609 mNonAnimatablePropertiesDirty = true;
610 mTree->onPropertyChanged(this);
611 }
612 }
613
614 void setScaledSize(int width, int height) {
615 if (mNonAnimatableProperties.scaledWidth != width
616 || mNonAnimatableProperties.scaledHeight != height) {
617 mNonAnimatableProperties.scaledWidth = width;
618 mNonAnimatableProperties.scaledHeight = height;
619 mNonAnimatablePropertiesDirty = true;
620 mTree->onPropertyChanged(this);
621 }
622 }
623 void setColorFilter(SkColorFilter* filter) {
624 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) {
625 mNonAnimatablePropertiesDirty = true;
626 mTree->onPropertyChanged(this);
627 }
628 }
629 SkColorFilter* getColorFilter() const{
630 return mNonAnimatableProperties.colorFilter;
631 }
632
633 float getViewportWidth() const {
634 return mNonAnimatableProperties.viewportWidth;
635 }
636 float getViewportHeight() const {
637 return mNonAnimatableProperties.viewportHeight;
638 }
639 float getScaledWidth() const {
640 return mNonAnimatableProperties.scaledWidth;
641 }
642 float getScaledHeight() const {
643 return mNonAnimatableProperties.scaledHeight;
644 }
645 void syncAnimatableProperties(const TreeProperties& prop) {
646 mRootAlpha = prop.mRootAlpha;
647 }
648 bool setRootAlpha(float rootAlpha) {
649 if (rootAlpha != mRootAlpha) {
650 mAnimatablePropertiesDirty = true;
651 mRootAlpha = rootAlpha;
652 mTree->onPropertyChanged(this);
653 return true;
654 }
655 return false;
656 }
657 float getRootAlpha() const { return mRootAlpha;}
658 const SkRect& getBounds() const {
659 return mNonAnimatableProperties.bounds;
660 }
661 Tree* mTree;
662 };
663 void onPropertyChanged(TreeProperties* prop);
664 TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
665 const TreeProperties* stagingProperties() { return &mStagingProperties; }
666 PushStagingFunctor* getFunctor() { return &mFunctor;}
667
668 // This should only be called from animations on RT
669 TreeProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800670
671private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800672 class VectorDrawableFunctor : public PushStagingFunctor {
673 public:
674 VectorDrawableFunctor(Tree* tree) : mTree(tree) {}
675 virtual void operator ()() {
676 mTree->syncProperties();
677 }
678 private:
679 Tree* mTree;
680 };
681
682 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop);
683 bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height);
684 bool canReuseBitmap(const SkBitmap&, int width, int height);
685 void updateBitmapCache(SkBitmap* outCache, bool useStagingData);
Doris Liu4bbc2932015-12-01 17:59:40 -0800686 // Cap the bitmap size, such that it won't hurt the performance too much
687 // and it won't crash due to a very large scale.
688 // The drawable will look blurry above this size.
689 const static int MAX_CACHED_BITMAP_SIZE;
690
Doris Liu4bbc2932015-12-01 17:59:40 -0800691 bool mAllowCaching = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800692 std::unique_ptr<Group> mRootNode;
Doris Liu4bbc2932015-12-01 17:59:40 -0800693
Doris Liu1d8e1942016-03-02 15:16:28 -0800694 TreeProperties mProperties = TreeProperties(this);
695 TreeProperties mStagingProperties = TreeProperties(this);
696
697 VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this);
698
699 SkPaint mPaint;
700 struct Cache {
701 SkBitmap bitmap;
702 bool dirty = true;
703 };
704
705 Cache mStagingCache;
706 Cache mCache;
707
708 PropertyChangedListener mPropertyChangedListener
709 = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
Doris Liu4bbc2932015-12-01 17:59:40 -0800710};
711
712} // namespace VectorDrawable
713
714typedef VectorDrawable::Path::Data PathData;
715} // namespace uirenderer
716} // namespace android
717
718#endif // ANDROID_HWUI_VPATH_H