RenderProperties.h revision 3b52c03f5035b833d365215420739aa840ac5080
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 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 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 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 LayerType type() const { 77 return mType; 78 } 79 80 bool setOpaque(bool opaque) { 81 return RP_SET(mOpaque, opaque); 82 } 83 84 bool opaque() const { 85 return mOpaque; 86 } 87 88 bool setAlpha(uint8_t alpha) { 89 return RP_SET(mAlpha, alpha); 90 } 91 92 uint8_t alpha() const { 93 return mAlpha; 94 } 95 96 bool setXferMode(SkXfermode::Mode mode) { 97 return RP_SET(mMode, mode); 98 } 99 100 SkXfermode::Mode xferMode() const { 101 return mMode; 102 } 103 104 bool setColorFilter(SkColorFilter* filter); 105 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 114 bool needsBlending() const { 115 return !opaque() || alpha() < 255; 116 } 117 118 LayerProperties& operator=(const LayerProperties& other); 119 120private: 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 */ 138class ANDROID_API RenderProperties { 139public: 140 RenderProperties(); 141 virtual ~RenderProperties(); 142 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 161 bool setClipToBounds(bool clipToBounds) { 162 return setFlag(CLIP_TO_BOUNDS, clipToBounds, &mPrimitiveFields.mClippingFlags); 163 } 164 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 170 bool setClipBoundsEmpty() { 171 return setFlag(CLIP_TO_CLIP_BOUNDS, false, &mPrimitiveFields.mClippingFlags); 172 } 173 174 bool setProjectBackwards(bool shouldProject) { 175 return RP_SET(mPrimitiveFields.mProjectBackwards, shouldProject); 176 } 177 178 bool setProjectionReceiver(bool shouldRecieve) { 179 return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldRecieve); 180 } 181 182 bool isProjectionReceiver() const { 183 return mPrimitiveFields.mProjectionReceiver; 184 } 185 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 197 const SkMatrix* getStaticMatrix() const { 198 return mStaticMatrix; 199 } 200 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 211 bool setAlpha(float alpha) { 212 alpha = MathUtils::clampAlpha(alpha); 213 return RP_SET(mPrimitiveFields.mAlpha, alpha); 214 } 215 216 float getAlpha() const { 217 return mPrimitiveFields.mAlpha; 218 } 219 220 bool setHasOverlappingRendering(bool hasOverlappingRendering) { 221 return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering); 222 } 223 224 bool hasOverlappingRendering() const { 225 return mPrimitiveFields.mHasOverlappingRendering; 226 } 227 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 233 float getElevation() const { 234 return mPrimitiveFields.mElevation; 235 } 236 237 bool setTranslationX(float translationX) { 238 return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX); 239 } 240 241 float getTranslationX() const { 242 return mPrimitiveFields.mTranslationX; 243 } 244 245 bool setTranslationY(float translationY) { 246 return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY); 247 } 248 249 float getTranslationY() const { 250 return mPrimitiveFields.mTranslationY; 251 } 252 253 bool setTranslationZ(float translationZ) { 254 return RP_SET(mPrimitiveFields.mTranslationZ, translationZ); 255 // mMatrixOrPivotDirty not set, since matrix doesn't respect Z 256 } 257 258 float getTranslationZ() const { 259 return mPrimitiveFields.mTranslationZ; 260 } 261 262 // Animation helper 263 bool setX(float value) { 264 return setTranslationX(value - getLeft()); 265 } 266 267 // Animation helper 268 float getX() const { 269 return getLeft() + getTranslationX(); 270 } 271 272 // Animation helper 273 bool setY(float value) { 274 return setTranslationY(value - getTop()); 275 } 276 277 // Animation helper 278 float getY() const { 279 return getTop() + getTranslationY(); 280 } 281 282 // Animation helper 283 bool setZ(float value) { 284 return setTranslationZ(value - getElevation()); 285 } 286 287 float getZ() const { 288 return getElevation() + getTranslationZ(); 289 } 290 291 bool setRotation(float rotation) { 292 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation); 293 } 294 295 float getRotation() const { 296 return mPrimitiveFields.mRotation; 297 } 298 299 bool setRotationX(float rotationX) { 300 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX); 301 } 302 303 float getRotationX() const { 304 return mPrimitiveFields.mRotationX; 305 } 306 307 bool setRotationY(float rotationY) { 308 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY); 309 } 310 311 float getRotationY() const { 312 return mPrimitiveFields.mRotationY; 313 } 314 315 bool setScaleX(float scaleX) { 316 LOG_ALWAYS_FATAL_IF(scaleX > 1000000, "invalid scaleX %e", 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 LOG_ALWAYS_FATAL_IF(scaleY > 1000000, "invalid scaleY %e", scaleY); 326 return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY); 327 } 328 329 float getScaleY() const { 330 return mPrimitiveFields.mScaleY; 331 } 332 333 bool setPivotX(float pivotX) { 334 if (RP_SET(mPrimitiveFields.mPivotX, pivotX) 335 || !mPrimitiveFields.mPivotExplicitlySet) { 336 mPrimitiveFields.mMatrixOrPivotDirty = true; 337 mPrimitiveFields.mPivotExplicitlySet = true; 338 return true; 339 } 340 return false; 341 } 342 343 /* Note that getPivotX and getPivotY are adjusted by updateMatrix(), 344 * so the value returned may be stale if the RenderProperties has been 345 * modified since the last call to updateMatrix() 346 */ 347 float getPivotX() const { 348 return mPrimitiveFields.mPivotX; 349 } 350 351 bool setPivotY(float pivotY) { 352 if (RP_SET(mPrimitiveFields.mPivotY, pivotY) 353 || !mPrimitiveFields.mPivotExplicitlySet) { 354 mPrimitiveFields.mMatrixOrPivotDirty = true; 355 mPrimitiveFields.mPivotExplicitlySet = true; 356 return true; 357 } 358 return false; 359 } 360 361 float getPivotY() const { 362 return mPrimitiveFields.mPivotY; 363 } 364 365 bool isPivotExplicitlySet() const { 366 return mPrimitiveFields.mPivotExplicitlySet; 367 } 368 369 bool setCameraDistance(float distance) { 370 if (distance != getCameraDistance()) { 371 mPrimitiveFields.mMatrixOrPivotDirty = true; 372 mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance); 373 return true; 374 } 375 return false; 376 } 377 378 float getCameraDistance() const { 379 // TODO: update getCameraLocationZ() to be const 380 return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ(); 381 } 382 383 bool setLeft(int left) { 384 if (RP_SET(mPrimitiveFields.mLeft, left)) { 385 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 386 if (!mPrimitiveFields.mPivotExplicitlySet) { 387 mPrimitiveFields.mMatrixOrPivotDirty = true; 388 } 389 return true; 390 } 391 return false; 392 } 393 394 float getLeft() const { 395 return mPrimitiveFields.mLeft; 396 } 397 398 bool setTop(int top) { 399 if (RP_SET(mPrimitiveFields.mTop, top)) { 400 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 401 if (!mPrimitiveFields.mPivotExplicitlySet) { 402 mPrimitiveFields.mMatrixOrPivotDirty = true; 403 } 404 return true; 405 } 406 return false; 407 } 408 409 float getTop() const { 410 return mPrimitiveFields.mTop; 411 } 412 413 bool setRight(int right) { 414 if (RP_SET(mPrimitiveFields.mRight, right)) { 415 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 416 if (!mPrimitiveFields.mPivotExplicitlySet) { 417 mPrimitiveFields.mMatrixOrPivotDirty = true; 418 } 419 return true; 420 } 421 return false; 422 } 423 424 float getRight() const { 425 return mPrimitiveFields.mRight; 426 } 427 428 bool setBottom(int bottom) { 429 if (RP_SET(mPrimitiveFields.mBottom, bottom)) { 430 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 431 if (!mPrimitiveFields.mPivotExplicitlySet) { 432 mPrimitiveFields.mMatrixOrPivotDirty = true; 433 } 434 return true; 435 } 436 return false; 437 } 438 439 float getBottom() const { 440 return mPrimitiveFields.mBottom; 441 } 442 443 bool setLeftTop(int left, int top) { 444 bool leftResult = setLeft(left); 445 bool topResult = setTop(top); 446 return leftResult || topResult; 447 } 448 449 bool setLeftTopRightBottom(int left, int top, int right, int bottom) { 450 if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop 451 || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) { 452 mPrimitiveFields.mLeft = left; 453 mPrimitiveFields.mTop = top; 454 mPrimitiveFields.mRight = right; 455 mPrimitiveFields.mBottom = bottom; 456 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 457 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 458 if (!mPrimitiveFields.mPivotExplicitlySet) { 459 mPrimitiveFields.mMatrixOrPivotDirty = true; 460 } 461 return true; 462 } 463 return false; 464 } 465 466 bool offsetLeftRight(int offset) { 467 if (offset != 0) { 468 mPrimitiveFields.mLeft += offset; 469 mPrimitiveFields.mRight += offset; 470 return true; 471 } 472 return false; 473 } 474 475 bool offsetTopBottom(int offset) { 476 if (offset != 0) { 477 mPrimitiveFields.mTop += offset; 478 mPrimitiveFields.mBottom += offset; 479 return true; 480 } 481 return false; 482 } 483 484 int getWidth() const { 485 return mPrimitiveFields.mWidth; 486 } 487 488 int getHeight() const { 489 return mPrimitiveFields.mHeight; 490 } 491 492 const SkMatrix* getAnimationMatrix() const { 493 return mAnimationMatrix; 494 } 495 496 bool hasTransformMatrix() const { 497 return getTransformMatrix() && !getTransformMatrix()->isIdentity(); 498 } 499 500 // May only call this if hasTransformMatrix() is true 501 bool isTransformTranslateOnly() const { 502 return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask; 503 } 504 505 const SkMatrix* getTransformMatrix() const { 506 LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!"); 507 return mComputedFields.mTransformMatrix; 508 } 509 510 int getClippingFlags() const { 511 return mPrimitiveFields.mClippingFlags; 512 } 513 514 bool getClipToBounds() const { 515 return mPrimitiveFields.mClippingFlags & CLIP_TO_BOUNDS; 516 } 517 518 void getClippingRectForFlags(uint32_t flags, Rect* outRect) const { 519 if (flags & CLIP_TO_BOUNDS) { 520 outRect->set(0, 0, getWidth(), getHeight()); 521 if (flags & CLIP_TO_CLIP_BOUNDS) { 522 outRect->intersect(mPrimitiveFields.mClipBounds); 523 } 524 } else { 525 outRect->set(mPrimitiveFields.mClipBounds); 526 } 527 } 528 529 bool getHasOverlappingRendering() const { 530 return mPrimitiveFields.mHasOverlappingRendering; 531 } 532 533 const Outline& getOutline() const { 534 return mPrimitiveFields.mOutline; 535 } 536 537 const RevealClip& getRevealClip() const { 538 return mPrimitiveFields.mRevealClip; 539 } 540 541 bool getProjectBackwards() const { 542 return mPrimitiveFields.mProjectBackwards; 543 } 544 545 void debugOutputProperties(const int level) const; 546 547 void updateMatrix(); 548 549 Outline& mutableOutline() { 550 return mPrimitiveFields.mOutline; 551 } 552 553 RevealClip& mutableRevealClip() { 554 return mPrimitiveFields.mRevealClip; 555 } 556 557 const LayerProperties& layerProperties() const { 558 return mLayerProperties; 559 } 560 561 LayerProperties& mutateLayerProperties() { 562 return mLayerProperties; 563 } 564 565 // Returns true if damage calculations should be clipped to bounds 566 // TODO: Figure out something better for getZ(), as children should still be 567 // clipped to this RP's bounds. But as we will damage -INT_MAX to INT_MAX 568 // for this RP's getZ() anyway, this can be optimized when we have a 569 // Z damage estimate instead of INT_MAX 570 bool getClipDamageToBounds() const { 571 return getClipToBounds() && (getZ() <= 0 || getOutline().isEmpty()); 572 } 573 574private: 575 // Rendering properties 576 struct PrimitiveFields { 577 PrimitiveFields(); 578 579 Outline mOutline; 580 RevealClip mRevealClip; 581 int mClippingFlags; 582 bool mProjectBackwards; 583 bool mProjectionReceiver; 584 float mAlpha; 585 bool mHasOverlappingRendering; 586 float mElevation; 587 float mTranslationX, mTranslationY, mTranslationZ; 588 float mRotation, mRotationX, mRotationY; 589 float mScaleX, mScaleY; 590 float mPivotX, mPivotY; 591 int mLeft, mTop, mRight, mBottom; 592 int mWidth, mHeight; 593 bool mPivotExplicitlySet; 594 bool mMatrixOrPivotDirty; 595 Rect mClipBounds; 596 } mPrimitiveFields; 597 598 SkMatrix* mStaticMatrix; 599 SkMatrix* mAnimationMatrix; 600 LayerProperties mLayerProperties; 601 602 /** 603 * These fields are all generated from other properties and are not set directly. 604 */ 605 struct ComputedFields { 606 ComputedFields(); 607 ~ComputedFields(); 608 609 /** 610 * Stores the total transformation of the DisplayList based upon its scalar 611 * translate/rotate/scale properties. 612 * 613 * In the common translation-only case, the matrix isn't necessarily allocated, 614 * and the mTranslation properties are used directly. 615 */ 616 SkMatrix* mTransformMatrix; 617 618 Sk3DView mTransformCamera; 619 } mComputedFields; 620}; 621 622} /* namespace uirenderer */ 623} /* namespace android */ 624 625#endif /* RENDERNODEPROPERTIES_H */ 626