RenderProperties.h revision 79c7de77a7da9cbcb9428ab6203987feb35a427f
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 34class SkBitmap; 35class SkPaint; 36 37namespace android { 38namespace uirenderer { 39 40class Matrix4; 41class RenderNode; 42 43// The __VA_ARGS__ will be executed if a & b are not equal 44#define RP_SET(a, b, ...) (a != b ? (a = b, ##__VA_ARGS__, true) : false) 45#define RP_SET_AND_DIRTY(a, b) RP_SET(a, b, mPrimitiveFields.mMatrixOrPivotDirty = true) 46 47/* 48 * Data structure that holds the properties for a RenderNode 49 */ 50class RenderProperties { 51public: 52 RenderProperties(); 53 virtual ~RenderProperties(); 54 55 RenderProperties& operator=(const RenderProperties& other); 56 57 bool setClipToBounds(bool clipToBounds) { 58 return RP_SET(mPrimitiveFields.mClipToBounds, clipToBounds); 59 } 60 61 bool setProjectBackwards(bool shouldProject) { 62 return RP_SET(mPrimitiveFields.mProjectBackwards, shouldProject); 63 } 64 65 bool setProjectionReceiver(bool shouldRecieve) { 66 return RP_SET(mPrimitiveFields.mProjectionReceiver, shouldRecieve); 67 } 68 69 bool isProjectionReceiver() const { 70 return mPrimitiveFields.mProjectionReceiver; 71 } 72 73 bool setStaticMatrix(const SkMatrix* matrix) { 74 delete mStaticMatrix; 75 if (matrix) { 76 mStaticMatrix = new SkMatrix(*matrix); 77 } else { 78 mStaticMatrix = NULL; 79 } 80 return true; 81 } 82 83 // Can return NULL 84 const SkMatrix* getStaticMatrix() const { 85 return mStaticMatrix; 86 } 87 88 bool setAnimationMatrix(const SkMatrix* matrix) { 89 delete mAnimationMatrix; 90 if (matrix) { 91 mAnimationMatrix = new SkMatrix(*matrix); 92 } else { 93 mAnimationMatrix = NULL; 94 } 95 return true; 96 } 97 98 bool setAlpha(float alpha) { 99 alpha = fminf(1.0f, fmaxf(0.0f, alpha)); 100 return RP_SET(mPrimitiveFields.mAlpha, alpha); 101 } 102 103 float getAlpha() const { 104 return mPrimitiveFields.mAlpha; 105 } 106 107 bool setHasOverlappingRendering(bool hasOverlappingRendering) { 108 return RP_SET(mPrimitiveFields.mHasOverlappingRendering, hasOverlappingRendering); 109 } 110 111 bool hasOverlappingRendering() const { 112 return mPrimitiveFields.mHasOverlappingRendering; 113 } 114 115 bool setElevation(float elevation) { 116 return RP_SET(mPrimitiveFields.mElevation, elevation); 117 // Don't dirty matrix/pivot, since they don't respect Z 118 } 119 120 float getElevation() const { 121 return mPrimitiveFields.mElevation; 122 } 123 124 bool setTranslationX(float translationX) { 125 return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationX, translationX); 126 } 127 128 float getTranslationX() const { 129 return mPrimitiveFields.mTranslationX; 130 } 131 132 bool setTranslationY(float translationY) { 133 return RP_SET_AND_DIRTY(mPrimitiveFields.mTranslationY, translationY); 134 } 135 136 float getTranslationY() const { 137 return mPrimitiveFields.mTranslationY; 138 } 139 140 bool setTranslationZ(float translationZ) { 141 return RP_SET(mPrimitiveFields.mTranslationZ, translationZ); 142 // mMatrixOrPivotDirty not set, since matrix doesn't respect Z 143 } 144 145 float getTranslationZ() const { 146 return mPrimitiveFields.mTranslationZ; 147 } 148 149 // Animation helper 150 bool setX(float value) { 151 return setTranslationX(value - getLeft()); 152 } 153 154 // Animation helper 155 float getX() const { 156 return getLeft() + getTranslationX(); 157 } 158 159 // Animation helper 160 bool setY(float value) { 161 return setTranslationY(value - getTop()); 162 } 163 164 // Animation helper 165 float getY() const { 166 return getTop() + getTranslationY(); 167 } 168 169 // Animation helper 170 bool setZ(float value) { 171 return setTranslationZ(value - getElevation()); 172 } 173 174 float getZ() const { 175 return getElevation() + getTranslationZ(); 176 } 177 178 bool setRotation(float rotation) { 179 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotation, rotation); 180 } 181 182 float getRotation() const { 183 return mPrimitiveFields.mRotation; 184 } 185 186 bool setRotationX(float rotationX) { 187 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationX, rotationX); 188 } 189 190 float getRotationX() const { 191 return mPrimitiveFields.mRotationX; 192 } 193 194 bool setRotationY(float rotationY) { 195 return RP_SET_AND_DIRTY(mPrimitiveFields.mRotationY, rotationY); 196 } 197 198 float getRotationY() const { 199 return mPrimitiveFields.mRotationY; 200 } 201 202 bool setScaleX(float scaleX) { 203 return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleX, scaleX); 204 } 205 206 float getScaleX() const { 207 return mPrimitiveFields.mScaleX; 208 } 209 210 bool setScaleY(float scaleY) { 211 return RP_SET_AND_DIRTY(mPrimitiveFields.mScaleY, scaleY); 212 } 213 214 float getScaleY() const { 215 return mPrimitiveFields.mScaleY; 216 } 217 218 bool setPivotX(float pivotX) { 219 if (RP_SET(mPrimitiveFields.mPivotX, pivotX) 220 || !mPrimitiveFields.mPivotExplicitlySet) { 221 mPrimitiveFields.mMatrixOrPivotDirty = true; 222 mPrimitiveFields.mPivotExplicitlySet = true; 223 return true; 224 } 225 return false; 226 } 227 228 /* Note that getPivotX and getPivotY are adjusted by updateMatrix(), 229 * so the value returned may be stale if the RenderProperties has been 230 * modified since the last call to updateMatrix() 231 */ 232 float getPivotX() const { 233 return mPrimitiveFields.mPivotX; 234 } 235 236 bool setPivotY(float pivotY) { 237 if (RP_SET(mPrimitiveFields.mPivotY, pivotY) 238 || !mPrimitiveFields.mPivotExplicitlySet) { 239 mPrimitiveFields.mMatrixOrPivotDirty = true; 240 mPrimitiveFields.mPivotExplicitlySet = true; 241 return true; 242 } 243 return false; 244 } 245 246 float getPivotY() const { 247 return mPrimitiveFields.mPivotY; 248 } 249 250 bool isPivotExplicitlySet() const { 251 return mPrimitiveFields.mPivotExplicitlySet; 252 } 253 254 bool setCameraDistance(float distance) { 255 if (distance != getCameraDistance()) { 256 mPrimitiveFields.mMatrixOrPivotDirty = true; 257 mComputedFields.mTransformCamera.setCameraLocation(0, 0, distance); 258 return true; 259 } 260 return false; 261 } 262 263 float getCameraDistance() const { 264 // TODO: update getCameraLocationZ() to be const 265 return const_cast<Sk3DView*>(&mComputedFields.mTransformCamera)->getCameraLocationZ(); 266 } 267 268 bool setLeft(int left) { 269 if (RP_SET(mPrimitiveFields.mLeft, left)) { 270 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 271 if (!mPrimitiveFields.mPivotExplicitlySet) { 272 mPrimitiveFields.mMatrixOrPivotDirty = true; 273 } 274 return true; 275 } 276 return false; 277 } 278 279 float getLeft() const { 280 return mPrimitiveFields.mLeft; 281 } 282 283 bool setTop(int top) { 284 if (RP_SET(mPrimitiveFields.mTop, top)) { 285 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 286 if (!mPrimitiveFields.mPivotExplicitlySet) { 287 mPrimitiveFields.mMatrixOrPivotDirty = true; 288 } 289 return true; 290 } 291 return false; 292 } 293 294 float getTop() const { 295 return mPrimitiveFields.mTop; 296 } 297 298 bool setRight(int right) { 299 if (RP_SET(mPrimitiveFields.mRight, right)) { 300 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 301 if (!mPrimitiveFields.mPivotExplicitlySet) { 302 mPrimitiveFields.mMatrixOrPivotDirty = true; 303 } 304 return true; 305 } 306 return false; 307 } 308 309 float getRight() const { 310 return mPrimitiveFields.mRight; 311 } 312 313 bool setBottom(int bottom) { 314 if (RP_SET(mPrimitiveFields.mBottom, bottom)) { 315 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 316 if (!mPrimitiveFields.mPivotExplicitlySet) { 317 mPrimitiveFields.mMatrixOrPivotDirty = true; 318 } 319 return true; 320 } 321 return false; 322 } 323 324 float getBottom() const { 325 return mPrimitiveFields.mBottom; 326 } 327 328 bool setLeftTop(int left, int top) { 329 bool leftResult = setLeft(left); 330 bool topResult = setTop(top); 331 return leftResult || topResult; 332 } 333 334 bool setLeftTopRightBottom(int left, int top, int right, int bottom) { 335 if (left != mPrimitiveFields.mLeft || top != mPrimitiveFields.mTop 336 || right != mPrimitiveFields.mRight || bottom != mPrimitiveFields.mBottom) { 337 mPrimitiveFields.mLeft = left; 338 mPrimitiveFields.mTop = top; 339 mPrimitiveFields.mRight = right; 340 mPrimitiveFields.mBottom = bottom; 341 mPrimitiveFields.mWidth = mPrimitiveFields.mRight - mPrimitiveFields.mLeft; 342 mPrimitiveFields.mHeight = mPrimitiveFields.mBottom - mPrimitiveFields.mTop; 343 if (!mPrimitiveFields.mPivotExplicitlySet) { 344 mPrimitiveFields.mMatrixOrPivotDirty = true; 345 } 346 return true; 347 } 348 return false; 349 } 350 351 bool offsetLeftRight(float offset) { 352 if (offset != 0) { 353 mPrimitiveFields.mLeft += offset; 354 mPrimitiveFields.mRight += offset; 355 return true; 356 } 357 return false; 358 } 359 360 bool offsetTopBottom(float offset) { 361 if (offset != 0) { 362 mPrimitiveFields.mTop += offset; 363 mPrimitiveFields.mBottom += offset; 364 return true; 365 } 366 return false; 367 } 368 369 bool setCaching(bool caching) { 370 return RP_SET(mPrimitiveFields.mCaching, caching); 371 } 372 373 int getWidth() const { 374 return mPrimitiveFields.mWidth; 375 } 376 377 int getHeight() const { 378 return mPrimitiveFields.mHeight; 379 } 380 381 const SkMatrix* getAnimationMatrix() const { 382 return mAnimationMatrix; 383 } 384 385 bool hasTransformMatrix() const { 386 return getTransformMatrix() && !getTransformMatrix()->isIdentity(); 387 } 388 389 // May only call this if hasTransformMatrix() is true 390 bool isTransformTranslateOnly() const { 391 return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask; 392 } 393 394 const SkMatrix* getTransformMatrix() const { 395 LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!"); 396 return mComputedFields.mTransformMatrix; 397 } 398 399 bool getCaching() const { 400 return mPrimitiveFields.mCaching; 401 } 402 403 bool getClipToBounds() const { 404 return mPrimitiveFields.mClipToBounds; 405 } 406 407 bool getHasOverlappingRendering() const { 408 return mPrimitiveFields.mHasOverlappingRendering; 409 } 410 411 const Outline& getOutline() const { 412 return mPrimitiveFields.mOutline; 413 } 414 415 const RevealClip& getRevealClip() const { 416 return mPrimitiveFields.mRevealClip; 417 } 418 419 bool getProjectBackwards() const { 420 return mPrimitiveFields.mProjectBackwards; 421 } 422 423 void debugOutputProperties(const int level) const; 424 425 ANDROID_API void updateMatrix(); 426 427 bool hasClippingPath() const { 428 return mPrimitiveFields.mRevealClip.willClip(); 429 } 430 431 const SkPath* getClippingPath() const { 432 return mPrimitiveFields.mRevealClip.getPath(); 433 } 434 435 SkRegion::Op getClippingPathOp() const { 436 return mPrimitiveFields.mRevealClip.isInverseClip() 437 ? SkRegion::kDifference_Op : SkRegion::kIntersect_Op; 438 } 439 440 Outline& mutableOutline() { 441 return mPrimitiveFields.mOutline; 442 } 443 444 RevealClip& mutableRevealClip() { 445 return mPrimitiveFields.mRevealClip; 446 } 447 448private: 449 450 // Rendering properties 451 struct PrimitiveFields { 452 PrimitiveFields(); 453 454 Outline mOutline; 455 RevealClip mRevealClip; 456 bool mClipToBounds; 457 bool mProjectBackwards; 458 bool mProjectionReceiver; 459 float mAlpha; 460 bool mHasOverlappingRendering; 461 float mElevation; 462 float mTranslationX, mTranslationY, mTranslationZ; 463 float mRotation, mRotationX, mRotationY; 464 float mScaleX, mScaleY; 465 float mPivotX, mPivotY; 466 int mLeft, mTop, mRight, mBottom; 467 int mWidth, mHeight; 468 bool mPivotExplicitlySet; 469 bool mMatrixOrPivotDirty; 470 bool mCaching; 471 } mPrimitiveFields; 472 473 SkMatrix* mStaticMatrix; 474 SkMatrix* mAnimationMatrix; 475 476 /** 477 * These fields are all generated from other properties and are not set directly. 478 */ 479 struct ComputedFields { 480 ComputedFields(); 481 ~ComputedFields(); 482 483 /** 484 * Stores the total transformation of the DisplayList based upon its scalar 485 * translate/rotate/scale properties. 486 * 487 * In the common translation-only case, the matrix isn't necessarily allocated, 488 * and the mTranslation properties are used directly. 489 */ 490 SkMatrix* mTransformMatrix; 491 492 Sk3DView mTransformCamera; 493 } mComputedFields; 494}; 495 496} /* namespace uirenderer */ 497} /* namespace android */ 498 499#endif /* RENDERNODEPROPERTIES_H */ 500