RenderProperties.h revision 79c7de77a7da9cbcb9428ab6203987feb35a427f
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 setCaching(bool caching) {
370        return RP_SET(mPrimitiveFields.mCaching, caching);
371    }
372
373    int getWidth() const {
374        return mPrimitiveFields.mWidth;
375    }
376
377    int getHeight() const {
378        return mPrimitiveFields.mHeight;
379    }
380
381    const SkMatrix* getAnimationMatrix() const {
382        return mAnimationMatrix;
383    }
384
385    bool hasTransformMatrix() const {
386        return getTransformMatrix() && !getTransformMatrix()->isIdentity();
387    }
388
389    // May only call this if hasTransformMatrix() is true
390    bool isTransformTranslateOnly() const {
391        return getTransformMatrix()->getType() == SkMatrix::kTranslate_Mask;
392    }
393
394    const SkMatrix* getTransformMatrix() const {
395        LOG_ALWAYS_FATAL_IF(mPrimitiveFields.mMatrixOrPivotDirty, "Cannot get a dirty matrix!");
396        return mComputedFields.mTransformMatrix;
397    }
398
399    bool getCaching() const {
400        return mPrimitiveFields.mCaching;
401    }
402
403    bool getClipToBounds() const {
404        return mPrimitiveFields.mClipToBounds;
405    }
406
407    bool getHasOverlappingRendering() const {
408        return mPrimitiveFields.mHasOverlappingRendering;
409    }
410
411    const Outline& getOutline() const {
412        return mPrimitiveFields.mOutline;
413    }
414
415    const RevealClip& getRevealClip() const {
416        return mPrimitiveFields.mRevealClip;
417    }
418
419    bool getProjectBackwards() const {
420        return mPrimitiveFields.mProjectBackwards;
421    }
422
423    void debugOutputProperties(const int level) const;
424
425    ANDROID_API void updateMatrix();
426
427    bool hasClippingPath() const {
428        return mPrimitiveFields.mRevealClip.willClip();
429    }
430
431    const SkPath* getClippingPath() const {
432        return mPrimitiveFields.mRevealClip.getPath();
433    }
434
435    SkRegion::Op getClippingPathOp() const {
436        return mPrimitiveFields.mRevealClip.isInverseClip()
437                ? SkRegion::kDifference_Op : SkRegion::kIntersect_Op;
438    }
439
440    Outline& mutableOutline() {
441        return mPrimitiveFields.mOutline;
442    }
443
444    RevealClip& mutableRevealClip() {
445        return mPrimitiveFields.mRevealClip;
446    }
447
448private:
449
450    // Rendering properties
451    struct PrimitiveFields {
452        PrimitiveFields();
453
454        Outline mOutline;
455        RevealClip mRevealClip;
456        bool mClipToBounds;
457        bool mProjectBackwards;
458        bool mProjectionReceiver;
459        float mAlpha;
460        bool mHasOverlappingRendering;
461        float mElevation;
462        float mTranslationX, mTranslationY, mTranslationZ;
463        float mRotation, mRotationX, mRotationY;
464        float mScaleX, mScaleY;
465        float mPivotX, mPivotY;
466        int mLeft, mTop, mRight, mBottom;
467        int mWidth, mHeight;
468        bool mPivotExplicitlySet;
469        bool mMatrixOrPivotDirty;
470        bool mCaching;
471    } mPrimitiveFields;
472
473    SkMatrix* mStaticMatrix;
474    SkMatrix* mAnimationMatrix;
475
476    /**
477     * These fields are all generated from other properties and are not set directly.
478     */
479    struct ComputedFields {
480        ComputedFields();
481        ~ComputedFields();
482
483        /**
484         * Stores the total transformation of the DisplayList based upon its scalar
485         * translate/rotate/scale properties.
486         *
487         * In the common translation-only case, the matrix isn't necessarily allocated,
488         * and the mTranslation properties are used directly.
489         */
490        SkMatrix* mTransformMatrix;
491
492        Sk3DView mTransformCamera;
493    } mComputedFields;
494};
495
496} /* namespace uirenderer */
497} /* namespace android */
498
499#endif /* RENDERNODEPROPERTIES_H */
500