RenderProperties.cpp revision 49e6c73913e9bee58ea5e3984be151ee8e033163
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you mPrimitiveFields.may not use this file except in compliance with the License.
6 * You mPrimitiveFields.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
17#define LOG_TAG "OpenGLRenderer"
18
19#include "RenderProperties.h"
20
21#include <utils/Trace.h>
22
23#include <SkCanvas.h>
24#include <SkMatrix.h>
25#include <SkPath.h>
26#include <SkPathOps.h>
27
28#include "Matrix.h"
29
30namespace android {
31namespace uirenderer {
32
33RenderProperties::PrimitiveFields::PrimitiveFields()
34        : mClipToBounds(true)
35        , mProjectBackwards(false)
36        , mProjectionReceiver(false)
37        , mAlpha(1)
38        , mHasOverlappingRendering(true)
39        , mTranslationX(0), mTranslationY(0), mTranslationZ(0)
40        , mRotation(0), mRotationX(0), mRotationY(0)
41        , mScaleX(1), mScaleY(1)
42        , mPivotX(0), mPivotY(0)
43        , mLeft(0), mTop(0), mRight(0), mBottom(0)
44        , mWidth(0), mHeight(0)
45        , mPrevWidth(-1), mPrevHeight(-1)
46        , mPivotExplicitlySet(false)
47        , mMatrixDirty(false)
48        , mMatrixFlags(0)
49        , mCaching(false) {
50}
51
52RenderProperties::ComputedFields::ComputedFields()
53        : mTransformMatrix(NULL)
54        , mTransformMatrix3D(NULL)
55        , mClipPath(NULL) {
56}
57
58RenderProperties::ComputedFields::~ComputedFields() {
59    delete mTransformMatrix;
60    delete mTransformMatrix3D;
61    delete mClipPath;
62}
63
64RenderProperties::RenderProperties()
65        : mStaticMatrix(NULL)
66        , mAnimationMatrix(NULL) {
67}
68
69RenderProperties::~RenderProperties() {
70    delete mStaticMatrix;
71    delete mAnimationMatrix;
72}
73
74RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
75    if (this != &other) {
76        mPrimitiveFields = other.mPrimitiveFields;
77        setStaticMatrix(other.getStaticMatrix());
78        setAnimationMatrix(other.getAnimationMatrix());
79        setCameraDistance(other.getCameraDistance());
80
81        // Update the computed clip path
82        updateClipPath();
83
84        // Force recalculation of the matrix, since other's dirty bit may be clear
85        mPrimitiveFields.mMatrixDirty = true;
86        updateMatrix();
87    }
88    return *this;
89}
90
91void RenderProperties::debugOutputProperties(const int level) const {
92    if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
93        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
94    }
95    if (mStaticMatrix) {
96        ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
97                level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
98    }
99    if (mAnimationMatrix) {
100        ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
101                level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
102    }
103    if (mPrimitiveFields.mMatrixFlags != 0) {
104        if (mPrimitiveFields.mMatrixFlags == TRANSLATION) {
105            ALOGD("%*sTranslate %.2f, %.2f, %.2f",
106                    level * 2, "", mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY, mPrimitiveFields.mTranslationZ);
107        } else {
108            ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
109                    level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
110        }
111    }
112
113    bool clipToBoundsNeeded = mPrimitiveFields.mCaching ? false : mPrimitiveFields.mClipToBounds;
114    if (mPrimitiveFields.mAlpha < 1) {
115        if (mPrimitiveFields.mCaching) {
116            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
117        } else if (!mPrimitiveFields.mHasOverlappingRendering) {
118            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
119        } else {
120            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
121            if (clipToBoundsNeeded) {
122                flags |= SkCanvas::kClipToLayer_SaveFlag;
123                clipToBoundsNeeded = false; // clipping done by save layer
124            }
125            ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
126                    0, 0, getWidth(), getHeight(),
127                    (int)(mPrimitiveFields.mAlpha * 255), flags);
128        }
129    }
130    if (clipToBoundsNeeded) {
131        ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
132                0, 0, getWidth(), getHeight());
133    }
134}
135
136void RenderProperties::updateMatrix() {
137    if (mPrimitiveFields.mMatrixDirty) {
138        // NOTE: mComputedFields.mTransformMatrix won't be up to date if a DisplayList goes from a complex transform
139        // to a pure translate. This is safe because the mPrimitiveFields.matrix isn't read in pure translate cases.
140        if (mPrimitiveFields.mMatrixFlags && mPrimitiveFields.mMatrixFlags != TRANSLATION) {
141            if (!mComputedFields.mTransformMatrix) {
142                // only allocate a mPrimitiveFields.matrix if we have a complex transform
143                mComputedFields.mTransformMatrix = new SkMatrix();
144            }
145            if (!mPrimitiveFields.mPivotExplicitlySet) {
146                if (mPrimitiveFields.mWidth != mPrimitiveFields.mPrevWidth || mPrimitiveFields.mHeight != mPrimitiveFields.mPrevHeight) {
147                    mPrimitiveFields.mPrevWidth = mPrimitiveFields.mWidth;
148                    mPrimitiveFields.mPrevHeight = mPrimitiveFields.mHeight;
149                    mPrimitiveFields.mPivotX = mPrimitiveFields.mPrevWidth / 2.0f;
150                    mPrimitiveFields.mPivotY = mPrimitiveFields.mPrevHeight / 2.0f;
151                }
152            }
153
154            if ((mPrimitiveFields.mMatrixFlags & ROTATION_3D) == 0) {
155                mComputedFields.mTransformMatrix->setTranslate(
156                        mPrimitiveFields.mTranslationX, mPrimitiveFields.mTranslationY);
157                mComputedFields.mTransformMatrix->preRotate(mPrimitiveFields.mRotation,
158                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
159                mComputedFields.mTransformMatrix->preScale(
160                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
161                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
162            } else {
163                if (!mComputedFields.mTransformMatrix3D) {
164                    mComputedFields.mTransformMatrix3D = new SkMatrix();
165                }
166                mComputedFields.mTransformMatrix->reset();
167                mComputedFields.mTransformCamera.save();
168                mComputedFields.mTransformMatrix->preScale(
169                        mPrimitiveFields.mScaleX, mPrimitiveFields.mScaleY,
170                        mPrimitiveFields.mPivotX, mPrimitiveFields.mPivotY);
171                mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
172                mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
173                mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
174                mComputedFields.mTransformCamera.getMatrix(mComputedFields.mTransformMatrix3D);
175                mComputedFields.mTransformMatrix3D->preTranslate(-mPrimitiveFields.mPivotX, -mPrimitiveFields.mPivotY);
176                mComputedFields.mTransformMatrix3D->postTranslate(mPrimitiveFields.mPivotX + mPrimitiveFields.mTranslationX,
177                        mPrimitiveFields.mPivotY + mPrimitiveFields.mTranslationY);
178                mComputedFields.mTransformMatrix->postConcat(*mComputedFields.mTransformMatrix3D);
179                mComputedFields.mTransformCamera.restore();
180            }
181        }
182        mPrimitiveFields.mMatrixDirty = false;
183    }
184}
185
186void RenderProperties::updateClipPath() {
187    const SkPath* outlineClipPath = mPrimitiveFields.mOutline.willClip()
188            ? mPrimitiveFields.mOutline.getPath() : NULL;
189    const SkPath* revealClipPath = mPrimitiveFields.mRevealClip.getPath();
190
191    if (!outlineClipPath && !revealClipPath) {
192        // mComputedFields.mClipPath doesn't need to be updated, since it won't be used
193        return;
194    }
195
196    if (mComputedFields.mClipPath == NULL) {
197        mComputedFields.mClipPath = new SkPath();
198    }
199    SkPath* clipPath = mComputedFields.mClipPath;
200    mComputedFields.mClipPathOp = SkRegion::kIntersect_Op;
201
202    if (outlineClipPath && revealClipPath) {
203        SkPathOp op = kIntersect_PathOp;
204        if (mPrimitiveFields.mRevealClip.isInverseClip()) {
205            op = kDifference_PathOp; // apply difference step in the Op below, instead of draw time
206        }
207
208        Op(*outlineClipPath, *revealClipPath, op, clipPath);
209    } else if (outlineClipPath) {
210        *clipPath = *outlineClipPath;
211    } else {
212        *clipPath = *revealClipPath;
213        if (mPrimitiveFields.mRevealClip.isInverseClip()) {
214            // apply difference step at draw time
215            mComputedFields.mClipPathOp = SkRegion::kDifference_Op;
216        }
217    }
218}
219
220} /* namespace uirenderer */
221} /* namespace android */
222