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