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