VectorDrawable.h revision 1bcacfdcab0eaa0cee92bd7f5a1b5e271dd68e52
1/* 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 20#include "DisplayList.h" 21#include "hwui/Bitmap.h" 22#include "hwui/Canvas.h" 23#include "renderthread/CacheManager.h" 24 25#include <SkBitmap.h> 26#include <SkCanvas.h> 27#include <SkColor.h> 28#include <SkColorFilter.h> 29#include <SkMatrix.h> 30#include <SkPaint.h> 31#include <SkPath.h> 32#include <SkPathMeasure.h> 33#include <SkRect.h> 34#include <SkShader.h> 35#include <SkSurface.h> 36 37#include <cutils/compiler.h> 38#include <stddef.h> 39#include <string> 40#include <vector> 41 42namespace android { 43namespace uirenderer { 44 45// Debug 46#if DEBUG_VECTOR_DRAWABLE 47#define VECTOR_DRAWABLE_LOGD(...) ALOGD(__VA_ARGS__) 48#else 49#define VECTOR_DRAWABLE_LOGD(...) 50#endif 51 52namespace VectorDrawable { 53#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) \ 54 (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false) 55#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false) 56#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) \ 57 ({ \ 58 bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value)); \ 59 onPropertyChanged(); \ 60 retVal; \ 61 }) 62#define UPDATE_SKPROP(field, value) \ 63 ({ \ 64 bool retVal = ((field) != (value)); \ 65 if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); \ 66 retVal; \ 67 }) 68 69/* A VectorDrawable is composed of a tree of nodes. 70 * Each node can be a group node, or a path. 71 * A group node can have groups or paths as children, but a path node has 72 * no children. 73 * One example can be: 74 * Root Group 75 * / | \ 76 * Group Path Group 77 * / \ | 78 * Path Path Path 79 * 80 * VectorDrawables are drawn into bitmap caches first, then the caches are drawn to the given 81 * canvas with root alpha applied. Two caches are maintained for VD, one in UI thread, the other in 82 * Render Thread. A generation id is used to keep track of changes in the vector drawable tree. 83 * Each cache has their own generation id to track whether they are up to date with the latest 84 * change in the tree. 85 * 86 * Any property change to the vector drawable coming from UI thread (such as bulk setters to update 87 * all the properties, and viewport change, etc.) are only modifying the staging properties. The 88 * staging properties will then be marked dirty and will be pushed over to render thread properties 89 * at sync point. If staging properties are not dirty at sync point, we sync backwards by updating 90 * staging properties with render thread properties to reflect the latest animation value. 91 * 92 */ 93 94class PropertyChangedListener { 95public: 96 PropertyChangedListener(bool* dirty, bool* stagingDirty) 97 : mDirty(dirty), mStagingDirty(stagingDirty) {} 98 void onPropertyChanged() { *mDirty = true; } 99 void onStagingPropertyChanged() { *mStagingDirty = true; } 100 101private: 102 bool* mDirty; 103 bool* mStagingDirty; 104}; 105 106class ANDROID_API Node { 107public: 108 class Properties { 109 public: 110 explicit Properties(Node* node) : mNode(node) {} 111 inline void onPropertyChanged() { mNode->onPropertyChanged(this); } 112 113 private: 114 Node* mNode; 115 }; 116 Node(const Node& node) { mName = node.mName; } 117 Node() {} 118 virtual void draw(SkCanvas* outCanvas, bool useStagingData) = 0; 119 virtual void dump() = 0; 120 void setName(const char* name) { mName = name; } 121 virtual void setPropertyChangedListener(PropertyChangedListener* listener) { 122 mPropertyChangedListener = listener; 123 } 124 virtual void onPropertyChanged(Properties* properties) = 0; 125 virtual ~Node() {} 126 virtual void syncProperties() = 0; 127 128protected: 129 std::string mName; 130 PropertyChangedListener* mPropertyChangedListener = nullptr; 131}; 132 133class ANDROID_API Path : public Node { 134public: 135 struct ANDROID_API Data { 136 std::vector<char> verbs; 137 std::vector<size_t> verbSizes; 138 std::vector<float> points; 139 bool operator==(const Data& data) const { 140 return verbs == data.verbs && verbSizes == data.verbSizes && points == data.points; 141 } 142 }; 143 144 class PathProperties : public Properties { 145 public: 146 explicit PathProperties(Node* node) : Properties(node) {} 147 void syncProperties(const PathProperties& prop) { 148 mData = prop.mData; 149 onPropertyChanged(); 150 } 151 void setData(const Data& data) { 152 // Updates the path data. Note that we don't generate a new Skia path right away 153 // because there are cases where the animation is changing the path data, but the view 154 // that hosts the VD has gone off screen, in which case we won't even draw. So we 155 // postpone the Skia path generation to the draw time. 156 if (data == mData) { 157 return; 158 } 159 mData = data; 160 onPropertyChanged(); 161 } 162 const Data& getData() const { return mData; } 163 164 private: 165 Data mData; 166 }; 167 168 Path(const Path& path); 169 Path(const char* path, size_t strLength); 170 Path() {} 171 172 void dump() override; 173 virtual void syncProperties() override; 174 virtual void onPropertyChanged(Properties* prop) override { 175 if (prop == &mStagingProperties) { 176 mStagingPropertiesDirty = true; 177 if (mPropertyChangedListener) { 178 mPropertyChangedListener->onStagingPropertyChanged(); 179 } 180 } else if (prop == &mProperties) { 181 mSkPathDirty = true; 182 if (mPropertyChangedListener) { 183 mPropertyChangedListener->onPropertyChanged(); 184 } 185 } 186 } 187 PathProperties* mutateStagingProperties() { return &mStagingProperties; } 188 const PathProperties* stagingProperties() { return &mStagingProperties; } 189 190 // This should only be called from animations on RT 191 PathProperties* mutateProperties() { return &mProperties; } 192 193protected: 194 virtual const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath); 195 196 // Internal data, render thread only. 197 bool mSkPathDirty = true; 198 SkPath mSkPath; 199 200private: 201 PathProperties mProperties = PathProperties(this); 202 PathProperties mStagingProperties = PathProperties(this); 203 bool mStagingPropertiesDirty = true; 204}; 205 206class ANDROID_API FullPath : public Path { 207public: 208 class FullPathProperties : public Properties { 209 public: 210 struct PrimitiveFields { 211 float strokeWidth = 0; 212 SkColor strokeColor = SK_ColorTRANSPARENT; 213 float strokeAlpha = 1; 214 SkColor fillColor = SK_ColorTRANSPARENT; 215 float fillAlpha = 1; 216 float trimPathStart = 0; 217 float trimPathEnd = 1; 218 float trimPathOffset = 0; 219 int32_t strokeLineCap = SkPaint::Cap::kButt_Cap; 220 int32_t strokeLineJoin = SkPaint::Join::kMiter_Join; 221 float strokeMiterLimit = 4; 222 int fillType = 0; /* non-zero or kWinding_FillType in Skia */ 223 }; 224 explicit FullPathProperties(Node* mNode) : Properties(mNode), mTrimDirty(false) {} 225 ~FullPathProperties() { 226 SkSafeUnref(fillGradient); 227 SkSafeUnref(strokeGradient); 228 } 229 void syncProperties(const FullPathProperties& prop) { 230 mPrimitiveFields = prop.mPrimitiveFields; 231 mTrimDirty = true; 232 UPDATE_SKPROP(fillGradient, prop.fillGradient); 233 UPDATE_SKPROP(strokeGradient, prop.strokeGradient); 234 onPropertyChanged(); 235 } 236 void setFillGradient(SkShader* gradient) { 237 if (UPDATE_SKPROP(fillGradient, gradient)) { 238 onPropertyChanged(); 239 } 240 } 241 void setStrokeGradient(SkShader* gradient) { 242 if (UPDATE_SKPROP(strokeGradient, gradient)) { 243 onPropertyChanged(); 244 } 245 } 246 SkShader* getFillGradient() const { return fillGradient; } 247 SkShader* getStrokeGradient() const { return strokeGradient; } 248 float getStrokeWidth() const { return mPrimitiveFields.strokeWidth; } 249 void setStrokeWidth(float strokeWidth) { 250 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth); 251 } 252 SkColor getStrokeColor() const { return mPrimitiveFields.strokeColor; } 253 void setStrokeColor(SkColor strokeColor) { 254 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor); 255 } 256 float getStrokeAlpha() const { return mPrimitiveFields.strokeAlpha; } 257 void setStrokeAlpha(float strokeAlpha) { 258 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha); 259 } 260 SkColor getFillColor() const { return mPrimitiveFields.fillColor; } 261 void setFillColor(SkColor fillColor) { 262 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor); 263 } 264 float getFillAlpha() const { return mPrimitiveFields.fillAlpha; } 265 void setFillAlpha(float fillAlpha) { 266 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha); 267 } 268 float getTrimPathStart() const { return mPrimitiveFields.trimPathStart; } 269 void setTrimPathStart(float trimPathStart) { 270 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty); 271 } 272 float getTrimPathEnd() const { return mPrimitiveFields.trimPathEnd; } 273 void setTrimPathEnd(float trimPathEnd) { 274 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty); 275 } 276 float getTrimPathOffset() const { return mPrimitiveFields.trimPathOffset; } 277 void setTrimPathOffset(float trimPathOffset) { 278 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty); 279 } 280 281 float getStrokeMiterLimit() const { return mPrimitiveFields.strokeMiterLimit; } 282 float getStrokeLineCap() const { return mPrimitiveFields.strokeLineCap; } 283 float getStrokeLineJoin() const { return mPrimitiveFields.strokeLineJoin; } 284 float getFillType() const { return mPrimitiveFields.fillType; } 285 bool copyProperties(int8_t* outProperties, int length) const; 286 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha, 287 SkColor fillColor, float fillAlpha, float trimPathStart, 288 float trimPathEnd, float trimPathOffset, float strokeMiterLimit, 289 int strokeLineCap, int strokeLineJoin, int fillType) { 290 mPrimitiveFields.strokeWidth = strokeWidth; 291 mPrimitiveFields.strokeColor = strokeColor; 292 mPrimitiveFields.strokeAlpha = strokeAlpha; 293 mPrimitiveFields.fillColor = fillColor; 294 mPrimitiveFields.fillAlpha = fillAlpha; 295 mPrimitiveFields.trimPathStart = trimPathStart; 296 mPrimitiveFields.trimPathEnd = trimPathEnd; 297 mPrimitiveFields.trimPathOffset = trimPathOffset; 298 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit; 299 mPrimitiveFields.strokeLineCap = strokeLineCap; 300 mPrimitiveFields.strokeLineJoin = strokeLineJoin; 301 mPrimitiveFields.fillType = fillType; 302 mTrimDirty = true; 303 onPropertyChanged(); 304 } 305 // Set property values during animation 306 void setColorPropertyValue(int propertyId, int32_t value); 307 void setPropertyValue(int propertyId, float value); 308 bool mTrimDirty; 309 310 private: 311 enum class Property { 312 strokeWidth = 0, 313 strokeColor, 314 strokeAlpha, 315 fillColor, 316 fillAlpha, 317 trimPathStart, 318 trimPathEnd, 319 trimPathOffset, 320 strokeLineCap, 321 strokeLineJoin, 322 strokeMiterLimit, 323 fillType, 324 count, 325 }; 326 PrimitiveFields mPrimitiveFields; 327 SkShader* fillGradient = nullptr; 328 SkShader* strokeGradient = nullptr; 329 }; 330 331 // Called from UI thread 332 FullPath(const FullPath& path); // for cloning 333 FullPath(const char* path, size_t strLength) : Path(path, strLength) {} 334 FullPath() : Path() {} 335 void draw(SkCanvas* outCanvas, bool useStagingData) override; 336 void dump() override; 337 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; } 338 const FullPathProperties* stagingProperties() { return &mStagingProperties; } 339 340 // This should only be called from animations on RT 341 FullPathProperties* mutateProperties() { return &mProperties; } 342 343 virtual void syncProperties() override; 344 virtual void onPropertyChanged(Properties* properties) override { 345 Path::onPropertyChanged(properties); 346 if (properties == &mStagingProperties) { 347 mStagingPropertiesDirty = true; 348 if (mPropertyChangedListener) { 349 mPropertyChangedListener->onStagingPropertyChanged(); 350 } 351 } else if (properties == &mProperties) { 352 if (mPropertyChangedListener) { 353 mPropertyChangedListener->onPropertyChanged(); 354 } 355 } 356 } 357 358protected: 359 const SkPath& getUpdatedPath(bool useStagingData, SkPath* tempStagingPath) override; 360 361private: 362 FullPathProperties mProperties = FullPathProperties(this); 363 FullPathProperties mStagingProperties = FullPathProperties(this); 364 bool mStagingPropertiesDirty = true; 365 366 // Intermediate data for drawing, render thread only 367 SkPath mTrimmedSkPath; 368}; 369 370class ANDROID_API ClipPath : public Path { 371public: 372 ClipPath(const ClipPath& path) : Path(path) {} 373 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {} 374 ClipPath() : Path() {} 375 void draw(SkCanvas* outCanvas, bool useStagingData) override; 376}; 377 378class ANDROID_API Group : public Node { 379public: 380 class GroupProperties : public Properties { 381 public: 382 explicit GroupProperties(Node* mNode) : Properties(mNode) {} 383 struct PrimitiveFields { 384 float rotate = 0; 385 float pivotX = 0; 386 float pivotY = 0; 387 float scaleX = 1; 388 float scaleY = 1; 389 float translateX = 0; 390 float translateY = 0; 391 } mPrimitiveFields; 392 void syncProperties(const GroupProperties& prop) { 393 mPrimitiveFields = prop.mPrimitiveFields; 394 onPropertyChanged(); 395 } 396 float getRotation() const { return mPrimitiveFields.rotate; } 397 void setRotation(float rotation) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation); } 398 float getPivotX() const { return mPrimitiveFields.pivotX; } 399 void setPivotX(float pivotX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX); } 400 float getPivotY() const { return mPrimitiveFields.pivotY; } 401 void setPivotY(float pivotY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY); } 402 float getScaleX() const { return mPrimitiveFields.scaleX; } 403 void setScaleX(float scaleX) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX); } 404 float getScaleY() const { return mPrimitiveFields.scaleY; } 405 void setScaleY(float scaleY) { VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY); } 406 float getTranslateX() const { return mPrimitiveFields.translateX; } 407 void setTranslateX(float translateX) { 408 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX); 409 } 410 float getTranslateY() const { return mPrimitiveFields.translateY; } 411 void setTranslateY(float translateY) { 412 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY); 413 } 414 void updateProperties(float rotate, float pivotX, float pivotY, float scaleX, float scaleY, 415 float translateX, float translateY) { 416 mPrimitiveFields.rotate = rotate; 417 mPrimitiveFields.pivotX = pivotX; 418 mPrimitiveFields.pivotY = pivotY; 419 mPrimitiveFields.scaleX = scaleX; 420 mPrimitiveFields.scaleY = scaleY; 421 mPrimitiveFields.translateX = translateX; 422 mPrimitiveFields.translateY = translateY; 423 onPropertyChanged(); 424 } 425 void setPropertyValue(int propertyId, float value); 426 float getPropertyValue(int propertyId) const; 427 bool copyProperties(float* outProperties, int length) const; 428 static bool isValidProperty(int propertyId); 429 430 private: 431 enum class Property { 432 rotate = 0, 433 pivotX, 434 pivotY, 435 scaleX, 436 scaleY, 437 translateX, 438 translateY, 439 // Count of the properties, must be at the end. 440 count, 441 }; 442 }; 443 444 Group(const Group& group); 445 Group() {} 446 void addChild(Node* child); 447 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override { 448 Node::setPropertyChangedListener(listener); 449 for (auto& child : mChildren) { 450 child->setPropertyChangedListener(listener); 451 } 452 } 453 virtual void syncProperties() override; 454 GroupProperties* mutateStagingProperties() { return &mStagingProperties; } 455 const GroupProperties* stagingProperties() { return &mStagingProperties; } 456 457 // This should only be called from animations on RT 458 GroupProperties* mutateProperties() { return &mProperties; } 459 460 // Methods below could be called from either UI thread or Render Thread. 461 virtual void draw(SkCanvas* outCanvas, bool useStagingData) override; 462 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties); 463 void dump() override; 464 static bool isValidProperty(int propertyId); 465 466 virtual void onPropertyChanged(Properties* properties) override { 467 if (properties == &mStagingProperties) { 468 mStagingPropertiesDirty = true; 469 if (mPropertyChangedListener) { 470 mPropertyChangedListener->onStagingPropertyChanged(); 471 } 472 } else { 473 if (mPropertyChangedListener) { 474 mPropertyChangedListener->onPropertyChanged(); 475 } 476 } 477 } 478 479private: 480 GroupProperties mProperties = GroupProperties(this); 481 GroupProperties mStagingProperties = GroupProperties(this); 482 bool mStagingPropertiesDirty = true; 483 std::vector<std::unique_ptr<Node> > mChildren; 484}; 485 486class ANDROID_API Tree : public VirtualLightRefBase { 487public: 488 explicit Tree(Group* rootNode) : mRootNode(rootNode) { 489 mRootNode->setPropertyChangedListener(&mPropertyChangedListener); 490 } 491 492 // Copy properties from the tree and use the give node as the root node 493 Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) { 494 mStagingProperties.syncAnimatableProperties(*copy->stagingProperties()); 495 mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties()); 496 } 497 // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input 498 // canvas. Returns the number of pixels needed for the bitmap cache. 499 int draw(Canvas* outCanvas, SkColorFilter* colorFilter, const SkRect& bounds, 500 bool needsMirroring, bool canReuseCache); 501 void drawStaging(Canvas* canvas); 502 503 Bitmap& getBitmapUpdateIfDirty(); 504 void setAllowCaching(bool allowCaching) { mAllowCaching = allowCaching; } 505 SkPaint* getPaint(); 506 void syncProperties() { 507 if (mStagingProperties.mNonAnimatablePropertiesDirty) { 508 mCache.dirty |= (mProperties.mNonAnimatableProperties.viewportWidth != 509 mStagingProperties.mNonAnimatableProperties.viewportWidth) || 510 (mProperties.mNonAnimatableProperties.viewportHeight != 511 mStagingProperties.mNonAnimatableProperties.viewportHeight) || 512 (mProperties.mNonAnimatableProperties.scaledWidth != 513 mStagingProperties.mNonAnimatableProperties.scaledWidth) || 514 (mProperties.mNonAnimatableProperties.scaledHeight != 515 mStagingProperties.mNonAnimatableProperties.scaledHeight) || 516 (mProperties.mNonAnimatableProperties.bounds != 517 mStagingProperties.mNonAnimatableProperties.bounds); 518 mProperties.syncNonAnimatableProperties(mStagingProperties); 519 mStagingProperties.mNonAnimatablePropertiesDirty = false; 520 } 521 522 if (mStagingProperties.mAnimatablePropertiesDirty) { 523 mProperties.syncAnimatableProperties(mStagingProperties); 524 } else { 525 mStagingProperties.syncAnimatableProperties(mProperties); 526 } 527 mStagingProperties.mAnimatablePropertiesDirty = false; 528 mRootNode->syncProperties(); 529 } 530 531 class TreeProperties { 532 public: 533 explicit TreeProperties(Tree* tree) : mTree(tree) {} 534 // Properties that can only be modified by UI thread, therefore sync should 535 // only go from UI to RT 536 struct NonAnimatableProperties { 537 float viewportWidth = 0; 538 float viewportHeight = 0; 539 SkRect bounds; 540 int scaledWidth = 0; 541 int scaledHeight = 0; 542 SkColorFilter* colorFilter = nullptr; 543 ~NonAnimatableProperties() { SkSafeUnref(colorFilter); } 544 } mNonAnimatableProperties; 545 bool mNonAnimatablePropertiesDirty = true; 546 547 float mRootAlpha = 1.0f; 548 bool mAnimatablePropertiesDirty = true; 549 550 void syncNonAnimatableProperties(const TreeProperties& prop) { 551 // Copy over the data that can only be changed in UI thread 552 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) { 553 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter, 554 prop.mNonAnimatableProperties.colorFilter); 555 } 556 mNonAnimatableProperties = prop.mNonAnimatableProperties; 557 } 558 559 void setViewportSize(float width, float height) { 560 if (mNonAnimatableProperties.viewportWidth != width || 561 mNonAnimatableProperties.viewportHeight != height) { 562 mNonAnimatablePropertiesDirty = true; 563 mNonAnimatableProperties.viewportWidth = width; 564 mNonAnimatableProperties.viewportHeight = height; 565 mTree->onPropertyChanged(this); 566 } 567 } 568 void setBounds(const SkRect& bounds) { 569 if (mNonAnimatableProperties.bounds != bounds) { 570 mNonAnimatableProperties.bounds = bounds; 571 mNonAnimatablePropertiesDirty = true; 572 mTree->onPropertyChanged(this); 573 } 574 } 575 576 void setScaledSize(int width, int height) { 577 // If the requested size is bigger than what the bitmap was, then 578 // we increase the bitmap size to match. The width and height 579 // are bound by MAX_CACHED_BITMAP_SIZE. 580 if (mNonAnimatableProperties.scaledWidth < width || 581 mNonAnimatableProperties.scaledHeight < height) { 582 mNonAnimatableProperties.scaledWidth = 583 std::max(width, mNonAnimatableProperties.scaledWidth); 584 mNonAnimatableProperties.scaledHeight = 585 std::max(height, mNonAnimatableProperties.scaledHeight); 586 mNonAnimatablePropertiesDirty = true; 587 mTree->onPropertyChanged(this); 588 } 589 } 590 void setColorFilter(SkColorFilter* filter) { 591 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) { 592 mNonAnimatablePropertiesDirty = true; 593 mTree->onPropertyChanged(this); 594 } 595 } 596 SkColorFilter* getColorFilter() const { return mNonAnimatableProperties.colorFilter; } 597 598 float getViewportWidth() const { return mNonAnimatableProperties.viewportWidth; } 599 float getViewportHeight() const { return mNonAnimatableProperties.viewportHeight; } 600 float getScaledWidth() const { return mNonAnimatableProperties.scaledWidth; } 601 float getScaledHeight() const { return mNonAnimatableProperties.scaledHeight; } 602 void syncAnimatableProperties(const TreeProperties& prop) { mRootAlpha = prop.mRootAlpha; } 603 bool setRootAlpha(float rootAlpha) { 604 if (rootAlpha != mRootAlpha) { 605 mAnimatablePropertiesDirty = true; 606 mRootAlpha = rootAlpha; 607 mTree->onPropertyChanged(this); 608 return true; 609 } 610 return false; 611 } 612 float getRootAlpha() const { return mRootAlpha; } 613 const SkRect& getBounds() const { return mNonAnimatableProperties.bounds; } 614 Tree* mTree; 615 }; 616 void onPropertyChanged(TreeProperties* prop); 617 TreeProperties* mutateStagingProperties() { return &mStagingProperties; } 618 const TreeProperties* stagingProperties() const { return &mStagingProperties; } 619 620 // This should only be called from animations on RT 621 TreeProperties* mutateProperties() { return &mProperties; } 622 623 // called from RT only 624 const TreeProperties& properties() const { return mProperties; } 625 626 // This should always be called from RT. 627 void markDirty() { mCache.dirty = true; } 628 bool isDirty() const { return mCache.dirty; } 629 bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; } 630 void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; } 631 632 /** 633 * Draws VD cache into a canvas. This should always be called from RT and it works with Skia 634 * pipelines only. 635 */ 636 void draw(SkCanvas* canvas); 637 638 /** 639 * Draws VD into a GPU backed surface. 640 * This should always be called from RT and it works with Skia pipeline only. 641 */ 642 void updateCache(sp<skiapipeline::VectorDrawableAtlas>& atlas, GrContext* context); 643 644private: 645 class Cache { 646 public: 647 sk_sp<Bitmap> bitmap; // used by HWUI pipeline and software 648 // TODO: use surface instead of bitmap when drawing in software canvas 649 bool dirty = true; 650 651 // the rest of the code in Cache is used by Skia pipelines only 652 653 ~Cache() { clear(); } 654 655 /** 656 * Stores a weak pointer to the atlas and a key. 657 */ 658 void setAtlas(sp<skiapipeline::VectorDrawableAtlas> atlas, 659 skiapipeline::AtlasKey newAtlasKey); 660 661 /** 662 * Gets a surface and bounds from the atlas. 663 * 664 * @return nullptr if the altas has been deleted. 665 */ 666 sk_sp<SkSurface> getSurface(SkRect* bounds); 667 668 /** 669 * Releases atlas key from the atlas, which makes it available for reuse. 670 */ 671 void clear(); 672 673 private: 674 wp<skiapipeline::VectorDrawableAtlas> mAtlas; 675 skiapipeline::AtlasKey mAtlasKey = INVALID_ATLAS_KEY; 676 }; 677 678 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop); 679 bool allocateBitmapIfNeeded(Cache& cache, int width, int height); 680 bool canReuseBitmap(Bitmap*, int width, int height); 681 void updateBitmapCache(Bitmap& outCache, bool useStagingData); 682 683 // Cap the bitmap size, such that it won't hurt the performance too much 684 // and it won't crash due to a very large scale. 685 // The drawable will look blurry above this size. 686 const static int MAX_CACHED_BITMAP_SIZE; 687 688 bool mAllowCaching = true; 689 std::unique_ptr<Group> mRootNode; 690 691 TreeProperties mProperties = TreeProperties(this); 692 TreeProperties mStagingProperties = TreeProperties(this); 693 694 SkPaint mPaint; 695 696 Cache mStagingCache; 697 Cache mCache; 698 699 PropertyChangedListener mPropertyChangedListener = 700 PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty); 701 702 mutable bool mWillBeConsumed = false; 703}; 704 705} // namespace VectorDrawable 706 707typedef VectorDrawable::Path::Data PathData; 708} // namespace uirenderer 709} // namespace android 710 711#endif // ANDROID_HWUI_VPATH_H 712