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