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.
5 #include "cc/playback/display_item_list.h"
9 #include "cc/output/filter_operation.h"
10 #include "cc/output/filter_operations.h"
11 #include "cc/playback/clip_display_item.h"
12 #include "cc/playback/drawing_display_item.h"
13 #include "cc/playback/filter_display_item.h"
14 #include "cc/playback/transform_display_item.h"
15 #include "cc/test/skia_common.h"
16 #include "skia/ext/refptr.h"
17 #include "testing/gtest/include/gtest/gtest.h"
18 #include "third_party/skia/include/core/SkBitmap.h"
19 #include "third_party/skia/include/core/SkCanvas.h"
20 #include "third_party/skia/include/core/SkColor.h"
21 #include "third_party/skia/include/core/SkPictureRecorder.h"
22 #include "third_party/skia/include/effects/SkBitmapSource.h"
23 #include "third_party/skia/include/utils/SkPictureUtils.h"
24 #include "ui/gfx/geometry/rect_conversions.h"
25 #include "ui/gfx/skia_util.h"
29 TEST(DisplayItemListTest
, SingleDrawingItem
) {
30 gfx::Rect
layer_rect(100, 100);
31 SkPictureRecorder recorder
;
32 skia::RefPtr
<SkCanvas
> canvas
;
33 skia::RefPtr
<SkPicture
> picture
;
35 blue_paint
.setColor(SK_ColorBLUE
);
37 red_paint
.setColor(SK_ColorRED
);
38 unsigned char pixels
[4 * 100 * 100] = {0};
39 const bool use_cached_picture
= true;
40 scoped_refptr
<DisplayItemList
> list
=
41 DisplayItemList::Create(layer_rect
, use_cached_picture
);
43 gfx::PointF
offset(8.f
, 9.f
);
44 gfx::RectF
recording_rect(offset
, layer_rect
.size());
45 canvas
= skia::SharePtr(
46 recorder
.beginRecording(gfx::RectFToSkRect(recording_rect
)));
47 canvas
->translate(offset
.x(), offset
.y());
48 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
49 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
50 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
51 auto* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
52 item
->SetNew(picture
);
53 list
->ProcessAppendedItems();
54 list
->CreateAndCacheSkPicture();
55 DrawDisplayList(pixels
, layer_rect
, list
);
57 SkBitmap expected_bitmap
;
58 unsigned char expected_pixels
[4 * 100 * 100] = {0};
60 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
61 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
62 SkCanvas
expected_canvas(expected_bitmap
);
63 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
64 expected_canvas
.drawRectCoords(0.f
+ offset
.x(), 0.f
+ offset
.y(),
65 60.f
+ offset
.x(), 60.f
+ offset
.y(),
67 expected_canvas
.drawRectCoords(50.f
+ offset
.x(), 50.f
+ offset
.y(),
68 75.f
+ offset
.x(), 75.f
+ offset
.y(),
71 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
74 TEST(DisplayItemListTest
, ClipItem
) {
75 gfx::Rect
layer_rect(100, 100);
76 SkPictureRecorder recorder
;
77 skia::RefPtr
<SkCanvas
> canvas
;
78 skia::RefPtr
<SkPicture
> picture
;
80 blue_paint
.setColor(SK_ColorBLUE
);
82 red_paint
.setColor(SK_ColorRED
);
83 unsigned char pixels
[4 * 100 * 100] = {0};
84 const bool use_cached_picture
= true;
85 scoped_refptr
<DisplayItemList
> list
=
86 DisplayItemList::Create(layer_rect
, use_cached_picture
);
88 gfx::PointF
first_offset(8.f
, 9.f
);
89 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
90 canvas
= skia::SharePtr(
91 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
92 canvas
->translate(first_offset
.x(), first_offset
.y());
93 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
94 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
95 auto* item1
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
96 item1
->SetNew(picture
.Pass());
98 gfx::Rect
clip_rect(60, 60, 10, 10);
99 auto* item2
= list
->CreateAndAppendItem
<ClipDisplayItem
>();
100 item2
->SetNew(clip_rect
, std::vector
<SkRRect
>());
102 gfx::PointF
second_offset(2.f
, 3.f
);
103 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
104 canvas
= skia::SharePtr(
105 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
106 canvas
->translate(second_offset
.x(), second_offset
.y());
107 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
108 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
109 auto* item3
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
110 item3
->SetNew(picture
.Pass());
112 list
->CreateAndAppendItem
<EndClipDisplayItem
>();
113 list
->ProcessAppendedItems();
114 list
->CreateAndCacheSkPicture();
116 DrawDisplayList(pixels
, layer_rect
, list
);
118 SkBitmap expected_bitmap
;
119 unsigned char expected_pixels
[4 * 100 * 100] = {0};
121 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
122 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
123 SkCanvas
expected_canvas(expected_bitmap
);
124 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
125 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
126 60.f
+ first_offset
.x(),
127 60.f
+ first_offset
.y(), red_paint
);
128 expected_canvas
.clipRect(gfx::RectToSkRect(clip_rect
));
129 expected_canvas
.drawRectCoords(
130 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
131 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
133 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
136 TEST(DisplayItemListTest
, TransformItem
) {
137 gfx::Rect
layer_rect(100, 100);
138 SkPictureRecorder recorder
;
139 skia::RefPtr
<SkCanvas
> canvas
;
140 skia::RefPtr
<SkPicture
> picture
;
142 blue_paint
.setColor(SK_ColorBLUE
);
144 red_paint
.setColor(SK_ColorRED
);
145 unsigned char pixels
[4 * 100 * 100] = {0};
146 const bool use_cached_picture
= true;
147 scoped_refptr
<DisplayItemList
> list
=
148 DisplayItemList::Create(layer_rect
, use_cached_picture
);
150 gfx::PointF
first_offset(8.f
, 9.f
);
151 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
152 canvas
= skia::SharePtr(
153 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
154 canvas
->translate(first_offset
.x(), first_offset
.y());
155 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
156 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
157 auto* item1
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
158 item1
->SetNew(picture
);
160 gfx::Transform transform
;
161 transform
.Rotate(45.0);
162 auto* item2
= list
->CreateAndAppendItem
<TransformDisplayItem
>();
163 item2
->SetNew(transform
);
165 gfx::PointF
second_offset(2.f
, 3.f
);
166 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
167 canvas
= skia::SharePtr(
168 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
169 canvas
->translate(second_offset
.x(), second_offset
.y());
170 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
171 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
172 auto* item3
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
173 item3
->SetNew(picture
);
175 list
->CreateAndAppendItem
<EndTransformDisplayItem
>();
176 list
->ProcessAppendedItems();
177 list
->CreateAndCacheSkPicture();
179 DrawDisplayList(pixels
, layer_rect
, list
);
181 SkBitmap expected_bitmap
;
182 unsigned char expected_pixels
[4 * 100 * 100] = {0};
184 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
185 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
186 SkCanvas
expected_canvas(expected_bitmap
);
187 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
188 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
189 60.f
+ first_offset
.x(),
190 60.f
+ first_offset
.y(), red_paint
);
191 expected_canvas
.setMatrix(transform
.matrix());
192 expected_canvas
.drawRectCoords(
193 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
194 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
196 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
199 TEST(DisplayItemListTest
, FilterItem
) {
200 gfx::Rect
layer_rect(100, 100);
201 FilterOperations filters
;
202 unsigned char pixels
[4 * 100 * 100] = {0};
203 const bool use_cached_picture
= true;
204 scoped_refptr
<DisplayItemList
> list
=
205 DisplayItemList::Create(layer_rect
, use_cached_picture
);
207 SkBitmap source_bitmap
;
208 source_bitmap
.allocN32Pixels(50, 50);
209 SkCanvas
source_canvas(source_bitmap
);
210 source_canvas
.clear(SkColorSetRGB(128, 128, 128));
212 // For most SkImageFilters, the |dst| bounds computed by computeFastBounds are
213 // dependent on the provided |src| bounds. This means, for example, that
214 // translating |src| results in a corresponding translation of |dst|. But this
215 // is not the case for all SkImageFilters; for some of them (e.g.
216 // SkBitmapSource), the computation of |dst| in computeFastBounds doesn't
217 // involve |src| at all. Incorrectly assuming such a relationship (e.g. by
218 // translating |dst| after it is computed by computeFastBounds, rather than
219 // translating |src| before it provided to computedFastBounds) can cause
220 // incorrect clipping of filter output. To test for this, we include an
221 // SkBitmapSource filter in |filters|. Here, |src| is |filter_bounds|, defined
223 skia::RefPtr
<SkImageFilter
> image_filter
=
224 skia::AdoptRef(SkBitmapSource::Create(source_bitmap
));
225 filters
.Append(FilterOperation::CreateReferenceFilter(image_filter
));
226 filters
.Append(FilterOperation::CreateBrightnessFilter(0.5f
));
227 gfx::RectF
filter_bounds(10.f
, 10.f
, 50.f
, 50.f
);
228 auto* item
= list
->CreateAndAppendItem
<FilterDisplayItem
>();
229 item
->SetNew(filters
, filter_bounds
);
230 list
->CreateAndAppendItem
<EndFilterDisplayItem
>();
231 list
->ProcessAppendedItems();
232 list
->CreateAndCacheSkPicture();
234 DrawDisplayList(pixels
, layer_rect
, list
);
236 SkBitmap expected_bitmap
;
237 unsigned char expected_pixels
[4 * 100 * 100] = {0};
239 paint
.setColor(SkColorSetRGB(64, 64, 64));
241 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
242 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
243 SkCanvas
expected_canvas(expected_bitmap
);
244 expected_canvas
.drawRect(RectFToSkRect(filter_bounds
), paint
);
246 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
249 TEST(DisplayItemListTest
, CompactingItems
) {
250 gfx::Rect
layer_rect(100, 100);
251 SkPictureRecorder recorder
;
252 skia::RefPtr
<SkCanvas
> canvas
;
253 skia::RefPtr
<SkPicture
> picture
;
255 blue_paint
.setColor(SK_ColorBLUE
);
257 red_paint
.setColor(SK_ColorRED
);
258 unsigned char pixels
[4 * 100 * 100] = {0};
260 gfx::PointF
offset(8.f
, 9.f
);
261 gfx::RectF
recording_rect(offset
, layer_rect
.size());
263 bool use_cached_picture
= false;
264 scoped_refptr
<DisplayItemList
> list_without_caching
=
265 DisplayItemList::Create(layer_rect
, use_cached_picture
);
267 canvas
= skia::SharePtr(
268 recorder
.beginRecording(gfx::RectFToSkRect(recording_rect
)));
269 canvas
->translate(offset
.x(), offset
.y());
270 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
271 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
272 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
273 auto* item1
= list_without_caching
->CreateAndAppendItem
<DrawingDisplayItem
>();
274 item1
->SetNew(picture
);
275 list_without_caching
->ProcessAppendedItems();
276 DrawDisplayList(pixels
, layer_rect
, list_without_caching
);
278 unsigned char expected_pixels
[4 * 100 * 100] = {0};
279 use_cached_picture
= true;
280 scoped_refptr
<DisplayItemList
> list_with_caching
=
281 DisplayItemList::Create(layer_rect
, use_cached_picture
);
282 auto* item2
= list_with_caching
->CreateAndAppendItem
<DrawingDisplayItem
>();
283 item2
->SetNew(picture
);
284 list_with_caching
->ProcessAppendedItems();
285 list_with_caching
->CreateAndCacheSkPicture();
286 DrawDisplayList(expected_pixels
, layer_rect
, list_with_caching
);
288 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
291 TEST(DisplayItemListTest
, PictureMemoryUsage
) {
292 scoped_refptr
<DisplayItemList
> list
;
295 // Make an SkPicture whose size is known.
296 gfx::Rect
layer_rect(100, 100);
297 SkPictureRecorder recorder
;
299 blue_paint
.setColor(SK_ColorBLUE
);
300 SkCanvas
* canvas
= recorder
.beginRecording(gfx::RectFToSkRect(layer_rect
));
301 for (int i
= 0; i
< 100; i
++)
302 canvas
->drawPaint(blue_paint
);
303 skia::RefPtr
<SkPicture
> picture
=
304 skia::AdoptRef(recorder
.endRecordingAsPicture());
305 size_t picture_size
= SkPictureUtils::ApproximateBytesUsed(picture
.get());
306 ASSERT_GE(picture_size
, 100 * sizeof(SkPaint
));
307 ASSERT_LE(picture_size
, 200 * sizeof(SkPaint
));
309 // Using a cached picture, we should get about the right size.
310 list
= DisplayItemList::Create(layer_rect
, true);
311 auto* item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
312 item
->SetNew(picture
);
313 list
->ProcessAppendedItems();
314 list
->CreateAndCacheSkPicture();
315 memory_usage
= list
->PictureMemoryUsage();
316 EXPECT_GE(memory_usage
, picture_size
);
317 EXPECT_LE(memory_usage
, 2 * picture_size
);
319 // Using no cached picture, we should still get the right size.
320 list
= DisplayItemList::Create(layer_rect
, false);
321 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
322 item
->SetNew(picture
);
323 list
->ProcessAppendedItems();
324 memory_usage
= list
->PictureMemoryUsage();
325 EXPECT_GE(memory_usage
, picture_size
);
326 EXPECT_LE(memory_usage
, 2 * picture_size
);
328 // To avoid double counting, we expect zero size to be computed if both the
329 // picture and items are retained (currently this only happens due to certain
330 // categories being traced).
331 list
= new DisplayItemList(layer_rect
, true, true);
332 item
= list
->CreateAndAppendItem
<DrawingDisplayItem
>();
333 item
->SetNew(picture
);
334 list
->ProcessAppendedItems();
335 list
->CreateAndCacheSkPicture();
336 memory_usage
= list
->PictureMemoryUsage();
337 EXPECT_EQ(static_cast<size_t>(0), memory_usage
);