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 #include "RenderProperties.h"
18
19 #include <utils/Trace.h>
20
21 #include <SkColorFilter.h>
22 #include <SkMatrix.h>
23 #include <SkPath.h>
24 #include <SkPathOps.h>
25
26 #include "Matrix.h"
27 #include "OpenGLRenderer.h"
28 #include "hwui/Canvas.h"
29 #include "utils/MathUtils.h"
30
31 namespace android {
32 namespace uirenderer {
33
LayerProperties()34 LayerProperties::LayerProperties() {
35 reset();
36 }
37
~LayerProperties()38 LayerProperties::~LayerProperties() {
39 setType(LayerType::None);
40 }
41
reset()42 void LayerProperties::reset() {
43 mOpaque = false;
44 setFromPaint(nullptr);
45 }
46
setColorFilter(SkColorFilter * filter)47 bool LayerProperties::setColorFilter(SkColorFilter* filter) {
48 if (mColorFilter == filter) return false;
49 SkRefCnt_SafeAssign(mColorFilter, filter);
50 return true;
51 }
52
setFromPaint(const SkPaint * paint)53 bool LayerProperties::setFromPaint(const SkPaint* paint) {
54 bool changed = false;
55 changed |= setAlpha(static_cast<uint8_t>(PaintUtils::getAlphaDirect(paint)));
56 changed |= setXferMode(PaintUtils::getXfermodeDirect(paint));
57 changed |= setColorFilter(paint ? paint->getColorFilter() : nullptr);
58 return changed;
59 }
60
operator =(const LayerProperties & other)61 LayerProperties& LayerProperties::operator=(const LayerProperties& other) {
62 setType(other.type());
63 setOpaque(other.opaque());
64 setAlpha(other.alpha());
65 setXferMode(other.xferMode());
66 setColorFilter(other.colorFilter());
67 return *this;
68 }
69
ComputedFields()70 RenderProperties::ComputedFields::ComputedFields()
71 : mTransformMatrix(nullptr) {
72 }
73
~ComputedFields()74 RenderProperties::ComputedFields::~ComputedFields() {
75 delete mTransformMatrix;
76 }
77
RenderProperties()78 RenderProperties::RenderProperties()
79 : mStaticMatrix(nullptr)
80 , mAnimationMatrix(nullptr) {
81 }
82
~RenderProperties()83 RenderProperties::~RenderProperties() {
84 delete mStaticMatrix;
85 delete mAnimationMatrix;
86 }
87
operator =(const RenderProperties & other)88 RenderProperties& RenderProperties::operator=(const RenderProperties& other) {
89 if (this != &other) {
90 mPrimitiveFields = other.mPrimitiveFields;
91 setStaticMatrix(other.getStaticMatrix());
92 setAnimationMatrix(other.getAnimationMatrix());
93 setCameraDistance(other.getCameraDistance());
94 mLayerProperties = other.layerProperties();
95
96 // Force recalculation of the matrix, since other's dirty bit may be clear
97 mPrimitiveFields.mMatrixOrPivotDirty = true;
98 updateMatrix();
99 }
100 return *this;
101 }
102
debugOutputProperties(const int level) const103 void RenderProperties::debugOutputProperties(const int level) const {
104 if (mPrimitiveFields.mLeft != 0 || mPrimitiveFields.mTop != 0) {
105 ALOGD("%*s(Translate (left, top) %d, %d)", level * 2, "",
106 mPrimitiveFields.mLeft, mPrimitiveFields.mTop);
107 }
108 if (mStaticMatrix) {
109 ALOGD("%*s(ConcatMatrix (static) %p: " SK_MATRIX_STRING ")",
110 level * 2, "", mStaticMatrix, SK_MATRIX_ARGS(mStaticMatrix));
111 }
112 if (mAnimationMatrix) {
113 ALOGD("%*s(ConcatMatrix (animation) %p: " SK_MATRIX_STRING ")",
114 level * 2, "", mAnimationMatrix, SK_MATRIX_ARGS(mAnimationMatrix));
115 }
116 if (hasTransformMatrix()) {
117 if (isTransformTranslateOnly()) {
118 ALOGD("%*s(Translate %.2f, %.2f, %.2f)",
119 level * 2, "", getTranslationX(), getTranslationY(), getZ());
120 } else {
121 ALOGD("%*s(ConcatMatrix %p: " SK_MATRIX_STRING ")",
122 level * 2, "", mComputedFields.mTransformMatrix, SK_MATRIX_ARGS(mComputedFields.mTransformMatrix));
123 }
124 }
125
126 const bool isLayer = effectiveLayerType() != LayerType::None;
127 int clipFlags = getClippingFlags();
128 if (mPrimitiveFields.mAlpha < 1
129 && !MathUtils::isZero(mPrimitiveFields.mAlpha)) {
130 if (isLayer) {
131 clipFlags &= ~CLIP_TO_BOUNDS; // bounds clipping done by layer
132 }
133
134 if (CC_LIKELY(isLayer || !getHasOverlappingRendering())) {
135 // simply scale rendering content's alpha
136 ALOGD("%*s(ScaleAlpha %.2f)", level * 2, "", mPrimitiveFields.mAlpha);
137 } else {
138 // savelayeralpha to create an offscreen buffer to apply alpha
139 Rect layerBounds(0, 0, getWidth(), getHeight());
140 if (clipFlags) {
141 getClippingRectForFlags(clipFlags, &layerBounds);
142 clipFlags = 0; // all clipping done by savelayer
143 }
144 ALOGD("%*s(SaveLayerAlpha %d, %d, %d, %d, %d, 0x%x)", level * 2, "",
145 (int)layerBounds.left, (int)layerBounds.top,
146 (int)layerBounds.right, (int)layerBounds.bottom,
147 (int)(mPrimitiveFields.mAlpha * 255),
148 SaveFlags::HasAlphaLayer | SaveFlags::ClipToLayer);
149 }
150 }
151
152 if (clipFlags) {
153 Rect clipRect;
154 getClippingRectForFlags(clipFlags, &clipRect);
155 ALOGD("%*s(ClipRect %d, %d, %d, %d)", level * 2, "",
156 (int)clipRect.left, (int)clipRect.top, (int)clipRect.right, (int)clipRect.bottom);
157 }
158
159 if (getRevealClip().willClip()) {
160 Rect bounds;
161 getRevealClip().getBounds(&bounds);
162 ALOGD("%*s(Clip to reveal clip with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
163 RECT_ARGS(bounds));
164 }
165
166 auto& outline = mPrimitiveFields.mOutline;
167 if (outline.getShouldClip()) {
168 if (outline.isEmpty()) {
169 ALOGD("%*s(Clip to empty outline)", level * 2, "");
170 } else if (outline.willClip()) {
171 ALOGD("%*s(Clip to outline with bounds %.2f %.2f %.2f %.2f)", level * 2, "",
172 RECT_ARGS(outline.getBounds()));
173 }
174 }
175 }
176
updateMatrix()177 void RenderProperties::updateMatrix() {
178 if (mPrimitiveFields.mMatrixOrPivotDirty) {
179 if (!mComputedFields.mTransformMatrix) {
180 // only allocate a mPrimitiveFields.matrix if we have a complex transform
181 mComputedFields.mTransformMatrix = new SkMatrix();
182 }
183 if (!mPrimitiveFields.mPivotExplicitlySet) {
184 mPrimitiveFields.mPivotX = mPrimitiveFields.mWidth / 2.0f;
185 mPrimitiveFields.mPivotY = mPrimitiveFields.mHeight / 2.0f;
186 }
187 SkMatrix* transform = mComputedFields.mTransformMatrix;
188 transform->reset();
189 if (MathUtils::isZero(getRotationX()) && MathUtils::isZero(getRotationY())) {
190 transform->setTranslate(getTranslationX(), getTranslationY());
191 transform->preRotate(getRotation(), getPivotX(), getPivotY());
192 transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
193 } else {
194 SkMatrix transform3D;
195 mComputedFields.mTransformCamera.save();
196 transform->preScale(getScaleX(), getScaleY(), getPivotX(), getPivotY());
197 mComputedFields.mTransformCamera.rotateX(mPrimitiveFields.mRotationX);
198 mComputedFields.mTransformCamera.rotateY(mPrimitiveFields.mRotationY);
199 mComputedFields.mTransformCamera.rotateZ(-mPrimitiveFields.mRotation);
200 mComputedFields.mTransformCamera.getMatrix(&transform3D);
201 transform3D.preTranslate(-getPivotX(), -getPivotY());
202 transform3D.postTranslate(getPivotX() + getTranslationX(),
203 getPivotY() + getTranslationY());
204 transform->postConcat(transform3D);
205 mComputedFields.mTransformCamera.restore();
206 }
207 mPrimitiveFields.mMatrixOrPivotDirty = false;
208 }
209 }
210
211 } /* namespace uirenderer */
212 } /* namespace android */
213