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", &params_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", &params_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", &params_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", &params_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", &params_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", &params_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", &params_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", &params_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", &params_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", &params_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", &params_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