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