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