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