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/test/layer_tree_pixel_resource_test.h"
11 #include "cc/test/pixel_comparator.h"
13 #if !defined(OS_ANDROID)
18 typedef ParameterizedPixelResourceTest LayerTreeHostMasksPixelTest
;
20 INSTANTIATE_PIXEL_RESOURCE_TEST_CASE_P(LayerTreeHostMasksPixelTest
);
22 class MaskContentLayerClient
: public ContentLayerClient
{
24 explicit MaskContentLayerClient(const gfx::Size
& bounds
) : bounds_(bounds
) {}
25 ~MaskContentLayerClient() override
{}
27 bool FillsBoundsCompletely() const override
{ return false; }
28 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
30 void PaintContents(SkCanvas
* canvas
,
31 const gfx::Rect
& rect
,
32 PaintingControlSetting picture_control
) override
{
34 paint
.setStyle(SkPaint::kStroke_Style
);
35 paint
.setStrokeWidth(SkIntToScalar(2));
36 paint
.setColor(SK_ColorWHITE
);
38 canvas
->clear(SK_ColorTRANSPARENT
);
39 gfx::Rect
inset_rect(bounds_
);
40 while (!inset_rect
.IsEmpty()) {
41 inset_rect
.Inset(3, 3, 2, 2);
43 SkRect::MakeXYWH(inset_rect
.x(), inset_rect
.y(),
44 inset_rect
.width(), inset_rect
.height()),
46 inset_rect
.Inset(3, 3, 2, 2);
50 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
51 const gfx::Rect
& clip
,
52 PaintingControlSetting picture_control
) override
{
61 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfLayer
) {
62 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
63 gfx::Rect(100, 100), SK_ColorWHITE
);
65 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
66 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
67 background
->AddChild(green
);
69 gfx::Size
mask_bounds(50, 50);
70 MaskContentLayerClient
client(mask_bounds
);
71 scoped_refptr
<PictureLayer
> mask
=
72 PictureLayer::Create(layer_settings(), &client
);
73 mask
->SetBounds(mask_bounds
);
74 mask
->SetIsDrawable(true);
75 mask
->SetIsMask(true);
76 green
->SetMaskLayer(mask
.get());
78 RunPixelResourceTest(background
,
79 base::FilePath(FILE_PATH_LITERAL("mask_of_layer.png")));
82 TEST_P(LayerTreeHostMasksPixelTest
, ImageMaskOfLayer
) {
83 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
84 gfx::Rect(100, 100), SK_ColorWHITE
);
86 gfx::Size
mask_bounds(50, 50);
88 scoped_refptr
<PictureImageLayer
> mask
=
89 PictureImageLayer::Create(layer_settings());
90 mask
->SetIsDrawable(true);
91 mask
->SetIsMask(true);
92 mask
->SetBounds(mask_bounds
);
95 bitmap
.allocN32Pixels(200, 200);
96 SkCanvas
canvas(bitmap
);
97 canvas
.scale(SkIntToScalar(4), SkIntToScalar(4));
98 MaskContentLayerClient
client(mask_bounds
);
99 client
.PaintContents(&canvas
, gfx::Rect(mask_bounds
),
100 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL
);
101 mask
->SetBitmap(bitmap
);
103 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
104 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
105 green
->SetMaskLayer(mask
.get());
106 background
->AddChild(green
);
108 RunPixelResourceTest(
109 background
, base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png")));
112 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfClippedLayer
) {
113 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
114 gfx::Rect(100, 100), SK_ColorWHITE
);
116 // Clip to the top half of the green layer.
117 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
118 clip
->SetPosition(gfx::Point(0, 0));
119 clip
->SetBounds(gfx::Size(100, 50));
120 clip
->SetMasksToBounds(true);
121 background
->AddChild(clip
);
123 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
124 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
125 clip
->AddChild(green
);
127 gfx::Size
mask_bounds(50, 50);
128 MaskContentLayerClient
client(mask_bounds
);
129 scoped_refptr
<PictureLayer
> mask
=
130 PictureLayer::Create(layer_settings(), &client
);
131 mask
->SetBounds(mask_bounds
);
132 mask
->SetIsDrawable(true);
133 mask
->SetIsMask(true);
134 green
->SetMaskLayer(mask
.get());
136 RunPixelResourceTest(
138 base::FilePath(FILE_PATH_LITERAL("mask_of_clipped_layer.png")));
141 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplica
) {
142 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
143 gfx::Rect(100, 100), SK_ColorWHITE
);
145 gfx::Size
mask_bounds(50, 50);
146 MaskContentLayerClient
client(mask_bounds
);
147 scoped_refptr
<PictureLayer
> mask
=
148 PictureLayer::Create(layer_settings(), &client
);
149 mask
->SetBounds(mask_bounds
);
150 mask
->SetIsDrawable(true);
151 mask
->SetIsMask(true);
153 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
154 gfx::Rect(0, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
155 background
->AddChild(green
);
156 green
->SetMaskLayer(mask
.get());
158 gfx::Transform replica_transform
;
159 replica_transform
.Rotate(-90.0);
161 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
162 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
163 replica
->SetPosition(gfx::Point(50, 50));
164 replica
->SetTransform(replica_transform
);
165 green
->SetReplicaLayer(replica
.get());
167 RunPixelResourceTest(
168 background
, base::FilePath(FILE_PATH_LITERAL("mask_with_replica.png")));
171 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplicaOfClippedLayer
) {
172 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
173 gfx::Rect(100, 100), SK_ColorWHITE
);
175 gfx::Size
mask_bounds(50, 50);
176 MaskContentLayerClient
client(mask_bounds
);
177 scoped_refptr
<PictureLayer
> mask
=
178 PictureLayer::Create(layer_settings(), &client
);
179 mask
->SetBounds(mask_bounds
);
180 mask
->SetIsDrawable(true);
181 mask
->SetIsMask(true);
183 // Clip to the bottom half of the green layer, and the left half of the
185 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
186 clip
->SetPosition(gfx::Point(0, 25));
187 clip
->SetBounds(gfx::Size(75, 75));
188 clip
->SetMasksToBounds(true);
189 background
->AddChild(clip
);
191 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
192 gfx::Rect(0, -25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
193 clip
->AddChild(green
);
194 green
->SetMaskLayer(mask
.get());
196 gfx::Transform replica_transform
;
197 replica_transform
.Rotate(-90.0);
199 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
200 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
201 replica
->SetPosition(gfx::Point(50, 50));
202 replica
->SetTransform(replica_transform
);
203 green
->SetReplicaLayer(replica
.get());
205 RunPixelResourceTest(background
,
206 base::FilePath(FILE_PATH_LITERAL(
207 "mask_with_replica_of_clipped_layer.png")));
210 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplica
) {
211 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
212 gfx::Rect(100, 100), SK_ColorWHITE
);
214 gfx::Size
mask_bounds(50, 50);
215 MaskContentLayerClient
client(mask_bounds
);
216 scoped_refptr
<PictureLayer
> mask
=
217 PictureLayer::Create(layer_settings(), &client
);
218 mask
->SetBounds(mask_bounds
);
219 mask
->SetIsDrawable(true);
220 mask
->SetIsMask(true);
222 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
223 gfx::Rect(25, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
224 background
->AddChild(green
);
226 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
227 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
228 green
->AddChild(orange
);
230 gfx::Transform replica_transform
;
231 replica_transform
.Rotate(180.0);
232 replica_transform
.Translate(50.0, 0.0);
234 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
235 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
236 replica
->SetPosition(gfx::Point());
237 replica
->SetTransform(replica_transform
);
238 replica
->SetMaskLayer(mask
.get());
239 green
->SetReplicaLayer(replica
.get());
241 RunPixelResourceTest(
242 background
, base::FilePath(FILE_PATH_LITERAL("mask_of_replica.png")));
245 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplicaOfClippedLayer
) {
246 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
247 gfx::Rect(100, 100), SK_ColorWHITE
);
249 gfx::Size
mask_bounds(50, 50);
250 MaskContentLayerClient
client(mask_bounds
);
251 scoped_refptr
<PictureLayer
> mask
=
252 PictureLayer::Create(layer_settings(), &client
);
253 mask
->SetBounds(mask_bounds
);
254 mask
->SetIsDrawable(true);
255 mask
->SetIsMask(true);
257 // Clip to the bottom 3/4 of the green layer, and the top 3/4 of the replica.
258 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
259 clip
->SetPosition(gfx::Point(0, 12));
260 clip
->SetBounds(gfx::Size(100, 75));
261 clip
->SetMasksToBounds(true);
262 background
->AddChild(clip
);
264 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
265 gfx::Rect(25, -12, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
266 clip
->AddChild(green
);
268 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
269 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
270 green
->AddChild(orange
);
272 gfx::Transform replica_transform
;
273 replica_transform
.Rotate(180.0);
274 replica_transform
.Translate(50.0, 0.0);
276 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
277 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
278 replica
->SetPosition(gfx::Point());
279 replica
->SetTransform(replica_transform
);
280 replica
->SetMaskLayer(mask
.get());
281 green
->SetReplicaLayer(replica
.get());
283 RunPixelResourceTest(background
,
284 base::FilePath(FILE_PATH_LITERAL(
285 "mask_of_replica_of_clipped_layer.png")));
288 class CheckerContentLayerClient
: public ContentLayerClient
{
290 CheckerContentLayerClient(const gfx::Size
& bounds
,
293 : bounds_(bounds
), color_(color
), vertical_(vertical
) {}
294 ~CheckerContentLayerClient() override
{}
295 bool FillsBoundsCompletely() const override
{ return false; }
296 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
297 void PaintContents(SkCanvas
* canvas
,
298 const gfx::Rect
& rect
,
299 PaintingControlSetting picture_control
) override
{
301 paint
.setStyle(SkPaint::kStroke_Style
);
302 paint
.setStrokeWidth(SkIntToScalar(4));
303 paint
.setColor(color_
);
304 canvas
->clear(SK_ColorTRANSPARENT
);
306 for (int i
= 4; i
< bounds_
.width(); i
+= 16) {
307 canvas
->drawLine(i
, 0, i
, bounds_
.height(), paint
);
310 for (int i
= 4; i
< bounds_
.height(); i
+= 16) {
311 canvas
->drawLine(0, i
, bounds_
.width(), i
, paint
);
315 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
316 const gfx::Rect
& clip
,
317 PaintingControlSetting picture_control
) override
{
328 class CircleContentLayerClient
: public ContentLayerClient
{
330 explicit CircleContentLayerClient(const gfx::Size
& bounds
)
332 ~CircleContentLayerClient() override
{}
333 bool FillsBoundsCompletely() const override
{ return false; }
334 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
335 void PaintContents(SkCanvas
* canvas
,
336 const gfx::Rect
& rect
,
337 PaintingControlSetting picture_control
) override
{
339 paint
.setStyle(SkPaint::kFill_Style
);
340 paint
.setColor(SK_ColorWHITE
);
341 canvas
->clear(SK_ColorTRANSPARENT
);
342 canvas
->drawCircle(bounds_
.width() / 2,
343 bounds_
.height() / 2,
347 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
348 const gfx::Rect
& clip
,
349 PaintingControlSetting picture_control
) override
{
358 using LayerTreeHostMasksForBackgroundFiltersPixelTest
=
359 ParameterizedPixelResourceTest
;
361 INSTANTIATE_TEST_CASE_P(
363 LayerTreeHostMasksForBackgroundFiltersPixelTest
,
365 // SOFTWARE, Background filters aren't implemented in software
366 GL_GPU_RASTER_2D_DRAW
,
367 GL_ONE_COPY_2D_STAGING_2D_DRAW
,
368 GL_ONE_COPY_RECT_STAGING_2D_DRAW
,
369 GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW
,
370 GL_ZERO_COPY_2D_DRAW
,
371 GL_ZERO_COPY_RECT_DRAW
,
372 GL_ZERO_COPY_EXTERNAL_DRAW
,
373 GL_ASYNC_UPLOAD_2D_DRAW
));
375 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
376 MaskOfLayerWithBackgroundFilter
) {
377 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
378 gfx::Rect(100, 100), SK_ColorWHITE
);
380 gfx::Size
picture_bounds(100, 100);
381 CheckerContentLayerClient
picture_client(picture_bounds
, SK_ColorGREEN
, true);
382 scoped_refptr
<PictureLayer
> picture
=
383 PictureLayer::Create(layer_settings(), &picture_client
);
384 picture
->SetBounds(picture_bounds
);
385 picture
->SetIsDrawable(true);
387 scoped_refptr
<SolidColorLayer
> blur
= CreateSolidColorLayer(
388 gfx::Rect(100, 100), SK_ColorTRANSPARENT
);
389 background
->AddChild(picture
);
390 background
->AddChild(blur
);
392 FilterOperations filters
;
393 filters
.Append(FilterOperation::CreateBlurFilter(1.5f
));
394 blur
->SetBackgroundFilters(filters
);
396 gfx::Size
mask_bounds(100, 100);
397 CircleContentLayerClient
mask_client(mask_bounds
);
398 scoped_refptr
<PictureLayer
> mask
=
399 PictureLayer::Create(layer_settings(), &mask_client
);
400 mask
->SetBounds(mask_bounds
);
401 mask
->SetIsDrawable(true);
402 mask
->SetIsMask(true);
403 blur
->SetMaskLayer(mask
.get());
405 float percentage_pixels_large_error
= 2.5f
; // 2.5%, ~250px / (100*100)
406 float percentage_pixels_small_error
= 0.0f
;
407 float average_error_allowed_in_bad_pixels
= 100.0f
;
408 int large_error_allowed
= 256;
409 int small_error_allowed
= 0;
410 pixel_comparator_
.reset(new FuzzyPixelComparator(
411 true, // discard_alpha
412 percentage_pixels_large_error
,
413 percentage_pixels_small_error
,
414 average_error_allowed_in_bad_pixels
,
416 small_error_allowed
));
418 RunPixelResourceTest(background
,
420 FILE_PATH_LITERAL("mask_of_background_filter.png")));
423 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
424 MaskOfLayerWithBlend
) {
425 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
426 gfx::Rect(128, 128), SK_ColorWHITE
);
428 gfx::Size
picture_bounds(128, 128);
429 CheckerContentLayerClient
picture_client_vertical(
430 picture_bounds
, SK_ColorGREEN
, true);
431 scoped_refptr
<PictureLayer
> picture_vertical
=
432 PictureLayer::Create(layer_settings(), &picture_client_vertical
);
433 picture_vertical
->SetBounds(picture_bounds
);
434 picture_vertical
->SetIsDrawable(true);
436 CheckerContentLayerClient
picture_client_horizontal(
437 picture_bounds
, SK_ColorMAGENTA
, false);
438 scoped_refptr
<PictureLayer
> picture_horizontal
=
439 PictureLayer::Create(layer_settings(), &picture_client_horizontal
);
440 picture_horizontal
->SetBounds(picture_bounds
);
441 picture_horizontal
->SetIsDrawable(true);
442 picture_horizontal
->SetContentsOpaque(false);
443 picture_horizontal
->SetBlendMode(SkXfermode::kMultiply_Mode
);
445 background
->AddChild(picture_vertical
);
446 background
->AddChild(picture_horizontal
);
448 gfx::Size
mask_bounds(128, 128);
449 CircleContentLayerClient
mask_client(mask_bounds
);
450 scoped_refptr
<PictureLayer
> mask
=
451 PictureLayer::Create(layer_settings(), &mask_client
);
452 mask
->SetBounds(mask_bounds
);
453 mask
->SetIsDrawable(true);
454 mask
->SetIsMask(true);
455 picture_horizontal
->SetMaskLayer(mask
.get());
457 float percentage_pixels_large_error
= 0.04f
; // 0.04%, ~6px / (128*128)
458 float percentage_pixels_small_error
= 0.0f
;
459 float average_error_allowed_in_bad_pixels
= 256.0f
;
460 int large_error_allowed
= 256;
461 int small_error_allowed
= 0;
462 pixel_comparator_
.reset(new FuzzyPixelComparator(
463 true, // discard_alpha
464 percentage_pixels_large_error
,
465 percentage_pixels_small_error
,
466 average_error_allowed_in_bad_pixels
,
468 small_error_allowed
));
470 RunPixelResourceTest(background
,
472 FILE_PATH_LITERAL("mask_of_layer_with_blend.png")));
478 #endif // !defined(OS_ANDROID)