2 * Copyright (C) 2014 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 #define LOG_TAG "OpenGLRenderer"
19 #include "RenderProperties.h"
21 #include <utils/Trace.h>
24 #include <SkColorFilter.h>
27 #include <SkPathOps.h>
30 #include "OpenGLRenderer.h"
31 #include "utils/MathUtils.h"
34 namespace uirenderer {
36 LayerProperties::LayerProperties() {
40 LayerProperties::~LayerProperties() {
41 setType(LayerType::None);
44 void LayerProperties::reset() {
46 setFromPaint(nullptr);
49 bool LayerProperties::setColorFilter(SkColorFilter* filter) {
50 if (mColorFilter == filter) return false;
51 SkRefCnt_SafeAssign(mColorFilter, filter);
55 bool LayerProperties::setFromPaint(const SkPaint* paint) {
57 SkXfermode::Mode mode;
59 OpenGLRenderer::getAlphaAndModeDirect(paint, &alpha, &mode);
60 changed |= setAlpha(static_cast<uint8_t>(alpha));
61 changed |= setXferMode(mode);
62 changed |= setColorFilter(paint ? paint->getColorFilter() : nullptr);
66 LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
67 setType(other.type());
68 setOpaque(other.opaque());
69 setAlpha(other.alpha());
70 setXferMode(other.xferMode());
71 setColorFilter(other.colorFilter());
75 RenderProperties::PrimitiveFields::PrimitiveFields()
76 : mClippingFlags(CLIP_TO_BOUNDS)
77 , mProjectBackwards(false)
78 , mProjectionReceiver(false)
80 , mHasOverlappingRendering(true)
82 , mTranslationX(0), mTranslationY(0), mTranslationZ(0)
83 , mRotation(0), mRotationX(0), mRotationY(0)
84 , mScaleX(1), mScaleY(1)
85 , mPivotX(0), mPivotY(0)
86 , mLeft(0), mTop(0), mRight(0), mBottom(0)
87 , mWidth(0), mHeight(0)
88 , mPivotExplicitlySet(false)
89 , mMatrixOrPivotDirty(false) {
92 RenderProperties::ComputedFields::ComputedFields()
93 : mTransformMatrix(nullptr) {
96 RenderProperties::ComputedFields::~ComputedFields() {
97 delete mTransformMatrix;
100 RenderProperties::RenderProperties()
101 : mStaticMatrix(nullptr)
102 , mAnimationMatrix(nullptr) {
105 RenderProperties::~RenderProperties() {
106 delete mStaticMatrix;
107 delete mAnimationMatrix;
110 RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
111 if (this != &other) {
112 mPrimitiveFields = other.mPrimitiveFields;
113 setStaticMatrix(other.getStaticMatrix());
114 setAnimationMatrix(other.getAnimationMatrix());
115 setCameraDistance(other.getCameraDistance());
116 mLayerProperties = other.layerProperties();
118 // Force recalculation of the matrix, since other's dirty bit may be clear
119 mPrimitiveFields.mMatrixOrPivotDirty = true;
125 void RenderProperties::debugOutputProperties(const int level) const {
126 if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
127 ALOGD("%*sTranslate (left, top) %d, %d", level * 2, "", mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
130 ALOGD("%*sConcatMatrix (static) %p: " SK_MATRIX_STRING,
131 level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
133 if (mAnimationMatrix) {
134 ALOGD("%*sConcatMatrix (animation) %p: " SK_MATRIX_STRING,
135 level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
137 if (hasTransformMatrix()) {
138 if (isTransformTranslateOnly()) {
139 ALOGD("%*sTranslate %.2f, %.2f, %.2f",
140 level * 2, "", getTranslationX(), getTranslationY(), getZ());
142 ALOGD("%*sConcatMatrix %p: " SK_MATRIX_STRING,
143 level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
147 const bool isLayer = effectiveLayerType() != LayerType::None;
148 int clipFlags = getClippingFlags();
149 if (mPrimitiveFields.mAlpha < 1
150 && !MathUtils::isZero(mPrimitiveFields.mAlpha)) {
152 clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
155 if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
156 // simply scale rendering content's alpha
157 ALOGD("%*sScaleAlpha %.2f", level * 2, "", mPrimitiveFields.mAlpha);
159 // savelayeralpha to create an offscreen buffer to apply alpha
160 Rect layerBounds(0, 0, getWidth(), getHeight());
162 getClippingRectForFlags(clipFlags, &layerBounds);
163 clipFlags = 0; // all clipping done by savelayer
165 ALOGD("%*sSaveLayerAlpha %d, %d, %d, %d, %d, 0x%x", level * 2, "",
166 (int)layerBounds.left, (int)layerBounds.top,
167 (int)layerBounds.right, (int)layerBounds.bottom,
168 (int)(mPrimitiveFields.mAlpha * 255),
169 SkCanvas::kHasAlphaLayer_SaveFlag | SkCanvas::kClipToLayer_SaveFlag);
176 getClippingRectForFlags(clipFlags, &clipRect);
177 ALOGD("%*sClipRect %d, %d, %d, %d", level * 2, "",
178 (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
182 void RenderProperties::updateMatrix() {
183 if (mPrimitiveFields.mMatrixOrPivotDirty) {
184 if (!mComputedFields.mTransformMatrix) {
185 // only allocate a mPrimitiveFields.matrix if we have a complex transform
186 mComputedFields.mTransformMatrix = new SkMatrix();
188 if (!mPrimitiveFields.mPivotExplicitlySet) {
189 mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f;
190 mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f;
192 SkMatrix* transform = mComputedFields.mTransformMatrix;
194 if (MathUtils::isZero(getRotationX()) && MathUtils::isZero(getRotationY())) {
195 transform->setTranslate(getTranslationX(), getTranslationY());
196 transform->preRotate(getRotation(), getPivotX(), getPivotY());
197 transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
199 SkMatrix transform3D;
200 mComputedFields.mTransformCamera.save();
201 transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
202 mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
203 mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
204 mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
205 mComputedFields.mTransformCamera.getMatrix(&transform3D);
206 transform3D.preTranslate(-getPivotX(), -getPivotY());
207 transform3D.postTranslate(getPivotX() + getTranslationX(),
208 getPivotY() + getTranslationY());
209 transform->postConcat(transform3D);
210 mComputedFields.mTransformCamera.restore();
212 mPrimitiveFields.mMatrixOrPivotDirty = false;
216 } /* namespace uirenderer */
217 } /* namespace android */