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