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"
12 #include "third_party/skia/include/core/SkImage.h"
13 #include "third_party/skia/include/core/SkSurface.h"
15 #if !defined(OS_ANDROID)
20 typedef ParameterizedPixelResourceTest LayerTreeHostMasksPixelTest
;
22 INSTANTIATE_PIXEL_RESOURCE_TEST_CASE_P(LayerTreeHostMasksPixelTest
);
24 class MaskContentLayerClient
: public ContentLayerClient
{
26 explicit MaskContentLayerClient(const gfx::Size
& bounds
) : bounds_(bounds
) {}
27 ~MaskContentLayerClient() override
{}
29 bool FillsBoundsCompletely() const override
{ return false; }
30 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
32 void PaintContents(SkCanvas
* canvas
,
33 const gfx::Rect
& rect
,
34 PaintingControlSetting picture_control
) override
{
36 paint
.setStyle(SkPaint::kStroke_Style
);
37 paint
.setStrokeWidth(SkIntToScalar(2));
38 paint
.setColor(SK_ColorWHITE
);
40 canvas
->clear(SK_ColorTRANSPARENT
);
41 gfx::Rect
inset_rect(bounds_
);
42 while (!inset_rect
.IsEmpty()) {
43 inset_rect
.Inset(3, 3, 2, 2);
45 SkRect::MakeXYWH(inset_rect
.x(), inset_rect
.y(),
46 inset_rect
.width(), inset_rect
.height()),
48 inset_rect
.Inset(3, 3, 2, 2);
52 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
53 const gfx::Rect
& clip
,
54 PaintingControlSetting picture_control
) override
{
63 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfLayer
) {
64 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
65 gfx::Rect(100, 100), SK_ColorWHITE
);
67 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
68 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
69 background
->AddChild(green
);
71 gfx::Size
mask_bounds(50, 50);
72 MaskContentLayerClient
client(mask_bounds
);
73 scoped_refptr
<PictureLayer
> mask
=
74 PictureLayer::Create(layer_settings(), &client
);
75 mask
->SetBounds(mask_bounds
);
76 mask
->SetIsDrawable(true);
77 mask
->SetIsMask(true);
78 green
->SetMaskLayer(mask
.get());
80 RunPixelResourceTest(background
,
81 base::FilePath(FILE_PATH_LITERAL("mask_of_layer.png")));
84 TEST_P(LayerTreeHostMasksPixelTest
, ImageMaskOfLayer
) {
85 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
86 gfx::Rect(100, 100), SK_ColorWHITE
);
88 gfx::Size
mask_bounds(50, 50);
90 scoped_refptr
<PictureImageLayer
> mask
=
91 PictureImageLayer::Create(layer_settings());
92 mask
->SetIsDrawable(true);
93 mask
->SetIsMask(true);
94 mask
->SetBounds(mask_bounds
);
96 skia::RefPtr
<SkSurface
> surface
=
97 skia::AdoptRef(SkSurface::NewRasterN32Premul(200, 200));
98 SkCanvas
* canvas
= surface
->getCanvas();
99 canvas
->scale(SkIntToScalar(4), SkIntToScalar(4));
100 MaskContentLayerClient
client(mask_bounds
);
101 client
.PaintContents(canvas
, gfx::Rect(mask_bounds
),
102 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL
);
103 skia::RefPtr
<const SkImage
> image
=
104 skia::AdoptRef(surface
->newImageSnapshot());
105 mask
->SetImage(image
.Pass());
107 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
108 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
109 green
->SetMaskLayer(mask
.get());
110 background
->AddChild(green
);
112 RunPixelResourceTest(
113 background
, base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png")));
116 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfClippedLayer
) {
117 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
118 gfx::Rect(100, 100), SK_ColorWHITE
);
120 // Clip to the top half of the green layer.
121 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
122 clip
->SetPosition(gfx::Point(0, 0));
123 clip
->SetBounds(gfx::Size(100, 50));
124 clip
->SetMasksToBounds(true);
125 background
->AddChild(clip
);
127 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
128 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
129 clip
->AddChild(green
);
131 gfx::Size
mask_bounds(50, 50);
132 MaskContentLayerClient
client(mask_bounds
);
133 scoped_refptr
<PictureLayer
> mask
=
134 PictureLayer::Create(layer_settings(), &client
);
135 mask
->SetBounds(mask_bounds
);
136 mask
->SetIsDrawable(true);
137 mask
->SetIsMask(true);
138 green
->SetMaskLayer(mask
.get());
140 RunPixelResourceTest(
142 base::FilePath(FILE_PATH_LITERAL("mask_of_clipped_layer.png")));
145 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplica
) {
146 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
147 gfx::Rect(100, 100), SK_ColorWHITE
);
149 gfx::Size
mask_bounds(50, 50);
150 MaskContentLayerClient
client(mask_bounds
);
151 scoped_refptr
<PictureLayer
> mask
=
152 PictureLayer::Create(layer_settings(), &client
);
153 mask
->SetBounds(mask_bounds
);
154 mask
->SetIsDrawable(true);
155 mask
->SetIsMask(true);
157 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
158 gfx::Rect(0, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
159 background
->AddChild(green
);
160 green
->SetMaskLayer(mask
.get());
162 gfx::Transform replica_transform
;
163 replica_transform
.Rotate(-90.0);
165 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
166 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
167 replica
->SetPosition(gfx::Point(50, 50));
168 replica
->SetTransform(replica_transform
);
169 green
->SetReplicaLayer(replica
.get());
171 RunPixelResourceTest(
172 background
, base::FilePath(FILE_PATH_LITERAL("mask_with_replica.png")));
175 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplicaOfClippedLayer
) {
176 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
177 gfx::Rect(100, 100), SK_ColorWHITE
);
179 gfx::Size
mask_bounds(50, 50);
180 MaskContentLayerClient
client(mask_bounds
);
181 scoped_refptr
<PictureLayer
> mask
=
182 PictureLayer::Create(layer_settings(), &client
);
183 mask
->SetBounds(mask_bounds
);
184 mask
->SetIsDrawable(true);
185 mask
->SetIsMask(true);
187 // Clip to the bottom half of the green layer, and the left half of the
189 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
190 clip
->SetPosition(gfx::Point(0, 25));
191 clip
->SetBounds(gfx::Size(75, 75));
192 clip
->SetMasksToBounds(true);
193 background
->AddChild(clip
);
195 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
196 gfx::Rect(0, -25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
197 clip
->AddChild(green
);
198 green
->SetMaskLayer(mask
.get());
200 gfx::Transform replica_transform
;
201 replica_transform
.Rotate(-90.0);
203 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
204 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
205 replica
->SetPosition(gfx::Point(50, 50));
206 replica
->SetTransform(replica_transform
);
207 green
->SetReplicaLayer(replica
.get());
209 RunPixelResourceTest(background
,
210 base::FilePath(FILE_PATH_LITERAL(
211 "mask_with_replica_of_clipped_layer.png")));
214 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplica
) {
215 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
216 gfx::Rect(100, 100), SK_ColorWHITE
);
218 gfx::Size
mask_bounds(50, 50);
219 MaskContentLayerClient
client(mask_bounds
);
220 scoped_refptr
<PictureLayer
> mask
=
221 PictureLayer::Create(layer_settings(), &client
);
222 mask
->SetBounds(mask_bounds
);
223 mask
->SetIsDrawable(true);
224 mask
->SetIsMask(true);
226 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
227 gfx::Rect(25, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
228 background
->AddChild(green
);
230 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
231 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
232 green
->AddChild(orange
);
234 gfx::Transform replica_transform
;
235 replica_transform
.Rotate(180.0);
236 replica_transform
.Translate(50.0, 0.0);
238 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
239 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
240 replica
->SetPosition(gfx::Point());
241 replica
->SetTransform(replica_transform
);
242 replica
->SetMaskLayer(mask
.get());
243 green
->SetReplicaLayer(replica
.get());
245 RunPixelResourceTest(
246 background
, base::FilePath(FILE_PATH_LITERAL("mask_of_replica.png")));
249 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplicaOfClippedLayer
) {
250 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
251 gfx::Rect(100, 100), SK_ColorWHITE
);
253 gfx::Size
mask_bounds(50, 50);
254 MaskContentLayerClient
client(mask_bounds
);
255 scoped_refptr
<PictureLayer
> mask
=
256 PictureLayer::Create(layer_settings(), &client
);
257 mask
->SetBounds(mask_bounds
);
258 mask
->SetIsDrawable(true);
259 mask
->SetIsMask(true);
261 // Clip to the bottom 3/4 of the green layer, and the top 3/4 of the replica.
262 scoped_refptr
<Layer
> clip
= Layer::Create(layer_settings());
263 clip
->SetPosition(gfx::Point(0, 12));
264 clip
->SetBounds(gfx::Size(100, 75));
265 clip
->SetMasksToBounds(true);
266 background
->AddChild(clip
);
268 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
269 gfx::Rect(25, -12, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
270 clip
->AddChild(green
);
272 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
273 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
274 green
->AddChild(orange
);
276 gfx::Transform replica_transform
;
277 replica_transform
.Rotate(180.0);
278 replica_transform
.Translate(50.0, 0.0);
280 scoped_refptr
<Layer
> replica
= Layer::Create(layer_settings());
281 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
282 replica
->SetPosition(gfx::Point());
283 replica
->SetTransform(replica_transform
);
284 replica
->SetMaskLayer(mask
.get());
285 green
->SetReplicaLayer(replica
.get());
287 RunPixelResourceTest(background
,
288 base::FilePath(FILE_PATH_LITERAL(
289 "mask_of_replica_of_clipped_layer.png")));
292 class CheckerContentLayerClient
: public ContentLayerClient
{
294 CheckerContentLayerClient(const gfx::Size
& bounds
,
297 : bounds_(bounds
), color_(color
), vertical_(vertical
) {}
298 ~CheckerContentLayerClient() override
{}
299 bool FillsBoundsCompletely() const override
{ return false; }
300 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
301 void PaintContents(SkCanvas
* canvas
,
302 const gfx::Rect
& rect
,
303 PaintingControlSetting picture_control
) override
{
305 paint
.setStyle(SkPaint::kStroke_Style
);
306 paint
.setStrokeWidth(SkIntToScalar(4));
307 paint
.setColor(color_
);
308 canvas
->clear(SK_ColorTRANSPARENT
);
310 for (int i
= 4; i
< bounds_
.width(); i
+= 16) {
311 canvas
->drawLine(i
, 0, i
, bounds_
.height(), paint
);
314 for (int i
= 4; i
< bounds_
.height(); i
+= 16) {
315 canvas
->drawLine(0, i
, bounds_
.width(), i
, paint
);
319 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
320 const gfx::Rect
& clip
,
321 PaintingControlSetting picture_control
) override
{
332 class CircleContentLayerClient
: public ContentLayerClient
{
334 explicit CircleContentLayerClient(const gfx::Size
& bounds
)
336 ~CircleContentLayerClient() override
{}
337 bool FillsBoundsCompletely() const override
{ return false; }
338 size_t GetApproximateUnsharedMemoryUsage() const override
{ return 0; }
339 void PaintContents(SkCanvas
* canvas
,
340 const gfx::Rect
& rect
,
341 PaintingControlSetting picture_control
) override
{
343 paint
.setStyle(SkPaint::kFill_Style
);
344 paint
.setColor(SK_ColorWHITE
);
345 canvas
->clear(SK_ColorTRANSPARENT
);
346 canvas
->drawCircle(bounds_
.width() / 2,
347 bounds_
.height() / 2,
351 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
352 const gfx::Rect
& clip
,
353 PaintingControlSetting picture_control
) override
{
362 using LayerTreeHostMasksForBackgroundFiltersPixelTest
=
363 ParameterizedPixelResourceTest
;
365 INSTANTIATE_TEST_CASE_P(
367 LayerTreeHostMasksForBackgroundFiltersPixelTest
,
369 // SOFTWARE, Background filters aren't implemented in software
370 GL_GPU_RASTER_2D_DRAW
,
371 GL_ONE_COPY_2D_STAGING_2D_DRAW
,
372 GL_ONE_COPY_RECT_STAGING_2D_DRAW
,
373 GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW
,
374 GL_ZERO_COPY_2D_DRAW
,
375 GL_ZERO_COPY_RECT_DRAW
,
376 GL_ZERO_COPY_EXTERNAL_DRAW
,
377 GL_ASYNC_UPLOAD_2D_DRAW
));
379 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
380 MaskOfLayerWithBackgroundFilter
) {
381 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
382 gfx::Rect(100, 100), SK_ColorWHITE
);
384 gfx::Size
picture_bounds(100, 100);
385 CheckerContentLayerClient
picture_client(picture_bounds
, SK_ColorGREEN
, true);
386 scoped_refptr
<PictureLayer
> picture
=
387 PictureLayer::Create(layer_settings(), &picture_client
);
388 picture
->SetBounds(picture_bounds
);
389 picture
->SetIsDrawable(true);
391 scoped_refptr
<SolidColorLayer
> blur
= CreateSolidColorLayer(
392 gfx::Rect(100, 100), SK_ColorTRANSPARENT
);
393 background
->AddChild(picture
);
394 background
->AddChild(blur
);
396 FilterOperations filters
;
397 filters
.Append(FilterOperation::CreateBlurFilter(1.5f
));
398 blur
->SetBackgroundFilters(filters
);
400 gfx::Size
mask_bounds(100, 100);
401 CircleContentLayerClient
mask_client(mask_bounds
);
402 scoped_refptr
<PictureLayer
> mask
=
403 PictureLayer::Create(layer_settings(), &mask_client
);
404 mask
->SetBounds(mask_bounds
);
405 mask
->SetIsDrawable(true);
406 mask
->SetIsMask(true);
407 blur
->SetMaskLayer(mask
.get());
409 float percentage_pixels_large_error
= 2.5f
; // 2.5%, ~250px / (100*100)
410 float percentage_pixels_small_error
= 0.0f
;
411 float average_error_allowed_in_bad_pixels
= 100.0f
;
412 int large_error_allowed
= 256;
413 int small_error_allowed
= 0;
414 pixel_comparator_
.reset(new FuzzyPixelComparator(
415 true, // discard_alpha
416 percentage_pixels_large_error
,
417 percentage_pixels_small_error
,
418 average_error_allowed_in_bad_pixels
,
420 small_error_allowed
));
422 RunPixelResourceTest(background
,
424 FILE_PATH_LITERAL("mask_of_background_filter.png")));
427 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
428 MaskOfLayerWithBlend
) {
429 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
430 gfx::Rect(128, 128), SK_ColorWHITE
);
432 gfx::Size
picture_bounds(128, 128);
433 CheckerContentLayerClient
picture_client_vertical(
434 picture_bounds
, SK_ColorGREEN
, true);
435 scoped_refptr
<PictureLayer
> picture_vertical
=
436 PictureLayer::Create(layer_settings(), &picture_client_vertical
);
437 picture_vertical
->SetBounds(picture_bounds
);
438 picture_vertical
->SetIsDrawable(true);
440 CheckerContentLayerClient
picture_client_horizontal(
441 picture_bounds
, SK_ColorMAGENTA
, false);
442 scoped_refptr
<PictureLayer
> picture_horizontal
=
443 PictureLayer::Create(layer_settings(), &picture_client_horizontal
);
444 picture_horizontal
->SetBounds(picture_bounds
);
445 picture_horizontal
->SetIsDrawable(true);
446 picture_horizontal
->SetContentsOpaque(false);
447 picture_horizontal
->SetBlendMode(SkXfermode::kMultiply_Mode
);
449 background
->AddChild(picture_vertical
);
450 background
->AddChild(picture_horizontal
);
452 gfx::Size
mask_bounds(128, 128);
453 CircleContentLayerClient
mask_client(mask_bounds
);
454 scoped_refptr
<PictureLayer
> mask
=
455 PictureLayer::Create(layer_settings(), &mask_client
);
456 mask
->SetBounds(mask_bounds
);
457 mask
->SetIsDrawable(true);
458 mask
->SetIsMask(true);
459 picture_horizontal
->SetMaskLayer(mask
.get());
461 float percentage_pixels_large_error
= 0.04f
; // 0.04%, ~6px / (128*128)
462 float percentage_pixels_small_error
= 0.0f
;
463 float average_error_allowed_in_bad_pixels
= 256.0f
;
464 int large_error_allowed
= 256;
465 int small_error_allowed
= 0;
466 pixel_comparator_
.reset(new FuzzyPixelComparator(
467 true, // discard_alpha
468 percentage_pixels_large_error
,
469 percentage_pixels_small_error
,
470 average_error_allowed_in_bad_pixels
,
472 small_error_allowed
));
474 RunPixelResourceTest(background
,
476 FILE_PATH_LITERAL("mask_of_layer_with_blend.png")));
482 #endif // !defined(OS_ANDROID)