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