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 "cc/layers/picture_image_layer.h"
6 #include "cc/layers/solid_color_layer.h"
7 #include "cc/test/layer_tree_pixel_resource_test.h"
8 #include "cc/test/pixel_comparator.h"
9 #include "third_party/skia/include/core/SkImage.h"
10 #include "third_party/skia/include/core/SkSurface.h"
12 #if !defined(OS_ANDROID)
17 SkXfermode::Mode
const kBlendModes
[] = {
18 SkXfermode::kSrcOver_Mode
, SkXfermode::kScreen_Mode
,
19 SkXfermode::kOverlay_Mode
, SkXfermode::kDarken_Mode
,
20 SkXfermode::kLighten_Mode
, SkXfermode::kColorDodge_Mode
,
21 SkXfermode::kColorBurn_Mode
, SkXfermode::kHardLight_Mode
,
22 SkXfermode::kSoftLight_Mode
, SkXfermode::kDifference_Mode
,
23 SkXfermode::kExclusion_Mode
, SkXfermode::kMultiply_Mode
,
24 SkXfermode::kHue_Mode
, SkXfermode::kSaturation_Mode
,
25 SkXfermode::kColor_Mode
, SkXfermode::kLuminosity_Mode
};
27 SkColor kCSSTestColors
[] = {
32 0xffff00ff, // fuchsia
44 0x80000000, // black with transparency
46 0x80ffffff, // white with transparency
47 0x00000000 // transparent
50 const int kBlendModesCount
= arraysize(kBlendModes
);
51 const int kCSSTestColorsCount
= arraysize(kCSSTestColors
);
53 using RenderPassOptions
= uint32
;
54 const uint32 kUseMasks
= 1 << 0;
55 const uint32 kUseAntialiasing
= 1 << 1;
56 const uint32 kUseColorMatrix
= 1 << 2;
57 const uint32 kForceShaders
= 1 << 3;
59 class LayerTreeHostBlendingPixelTest
: public LayerTreeHostPixelResourceTest
{
61 LayerTreeHostBlendingPixelTest()
62 : force_antialiasing_(false), force_blending_with_shaders_(false) {
63 pixel_comparator_
.reset(new FuzzyPixelOffByOneComparator(true));
66 void InitializeSettings(LayerTreeSettings
* settings
) override
{
67 settings
->renderer_settings
.force_antialiasing
= force_antialiasing_
;
68 settings
->renderer_settings
.force_blending_with_shaders
=
69 force_blending_with_shaders_
;
73 void RunBlendingWithRootPixelTestType(PixelResourceTestCase type
) {
74 const int kLaneWidth
= 2;
75 const int kLaneHeight
= kLaneWidth
;
76 const int kRootWidth
= (kBlendModesCount
+ 2) * kLaneWidth
;
77 const int kRootHeight
= 2 * kLaneWidth
+ kLaneHeight
;
78 InitializeFromTestCase(type
);
80 scoped_refptr
<SolidColorLayer
> background
=
81 CreateSolidColorLayer(gfx::Rect(kRootWidth
, kRootHeight
), kCSSOrange
);
83 // Orange child layers will blend with the green background
84 for (int i
= 0; i
< kBlendModesCount
; ++i
) {
86 (i
+ 1) * kLaneWidth
, kLaneWidth
, kLaneWidth
, kLaneHeight
);
87 scoped_refptr
<SolidColorLayer
> green_lane
=
88 CreateSolidColorLayer(child_rect
, kCSSGreen
);
89 background
->AddChild(green_lane
);
90 green_lane
->SetBlendMode(kBlendModes
[i
]);
95 base::FilePath(FILE_PATH_LITERAL("blending_with_root.png")));
98 void RunBlendingWithTransparentPixelTestType(PixelResourceTestCase type
) {
99 const int kLaneWidth
= 2;
100 const int kLaneHeight
= 3 * kLaneWidth
;
101 const int kRootWidth
= (kBlendModesCount
+ 2) * kLaneWidth
;
102 const int kRootHeight
= 2 * kLaneWidth
+ kLaneHeight
;
103 InitializeFromTestCase(type
);
105 scoped_refptr
<SolidColorLayer
> root
=
106 CreateSolidColorLayer(gfx::Rect(kRootWidth
, kRootHeight
), kCSSBrown
);
108 scoped_refptr
<SolidColorLayer
> background
= CreateSolidColorLayer(
109 gfx::Rect(0, kLaneWidth
* 2, kRootWidth
, kLaneWidth
), kCSSOrange
);
111 root
->AddChild(background
);
112 background
->SetIsRootForIsolatedGroup(true);
114 // Orange child layers will blend with the green background
115 for (int i
= 0; i
< kBlendModesCount
; ++i
) {
116 gfx::Rect
child_rect(
117 (i
+ 1) * kLaneWidth
, -kLaneWidth
, kLaneWidth
, kLaneHeight
);
118 scoped_refptr
<SolidColorLayer
> green_lane
=
119 CreateSolidColorLayer(child_rect
, kCSSGreen
);
120 background
->AddChild(green_lane
);
121 green_lane
->SetBlendMode(kBlendModes
[i
]);
124 RunPixelResourceTest(
125 root
, base::FilePath(FILE_PATH_LITERAL("blending_transparent.png")));
128 scoped_refptr
<Layer
> CreateColorfulBackdropLayer(int width
, int height
) {
129 // Draw the backdrop with horizontal lanes.
130 const int kLaneWidth
= width
;
131 const int kLaneHeight
= height
/ kCSSTestColorsCount
;
132 skia::RefPtr
<SkSurface
> backing_store
=
133 skia::AdoptRef(SkSurface::NewRasterN32Premul(width
, height
));
134 SkCanvas
* canvas
= backing_store
->getCanvas();
135 canvas
->clear(SK_ColorTRANSPARENT
);
136 for (int i
= 0; i
< kCSSTestColorsCount
; ++i
) {
138 paint
.setColor(kCSSTestColors
[i
]);
140 SkRect::MakeXYWH(0, i
* kLaneHeight
, kLaneWidth
, kLaneHeight
), paint
);
142 scoped_refptr
<PictureImageLayer
> layer
=
143 PictureImageLayer::Create(layer_settings());
144 layer
->SetIsDrawable(true);
145 layer
->SetBounds(gfx::Size(width
, height
));
146 skia::RefPtr
<const SkImage
> image
=
147 skia::AdoptRef(backing_store
->newImageSnapshot());
148 layer
->SetImage(image
.Pass());
152 void SetupMaskLayer(scoped_refptr
<Layer
> layer
) {
153 const int kMaskOffset
= 2;
154 gfx::Size bounds
= layer
->bounds();
155 scoped_refptr
<PictureImageLayer
> mask
=
156 PictureImageLayer::Create(layer_settings());
157 mask
->SetIsDrawable(true);
158 mask
->SetIsMask(true);
159 mask
->SetBounds(bounds
);
161 skia::RefPtr
<SkSurface
> surface
= skia::AdoptRef(
162 SkSurface::NewRasterN32Premul(bounds
.width(), bounds
.height()));
163 SkCanvas
* canvas
= surface
->getCanvas();
165 paint
.setColor(SK_ColorWHITE
);
166 canvas
->clear(SK_ColorTRANSPARENT
);
167 canvas
->drawRect(SkRect::MakeXYWH(kMaskOffset
, kMaskOffset
,
168 bounds
.width() - kMaskOffset
* 2,
169 bounds
.height() - kMaskOffset
* 2),
171 skia::RefPtr
<const SkImage
> image
=
172 skia::AdoptRef(surface
->newImageSnapshot());
173 mask
->SetImage(image
.Pass());
174 layer
->SetMaskLayer(mask
.get());
177 void SetupColorMatrix(scoped_refptr
<Layer
> layer
) {
178 FilterOperations filter_operations
;
179 filter_operations
.Append(FilterOperation::CreateSepiaFilter(.001f
));
180 layer
->SetFilters(filter_operations
);
183 void CreateBlendingColorLayers(int lane_width
,
185 scoped_refptr
<Layer
> background
,
186 RenderPassOptions flags
) {
187 const int kLanesCount
= kBlendModesCount
+ 4;
188 const SkColor kMiscOpaqueColor
= 0xffc86464;
189 const SkColor kMiscTransparentColor
= 0x80c86464;
190 const SkXfermode::Mode kCoeffBlendMode
= SkXfermode::kScreen_Mode
;
191 const SkXfermode::Mode kShaderBlendMode
= SkXfermode::kColorBurn_Mode
;
192 // add vertical lanes with each of the blend modes
193 for (int i
= 0; i
< kLanesCount
; ++i
) {
194 gfx::Rect
child_rect(i
* lane_width
, 0, lane_width
, lane_height
);
195 SkXfermode::Mode blend_mode
= SkXfermode::kSrcOver_Mode
;
197 SkColor color
= kMiscOpaqueColor
;
199 if (i
< kBlendModesCount
) {
200 blend_mode
= kBlendModes
[i
];
201 } else if (i
== kBlendModesCount
) {
202 blend_mode
= kCoeffBlendMode
;
204 } else if (i
== kBlendModesCount
+ 1) {
205 blend_mode
= kCoeffBlendMode
;
206 color
= kMiscTransparentColor
;
207 } else if (i
== kBlendModesCount
+ 2) {
208 blend_mode
= kShaderBlendMode
;
210 } else if (i
== kBlendModesCount
+ 3) {
211 blend_mode
= kShaderBlendMode
;
212 color
= kMiscTransparentColor
;
215 scoped_refptr
<SolidColorLayer
> lane
=
216 CreateSolidColorLayer(child_rect
, color
);
217 lane
->SetBlendMode(blend_mode
);
218 lane
->SetOpacity(opacity
);
219 lane
->SetForceRenderSurface(true);
220 if (flags
& kUseMasks
)
221 SetupMaskLayer(lane
);
222 if (flags
& kUseColorMatrix
) {
223 SetupColorMatrix(lane
);
225 background
->AddChild(lane
);
229 void RunBlendingWithRenderPass(PixelResourceTestCase type
,
230 const base::FilePath::CharType
* expected_path
,
231 RenderPassOptions flags
) {
232 const int kLaneWidth
= 8;
233 const int kLaneHeight
= kLaneWidth
* kCSSTestColorsCount
;
234 const int kRootSize
= kLaneHeight
;
235 InitializeFromTestCase(type
);
237 scoped_refptr
<SolidColorLayer
> root
=
238 CreateSolidColorLayer(gfx::Rect(kRootSize
, kRootSize
), SK_ColorWHITE
);
239 scoped_refptr
<Layer
> background
=
240 CreateColorfulBackdropLayer(kRootSize
, kRootSize
);
242 background
->SetIsRootForIsolatedGroup(true);
243 root
->AddChild(background
);
245 CreateBlendingColorLayers(kLaneWidth
, kLaneHeight
, background
.get(), flags
);
247 this->force_antialiasing_
= (flags
& kUseAntialiasing
);
248 this->force_blending_with_shaders_
= (flags
& kForceShaders
);
250 if ((flags
& kUseAntialiasing
) && (test_type_
== PIXEL_TEST_GL
)) {
251 // Anti aliasing causes differences up to 8 pixels at the edges.
252 int large_error_allowed
= 8;
253 // Blending results might differ with one pixel.
254 int small_error_allowed
= 1;
255 // Most of the errors are one pixel errors.
256 float percentage_pixels_small_error
= 13.1f
;
257 // Because of anti-aliasing, around 10% of pixels (at the edges) have
258 // bigger errors (from small_error_allowed + 1 to large_error_allowed).
259 float percentage_pixels_error
= 22.5f
;
260 // The average error is still close to 1.
261 float average_error_allowed_in_bad_pixels
= 1.4f
;
263 pixel_comparator_
.reset(
264 new FuzzyPixelComparator(false, // discard_alpha
265 percentage_pixels_error
,
266 percentage_pixels_small_error
,
267 average_error_allowed_in_bad_pixels
,
269 small_error_allowed
));
272 RunPixelResourceTest(root
, base::FilePath(expected_path
));
275 bool force_antialiasing_
;
276 bool force_blending_with_shaders_
;
279 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRoot_GL
) {
280 RunBlendingWithRootPixelTestType(GL_ASYNC_UPLOAD_2D_DRAW
);
283 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRoot_Software
) {
284 RunBlendingWithRootPixelTestType(SOFTWARE
);
287 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithBackgroundFilter
) {
288 const int kLaneWidth
= 2;
289 const int kLaneHeight
= kLaneWidth
;
290 const int kRootWidth
= (kBlendModesCount
+ 2) * kLaneWidth
;
291 const int kRootHeight
= 2 * kLaneWidth
+ kLaneHeight
;
292 InitializeFromTestCase(GL_ASYNC_UPLOAD_2D_DRAW
);
294 scoped_refptr
<SolidColorLayer
> background
=
295 CreateSolidColorLayer(gfx::Rect(kRootWidth
, kRootHeight
), kCSSOrange
);
297 // Orange child layers have a background filter set and they will blend with
298 // the green background
299 for (int i
= 0; i
< kBlendModesCount
; ++i
) {
300 gfx::Rect
child_rect(
301 (i
+ 1) * kLaneWidth
, kLaneWidth
, kLaneWidth
, kLaneHeight
);
302 scoped_refptr
<SolidColorLayer
> green_lane
=
303 CreateSolidColorLayer(child_rect
, kCSSGreen
);
304 background
->AddChild(green_lane
);
306 FilterOperations filters
;
307 filters
.Append(FilterOperation::CreateGrayscaleFilter(.75));
308 green_lane
->SetBackgroundFilters(filters
);
309 green_lane
->SetBlendMode(kBlendModes
[i
]);
312 RunPixelResourceTest(
313 background
, base::FilePath(FILE_PATH_LITERAL("blending_and_filter.png")));
316 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithTransparent_GL
) {
317 RunBlendingWithTransparentPixelTestType(GL_ASYNC_UPLOAD_2D_DRAW
);
320 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithTransparent_Software
) {
321 RunBlendingWithTransparentPixelTestType(SOFTWARE
);
324 // Tests for render passes
325 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPass_GL
) {
326 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
327 FILE_PATH_LITERAL("blending_render_pass.png"), 0);
330 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPass_Software
) {
331 RunBlendingWithRenderPass(SOFTWARE
,
332 FILE_PATH_LITERAL("blending_render_pass.png"), 0);
335 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassAA_GL
) {
336 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
337 FILE_PATH_LITERAL("blending_render_pass.png"),
341 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassAA_Software
) {
342 RunBlendingWithRenderPass(SOFTWARE
,
343 FILE_PATH_LITERAL("blending_render_pass.png"),
347 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassWithMask_GL
) {
348 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
349 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
353 TEST_F(LayerTreeHostBlendingPixelTest
,
354 BlendingWithRenderPassWithMask_Software
) {
355 RunBlendingWithRenderPass(
356 SOFTWARE
, FILE_PATH_LITERAL("blending_render_pass_mask.png"), kUseMasks
);
359 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassWithMaskAA_GL
) {
360 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
361 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
362 kUseMasks
| kUseAntialiasing
);
365 TEST_F(LayerTreeHostBlendingPixelTest
,
366 BlendingWithRenderPassWithMaskAA_Software
) {
367 RunBlendingWithRenderPass(SOFTWARE
,
368 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
369 kUseMasks
| kUseAntialiasing
);
372 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassColorMatrix_GL
) {
373 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
374 FILE_PATH_LITERAL("blending_render_pass.png"),
378 TEST_F(LayerTreeHostBlendingPixelTest
,
379 BlendingWithRenderPassColorMatrix_Software
) {
380 RunBlendingWithRenderPass(
381 SOFTWARE
, FILE_PATH_LITERAL("blending_render_pass.png"), kUseColorMatrix
);
384 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassColorMatrixAA_GL
) {
385 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
386 FILE_PATH_LITERAL("blending_render_pass.png"),
387 kUseAntialiasing
| kUseColorMatrix
);
390 TEST_F(LayerTreeHostBlendingPixelTest
,
391 BlendingWithRenderPassColorMatrixAA_Software
) {
392 RunBlendingWithRenderPass(SOFTWARE
,
393 FILE_PATH_LITERAL("blending_render_pass.png"),
394 kUseAntialiasing
| kUseColorMatrix
);
397 TEST_F(LayerTreeHostBlendingPixelTest
,
398 BlendingWithRenderPassWithMaskColorMatrix_GL
) {
399 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
400 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
401 kUseMasks
| kUseColorMatrix
);
404 TEST_F(LayerTreeHostBlendingPixelTest
,
405 BlendingWithRenderPassWithMaskColorMatrix_Software
) {
406 RunBlendingWithRenderPass(SOFTWARE
,
407 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
408 kUseMasks
| kUseColorMatrix
);
411 TEST_F(LayerTreeHostBlendingPixelTest
,
412 BlendingWithRenderPassWithMaskColorMatrixAA_GL
) {
413 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
414 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
415 kUseMasks
| kUseAntialiasing
| kUseColorMatrix
);
418 TEST_F(LayerTreeHostBlendingPixelTest
,
419 BlendingWithRenderPassWithMaskColorMatrixAA_Software
) {
420 RunBlendingWithRenderPass(SOFTWARE
,
421 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
422 kUseMasks
| kUseAntialiasing
| kUseColorMatrix
);
425 // Tests for render passes forcing shaders for all the blend modes.
426 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassShaders_GL
) {
427 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
428 FILE_PATH_LITERAL("blending_render_pass.png"),
432 TEST_F(LayerTreeHostBlendingPixelTest
, BlendingWithRenderPassShadersAA_GL
) {
433 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
434 FILE_PATH_LITERAL("blending_render_pass.png"),
435 kUseAntialiasing
| kForceShaders
);
438 TEST_F(LayerTreeHostBlendingPixelTest
,
439 BlendingWithRenderPassShadersWithMask_GL
) {
440 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
441 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
442 kUseMasks
| kForceShaders
);
445 TEST_F(LayerTreeHostBlendingPixelTest
,
446 BlendingWithRenderPassShadersWithMask_GL_TextureRect
) {
447 RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW
,
448 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
449 kUseMasks
| kForceShaders
);
452 TEST_F(LayerTreeHostBlendingPixelTest
,
453 BlendingWithRenderPassShadersWithMaskAA_GL
) {
454 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
455 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
456 kUseMasks
| kUseAntialiasing
| kForceShaders
);
459 TEST_F(LayerTreeHostBlendingPixelTest
,
460 BlendingWithRenderPassShadersWithMaskAA_GL_TextureRect
) {
461 RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW
,
462 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
463 kUseMasks
| kUseAntialiasing
| kForceShaders
);
466 TEST_F(LayerTreeHostBlendingPixelTest
,
467 BlendingWithRenderPassShadersColorMatrix_GL
) {
468 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
469 FILE_PATH_LITERAL("blending_render_pass.png"),
470 kUseColorMatrix
| kForceShaders
);
473 TEST_F(LayerTreeHostBlendingPixelTest
,
474 BlendingWithRenderPassShadersColorMatrixAA_GL
) {
475 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
476 FILE_PATH_LITERAL("blending_render_pass.png"),
477 kUseAntialiasing
| kUseColorMatrix
| kForceShaders
);
480 TEST_F(LayerTreeHostBlendingPixelTest
,
481 BlendingWithRenderPassShadersWithMaskColorMatrix_GL
) {
482 RunBlendingWithRenderPass(GL_ASYNC_UPLOAD_2D_DRAW
,
483 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
484 kUseMasks
| kUseColorMatrix
| kForceShaders
);
487 TEST_F(LayerTreeHostBlendingPixelTest
,
488 BlendingWithRenderPassShadersWithMaskColorMatrix_GL_TextureRect
) {
489 RunBlendingWithRenderPass(GL_ZERO_COPY_RECT_DRAW
,
490 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
491 kUseMasks
| kUseColorMatrix
| kForceShaders
);
494 TEST_F(LayerTreeHostBlendingPixelTest
,
495 BlendingWithRenderPassShadersWithMaskColorMatrixAA_GL
) {
496 RunBlendingWithRenderPass(
497 GL_ASYNC_UPLOAD_2D_DRAW
,
498 FILE_PATH_LITERAL("blending_render_pass_mask.png"),
499 kUseMasks
| kUseAntialiasing
| kUseColorMatrix
| kForceShaders
);