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