• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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