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