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/resources/display_item_list.h"
9 #include "cc/output/filter_operation.h"
10 #include "cc/output/filter_operations.h"
11 #include "cc/resources/clip_display_item.h"
12 #include "cc/resources/drawing_display_item.h"
13 #include "cc/resources/filter_display_item.h"
14 #include "cc/resources/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 list
->AppendItem(DrawingDisplayItem::Create(picture
));
52 list
->CreateAndCacheSkPicture();
53 DrawDisplayList(pixels
, layer_rect
, list
);
55 SkBitmap expected_bitmap
;
56 unsigned char expected_pixels
[4 * 100 * 100] = {0};
58 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
59 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
60 SkCanvas
expected_canvas(expected_bitmap
);
61 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
62 expected_canvas
.drawRectCoords(0.f
+ offset
.x(), 0.f
+ offset
.y(),
63 60.f
+ offset
.x(), 60.f
+ offset
.y(),
65 expected_canvas
.drawRectCoords(50.f
+ offset
.x(), 50.f
+ offset
.y(),
66 75.f
+ offset
.x(), 75.f
+ offset
.y(),
69 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
72 TEST(DisplayItemListTest
, ClipItem
) {
73 gfx::Rect
layer_rect(100, 100);
74 SkPictureRecorder recorder
;
75 skia::RefPtr
<SkCanvas
> canvas
;
76 skia::RefPtr
<SkPicture
> picture
;
78 blue_paint
.setColor(SK_ColorBLUE
);
80 red_paint
.setColor(SK_ColorRED
);
81 unsigned char pixels
[4 * 100 * 100] = {0};
82 const bool use_cached_picture
= true;
83 scoped_refptr
<DisplayItemList
> list
=
84 DisplayItemList::Create(layer_rect
, use_cached_picture
);
86 gfx::PointF
first_offset(8.f
, 9.f
);
87 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
88 canvas
= skia::SharePtr(
89 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
90 canvas
->translate(first_offset
.x(), first_offset
.y());
91 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
92 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
93 list
->AppendItem(DrawingDisplayItem::Create(picture
));
95 gfx::Rect
clip_rect(60, 60, 10, 10);
96 list
->AppendItem(ClipDisplayItem::Create(clip_rect
, std::vector
<SkRRect
>()));
98 gfx::PointF
second_offset(2.f
, 3.f
);
99 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
100 canvas
= skia::SharePtr(
101 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
102 canvas
->translate(second_offset
.x(), second_offset
.y());
103 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
104 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
105 list
->AppendItem(DrawingDisplayItem::Create(picture
));
107 list
->AppendItem(EndClipDisplayItem::Create());
108 list
->CreateAndCacheSkPicture();
110 DrawDisplayList(pixels
, layer_rect
, list
);
112 SkBitmap expected_bitmap
;
113 unsigned char expected_pixels
[4 * 100 * 100] = {0};
115 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
116 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
117 SkCanvas
expected_canvas(expected_bitmap
);
118 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
119 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
120 60.f
+ first_offset
.x(),
121 60.f
+ first_offset
.y(), red_paint
);
122 expected_canvas
.clipRect(gfx::RectToSkRect(clip_rect
));
123 expected_canvas
.drawRectCoords(
124 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
125 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
127 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
130 TEST(DisplayItemListTest
, TransformItem
) {
131 gfx::Rect
layer_rect(100, 100);
132 SkPictureRecorder recorder
;
133 skia::RefPtr
<SkCanvas
> canvas
;
134 skia::RefPtr
<SkPicture
> picture
;
136 blue_paint
.setColor(SK_ColorBLUE
);
138 red_paint
.setColor(SK_ColorRED
);
139 unsigned char pixels
[4 * 100 * 100] = {0};
140 const bool use_cached_picture
= true;
141 scoped_refptr
<DisplayItemList
> list
=
142 DisplayItemList::Create(layer_rect
, use_cached_picture
);
144 gfx::PointF
first_offset(8.f
, 9.f
);
145 gfx::RectF
first_recording_rect(first_offset
, layer_rect
.size());
146 canvas
= skia::SharePtr(
147 recorder
.beginRecording(gfx::RectFToSkRect(first_recording_rect
)));
148 canvas
->translate(first_offset
.x(), first_offset
.y());
149 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
150 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
151 list
->AppendItem(DrawingDisplayItem::Create(picture
));
153 gfx::Transform transform
;
154 transform
.Rotate(45.0);
155 list
->AppendItem(TransformDisplayItem::Create(transform
));
157 gfx::PointF
second_offset(2.f
, 3.f
);
158 gfx::RectF
second_recording_rect(second_offset
, layer_rect
.size());
159 canvas
= skia::SharePtr(
160 recorder
.beginRecording(gfx::RectFToSkRect(second_recording_rect
)));
161 canvas
->translate(second_offset
.x(), second_offset
.y());
162 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
163 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
164 list
->AppendItem(DrawingDisplayItem::Create(picture
));
166 list
->AppendItem(EndTransformDisplayItem::Create());
167 list
->CreateAndCacheSkPicture();
169 DrawDisplayList(pixels
, layer_rect
, list
);
171 SkBitmap expected_bitmap
;
172 unsigned char expected_pixels
[4 * 100 * 100] = {0};
174 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
175 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
176 SkCanvas
expected_canvas(expected_bitmap
);
177 expected_canvas
.clipRect(gfx::RectToSkRect(layer_rect
));
178 expected_canvas
.drawRectCoords(0.f
+ first_offset
.x(), 0.f
+ first_offset
.y(),
179 60.f
+ first_offset
.x(),
180 60.f
+ first_offset
.y(), red_paint
);
181 expected_canvas
.setMatrix(transform
.matrix());
182 expected_canvas
.drawRectCoords(
183 50.f
+ second_offset
.x(), 50.f
+ second_offset
.y(),
184 75.f
+ second_offset
.x(), 75.f
+ second_offset
.y(), blue_paint
);
186 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
189 TEST(DisplayItemListTest
, FilterItem
) {
190 gfx::Rect
layer_rect(100, 100);
191 FilterOperations filters
;
192 unsigned char pixels
[4 * 100 * 100] = {0};
193 const bool use_cached_picture
= true;
194 scoped_refptr
<DisplayItemList
> list
=
195 DisplayItemList::Create(layer_rect
, use_cached_picture
);
197 SkBitmap source_bitmap
;
198 source_bitmap
.allocN32Pixels(50, 50);
199 SkCanvas
source_canvas(source_bitmap
);
200 source_canvas
.clear(SkColorSetRGB(128, 128, 128));
202 // For most SkImageFilters, the |dst| bounds computed by computeFastBounds are
203 // dependent on the provided |src| bounds. This means, for example, that
204 // translating |src| results in a corresponding translation of |dst|. But this
205 // is not the case for all SkImageFilters; for some of them (e.g.
206 // SkBitmapSource), the computation of |dst| in computeFastBounds doesn't
207 // involve |src| at all. Incorrectly assuming such a relationship (e.g. by
208 // translating |dst| after it is computed by computeFastBounds, rather than
209 // translating |src| before it provided to computedFastBounds) can cause
210 // incorrect clipping of filter output. To test for this, we include an
211 // SkBitmapSource filter in |filters|. Here, |src| is |filter_bounds|, defined
213 skia::RefPtr
<SkImageFilter
> image_filter
=
214 skia::AdoptRef(SkBitmapSource::Create(source_bitmap
));
215 filters
.Append(FilterOperation::CreateReferenceFilter(image_filter
));
216 filters
.Append(FilterOperation::CreateBrightnessFilter(0.5f
));
217 gfx::RectF
filter_bounds(10.f
, 10.f
, 50.f
, 50.f
);
218 list
->AppendItem(FilterDisplayItem::Create(filters
, filter_bounds
));
219 list
->AppendItem(EndFilterDisplayItem::Create());
220 list
->CreateAndCacheSkPicture();
222 DrawDisplayList(pixels
, layer_rect
, list
);
224 SkBitmap expected_bitmap
;
225 unsigned char expected_pixels
[4 * 100 * 100] = {0};
227 paint
.setColor(SkColorSetRGB(64, 64, 64));
229 SkImageInfo::MakeN32Premul(layer_rect
.width(), layer_rect
.height());
230 expected_bitmap
.installPixels(info
, expected_pixels
, info
.minRowBytes());
231 SkCanvas
expected_canvas(expected_bitmap
);
232 expected_canvas
.drawRect(RectFToSkRect(filter_bounds
), paint
);
234 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
237 TEST(DisplayItemListTest
, CompactingItems
) {
238 gfx::Rect
layer_rect(100, 100);
239 SkPictureRecorder recorder
;
240 skia::RefPtr
<SkCanvas
> canvas
;
241 skia::RefPtr
<SkPicture
> picture
;
243 blue_paint
.setColor(SK_ColorBLUE
);
245 red_paint
.setColor(SK_ColorRED
);
246 unsigned char pixels
[4 * 100 * 100] = {0};
248 gfx::PointF
offset(8.f
, 9.f
);
249 gfx::RectF
recording_rect(offset
, layer_rect
.size());
251 bool use_cached_picture
= false;
252 scoped_refptr
<DisplayItemList
> list_without_caching
=
253 DisplayItemList::Create(layer_rect
, use_cached_picture
);
255 canvas
= skia::SharePtr(
256 recorder
.beginRecording(gfx::RectFToSkRect(recording_rect
)));
257 canvas
->translate(offset
.x(), offset
.y());
258 canvas
->drawRectCoords(0.f
, 0.f
, 60.f
, 60.f
, red_paint
);
259 canvas
->drawRectCoords(50.f
, 50.f
, 75.f
, 75.f
, blue_paint
);
260 picture
= skia::AdoptRef(recorder
.endRecordingAsPicture());
261 list_without_caching
->AppendItem(DrawingDisplayItem::Create(picture
));
262 DrawDisplayList(pixels
, layer_rect
, list_without_caching
);
264 unsigned char expected_pixels
[4 * 100 * 100] = {0};
265 use_cached_picture
= true;
266 scoped_refptr
<DisplayItemList
> list_with_caching
=
267 DisplayItemList::Create(layer_rect
, use_cached_picture
);
268 list_with_caching
->AppendItem(DrawingDisplayItem::Create(picture
));
269 list_with_caching
->CreateAndCacheSkPicture();
270 DrawDisplayList(expected_pixels
, layer_rect
, list_with_caching
);
272 EXPECT_EQ(0, memcmp(pixels
, expected_pixels
, 4 * 100 * 100));
275 TEST(DisplayItemListTest
, PictureMemoryUsage
) {
276 scoped_refptr
<DisplayItemList
> list
;
279 // Make an SkPicture whose size is known.
280 gfx::Rect
layer_rect(100, 100);
281 SkPictureRecorder recorder
;
283 blue_paint
.setColor(SK_ColorBLUE
);
284 SkCanvas
* canvas
= recorder
.beginRecording(gfx::RectFToSkRect(layer_rect
));
285 for (int i
= 0; i
< 100; i
++)
286 canvas
->drawPaint(blue_paint
);
287 skia::RefPtr
<SkPicture
> picture
=
288 skia::AdoptRef(recorder
.endRecordingAsPicture());
289 size_t picture_size
= SkPictureUtils::ApproximateBytesUsed(picture
.get());
290 ASSERT_GE(picture_size
, 100 * sizeof(SkPaint
));
291 ASSERT_LE(picture_size
, 200 * sizeof(SkPaint
));
293 // Using a cached picture, we should get about the right size.
294 list
= DisplayItemList::Create(layer_rect
, true);
295 list
->AppendItem(DrawingDisplayItem::Create(picture
));
296 list
->CreateAndCacheSkPicture();
297 memory_usage
= list
->PictureMemoryUsage();
298 EXPECT_GE(memory_usage
, picture_size
);
299 EXPECT_LE(memory_usage
, 2 * picture_size
);
301 // Using no cached picture, we should still get the right size.
302 list
= DisplayItemList::Create(layer_rect
, false);
303 list
->AppendItem(DrawingDisplayItem::Create(picture
));
304 memory_usage
= list
->PictureMemoryUsage();
305 EXPECT_GE(memory_usage
, picture_size
);
306 EXPECT_LE(memory_usage
, 2 * picture_size
);
308 // To avoid double counting, we expect zero size to be computed if both the
309 // picture and items are retained (currently this only happens due to certain
310 // categories being traced).
311 list
= new DisplayItemList(layer_rect
, true, true);
312 list
->AppendItem(DrawingDisplayItem::Create(picture
));
313 list
->CreateAndCacheSkPicture();
314 memory_usage
= list
->PictureMemoryUsage();
315 EXPECT_EQ(static_cast<size_t>(0), memory_usage
);