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