blob: c92654c479c1a52e05d1fcca52323f9a29293694 [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
Doris Liu1d8e1942016-03-02 15:16:28 -080020#include "DisplayList.h"
John Reck1bcacfd2017-11-03 10:12:19 -070021#include "hwui/Bitmap.h"
22#include "hwui/Canvas.h"
23#include "renderthread/CacheManager.h"
Doris Liu766431a2016-02-04 22:17:11 +000024
Doris Liu4bbc2932015-12-01 17:59:40 -080025#include <SkBitmap.h>
John Reck1bcacfd2017-11-03 10:12:19 -070026#include <SkCanvas.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080027#include <SkColor.h>
Doris Liu1d8e1942016-03-02 15:16:28 -080028#include <SkColorFilter.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080029#include <SkMatrix.h>
30#include <SkPaint.h>
31#include <SkPath.h>
32#include <SkPathMeasure.h>
33#include <SkRect.h>
Kevin Lubick1175dc02022-02-28 12:41:27 -050034#include <SkRefCnt.h>
Nader Jawad5bed1f52020-09-25 00:27:29 -070035#include <SkShader.h>
Stan Iliev23c38a92017-03-23 00:12:50 -040036#include <SkSurface.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080037
38#include <cutils/compiler.h>
39#include <stddef.h>
Doris Liu4bbc2932015-12-01 17:59:40 -080040#include <string>
John Reck1bcacfd2017-11-03 10:12:19 -070041#include <vector>
Doris Liu4bbc2932015-12-01 17:59:40 -080042
43namespace android {
44namespace uirenderer {
45
Teng-Hui Zhu85d99522016-04-25 14:23:40 -070046// Debug
47#if DEBUG_VECTOR_DRAWABLE
John Reck1bcacfd2017-11-03 10:12:19 -070048#define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__)
Teng-Hui Zhu85d99522016-04-25 14:23:40 -070049#else
John Reck1bcacfd2017-11-03 10:12:19 -070050#define VECTOR_DRAWABLE_LOGD(...)
Teng-Hui Zhu85d99522016-04-25 14:23:40 -070051#endif
52
Doris Liu4bbc2932015-12-01 17:59:40 -080053namespace VectorDrawable {
John Reck1bcacfd2017-11-03 10:12:19 -070054#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) \
55 (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
Doris Liu32d7cda2016-04-08 13:48:47 -070056#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
John Reck1bcacfd2017-11-03 10:12:19 -070057#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) \
58 ({ \
59 bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value)); \
60 onPropertyChanged(); \
61 retVal; \
62 })
Doris Liu4bbc2932015-12-01 17:59:40 -080063
64/* A VectorDrawable is composed of a tree of nodes.
65 * Each node can be a group node, or a path.
66 * A group node can have groups or paths as children, but a path node has
67 * no children.
68 * One example can be:
69 * Root Group
70 * / | \
71 * Group Path Group
72 * / \ |
73 * Path Path Path
74 *
Doris Liu1d8e1942016-03-02 15:16:28 -080075 * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given
76 * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in
77 * Render Thread. A generation id is used to keep track of changes in the vector drawable tree.
78 * Each cache has their own generation id to track whether they are up to date with the latest
79 * change in the tree.
80 *
81 * Any property change to the vector drawable coming from UI thread (such as bulk setters to update
82 * all the properties, and viewport change, etc.) are only modifying the staging properties. The
83 * staging properties will then be marked dirty and will be pushed over to render thread properties
84 * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating
85 * staging properties with render thread properties to reflect the latest animation value.
86 *
Doris Liu4bbc2932015-12-01 17:59:40 -080087 */
Doris Liu1d8e1942016-03-02 15:16:28 -080088
89class PropertyChangedListener {
90public:
91 PropertyChangedListener(bool* dirty, bool* stagingDirty)
92 : mDirty(dirty), mStagingDirty(stagingDirty) {}
John Reck1bcacfd2017-11-03 10:12:19 -070093 void onPropertyChanged() { *mDirty = true; }
94 void onStagingPropertyChanged() { *mStagingDirty = true; }
95
Doris Liu1d8e1942016-03-02 15:16:28 -080096private:
97 bool* mDirty;
98 bool* mStagingDirty;
99};
100
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -0500101class Node {
Doris Liu4bbc2932015-12-01 17:59:40 -0800102public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800103 class Properties {
104 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700105 explicit Properties(Node* node) : mNode(node) {}
John Reck1bcacfd2017-11-03 10:12:19 -0700106 inline void onPropertyChanged() { mNode->onPropertyChanged(this); }
107
Doris Liu1d8e1942016-03-02 15:16:28 -0800108 private:
109 Node* mNode;
110 };
John Reck1bcacfd2017-11-03 10:12:19 -0700111 Node(const Node& node) { mName = node.mName; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800112 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;
John Reck1bcacfd2017-11-03 10:12:19 -0700115 void setName(const char* name) { mName = name; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800116 virtual void setPropertyChangedListener(PropertyChangedListener* listener) {
117 mPropertyChangedListener = listener;
118 }
119 virtual void onPropertyChanged(Properties* properties) = 0;
John Reck1bcacfd2017-11-03 10:12:19 -0700120 virtual ~Node() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800121 virtual void syncProperties() = 0;
Doris Liu6b184d72017-12-04 16:31:07 -0800122 virtual void setAntiAlias(bool aa) = 0;
John Reck1bcacfd2017-11-03 10:12:19 -0700123
John Reck08ee8152018-09-20 16:27:46 -0700124 virtual void forEachFillColor(const std::function<void(SkColor)>& func) const { }
125
Doris Liu4bbc2932015-12-01 17:59:40 -0800126protected:
127 std::string mName;
Doris Liu1d8e1942016-03-02 15:16:28 -0800128 PropertyChangedListener* mPropertyChangedListener = nullptr;
Doris Liu4bbc2932015-12-01 17:59:40 -0800129};
130
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -0500131class Path : public Node {
Doris Liu4bbc2932015-12-01 17:59:40 -0800132public:
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -0500133 struct Data {
Doris Liu4bbc2932015-12-01 17:59:40 -0800134 std::vector<char> verbs;
135 std::vector<size_t> verbSizes;
136 std::vector<float> points;
137 bool operator==(const Data& data) const {
John Reck1bcacfd2017-11-03 10:12:19 -0700138 return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points;
Doris Liu4bbc2932015-12-01 17:59:40 -0800139 }
140 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800141
142 class PathProperties : public Properties {
143 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700144 explicit PathProperties(Node* node) : Properties(node) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800145 void syncProperties(const PathProperties& prop) {
146 mData = prop.mData;
147 onPropertyChanged();
148 }
149 void setData(const Data& data) {
150 // Updates the path data. Note that we don't generate a new Skia path right away
151 // because there are cases where the animation is changing the path data, but the view
152 // that hosts the VD has gone off screen, in which case we won't even draw. So we
153 // postpone the Skia path generation to the draw time.
154 if (data == mData) {
155 return;
156 }
157 mData = data;
158 onPropertyChanged();
John Reck1bcacfd2017-11-03 10:12:19 -0700159 }
160 const Data& getData() const { return mData; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800161
Doris Liu1d8e1942016-03-02 15:16:28 -0800162 private:
163 Data mData;
164 };
165
Doris Liu4bbc2932015-12-01 17:59:40 -0800166 Path(const Path& path);
167 Path(const char* path, size_t strLength);
168 Path() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800169
Doris Liu4bbc2932015-12-01 17:59:40 -0800170 void dump() override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800171 virtual void syncProperties() override;
172 virtual void onPropertyChanged(Properties* prop) override {
173 if (prop == &mStagingProperties) {
174 mStagingPropertiesDirty = true;
175 if (mPropertyChangedListener) {
176 mPropertyChangedListener->onStagingPropertyChanged();
177 }
John Reck1bcacfd2017-11-03 10:12:19 -0700178 } else if (prop == &mProperties) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800179 mSkPathDirty = true;
180 if (mPropertyChangedListener) {
181 mPropertyChangedListener->onPropertyChanged();
182 }
183 }
184 }
185 PathProperties* mutateStagingProperties() { return &mStagingProperties; }
186 const PathProperties* stagingProperties() { return &mStagingProperties; }
187
188 // This should only be called from animations on RT
189 PathProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800190
191protected:
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400192 virtual const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath);
Doris Liu1d8e1942016-03-02 15:16:28 -0800193
194 // Internal data, render thread only.
Doris Liu4bbc2932015-12-01 17:59:40 -0800195 bool mSkPathDirty = true;
Doris Liu1d8e1942016-03-02 15:16:28 -0800196 SkPath mSkPath;
197
198private:
199 PathProperties mProperties = PathProperties(this);
200 PathProperties mStagingProperties = PathProperties(this);
201 bool mStagingPropertiesDirty = true;
Doris Liu4bbc2932015-12-01 17:59:40 -0800202};
203
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -0500204class FullPath : public Path {
Doris Liu4bbc2932015-12-01 17:59:40 -0800205public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800206 class FullPathProperties : public Properties {
207 public:
208 struct PrimitiveFields {
209 float strokeWidth = 0;
210 SkColor strokeColor = SK_ColorTRANSPARENT;
211 float strokeAlpha = 1;
212 SkColor fillColor = SK_ColorTRANSPARENT;
213 float fillAlpha = 1;
214 float trimPathStart = 0;
215 float trimPathEnd = 1;
216 float trimPathOffset = 0;
217 int32_t strokeLineCap = SkPaint::Cap::kButt_Cap;
218 int32_t strokeLineJoin = SkPaint::Join::kMiter_Join;
219 float strokeMiterLimit = 4;
220 int fillType = 0; /* non-zero or kWinding_FillType in Skia */
221 };
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700222 explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {}
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400223 ~FullPathProperties() {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800224 void syncProperties(const FullPathProperties& prop) {
225 mPrimitiveFields = prop.mPrimitiveFields;
226 mTrimDirty = true;
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400227 fillGradient = prop.fillGradient;
228 strokeGradient = prop.strokeGradient;
Doris Liu1d8e1942016-03-02 15:16:28 -0800229 onPropertyChanged();
230 }
Nader Jawad5bed1f52020-09-25 00:27:29 -0700231 void setFillGradient(SkShader* gradient) {
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400232 if (fillGradient.get() != gradient) {
233 fillGradient = sk_ref_sp(gradient);
Doris Liu1d8e1942016-03-02 15:16:28 -0800234 onPropertyChanged();
235 }
236 }
Nader Jawad5bed1f52020-09-25 00:27:29 -0700237 void setStrokeGradient(SkShader* gradient) {
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400238 if (strokeGradient.get() != gradient) {
239 strokeGradient = sk_ref_sp(gradient);
Doris Liu1d8e1942016-03-02 15:16:28 -0800240 onPropertyChanged();
241 }
242 }
Nader Jawad5bed1f52020-09-25 00:27:29 -0700243 SkShader* getFillGradient() const { return fillGradient.get(); }
244 SkShader* getStrokeGradient() const { return strokeGradient.get(); }
John Reck1bcacfd2017-11-03 10:12:19 -0700245 float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800246 void setStrokeWidth(float strokeWidth) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700247 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
Doris Liu1d8e1942016-03-02 15:16:28 -0800248 }
John Reck1bcacfd2017-11-03 10:12:19 -0700249 SkColor getStrokeColor() const { return mPrimitiveFields.strokeColor; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800250 void setStrokeColor(SkColor strokeColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700251 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800252 }
John Reck1bcacfd2017-11-03 10:12:19 -0700253 float getStrokeAlpha() const { return mPrimitiveFields.strokeAlpha; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800254 void setStrokeAlpha(float strokeAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700255 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800256 }
John Reck1bcacfd2017-11-03 10:12:19 -0700257 SkColor getFillColor() const { return mPrimitiveFields.fillColor; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800258 void setFillColor(SkColor fillColor) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700259 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
Doris Liu1d8e1942016-03-02 15:16:28 -0800260 }
John Reck1bcacfd2017-11-03 10:12:19 -0700261 float getFillAlpha() const { return mPrimitiveFields.fillAlpha; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800262 void setFillAlpha(float fillAlpha) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700263 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
Doris Liu1d8e1942016-03-02 15:16:28 -0800264 }
John Reck1bcacfd2017-11-03 10:12:19 -0700265 float getTrimPathStart() const { return mPrimitiveFields.trimPathStart; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800266 void setTrimPathStart(float trimPathStart) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700267 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800268 }
John Reck1bcacfd2017-11-03 10:12:19 -0700269 float getTrimPathEnd() const { return mPrimitiveFields.trimPathEnd; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800270 void setTrimPathEnd(float trimPathEnd) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700271 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800272 }
John Reck1bcacfd2017-11-03 10:12:19 -0700273 float getTrimPathOffset() const { return mPrimitiveFields.trimPathOffset; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800274 void setTrimPathOffset(float trimPathOffset) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700275 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
Doris Liu1d8e1942016-03-02 15:16:28 -0800276 }
Doris Liu766431a2016-02-04 22:17:11 +0000277
John Reck1bcacfd2017-11-03 10:12:19 -0700278 float getStrokeMiterLimit() const { return mPrimitiveFields.strokeMiterLimit; }
279 float getStrokeLineCap() const { return mPrimitiveFields.strokeLineCap; }
280 float getStrokeLineJoin() const { return mPrimitiveFields.strokeLineJoin; }
281 float getFillType() const { return mPrimitiveFields.fillType; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800282 bool copyProperties(int8_t* outProperties, int length) const;
283 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha,
John Reck1bcacfd2017-11-03 10:12:19 -0700284 SkColor fillColor, float fillAlpha, float trimPathStart,
285 float trimPathEnd, float trimPathOffset, float strokeMiterLimit,
286 int strokeLineCap, int strokeLineJoin, int fillType) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800287 mPrimitiveFields.strokeWidth = strokeWidth;
288 mPrimitiveFields.strokeColor = strokeColor;
289 mPrimitiveFields.strokeAlpha = strokeAlpha;
290 mPrimitiveFields.fillColor = fillColor;
291 mPrimitiveFields.fillAlpha = fillAlpha;
292 mPrimitiveFields.trimPathStart = trimPathStart;
293 mPrimitiveFields.trimPathEnd = trimPathEnd;
294 mPrimitiveFields.trimPathOffset = trimPathOffset;
295 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit;
296 mPrimitiveFields.strokeLineCap = strokeLineCap;
297 mPrimitiveFields.strokeLineJoin = strokeLineJoin;
298 mPrimitiveFields.fillType = fillType;
299 mTrimDirty = true;
300 onPropertyChanged();
301 }
302 // Set property values during animation
303 void setColorPropertyValue(int propertyId, int32_t value);
304 void setPropertyValue(int propertyId, float value);
305 bool mTrimDirty;
John Reck1bcacfd2017-11-03 10:12:19 -0700306
Doris Liu1d8e1942016-03-02 15:16:28 -0800307 private:
308 enum class Property {
309 strokeWidth = 0,
310 strokeColor,
311 strokeAlpha,
312 fillColor,
313 fillAlpha,
314 trimPathStart,
315 trimPathEnd,
316 trimPathOffset,
317 strokeLineCap,
318 strokeLineJoin,
319 strokeMiterLimit,
320 fillType,
321 count,
322 };
323 PrimitiveFields mPrimitiveFields;
Nader Jawad5bed1f52020-09-25 00:27:29 -0700324 sk_sp<SkShader> fillGradient;
325 sk_sp<SkShader> strokeGradient;
Doris Liu1d8e1942016-03-02 15:16:28 -0800326 };
Doris Liu766431a2016-02-04 22:17:11 +0000327
Doris Liu1d8e1942016-03-02 15:16:28 -0800328 // Called from UI thread
John Reck1bcacfd2017-11-03 10:12:19 -0700329 FullPath(const FullPath& path); // for cloning
Doris Liu4bbc2932015-12-01 17:59:40 -0800330 FullPath(const char* path, size_t strLength) : Path(path, strLength) {}
331 FullPath() : Path() {}
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400332 void draw(SkCanvas* outCanvas, bool useStagingData) override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800333 void dump() override;
334 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; }
335 const FullPathProperties* stagingProperties() { return &mStagingProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800336
Doris Liu1d8e1942016-03-02 15:16:28 -0800337 // This should only be called from animations on RT
338 FullPathProperties* mutateProperties() { return &mProperties; }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800339
Doris Liu1d8e1942016-03-02 15:16:28 -0800340 virtual void syncProperties() override;
341 virtual void onPropertyChanged(Properties* properties) override {
342 Path::onPropertyChanged(properties);
343 if (properties == &mStagingProperties) {
344 mStagingPropertiesDirty = true;
345 if (mPropertyChangedListener) {
346 mPropertyChangedListener->onStagingPropertyChanged();
347 }
348 } else if (properties == &mProperties) {
349 if (mPropertyChangedListener) {
350 mPropertyChangedListener->onPropertyChanged();
351 }
352 }
Doris Liu4bbc2932015-12-01 17:59:40 -0800353 }
Doris Liu6b184d72017-12-04 16:31:07 -0800354 virtual void setAntiAlias(bool aa) { mAntiAlias = aa; }
John Reck08ee8152018-09-20 16:27:46 -0700355 void forEachFillColor(const std::function<void(SkColor)>& func) const override {
356 func(mStagingProperties.getFillColor());
357 }
Teng-Hui Zhudbee9bb2015-12-15 11:01:27 -0800358
Doris Liu4bbc2932015-12-01 17:59:40 -0800359protected:
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400360 const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800361
John Reck1bcacfd2017-11-03 10:12:19 -0700362private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800363 FullPathProperties mProperties = FullPathProperties(this);
364 FullPathProperties mStagingProperties = FullPathProperties(this);
365 bool mStagingPropertiesDirty = true;
366
367 // Intermediate data for drawing, render thread only
Doris Liu5a11e8d2016-02-04 20:04:10 +0000368 SkPath mTrimmedSkPath;
Doris Liu6b184d72017-12-04 16:31:07 -0800369 // Default to use AntiAlias
370 bool mAntiAlias = true;
Doris Liu4bbc2932015-12-01 17:59:40 -0800371};
372
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -0500373class ClipPath : public Path {
Doris Liu4bbc2932015-12-01 17:59:40 -0800374public:
375 ClipPath(const ClipPath& path) : Path(path) {}
376 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {}
377 ClipPath() : Path() {}
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400378 void draw(SkCanvas* outCanvas, bool useStagingData) override;
Doris Liu6b184d72017-12-04 16:31:07 -0800379 virtual void setAntiAlias(bool aa) {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800380};
381
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -0500382class Group : public Node {
Doris Liu4bbc2932015-12-01 17:59:40 -0800383public:
Doris Liu1d8e1942016-03-02 15:16:28 -0800384 class GroupProperties : public Properties {
385 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700386 explicit GroupProperties(Node* mNode) : Properties(mNode) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800387 struct PrimitiveFields {
388 float rotate = 0;
389 float pivotX = 0;
390 float pivotY = 0;
391 float scaleX = 1;
392 float scaleY = 1;
393 float translateX = 0;
394 float translateY = 0;
395 } mPrimitiveFields;
396 void syncProperties(const GroupProperties& prop) {
397 mPrimitiveFields = prop.mPrimitiveFields;
398 onPropertyChanged();
399 }
John Reck1bcacfd2017-11-03 10:12:19 -0700400 float getRotation() const { return mPrimitiveFields.rotate; }
401 void setRotation(float rotation) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation); }
402 float getPivotX() const { return mPrimitiveFields.pivotX; }
403 void setPivotX(float pivotX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX); }
404 float getPivotY() const { return mPrimitiveFields.pivotY; }
405 void setPivotY(float pivotY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY); }
406 float getScaleX() const { return mPrimitiveFields.scaleX; }
407 void setScaleX(float scaleX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX); }
408 float getScaleY() const { return mPrimitiveFields.scaleY; }
409 void setScaleY(float scaleY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY); }
410 float getTranslateX() const { return mPrimitiveFields.translateX; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800411 void setTranslateX(float translateX) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700412 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
Doris Liu1d8e1942016-03-02 15:16:28 -0800413 }
John Reck1bcacfd2017-11-03 10:12:19 -0700414 float getTranslateY() const { return mPrimitiveFields.translateY; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800415 void setTranslateY(float translateY) {
Doris Liu32d7cda2016-04-08 13:48:47 -0700416 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
Doris Liu1d8e1942016-03-02 15:16:28 -0800417 }
John Reck1bcacfd2017-11-03 10:12:19 -0700418 void updateProperties(float rotate, float pivotX, float pivotY, float scaleX, float scaleY,
419 float translateX, float translateY) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800420 mPrimitiveFields.rotate = rotate;
421 mPrimitiveFields.pivotX = pivotX;
422 mPrimitiveFields.pivotY = pivotY;
423 mPrimitiveFields.scaleX = scaleX;
424 mPrimitiveFields.scaleY = scaleY;
425 mPrimitiveFields.translateX = translateX;
426 mPrimitiveFields.translateY = translateY;
427 onPropertyChanged();
428 }
429 void setPropertyValue(int propertyId, float value);
430 float getPropertyValue(int propertyId) const;
431 bool copyProperties(float* outProperties, int length) const;
432 static bool isValidProperty(int propertyId);
John Reck1bcacfd2017-11-03 10:12:19 -0700433
Doris Liu1d8e1942016-03-02 15:16:28 -0800434 private:
435 enum class Property {
436 rotate = 0,
437 pivotX,
438 pivotY,
439 scaleX,
440 scaleY,
441 translateX,
442 translateY,
443 // Count of the properties, must be at the end.
444 count,
445 };
Doris Liu766431a2016-02-04 22:17:11 +0000446 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800447
Doris Liu4bbc2932015-12-01 17:59:40 -0800448 Group(const Group& group);
449 Group() {}
Doris Liu4bbc2932015-12-01 17:59:40 -0800450 void addChild(Node* child);
Doris Liu1d8e1942016-03-02 15:16:28 -0800451 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override {
452 Node::setPropertyChangedListener(listener);
453 for (auto& child : mChildren) {
John Reck1bcacfd2017-11-03 10:12:19 -0700454 child->setPropertyChangedListener(listener);
Doris Liu1d8e1942016-03-02 15:16:28 -0800455 }
456 }
457 virtual void syncProperties() override;
458 GroupProperties* mutateStagingProperties() { return &mStagingProperties; }
459 const GroupProperties* stagingProperties() { return &mStagingProperties; }
460
461 // This should only be called from animations on RT
462 GroupProperties* mutateProperties() { return &mProperties; }
463
464 // Methods below could be called from either UI thread or Render Thread.
Stan Ilievcc29a5d2017-03-15 16:37:10 -0400465 virtual void draw(SkCanvas* outCanvas, bool useStagingData) override;
Doris Liu1d8e1942016-03-02 15:16:28 -0800466 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties);
Doris Liu4bbc2932015-12-01 17:59:40 -0800467 void dump() override;
Doris Liu766431a2016-02-04 22:17:11 +0000468 static bool isValidProperty(int propertyId);
Doris Liu4bbc2932015-12-01 17:59:40 -0800469
Doris Liu1d8e1942016-03-02 15:16:28 -0800470 virtual void onPropertyChanged(Properties* properties) override {
471 if (properties == &mStagingProperties) {
472 mStagingPropertiesDirty = true;
473 if (mPropertyChangedListener) {
474 mPropertyChangedListener->onStagingPropertyChanged();
475 }
476 } else {
477 if (mPropertyChangedListener) {
478 mPropertyChangedListener->onPropertyChanged();
479 }
480 }
481 }
482
Doris Liu6b184d72017-12-04 16:31:07 -0800483 virtual void setAntiAlias(bool aa) {
484 for (auto& child : mChildren) {
485 child->setAntiAlias(aa);
486 }
487 }
488
John Reck08ee8152018-09-20 16:27:46 -0700489 void forEachFillColor(const std::function<void(SkColor)>& func) const override {
490 for (auto& child : mChildren) {
491 child->forEachFillColor(func);
492 }
493 }
494
Doris Liu4bbc2932015-12-01 17:59:40 -0800495private:
Doris Liu1d8e1942016-03-02 15:16:28 -0800496 GroupProperties mProperties = GroupProperties(this);
497 GroupProperties mStagingProperties = GroupProperties(this);
498 bool mStagingPropertiesDirty = true;
John Reck1bcacfd2017-11-03 10:12:19 -0700499 std::vector<std::unique_ptr<Node> > mChildren;
Doris Liu4bbc2932015-12-01 17:59:40 -0800500};
501
Derek Sollenberger3fedf5a2020-02-21 13:07:28 -0500502class Tree : public VirtualLightRefBase {
Doris Liu4bbc2932015-12-01 17:59:40 -0800503public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700504 explicit Tree(Group* rootNode) : mRootNode(rootNode) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800505 mRootNode->setPropertyChangedListener(&mPropertyChangedListener);
506 }
Doris Liu335d7d12016-05-26 15:19:15 -0700507
508 // Copy properties from the tree and use the give node as the root node
509 Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) {
John Reck08ee8152018-09-20 16:27:46 -0700510 mStagingProperties.syncAnimatableProperties(copy->stagingProperties());
511 mStagingProperties.syncNonAnimatableProperties(copy->stagingProperties());
Doris Liu335d7d12016-05-26 15:19:15 -0700512 }
Doris Liuf8d131c2016-04-29 18:41:29 -0700513 // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input
514 // canvas. Returns the number of pixels needed for the bitmap cache.
John Reck1bcacfd2017-11-03 10:12:19 -0700515 int draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds,
516 bool needsMirroring, bool canReuseCache);
Doris Liu1d8e1942016-03-02 15:16:28 -0800517 void drawStaging(Canvas* canvas);
Doris Liu4bbc2932015-12-01 17:59:40 -0800518
sergeyvfc9999502016-10-17 13:07:38 -0700519 Bitmap& getBitmapUpdateIfDirty();
John Reck1bcacfd2017-11-03 10:12:19 -0700520 void setAllowCaching(bool allowCaching) { mAllowCaching = allowCaching; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800521 void syncProperties() {
522 if (mStagingProperties.mNonAnimatablePropertiesDirty) {
John Reck1bcacfd2017-11-03 10:12:19 -0700523 mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth !=
524 mStagingProperties.mNonAnimatableProperties.viewportWidth) ||
525 (mProperties.mNonAnimatableProperties.viewportHeight !=
526 mStagingProperties.mNonAnimatableProperties.viewportHeight) ||
527 (mProperties.mNonAnimatableProperties.scaledWidth !=
528 mStagingProperties.mNonAnimatableProperties.scaledWidth) ||
529 (mProperties.mNonAnimatableProperties.scaledHeight !=
530 mStagingProperties.mNonAnimatableProperties.scaledHeight) ||
531 (mProperties.mNonAnimatableProperties.bounds !=
532 mStagingProperties.mNonAnimatableProperties.bounds);
Doris Liu1d8e1942016-03-02 15:16:28 -0800533 mProperties.syncNonAnimatableProperties(mStagingProperties);
534 mStagingProperties.mNonAnimatablePropertiesDirty = false;
535 }
536
537 if (mStagingProperties.mAnimatablePropertiesDirty) {
538 mProperties.syncAnimatableProperties(mStagingProperties);
539 } else {
540 mStagingProperties.syncAnimatableProperties(mProperties);
541 }
542 mStagingProperties.mAnimatablePropertiesDirty = false;
543 mRootNode->syncProperties();
Doris Liu4bbc2932015-12-01 17:59:40 -0800544 }
545
Doris Liu1d8e1942016-03-02 15:16:28 -0800546 class TreeProperties {
547 public:
Chih-Hung Hsieha619ec72016-08-29 14:52:43 -0700548 explicit TreeProperties(Tree* tree) : mTree(tree) {}
Doris Liu1d8e1942016-03-02 15:16:28 -0800549 // Properties that can only be modified by UI thread, therefore sync should
550 // only go from UI to RT
551 struct NonAnimatableProperties {
552 float viewportWidth = 0;
553 float viewportHeight = 0;
554 SkRect bounds;
555 int scaledWidth = 0;
556 int scaledHeight = 0;
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400557 sk_sp<SkColorFilter> colorFilter;
Doris Liu1d8e1942016-03-02 15:16:28 -0800558 } mNonAnimatableProperties;
559 bool mNonAnimatablePropertiesDirty = true;
560
561 float mRootAlpha = 1.0f;
562 bool mAnimatablePropertiesDirty = true;
563
564 void syncNonAnimatableProperties(const TreeProperties& prop) {
565 // Copy over the data that can only be changed in UI thread
566 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) {
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400567 mNonAnimatableProperties.colorFilter = prop.mNonAnimatableProperties.colorFilter;
Doris Liu1d8e1942016-03-02 15:16:28 -0800568 }
569 mNonAnimatableProperties = prop.mNonAnimatableProperties;
570 }
571
572 void setViewportSize(float width, float height) {
John Reck1bcacfd2017-11-03 10:12:19 -0700573 if (mNonAnimatableProperties.viewportWidth != width ||
574 mNonAnimatableProperties.viewportHeight != height) {
Doris Liu1d8e1942016-03-02 15:16:28 -0800575 mNonAnimatablePropertiesDirty = true;
576 mNonAnimatableProperties.viewportWidth = width;
577 mNonAnimatableProperties.viewportHeight = height;
578 mTree->onPropertyChanged(this);
579 }
580 }
581 void setBounds(const SkRect& bounds) {
582 if (mNonAnimatableProperties.bounds != bounds) {
583 mNonAnimatableProperties.bounds = bounds;
584 mNonAnimatablePropertiesDirty = true;
585 mTree->onPropertyChanged(this);
586 }
587 }
588
589 void setScaledSize(int width, int height) {
Teng-Hui Zhu037fc182016-11-16 10:29:39 -0800590 // If the requested size is bigger than what the bitmap was, then
591 // we increase the bitmap size to match. The width and height
592 // are bound by MAX_CACHED_BITMAP_SIZE.
John Reck1bcacfd2017-11-03 10:12:19 -0700593 if (mNonAnimatableProperties.scaledWidth < width ||
594 mNonAnimatableProperties.scaledHeight < height) {
595 mNonAnimatableProperties.scaledWidth =
596 std::max(width, mNonAnimatableProperties.scaledWidth);
597 mNonAnimatableProperties.scaledHeight =
598 std::max(height, mNonAnimatableProperties.scaledHeight);
Doris Liu1d8e1942016-03-02 15:16:28 -0800599 mNonAnimatablePropertiesDirty = true;
600 mTree->onPropertyChanged(this);
601 }
602 }
603 void setColorFilter(SkColorFilter* filter) {
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400604 if (mNonAnimatableProperties.colorFilter.get() != filter) {
605 mNonAnimatableProperties.colorFilter = sk_ref_sp(filter);
Doris Liu1d8e1942016-03-02 15:16:28 -0800606 mNonAnimatablePropertiesDirty = true;
607 mTree->onPropertyChanged(this);
608 }
609 }
Ben Wagnerc1a8a462018-07-12 12:41:28 -0400610 SkColorFilter* getColorFilter() const { return mNonAnimatableProperties.colorFilter.get(); }
Doris Liu1d8e1942016-03-02 15:16:28 -0800611
John Reck1bcacfd2017-11-03 10:12:19 -0700612 float getViewportWidth() const { return mNonAnimatableProperties.viewportWidth; }
613 float getViewportHeight() const { return mNonAnimatableProperties.viewportHeight; }
614 float getScaledWidth() const { return mNonAnimatableProperties.scaledWidth; }
615 float getScaledHeight() const { return mNonAnimatableProperties.scaledHeight; }
616 void syncAnimatableProperties(const TreeProperties& prop) { mRootAlpha = prop.mRootAlpha; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800617 bool setRootAlpha(float rootAlpha) {
618 if (rootAlpha != mRootAlpha) {
619 mAnimatablePropertiesDirty = true;
620 mRootAlpha = rootAlpha;
621 mTree->onPropertyChanged(this);
622 return true;
623 }
624 return false;
625 }
John Reck1bcacfd2017-11-03 10:12:19 -0700626 float getRootAlpha() const { return mRootAlpha; }
627 const SkRect& getBounds() const { return mNonAnimatableProperties.bounds; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800628 Tree* mTree;
629 };
630 void onPropertyChanged(TreeProperties* prop);
631 TreeProperties* mutateStagingProperties() { return &mStagingProperties; }
John Reck08ee8152018-09-20 16:27:46 -0700632 const TreeProperties& stagingProperties() const { return mStagingProperties; }
Doris Liu1d8e1942016-03-02 15:16:28 -0800633
634 // This should only be called from animations on RT
635 TreeProperties* mutateProperties() { return &mProperties; }
Doris Liu4bbc2932015-12-01 17:59:40 -0800636
Stan Iliev23c38a92017-03-23 00:12:50 -0400637 // called from RT only
638 const TreeProperties& properties() const { return mProperties; }
639
Doris Liu67ce99b2016-05-17 16:50:31 -0700640 // This should always be called from RT.
Doris Liu7c7052d2016-07-25 17:19:24 -0700641 void markDirty() { mCache.dirty = true; }
Doris Liu67ce99b2016-05-17 16:50:31 -0700642 bool isDirty() const { return mCache.dirty; }
643 bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; }
644 void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; }
645
Stan Iliev3310fb12017-03-23 16:56:51 -0400646 /**
647 * Draws VD cache into a canvas. This should always be called from RT and it works with Skia
648 * pipelines only.
649 */
John Reck08ee8152018-09-20 16:27:46 -0700650 void draw(SkCanvas* canvas, const SkRect& bounds, const SkPaint& paint);
651
Mike Reeda6cb58a2021-07-10 13:31:34 -0400652 void getPaintFor(Paint* outPaint, const TreeProperties &props) const;
John Reck08ee8152018-09-20 16:27:46 -0700653 BitmapPalette computePalette();
Stan Iliev23c38a92017-03-23 00:12:50 -0400654
Doris Liu6b184d72017-12-04 16:31:07 -0800655 void setAntiAlias(bool aa) { mRootNode->setAntiAlias(aa); }
656
Doris Liu4bbc2932015-12-01 17:59:40 -0800657private:
Stan Iliev3310fb12017-03-23 16:56:51 -0400658 class Cache {
659 public:
John Reck1bcacfd2017-11-03 10:12:19 -0700660 sk_sp<Bitmap> bitmap; // used by HWUI pipeline and software
sergeyvfc9999502016-10-17 13:07:38 -0700661 bool dirty = true;
662 };
Doris Liu1d8e1942016-03-02 15:16:28 -0800663
sergeyvfc9999502016-10-17 13:07:38 -0700664 bool allocateBitmapIfNeeded(Cache& cache, int width, int height);
665 bool canReuseBitmap(Bitmap*, int width, int height);
666 void updateBitmapCache(Bitmap& outCache, bool useStagingData);
Stan Iliev3310fb12017-03-23 16:56:51 -0400667
Doris Liu4bbc2932015-12-01 17:59:40 -0800668 // Cap the bitmap size, such that it won't hurt the performance too much
669 // and it won't crash due to a very large scale.
670 // The drawable will look blurry above this size.
671 const static int MAX_CACHED_BITMAP_SIZE;
672
Doris Liu4bbc2932015-12-01 17:59:40 -0800673 bool mAllowCaching = true;
Doris Liuef062eb2016-02-04 16:16:27 -0800674 std::unique_ptr<Group> mRootNode;
Doris Liu4bbc2932015-12-01 17:59:40 -0800675
Doris Liu1d8e1942016-03-02 15:16:28 -0800676 TreeProperties mProperties = TreeProperties(this);
677 TreeProperties mStagingProperties = TreeProperties(this);
678
Doris Liu1d8e1942016-03-02 15:16:28 -0800679 Cache mStagingCache;
680 Cache mCache;
681
John Reck1bcacfd2017-11-03 10:12:19 -0700682 PropertyChangedListener mPropertyChangedListener =
683 PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty);
Doris Liu67ce99b2016-05-17 16:50:31 -0700684
685 mutable bool mWillBeConsumed = false;
Doris Liu4bbc2932015-12-01 17:59:40 -0800686};
687
John Reck1bcacfd2017-11-03 10:12:19 -0700688} // namespace VectorDrawable
Doris Liu4bbc2932015-12-01 17:59:40 -0800689
690typedef VectorDrawable::Path::Data PathData;
John Reckd9d7f122018-05-03 14:40:56 -0700691typedef uirenderer::VectorDrawable::Tree VectorDrawableRoot;
692
John Reck1bcacfd2017-11-03 10:12:19 -0700693} // namespace uirenderer
694} // namespace android
Doris Liu4bbc2932015-12-01 17:59:40 -0800695
John Reck1bcacfd2017-11-03 10:12:19 -0700696#endif // ANDROID_HWUI_VPATH_H