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