VectorDrawable.h revision 32d7cda0b89a114171f14de0753674090b3d75fc
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 42namespace 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 74class PropertyChangedListener { 75public: 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 } 84private: 85 bool* mDirty; 86 bool* mStagingDirty; 87}; 88 89class ANDROID_API Node { 90public: 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; 116protected: 117 std::string mName; 118 PropertyChangedListener* mPropertyChangedListener = nullptr; 119}; 120 121class ANDROID_API Path : public Node { 122public: 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 187protected: 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 197private: 198 PathProperties mProperties = PathProperties(this); 199 PathProperties mStagingProperties = PathProperties(this); 200 bool mStagingPropertiesDirty = true; 201}; 202 203class ANDROID_API FullPath: public Path { 204public: 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 void syncProperties(const FullPathProperties& prop) { 223 mPrimitiveFields = prop.mPrimitiveFields; 224 mTrimDirty = true; 225 fillGradient.reset(prop.fillGradient); 226 strokeGradient.reset(prop.strokeGradient); 227 onPropertyChanged(); 228 } 229 void setFillGradient(SkShader* gradient) { 230 if(fillGradient != gradient){ 231 fillGradient.reset(gradient); 232 onPropertyChanged(); 233 } 234 } 235 void setStrokeGradient(SkShader* gradient) { 236 if(strokeGradient != gradient){ 237 strokeGradient.reset(gradient); 238 onPropertyChanged(); 239 } 240 } 241 SkShader* getFillGradient() const { 242 return fillGradient; 243 } 244 SkShader* getStrokeGradient() const { 245 return strokeGradient; 246 } 247 float getStrokeWidth() const{ 248 return mPrimitiveFields.strokeWidth; 249 } 250 void setStrokeWidth(float strokeWidth) { 251 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth); 252 } 253 SkColor getStrokeColor() const{ 254 return mPrimitiveFields.strokeColor; 255 } 256 void setStrokeColor(SkColor strokeColor) { 257 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor); 258 } 259 float getStrokeAlpha() const{ 260 return mPrimitiveFields.strokeAlpha; 261 } 262 void setStrokeAlpha(float strokeAlpha) { 263 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha); 264 } 265 SkColor getFillColor() const { 266 return mPrimitiveFields.fillColor; 267 } 268 void setFillColor(SkColor fillColor) { 269 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor); 270 } 271 float getFillAlpha() const{ 272 return mPrimitiveFields.fillAlpha; 273 } 274 void setFillAlpha(float fillAlpha) { 275 VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha); 276 } 277 float getTrimPathStart() const{ 278 return mPrimitiveFields.trimPathStart; 279 } 280 void setTrimPathStart(float trimPathStart) { 281 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty); 282 } 283 float getTrimPathEnd() const{ 284 return mPrimitiveFields.trimPathEnd; 285 } 286 void setTrimPathEnd(float trimPathEnd) { 287 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty); 288 } 289 float getTrimPathOffset() const{ 290 return mPrimitiveFields.trimPathOffset; 291 } 292 void setTrimPathOffset(float trimPathOffset) { 293 VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty); 294 } 295 296 float getStrokeMiterLimit() const { 297 return mPrimitiveFields.strokeMiterLimit; 298 } 299 float getStrokeLineCap() const { 300 return mPrimitiveFields.strokeLineCap; 301 } 302 float getStrokeLineJoin() const { 303 return mPrimitiveFields.strokeLineJoin; 304 } 305 float getFillType() const { 306 return mPrimitiveFields.fillType; 307 } 308 bool copyProperties(int8_t* outProperties, int length) const; 309 void updateProperties(float strokeWidth, SkColor strokeColor, float strokeAlpha, 310 SkColor fillColor, float fillAlpha, float trimPathStart, float trimPathEnd, 311 float trimPathOffset, float strokeMiterLimit, int strokeLineCap, int strokeLineJoin, 312 int fillType) { 313 mPrimitiveFields.strokeWidth = strokeWidth; 314 mPrimitiveFields.strokeColor = strokeColor; 315 mPrimitiveFields.strokeAlpha = strokeAlpha; 316 mPrimitiveFields.fillColor = fillColor; 317 mPrimitiveFields.fillAlpha = fillAlpha; 318 mPrimitiveFields.trimPathStart = trimPathStart; 319 mPrimitiveFields.trimPathEnd = trimPathEnd; 320 mPrimitiveFields.trimPathOffset = trimPathOffset; 321 mPrimitiveFields.strokeMiterLimit = strokeMiterLimit; 322 mPrimitiveFields.strokeLineCap = strokeLineCap; 323 mPrimitiveFields.strokeLineJoin = strokeLineJoin; 324 mPrimitiveFields.fillType = fillType; 325 mTrimDirty = true; 326 onPropertyChanged(); 327 } 328 // Set property values during animation 329 void setColorPropertyValue(int propertyId, int32_t value); 330 void setPropertyValue(int propertyId, float value); 331 bool mTrimDirty; 332 private: 333 enum class Property { 334 strokeWidth = 0, 335 strokeColor, 336 strokeAlpha, 337 fillColor, 338 fillAlpha, 339 trimPathStart, 340 trimPathEnd, 341 trimPathOffset, 342 strokeLineCap, 343 strokeLineJoin, 344 strokeMiterLimit, 345 fillType, 346 count, 347 }; 348 PrimitiveFields mPrimitiveFields; 349 SkAutoTUnref<SkShader> fillGradient; 350 SkAutoTUnref<SkShader> strokeGradient; 351 }; 352 353 // Called from UI thread 354 FullPath(const FullPath& path); // for cloning 355 FullPath(const char* path, size_t strLength) : Path(path, strLength) {} 356 FullPath() : Path() {} 357 void dump() override; 358 FullPathProperties* mutateStagingProperties() { return &mStagingProperties; } 359 const FullPathProperties* stagingProperties() { return &mStagingProperties; } 360 361 // This should only be called from animations on RT 362 FullPathProperties* mutateProperties() { return &mProperties; } 363 364 virtual void syncProperties() override; 365 virtual void onPropertyChanged(Properties* properties) override { 366 Path::onPropertyChanged(properties); 367 if (properties == &mStagingProperties) { 368 mStagingPropertiesDirty = true; 369 if (mPropertyChangedListener) { 370 mPropertyChangedListener->onStagingPropertyChanged(); 371 } 372 } else if (properties == &mProperties) { 373 if (mPropertyChangedListener) { 374 mPropertyChangedListener->onPropertyChanged(); 375 } 376 } 377 } 378 379protected: 380 const SkPath& getUpdatedPath() override; 381 void getStagingPath(SkPath* outPath) override; 382 void drawPath(SkCanvas* outCanvas, SkPath& renderPath, 383 float strokeScale, const SkMatrix& matrix, bool useStagingData) override; 384private: 385 386 FullPathProperties mProperties = FullPathProperties(this); 387 FullPathProperties mStagingProperties = FullPathProperties(this); 388 bool mStagingPropertiesDirty = true; 389 390 // Intermediate data for drawing, render thread only 391 SkPath mTrimmedSkPath; 392 393}; 394 395class ANDROID_API ClipPath: public Path { 396public: 397 ClipPath(const ClipPath& path) : Path(path) {} 398 ClipPath(const char* path, size_t strLength) : Path(path, strLength) {} 399 ClipPath() : Path() {} 400 401protected: 402 void drawPath(SkCanvas* outCanvas, SkPath& renderPath, 403 float strokeScale, const SkMatrix& matrix, bool useStagingData) override; 404}; 405 406class ANDROID_API Group: public Node { 407public: 408 class GroupProperties : public Properties { 409 public: 410 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, const SkMatrix& currentMatrix, 513 float scaleX, float scaleY, bool useStagingData) override; 514 void getLocalMatrix(SkMatrix* outMatrix, const GroupProperties& properties); 515 void dump() override; 516 static bool isValidProperty(int propertyId); 517 518 virtual void onPropertyChanged(Properties* properties) override { 519 if (properties == &mStagingProperties) { 520 mStagingPropertiesDirty = true; 521 if (mPropertyChangedListener) { 522 mPropertyChangedListener->onStagingPropertyChanged(); 523 } 524 } else { 525 if (mPropertyChangedListener) { 526 mPropertyChangedListener->onPropertyChanged(); 527 } 528 } 529 } 530 531private: 532 GroupProperties mProperties = GroupProperties(this); 533 GroupProperties mStagingProperties = GroupProperties(this); 534 bool mStagingPropertiesDirty = true; 535 std::vector< std::unique_ptr<Node> > mChildren; 536}; 537 538class ANDROID_API Tree : public VirtualLightRefBase { 539public: 540 Tree(Group* rootNode) : mRootNode(rootNode) { 541 mRootNode->setPropertyChangedListener(&mPropertyChangedListener); 542 } 543 void draw(Canvas* outCanvas, SkColorFilter* colorFilter, 544 const SkRect& bounds, bool needsMirroring, bool canReuseCache); 545 void drawStaging(Canvas* canvas); 546 547 const SkBitmap& getBitmapUpdateIfDirty(); 548 void setAllowCaching(bool allowCaching) { 549 mAllowCaching = allowCaching; 550 } 551 SkPaint* getPaint(); 552 void syncProperties() { 553 if (mStagingProperties.mNonAnimatablePropertiesDirty) { 554 mProperties.syncNonAnimatableProperties(mStagingProperties); 555 mStagingProperties.mNonAnimatablePropertiesDirty = false; 556 } 557 558 if (mStagingProperties.mAnimatablePropertiesDirty) { 559 mProperties.syncAnimatableProperties(mStagingProperties); 560 } else { 561 mStagingProperties.syncAnimatableProperties(mProperties); 562 } 563 mStagingProperties.mAnimatablePropertiesDirty = false; 564 mRootNode->syncProperties(); 565 } 566 567 class TreeProperties { 568 public: 569 TreeProperties(Tree* tree) : mTree(tree) {} 570 // Properties that can only be modified by UI thread, therefore sync should 571 // only go from UI to RT 572 struct NonAnimatableProperties { 573 float viewportWidth = 0; 574 float viewportHeight = 0; 575 SkRect bounds; 576 int scaledWidth = 0; 577 int scaledHeight = 0; 578 SkColorFilter* colorFilter = nullptr; 579 ~NonAnimatableProperties() { 580 SkSafeUnref(colorFilter); 581 } 582 } mNonAnimatableProperties; 583 bool mNonAnimatablePropertiesDirty = true; 584 585 float mRootAlpha = 1.0f; 586 bool mAnimatablePropertiesDirty = true; 587 588 void syncNonAnimatableProperties(const TreeProperties& prop) { 589 // Copy over the data that can only be changed in UI thread 590 if (mNonAnimatableProperties.colorFilter != prop.mNonAnimatableProperties.colorFilter) { 591 SkRefCnt_SafeAssign(mNonAnimatableProperties.colorFilter, 592 prop.mNonAnimatableProperties.colorFilter); 593 } 594 mNonAnimatableProperties = prop.mNonAnimatableProperties; 595 } 596 597 void setViewportSize(float width, float height) { 598 if (mNonAnimatableProperties.viewportWidth != width 599 || mNonAnimatableProperties.viewportHeight != height) { 600 mNonAnimatablePropertiesDirty = true; 601 mNonAnimatableProperties.viewportWidth = width; 602 mNonAnimatableProperties.viewportHeight = height; 603 mTree->onPropertyChanged(this); 604 } 605 } 606 void setBounds(const SkRect& bounds) { 607 if (mNonAnimatableProperties.bounds != bounds) { 608 mNonAnimatableProperties.bounds = bounds; 609 mNonAnimatablePropertiesDirty = true; 610 mTree->onPropertyChanged(this); 611 } 612 } 613 614 void setScaledSize(int width, int height) { 615 if (mNonAnimatableProperties.scaledWidth != width 616 || mNonAnimatableProperties.scaledHeight != height) { 617 mNonAnimatableProperties.scaledWidth = width; 618 mNonAnimatableProperties.scaledHeight = height; 619 mNonAnimatablePropertiesDirty = true; 620 mTree->onPropertyChanged(this); 621 } 622 } 623 void setColorFilter(SkColorFilter* filter) { 624 if (UPDATE_SKPROP(mNonAnimatableProperties.colorFilter, filter)) { 625 mNonAnimatablePropertiesDirty = true; 626 mTree->onPropertyChanged(this); 627 } 628 } 629 SkColorFilter* getColorFilter() const{ 630 return mNonAnimatableProperties.colorFilter; 631 } 632 633 float getViewportWidth() const { 634 return mNonAnimatableProperties.viewportWidth; 635 } 636 float getViewportHeight() const { 637 return mNonAnimatableProperties.viewportHeight; 638 } 639 float getScaledWidth() const { 640 return mNonAnimatableProperties.scaledWidth; 641 } 642 float getScaledHeight() const { 643 return mNonAnimatableProperties.scaledHeight; 644 } 645 void syncAnimatableProperties(const TreeProperties& prop) { 646 mRootAlpha = prop.mRootAlpha; 647 } 648 bool setRootAlpha(float rootAlpha) { 649 if (rootAlpha != mRootAlpha) { 650 mAnimatablePropertiesDirty = true; 651 mRootAlpha = rootAlpha; 652 mTree->onPropertyChanged(this); 653 return true; 654 } 655 return false; 656 } 657 float getRootAlpha() const { return mRootAlpha;} 658 const SkRect& getBounds() const { 659 return mNonAnimatableProperties.bounds; 660 } 661 Tree* mTree; 662 }; 663 void onPropertyChanged(TreeProperties* prop); 664 TreeProperties* mutateStagingProperties() { return &mStagingProperties; } 665 const TreeProperties* stagingProperties() { return &mStagingProperties; } 666 PushStagingFunctor* getFunctor() { return &mFunctor;} 667 668 // This should only be called from animations on RT 669 TreeProperties* mutateProperties() { return &mProperties; } 670 671private: 672 class VectorDrawableFunctor : public PushStagingFunctor { 673 public: 674 VectorDrawableFunctor(Tree* tree) : mTree(tree) {} 675 virtual void operator ()() { 676 mTree->syncProperties(); 677 } 678 private: 679 Tree* mTree; 680 }; 681 682 SkPaint* updatePaint(SkPaint* outPaint, TreeProperties* prop); 683 bool allocateBitmapIfNeeded(SkBitmap* outCache, int width, int height); 684 bool canReuseBitmap(const SkBitmap&, int width, int height); 685 void updateBitmapCache(SkBitmap* outCache, bool useStagingData); 686 // Cap the bitmap size, such that it won't hurt the performance too much 687 // and it won't crash due to a very large scale. 688 // The drawable will look blurry above this size. 689 const static int MAX_CACHED_BITMAP_SIZE; 690 691 bool mAllowCaching = true; 692 std::unique_ptr<Group> mRootNode; 693 694 TreeProperties mProperties = TreeProperties(this); 695 TreeProperties mStagingProperties = TreeProperties(this); 696 697 VectorDrawableFunctor mFunctor = VectorDrawableFunctor(this); 698 699 SkPaint mPaint; 700 struct Cache { 701 SkBitmap bitmap; 702 bool dirty = true; 703 }; 704 705 Cache mStagingCache; 706 Cache mCache; 707 708 PropertyChangedListener mPropertyChangedListener 709 = PropertyChangedListener(&mCache.dirty, &mStagingCache.dirty); 710}; 711 712} // namespace VectorDrawable 713 714typedef VectorDrawable::Path::Data PathData; 715} // namespace uirenderer 716} // namespace android 717 718#endif // ANDROID_HWUI_VPATH_H 719