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