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