blob: f9f5316a58dff4cc22266066d1640afac49cfcec [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>
20#include <RecordedOp.h>
Chris Craik8160f202015-12-02 14:50:25 -080021#include <tests/common/TestUtils.h>
Chris Craikb565df12015-10-05 13:00:52 -070022
23namespace android {
24namespace uirenderer {
25
Chris Craik386aa032015-12-07 17:08:25 -080026TEST(ResolvedRenderState, construct) {
Chris Craikb565df12015-10-05 13:00:52 -070027 Matrix4 translate10x20;
28 translate10x20.loadTranslate(10, 20, 0);
29
30 SkPaint paint;
Chris Craik386aa032015-12-07 17:08:25 -080031 RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(100, 200), &paint);
Chris Craikb565df12015-10-05 13:00:52 -070032 {
33 // recorded with transform, no parent transform
Chris Craik386aa032015-12-07 17:08:25 -080034 auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
35 ResolvedRenderState state(*parentSnapshot, recordedOp, false);
Chris Craikb565df12015-10-05 13:00:52 -070036 EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
Chris Craik5430ab22015-12-10 16:28:16 -080037 EXPECT_EQ(Rect(100, 200), state.clipRect);
Chris Craik386aa032015-12-07 17:08:25 -080038 EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
39 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
Chris Craikb565df12015-10-05 13:00:52 -070040 }
41 {
42 // recorded with transform and parent transform
Chris Craik386aa032015-12-07 17:08:25 -080043 auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
44 ResolvedRenderState state(*parentSnapshot, recordedOp, false);
Chris Craikb565df12015-10-05 13:00:52 -070045
46 Matrix4 expectedTranslate;
47 expectedTranslate.loadTranslate(20, 40, 0);
Chris Craik386aa032015-12-07 17:08:25 -080048 EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform);
Chris Craikb565df12015-10-05 13:00:52 -070049
50 // intersection of parent & transformed child clip
Chris Craik386aa032015-12-07 17:08:25 -080051 EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect);
Chris Craikb565df12015-10-05 13:00:52 -070052
53 // translated and also clipped
Chris Craik386aa032015-12-07 17:08:25 -080054 EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds);
55 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
Chris Craikb565df12015-10-05 13:00:52 -070056 }
57}
58
Chris Craikd7448e62015-12-15 10:34:36 -080059TEST(ResolvedRenderState, computeLocalSpaceClip) {
60 Matrix4 translate10x20;
61 translate10x20.loadTranslate(10, 20, 0);
62
63 SkPaint paint;
64 RectOp recordedOp(Rect(1000, 1000), translate10x20, Rect(100, 200), &paint);
65 {
66 // recorded with transform, no parent transform
67 auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
68 ResolvedRenderState state(*parentSnapshot, recordedOp, false);
69 EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
70 << "Local clip rect should be 100x200, offset by -10,-20";
71 }
72 {
73 // recorded with transform + parent transform
74 auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
75 ResolvedRenderState state(*parentSnapshot, recordedOp, false);
76 EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
77 << "Local clip rect should be 90x190, offset by -10,-20";
78 }
79}
80
Chris Craik386aa032015-12-07 17:08:25 -080081const float HAIRLINE = 0.0f;
82
83// Note: bounds will be conservative, but not precise for non-hairline
84// - use approx bounds checks for these
85const float SEMI_HAIRLINE = 0.3f;
86
87struct StrokeTestCase {
88 float scale;
89 float strokeWidth;
90 const std::function<void(const ResolvedRenderState&)> validator;
91};
92
93const static StrokeTestCase sStrokeTestCases[] = {
94 {
95 1, HAIRLINE, [](const ResolvedRenderState& state) {
96 EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
97 }
98 },
99 {
100 1, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
101 EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
102 EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
103 }
104 },
105 {
106 1, 20, [](const ResolvedRenderState& state) {
107 EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
108 }
109 },
110
111 // 3x3 scale:
112 {
113 3, HAIRLINE, [](const ResolvedRenderState& state) {
114 EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
115 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
116 }
117 },
118 {
119 3, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
120 EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
121 EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
122 }
123 },
124 {
125 3, 20, [](const ResolvedRenderState& state) {
126 EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
127 EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
128 }
129 },
130
131 // 0.5f x 0.5f scale
132 {
133 0.5f, HAIRLINE, [](const ResolvedRenderState& state) {
134 EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
135 }
136 },
137 {
138 0.5f, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
139 EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
140 EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
141 }
142 },
143 {
144 0.5f, 20, [](const ResolvedRenderState& state) {
145 EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
146 EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
147 }
148 }
149};
150
151TEST(ResolvedRenderState, construct_expandForStroke) {
152 // Loop over table of test cases and verify different combinations of stroke width and transform
153 for (auto&& testCase : sStrokeTestCases) {
154 SkPaint strokedPaint;
155 strokedPaint.setAntiAlias(true);
156 strokedPaint.setStyle(SkPaint::kStroke_Style);
157 strokedPaint.setStrokeWidth(testCase.strokeWidth);
158
159 RectOp recordedOp(Rect(50, 50, 150, 150),
160 Matrix4::identity(), Rect(200, 200), &strokedPaint);
161
162 Matrix4 snapshotMatrix;
163 snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
164 auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
165
166 ResolvedRenderState state(*parentSnapshot, recordedOp, true);
167 testCase.validator(state);
168 }
169}
170
171TEST(BakedOpState, tryConstruct) {
Chris Craikb565df12015-10-05 13:00:52 -0700172 LinearAllocator allocator;
173
Chris Craikb565df12015-10-05 13:00:52 -0700174 Matrix4 translate100x0;
175 translate100x0.loadTranslate(100, 0, 0);
176
177 SkPaint paint;
178 {
Chris Craik386aa032015-12-07 17:08:25 -0800179 RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(100, 200), &paint);
180 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
181 BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
Chris Craikb565df12015-10-05 13:00:52 -0700182
Chris Craik386aa032015-12-07 17:08:25 -0800183 EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
184 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
Chris Craikb565df12015-10-05 13:00:52 -0700185 }
186 {
Chris Craik386aa032015-12-07 17:08:25 -0800187 RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
188 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
189 BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
Chris Craikb565df12015-10-05 13:00:52 -0700190
Chris Craik386aa032015-12-07 17:08:25 -0800191 EXPECT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
192 EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
Chris Craikb565df12015-10-05 13:00:52 -0700193 }
194}
195
Chris Craik386aa032015-12-07 17:08:25 -0800196TEST(BakedOpState, tryShadowOpConstruct) {
Chris Craikd3daa312015-11-06 10:59:56 -0800197 LinearAllocator allocator;
198 {
Chris Craik386aa032015-12-07 17:08:25 -0800199 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
200 BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800201
Chris Craik386aa032015-12-07 17:08:25 -0800202 EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
203 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
Chris Craikd3daa312015-11-06 10:59:56 -0800204 }
205 {
Chris Craik386aa032015-12-07 17:08:25 -0800206 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
207 BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800208
Chris Craik386aa032015-12-07 17:08:25 -0800209 ASSERT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
210 EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
Chris Craikd3daa312015-11-06 10:59:56 -0800211 }
212}
213
Chris Craik386aa032015-12-07 17:08:25 -0800214TEST(BakedOpState, tryStrokeableOpConstruct) {
215 LinearAllocator allocator;
216 {
217 // check regular rejection
218 SkPaint paint;
219 paint.setStyle(SkPaint::kStrokeAndFill_Style);
220 paint.setStrokeWidth(0.0f);
Chris Craik5430ab22015-12-10 16:28:16 -0800221 RectOp rejectOp(Rect(100, 200), Matrix4::identity(), Rect(100, 200), &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800222 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
223 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
224 BakedOpState::StrokeBehavior::StyleDefined);
225
226 EXPECT_EQ(nullptr, bakedState);
227 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
228 }
229 {
230 // check simple unscaled expansion
231 SkPaint paint;
232 paint.setStyle(SkPaint::kStrokeAndFill_Style);
233 paint.setStrokeWidth(10.0f);
234 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
235 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
236 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
237 BakedOpState::StrokeBehavior::StyleDefined);
238
239 ASSERT_NE(nullptr, bakedState);
240 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
241 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
242 }
243 {
244 // check simple unscaled expansion, and fill style with stroke forced
245 SkPaint paint;
246 paint.setStyle(SkPaint::kFill_Style);
247 paint.setStrokeWidth(10.0f);
248 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
249 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
250 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
251 BakedOpState::StrokeBehavior::Forced);
252
253 ASSERT_NE(nullptr, bakedState);
254 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
255 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
256 }
Chris Craikb565df12015-10-05 13:00:52 -0700257}
Chris Craik386aa032015-12-07 17:08:25 -0800258
259} // namespace uirenderer
260} // namespace android