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