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