blob: 3fd822d71310745fa124724fbde671a42564a5a1 [file] [log] [blame]
Chris Craikb565df12015-10-05 13:00:52 -07001/*
2 * Copyright (C) 2015 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
17#include <gtest/gtest.h>
18
19#include <BakedOpState.h>
Chris Craike4db79d2015-12-22 16:32:23 -080020#include <ClipArea.h>
Chris Craikb565df12015-10-05 13:00:52 -070021#include <RecordedOp.h>
Chris Craik8160f202015-12-02 14:50:25 -080022#include <tests/common/TestUtils.h>
Chris Craikb565df12015-10-05 13:00:52 -070023
24namespace android {
25namespace uirenderer {
26
Chris Craik386aa032015-12-07 17:08:25 -080027TEST(ResolvedRenderState, construct) {
Chris Craike4db79d2015-12-22 16:32:23 -080028 LinearAllocator allocator;
Chris Craikb565df12015-10-05 13:00:52 -070029 Matrix4 translate10x20;
30 translate10x20.loadTranslate(10, 20, 0);
31
32 SkPaint paint;
Chris Craike4db79d2015-12-22 16:32:23 -080033 ClipRect clip(Rect(100, 200));
34 RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, &clip, &paint);
Chris Craikb565df12015-10-05 13:00:52 -070035 {
36 // recorded with transform, no parent transform
Chris Craik386aa032015-12-07 17:08:25 -080037 auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
Chris Craike4db79d2015-12-22 16:32:23 -080038 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
Chris Craikb565df12015-10-05 13:00:52 -070039 EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
Chris Craike4db79d2015-12-22 16:32:23 -080040 EXPECT_EQ(Rect(100, 200), state.clipRect());
Chris Craik386aa032015-12-07 17:08:25 -080041 EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
42 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
Chris Craikb565df12015-10-05 13:00:52 -070043 }
44 {
45 // recorded with transform and parent transform
Chris Craik386aa032015-12-07 17:08:25 -080046 auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
Chris Craike4db79d2015-12-22 16:32:23 -080047 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
Chris Craikb565df12015-10-05 13:00:52 -070048
49 Matrix4 expectedTranslate;
50 expectedTranslate.loadTranslate(20, 40, 0);
Chris Craik386aa032015-12-07 17:08:25 -080051 EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform);
Chris Craikb565df12015-10-05 13:00:52 -070052
53 // intersection of parent & transformed child clip
Chris Craike4db79d2015-12-22 16:32:23 -080054 EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect());
Chris Craikb565df12015-10-05 13:00:52 -070055
56 // translated and also clipped
Chris Craik386aa032015-12-07 17:08:25 -080057 EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds);
58 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
Chris Craikb565df12015-10-05 13:00:52 -070059 }
60}
61
Chris Craikd7448e62015-12-15 10:34:36 -080062TEST(ResolvedRenderState, computeLocalSpaceClip) {
Chris Craike4db79d2015-12-22 16:32:23 -080063 LinearAllocator allocator;
Chris Craikd7448e62015-12-15 10:34:36 -080064 Matrix4 translate10x20;
65 translate10x20.loadTranslate(10, 20, 0);
66
67 SkPaint paint;
Chris Craike4db79d2015-12-22 16:32:23 -080068 ClipRect clip(Rect(100, 200));
69 RectOp recordedOp(Rect(1000, 1000), translate10x20, &clip, &paint);
Chris Craikd7448e62015-12-15 10:34:36 -080070 {
71 // recorded with transform, no parent transform
72 auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
Chris Craike4db79d2015-12-22 16:32:23 -080073 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
Chris Craikd7448e62015-12-15 10:34:36 -080074 EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
75 << "Local clip rect should be 100x200, offset by -10,-20";
76 }
77 {
78 // recorded with transform + parent transform
79 auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
Chris Craike4db79d2015-12-22 16:32:23 -080080 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
Chris Craikd7448e62015-12-15 10:34:36 -080081 EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
82 << "Local clip rect should be 90x190, offset by -10,-20";
83 }
84}
85
Chris Craik386aa032015-12-07 17:08:25 -080086const float HAIRLINE = 0.0f;
87
88// Note: bounds will be conservative, but not precise for non-hairline
89// - use approx bounds checks for these
90const float SEMI_HAIRLINE = 0.3f;
91
92struct StrokeTestCase {
93 float scale;
94 float strokeWidth;
95 const std::function<void(const ResolvedRenderState&)> validator;
96};
97
98const static StrokeTestCase sStrokeTestCases[] = {
99 {
100 1, HAIRLINE, [](const ResolvedRenderState& state) {
101 EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
102 }
103 },
104 {
105 1, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
106 EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
107 EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
108 }
109 },
110 {
111 1, 20, [](const ResolvedRenderState& state) {
112 EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
113 }
114 },
115
116 // 3x3 scale:
117 {
118 3, HAIRLINE, [](const ResolvedRenderState& state) {
119 EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
120 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
121 }
122 },
123 {
124 3, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
125 EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
126 EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
127 }
128 },
129 {
130 3, 20, [](const ResolvedRenderState& state) {
131 EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
132 EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
133 }
134 },
135
136 // 0.5f x 0.5f scale
137 {
138 0.5f, HAIRLINE, [](const ResolvedRenderState& state) {
139 EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
140 }
141 },
142 {
143 0.5f, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
144 EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
145 EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
146 }
147 },
148 {
149 0.5f, 20, [](const ResolvedRenderState& state) {
150 EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
151 EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
152 }
153 }
154};
155
156TEST(ResolvedRenderState, construct_expandForStroke) {
Chris Craike4db79d2015-12-22 16:32:23 -0800157 LinearAllocator allocator;
Chris Craik386aa032015-12-07 17:08:25 -0800158 // Loop over table of test cases and verify different combinations of stroke width and transform
159 for (auto&& testCase : sStrokeTestCases) {
160 SkPaint strokedPaint;
161 strokedPaint.setAntiAlias(true);
162 strokedPaint.setStyle(SkPaint::kStroke_Style);
163 strokedPaint.setStrokeWidth(testCase.strokeWidth);
164
Chris Craike4db79d2015-12-22 16:32:23 -0800165 ClipRect clip(Rect(200, 200));
Chris Craik386aa032015-12-07 17:08:25 -0800166 RectOp recordedOp(Rect(50, 50, 150, 150),
Chris Craike4db79d2015-12-22 16:32:23 -0800167 Matrix4::identity(), &clip, &strokedPaint);
Chris Craik386aa032015-12-07 17:08:25 -0800168
169 Matrix4 snapshotMatrix;
170 snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
171 auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
172
Chris Craike4db79d2015-12-22 16:32:23 -0800173 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true);
Chris Craik386aa032015-12-07 17:08:25 -0800174 testCase.validator(state);
175 }
176}
177
178TEST(BakedOpState, tryConstruct) {
Chris Craikb565df12015-10-05 13:00:52 -0700179 LinearAllocator allocator;
180
Chris Craikb565df12015-10-05 13:00:52 -0700181 Matrix4 translate100x0;
182 translate100x0.loadTranslate(100, 0, 0);
183
184 SkPaint paint;
Chris Craike4db79d2015-12-22 16:32:23 -0800185 ClipRect clip(Rect(100, 200));
Chris Craikb565df12015-10-05 13:00:52 -0700186 {
Chris Craike4db79d2015-12-22 16:32:23 -0800187 RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800188 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
189 BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
Chris Craikb565df12015-10-05 13:00:52 -0700190
Chris Craik386aa032015-12-07 17:08:25 -0800191 EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
192 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
Chris Craikb565df12015-10-05 13:00:52 -0700193 }
194 {
Chris Craike4db79d2015-12-22 16:32:23 -0800195 RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800196 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
197 BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
Chris Craikb565df12015-10-05 13:00:52 -0700198
Chris Craik386aa032015-12-07 17:08:25 -0800199 EXPECT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
200 EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
Chris Craikb565df12015-10-05 13:00:52 -0700201 }
202}
203
Chris Craik386aa032015-12-07 17:08:25 -0800204TEST(BakedOpState, tryShadowOpConstruct) {
Chris Craikd3daa312015-11-06 10:59:56 -0800205 LinearAllocator allocator;
206 {
Chris Craik386aa032015-12-07 17:08:25 -0800207 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
208 BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800209
Chris Craik386aa032015-12-07 17:08:25 -0800210 EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
211 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
Chris Craikd3daa312015-11-06 10:59:56 -0800212 }
213 {
Chris Craik386aa032015-12-07 17:08:25 -0800214 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
215 BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800216
Chris Craik386aa032015-12-07 17:08:25 -0800217 ASSERT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
218 EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
Chris Craikd3daa312015-11-06 10:59:56 -0800219 }
220}
221
Chris Craik386aa032015-12-07 17:08:25 -0800222TEST(BakedOpState, tryStrokeableOpConstruct) {
223 LinearAllocator allocator;
224 {
225 // check regular rejection
226 SkPaint paint;
227 paint.setStyle(SkPaint::kStrokeAndFill_Style);
228 paint.setStrokeWidth(0.0f);
Chris Craike4db79d2015-12-22 16:32:23 -0800229 ClipRect clip(Rect(100, 200));
230 RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800231 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
232 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
233 BakedOpState::StrokeBehavior::StyleDefined);
234
235 EXPECT_EQ(nullptr, bakedState);
236 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
237 }
238 {
239 // check simple unscaled expansion
240 SkPaint paint;
241 paint.setStyle(SkPaint::kStrokeAndFill_Style);
242 paint.setStrokeWidth(10.0f);
Chris Craike4db79d2015-12-22 16:32:23 -0800243 ClipRect clip(Rect(200, 200));
244 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800245 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
246 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
247 BakedOpState::StrokeBehavior::StyleDefined);
248
249 ASSERT_NE(nullptr, bakedState);
250 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
251 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
252 }
253 {
254 // check simple unscaled expansion, and fill style with stroke forced
255 SkPaint paint;
256 paint.setStyle(SkPaint::kFill_Style);
257 paint.setStrokeWidth(10.0f);
Chris Craike4db79d2015-12-22 16:32:23 -0800258 ClipRect clip(Rect(200, 200));
259 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800260 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
261 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
262 BakedOpState::StrokeBehavior::Forced);
263
264 ASSERT_NE(nullptr, bakedState);
265 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
266 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
267 }
Chris Craikb565df12015-10-05 13:00:52 -0700268}
Chris Craik386aa032015-12-07 17:08:25 -0800269
270} // namespace uirenderer
271} // namespace android