1 /* 2 * Copyright (C) 2014 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 #ifndef RENDERNODEPROPERTIES_H 17 #define RENDERNODEPROPERTIES_H 18 19 #include <algorithm> 20 #include <stddef.h> 21 #include <vector> 22 #include <cutils/compiler.h> 23 #include <androidfw/ResourceTypes.h> 24 #include <utils/Log.h> 25 26 #include <SkCamera.h> 27 #include <SkMatrix.h> 28 #include <SkRegion.h> 29 30 #include "Animator.h" 31 #include "Rect.h" 32 #include "RevealClip.h" 33 #include "Outline.h" 34 #include "utils/MathUtils.h" 35 36 class SkBitmap; 37 class SkColorFilter; 38 class SkPaint; 39 40 namespace android { 41 namespace uirenderer { 42 43 class Matrix4; 44 class RenderNode; 45 class RenderProperties; 46 47 // The __VA_ARGS__ will be executed if a & b are not equal 48 #define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false) 49 #define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true) 50 51 // Keep in sync with View.java:LAYER_TYPE_* 52 enum LayerType { 53 kLayerTypeNone = 0, 54 // Although we cannot build the software layer directly (must be done at 55 // record time), this information is used when applying alpha. 56 kLayerTypeSoftware = 1, 57 kLayerTypeRenderLayer = 2, 58 // TODO: LayerTypeSurfaceTexture? Maybe? 59 }; 60 61 enum ClippingFlags { 62 CLIP_TO_BOUNDS = 0x1 << 0, 63 CLIP_TO_CLIP_BOUNDS = 0x1 << 1, 64 }; 65 66 class ANDROID_API LayerProperties { 67 public: setType(LayerType type)68 bool setType(LayerType type) { 69 if (RP_SET(mType, type)) { 70 reset(); 71 return true; 72 } 73 return false; 74 } 75 type()76 LayerType type() const { 77 return mType; 78 } 79 setOpaque(bool opaque)80 bool setOpaque(bool opaque) { 81 return RP_SET(mOpaque, opaque); 82 } 83 opaque()84 bool opaque() const { 85 return mOpaque; 86 } 87 setAlpha(uint8_t alpha)88 bool setAlpha(uint8_t alpha) { 89 return RP_SET(mAlpha, alpha); 90 } 91 alpha()92 uint8_t alpha() const { 93 return mAlpha; 94 } 95 setXferMode(SkXfermode::Mode mode)96 bool setXferMode(SkXfermode::Mode mode) { 97 return RP_SET(mMode, mode); 98 } 99 xferMode()100 SkXfermode::Mode xferMode() const { 101 return mMode; 102 } 103 104 bool setColorFilter(SkColorFilter* filter); 105 colorFilter()106 SkColorFilter* colorFilter() const { 107 return mColorFilter; 108 } 109 110 // Sets alpha, xfermode, and colorfilter from an SkPaint 111 // paint may be NULL, in which case defaults will be set 112 bool setFromPaint(const SkPaint* paint); 113 needsBlending()114 bool needsBlending() const { 115 return !opaque() || alpha() < 255; 116 } 117 118 LayerProperties& operator=(const LayerProperties& other); 119 120 private: 121 LayerProperties(); 122 ~LayerProperties(); 123 void reset(); 124 125 friend class RenderProperties; 126 127 LayerType mType; 128 // Whether or not that Layer's content is opaque, doesn't include alpha 129 bool mOpaque; 130 uint8_t mAlpha; 131 SkXfermode::Mode mMode; 132 SkColorFilter* mColorFilter; 133 }; 134 135 /* 136 * Data structure that holds the properties for a RenderNode 137 */ 138 class ANDROID_API RenderProperties { 139 public: 140 RenderProperties(); 141 virtual ~RenderProperties(); 142 setFlag(int flag,bool newValue,int * outFlags)143 static bool setFlag(int flag, bool newValue, int* outFlags) { 144 if (newValue) { 145 if (!(flag & *outFlags)) { 146 *outFlags |= flag; 147 return true; 148 } 149 return false; 150 } else { 151 if (flag & *outFlags) { 152 *outFlags &= ~flag; 153 return true; 154 } 155 return false; 156 } 157 } 158 159 RenderProperties& operator=(const RenderProperties& other); 160 setClipToBounds(bool clipToBounds)161 bool setClipToBounds(bool clipToBounds) { 162 return setFlag(CLIP_TO_BOUNDS, clipToBounds, &mPrimitiveFields.mClippingFlags); 163 } 164 setClipBounds(const Rect & clipBounds)165 bool setClipBounds(const Rect& clipBounds) { 166 bool ret = setFlag(CLIP_TO_CLIP_BOUNDS, true, &mPrimitiveFields.mClippingFlags); 167 return RP_SET(mPrimitiveFields.mClipBounds, clipBounds) || ret; 168 } 169 setClipBoundsEmpty()170 bool setClipBoundsEmpty() { 171 return setFlag(CLIP_TO_CLIP_BOUNDS, false, &mPrimitiveFields.mClippingFlags); 172 } 173 setProjectBackwards(bool shouldProject)174 bool setProjectBackwards(bool shouldProject) { 175 return RP_SET(mPrimitiveFields.mProjectBackwards, shouldProject); 176 } 177 setProjectionReceiver(bool shouldRecieve)178 bool setProjectionReceiver(bool shouldRecieve) { 179 return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldRecieve); 180 } 181 isProjectionReceiver()182 bool isProjectionReceiver() const { 183 return mPrimitiveFields.mProjectionReceiver; 184 } 185 setStaticMatrix(const SkMatrix * matrix)186 bool setStaticMatrix(const SkMatrix* matrix) { 187 delete mStaticMatrix; 188 if (matrix) { 189 mStaticMatrix = new SkMatrix(*matrix); 190 } else { 191 mStaticMatrix = NULL; 192 } 193 return true; 194 } 195 196 // Can return NULL getStaticMatrix()197 const SkMatrix* getStaticMatrix() const { 198 return mStaticMatrix; 199 } 200 setAnimationMatrix(const SkMatrix * matrix)201 bool setAnimationMatrix(const SkMatrix* matrix) { 202 delete mAnimationMatrix; 203 if (matrix) { 204 mAnimationMatrix = new SkMatrix(*matrix); 205 } else { 206 mAnimationMatrix = NULL; 207 } 208 return true; 209 } 210 setAlpha(float alpha)211 bool setAlpha(float alpha) { 212 alpha = MathUtils::clampAlpha(alpha); 213 return RP_SET(mPrimitiveFields.mAlpha, alpha); 214 } 215 getAlpha()216 float getAlpha() const { 217 return mPrimitiveFields.mAlpha; 218 } 219 setHasOverlappingRendering(bool hasOverlappingRendering)220 bool setHasOverlappingRendering(bool hasOverlappingRendering) { 221 return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering); 222 } 223 hasOverlappingRendering()224 bool hasOverlappingRendering() const { 225 return mPrimitiveFields.mHasOverlappingRendering; 226 } 227 setElevation(float elevation)228 bool setElevation(float elevation) { 229 return RP_SET(mPrimitiveFields.mElevation, elevation); 230 // Don't dirty matrix/pivot, since they don't respect Z 231 } 232 getElevation()233 float getElevation() const { 234 return mPrimitiveFields.mElevation; 235 } 236 setTranslationX(float translationX)237 bool setTranslationX(float translationX) { 238 return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX); 239 } 240 getTranslationX()241 float getTranslationX() const { 242 return mPrimitiveFields.mTranslationX; 243 } 244 setTranslationY(float translationY)245 bool setTranslationY(float translationY) { 246 return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY); 247 } 248 getTranslationY()249 float getTranslationY() const { 250 return mPrimitiveFields.mTranslationY; 251 } 252 setTranslationZ(float translationZ)253 bool setTranslationZ(float translationZ) { 254 return RP_SET(mPrimitiveFields.mTranslationZ, translationZ); 255 // mMatrixOrPivotDirty not set, since matrix doesn't respect Z 256 } 257 getTranslationZ()258 float getTranslationZ() const { 259 return mPrimitiveFields.mTranslationZ; 260 } 261 262 // Animation helper setX(float value)263 bool setX(float value) { 264 return setTranslationX(value - getLeft()); 265 } 266 267 // Animation helper getX()268 float getX() const { 269 return getLeft() + getTranslationX(); 270 } 271 272 // Animation helper setY(float value)273 bool setY(float value) { 274 return setTranslationY(value - getTop()); 275 } 276 277 // Animation helper getY()278 float getY() const { 279 return getTop() + getTranslationY(); 280 } 281 282 // Animation helper setZ(float value)283 bool setZ(float value) { 284 return setTranslationZ(value - getElevation()); 285 } 286 getZ()287 float getZ() const { 288 return getElevation() + getTranslationZ(); 289 } 290 setRotation(float rotation)291 bool setRotation(float rotation) { 292 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation); 293 } 294 getRotation()295 float getRotation() const { 296 return mPrimitiveFields.mRotation; 297 } 298 setRotationX(float rotationX)299 bool setRotationX(float rotationX) { 300 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX); 301 } 302 getRotationX()303 float getRotationX() const { 304 return mPrimitiveFields.mRotationX; 305 } 306 setRotationY(float rotationY)307 bool setRotationY(float rotationY) { 308 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY); 309 } 310 getRotationY()311 float getRotationY() const { 312 return mPrimitiveFields.mRotationY; 313 } 314 setScaleX(float scaleX)315 bool setScaleX(float scaleX) { 316 return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX); 317 } 318 getScaleX()319 float getScaleX() const { 320 return mPrimitiveFields.mScaleX; 321 } 322 setScaleY(float scaleY)323 bool setScaleY(float scaleY) { 324 return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY); 325 } 326 getScaleY()327 float getScaleY() const { 328 return mPrimitiveFields.mScaleY; 329 } 330 setPivotX(float pivotX)331 bool setPivotX(float pivotX) { 332 if (RP_SET(mPrimitiveFields.mPivotX, pivotX) 333 || !mPrimitiveFields.mPivotExplicitlySet) { 334 mPrimitiveFields.mMatrixOrPivotDirty = true; 335 mPrimitiveFields.mPivotExplicitlySet = true; 336 return true; 337 } 338 return false; 339 } 340 341 /* Note that getPivotX and getPivotY are adjusted by updateMatrix(), 342 * so the value returned may be stale if the RenderProperties has been 343 * modified since the last call to updateMatrix() 344 */ getPivotX()345 float getPivotX() const { 346 return mPrimitiveFields.mPivotX; 347 } 348 setPivotY(float pivotY)349 bool setPivotY(float pivotY) { 350 if (RP_SET(mPrimitiveFields.mPivotY, pivotY) 351 || !mPrimitiveFields.mPivotExplicitlySet) { 352 mPrimitiveFields.mMatrixOrPivotDirty = true; 353 mPrimitiveFields.mPivotExplicitlySet = true; 354 return true; 355 } 356 return false; 357 } 358 getPivotY()359 float getPivotY() const { 360 return mPrimitiveFields.mPivotY; 361 } 362 isPivotExplicitlySet()363 bool isPivotExplicitlySet() const { 364 return mPrimitiveFields.mPivotExplicitlySet; 365 } 366 setCameraDistance(float distance)367 bool setCameraDistance(float distance) { 368 if (distance != getCameraDistance()) { 369 mPrimitiveFields.mMatrixOrPivotDirty = true; 370 mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance); 371 return true; 372 } 373 return false; 374 } 375 getCameraDistance()376 float getCameraDistance() const { 377 // TODO: update getCameraLocationZ() to be const 378 return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ(); 379 } 380 setLeft(int left)381 bool setLeft(int left) { 382 if (RP_SET(mPrimitiveFields.mLeft, left)) { 383 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 384 if (!mPrimitiveFields.mPivotExplicitlySet) { 385 mPrimitiveFields.mMatrixOrPivotDirty = true; 386 } 387 return true; 388 } 389 return false; 390 } 391 getLeft()392 float getLeft() const { 393 return mPrimitiveFields.mLeft; 394 } 395 setTop(int top)396 bool setTop(int top) { 397 if (RP_SET(mPrimitiveFields.mTop, top)) { 398 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 399 if (!mPrimitiveFields.mPivotExplicitlySet) { 400 mPrimitiveFields.mMatrixOrPivotDirty = true; 401 } 402 return true; 403 } 404 return false; 405 } 406 getTop()407 float getTop() const { 408 return mPrimitiveFields.mTop; 409 } 410 setRight(int right)411 bool setRight(int right) { 412 if (RP_SET(mPrimitiveFields.mRight, right)) { 413 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 414 if (!mPrimitiveFields.mPivotExplicitlySet) { 415 mPrimitiveFields.mMatrixOrPivotDirty = true; 416 } 417 return true; 418 } 419 return false; 420 } 421 getRight()422 float getRight() const { 423 return mPrimitiveFields.mRight; 424 } 425 setBottom(int bottom)426 bool setBottom(int bottom) { 427 if (RP_SET(mPrimitiveFields.mBottom, bottom)) { 428 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 429 if (!mPrimitiveFields.mPivotExplicitlySet) { 430 mPrimitiveFields.mMatrixOrPivotDirty = true; 431 } 432 return true; 433 } 434 return false; 435 } 436 getBottom()437 float getBottom() const { 438 return mPrimitiveFields.mBottom; 439 } 440 setLeftTop(int left,int top)441 bool setLeftTop(int left, int top) { 442 bool leftResult = setLeft(left); 443 bool topResult = setTop(top); 444 return leftResult || topResult; 445 } 446 setLeftTopRightBottom(int left,int top,int right,int bottom)447 bool setLeftTopRightBottom(int left, int top, int right, int bottom) { 448 if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop 449 || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) { 450 mPrimitiveFields.mLeft = left; 451 mPrimitiveFields.mTop = top; 452 mPrimitiveFields.mRight = right; 453 mPrimitiveFields.mBottom = bottom; 454 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 455 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 456 if (!mPrimitiveFields.mPivotExplicitlySet) { 457 mPrimitiveFields.mMatrixOrPivotDirty = true; 458 } 459 return true; 460 } 461 return false; 462 } 463 offsetLeftRight(int offset)464 bool offsetLeftRight(int offset) { 465 if (offset != 0) { 466 mPrimitiveFields.mLeft += offset; 467 mPrimitiveFields.mRight += offset; 468 return true; 469 } 470 return false; 471 } 472 offsetTopBottom(int offset)473 bool offsetTopBottom(int offset) { 474 if (offset != 0) { 475 mPrimitiveFields.mTop += offset; 476 mPrimitiveFields.mBottom += offset; 477 return true; 478 } 479 return false; 480 } 481 getWidth()482 int getWidth() const { 483 return mPrimitiveFields.mWidth; 484 } 485 getHeight()486 int getHeight() const { 487 return mPrimitiveFields.mHeight; 488 } 489 getAnimationMatrix()490 const SkMatrix* getAnimationMatrix() const { 491 return mAnimationMatrix; 492 } 493 hasTransformMatrix()494 bool hasTransformMatrix() const { 495 return getTransformMatrix() && !getTransformMatrix()->isIdentity(); 496 } 497 498 // May only call this if hasTransformMatrix() is true isTransformTranslateOnly()499 bool isTransformTranslateOnly() const { 500 return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask; 501 } 502 getTransformMatrix()503 const SkMatrix* getTransformMatrix() const { 504 LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!"); 505 return mComputedFields.mTransformMatrix; 506 } 507 getClippingFlags()508 int getClippingFlags() const { 509 return mPrimitiveFields.mClippingFlags; 510 } 511 getClipToBounds()512 bool getClipToBounds() const { 513 return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS; 514 } 515 getClippingRectForFlags(uint32_t flags,Rect * outRect)516 void getClippingRectForFlags(uint32_t flags, Rect* outRect) const { 517 if (flags & CLIP_TO_BOUNDS) { 518 outRect->set(0, 0, getWidth(), getHeight()); 519 if (flags & CLIP_TO_CLIP_BOUNDS) { 520 outRect->intersect(mPrimitiveFields.mClipBounds); 521 } 522 } else { 523 outRect->set(mPrimitiveFields.mClipBounds); 524 } 525 } 526 getHasOverlappingRendering()527 bool getHasOverlappingRendering() const { 528 return mPrimitiveFields.mHasOverlappingRendering; 529 } 530 getOutline()531 const Outline& getOutline() const { 532 return mPrimitiveFields.mOutline; 533 } 534 getRevealClip()535 const RevealClip& getRevealClip() const { 536 return mPrimitiveFields.mRevealClip; 537 } 538 getProjectBackwards()539 bool getProjectBackwards() const { 540 return mPrimitiveFields.mProjectBackwards; 541 } 542 543 void debugOutputProperties(const int level) const; 544 545 void updateMatrix(); 546 mutableOutline()547 Outline& mutableOutline() { 548 return mPrimitiveFields.mOutline; 549 } 550 mutableRevealClip()551 RevealClip& mutableRevealClip() { 552 return mPrimitiveFields.mRevealClip; 553 } 554 layerProperties()555 const LayerProperties& layerProperties() const { 556 return mLayerProperties; 557 } 558 mutateLayerProperties()559 LayerProperties& mutateLayerProperties() { 560 return mLayerProperties; 561 } 562 563 // Returns true if damage calculations should be clipped to bounds 564 // TODO: Figure out something better for getZ(), as children should still be 565 // clipped to this RP's bounds. But as we will damage -INT_MAX to INT_MAX 566 // for this RP's getZ() anyway, this can be optimized when we have a 567 // Z damage estimate instead of INT_MAX getClipDamageToBounds()568 bool getClipDamageToBounds() const { 569 return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty()); 570 } 571 hasShadow()572 bool hasShadow() const { 573 return getZ() > 0.0f 574 && getOutline().getPath() != NULL 575 && getOutline().getAlpha() != 0.0f; 576 } 577 578 private: 579 // Rendering properties 580 struct PrimitiveFields { 581 PrimitiveFields(); 582 583 Outline mOutline; 584 RevealClip mRevealClip; 585 int mClippingFlags; 586 bool mProjectBackwards; 587 bool mProjectionReceiver; 588 float mAlpha; 589 bool mHasOverlappingRendering; 590 float mElevation; 591 float mTranslationX, mTranslationY, mTranslationZ; 592 float mRotation, mRotationX, mRotationY; 593 float mScaleX, mScaleY; 594 float mPivotX, mPivotY; 595 int mLeft, mTop, mRight, mBottom; 596 int mWidth, mHeight; 597 bool mPivotExplicitlySet; 598 bool mMatrixOrPivotDirty; 599 Rect mClipBounds; 600 } mPrimitiveFields; 601 602 SkMatrix* mStaticMatrix; 603 SkMatrix* mAnimationMatrix; 604 LayerProperties mLayerProperties; 605 606 /** 607 * These fields are all generated from other properties and are not set directly. 608 */ 609 struct ComputedFields { 610 ComputedFields(); 611 ~ComputedFields(); 612 613 /** 614 * Stores the total transformation of the DisplayList based upon its scalar 615 * translate/rotate/scale properties. 616 * 617 * In the common translation-only case, the matrix isn't necessarily allocated, 618 * and the mTranslation properties are used directly. 619 */ 620 SkMatrix* mTransformMatrix; 621 622 Sk3DView mTransformCamera; 623 } mComputedFields; 624 }; 625 626 } /* namespace uirenderer */ 627 } /* namespace android */ 628 629 #endif /* RENDERNODEPROPERTIES_H */ 630