RenderProperties.cpp revision cc39e16cb98855f35079941b5e7e6eac2b7bc388
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#include "utils/MathUtils.h"
30
31namespace android {
32namespace uirenderer {
33
34RenderProperties::PrimitiveFields::PrimitiveFields()
35        : mClipToBounds(true)
36        , mProjectBackwards(false)
37        , mProjectionReceiver(false)
38        , mAlpha(1)
39        , mHasOverlappingRendering(true)
40        , mElevation(0)
41        , mTranslationX(0), mTranslationY(0), mTranslationZ(0)
42        , mRotation(0), mRotationX(0), mRotationY(0)
43        , mScaleX(1), mScaleY(1)
44        , mPivotX(0), mPivotY(0)
45        , mLeft(0), mTop(0), mRight(0), mBottom(0)
46        , mWidth(0), mHeight(0)
47        , mPivotExplicitlySet(false)
48        , mMatrixOrPivotDirty(false)
49        , mCaching(false) {
50}
51
52RenderProperties::ComputedFields::ComputedFields()
53        : mTransformMatrix(NULL)
54        , mClipPath(NULL) {
55}
56
57RenderProperties::ComputedFields::~ComputedFields() {
58    delete mTransformMatrix;
59    delete mClipPath;
60}
61
62RenderProperties::RenderProperties()
63        : mStaticMatrix(NULL)
64        , mAnimationMatrix(NULL) {
65}
66
67RenderProperties::~RenderProperties() {
68    delete mStaticMatrix;
69    delete mAnimationMatrix;
70}
71
72RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
73    if (this != &other) {
74        mPrimitiveFields = other.mPrimitiveFields;
75        setStaticMatrix(other.getStaticMatrix());
76        setAnimationMatrix(other.getAnimationMatrix());
77        setCameraDistance(other.getCameraDistance());
78
79        // Update the computed clip path
80        updateClipPath();
81
82        // Force recalculation of the matrix, since other's dirty bit may be clear
83        mPrimitiveFields.mMatrixOrPivotDirty = true;
84        updateMatrix();
85    }
86    return *this;
87}
88
89void RenderProperties::debugOutputProperties(const int level) const {
90    if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
91        ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
92    }
93    if (mStaticMatrix) {
94        ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
95                level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
96    }
97    if (mAnimationMatrix) {
98        ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
99                level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
100    }
101    if (hasTransformMatrix()) {
102        if (isTransformTranslateOnly()) {
103            ALOGD("%*sTranslate %.2f, %.2f, %.2f",
104                    level * 2, "", getTranslationX(), getTranslationY(), getZ());
105        } else {
106            ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
107                    level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
108        }
109    }
110
111    bool clipToBoundsNeeded = mPrimitiveFields.mCaching ? false : mPrimitiveFields.mClipToBounds;
112    if (mPrimitiveFields.mAlpha < 1) {
113        if (mPrimitiveFields.mCaching) {
114            ALOGD("%*sSetOverrideLayerAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
115        } else if (!mPrimitiveFields.mHasOverlappingRendering) {
116            ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
117        } else {
118            int flags = SkCanvas::kHasAlphaLayer_SaveFlag;
119            if (clipToBoundsNeeded) {
120                flags |= SkCanvas::kClipToLayer_SaveFlag;
121                clipToBoundsNeeded = false; // clipping done by save layer
122            }
123            ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
124                    0, 0, getWidth(), getHeight(),
125                    (int)(mPrimitiveFields.mAlpha * 255), flags);
126        }
127    }
128    if (clipToBoundsNeeded) {
129        ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
130                0, 0, getWidth(), getHeight());
131    }
132}
133
134void RenderProperties::updateMatrix() {
135    if (mPrimitiveFields.mMatrixOrPivotDirty) {
136        if (!mComputedFields.mTransformMatrix) {
137            // only allocate a mPrimitiveFields.matrix if we have a complex transform
138            mComputedFields.mTransformMatrix = new SkMatrix();
139        }
140        if (!mPrimitiveFields.mPivotExplicitlySet) {
141            mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f;
142            mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f;
143        }
144        SkMatrix* transform = mComputedFields.mTransformMatrix;
145        transform->reset();
146        if (MathUtils::isZero(getRotationX()) && MathUtils::isZero(getRotationY())) {
147            transform->setTranslate(getTranslationX(), getTranslationY());
148            transform->preRotate(getRotation(), getPivotX(), getPivotY());
149            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
150        } else {
151            SkMatrix transform3D;
152            mComputedFields.mTransformCamera.save();
153            transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
154            mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
155            mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
156            mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
157            mComputedFields.mTransformCamera.getMatrix(&transform3D);
158            transform3D.preTranslate(-getPivotX(), -getPivotY());
159            transform3D.postTranslate(getPivotX() + getTranslationX(),
160                    getPivotY() + getTranslationY());
161            transform->postConcat(transform3D);
162            mComputedFields.mTransformCamera.restore();
163        }
164        mPrimitiveFields.mMatrixOrPivotDirty = false;
165    }
166}
167
168void RenderProperties::updateClipPath() {
169    const SkPath* outlineClipPath = mPrimitiveFields.mOutline.willClip()
170            ? mPrimitiveFields.mOutline.getPath() : NULL;
171    const SkPath* revealClipPath = mPrimitiveFields.mRevealClip.getPath();
172
173    if (!outlineClipPath && !revealClipPath) {
174        // mComputedFields.mClipPath doesn't need to be updated, since it won't be used
175        return;
176    }
177
178    if (mComputedFields.mClipPath == NULL) {
179        mComputedFields.mClipPath = new SkPath();
180    }
181    SkPath* clipPath = mComputedFields.mClipPath;
182    mComputedFields.mClipPathOp = SkRegion::kIntersect_Op;
183
184    if (outlineClipPath && revealClipPath) {
185        SkPathOp op = kIntersect_PathOp;
186        if (mPrimitiveFields.mRevealClip.isInverseClip()) {
187            op = kDifference_PathOp; // apply difference step in the Op below, instead of draw time
188        }
189
190        Op(*outlineClipPath, *revealClipPath, op, clipPath);
191    } else if (outlineClipPath) {
192        *clipPath = *outlineClipPath;
193    } else {
194        *clipPath = *revealClipPath;
195        if (mPrimitiveFields.mRevealClip.isInverseClip()) {
196            // apply difference step at draw time
197            mComputedFields.mClipPathOp = SkRegion::kDifference_Op;
198        }
199    }
200}
201
202} /* namespace uirenderer */
203} /* namespace android */
204