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 39 namespace android { 40 namespace uirenderer { 41 42 namespace VectorDrawable { 43 #define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false) 44 #define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false) 45 #define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\ 46 onPropertyChanged(); retVal;}) 47 #define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;}) 48 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 * 60 * 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 * 72 */ 73 74 class PropertyChangedListener { 75 public: 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 } 84 private: 85 bool* mDirty; 86 bool* mStagingDirty; 87 }; 88 89 class ANDROID_API Node { 90 public: 91 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 }; 100 Node(const Node& node) { 101 mName = node.mName; 102 } 103 Node() {} 104 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, 105 float scaleX, float scaleY, bool useStagingData) = 0; 106 virtual void dump() = 0; 107 void setName(const char* name) { 108 mName = name; 109 } 110 virtual void setPropertyChangedListener(PropertyChangedListener* listener) { 111 mPropertyChangedListener = listener; 112 } 113 virtual void onPropertyChanged(Properties* properties) = 0; 114 virtual ~Node(){} 115 virtual void syncProperties() = 0; 116 protected: 117 std::string mName; 118 PropertyChangedListener* mPropertyChangedListener = nullptr; 119 }; 120 121 class ANDROID_API Path : public Node { 122 public: 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 }; 132 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 159 Path(const Path& path); 160 Path(const char* path, size_t strLength); 161 Path() {} 162 163 void dump() override; 164 void draw(SkCanvas* outCanvas, const SkMatrix& groupStackedMatrix, 165 float scaleX, float scaleY, bool useStagingData) override; 166 static float getMatrixScale(const SkMatrix& groupStackedMatrix); 167 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; } 186 187 protected: 188 virtual const SkPath& getUpdatedPath(); 189 virtual void getStagingPath(SkPath* outPath); 190 virtual void drawPath(SkCanvas *outCanvas, SkPath& renderPath, 191 float strokeScale, const SkMatrix& matrix, bool useStagingData) = 0; 192 193 // Internal data, render thread only. 194 bool mSkPathDirty = true; 195 SkPath mSkPath; 196 197 private: 198 PathProperties mProperties = PathProperties(this); 199 PathProperties mStagingProperties = PathProperties(this); 200 bool mStagingPropertiesDirty = true; 201 }; 202 203 class ANDROID_API FullPath: public Path { 204 public: 205 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 ~FullPathProperties() { 223 SkSafeUnref(fillGradient); 224 SkSafeUnref(strokeGradient); 225 } 226 void syncProperties(const FullPathProperties& prop) { 227 mPrimitiveFields = prop.mPrimitiveFields; 228 mTrimDirty = true; 229 UPDATE_SKPROP(fillGradient, prop.fillGradient); 230 UPDATE_SKPROP(strokeGradient, prop.strokeGradient); 231 onPropertyChanged(); 232 } 233 void setFillGradient(SkShader* gradient) { 234 if(UPDATE_SKPROP(fillGradient, gradient)) { 235 onPropertyChanged(); 236 } 237 } 238 void setStrokeGradient(SkShader* gradient) { 239 if(UPDATE_SKPROP(strokeGradient, gradient)) { 240 onPropertyChanged(); 241 } 242 } 243 SkShader* getFillGradient() const { 244 return fillGradient; 245 } 246 SkShader* getStrokeGradient() const { 247 return strokeGradient; 248 } 249 float getStrokeWidth() const{ 250 return mPrimitiveFields.strokeWidth; 251 } 252 void setStrokeWidth(float strokeWidth) { 253 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth); 254 } 255 SkColor getStrokeColor() const{ 256 return mPrimitiveFields.strokeColor; 257 } 258 void setStrokeColor(SkColor strokeColor) { 259 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor); 260 } 261 float getStrokeAlpha() const{ 262 return mPrimitiveFields.strokeAlpha; 263 } 264 void setStrokeAlpha(float strokeAlpha) { 265 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha); 266 } 267 SkColor getFillColor() const { 268 return mPrimitiveFields.fillColor; 269 } 270 void setFillColor(SkColor fillColor) { 271 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor); 272 } 273 float getFillAlpha() const{ 274 return mPrimitiveFields.fillAlpha; 275 } 276 void setFillAlpha(float fillAlpha) { 277 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha); 278 } 279 float getTrimPathStart() const{ 280 return mPrimitiveFields.trimPathStart; 281 } 282 void setTrimPathStart(float trimPathStart) { 283 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty); 284 } 285 float getTrimPathEnd() const{ 286 return mPrimitiveFields.trimPathEnd; 287 } 288 void setTrimPathEnd(float trimPathEnd) { 289 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty); 290 } 291 float getTrimPathOffset() const{ 292 return mPrimitiveFields.trimPathOffset; 293 } 294 void setTrimPathOffset(float trimPathOffset) { 295 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty); 296 } 297 298 float getStrokeMiterLimit() const { 299 return mPrimitiveFields.strokeMiterLimit; 300 } 301 float getStrokeLineCap() const { 302 return mPrimitiveFields.strokeLineCap; 303 } 304 float getStrokeLineJoin() const { 305 return mPrimitiveFields.strokeLineJoin; 306 } 307 float getFillType() const { 308 return mPrimitiveFields.fillType; 309 } 310 bool copyProperties(int8_t* outProperties, int length) const; 311 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha, 312 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd, 313 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin, 314 int fillType) { 315 mPrimitiveFields.strokeWidth = strokeWidth; 316 mPrimitiveFields.strokeColor = strokeColor; 317 mPrimitiveFields.strokeAlpha = strokeAlpha; 318 mPrimitiveFields.fillColor = fillColor; 319 mPrimitiveFields.fillAlpha = fillAlpha; 320 mPrimitiveFields.trimPathStart = trimPathStart; 321 mPrimitiveFields.trimPathEnd = trimPathEnd; 322 mPrimitiveFields.trimPathOffset = trimPathOffset; 323 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit; 324 mPrimitiveFields.strokeLineCap = strokeLineCap; 325 mPrimitiveFields.strokeLineJoin = strokeLineJoin; 326 mPrimitiveFields.fillType = fillType; 327 mTrimDirty = true; 328 onPropertyChanged(); 329 } 330 // Set property values during animation 331 void setColorPropertyValue(int propertyId, int32_t value); 332 void setPropertyValue(int propertyId, float value); 333 bool mTrimDirty; 334 private: 335 enum class Property { 336 strokeWidth = 0, 337 strokeColor, 338 strokeAlpha, 339 fillColor, 340 fillAlpha, 341 trimPathStart, 342 trimPathEnd, 343 trimPathOffset, 344 strokeLineCap, 345 strokeLineJoin, 346 strokeMiterLimit, 347 fillType, 348 count, 349 }; 350 PrimitiveFields mPrimitiveFields; 351 SkShader* fillGradient = nullptr; 352 SkShader* strokeGradient = nullptr; 353 }; 354 355 // Called from UI thread 356 FullPath(const FullPath& path); // for cloning 357 FullPath(const char* path, size_t strLength) : Path(path, strLength) {} 358 FullPath() : Path() {} 359 void dump() override; 360 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; } 361 const FullPathProperties* stagingProperties() { return &mStagingProperties; } 362 363 // This should only be called from animations on RT 364 FullPathProperties* mutateProperties() { return &mProperties; } 365 366 virtual void syncProperties() override; 367 virtual void onPropertyChanged(Properties* properties) override { 368 Path::onPropertyChanged(properties); 369 if (properties == &mStagingProperties) { 370 mStagingPropertiesDirty = true; 371 if (mPropertyChangedListener) { 372 mPropertyChangedListener->onStagingPropertyChanged(); 373 } 374 } else if (properties == &mProperties) { 375 if (mPropertyChangedListener) { 376 mPropertyChangedListener->onPropertyChanged(); 377 } 378 } 379 } 380 381 protected: 382 const SkPath& getUpdatedPath() override; 383 void getStagingPath(SkPath* outPath) override; 384 void drawPath(SkCanvas* outCanvas, SkPath& renderPath, 385 float strokeScale, const SkMatrix& matrix, bool useStagingData) override; 386 private: 387 388 FullPathProperties mProperties = FullPathProperties(this); 389 FullPathProperties mStagingProperties = FullPathProperties(this); 390 bool mStagingPropertiesDirty = true; 391 392 // Intermediate data for drawing, render thread only 393 SkPath mTrimmedSkPath; 394 395 }; 396 397 class ANDROID_API ClipPath: public Path { 398 public: 399 ClipPath(const ClipPath& path) : Path(path) {} 400 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {} 401 ClipPath() : Path() {} 402 403 protected: 404 void drawPath(SkCanvas* outCanvas, SkPath& renderPath, 405 float strokeScale, const SkMatrix& matrix, bool useStagingData) override; 406 }; 407 408 class ANDROID_API Group: public Node { 409 public: 410 class GroupProperties : public Properties { 411 public: 412 GroupProperties(Node* mNode) : Properties(mNode) {} 413 struct PrimitiveFields { 414 float rotate = 0; 415 float pivotX = 0; 416 float pivotY = 0; 417 float scaleX = 1; 418 float scaleY = 1; 419 float translateX = 0; 420 float translateY = 0; 421 } mPrimitiveFields; 422 void syncProperties(const GroupProperties& prop) { 423 mPrimitiveFields = prop.mPrimitiveFields; 424 onPropertyChanged(); 425 } 426 float getRotation() const { 427 return mPrimitiveFields.rotate; 428 } 429 void setRotation(float rotation) { 430 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation); 431 } 432 float getPivotX() const { 433 return mPrimitiveFields.pivotX; 434 } 435 void setPivotX(float pivotX) { 436 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX); 437 } 438 float getPivotY() const { 439 return mPrimitiveFields.pivotY; 440 } 441 void setPivotY(float pivotY) { 442 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY); 443 } 444 float getScaleX() const { 445 return mPrimitiveFields.scaleX; 446 } 447 void setScaleX(float scaleX) { 448 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX); 449 } 450 float getScaleY() const { 451 return mPrimitiveFields.scaleY; 452 } 453 void setScaleY(float scaleY) { 454 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY); 455 } 456 float getTranslateX() const { 457 return mPrimitiveFields.translateX; 458 } 459 void setTranslateX(float translateX) { 460 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX); 461 } 462 float getTranslateY() const { 463 return mPrimitiveFields.translateY; 464 } 465 void setTranslateY(float translateY) { 466 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY); 467 } 468 void updateProperties(float rotate, float pivotX, float pivotY, 469 float scaleX, float scaleY, float translateX, float translateY) { 470 mPrimitiveFields.rotate = rotate; 471 mPrimitiveFields.pivotX = pivotX; 472 mPrimitiveFields.pivotY = pivotY; 473 mPrimitiveFields.scaleX = scaleX; 474 mPrimitiveFields.scaleY = scaleY; 475 mPrimitiveFields.translateX = translateX; 476 mPrimitiveFields.translateY = translateY; 477 onPropertyChanged(); 478 } 479 void setPropertyValue(int propertyId, float value); 480 float getPropertyValue(int propertyId) const; 481 bool copyProperties(float* outProperties, int length) const; 482 static bool isValidProperty(int propertyId); 483 private: 484 enum class Property { 485 rotate = 0, 486 pivotX, 487 pivotY, 488 scaleX, 489 scaleY, 490 translateX, 491 translateY, 492 // Count of the properties, must be at the end. 493 count, 494 }; 495 }; 496 497 Group(const Group& group); 498 Group() {} 499 void addChild(Node* child); 500 virtual void setPropertyChangedListener(PropertyChangedListener* listener) override { 501 Node::setPropertyChangedListener(listener); 502 for (auto& child : mChildren) { 503 child->setPropertyChangedListener(listener); 504 } 505 } 506 virtual void syncProperties() override; 507 GroupProperties* mutateStagingProperties() { return &mStagingProperties; } 508 const GroupProperties* stagingProperties() { return &mStagingProperties; } 509 510 // This should only be called from animations on RT 511 GroupProperties* mutateProperties() { return &mProperties; } 512 513 // Methods below could be called from either UI thread or Render Thread. 514 virtual void draw(SkCanvas* outCanvas, const SkMatrix& currentMatrix, 515 float scaleX, float scaleY, bool useStagingData) override; 516 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties); 517 void dump() override; 518 static bool isValidProperty(int propertyId); 519 520 virtual void onPropertyChanged(Properties* properties) override { 521 if (properties == &mStagingProperties) { 522 mStagingPropertiesDirty = true; 523 if (mPropertyChangedListener) { 524 mPropertyChangedListener->onStagingPropertyChanged(); 525 } 526 } else { 527 if (mPropertyChangedListener) { 528 mPropertyChangedListener->onPropertyChanged(); 529 } 530 } 531 } 532 533 private: 534 GroupProperties mProperties = GroupProperties(this); 535 GroupProperties mStagingProperties = GroupProperties(this); 536 bool mStagingPropertiesDirty = true; 537 std::vector< std::unique_ptr<Node> > mChildren; 538 }; 539 540 class ANDROID_API Tree : public VirtualLightRefBase { 541 public: 542 Tree(Group* rootNode) : mRootNode(rootNode) { 543 mRootNode->setPropertyChangedListener(&mPropertyChangedListener); 544 } 545 546 // Copy properties from the tree and use the give node as the root node 547 Tree(const Tree* copy, Group* rootNode) : Tree(rootNode) { 548 mStagingProperties.syncAnimatableProperties(*copy->stagingProperties()); 549 mStagingProperties.syncNonAnimatableProperties(*copy->stagingProperties()); 550 } 551 // Draws the VD onto a bitmap cache, then the bitmap cache will be rendered onto the input 552 // canvas. Returns the number of pixels needed for the bitmap cache. 553 int draw(Canvas* outCanvas, SkColorFilter* colorFilter, 554 const SkRect& bounds, bool needsMirroring, bool canReuseCache); 555 void drawStaging(Canvas* canvas); 556 557 const SkBitmap& getBitmapUpdateIfDirty(); 558 void setAllowCaching(bool allowCaching) { 559 mAllowCaching = allowCaching; 560 } 561 SkPaint* getPaint(); 562 void syncProperties() { 563 if (mStagingProperties.mNonAnimatablePropertiesDirty) { 564 mProperties.syncNonAnimatableProperties(mStagingProperties); 565 mStagingProperties.mNonAnimatablePropertiesDirty = false; 566 } 567 568 if (mStagingProperties.mAnimatablePropertiesDirty) { 569 mProperties.syncAnimatableProperties(mStagingProperties); 570 } else { 571 mStagingProperties.syncAnimatableProperties(mProperties); 572 } 573 mStagingProperties.mAnimatablePropertiesDirty = false; 574 mRootNode->syncProperties(); 575 } 576 577 class TreeProperties { 578 public: 579 TreeProperties(Tree* tree) : mTree(tree) {} 580 // Properties that can only be modified by UI thread, therefore sync should 581 // only go from UI to RT 582 struct NonAnimatableProperties { 583 float viewportWidth = 0; 584 float viewportHeight = 0; 585 SkRect bounds; 586 int scaledWidth = 0; 587 int scaledHeight = 0; 588 SkColorFilter* colorFilter = nullptr; 589 ~NonAnimatableProperties() { 590 SkSafeUnref(colorFilter); 591 } 592 } mNonAnimatableProperties; 593 bool mNonAnimatablePropertiesDirty = true; 594 595 float mRootAlpha = 1.0f; 596 bool mAnimatablePropertiesDirty = true; 597 598 void syncNonAnimatableProperties(const TreeProperties& prop) { 599 // Copy over the data that can only be changed in UI thread 600 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) { 601 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter, 602 prop.mNonAnimatableProperties.colorFilter); 603 } 604 mNonAnimatableProperties = prop.mNonAnimatableProperties; 605 } 606 607 void setViewportSize(float width, float height) { 608 if (mNonAnimatableProperties.viewportWidth != width 609 || mNonAnimatableProperties.viewportHeight != height) { 610 mNonAnimatablePropertiesDirty = true; 611 mNonAnimatableProperties.viewportWidth = width; 612 mNonAnimatableProperties.viewportHeight = height; 613 mTree->onPropertyChanged(this); 614 } 615 } 616 void setBounds(const SkRect& bounds) { 617 if (mNonAnimatableProperties.bounds != bounds) { 618 mNonAnimatableProperties.bounds = bounds; 619 mNonAnimatablePropertiesDirty = true; 620 mTree->onPropertyChanged(this); 621 } 622 } 623 624 void setScaledSize(int width, int height) { 625 if (mNonAnimatableProperties.scaledWidth != width 626 || mNonAnimatableProperties.scaledHeight != height) { 627 mNonAnimatableProperties.scaledWidth = width; 628 mNonAnimatableProperties.scaledHeight = height; 629 mNonAnimatablePropertiesDirty = true; 630 mTree->onPropertyChanged(this); 631 } 632 } 633 void setColorFilter(SkColorFilter* filter) { 634 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) { 635 mNonAnimatablePropertiesDirty = true; 636 mTree->onPropertyChanged(this); 637 } 638 } 639 SkColorFilter* getColorFilter() const{ 640 return mNonAnimatableProperties.colorFilter; 641 } 642 643 float getViewportWidth() const { 644 return mNonAnimatableProperties.viewportWidth; 645 } 646 float getViewportHeight() const { 647 return mNonAnimatableProperties.viewportHeight; 648 } 649 float getScaledWidth() const { 650 return mNonAnimatableProperties.scaledWidth; 651 } 652 float getScaledHeight() const { 653 return mNonAnimatableProperties.scaledHeight; 654 } 655 void syncAnimatableProperties(const TreeProperties& prop) { 656 mRootAlpha = prop.mRootAlpha; 657 } 658 bool setRootAlpha(float rootAlpha) { 659 if (rootAlpha != mRootAlpha) { 660 mAnimatablePropertiesDirty = true; 661 mRootAlpha = rootAlpha; 662 mTree->onPropertyChanged(this); 663 return true; 664 } 665 return false; 666 } 667 float getRootAlpha() const { return mRootAlpha;} 668 const SkRect& getBounds() const { 669 return mNonAnimatableProperties.bounds; 670 } 671 Tree* mTree; 672 }; 673 void onPropertyChanged(TreeProperties* prop); 674 TreeProperties* mutateStagingProperties() { return &mStagingProperties; } 675 const TreeProperties* stagingProperties() const { return &mStagingProperties; } 676 677 // This should only be called from animations on RT 678 TreeProperties* mutateProperties() { return &mProperties; } 679 680 // This should always be called from RT. 681 void markDirty() { mCache.dirty = true; } 682 bool isDirty() const { return mCache.dirty; } 683 bool getPropertyChangeWillBeConsumed() const { return mWillBeConsumed; } 684 void setPropertyChangeWillBeConsumed(bool willBeConsumed) { mWillBeConsumed = willBeConsumed; } 685 686 private: 687 688 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop); 689 bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height); 690 bool canReuseBitmap(const SkBitmap&, int width, int height); 691 void updateBitmapCache(SkBitmap* outCache, bool useStagingData); 692 // Cap the bitmap size, such that it won't hurt the performance too much 693 // and it won't crash due to a very large scale. 694 // The drawable will look blurry above this size. 695 const static int MAX_CACHED_BITMAP_SIZE; 696 697 bool mAllowCaching = true; 698 std::unique_ptr<Group> mRootNode; 699 700 TreeProperties mProperties = TreeProperties(this); 701 TreeProperties mStagingProperties = TreeProperties(this); 702 703 SkPaint mPaint; 704 struct Cache { 705 SkBitmap bitmap; 706 bool dirty = true; 707 }; 708 709 Cache mStagingCache; 710 Cache mCache; 711 712 PropertyChangedListener mPropertyChangedListener 713 = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty); 714 715 mutable bool mWillBeConsumed = false; 716 }; 717 718 } // namespace VectorDrawable 719 720 typedef VectorDrawable::Path::Data PathData; 721 } // namespace uirenderer 722 } // namespace android 723 724 #endif // ANDROID_HWUI_VPATH_H 725