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