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