RenderProperties.h revision fe02b4b344c37200486d8afc972560fb550cb17e
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 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 LOG_ALWAYS_FATAL_IF(scaleX > 1000000, "invalid scaleX %e", scaleX); 286 return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX); 287 } 288 289 float getScaleX() const { 290 return mPrimitiveFields.mScaleX; 291 } 292 293 bool setScaleY(float scaleY) { 294 LOG_ALWAYS_FATAL_IF(scaleY > 1000000, "invalid scaleY %e", scaleY); 295 return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY); 296 } 297 298 float getScaleY() const { 299 return mPrimitiveFields.mScaleY; 300 } 301 302 bool setPivotX(float pivotX) { 303 if (RP_SET(mPrimitiveFields.mPivotX, pivotX) 304 || !mPrimitiveFields.mPivotExplicitlySet) { 305 mPrimitiveFields.mMatrixOrPivotDirty = true; 306 mPrimitiveFields.mPivotExplicitlySet = true; 307 return true; 308 } 309 return false; 310 } 311 312 /* Note that getPivotX and getPivotY are adjusted by updateMatrix(), 313 * so the value returned may be stale if the RenderProperties has been 314 * modified since the last call to updateMatrix() 315 */ 316 float getPivotX() const { 317 return mPrimitiveFields.mPivotX; 318 } 319 320 bool setPivotY(float pivotY) { 321 if (RP_SET(mPrimitiveFields.mPivotY, pivotY) 322 || !mPrimitiveFields.mPivotExplicitlySet) { 323 mPrimitiveFields.mMatrixOrPivotDirty = true; 324 mPrimitiveFields.mPivotExplicitlySet = true; 325 return true; 326 } 327 return false; 328 } 329 330 float getPivotY() const { 331 return mPrimitiveFields.mPivotY; 332 } 333 334 bool isPivotExplicitlySet() const { 335 return mPrimitiveFields.mPivotExplicitlySet; 336 } 337 338 bool setCameraDistance(float distance) { 339 if (distance != getCameraDistance()) { 340 mPrimitiveFields.mMatrixOrPivotDirty = true; 341 mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance); 342 return true; 343 } 344 return false; 345 } 346 347 float getCameraDistance() const { 348 // TODO: update getCameraLocationZ() to be const 349 return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ(); 350 } 351 352 bool setLeft(int left) { 353 if (RP_SET(mPrimitiveFields.mLeft, left)) { 354 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 355 if (!mPrimitiveFields.mPivotExplicitlySet) { 356 mPrimitiveFields.mMatrixOrPivotDirty = true; 357 } 358 return true; 359 } 360 return false; 361 } 362 363 float getLeft() const { 364 return mPrimitiveFields.mLeft; 365 } 366 367 bool setTop(int top) { 368 if (RP_SET(mPrimitiveFields.mTop, top)) { 369 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 370 if (!mPrimitiveFields.mPivotExplicitlySet) { 371 mPrimitiveFields.mMatrixOrPivotDirty = true; 372 } 373 return true; 374 } 375 return false; 376 } 377 378 float getTop() const { 379 return mPrimitiveFields.mTop; 380 } 381 382 bool setRight(int right) { 383 if (RP_SET(mPrimitiveFields.mRight, right)) { 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 getRight() const { 394 return mPrimitiveFields.mRight; 395 } 396 397 bool setBottom(int bottom) { 398 if (RP_SET(mPrimitiveFields.mBottom, bottom)) { 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 getBottom() const { 409 return mPrimitiveFields.mBottom; 410 } 411 412 bool setLeftTop(int left, int top) { 413 bool leftResult = setLeft(left); 414 bool topResult = setTop(top); 415 return leftResult || topResult; 416 } 417 418 bool setLeftTopRightBottom(int left, int top, int right, int bottom) { 419 if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop 420 || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) { 421 mPrimitiveFields.mLeft = left; 422 mPrimitiveFields.mTop = top; 423 mPrimitiveFields.mRight = right; 424 mPrimitiveFields.mBottom = bottom; 425 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 426 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 427 if (!mPrimitiveFields.mPivotExplicitlySet) { 428 mPrimitiveFields.mMatrixOrPivotDirty = true; 429 } 430 return true; 431 } 432 return false; 433 } 434 435 bool offsetLeftRight(float offset) { 436 if (offset != 0) { 437 mPrimitiveFields.mLeft += offset; 438 mPrimitiveFields.mRight += offset; 439 return true; 440 } 441 return false; 442 } 443 444 bool offsetTopBottom(float offset) { 445 if (offset != 0) { 446 mPrimitiveFields.mTop += offset; 447 mPrimitiveFields.mBottom += offset; 448 return true; 449 } 450 return false; 451 } 452 453 int getWidth() const { 454 return mPrimitiveFields.mWidth; 455 } 456 457 int getHeight() const { 458 return mPrimitiveFields.mHeight; 459 } 460 461 const SkMatrix* getAnimationMatrix() const { 462 return mAnimationMatrix; 463 } 464 465 bool hasTransformMatrix() const { 466 return getTransformMatrix() && !getTransformMatrix()->isIdentity(); 467 } 468 469 // May only call this if hasTransformMatrix() is true 470 bool isTransformTranslateOnly() const { 471 return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask; 472 } 473 474 const SkMatrix* getTransformMatrix() const { 475 LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!"); 476 return mComputedFields.mTransformMatrix; 477 } 478 479 bool getClipToBounds() const { 480 return mPrimitiveFields.mClipToBounds; 481 } 482 483 bool getHasOverlappingRendering() const { 484 return mPrimitiveFields.mHasOverlappingRendering; 485 } 486 487 const Outline& getOutline() const { 488 return mPrimitiveFields.mOutline; 489 } 490 491 const RevealClip& getRevealClip() const { 492 return mPrimitiveFields.mRevealClip; 493 } 494 495 bool getProjectBackwards() const { 496 return mPrimitiveFields.mProjectBackwards; 497 } 498 499 void debugOutputProperties(const int level) const; 500 501 void updateMatrix(); 502 503 bool hasClippingPath() const { 504 return mPrimitiveFields.mRevealClip.willClip(); 505 } 506 507 const SkPath* getClippingPath() const { 508 return mPrimitiveFields.mRevealClip.getPath(); 509 } 510 511 SkRegion::Op getClippingPathOp() const { 512 return mPrimitiveFields.mRevealClip.isInverseClip() 513 ? SkRegion::kDifference_Op : SkRegion::kIntersect_Op; 514 } 515 516 Outline& mutableOutline() { 517 return mPrimitiveFields.mOutline; 518 } 519 520 RevealClip& mutableRevealClip() { 521 return mPrimitiveFields.mRevealClip; 522 } 523 524 const LayerProperties& layerProperties() const { 525 return mLayerProperties; 526 } 527 528 LayerProperties& mutateLayerProperties() { 529 return mLayerProperties; 530 } 531 532private: 533 534 // Rendering properties 535 struct PrimitiveFields { 536 PrimitiveFields(); 537 538 Outline mOutline; 539 RevealClip mRevealClip; 540 bool mClipToBounds; 541 bool mProjectBackwards; 542 bool mProjectionReceiver; 543 float mAlpha; 544 bool mHasOverlappingRendering; 545 float mElevation; 546 float mTranslationX, mTranslationY, mTranslationZ; 547 float mRotation, mRotationX, mRotationY; 548 float mScaleX, mScaleY; 549 float mPivotX, mPivotY; 550 int mLeft, mTop, mRight, mBottom; 551 int mWidth, mHeight; 552 bool mPivotExplicitlySet; 553 bool mMatrixOrPivotDirty; 554 } mPrimitiveFields; 555 556 SkMatrix* mStaticMatrix; 557 SkMatrix* mAnimationMatrix; 558 LayerProperties mLayerProperties; 559 560 /** 561 * These fields are all generated from other properties and are not set directly. 562 */ 563 struct ComputedFields { 564 ComputedFields(); 565 ~ComputedFields(); 566 567 /** 568 * Stores the total transformation of the DisplayList based upon its scalar 569 * translate/rotate/scale properties. 570 * 571 * In the common translation-only case, the matrix isn't necessarily allocated, 572 * and the mTranslation properties are used directly. 573 */ 574 SkMatrix* mTransformMatrix; 575 576 Sk3DView mTransformCamera; 577 } mComputedFields; 578}; 579 580} /* namespace uirenderer */ 581} /* namespace android */ 582 583#endif /* RENDERNODEPROPERTIES_H */ 584