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