1 // Copyright 2014 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/display_item_list.h"
6
7 #include <stddef.h>
8
9 #include <vector>
10
11 #include "base/logging.h"
12 #include "base/trace_event/traced_value.h"
13 #include "base/values.h"
14 #include "cc/paint/filter_operation.h"
15 #include "cc/paint/filter_operations.h"
16 #include "cc/paint/paint_canvas.h"
17 #include "cc/paint/paint_flags.h"
18 #include "cc/paint/paint_image_builder.h"
19 #include "cc/paint/paint_record.h"
20 #include "cc/paint/render_surface_filters.h"
21 #include "cc/paint/skia_paint_canvas.h"
22 #include "cc/test/geometry_test_utils.h"
23 #include "cc/test/pixel_test_utils.h"
24 #include "cc/test/skia_common.h"
25 #include "cc/test/test_skcanvas.h"
26 #include "testing/gmock/include/gmock/gmock.h"
27 #include "testing/gtest/include/gtest/gtest.h"
28 #include "third_party/skia/include/core/SkBitmap.h"
29 #include "third_party/skia/include/core/SkColor.h"
30 #include "third_party/skia/include/core/SkSurface.h"
31 #include "ui/gfx/geometry/rect.h"
32 #include "ui/gfx/geometry/rect_conversions.h"
33 #include "ui/gfx/skia_util.h"
34
35 namespace cc {
36
37 namespace {
38
CompareN32Pixels(void * actual_pixels,void * expected_pixels,int width,int height)39 bool CompareN32Pixels(void* actual_pixels,
40 void* expected_pixels,
41 int width,
42 int height) {
43 if (memcmp(actual_pixels, expected_pixels, 4 * width * height) == 0)
44 return true;
45
46 SkImageInfo actual_info = SkImageInfo::MakeN32Premul(width, height);
47 SkBitmap actual_bitmap;
48 actual_bitmap.installPixels(actual_info, actual_pixels,
49 actual_info.minRowBytes());
50
51 SkImageInfo expected_info = SkImageInfo::MakeN32Premul(width, height);
52 SkBitmap expected_bitmap;
53 expected_bitmap.installPixels(expected_info, expected_pixels,
54 expected_info.minRowBytes());
55
56 std::string gen_bmp_data_url = GetPNGDataUrl(actual_bitmap);
57 std::string ref_bmp_data_url = GetPNGDataUrl(expected_bitmap);
58
59 LOG(ERROR) << "Pixels do not match!";
60 LOG(ERROR) << "Actual: " << gen_bmp_data_url;
61 LOG(ERROR) << "Expected: " << ref_bmp_data_url;
62 return false;
63 }
64
65 } // namespace
66
67 class DisplayItemListTest : public testing::Test {
68 protected:
ToBaseValue(const DisplayItemList * list,bool include_items)69 std::unique_ptr<base::Value> ToBaseValue(const DisplayItemList* list,
70 bool include_items) {
71 base::trace_event::TracedValueJSON value;
72 list->AddToValue(&value, include_items);
73 return value.ToBaseValue();
74 }
75 };
76
77 #define EXPECT_TRACED_RECT(x, y, width, height, rect_list) \
78 do { \
79 ASSERT_EQ(4u, rect_list->GetSize()); \
80 double d; \
81 EXPECT_TRUE((rect_list)->GetDouble(0, &d)); \
82 EXPECT_EQ(x, d); \
83 EXPECT_TRUE((rect_list)->GetDouble(1, &d)); \
84 EXPECT_EQ(y, d); \
85 EXPECT_TRUE((rect_list)->GetDouble(2, &d)); \
86 EXPECT_EQ(width, d); \
87 EXPECT_TRUE((rect_list)->GetDouble(3, &d)); \
88 EXPECT_EQ(height, d); \
89 } while (false)
90
91 // AddToValue should not crash if there are different numbers of visual_rect
92 // are paint_op
TEST_F(DisplayItemListTest,TraceEmptyVisualRect)93 TEST_F(DisplayItemListTest, TraceEmptyVisualRect) {
94 PaintFlags red_paint;
95 red_paint.setColor(SK_ColorRED);
96 auto list = base::MakeRefCounted<DisplayItemList>();
97
98 gfx::Point offset(8, 9);
99
100 list->StartPaint();
101 list->push<DrawRectOp>(SkRect::MakeEmpty(), red_paint);
102 // The rect is empty to cause rtree generation to skip it.
103 list->EndPaintOfUnpaired(gfx::Rect(offset, gfx::Size(0, 10)));
104 list->StartPaint();
105 list->push<DrawRectOp>(SkRect::MakeXYWH(0, 0, 10, 10), red_paint);
106 // This rect is not empty.
107 list->EndPaintOfUnpaired(gfx::Rect(offset, gfx::Size(10, 10)));
108 list->Finalize();
109
110 // Pass: we don't crash
111 std::unique_ptr<base::Value> root = ToBaseValue(list.get(), true);
112
113 const base::DictionaryValue* root_dict;
114 ASSERT_TRUE(root->GetAsDictionary(&root_dict));
115 const base::DictionaryValue* params_dict;
116 ASSERT_TRUE(root_dict->GetDictionary("params", ¶ms_dict));
117 const base::ListValue* items;
118 ASSERT_TRUE(params_dict->GetList("items", &items));
119 ASSERT_EQ(2u, items->GetSize());
120
121 const base::DictionaryValue* item_dict;
122 const base::ListValue* visual_rect;
123 std::string name;
124
125 ASSERT_TRUE(items->GetDictionary(0, &item_dict));
126 ASSERT_TRUE(item_dict->GetList("visual_rect", &visual_rect));
127 EXPECT_TRACED_RECT(0, 0, 0, 0, visual_rect);
128 EXPECT_TRUE(item_dict->GetString("name", &name));
129 EXPECT_EQ("DrawRect", name);
130
131 ASSERT_TRUE(items->GetDictionary(1, &item_dict));
132 ASSERT_TRUE(item_dict->GetList("visual_rect", &visual_rect));
133 EXPECT_TRACED_RECT(8, 9, 10, 10, visual_rect);
134 EXPECT_TRUE(item_dict->GetString("name", &name));
135 EXPECT_EQ("DrawRect", name);
136 }
137
TEST_F(DisplayItemListTest,SingleUnpairedRange)138 TEST_F(DisplayItemListTest, SingleUnpairedRange) {
139 gfx::Rect layer_rect(100, 100);
140 PaintFlags blue_flags;
141 blue_flags.setColor(SK_ColorBLUE);
142 PaintFlags red_paint;
143 red_paint.setColor(SK_ColorRED);
144 unsigned char pixels[4 * 100 * 100] = {0};
145 auto list = base::MakeRefCounted<DisplayItemList>();
146
147 gfx::Point offset(8, 9);
148
149 list->StartPaint();
150 list->push<SaveOp>();
151 list->push<TranslateOp>(static_cast<float>(offset.x()),
152 static_cast<float>(offset.y()));
153 list->push<DrawRectOp>(SkRect::MakeLTRB(0.f, 0.f, 60.f, 60.f), red_paint);
154 list->push<DrawRectOp>(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f), blue_flags);
155 list->push<RestoreOp>();
156 list->EndPaintOfUnpaired(gfx::Rect(offset, layer_rect.size()));
157 list->Finalize();
158 DrawDisplayList(pixels, layer_rect, list);
159
160 SkBitmap expected_bitmap;
161 unsigned char expected_pixels[4 * 100 * 100] = {0};
162 SkImageInfo info =
163 SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
164 expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
165 SkiaPaintCanvas expected_canvas(expected_bitmap);
166 expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
167 expected_canvas.drawRect(
168 SkRect::MakeLTRB(0.f + offset.x(), 0.f + offset.y(), 60.f + offset.x(),
169 60.f + offset.y()),
170 red_paint);
171 expected_canvas.drawRect(
172 SkRect::MakeLTRB(50.f + offset.x(), 50.f + offset.y(), 75.f + offset.x(),
173 75.f + offset.y()),
174 blue_flags);
175
176 EXPECT_TRUE(CompareN32Pixels(pixels, expected_pixels, 100, 100));
177 }
178
TEST_F(DisplayItemListTest,EmptyUnpairedRangeDoesNotAddVisualRect)179 TEST_F(DisplayItemListTest, EmptyUnpairedRangeDoesNotAddVisualRect) {
180 gfx::Rect layer_rect(100, 100);
181 auto list = base::MakeRefCounted<DisplayItemList>();
182
183 {
184 list->StartPaint();
185 list->EndPaintOfUnpaired(layer_rect);
186 }
187 // No ops.
188 EXPECT_EQ(0u, list->TotalOpCount());
189
190 {
191 list->StartPaint();
192 list->push<SaveOp>();
193 list->push<RestoreOp>();
194 list->EndPaintOfUnpaired(layer_rect);
195 }
196 // Two ops.
197 EXPECT_EQ(2u, list->TotalOpCount());
198 }
199
TEST_F(DisplayItemListTest,ClipPairedRange)200 TEST_F(DisplayItemListTest, ClipPairedRange) {
201 gfx::Rect layer_rect(100, 100);
202 PaintFlags blue_flags;
203 blue_flags.setColor(SK_ColorBLUE);
204 PaintFlags red_paint;
205 red_paint.setColor(SK_ColorRED);
206 unsigned char pixels[4 * 100 * 100] = {0};
207 auto list = base::MakeRefCounted<DisplayItemList>();
208
209 gfx::Point first_offset(8, 9);
210 gfx::Rect first_recording_rect(first_offset, layer_rect.size());
211
212 {
213 list->StartPaint();
214 list->push<SaveOp>();
215 list->push<TranslateOp>(static_cast<float>(first_offset.x()),
216 static_cast<float>(first_offset.y()));
217 list->push<DrawRectOp>(SkRect::MakeWH(60, 60), red_paint);
218 list->push<RestoreOp>();
219 list->EndPaintOfUnpaired(first_recording_rect);
220 }
221
222 gfx::Rect clip_rect(60, 60, 10, 10);
223 {
224 list->StartPaint();
225 list->push<SaveOp>();
226 list->push<ClipRectOp>(gfx::RectToSkRect(clip_rect), SkClipOp::kIntersect,
227 true);
228 list->EndPaintOfPairedBegin();
229 }
230
231 gfx::Point second_offset(2, 3);
232 gfx::Rect second_recording_rect(second_offset, layer_rect.size());
233 {
234 list->StartPaint();
235 list->push<SaveOp>();
236 list->push<TranslateOp>(static_cast<float>(second_offset.x()),
237 static_cast<float>(second_offset.y()));
238 list->push<DrawRectOp>(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f),
239 blue_flags);
240 list->push<RestoreOp>();
241 list->EndPaintOfUnpaired(second_recording_rect);
242 }
243
244 {
245 list->StartPaint();
246 list->push<RestoreOp>();
247 list->EndPaintOfPairedEnd();
248 }
249
250 list->Finalize();
251
252 DrawDisplayList(pixels, layer_rect, list);
253
254 SkBitmap expected_bitmap;
255 unsigned char expected_pixels[4 * 100 * 100] = {0};
256 SkImageInfo info =
257 SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
258 expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
259 SkiaPaintCanvas expected_canvas(expected_bitmap);
260 expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
261 expected_canvas.drawRect(
262 SkRect::MakeLTRB(0.f + first_offset.x(), 0.f + first_offset.y(),
263 60.f + first_offset.x(), 60.f + first_offset.y()),
264 red_paint);
265 expected_canvas.clipRect(gfx::RectToSkRect(clip_rect));
266 expected_canvas.drawRect(
267 SkRect::MakeLTRB(50.f + second_offset.x(), 50.f + second_offset.y(),
268 75.f + second_offset.x(), 75.f + second_offset.y()),
269 blue_flags);
270
271 EXPECT_TRUE(CompareN32Pixels(pixels, expected_pixels, 100, 100));
272 }
273
TEST_F(DisplayItemListTest,TransformPairedRange)274 TEST_F(DisplayItemListTest, TransformPairedRange) {
275 gfx::Rect layer_rect(100, 100);
276 PaintFlags blue_flags;
277 blue_flags.setColor(SK_ColorBLUE);
278 PaintFlags red_paint;
279 red_paint.setColor(SK_ColorRED);
280 unsigned char pixels[4 * 100 * 100] = {0};
281 auto list = base::MakeRefCounted<DisplayItemList>();
282
283 gfx::Point first_offset(8, 9);
284 gfx::Rect first_recording_rect(first_offset, layer_rect.size());
285 {
286 list->StartPaint();
287 list->push<SaveOp>();
288 list->push<TranslateOp>(static_cast<float>(first_offset.x()),
289 static_cast<float>(first_offset.y()));
290 list->push<DrawRectOp>(SkRect::MakeWH(60, 60), red_paint);
291 list->push<RestoreOp>();
292 list->EndPaintOfUnpaired(first_recording_rect);
293 }
294
295 gfx::Transform transform;
296 transform.Rotate(45.0);
297 {
298 list->StartPaint();
299 list->push<SaveOp>();
300 list->push<ConcatOp>(static_cast<SkMatrix>(transform.matrix()));
301 list->EndPaintOfPairedBegin();
302 }
303
304 gfx::Point second_offset(2, 3);
305 gfx::Rect second_recording_rect(second_offset, layer_rect.size());
306 {
307 list->StartPaint();
308 list->push<SaveOp>();
309 list->push<TranslateOp>(static_cast<float>(second_offset.x()),
310 static_cast<float>(second_offset.y()));
311 list->push<DrawRectOp>(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f),
312 blue_flags);
313 list->push<RestoreOp>();
314 list->EndPaintOfUnpaired(second_recording_rect);
315 }
316
317 {
318 list->StartPaint();
319 list->push<RestoreOp>();
320 list->EndPaintOfPairedEnd();
321 }
322 list->Finalize();
323
324 DrawDisplayList(pixels, layer_rect, list);
325
326 SkBitmap expected_bitmap;
327 unsigned char expected_pixels[4 * 100 * 100] = {0};
328 SkImageInfo info =
329 SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
330 expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
331 SkiaPaintCanvas expected_canvas(expected_bitmap);
332 expected_canvas.clipRect(gfx::RectToSkRect(layer_rect));
333 expected_canvas.drawRect(
334 SkRect::MakeLTRB(0.f + first_offset.x(), 0.f + first_offset.y(),
335 60.f + first_offset.x(), 60.f + first_offset.y()),
336 red_paint);
337 expected_canvas.setMatrix(SkMatrix(transform.matrix()));
338 expected_canvas.drawRect(
339 SkRect::MakeLTRB(50.f + second_offset.x(), 50.f + second_offset.y(),
340 75.f + second_offset.x(), 75.f + second_offset.y()),
341 blue_flags);
342
343 EXPECT_TRUE(CompareN32Pixels(pixels, expected_pixels, 100, 100));
344 }
345
TEST_F(DisplayItemListTest,FilterPairedRange)346 TEST_F(DisplayItemListTest, FilterPairedRange) {
347 gfx::Rect layer_rect(100, 100);
348 FilterOperations filters;
349 unsigned char pixels[4 * 100 * 100] = {0};
350 auto list = base::MakeRefCounted<DisplayItemList>();
351
352 sk_sp<SkSurface> source_surface = SkSurface::MakeRasterN32Premul(50, 50);
353 SkCanvas* source_canvas = source_surface->getCanvas();
354 source_canvas->clear(SkColorSetRGB(128, 128, 128));
355 PaintImage source_image = PaintImageBuilder::WithDefault()
356 .set_id(PaintImage::GetNextId())
357 .set_image(source_surface->makeImageSnapshot(),
358 PaintImage::GetNextContentId())
359 .TakePaintImage();
360
361 // For most SkImageFilters, the |dst| bounds computed by computeFastBounds are
362 // dependent on the provided |src| bounds. This means, for example, that
363 // translating |src| results in a corresponding translation of |dst|. But this
364 // is not the case for all SkImageFilters; for some of them (e.g.
365 // SkImageSource), the computation of |dst| in computeFastBounds doesn't
366 // involve |src| at all. Incorrectly assuming such a relationship (e.g. by
367 // translating |dst| after it is computed by computeFastBounds, rather than
368 // translating |src| before it provided to computedFastBounds) can cause
369 // incorrect clipping of filter output. To test for this, we include an
370 // SkImageSource filter in |filters|. Here, |src| is |filter_bounds|, defined
371 // below.
372 SkRect rect = SkRect::MakeWH(source_image.width(), source_image.height());
373 sk_sp<PaintFilter> image_filter = sk_make_sp<ImagePaintFilter>(
374 source_image, rect, rect, kHigh_SkFilterQuality);
375 filters.Append(FilterOperation::CreateReferenceFilter(image_filter));
376 filters.Append(FilterOperation::CreateBrightnessFilter(0.5f));
377 gfx::RectF filter_bounds(10.f, 10.f, 50.f, 50.f);
378 {
379 list->StartPaint();
380 list->push<SaveOp>();
381 list->push<TranslateOp>(filter_bounds.x(), filter_bounds.y());
382
383 PaintFlags flags;
384 flags.setImageFilter(
385 RenderSurfaceFilters::BuildImageFilter(filters, filter_bounds.size()));
386
387 SkRect layer_bounds = gfx::RectFToSkRect(filter_bounds);
388 layer_bounds.offset(-filter_bounds.x(), -filter_bounds.y());
389 list->push<SaveLayerOp>(&layer_bounds, &flags);
390 list->push<TranslateOp>(-filter_bounds.x(), -filter_bounds.y());
391
392 list->EndPaintOfPairedBegin();
393 }
394
395 // Include a rect drawing so that filter is actually applied to something.
396 {
397 list->StartPaint();
398
399 PaintFlags red_flags;
400 red_flags.setColor(SK_ColorRED);
401
402 list->push<DrawRectOp>(
403 SkRect::MakeLTRB(filter_bounds.x(), filter_bounds.y(),
404 filter_bounds.right(), filter_bounds.bottom()),
405 red_flags);
406
407 list->EndPaintOfUnpaired(ToEnclosingRect(filter_bounds));
408 }
409
410 {
411 list->StartPaint();
412 list->push<RestoreOp>(); // For SaveLayerOp.
413 list->push<RestoreOp>(); // For SaveOp.
414 list->EndPaintOfPairedEnd();
415 }
416
417 list->Finalize();
418
419 DrawDisplayList(pixels, layer_rect, list);
420
421 SkBitmap expected_bitmap;
422 unsigned char expected_pixels[4 * 100 * 100] = {0};
423 PaintFlags paint;
424 paint.setColor(SkColorSetRGB(64, 64, 64));
425 SkImageInfo info =
426 SkImageInfo::MakeN32Premul(layer_rect.width(), layer_rect.height());
427 expected_bitmap.installPixels(info, expected_pixels, info.minRowBytes());
428 SkiaPaintCanvas expected_canvas(expected_bitmap);
429 expected_canvas.drawRect(RectFToSkRect(filter_bounds), paint);
430
431 EXPECT_TRUE(CompareN32Pixels(pixels, expected_pixels, 100, 100));
432 }
433
TEST_F(DisplayItemListTest,BytesUsed)434 TEST_F(DisplayItemListTest, BytesUsed) {
435 const int kNumPaintOps = 1000;
436 size_t memory_usage;
437
438 auto list = base::MakeRefCounted<DisplayItemList>();
439
440 gfx::Rect layer_rect(100, 100);
441 PaintFlags blue_flags;
442 blue_flags.setColor(SK_ColorBLUE);
443
444 {
445 list->StartPaint();
446 for (int i = 0; i < kNumPaintOps; i++)
447 list->push<DrawRectOp>(SkRect::MakeWH(1, 1), blue_flags);
448 list->EndPaintOfUnpaired(layer_rect);
449 }
450
451 memory_usage = list->BytesUsed();
452 EXPECT_GE(memory_usage, sizeof(DrawRectOp) * kNumPaintOps);
453 EXPECT_LE(memory_usage, 2 * sizeof(DrawRectOp) * kNumPaintOps);
454 }
455
TEST_F(DisplayItemListTest,AsValueWithNoOps)456 TEST_F(DisplayItemListTest, AsValueWithNoOps) {
457 auto list = base::MakeRefCounted<DisplayItemList>();
458 list->Finalize();
459
460 // Pass |true| to ask for PaintOps even though there are none.
461 std::unique_ptr<base::Value> root = ToBaseValue(list.get(), true);
462 const base::DictionaryValue* root_dict;
463 ASSERT_TRUE(root->GetAsDictionary(&root_dict));
464 // The traced value has a params dictionary as its root.
465 {
466 const base::DictionaryValue* params_dict;
467 ASSERT_TRUE(root_dict->GetDictionary("params", ¶ms_dict));
468
469 // The real contents of the traced value is in here.
470 {
471 const base::ListValue* params_list;
472
473 // The layer_rect field is present by empty.
474 ASSERT_TRUE(params_dict->GetList("layer_rect", ¶ms_list));
475 EXPECT_TRACED_RECT(0, 0, 0, 0, params_list);
476
477 // The items list is there but empty.
478 ASSERT_TRUE(params_dict->GetList("items", ¶ms_list));
479 EXPECT_EQ(0u, params_list->GetSize());
480 }
481 }
482
483 // Pass |false| to not include PaintOps.
484 root = ToBaseValue(list.get(), false);
485 ASSERT_TRUE(root->GetAsDictionary(&root_dict));
486 // The traced value has a params dictionary as its root.
487 {
488 const base::DictionaryValue* params_dict;
489 ASSERT_TRUE(root_dict->GetDictionary("params", ¶ms_dict));
490
491 // The real contents of the traced value is in here.
492 {
493 const base::ListValue* params_list;
494
495 // The layer_rect field is present by empty.
496 ASSERT_TRUE(params_dict->GetList("layer_rect", ¶ms_list));
497 EXPECT_TRACED_RECT(0, 0, 0, 0, params_list);
498
499 // The items list is not there since we asked for no ops.
500 ASSERT_FALSE(params_dict->GetList("items", ¶ms_list));
501 }
502 }
503 }
504
TEST_F(DisplayItemListTest,AsValueWithOps)505 TEST_F(DisplayItemListTest, AsValueWithOps) {
506 gfx::Rect layer_rect = gfx::Rect(1, 2, 8, 9);
507 auto list = base::MakeRefCounted<DisplayItemList>();
508 gfx::Transform transform;
509 transform.Translate(6.f, 7.f);
510
511 {
512 list->StartPaint();
513 list->push<SaveOp>();
514 list->push<ConcatOp>(static_cast<SkMatrix>(transform.matrix()));
515 list->EndPaintOfPairedBegin();
516 }
517
518 gfx::Point offset(2, 3);
519 gfx::Rect bounds(offset, layer_rect.size());
520 {
521 list->StartPaint();
522
523 PaintFlags red_paint;
524 red_paint.setColor(SK_ColorRED);
525
526 list->push<SaveLayerOp>(nullptr, &red_paint);
527 list->push<TranslateOp>(static_cast<float>(offset.x()),
528 static_cast<float>(offset.y()));
529 list->push<DrawRectOp>(SkRect::MakeWH(4, 4), red_paint);
530 list->push<RestoreOp>();
531
532 list->EndPaintOfUnpaired(bounds);
533 }
534
535 {
536 list->StartPaint();
537 list->push<RestoreOp>();
538 list->EndPaintOfPairedEnd();
539 }
540 list->Finalize();
541
542 // Pass |true| to ask for PaintOps to be included.
543 std::unique_ptr<base::Value> root = ToBaseValue(list.get(), true);
544 const base::DictionaryValue* root_dict;
545 ASSERT_TRUE(root->GetAsDictionary(&root_dict));
546 // The traced value has a params dictionary as its root.
547 {
548 const base::DictionaryValue* params_dict;
549 ASSERT_TRUE(root_dict->GetDictionary("params", ¶ms_dict));
550
551 // The real contents of the traced value is in here.
552 {
553 const base::ListValue* layer_rect_list;
554 // The layer_rect field is present and has the bounds of the rtree.
555 ASSERT_TRUE(params_dict->GetList("layer_rect", &layer_rect_list));
556 EXPECT_TRACED_RECT(2, 3, 8, 9, layer_rect_list);
557
558 // The items list has 3 things in it since we built 3 visual rects.
559 const base::ListValue* items;
560 ASSERT_TRUE(params_dict->GetList("items", &items));
561 ASSERT_EQ(7u, items->GetSize());
562
563 const char* expected_names[] = {"Save", "Concat", "SaveLayer",
564 "Translate", "DrawRect", "Restore",
565 "Restore"};
566 bool expected_has_skp[] = {false, true, true, true, true, false, false};
567
568 for (int i = 0; i < 7; ++i) {
569 const base::DictionaryValue* item_dict;
570 ASSERT_TRUE(items->GetDictionary(i, &item_dict));
571
572 const base::ListValue* visual_rect;
573 ASSERT_TRUE(item_dict->GetList("visual_rect", &visual_rect));
574 EXPECT_TRACED_RECT(2, 3, 8, 9, visual_rect);
575
576 std::string name;
577 EXPECT_TRUE(item_dict->GetString("name", &name));
578 EXPECT_EQ(expected_names[i], name);
579
580 EXPECT_EQ(
581 expected_has_skp[i],
582 item_dict->GetString("skp64", static_cast<std::string*>(nullptr)));
583 }
584 }
585 }
586
587 // Pass |false| to not include PaintOps.
588 root = ToBaseValue(list.get(), false);
589 ASSERT_TRUE(root->GetAsDictionary(&root_dict));
590 // The traced value has a params dictionary as its root.
591 {
592 const base::DictionaryValue* params_dict;
593 ASSERT_TRUE(root_dict->GetDictionary("params", ¶ms_dict));
594
595 // The real contents of the traced value is in here.
596 {
597 const base::ListValue* params_list;
598 // The layer_rect field is present and has the bounds of the rtree.
599 ASSERT_TRUE(params_dict->GetList("layer_rect", ¶ms_list));
600 EXPECT_TRACED_RECT(2, 3, 8, 9, params_list);
601
602 // The items list is not present since we asked for no ops.
603 ASSERT_FALSE(params_dict->GetList("items", ¶ms_list));
604 }
605 }
606 }
607
TEST_F(DisplayItemListTest,SizeEmpty)608 TEST_F(DisplayItemListTest, SizeEmpty) {
609 auto list = base::MakeRefCounted<DisplayItemList>();
610 EXPECT_EQ(0u, list->TotalOpCount());
611 }
612
TEST_F(DisplayItemListTest,SizeOne)613 TEST_F(DisplayItemListTest, SizeOne) {
614 auto list = base::MakeRefCounted<DisplayItemList>();
615 gfx::Rect drawing_bounds(5, 6, 1, 1);
616 {
617 list->StartPaint();
618 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_bounds), PaintFlags());
619 list->EndPaintOfUnpaired(drawing_bounds);
620 }
621 EXPECT_EQ(1u, list->TotalOpCount());
622 }
623
TEST_F(DisplayItemListTest,SizeMultiple)624 TEST_F(DisplayItemListTest, SizeMultiple) {
625 auto list = base::MakeRefCounted<DisplayItemList>();
626 gfx::Rect clip_bounds(5, 6, 7, 8);
627 {
628 list->StartPaint();
629 list->push<SaveOp>();
630 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
631 false);
632 list->EndPaintOfPairedBegin();
633 }
634 {
635 list->StartPaint();
636 list->push<RestoreOp>();
637 list->EndPaintOfPairedEnd();
638 }
639 EXPECT_EQ(3u, list->TotalOpCount());
640 }
641
TEST_F(DisplayItemListTest,AppendVisualRectSimple)642 TEST_F(DisplayItemListTest, AppendVisualRectSimple) {
643 auto list = base::MakeRefCounted<DisplayItemList>();
644
645 // One drawing: D.
646
647 gfx::Rect drawing_bounds(5, 6, 7, 8);
648 {
649 list->StartPaint();
650 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_bounds), PaintFlags());
651 list->EndPaintOfUnpaired(drawing_bounds);
652 }
653
654 EXPECT_EQ(1u, list->TotalOpCount());
655 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
656 }
657
TEST_F(DisplayItemListTest,AppendVisualRectEmptyBlock)658 TEST_F(DisplayItemListTest, AppendVisualRectEmptyBlock) {
659 auto list = base::MakeRefCounted<DisplayItemList>();
660
661 // One block: B1, E1.
662
663 gfx::Rect clip_bounds(5, 6, 7, 8);
664 {
665 list->StartPaint();
666 list->push<SaveOp>();
667 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
668 false);
669 list->EndPaintOfPairedBegin();
670 }
671 {
672 list->StartPaint();
673 list->push<RestoreOp>();
674 list->EndPaintOfPairedEnd();
675 }
676
677 EXPECT_EQ(3u, list->TotalOpCount());
678 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0));
679 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1));
680 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(2));
681 }
682
TEST_F(DisplayItemListTest,AppendVisualRectEmptyBlockContainingEmptyBlock)683 TEST_F(DisplayItemListTest, AppendVisualRectEmptyBlockContainingEmptyBlock) {
684 auto list = base::MakeRefCounted<DisplayItemList>();
685
686 // Two nested blocks: B1, B2, E2, E1.
687
688 gfx::Rect clip_bounds(5, 6, 7, 8);
689 {
690 list->StartPaint();
691 list->push<SaveOp>();
692 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
693 false);
694 list->EndPaintOfPairedBegin();
695 }
696
697 {
698 list->StartPaint();
699 list->push<SaveOp>();
700 list->EndPaintOfPairedBegin();
701 }
702 {
703 list->StartPaint();
704 list->push<RestoreOp>();
705 list->EndPaintOfPairedEnd();
706 }
707
708 {
709 list->StartPaint();
710 list->push<RestoreOp>();
711 list->EndPaintOfPairedEnd();
712 }
713
714 EXPECT_EQ(5u, list->TotalOpCount());
715 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(0));
716 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(1));
717 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(2));
718 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(3));
719 EXPECT_RECT_EQ(gfx::Rect(), list->VisualRectForTesting(4));
720 }
721
TEST_F(DisplayItemListTest,AppendVisualRectBlockContainingDrawing)722 TEST_F(DisplayItemListTest, AppendVisualRectBlockContainingDrawing) {
723 auto list = base::MakeRefCounted<DisplayItemList>();
724
725 // One block with one drawing: B1, Da, E1.
726
727 gfx::Rect clip_bounds(5, 6, 7, 8);
728 {
729 list->StartPaint();
730 list->push<SaveOp>();
731 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
732 false);
733 list->EndPaintOfPairedBegin();
734 }
735
736 gfx::Rect drawing_bounds(5, 6, 1, 1);
737 {
738 list->StartPaint();
739 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_bounds), PaintFlags());
740 list->EndPaintOfUnpaired(drawing_bounds);
741 }
742
743 {
744 list->StartPaint();
745 list->push<RestoreOp>();
746 list->EndPaintOfPairedEnd();
747 }
748
749 EXPECT_EQ(4u, list->TotalOpCount());
750 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
751 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1));
752 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2));
753 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(3));
754 }
755
TEST_F(DisplayItemListTest,AppendVisualRectBlockContainingEscapedDrawing)756 TEST_F(DisplayItemListTest, AppendVisualRectBlockContainingEscapedDrawing) {
757 auto list = base::MakeRefCounted<DisplayItemList>();
758
759 // One block with one drawing: B1, Da (escapes), E1.
760
761 gfx::Rect clip_bounds(5, 6, 7, 8);
762 {
763 list->StartPaint();
764 list->push<SaveOp>();
765 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
766 false);
767 list->EndPaintOfPairedBegin();
768 }
769
770 gfx::Rect drawing_bounds(1, 2, 3, 4);
771 {
772 list->StartPaint();
773 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_bounds), PaintFlags());
774 list->EndPaintOfUnpaired(drawing_bounds);
775 }
776
777 {
778 list->StartPaint();
779 list->push<RestoreOp>();
780 list->EndPaintOfPairedEnd();
781 }
782
783 EXPECT_EQ(4u, list->TotalOpCount());
784 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
785 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(1));
786 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(2));
787 EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(3));
788 }
789
TEST_F(DisplayItemListTest,AppendVisualRectDrawingFollowedByBlockContainingEscapedDrawing)790 TEST_F(DisplayItemListTest,
791 AppendVisualRectDrawingFollowedByBlockContainingEscapedDrawing) {
792 auto list = base::MakeRefCounted<DisplayItemList>();
793
794 // One drawing followed by one block with one drawing: Da, B1, Db (escapes),
795 // E1.
796
797 gfx::Rect drawing_a_bounds(1, 2, 3, 4);
798 {
799 list->StartPaint();
800 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_a_bounds), PaintFlags());
801 list->EndPaintOfUnpaired(drawing_a_bounds);
802 }
803
804 gfx::Rect clip_bounds(5, 6, 7, 8);
805 {
806 list->StartPaint();
807 list->push<SaveOp>();
808 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
809 false);
810 list->EndPaintOfPairedBegin();
811 }
812
813 gfx::Rect drawing_b_bounds(13, 14, 1, 1);
814 {
815 list->StartPaint();
816 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_b_bounds), PaintFlags());
817 list->EndPaintOfUnpaired(drawing_b_bounds);
818 }
819
820 {
821 list->StartPaint();
822 list->push<RestoreOp>();
823 list->EndPaintOfPairedEnd();
824 }
825
826 EXPECT_EQ(5u, list->TotalOpCount());
827 EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(0));
828 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(1));
829 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(2));
830 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3));
831 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4));
832 }
833
TEST_F(DisplayItemListTest,AppendVisualRectTwoBlocksTwoDrawings)834 TEST_F(DisplayItemListTest, AppendVisualRectTwoBlocksTwoDrawings) {
835 auto list = base::MakeRefCounted<DisplayItemList>();
836
837 // Multiple nested blocks with drawings amidst: B1, Da, B2, Db, E2, E1.
838
839 gfx::Rect clip_bounds(5, 6, 7, 8);
840 {
841 list->StartPaint();
842 list->push<SaveOp>();
843 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
844 false);
845 list->EndPaintOfPairedBegin();
846 }
847
848 gfx::Rect drawing_a_bounds(5, 6, 1, 1);
849 {
850 list->StartPaint();
851 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_a_bounds), PaintFlags());
852 list->EndPaintOfUnpaired(drawing_a_bounds);
853 }
854
855 {
856 list->StartPaint();
857 list->push<SaveOp>();
858 list->push<ConcatOp>(SkMatrix::I());
859 list->EndPaintOfPairedBegin();
860 }
861
862 gfx::Rect drawing_b_bounds(7, 8, 1, 1);
863 {
864 list->StartPaint();
865 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_b_bounds), PaintFlags());
866 list->EndPaintOfUnpaired(drawing_b_bounds);
867 }
868
869 // End transform.
870 {
871 list->StartPaint();
872 list->push<RestoreOp>();
873 list->EndPaintOfPairedEnd();
874 }
875 // End clip.
876 {
877 list->StartPaint();
878 list->push<RestoreOp>();
879 list->EndPaintOfPairedEnd();
880 }
881
882 EXPECT_EQ(8u, list->TotalOpCount());
883 gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
884 merged_drawing_bounds.Union(drawing_b_bounds);
885 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
886 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(1));
887 EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(2));
888 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3));
889 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4));
890 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(5));
891 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(6));
892 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(7));
893 }
894
TEST_F(DisplayItemListTest,AppendVisualRectTwoBlocksTwoDrawingsInnerDrawingEscaped)895 TEST_F(DisplayItemListTest,
896 AppendVisualRectTwoBlocksTwoDrawingsInnerDrawingEscaped) {
897 auto list = base::MakeRefCounted<DisplayItemList>();
898
899 // Multiple nested blocks with drawings amidst: B1, Da, B2, Db (escapes), E2,
900 // E1.
901
902 gfx::Rect clip_bounds(5, 6, 7, 8);
903 {
904 list->StartPaint();
905 list->push<SaveOp>();
906 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
907 false);
908 list->EndPaintOfPairedBegin();
909 }
910
911 gfx::Rect drawing_a_bounds(5, 6, 1, 1);
912 {
913 list->StartPaint();
914 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_a_bounds), PaintFlags());
915 list->EndPaintOfUnpaired(drawing_a_bounds);
916 }
917
918 {
919 list->StartPaint();
920 list->push<SaveOp>();
921 list->push<ConcatOp>(SkMatrix::I());
922 list->EndPaintOfPairedBegin();
923 }
924
925 gfx::Rect drawing_b_bounds(1, 2, 3, 4);
926 {
927 list->StartPaint();
928 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_b_bounds), PaintFlags());
929 list->EndPaintOfUnpaired(drawing_b_bounds);
930 }
931
932 // End transform.
933 {
934 list->StartPaint();
935 list->push<RestoreOp>();
936 list->EndPaintOfPairedEnd();
937 }
938 // End clip.
939 {
940 list->StartPaint();
941 list->push<RestoreOp>();
942 list->EndPaintOfPairedEnd();
943 }
944
945 EXPECT_EQ(8u, list->TotalOpCount());
946 gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
947 merged_drawing_bounds.Union(drawing_b_bounds);
948 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
949 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(1));
950 EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(2));
951 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3));
952 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4));
953 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(5));
954 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(6));
955 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(7));
956 }
957
TEST_F(DisplayItemListTest,AppendVisualRectTwoBlocksTwoDrawingsOuterDrawingEscaped)958 TEST_F(DisplayItemListTest,
959 AppendVisualRectTwoBlocksTwoDrawingsOuterDrawingEscaped) {
960 auto list = base::MakeRefCounted<DisplayItemList>();
961
962 // Multiple nested blocks with drawings amidst: B1, Da (escapes), B2, Db, E2,
963 // E1.
964
965 gfx::Rect clip_bounds(5, 6, 7, 8);
966 {
967 list->StartPaint();
968 list->push<SaveOp>();
969 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
970 false);
971 list->EndPaintOfPairedBegin();
972 }
973
974 gfx::Rect drawing_a_bounds(1, 2, 3, 4);
975 {
976 list->StartPaint();
977 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_a_bounds), PaintFlags());
978 list->EndPaintOfUnpaired(drawing_a_bounds);
979 }
980
981 {
982 list->StartPaint();
983 list->push<SaveOp>();
984 list->push<ConcatOp>(SkMatrix::I());
985 list->EndPaintOfPairedBegin();
986 }
987
988 gfx::Rect drawing_b_bounds(7, 8, 1, 1);
989 {
990 list->StartPaint();
991 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_b_bounds), PaintFlags());
992 list->EndPaintOfUnpaired(drawing_b_bounds);
993 }
994
995 // End transform.
996 {
997 list->StartPaint();
998 list->push<RestoreOp>();
999 list->EndPaintOfPairedEnd();
1000 }
1001 // End clip.
1002 {
1003 list->StartPaint();
1004 list->push<RestoreOp>();
1005 list->EndPaintOfPairedEnd();
1006 }
1007
1008 EXPECT_EQ(8u, list->TotalOpCount());
1009 gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
1010 merged_drawing_bounds.Union(drawing_b_bounds);
1011 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
1012 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(1));
1013 EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(2));
1014 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3));
1015 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4));
1016 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(5));
1017 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(6));
1018 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(7));
1019 }
1020
TEST_F(DisplayItemListTest,AppendVisualRectTwoBlocksTwoDrawingsBothDrawingsEscaped)1021 TEST_F(DisplayItemListTest,
1022 AppendVisualRectTwoBlocksTwoDrawingsBothDrawingsEscaped) {
1023 auto list = base::MakeRefCounted<DisplayItemList>();
1024
1025 // Multiple nested blocks with drawings amidst:
1026 // B1, Da (escapes to the right), B2, Db (escapes to the left), E2, E1.
1027
1028 gfx::Rect clip_bounds(5, 6, 7, 8);
1029 {
1030 list->StartPaint();
1031 list->push<SaveOp>();
1032 list->push<ClipRectOp>(gfx::RectToSkRect(clip_bounds), SkClipOp::kIntersect,
1033 false);
1034 list->EndPaintOfPairedBegin();
1035 }
1036
1037 gfx::Rect drawing_a_bounds(13, 14, 1, 1);
1038 {
1039 list->StartPaint();
1040 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_a_bounds), PaintFlags());
1041 list->EndPaintOfUnpaired(drawing_a_bounds);
1042 }
1043
1044 {
1045 list->StartPaint();
1046 list->push<SaveOp>();
1047 list->push<ConcatOp>(SkMatrix::I());
1048 list->EndPaintOfPairedBegin();
1049 }
1050
1051 gfx::Rect drawing_b_bounds(1, 2, 3, 4);
1052 {
1053 list->StartPaint();
1054 list->push<DrawRectOp>(gfx::RectToSkRect(drawing_b_bounds), PaintFlags());
1055 list->EndPaintOfUnpaired(drawing_b_bounds);
1056 }
1057
1058 // End transform.
1059 {
1060 list->StartPaint();
1061 list->push<RestoreOp>();
1062 list->EndPaintOfPairedEnd();
1063 }
1064 // End clip.
1065 {
1066 list->StartPaint();
1067 list->push<RestoreOp>();
1068 list->EndPaintOfPairedEnd();
1069 }
1070
1071 EXPECT_EQ(8u, list->TotalOpCount());
1072 gfx::Rect merged_drawing_bounds = gfx::Rect(drawing_a_bounds);
1073 merged_drawing_bounds.Union(drawing_b_bounds);
1074 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(0));
1075 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(1));
1076 EXPECT_RECT_EQ(drawing_a_bounds, list->VisualRectForTesting(2));
1077 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(3));
1078 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(4));
1079 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(5));
1080 EXPECT_RECT_EQ(drawing_b_bounds, list->VisualRectForTesting(6));
1081 EXPECT_RECT_EQ(merged_drawing_bounds, list->VisualRectForTesting(7));
1082 }
1083
TEST_F(DisplayItemListTest,VisualRectForPairsEnclosingEmptyPainting)1084 TEST_F(DisplayItemListTest, VisualRectForPairsEnclosingEmptyPainting) {
1085 auto list = base::MakeRefCounted<DisplayItemList>();
1086
1087 // Some paired operations have drawing effect (e.g. some image filters),
1088 // so we should not ignore visual rect for empty painting.
1089
1090 gfx::Rect visual_rect(11, 22, 33, 44);
1091 {
1092 list->StartPaint();
1093 list->push<SaveOp>();
1094 list->push<TranslateOp>(10.f, 20.f);
1095 list->EndPaintOfPairedBegin();
1096 }
1097
1098 {
1099 list->StartPaint();
1100 list->EndPaintOfUnpaired(visual_rect);
1101 }
1102
1103 {
1104 list->StartPaint();
1105 list->push<RestoreOp>();
1106 list->EndPaintOfPairedEnd();
1107 }
1108
1109 EXPECT_EQ(3u, list->TotalOpCount());
1110 EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(0));
1111 EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(1));
1112 EXPECT_RECT_EQ(visual_rect, list->VisualRectForTesting(2));
1113 }
1114
TEST_F(DisplayItemListTest,TotalOpCount)1115 TEST_F(DisplayItemListTest, TotalOpCount) {
1116 auto list = base::MakeRefCounted<DisplayItemList>();
1117 auto sub_list = base::MakeRefCounted<DisplayItemList>();
1118
1119 sub_list->StartPaint();
1120 sub_list->push<SaveOp>();
1121 sub_list->push<TranslateOp>(10.f, 20.f);
1122 sub_list->push<DrawRectOp>(SkRect::MakeWH(10, 20), PaintFlags());
1123 sub_list->push<RestoreOp>();
1124 sub_list->EndPaintOfUnpaired(gfx::Rect());
1125 EXPECT_EQ(4u, sub_list->TotalOpCount());
1126
1127 list->StartPaint();
1128 list->push<SaveOp>();
1129 list->push<TranslateOp>(10.f, 20.f);
1130 list->push<DrawRecordOp>(sub_list->ReleaseAsRecord());
1131 list->push<RestoreOp>();
1132 list->EndPaintOfUnpaired(gfx::Rect());
1133 EXPECT_EQ(8u, list->TotalOpCount());
1134 }
1135
TEST_F(DisplayItemListTest,AreaOfDrawText)1136 TEST_F(DisplayItemListTest, AreaOfDrawText) {
1137 auto list = base::MakeRefCounted<DisplayItemList>();
1138 auto sub_list = base::MakeRefCounted<DisplayItemList>();
1139
1140 auto text_blob1 = SkTextBlob::MakeFromString("ABCD", SkFont());
1141 gfx::Size text_blob1_size(ceilf(text_blob1->bounds().width()),
1142 ceilf(text_blob1->bounds().height()));
1143 auto text_blob1_area = text_blob1_size.width() * text_blob1_size.height();
1144 auto text_blob2 = SkTextBlob::MakeFromString("EFG", SkFont());
1145 gfx::Size text_blob2_size(ceilf(text_blob2->bounds().width()),
1146 ceilf(text_blob2->bounds().height()));
1147 auto text_blob2_area = text_blob2_size.width() * text_blob2_size.height();
1148
1149 sub_list->StartPaint();
1150 sub_list->push<DrawTextBlobOp>(text_blob1, 0, 0, PaintFlags());
1151 sub_list->EndPaintOfUnpaired(gfx::Rect());
1152 auto record = sub_list->ReleaseAsRecord();
1153
1154 list->StartPaint();
1155 list->push<SaveOp>();
1156 list->push<TranslateOp>(100, 100);
1157 list->push<DrawRecordOp>(record);
1158 list->push<RestoreOp>();
1159 list->EndPaintOfUnpaired(gfx::Rect(gfx::Point(100, 100), text_blob1_size));
1160
1161 list->StartPaint();
1162 list->push<SaveOp>();
1163 list->push<TranslateOp>(100, 400);
1164 list->push<DrawRecordOp>(record);
1165 list->push<RestoreOp>();
1166 list->EndPaintOfUnpaired(gfx::Rect(gfx::Point(100, 400), text_blob1_size));
1167
1168 list->StartPaint();
1169 list->push<DrawTextBlobOp>(text_blob2, 10, 20, PaintFlags());
1170 list->EndPaintOfUnpaired(gfx::Rect(text_blob2_size));
1171
1172 list->StartPaint();
1173 list->push<DrawTextBlobOp>(text_blob2, 400, 100, PaintFlags());
1174 list->EndPaintOfUnpaired(gfx::Rect(gfx::Point(400, 100), text_blob2_size));
1175
1176 list->StartPaint();
1177 list->push<DrawRectOp>(SkRect::MakeXYWH(400, 100, 100, 100), PaintFlags());
1178 list->EndPaintOfUnpaired(gfx::Rect(400, 100, 100, 100));
1179
1180 list->Finalize();
1181 // This includes the DrawTextBlobOp in the first DrawRecordOp the the first
1182 // direct DrawTextBlobOp.
1183 EXPECT_EQ(static_cast<int>(text_blob1_area + text_blob2_area),
1184 static_cast<int>(list->AreaOfDrawText(gfx::Rect(200, 200))));
1185 // This includes all DrawTextBlobOps.
1186 EXPECT_EQ(static_cast<int>(text_blob1_area * 2 + text_blob2_area * 2),
1187 static_cast<int>(list->AreaOfDrawText(gfx::Rect(500, 500))));
1188 }
1189
1190 } // namespace cc
1191