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