blob: 8321ff92268cfa4c3d63a563c2613b9b64b68565 [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 Craik386aa032015-12-07 17:08:25 -080037 EXPECT_EQ(Rect(0, 0, 100, 200), state.clipRect);
38 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 Craik386aa032015-12-07 17:08:25 -080059const float HAIRLINE = 0.0f;
60
61// Note: bounds will be conservative, but not precise for non-hairline
62// - use approx bounds checks for these
63const float SEMI_HAIRLINE = 0.3f;
64
65struct StrokeTestCase {
66 float scale;
67 float strokeWidth;
68 const std::function<void(const ResolvedRenderState&)> validator;
69};
70
71const static StrokeTestCase sStrokeTestCases[] = {
72 {
73 1, HAIRLINE, [](const ResolvedRenderState& state) {
74 EXPECT_EQ(Rect(49.5f, 49.5f, 150.5f, 150.5f), state.clippedBounds);
75 }
76 },
77 {
78 1, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
79 EXPECT_TRUE(state.clippedBounds.contains(49.5f, 49.5f, 150.5f, 150.5f));
80 EXPECT_TRUE(Rect(49, 49, 151, 151).contains(state.clippedBounds));
81 }
82 },
83 {
84 1, 20, [](const ResolvedRenderState& state) {
85 EXPECT_EQ(Rect(40, 40, 160, 160), state.clippedBounds);
86 }
87 },
88
89 // 3x3 scale:
90 {
91 3, HAIRLINE, [](const ResolvedRenderState& state) {
92 EXPECT_EQ(Rect(149.5f, 149.5f, 200, 200), state.clippedBounds);
93 EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
94 }
95 },
96 {
97 3, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
98 EXPECT_TRUE(state.clippedBounds.contains(149.5f, 149.5f, 200, 200));
99 EXPECT_TRUE(Rect(149, 149, 200, 200).contains(state.clippedBounds));
100 }
101 },
102 {
103 3, 20, [](const ResolvedRenderState& state) {
104 EXPECT_TRUE(state.clippedBounds.contains(120, 120, 200, 200));
105 EXPECT_TRUE(Rect(119, 119, 200, 200).contains(state.clippedBounds));
106 }
107 },
108
109 // 0.5f x 0.5f scale
110 {
111 0.5f, HAIRLINE, [](const ResolvedRenderState& state) {
112 EXPECT_EQ(Rect(24.5f, 24.5f, 75.5f, 75.5f), state.clippedBounds);
113 }
114 },
115 {
116 0.5f, SEMI_HAIRLINE, [](const ResolvedRenderState& state) {
117 EXPECT_TRUE(state.clippedBounds.contains(24.5f, 24.5f, 75.5f, 75.5f));
118 EXPECT_TRUE(Rect(24, 24, 76, 76).contains(state.clippedBounds));
119 }
120 },
121 {
122 0.5f, 20, [](const ResolvedRenderState& state) {
123 EXPECT_TRUE(state.clippedBounds.contains(19.5f, 19.5f, 80.5f, 80.5f));
124 EXPECT_TRUE(Rect(19, 19, 81, 81).contains(state.clippedBounds));
125 }
126 }
127};
128
129TEST(ResolvedRenderState, construct_expandForStroke) {
130 // Loop over table of test cases and verify different combinations of stroke width and transform
131 for (auto&& testCase : sStrokeTestCases) {
132 SkPaint strokedPaint;
133 strokedPaint.setAntiAlias(true);
134 strokedPaint.setStyle(SkPaint::kStroke_Style);
135 strokedPaint.setStrokeWidth(testCase.strokeWidth);
136
137 RectOp recordedOp(Rect(50, 50, 150, 150),
138 Matrix4::identity(), Rect(200, 200), &strokedPaint);
139
140 Matrix4 snapshotMatrix;
141 snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
142 auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
143
144 ResolvedRenderState state(*parentSnapshot, recordedOp, true);
145 testCase.validator(state);
146 }
147}
148
149TEST(BakedOpState, tryConstruct) {
Chris Craikb565df12015-10-05 13:00:52 -0700150 LinearAllocator allocator;
151
Chris Craikb565df12015-10-05 13:00:52 -0700152 Matrix4 translate100x0;
153 translate100x0.loadTranslate(100, 0, 0);
154
155 SkPaint paint;
156 {
Chris Craik386aa032015-12-07 17:08:25 -0800157 RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(100, 200), &paint);
158 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
159 BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
Chris Craikb565df12015-10-05 13:00:52 -0700160
Chris Craik386aa032015-12-07 17:08:25 -0800161 EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
162 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
Chris Craikb565df12015-10-05 13:00:52 -0700163 }
164 {
Chris Craik386aa032015-12-07 17:08:25 -0800165 RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
166 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
167 BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
Chris Craikb565df12015-10-05 13:00:52 -0700168
Chris Craik386aa032015-12-07 17:08:25 -0800169 EXPECT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
170 EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
Chris Craikb565df12015-10-05 13:00:52 -0700171 }
172}
173
Chris Craik386aa032015-12-07 17:08:25 -0800174TEST(BakedOpState, tryShadowOpConstruct) {
Chris Craikd3daa312015-11-06 10:59:56 -0800175 LinearAllocator allocator;
176 {
Chris Craik386aa032015-12-07 17:08:25 -0800177 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
178 BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800179
Chris Craik386aa032015-12-07 17:08:25 -0800180 EXPECT_EQ(nullptr, bakedState); // rejected by clip, so not constructed
181 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
Chris Craikd3daa312015-11-06 10:59:56 -0800182 }
183 {
Chris Craik386aa032015-12-07 17:08:25 -0800184 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
185 BakedOpState* bakedState = BakedOpState::tryShadowOpConstruct(allocator, *snapshot, (ShadowOp*)0x1234);
Chris Craikd3daa312015-11-06 10:59:56 -0800186
Chris Craik386aa032015-12-07 17:08:25 -0800187 ASSERT_NE(nullptr, bakedState); // NOT rejected by clip, so will be constructed
188 EXPECT_LE(64u, allocator.usedSize()); // relatively large alloc for non-rejected op
Chris Craikd3daa312015-11-06 10:59:56 -0800189 }
190}
191
Chris Craik386aa032015-12-07 17:08:25 -0800192TEST(BakedOpState, tryStrokeableOpConstruct) {
193 LinearAllocator allocator;
194 {
195 // check regular rejection
196 SkPaint paint;
197 paint.setStyle(SkPaint::kStrokeAndFill_Style);
198 paint.setStrokeWidth(0.0f);
199 RectOp rejectOp(Rect(0, 0, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
200 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
201 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
202 BakedOpState::StrokeBehavior::StyleDefined);
203
204 EXPECT_EQ(nullptr, bakedState);
205 EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
206 }
207 {
208 // check simple unscaled expansion
209 SkPaint paint;
210 paint.setStyle(SkPaint::kStrokeAndFill_Style);
211 paint.setStrokeWidth(10.0f);
212 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
213 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
214 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
215 BakedOpState::StrokeBehavior::StyleDefined);
216
217 ASSERT_NE(nullptr, bakedState);
218 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
219 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
220 }
221 {
222 // check simple unscaled expansion, and fill style with stroke forced
223 SkPaint paint;
224 paint.setStyle(SkPaint::kFill_Style);
225 paint.setStrokeWidth(10.0f);
226 RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
227 auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
228 auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
229 BakedOpState::StrokeBehavior::Forced);
230
231 ASSERT_NE(nullptr, bakedState);
232 EXPECT_EQ(Rect(45, 45, 155, 155), bakedState->computedState.clippedBounds);
233 EXPECT_EQ(0, bakedState->computedState.clipSideFlags);
234 }
Chris Craikb565df12015-10-05 13:00:52 -0700235}
Chris Craik386aa032015-12-07 17:08:25 -0800236
237} // namespace uirenderer
238} // namespace android