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; }
29 void PaintContents(SkCanvas
* canvas
,
30 const gfx::Rect
& rect
,
31 PaintingControlSetting picture_control
) override
{
33 paint
.setStyle(SkPaint::kStroke_Style
);
34 paint
.setStrokeWidth(SkIntToScalar(2));
35 paint
.setColor(SK_ColorWHITE
);
37 canvas
->clear(SK_ColorTRANSPARENT
);
38 gfx::Rect
inset_rect(bounds_
);
39 while (!inset_rect
.IsEmpty()) {
40 inset_rect
.Inset(3, 3, 2, 2);
42 SkRect::MakeXYWH(inset_rect
.x(), inset_rect
.y(),
43 inset_rect
.width(), inset_rect
.height()),
45 inset_rect
.Inset(3, 3, 2, 2);
49 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
50 const gfx::Rect
& clip
,
51 PaintingControlSetting picture_control
) override
{
53 return DisplayItemList::Create();
60 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfLayer
) {
61 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
62 gfx::Rect(100, 100), SK_ColorWHITE
);
64 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
65 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
66 background
->AddChild(green
);
68 gfx::Size
mask_bounds(50, 50);
69 MaskContentLayerClient
client(mask_bounds
);
70 scoped_refptr
<PictureLayer
> mask
= PictureLayer::Create(&client
);
71 mask
->SetBounds(mask_bounds
);
72 mask
->SetIsDrawable(true);
73 mask
->SetIsMask(true);
74 green
->SetMaskLayer(mask
.get());
76 RunPixelResourceTest(background
,
77 base::FilePath(FILE_PATH_LITERAL("mask_of_layer.png")));
80 TEST_P(LayerTreeHostMasksPixelTest
, ImageMaskOfLayer
) {
81 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
82 gfx::Rect(100, 100), SK_ColorWHITE
);
84 gfx::Size
mask_bounds(50, 50);
86 scoped_refptr
<PictureImageLayer
> mask
= PictureImageLayer::Create();
87 mask
->SetIsDrawable(true);
88 mask
->SetIsMask(true);
89 mask
->SetBounds(mask_bounds
);
92 bitmap
.allocN32Pixels(200, 200);
93 SkCanvas
canvas(bitmap
);
94 canvas
.scale(SkIntToScalar(4), SkIntToScalar(4));
95 MaskContentLayerClient
client(mask_bounds
);
96 client
.PaintContents(&canvas
, gfx::Rect(mask_bounds
),
97 ContentLayerClient::PAINTING_BEHAVIOR_NORMAL
);
98 mask
->SetBitmap(bitmap
);
100 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
101 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
102 green
->SetMaskLayer(mask
.get());
103 background
->AddChild(green
);
105 RunPixelResourceTest(
106 background
, base::FilePath(FILE_PATH_LITERAL("image_mask_of_layer.png")));
109 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfClippedLayer
) {
110 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
111 gfx::Rect(100, 100), SK_ColorWHITE
);
113 // Clip to the top half of the green layer.
114 scoped_refptr
<Layer
> clip
= Layer::Create();
115 clip
->SetPosition(gfx::Point(0, 0));
116 clip
->SetBounds(gfx::Size(100, 50));
117 clip
->SetMasksToBounds(true);
118 background
->AddChild(clip
);
120 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
121 gfx::Rect(25, 25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
122 clip
->AddChild(green
);
124 gfx::Size
mask_bounds(50, 50);
125 MaskContentLayerClient
client(mask_bounds
);
126 scoped_refptr
<PictureLayer
> mask
= PictureLayer::Create(&client
);
127 mask
->SetBounds(mask_bounds
);
128 mask
->SetIsDrawable(true);
129 mask
->SetIsMask(true);
130 green
->SetMaskLayer(mask
.get());
132 RunPixelResourceTest(
134 base::FilePath(FILE_PATH_LITERAL("mask_of_clipped_layer.png")));
137 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplica
) {
138 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
139 gfx::Rect(100, 100), SK_ColorWHITE
);
141 gfx::Size
mask_bounds(50, 50);
142 MaskContentLayerClient
client(mask_bounds
);
143 scoped_refptr
<PictureLayer
> mask
= PictureLayer::Create(&client
);
144 mask
->SetBounds(mask_bounds
);
145 mask
->SetIsDrawable(true);
146 mask
->SetIsMask(true);
148 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
149 gfx::Rect(0, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
150 background
->AddChild(green
);
151 green
->SetMaskLayer(mask
.get());
153 gfx::Transform replica_transform
;
154 replica_transform
.Rotate(-90.0);
156 scoped_refptr
<Layer
> replica
= Layer::Create();
157 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
158 replica
->SetPosition(gfx::Point(50, 50));
159 replica
->SetTransform(replica_transform
);
160 green
->SetReplicaLayer(replica
.get());
162 RunPixelResourceTest(
163 background
, base::FilePath(FILE_PATH_LITERAL("mask_with_replica.png")));
166 TEST_P(LayerTreeHostMasksPixelTest
, MaskWithReplicaOfClippedLayer
) {
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
= PictureLayer::Create(&client
);
173 mask
->SetBounds(mask_bounds
);
174 mask
->SetIsDrawable(true);
175 mask
->SetIsMask(true);
177 // Clip to the bottom half of the green layer, and the left half of the
179 scoped_refptr
<Layer
> clip
= Layer::Create();
180 clip
->SetPosition(gfx::Point(0, 25));
181 clip
->SetBounds(gfx::Size(75, 75));
182 clip
->SetMasksToBounds(true);
183 background
->AddChild(clip
);
185 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
186 gfx::Rect(0, -25, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
187 clip
->AddChild(green
);
188 green
->SetMaskLayer(mask
.get());
190 gfx::Transform replica_transform
;
191 replica_transform
.Rotate(-90.0);
193 scoped_refptr
<Layer
> replica
= Layer::Create();
194 replica
->SetTransformOrigin(gfx::Point3F(25.f
, 25.f
, 0.f
));
195 replica
->SetPosition(gfx::Point(50, 50));
196 replica
->SetTransform(replica_transform
);
197 green
->SetReplicaLayer(replica
.get());
199 RunPixelResourceTest(background
,
200 base::FilePath(FILE_PATH_LITERAL(
201 "mask_with_replica_of_clipped_layer.png")));
204 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplica
) {
205 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
206 gfx::Rect(100, 100), SK_ColorWHITE
);
208 gfx::Size
mask_bounds(50, 50);
209 MaskContentLayerClient
client(mask_bounds
);
210 scoped_refptr
<PictureLayer
> mask
= PictureLayer::Create(&client
);
211 mask
->SetBounds(mask_bounds
);
212 mask
->SetIsDrawable(true);
213 mask
->SetIsMask(true);
215 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
216 gfx::Rect(25, 0, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
217 background
->AddChild(green
);
219 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
220 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
221 green
->AddChild(orange
);
223 gfx::Transform replica_transform
;
224 replica_transform
.Rotate(180.0);
225 replica_transform
.Translate(50.0, 0.0);
227 scoped_refptr
<Layer
> replica
= Layer::Create();
228 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
229 replica
->SetPosition(gfx::Point());
230 replica
->SetTransform(replica_transform
);
231 replica
->SetMaskLayer(mask
.get());
232 green
->SetReplicaLayer(replica
.get());
234 RunPixelResourceTest(
235 background
, base::FilePath(FILE_PATH_LITERAL("mask_of_replica.png")));
238 TEST_P(LayerTreeHostMasksPixelTest
, MaskOfReplicaOfClippedLayer
) {
239 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
240 gfx::Rect(100, 100), SK_ColorWHITE
);
242 gfx::Size
mask_bounds(50, 50);
243 MaskContentLayerClient
client(mask_bounds
);
244 scoped_refptr
<PictureLayer
> mask
= PictureLayer::Create(&client
);
245 mask
->SetBounds(mask_bounds
);
246 mask
->SetIsDrawable(true);
247 mask
->SetIsMask(true);
249 // Clip to the bottom 3/4 of the green layer, and the top 3/4 of the replica.
250 scoped_refptr
<Layer
> clip
= Layer::Create();
251 clip
->SetPosition(gfx::Point(0, 12));
252 clip
->SetBounds(gfx::Size(100, 75));
253 clip
->SetMasksToBounds(true);
254 background
->AddChild(clip
);
256 scoped_refptr
<SolidColorLayer
> green
= CreateSolidColorLayerWithBorder(
257 gfx::Rect(25, -12, 50, 50), kCSSGreen
, 1, SK_ColorBLACK
);
258 clip
->AddChild(green
);
260 scoped_refptr
<SolidColorLayer
> orange
= CreateSolidColorLayer(
261 gfx::Rect(-25, 25, 25, 25), kCSSOrange
);
262 green
->AddChild(orange
);
264 gfx::Transform replica_transform
;
265 replica_transform
.Rotate(180.0);
266 replica_transform
.Translate(50.0, 0.0);
268 scoped_refptr
<Layer
> replica
= Layer::Create();
269 replica
->SetTransformOrigin(gfx::Point3F(50.f
, 50.f
, 0.f
));
270 replica
->SetPosition(gfx::Point());
271 replica
->SetTransform(replica_transform
);
272 replica
->SetMaskLayer(mask
.get());
273 green
->SetReplicaLayer(replica
.get());
275 RunPixelResourceTest(background
,
276 base::FilePath(FILE_PATH_LITERAL(
277 "mask_of_replica_of_clipped_layer.png")));
280 class CheckerContentLayerClient
: public ContentLayerClient
{
282 CheckerContentLayerClient(const gfx::Size
& bounds
,
285 : bounds_(bounds
), color_(color
), vertical_(vertical
) {}
286 ~CheckerContentLayerClient() override
{}
287 bool FillsBoundsCompletely() const override
{ return false; }
288 void PaintContents(SkCanvas
* canvas
,
289 const gfx::Rect
& rect
,
290 PaintingControlSetting picture_control
) override
{
292 paint
.setStyle(SkPaint::kStroke_Style
);
293 paint
.setStrokeWidth(SkIntToScalar(4));
294 paint
.setColor(color_
);
295 canvas
->clear(SK_ColorTRANSPARENT
);
297 for (int i
= 4; i
< bounds_
.width(); i
+= 16) {
298 canvas
->drawLine(i
, 0, i
, bounds_
.height(), paint
);
301 for (int i
= 4; i
< bounds_
.height(); i
+= 16) {
302 canvas
->drawLine(0, i
, bounds_
.width(), i
, paint
);
306 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
307 const gfx::Rect
& clip
,
308 PaintingControlSetting picture_control
) override
{
310 return DisplayItemList::Create();
319 class CircleContentLayerClient
: public ContentLayerClient
{
321 explicit CircleContentLayerClient(const gfx::Size
& bounds
)
323 ~CircleContentLayerClient() override
{}
324 bool FillsBoundsCompletely() const override
{ return false; }
325 void PaintContents(SkCanvas
* canvas
,
326 const gfx::Rect
& rect
,
327 PaintingControlSetting picture_control
) override
{
329 paint
.setStyle(SkPaint::kFill_Style
);
330 paint
.setColor(SK_ColorWHITE
);
331 canvas
->clear(SK_ColorTRANSPARENT
);
332 canvas
->drawCircle(bounds_
.width() / 2,
333 bounds_
.height() / 2,
337 scoped_refptr
<DisplayItemList
> PaintContentsToDisplayList(
338 const gfx::Rect
& clip
,
339 PaintingControlSetting picture_control
) override
{
341 return DisplayItemList::Create();
348 using LayerTreeHostMasksForBackgroundFiltersPixelTest
=
349 ParameterizedPixelResourceTest
;
351 INSTANTIATE_TEST_CASE_P(
353 LayerTreeHostMasksForBackgroundFiltersPixelTest
,
355 // SOFTWARE, Background filters aren't implemented in software
356 GL_GPU_RASTER_2D_DRAW
,
357 GL_ONE_COPY_2D_STAGING_2D_DRAW
,
358 GL_ONE_COPY_RECT_STAGING_2D_DRAW
,
359 GL_ONE_COPY_EXTERNAL_STAGING_2D_DRAW
,
360 GL_ZERO_COPY_2D_DRAW
,
361 GL_ZERO_COPY_RECT_DRAW
,
362 GL_ZERO_COPY_EXTERNAL_DRAW
,
363 GL_ASYNC_UPLOAD_2D_DRAW
));
365 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
366 MaskOfLayerWithBackgroundFilter
) {
367 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
368 gfx::Rect(100, 100), SK_ColorWHITE
);
370 gfx::Size
picture_bounds(100, 100);
371 CheckerContentLayerClient
picture_client(picture_bounds
, SK_ColorGREEN
, true);
372 scoped_refptr
<PictureLayer
> picture
= PictureLayer::Create(&picture_client
);
373 picture
->SetBounds(picture_bounds
);
374 picture
->SetIsDrawable(true);
376 scoped_refptr
<SolidColorLayer
> blur
= CreateSolidColorLayer(
377 gfx::Rect(100, 100), SK_ColorTRANSPARENT
);
378 background
->AddChild(picture
);
379 background
->AddChild(blur
);
381 FilterOperations filters
;
382 filters
.Append(FilterOperation::CreateBlurFilter(1.5f
));
383 blur
->SetBackgroundFilters(filters
);
385 gfx::Size
mask_bounds(100, 100);
386 CircleContentLayerClient
mask_client(mask_bounds
);
387 scoped_refptr
<PictureLayer
> mask
= PictureLayer::Create(&mask_client
);
388 mask
->SetBounds(mask_bounds
);
389 mask
->SetIsDrawable(true);
390 mask
->SetIsMask(true);
391 blur
->SetMaskLayer(mask
.get());
393 float percentage_pixels_large_error
= 2.5f
; // 2.5%, ~250px / (100*100)
394 float percentage_pixels_small_error
= 0.0f
;
395 float average_error_allowed_in_bad_pixels
= 100.0f
;
396 int large_error_allowed
= 256;
397 int small_error_allowed
= 0;
398 pixel_comparator_
.reset(new FuzzyPixelComparator(
399 true, // discard_alpha
400 percentage_pixels_large_error
,
401 percentage_pixels_small_error
,
402 average_error_allowed_in_bad_pixels
,
404 small_error_allowed
));
406 RunPixelResourceTest(background
,
408 FILE_PATH_LITERAL("mask_of_background_filter.png")));
411 TEST_P(LayerTreeHostMasksForBackgroundFiltersPixelTest
,
412 MaskOfLayerWithBlend
) {
413 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
414 gfx::Rect(128, 128), SK_ColorWHITE
);
416 gfx::Size
picture_bounds(128, 128);
417 CheckerContentLayerClient
picture_client_vertical(
418 picture_bounds
, SK_ColorGREEN
, true);
419 scoped_refptr
<PictureLayer
> picture_vertical
=
420 PictureLayer::Create(&picture_client_vertical
);
421 picture_vertical
->SetBounds(picture_bounds
);
422 picture_vertical
->SetIsDrawable(true);
424 CheckerContentLayerClient
picture_client_horizontal(
425 picture_bounds
, SK_ColorMAGENTA
, false);
426 scoped_refptr
<PictureLayer
> picture_horizontal
=
427 PictureLayer::Create(&picture_client_horizontal
);
428 picture_horizontal
->SetBounds(picture_bounds
);
429 picture_horizontal
->SetIsDrawable(true);
430 picture_horizontal
->SetContentsOpaque(false);
431 picture_horizontal
->SetBlendMode(SkXfermode::kMultiply_Mode
);
433 background
->AddChild(picture_vertical
);
434 background
->AddChild(picture_horizontal
);
436 gfx::Size
mask_bounds(128, 128);
437 CircleContentLayerClient
mask_client(mask_bounds
);
438 scoped_refptr
<PictureLayer
> mask
= PictureLayer::Create(&mask_client
);
439 mask
->SetBounds(mask_bounds
);
440 mask
->SetIsDrawable(true);
441 mask
->SetIsMask(true);
442 picture_horizontal
->SetMaskLayer(mask
.get());
444 float percentage_pixels_large_error
= 0.04f
; // 0.04%, ~6px / (128*128)
445 float percentage_pixels_small_error
= 0.0f
;
446 float average_error_allowed_in_bad_pixels
= 256.0f
;
447 int large_error_allowed
= 256;
448 int small_error_allowed
= 0;
449 pixel_comparator_
.reset(new FuzzyPixelComparator(
450 true, // discard_alpha
451 percentage_pixels_large_error
,
452 percentage_pixels_small_error
,
453 average_error_allowed_in_bad_pixels
,
455 small_error_allowed
));
457 RunPixelResourceTest(background
,
459 FILE_PATH_LITERAL("mask_of_layer_with_blend.png")));
465 #endif // !defined(OS_ANDROID)