1 // Copyright 2013 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 "build/build_config.h"
6 #include "cc/layers/content_layer_client.h"
7 #include "cc/layers/picture_image_layer.h"
8 #include "cc/layers/picture_layer.h"
9 #include "cc/layers/solid_color_layer.h"
10 #include "cc/playback/display_item_list_settings.h"
11 #include "cc/playback/drawing_display_item.h"
12 #include "cc/test/layer_tree_pixel_resource_test.h"
13 #include "cc/test/pixel_comparator.h"
14 #include "third_party/skia/include/core/SkImage.h"
15 #include "third_party/skia/include/core/SkPictureRecorder.h"
16 #include "third_party/skia/include/core/SkSurface.h"
18 #if !defined(OS_ANDROID)
23 typedef ParameterizedPixelResourceTest LayerTreeHostMasksPixelTest
;
25 INSTANTIATE_PIXEL_RESOURCE_TEST_CASE_P(LayerTreeHostMasksPixelTest
);
27 class MaskContentLayerClient
: public ContentLayerClient
{
29 explicit MaskContentLayerClient(const gfx::Size
& bounds
) : bounds_(bounds
) {}
30 ~MaskContentLayerClient() override
{}
32 bool FillsBoundsCompletely() const override
{ return false; }
33 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
35 // TODO(pdr): Remove PaintContents as all calls should go through
36 // PaintContentsToDisplayList.
37 void PaintContents(SkCanvas
* canvas
,
38 const gfx::Rect
& rect
,
39 PaintingControlSetting picture_control
) override
{
40 scoped_refptr
<DisplayItemList
> contents
=
41 PaintContentsToDisplayList(rect
, picture_control
);
42 contents
->Raster(canvas
, nullptr, rect
, 1.0f
);
45 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
46 const gfx::Rect
& clip
,
47 PaintingControlSetting picture_control
) override
{
48 SkPictureRecorder recorder
;
49 skia::RefPtr
<SkCanvas
> canvas
= skia::SharePtr(
50 recorder
.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_
))));
53 paint
.setStyle(SkPaint::kStroke_Style
);
54 paint
.setStrokeWidth(SkIntToScalar(2));
55 paint
.setColor(SK_ColorWHITE
);
57 canvas
->clear(SK_ColorTRANSPARENT
);
58 gfx::Rect
inset_rect(bounds_
);
59 while (!inset_rect
.IsEmpty()) {
60 inset_rect
.Inset(3, 3, 2, 2);
62 SkRect::MakeXYWH(inset_rect
.x(), inset_rect
.y(),
63 inset_rect
.width(), inset_rect
.height()),
65 inset_rect
.Inset(3, 3, 2, 2);
68 scoped_refptr
<DisplayItemList
> display_list
=
69 DisplayItemList::Create(clip
, DisplayItemListSettings());
70 auto* item
= display_list
->CreateAndAppendItem
<DrawingDisplayItem
>();
72 skia::RefPtr
<SkPicture
> picture
=
73 skia::AdoptRef(recorder
.endRecordingAsPicture());
74 item
->SetNew(picture
.Pass());
76 display_list
->Finalize();
84 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfLayer
) {
85 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
86 gfx::Rect(100, 100), SK_ColorWHITE
);
88 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
89 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
90 background
->AddChild(green
);
92 gfx::Size
mask_bounds(50, 50);
93 MaskContentLayerClient
client(mask_bounds
);
94 scoped_refptr
<PictureLayer
> mask
=
95 PictureLayer::Create(layer_settings(), &client
);
96 mask
->SetBounds(mask_bounds
);
97 mask
->SetIsDrawable(true);
98 mask
->SetIsMask(true);
99 green
->SetMaskLayer(mask
.get());
101 RunPixelResourceTest(background
,
102 base::FilePath(FILE_PATH_LITERAL("mask_of_layer.png")));
105 TEST_P(LayerTreeHostMasksPixelTest
, ImageMaskOfLayer
) {
106 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
107 gfx::Rect(100, 100), SK_ColorWHITE
);
109 gfx::Size
mask_bounds(50, 50);
111 scoped_refptr
<PictureImageLayer
> mask
=
112 PictureImageLayer::Create(layer_settings());
113 mask
->SetIsDrawable(true);
114 mask
->SetIsMask(true);
115 mask
->SetBounds(mask_bounds
);
117 skia::RefPtr
<SkSurface
> surface
=
118 skia::AdoptRef(SkSurface::NewRasterN32Premul(200, 200));
119 SkCanvas
* canvas
= surface
->getCanvas();
120 canvas
->scale(SkIntToScalar(4), SkIntToScalar(4));
121 MaskContentLayerClient
client(mask_bounds
);
122 client
.PaintContents(canvas
, gfx::Rect(mask_bounds
),
123 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL
);
124 skia::RefPtr
<const SkImage
> image
=
125 skia::AdoptRef(surface
->newImageSnapshot());
126 mask
->SetImage(image
.Pass());
128 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
129 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
130 green
->SetMaskLayer(mask
.get());
131 background
->AddChild(green
);
133 RunPixelResourceTest(
134 background
, base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png")));
137 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfClippedLayer
) {
138 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
139 gfx::Rect(100, 100), SK_ColorWHITE
);
141 // Clip to the top half of the green layer.
142 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
143 clip
->SetPosition(gfx::Point(0, 0));
144 clip
->SetBounds(gfx::Size(100, 50));
145 clip
->SetMasksToBounds(true);
146 background
->AddChild(clip
);
148 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
149 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
150 clip
->AddChild(green
);
152 gfx::Size
mask_bounds(50, 50);
153 MaskContentLayerClient
client(mask_bounds
);
154 scoped_refptr
<PictureLayer
> mask
=
155 PictureLayer::Create(layer_settings(), &client
);
156 mask
->SetBounds(mask_bounds
);
157 mask
->SetIsDrawable(true);
158 mask
->SetIsMask(true);
159 green
->SetMaskLayer(mask
.get());
161 RunPixelResourceTest(
163 base::FilePath(FILE_PATH_LITERAL("mask_of_clipped_layer.png")));
166 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplica
) {
167 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
168 gfx::Rect(100, 100), SK_ColorWHITE
);
170 gfx::Size
mask_bounds(50, 50);
171 MaskContentLayerClient
client(mask_bounds
);
172 scoped_refptr
<PictureLayer
> mask
=
173 PictureLayer::Create(layer_settings(), &client
);
174 mask
->SetBounds(mask_bounds
);
175 mask
->SetIsDrawable(true);
176 mask
->SetIsMask(true);
178 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
179 gfx::Rect(0, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
180 background
->AddChild(green
);
181 green
->SetMaskLayer(mask
.get());
183 gfx::Transform replica_transform
;
184 replica_transform
.Rotate(-90.0);
186 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
187 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
188 replica
->SetPosition(gfx::Point(50, 50));
189 replica
->SetTransform(replica_transform
);
190 green
->SetReplicaLayer(replica
.get());
192 RunPixelResourceTest(
193 background
, base::FilePath(FILE_PATH_LITERAL("mask_with_replica.png")));
196 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplicaOfClippedLayer
) {
197 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
198 gfx::Rect(100, 100), SK_ColorWHITE
);
200 gfx::Size
mask_bounds(50, 50);
201 MaskContentLayerClient
client(mask_bounds
);
202 scoped_refptr
<PictureLayer
> mask
=
203 PictureLayer::Create(layer_settings(), &client
);
204 mask
->SetBounds(mask_bounds
);
205 mask
->SetIsDrawable(true);
206 mask
->SetIsMask(true);
208 // Clip to the bottom half of the green layer, and the left half of the
210 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
211 clip
->SetPosition(gfx::Point(0, 25));
212 clip
->SetBounds(gfx::Size(75, 75));
213 clip
->SetMasksToBounds(true);
214 background
->AddChild(clip
);
216 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
217 gfx::Rect(0, -25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
218 clip
->AddChild(green
);
219 green
->SetMaskLayer(mask
.get());
221 gfx::Transform replica_transform
;
222 replica_transform
.Rotate(-90.0);
224 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
225 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
226 replica
->SetPosition(gfx::Point(50, 50));
227 replica
->SetTransform(replica_transform
);
228 green
->SetReplicaLayer(replica
.get());
230 RunPixelResourceTest(background
,
231 base::FilePath(FILE_PATH_LITERAL(
232 "mask_with_replica_of_clipped_layer.png")));
235 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplica
) {
236 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
237 gfx::Rect(100, 100), SK_ColorWHITE
);
239 gfx::Size
mask_bounds(50, 50);
240 MaskContentLayerClient
client(mask_bounds
);
241 scoped_refptr
<PictureLayer
> mask
=
242 PictureLayer::Create(layer_settings(), &client
);
243 mask
->SetBounds(mask_bounds
);
244 mask
->SetIsDrawable(true);
245 mask
->SetIsMask(true);
247 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
248 gfx::Rect(25, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
249 background
->AddChild(green
);
251 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
252 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
253 green
->AddChild(orange
);
255 gfx::Transform replica_transform
;
256 replica_transform
.Rotate(180.0);
257 replica_transform
.Translate(50.0, 0.0);
259 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
260 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
261 replica
->SetPosition(gfx::Point());
262 replica
->SetTransform(replica_transform
);
263 replica
->SetMaskLayer(mask
.get());
264 green
->SetReplicaLayer(replica
.get());
266 RunPixelResourceTest(
267 background
, base::FilePath(FILE_PATH_LITERAL("mask_of_replica.png")));
270 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplicaOfClippedLayer
) {
271 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
272 gfx::Rect(100, 100), SK_ColorWHITE
);
274 gfx::Size
mask_bounds(50, 50);
275 MaskContentLayerClient
client(mask_bounds
);
276 scoped_refptr
<PictureLayer
> mask
=
277 PictureLayer::Create(layer_settings(), &client
);
278 mask
->SetBounds(mask_bounds
);
279 mask
->SetIsDrawable(true);
280 mask
->SetIsMask(true);
282 // Clip to the bottom 3/4 of the green layer, and the top 3/4 of the replica.
283 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
284 clip
->SetPosition(gfx::Point(0, 12));
285 clip
->SetBounds(gfx::Size(100, 75));
286 clip
->SetMasksToBounds(true);
287 background
->AddChild(clip
);
289 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
290 gfx::Rect(25, -12, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
291 clip
->AddChild(green
);
293 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
294 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
295 green
->AddChild(orange
);
297 gfx::Transform replica_transform
;
298 replica_transform
.Rotate(180.0);
299 replica_transform
.Translate(50.0, 0.0);
301 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
302 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
303 replica
->SetPosition(gfx::Point());
304 replica
->SetTransform(replica_transform
);
305 replica
->SetMaskLayer(mask
.get());
306 green
->SetReplicaLayer(replica
.get());
308 RunPixelResourceTest(background
,
309 base::FilePath(FILE_PATH_LITERAL(
310 "mask_of_replica_of_clipped_layer.png")));
313 class CheckerContentLayerClient
: public ContentLayerClient
{
315 CheckerContentLayerClient(const gfx::Size
& bounds
,
318 : bounds_(bounds
), color_(color
), vertical_(vertical
) {}
319 ~CheckerContentLayerClient() override
{}
320 bool FillsBoundsCompletely() const override
{ return false; }
321 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
322 // TODO(pdr): Remove PaintContents as all calls should go through
323 // PaintContentsToDisplayList.
324 void PaintContents(SkCanvas
* canvas
,
325 const gfx::Rect
& rect
,
326 PaintingControlSetting picture_control
) override
{
327 scoped_refptr
<DisplayItemList
> contents
=
328 PaintContentsToDisplayList(rect
, picture_control
);
329 contents
->Raster(canvas
, nullptr, rect
, 1.0f
);
331 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
332 const gfx::Rect
& clip
,
333 PaintingControlSetting picture_control
) override
{
334 SkPictureRecorder recorder
;
335 skia::RefPtr
<SkCanvas
> canvas
= skia::SharePtr(
336 recorder
.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_
))));
339 paint
.setStyle(SkPaint::kStroke_Style
);
340 paint
.setStrokeWidth(SkIntToScalar(4));
341 paint
.setColor(color_
);
342 canvas
->clear(SK_ColorTRANSPARENT
);
344 for (int i
= 4; i
< bounds_
.width(); i
+= 16) {
345 canvas
->drawLine(i
, 0, i
, bounds_
.height(), paint
);
348 for (int i
= 4; i
< bounds_
.height(); i
+= 16) {
349 canvas
->drawLine(0, i
, bounds_
.width(), i
, paint
);
353 scoped_refptr
<DisplayItemList
> display_list
=
354 DisplayItemList::Create(clip
, DisplayItemListSettings());
355 auto* item
= display_list
->CreateAndAppendItem
<DrawingDisplayItem
>();
357 skia::RefPtr
<SkPicture
> picture
=
358 skia::AdoptRef(recorder
.endRecordingAsPicture());
359 item
->SetNew(picture
.Pass());
361 display_list
->Finalize();
371 class CircleContentLayerClient
: public ContentLayerClient
{
373 explicit CircleContentLayerClient(const gfx::Size
& bounds
)
375 ~CircleContentLayerClient() override
{}
376 bool FillsBoundsCompletely() const override
{ return false; }
377 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
378 // TODO(pdr): Remove PaintContents as all calls should go through
379 // PaintContentsToDisplayList.
380 void PaintContents(SkCanvas
* canvas
,
381 const gfx::Rect
& rect
,
382 PaintingControlSetting picture_control
) override
{
383 scoped_refptr
<DisplayItemList
> contents
=
384 PaintContentsToDisplayList(rect
, picture_control
);
385 contents
->Raster(canvas
, nullptr, rect
, 1.0f
);
387 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
388 const gfx::Rect
& clip
,
389 PaintingControlSetting picture_control
) override
{
390 SkPictureRecorder recorder
;
391 skia::RefPtr
<SkCanvas
> canvas
= skia::SharePtr(
392 recorder
.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_
))));
395 paint
.setStyle(SkPaint::kFill_Style
);
396 paint
.setColor(SK_ColorWHITE
);
397 canvas
->clear(SK_ColorTRANSPARENT
);
398 canvas
->drawCircle(bounds_
.width() / 2,
399 bounds_
.height() / 2,
403 scoped_refptr
<DisplayItemList
> display_list
=
404 DisplayItemList::Create(clip
, DisplayItemListSettings());
405 auto* item
= display_list
->CreateAndAppendItem
<DrawingDisplayItem
>();
406 skia::RefPtr
<SkPicture
> picture
=
407 skia::AdoptRef(recorder
.endRecordingAsPicture());
408 item
->SetNew(picture
.Pass());
410 display_list
->Finalize();
418 using LayerTreeHostMasksForBackgroundFiltersPixelTest
=
419 ParameterizedPixelResourceTest
;
421 INSTANTIATE_TEST_CASE_P(PixelResourceTest
,
422 LayerTreeHostMasksForBackgroundFiltersPixelTest
,
423 ::testing::Values(SOFTWARE
,
424 GL_GPU_RASTER_2D_DRAW
,
425 GL_ONE_COPY_2D_STAGING_2D_DRAW
,
426 GL_ONE_COPY_RECT_STAGING_2D_DRAW
,
427 GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW
,
428 GL_ZERO_COPY_2D_DRAW
,
429 GL_ZERO_COPY_RECT_DRAW
,
430 GL_ZERO_COPY_EXTERNAL_DRAW
));
432 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
433 MaskOfLayerWithBackgroundFilter
) {
434 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
435 gfx::Rect(100, 100), SK_ColorWHITE
);
437 gfx::Size
picture_bounds(100, 100);
438 CheckerContentLayerClient
picture_client(picture_bounds
, SK_ColorGREEN
, true);
439 scoped_refptr
<PictureLayer
> picture
=
440 PictureLayer::Create(layer_settings(), &picture_client
);
441 picture
->SetBounds(picture_bounds
);
442 picture
->SetIsDrawable(true);
444 scoped_refptr
<SolidColorLayer
> blur
= CreateSolidColorLayer(
445 gfx::Rect(100, 100), SK_ColorTRANSPARENT
);
446 background
->AddChild(picture
);
447 background
->AddChild(blur
);
449 FilterOperations filters
;
450 filters
.Append(FilterOperation::CreateGrayscaleFilter(1.0));
451 blur
->SetBackgroundFilters(filters
);
453 gfx::Size
mask_bounds(100, 100);
454 CircleContentLayerClient
mask_client(mask_bounds
);
455 scoped_refptr
<PictureLayer
> mask
=
456 PictureLayer::Create(layer_settings(), &mask_client
);
457 mask
->SetBounds(mask_bounds
);
458 mask
->SetIsDrawable(true);
459 mask
->SetIsMask(true);
460 blur
->SetMaskLayer(mask
.get());
462 float percentage_pixels_large_error
= 2.5f
; // 2.5%, ~250px / (100*100)
463 float percentage_pixels_small_error
= 0.0f
;
464 float average_error_allowed_in_bad_pixels
= 100.0f
;
465 int large_error_allowed
= 256;
466 int small_error_allowed
= 0;
467 pixel_comparator_
.reset(new FuzzyPixelComparator(
468 true, // discard_alpha
469 percentage_pixels_large_error
,
470 percentage_pixels_small_error
,
471 average_error_allowed_in_bad_pixels
,
473 small_error_allowed
));
475 RunPixelResourceTest(background
,
477 FILE_PATH_LITERAL("mask_of_background_filter.png")));
480 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
481 MaskOfLayerWithBlend
) {
482 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
483 gfx::Rect(128, 128), SK_ColorWHITE
);
485 gfx::Size
picture_bounds(128, 128);
486 CheckerContentLayerClient
picture_client_vertical(
487 picture_bounds
, SK_ColorGREEN
, true);
488 scoped_refptr
<PictureLayer
> picture_vertical
=
489 PictureLayer::Create(layer_settings(), &picture_client_vertical
);
490 picture_vertical
->SetBounds(picture_bounds
);
491 picture_vertical
->SetIsDrawable(true);
493 CheckerContentLayerClient
picture_client_horizontal(
494 picture_bounds
, SK_ColorMAGENTA
, false);
495 scoped_refptr
<PictureLayer
> picture_horizontal
=
496 PictureLayer::Create(layer_settings(), &picture_client_horizontal
);
497 picture_horizontal
->SetBounds(picture_bounds
);
498 picture_horizontal
->SetIsDrawable(true);
499 picture_horizontal
->SetContentsOpaque(false);
500 picture_horizontal
->SetBlendMode(SkXfermode::kMultiply_Mode
);
502 background
->AddChild(picture_vertical
);
503 background
->AddChild(picture_horizontal
);
505 gfx::Size
mask_bounds(128, 128);
506 CircleContentLayerClient
mask_client(mask_bounds
);
507 scoped_refptr
<PictureLayer
> mask
=
508 PictureLayer::Create(layer_settings(), &mask_client
);
509 mask
->SetBounds(mask_bounds
);
510 mask
->SetIsDrawable(true);
511 mask
->SetIsMask(true);
512 picture_horizontal
->SetMaskLayer(mask
.get());
514 float percentage_pixels_large_error
= 0.04f
; // 0.04%, ~6px / (128*128)
515 float percentage_pixels_small_error
= 0.0f
;
516 float average_error_allowed_in_bad_pixels
= 256.0f
;
517 int large_error_allowed
= 256;
518 int small_error_allowed
= 0;
519 pixel_comparator_
.reset(new FuzzyPixelComparator(
520 true, // discard_alpha
521 percentage_pixels_large_error
,
522 percentage_pixels_small_error
,
523 average_error_allowed_in_bad_pixels
,
525 small_error_allowed
));
527 RunPixelResourceTest(background
,
529 FILE_PATH_LITERAL("mask_of_layer_with_blend.png")));
535 #endif // !defined(OS_ANDROID)