Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(110)

Side by Side Diff: cc/paint/paint_op_buffer_unittest.cc

Issue 2768143002: Back PaintRecord with PaintOpBuffer instead of SkPicture (Closed)
Patch Set: more const casting Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « cc/paint/paint_op_buffer.cc ('k') | cc/paint/paint_record.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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 const void* data = draw_text_op->GetData();
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 // Verify that PaintOps with data are stored properly.
170 TEST(PaintOpBufferTest, PaintOpData) {
171 PaintOpBuffer buffer;
172
173 buffer.push<SaveOp>();
174 PaintFlags flags;
175 char text1[] = "asdfasdf";
176 buffer.push_with_data<DrawTextOp>(text1, arraysize(text1), 0.f, 0.f, flags);
177
178 char text2[] = "qwerty";
179 buffer.push_with_data<DrawTextOp>(text2, arraysize(text2), 0.f, 0.f, flags);
180
181 ASSERT_EQ(buffer.approximateOpCount(), 3);
182
183 // Verify iteration behavior and brief smoke test of op state.
184 PaintOpBuffer::Iterator iter(&buffer);
185 PaintOp* save_op = *iter;
186 EXPECT_EQ(save_op->GetType(), PaintOpType::Save);
187 ++iter;
188
189 PaintOp* op1 = *iter;
190 ASSERT_EQ(op1->GetType(), PaintOpType::DrawText);
191 DrawTextOp* draw_text_op1 = static_cast<DrawTextOp*>(op1);
192 EXPECT_EQ(draw_text_op1->bytes, arraysize(text1));
193 const void* data1 = draw_text_op1->GetData();
194 EXPECT_EQ(memcmp(data1, text1, arraysize(text1)), 0);
195 ++iter;
196
197 PaintOp* op2 = *iter;
198 ASSERT_EQ(op2->GetType(), PaintOpType::DrawText);
199 DrawTextOp* draw_text_op2 = static_cast<DrawTextOp*>(op2);
200 EXPECT_EQ(draw_text_op2->bytes, arraysize(text2));
201 const void* data2 = draw_text_op2->GetData();
202 EXPECT_EQ(memcmp(data2, text2, arraysize(text2)), 0);
203 ++iter;
204
205 EXPECT_FALSE(iter);
206 }
207
208 // Verify that PaintOps with arrays are stored properly.
209 TEST(PaintOpBufferTest, PaintOpArray) {
210 PaintOpBuffer buffer;
211 buffer.push<SaveOp>();
212
213 // arbitrary data
214 std::string texts[] = {"xyz", "abcdefg", "thingerdoo"};
215 SkPoint point1[] = {SkPoint::Make(1, 2), SkPoint::Make(2, 3),
216 SkPoint::Make(3, 4)};
217 SkPoint point2[] = {SkPoint::Make(8, -12)};
218 SkPoint point3[] = {SkPoint::Make(0, 0), SkPoint::Make(5, 6),
219 SkPoint::Make(-1, -1), SkPoint::Make(9, 9),
220 SkPoint::Make(50, 50), SkPoint::Make(100, 100)};
221 SkPoint* points[] = {point1, point2, point3};
222 size_t counts[] = {arraysize(point1), arraysize(point2), arraysize(point3)};
223
224 for (size_t i = 0; i < arraysize(texts); ++i) {
225 PaintFlags flags;
226 flags.setAlpha(i);
227 buffer.push_with_array<DrawPosTextOp>(texts[i].c_str(), texts[i].length(),
228 points[i], counts[i], flags);
229 }
230
231 PaintOpBuffer::Iterator iter(&buffer);
232 PaintOp* save_op = *iter;
233 EXPECT_EQ(save_op->GetType(), PaintOpType::Save);
234 ++iter;
235
236 for (size_t i = 0; i < arraysize(texts); ++i) {
237 ASSERT_EQ(iter->GetType(), PaintOpType::DrawPosText);
238 DrawPosTextOp* op = static_cast<DrawPosTextOp*>(*iter);
239
240 EXPECT_EQ(op->flags.getAlpha(), i);
241
242 EXPECT_EQ(op->bytes, texts[i].length());
243 const void* data = op->GetData();
244 EXPECT_EQ(memcmp(data, texts[i].c_str(), op->bytes), 0);
245
246 EXPECT_EQ(op->count, counts[i]);
247 const SkPoint* op_points = op->GetArray();
248 for (size_t k = 0; k < op->count; ++k)
249 EXPECT_EQ(op_points[k], points[i][k]);
250
251 ++iter;
252 }
253
254 EXPECT_FALSE(iter);
255 }
256
257 TEST(PaintOpBufferTest, PeekEmpty) {
258 PaintOpBuffer empty;
259 PaintOpBuffer::Iterator empty_iter(&empty);
260 EXPECT_EQ(nullptr, empty_iter.peek1());
261 EXPECT_EQ(nullptr, empty_iter.peek2());
262 }
263
264 // Verify that a SaveLayerAlpha / Draw / Restore can be optimized to just
265 // a draw with opacity.
266 TEST(PaintOpBufferTest, SaveDrawRestore) {
267 PaintOpBuffer buffer;
268
269 uint8_t alpha = 100;
270 buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
271
272 PaintFlags draw_flags;
273 draw_flags.setColor(SK_ColorMAGENTA);
274 draw_flags.setAlpha(50);
275 EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
276 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
277 buffer.push<DrawRectOp>(rect, draw_flags);
278 buffer.push<RestoreOp>();
279
280 SaveCountingCanvas canvas;
281 buffer.playback(&canvas);
282
283 EXPECT_EQ(0, canvas.save_count_);
284 EXPECT_EQ(0, canvas.restore_count_);
285 EXPECT_EQ(rect, canvas.draw_rect_);
286
287 // Expect the alpha from the draw and the save layer to be folded together.
288 // Since alpha is stored in a uint8_t and gets rounded, so use tolerance.
289 float expected_alpha = alpha * 50 / 255.f;
290 EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f);
291 }
292
293 // The same as SaveDrawRestore, but test that the optimization doesn't apply
294 // when the drawing op's flags are not compatible with being folded into the
295 // save layer with opacity.
296 TEST(PaintOpBufferTest, SaveDrawRestoreFail_BadFlags) {
297 PaintOpBuffer buffer;
298
299 uint8_t alpha = 100;
300 buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
301
302 PaintFlags draw_flags;
303 draw_flags.setColor(SK_ColorMAGENTA);
304 draw_flags.setAlpha(50);
305 draw_flags.setBlendMode(SkBlendMode::kSrc);
306 EXPECT_FALSE(draw_flags.SupportsFoldingAlpha());
307 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
308 buffer.push<DrawRectOp>(rect, draw_flags);
309 buffer.push<RestoreOp>();
310
311 SaveCountingCanvas canvas;
312 buffer.playback(&canvas);
313
314 EXPECT_EQ(1, canvas.save_count_);
315 EXPECT_EQ(1, canvas.restore_count_);
316 EXPECT_EQ(rect, canvas.draw_rect_);
317 EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha());
318 }
319
320 // The same as SaveDrawRestore, but test that the optimization doesn't apply
321 // when there are more than one ops between the save and restore.
322 TEST(PaintOpBufferTest, SaveDrawRestoreFail_TooManyOps) {
323 PaintOpBuffer buffer;
324
325 uint8_t alpha = 100;
326 buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
327
328 PaintFlags draw_flags;
329 draw_flags.setColor(SK_ColorMAGENTA);
330 draw_flags.setAlpha(50);
331 draw_flags.setBlendMode(SkBlendMode::kSrcOver);
332 EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
333 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
334 buffer.push<DrawRectOp>(rect, draw_flags);
335 buffer.push<NoopOp>();
336 buffer.push<RestoreOp>();
337
338 SaveCountingCanvas canvas;
339 buffer.playback(&canvas);
340
341 EXPECT_EQ(1, canvas.save_count_);
342 EXPECT_EQ(1, canvas.restore_count_);
343 EXPECT_EQ(rect, canvas.draw_rect_);
344 EXPECT_EQ(draw_flags.getAlpha(), canvas.paint_.getAlpha());
345 }
346
347 // Verify that the save draw restore code works with a single op
348 // that's not a draw op, and the optimization does not kick in.
349 TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpNotADrawOp) {
350 PaintOpBuffer buffer;
351
352 uint8_t alpha = 100;
353 buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
354
355 buffer.push<NoopOp>();
356 buffer.push<RestoreOp>();
357
358 SaveCountingCanvas canvas;
359 buffer.playback(&canvas);
360
361 EXPECT_EQ(1, canvas.save_count_);
362 EXPECT_EQ(1, canvas.restore_count_);
363 }
364
365 // Test that the save/draw/restore optimization applies if the single op
366 // is a DrawRecord that itself has a single draw op.
367 TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleOp) {
368 sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
369
370 PaintFlags draw_flags;
371 draw_flags.setColor(SK_ColorMAGENTA);
372 draw_flags.setAlpha(50);
373 EXPECT_TRUE(draw_flags.SupportsFoldingAlpha());
374 SkRect rect = SkRect::MakeXYWH(1, 2, 3, 4);
375 record->push<DrawRectOp>(rect, draw_flags);
376 EXPECT_EQ(record->approximateOpCount(), 1);
377
378 PaintOpBuffer buffer;
379
380 uint8_t alpha = 100;
381 buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
382 buffer.push<DrawRecordOp>(std::move(record));
383 buffer.push<RestoreOp>();
384
385 SaveCountingCanvas canvas;
386 buffer.playback(&canvas);
387
388 EXPECT_EQ(0, canvas.save_count_);
389 EXPECT_EQ(0, canvas.restore_count_);
390 EXPECT_EQ(rect, canvas.draw_rect_);
391
392 float expected_alpha = alpha * 50 / 255.f;
393 EXPECT_LE(std::abs(expected_alpha - canvas.paint_.getAlpha()), 1.f);
394 }
395
396 // The same as the above SingleOpRecord test, but the single op is not
397 // a draw op. So, there's no way to fold in the save layer optimization.
398 // Verify that the optimization doesn't apply and that this doesn't crash.
399 // See: http://crbug.com/712093.
400 TEST(PaintOpBufferTest, SaveDrawRestore_SingleOpRecordWithSingleNonDrawOp) {
401 sk_sp<PaintRecord> record = sk_make_sp<PaintRecord>();
402 record->push<NoopOp>();
403 EXPECT_EQ(record->approximateOpCount(), 1);
404 EXPECT_FALSE(record->GetFirstOp()->IsDrawOp());
405
406 PaintOpBuffer buffer;
407
408 uint8_t alpha = 100;
409 buffer.push<SaveLayerAlphaOp>(nullptr, alpha);
410 buffer.push<DrawRecordOp>(std::move(record));
411 buffer.push<RestoreOp>();
412
413 SaveCountingCanvas canvas;
414 buffer.playback(&canvas);
415
416 EXPECT_EQ(1, canvas.save_count_);
417 EXPECT_EQ(1, canvas.restore_count_);
418 }
419
420 } // namespace cc
OLDNEW
« no previous file with comments | « cc/paint/paint_op_buffer.cc ('k') | cc/paint/paint_record.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698