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