blob: 6f8e24917767437aecc03beabb6cc614f60b4878 [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 Craik49b403d2017-03-06 13:51:43 -080038 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, 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());
John Reck1bcacfd2017-11-03 10:12:19 -070041 EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
Chris Craik386aa032015-12-07 17:08:25 -080042 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 Craik49b403d2017-03-06 13:51:43 -080047 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, 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 Craik49b403d2017-03-06 13:51:43 -080073 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
Chris Craikd7448e62015-12-15 10:34:36 -080074 EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
John Reck1bcacfd2017-11-03 10:12:19 -070075 << "Local clip rect should be 100x200, offset by -10,-20";
Chris Craikd7448e62015-12-15 10:34:36 -080076 }
77 {
78 // recorded with transform + parent transform
79 auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
Chris Craik49b403d2017-03-06 13:51:43 -080080 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false, false);
Chris Craikd7448e62015-12-15 10:34:36 -080081 EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
John Reck1bcacfd2017-11-03 10:12:19 -070082 << "Local clip rect should be 90x190, offset by -10,-20";
Chris Craikd7448e62015-12-15 10:34:36 -080083 }
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[] = {
John Reck1bcacfd2017-11-03 10:12:19 -070099 {1, HAIRLINE,
100 [](const ResolvedRenderState& state) {
101 EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
102 }},
103 {1, SEMI_HAIRLINE,
104 [](const ResolvedRenderState& state) {
105 EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
106 EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
107 }},
108 {1, 20,
109 [](const ResolvedRenderState& state) {
110 EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
111 }},
Chris Craik386aa032015-12-07 17:08:25 -0800112
John Reck1bcacfd2017-11-03 10:12:19 -0700113 // 3x3 scale:
114 {3, HAIRLINE,
115 [](const ResolvedRenderState& state) {
116 EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
117 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
118 }},
119 {3, SEMI_HAIRLINE,
120 [](const ResolvedRenderState& state) {
121 EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
122 EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
123 }},
124 {3, 20,
125 [](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 }},
Chris Craik386aa032015-12-07 17:08:25 -0800129
John Reck1bcacfd2017-11-03 10:12:19 -0700130 // 0.5f x 0.5f scale
131 {0.5f, HAIRLINE,
132 [](const ResolvedRenderState& state) {
133 EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
134 }},
135 {0.5f, SEMI_HAIRLINE,
136 [](const ResolvedRenderState& state) {
137 EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
138 EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
139 }},
140 {0.5f, 20, [](const ResolvedRenderState& state) {
141 EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
142 EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
143 }}};
Chris Craik386aa032015-12-07 17:08:25 -0800144
145TEST(ResolvedRenderState, construct_expandForStroke) {
Chris Craike4db79d2015-12-22 16:32:23 -0800146 LinearAllocator allocator;
Chris Craik386aa032015-12-07 17:08:25 -0800147 // Loop over table of test cases and verify different combinations of stroke width and transform
148 for (auto&& testCase : sStrokeTestCases) {
149 SkPaint strokedPaint;
150 strokedPaint.setAntiAlias(true);
151 strokedPaint.setStyle(SkPaint::kStroke_Style);
152 strokedPaint.setStrokeWidth(testCase.strokeWidth);
153
Chris Craike4db79d2015-12-22 16:32:23 -0800154 ClipRect clip(Rect(200, 200));
John Reck1bcacfd2017-11-03 10:12:19 -0700155 RectOp recordedOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &strokedPaint);
Chris Craik386aa032015-12-07 17:08:25 -0800156
157 Matrix4 snapshotMatrix;
158 snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
159 auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
160
Chris Craik49b403d2017-03-06 13:51:43 -0800161 ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true, false);
Chris Craik386aa032015-12-07 17:08:25 -0800162 testCase.validator(state);
163 }
164}
165
166TEST(BakedOpState, tryConstruct) {
Chris Craikb565df12015-10-05 13:00:52 -0700167 Matrix4 translate100x0;
168 translate100x0.loadTranslate(100, 0, 0);
169
170 SkPaint paint;
Chris Craike4db79d2015-12-22 16:32:23 -0800171 ClipRect clip(Rect(100, 200));
Chris Craikb565df12015-10-05 13:00:52 -0700172
Chris Craik15f04682016-01-11 17:50:08 -0800173 LinearAllocator allocator;
174 RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint);
175 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
176 EXPECT_NE(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, successOp))
177 << "successOp NOT rejected by clip, so should be constructed";
178 size_t successAllocSize = allocator.usedSize();
179 EXPECT_LE(64u, successAllocSize) << "relatively large alloc for non-rejected op";
Chris Craikb565df12015-10-05 13:00:52 -0700180
Chris Craik15f04682016-01-11 17:50:08 -0800181 RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint);
182 EXPECT_EQ(nullptr, BakedOpState::tryConstruct(allocator, *snapshot, rejectOp))
183 << "rejectOp rejected by clip, so should not be constructed";
184
185 // NOTE: this relies on the clip having already been serialized by the op above
186 EXPECT_EQ(successAllocSize, allocator.usedSize()) << "no extra allocation used for rejected op";
Chris Craikb565df12015-10-05 13:00:52 -0700187}
188
Chris Craik386aa032015-12-07 17:08:25 -0800189TEST(BakedOpState, tryShadowOpConstruct) {
Chris Craik420d6552016-01-12 15:38:14 -0800190 Matrix4 translate10x20;
191 translate10x20.loadTranslate(10, 20, 0);
192
Chris Craikd3daa312015-11-06 10:59:56 -0800193 LinearAllocator allocator;
194 {
John Reck1bcacfd2017-11-03 10:12:19 -0700195 auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect()); // Note: empty clip
196 BakedOpState* bakedState =
197 BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800198
Chris Craik15f04682016-01-11 17:50:08 -0800199 EXPECT_EQ(nullptr, bakedState) << "op should be rejected by clip, so not constructed";
200 EXPECT_EQ(0u, allocator.usedSize()) << "no serialization, even for clip,"
John Reck1bcacfd2017-11-03 10:12:19 -0700201 "since op is quick rejected based on snapshot clip";
Chris Craikd3daa312015-11-06 10:59:56 -0800202 }
203 {
Chris Craik420d6552016-01-12 15:38:14 -0800204 auto snapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
John Reck1bcacfd2017-11-03 10:12:19 -0700205 BakedOpState* bakedState =
206 BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800207
Chris Craik15f04682016-01-11 17:50:08 -0800208 ASSERT_NE(nullptr, bakedState) << "NOT rejected by clip, so op should be constructed";
209 EXPECT_LE(64u, allocator.usedSize()) << "relatively large alloc for non-rejected op";
Chris Craik420d6552016-01-12 15:38:14 -0800210
211 EXPECT_MATRIX_APPROX_EQ(translate10x20, bakedState->computedState.transform);
212 EXPECT_EQ(Rect(100, 200), bakedState->computedState.clippedBounds);
Chris Craikd3daa312015-11-06 10:59:56 -0800213 }
214}
215
Chris Craik386aa032015-12-07 17:08:25 -0800216TEST(BakedOpState, tryStrokeableOpConstruct) {
217 LinearAllocator allocator;
218 {
219 // check regular rejection
220 SkPaint paint;
221 paint.setStyle(SkPaint::kStrokeAndFill_Style);
222 paint.setStrokeWidth(0.0f);
Chris Craike4db79d2015-12-22 16:32:23 -0800223 ClipRect clip(Rect(100, 200));
224 RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
John Reck1bcacfd2017-11-03 10:12:19 -0700225 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
226 auto bakedState = BakedOpState::tryStrokeableOpConstruct(
227 allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false);
Chris Craik386aa032015-12-07 17:08:25 -0800228
229 EXPECT_EQ(nullptr, bakedState);
John Reck1bcacfd2017-11-03 10:12:19 -0700230 EXPECT_GT(8u,
231 allocator.usedSize()); // no significant allocation space used for rejected op
Chris Craik386aa032015-12-07 17:08:25 -0800232 }
233 {
234 // check simple unscaled expansion
235 SkPaint paint;
236 paint.setStyle(SkPaint::kStrokeAndFill_Style);
237 paint.setStrokeWidth(10.0f);
Chris Craike4db79d2015-12-22 16:32:23 -0800238 ClipRect clip(Rect(200, 200));
239 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800240 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
John Reck1bcacfd2017-11-03 10:12:19 -0700241 auto bakedState = BakedOpState::tryStrokeableOpConstruct(
242 allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::StyleDefined, false);
Chris Craik386aa032015-12-07 17:08:25 -0800243
244 ASSERT_NE(nullptr, bakedState);
245 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
246 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
247 }
248 {
249 // check simple unscaled expansion, and fill style with stroke forced
250 SkPaint paint;
251 paint.setStyle(SkPaint::kFill_Style);
252 paint.setStrokeWidth(10.0f);
Chris Craike4db79d2015-12-22 16:32:23 -0800253 ClipRect clip(Rect(200, 200));
254 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
Chris Craik386aa032015-12-07 17:08:25 -0800255 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
John Reck1bcacfd2017-11-03 10:12:19 -0700256 auto bakedState = BakedOpState::tryStrokeableOpConstruct(
257 allocator, *snapshot, rejectOp, BakedOpState::StrokeBehavior::Forced, false);
Chris Craik386aa032015-12-07 17:08:25 -0800258
259 ASSERT_NE(nullptr, bakedState);
260 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
261 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
262 }
Chris Craikb565df12015-10-05 13:00:52 -0700263}
Chris Craik386aa032015-12-07 17:08:25 -0800264
John Reck1bcacfd2017-11-03 10:12:19 -0700265} // namespace uirenderer
266} // namespace android