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