OLD | NEW |
| (Empty) |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/paint/paint_op_buffer.h" | |
6 #include "cc/test/test_skcanvas.h" | |
7 #include "testing/gtest/include/gtest/gtest.h" | |
8 | |
9 namespace { | |
10 | |
11 template <typename T> | |
12 void CheckRefCnt(const T& obj, int32_t count) { | |
13 // Skia doesn't define getRefCnt in all builds. | |
14 #ifdef SK_DEBUG | |
15 EXPECT_EQ(obj->getRefCnt(), count); | |
16 #endif | |
17 } | |
18 | |
19 } // namespace | |
20 | |
21 namespace cc { | |
22 | |
23 TEST(PaintOpBufferTest, Empty) { | |
24 PaintOpBuffer buffer; | |
25 EXPECT_EQ(buffer.approximateOpCount(), 0); | |
26 EXPECT_EQ(buffer.approximateBytesUsed(), sizeof(PaintOpBuffer)); | |
27 EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); | |
28 | |
29 buffer.Reset(); | |
30 EXPECT_EQ(buffer.approximateOpCount(), 0); | |
31 EXPECT_EQ(buffer.approximateBytesUsed(), sizeof(PaintOpBuffer)); | |
32 EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); | |
33 } | |
34 | |
35 TEST(PaintOpBufferTest, SimpleAppend) { | |
36 SkRect rect = SkRect::MakeXYWH(2, 3, 4, 5); | |
37 PaintFlags flags; | |
38 flags.setColor(SK_ColorMAGENTA); | |
39 flags.setAlpha(100); | |
40 SkColor draw_color = SK_ColorRED; | |
41 SkBlendMode blend = SkBlendMode::kSrc; | |
42 | |
43 PaintOpBuffer buffer; | |
44 buffer.push<SaveLayerOp>(&rect, &flags); | |
45 buffer.push<SaveOp>(); | |
46 buffer.push<DrawColorOp>(draw_color, blend); | |
47 buffer.push<RestoreOp>(); | |
48 | |
49 EXPECT_EQ(buffer.approximateOpCount(), 4); | |
50 | |
51 PaintOpBuffer::Iterator iter(&buffer); | |
52 ASSERT_EQ(iter->GetType(), PaintOpType::SaveLayer); | |
53 SaveLayerOp* save_op = static_cast<SaveLayerOp*>(*iter); | |
54 EXPECT_EQ(save_op->bounds, rect); | |
55 EXPECT_TRUE(save_op->flags == flags); | |
56 ++iter; | |
57 | |
58 ASSERT_EQ(iter->GetType(), PaintOpType::Save); | |
59 ++iter; | |
60 | |
61 ASSERT_EQ(iter->GetType(), PaintOpType::DrawColor); | |
62 DrawColorOp* op = static_cast<DrawColorOp*>(*iter); | |
63 EXPECT_EQ(op->color, draw_color); | |
64 EXPECT_EQ(op->mode, blend); | |
65 ++iter; | |
66 | |
67 ASSERT_EQ(iter->GetType(), PaintOpType::Restore); | |
68 ++iter; | |
69 | |
70 EXPECT_FALSE(iter); | |
71 } | |
72 | |
73 // PaintOpBuffer has a special case for first ops stored locally, so | |
74 // make sure that appending different kind of ops as a first op works | |
75 // properly, as well as resetting and reusing the first local op. | |
76 TEST(PaintOpBufferTest, FirstOpWithAndWithoutData) { | |
77 PaintOpBuffer buffer; | |
78 char text[] = "asdf"; | |
79 | |
80 // Use a color filter and its ref count to verify that the destructor | |
81 // is called on ops after reset. | |
82 PaintFlags flags; | |
83 sk_sp<SkColorFilter> filter = | |
84 SkColorFilter::MakeModeFilter(SK_ColorMAGENTA, SkBlendMode::kSrcOver); | |
85 flags.setColorFilter(filter); | |
86 CheckRefCnt(filter, 2); | |
87 | |
88 buffer.push_with_data<DrawTextOp>(text, arraysize(text), 0.f, 0.f, flags); | |
89 CheckRefCnt(filter, 3); | |
90 | |
91 // Verify that when the first op has data, which may not fit in the | |
92 // PaintRecord internal buffer, that it adds a noop as the first op | |
93 // and then appends the "op with data" into the heap buffer. | |
94 ASSERT_EQ(buffer.approximateOpCount(), 2); | |
95 EXPECT_EQ(buffer.GetFirstOp()->GetType(), PaintOpType::Noop); | |
96 | |
97 // Verify iteration behavior and brief smoke test of op state. | |
98 { | |
99 PaintOpBuffer::Iterator iter(&buffer); | |
100 PaintOp* noop = *iter; | |
101 EXPECT_EQ(buffer.GetFirstOp(), noop); | |
102 ++iter; | |
103 | |
104 PaintOp* op = *iter; | |
105 ASSERT_EQ(op->GetType(), PaintOpType::DrawText); | |
106 DrawTextOp* draw_text_op = static_cast<DrawTextOp*>(op); | |
107 EXPECT_EQ(draw_text_op->bytes, arraysize(text)); | |
108 | |
109 void* data = paint_op_data(draw_text_op); | |
110 EXPECT_EQ(memcmp(data, text, arraysize(text)), 0); | |
111 | |
112 ++iter; | |
113 EXPECT_FALSE(iter); | |
114 } | |
115 | |
116 // Reset, verify state, and append an op that will fit in the first slot. | |
117 buffer.Reset(); | |
118 CheckRefCnt(filter, 2); | |
119 | |
120 ASSERT_EQ(buffer.approximateOpCount(), 0); | |
121 EXPECT_EQ(PaintOpBuffer::Iterator(&buffer), false); | |
122 | |
123 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
124 buffer.push<DrawRectOp>(rect, flags); | |
125 CheckRefCnt(filter, 3); | |
126 | |
127 ASSERT_EQ(buffer.approximateOpCount(), 1); | |
128 EXPECT_EQ(buffer.GetFirstOp()->GetType(), PaintOpType::DrawRect); | |
129 | |
130 PaintOpBuffer::Iterator iter(&buffer); | |
131 ASSERT_EQ(iter->GetType(), PaintOpType::DrawRect); | |
132 DrawRectOp* draw_rect_op = static_cast<DrawRectOp*>(*iter); | |
133 EXPECT_EQ(draw_rect_op->rect, rect); | |
134 | |
135 ++iter; | |
136 EXPECT_FALSE(iter); | |
137 | |
138 buffer.Reset(); | |
139 ASSERT_EQ(buffer.approximateOpCount(), 0); | |
140 CheckRefCnt(filter, 2); | |
141 } | |
142 | |
143 TEST(PaintOpBufferTest, Peek) { | |
144 PaintOpBuffer buffer; | |
145 | |
146 uint8_t alpha = 100; | |
147 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
148 PaintFlags draw_flags; | |
149 buffer.push<DrawRectOp>(SkRect::MakeXYWH(1, 2, 3, 4), draw_flags); | |
150 buffer.push<RestoreOp>(); | |
151 buffer.push<SaveOp>(); | |
152 buffer.push<NoopOp>(); | |
153 buffer.push<RestoreOp>(); | |
154 | |
155 PaintOpBuffer::Iterator init_iter(&buffer); | |
156 PaintOp* peek[2] = {*init_iter, init_iter.peek1()}; | |
157 | |
158 // Expect that while iterating that next = current.peek1() and that | |
159 // next.peek1() == current.peek2(). | |
160 for (PaintOpBuffer::Iterator iter(&buffer); iter; ++iter) { | |
161 EXPECT_EQ(*iter, peek[0]) << iter.op_idx(); | |
162 EXPECT_EQ(iter.peek1(), peek[1]) << iter.op_idx(); | |
163 | |
164 peek[0] = iter.peek1(); | |
165 peek[1] = iter.peek2(); | |
166 } | |
167 } | |
168 | |
169 TEST(PaintOpBufferTest, PeekEmpty) { | |
170 PaintOpBuffer empty; | |
171 PaintOpBuffer::Iterator empty_iter(&empty); | |
172 EXPECT_EQ(nullptr, empty_iter.peek1()); | |
173 EXPECT_EQ(nullptr, empty_iter.peek2()); | |
174 } | |
175 | |
176 // Verify that a SaveLayerAlpha / Draw / Restore can be optimized to just | |
177 // a draw with opacity. | |
178 TEST(PaintOpBufferTest, SaveDrawRestore) { | |
179 PaintOpBuffer buffer; | |
180 | |
181 uint8_t alpha = 100; | |
182 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
183 | |
184 PaintFlags draw_flags; | |
185 draw_flags.setColor(SK_ColorMAGENTA); | |
186 draw_flags.setAlpha(50); | |
187 EXPECT_TRUE(draw_flags.SupportsFoldingAlpha()); | |
188 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
189 buffer.push<DrawRectOp>(rect, draw_flags); | |
190 buffer.push<RestoreOp>(); | |
191 | |
192 SaveCountingCanvas canvas; | |
193 buffer.playback(&canvas); | |
194 | |
195 EXPECT_EQ(0, canvas.save_count_); | |
196 EXPECT_EQ(0, canvas.restore_count_); | |
197 EXPECT_EQ(rect, canvas.draw_rect_); | |
198 | |
199 // Expect the alpha from the draw and the save layer to be folded together. | |
200 // Since alpha is stored in a uint8_t and gets rounded, so use tolerance. | |
201 float expected_alpha = alpha * 50 / 255.f; | |
202 EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f); | |
203 } | |
204 | |
205 // The same as SaveDrawRestore, but test that the optimization doesn't apply | |
206 // when the drawing op's flags are not compatible with being folded into the | |
207 // save layer with opacity. | |
208 TEST(PaintOpBufferTest, SaveDrawRestoreFail_BadFlags) { | |
209 PaintOpBuffer buffer; | |
210 | |
211 uint8_t alpha = 100; | |
212 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
213 | |
214 PaintFlags draw_flags; | |
215 draw_flags.setColor(SK_ColorMAGENTA); | |
216 draw_flags.setAlpha(50); | |
217 draw_flags.setBlendMode(SkBlendMode::kSrc); | |
218 EXPECT_FALSE(draw_flags.SupportsFoldingAlpha()); | |
219 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
220 buffer.push<DrawRectOp>(rect, draw_flags); | |
221 buffer.push<RestoreOp>(); | |
222 | |
223 SaveCountingCanvas canvas; | |
224 buffer.playback(&canvas); | |
225 | |
226 EXPECT_EQ(1, canvas.save_count_); | |
227 EXPECT_EQ(1, canvas.restore_count_); | |
228 EXPECT_EQ(rect, canvas.draw_rect_); | |
229 EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha()); | |
230 } | |
231 | |
232 // The same as SaveDrawRestore, but test that the optimization doesn't apply | |
233 // when there are more than one ops between the save and restore. | |
234 TEST(PaintOpBufferTest, SaveDrawRestoreFail_TooManyOps) { | |
235 PaintOpBuffer buffer; | |
236 | |
237 uint8_t alpha = 100; | |
238 buffer.push<SaveLayerAlphaOp>(nullptr, alpha); | |
239 | |
240 PaintFlags draw_flags; | |
241 draw_flags.setColor(SK_ColorMAGENTA); | |
242 draw_flags.setAlpha(50); | |
243 draw_flags.setBlendMode(SkBlendMode::kSrcOver); | |
244 EXPECT_TRUE(draw_flags.SupportsFoldingAlpha()); | |
245 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4); | |
246 buffer.push<DrawRectOp>(rect, draw_flags); | |
247 buffer.push<NoopOp>(); | |
248 buffer.push<RestoreOp>(); | |
249 | |
250 SaveCountingCanvas canvas; | |
251 buffer.playback(&canvas); | |
252 | |
253 EXPECT_EQ(1, canvas.save_count_); | |
254 EXPECT_EQ(1, canvas.restore_count_); | |
255 EXPECT_EQ(rect, canvas.draw_rect_); | |
256 EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha()); | |
257 } | |
258 | |
259 } // namespace cc | |
OLD | NEW |