OLD | NEW |
1 // Copyright 2013 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
| 5 #include "cc/layers/image_layer.h" |
5 #include "cc/layers/solid_color_layer.h" | 6 #include "cc/layers/solid_color_layer.h" |
6 #include "cc/layers/texture_layer.h" | |
7 #include "cc/test/layer_tree_pixel_test.h" | 7 #include "cc/test/layer_tree_pixel_test.h" |
8 #include "cc/test/pixel_comparator.h" | 8 #include "cc/test/pixel_comparator.h" |
9 | 9 |
10 #if !defined(OS_ANDROID) | 10 #if !defined(OS_ANDROID) |
11 | 11 |
12 namespace cc { | 12 namespace cc { |
13 namespace { | 13 namespace { |
14 | 14 |
15 SkXfermode::Mode const kBlendModes[] = { | 15 SkXfermode::Mode const kBlendModes[] = { |
16 SkXfermode::kSrcOver_Mode, SkXfermode::kScreen_Mode, | 16 SkXfermode::kSrcOver_Mode, SkXfermode::kScreen_Mode, |
17 SkXfermode::kOverlay_Mode, SkXfermode::kDarken_Mode, | 17 SkXfermode::kOverlay_Mode, SkXfermode::kDarken_Mode, |
18 SkXfermode::kLighten_Mode, SkXfermode::kColorDodge_Mode, | 18 SkXfermode::kLighten_Mode, SkXfermode::kColorDodge_Mode, |
19 SkXfermode::kColorBurn_Mode, SkXfermode::kHardLight_Mode, | 19 SkXfermode::kColorBurn_Mode, SkXfermode::kHardLight_Mode, |
20 SkXfermode::kSoftLight_Mode, SkXfermode::kDifference_Mode, | 20 SkXfermode::kSoftLight_Mode, SkXfermode::kDifference_Mode, |
21 SkXfermode::kExclusion_Mode, SkXfermode::kMultiply_Mode, | 21 SkXfermode::kExclusion_Mode, SkXfermode::kMultiply_Mode, |
22 SkXfermode::kHue_Mode, SkXfermode::kSaturation_Mode, | 22 SkXfermode::kHue_Mode, SkXfermode::kSaturation_Mode, |
23 SkXfermode::kColor_Mode, SkXfermode::kLuminosity_Mode}; | 23 SkXfermode::kColor_Mode, SkXfermode::kLuminosity_Mode}; |
24 | 24 |
| 25 SkColor kCSSTestColors[] = { |
| 26 0xffff0000, // red |
| 27 0xff00ff00, // lime |
| 28 0xff0000ff, // blue |
| 29 0xff00ffff, // aqua |
| 30 0xffff00ff, // fuchsia |
| 31 0xffffff00, // yellow |
| 32 0xff008000, // green |
| 33 0xff800000, // maroon |
| 34 0xff000080, // navy |
| 35 0xff800080, // purple |
| 36 0xff808000, // olive |
| 37 0xff008080, // teal |
| 38 0xfffa8072, // salmon |
| 39 0xffc0c0c0, // silver |
| 40 0xff000000, // black |
| 41 0xff808080, // gray |
| 42 0x80000000, // black with transparency |
| 43 0xffffffff, // white |
| 44 0x80ffffff, // white with transparency |
| 45 0x00000000 // transparent |
| 46 }; |
| 47 |
25 const int kBlendModesCount = arraysize(kBlendModes); | 48 const int kBlendModesCount = arraysize(kBlendModes); |
| 49 const int kCSSTestColorsCount = arraysize(kCSSTestColors); |
| 50 |
| 51 using RenderPassOptions = uint32; |
| 52 const uint32 kUseMasks = 1 << 0; |
| 53 const uint32 kUseAntialiasing = 1 << 1; |
| 54 const uint32 kUseColorMatrix = 1 << 2; |
26 | 55 |
27 class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest { | 56 class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest { |
28 public: | 57 public: |
29 LayerTreeHostBlendingPixelTest() { | 58 LayerTreeHostBlendingPixelTest() { |
30 pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true)); | 59 pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true)); |
31 } | 60 } |
32 | 61 |
| 62 virtual void InitializeSettings(LayerTreeSettings* settings) override { |
| 63 settings->force_antialiasing = force_antialiasing_; |
| 64 } |
| 65 |
33 protected: | 66 protected: |
34 void RunBlendingWithRootPixelTestType(PixelTestType type) { | 67 void RunBlendingWithRootPixelTestType(PixelTestType type) { |
35 const int kLaneWidth = 15; | 68 const int kLaneWidth = 15; |
36 const int kLaneHeight = kBlendModesCount * kLaneWidth; | 69 const int kLaneHeight = kBlendModesCount * kLaneWidth; |
37 const int kRootSize = (kBlendModesCount + 2) * kLaneWidth; | 70 const int kRootSize = (kBlendModesCount + 2) * kLaneWidth; |
38 | 71 |
39 scoped_refptr<SolidColorLayer> background = | 72 scoped_refptr<SolidColorLayer> background = |
40 CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange); | 73 CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), kCSSOrange); |
41 | 74 |
42 // Orange child layers will blend with the green background | 75 // Orange child layers will blend with the green background |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
75 scoped_refptr<SolidColorLayer> green_lane = | 108 scoped_refptr<SolidColorLayer> green_lane = |
76 CreateSolidColorLayer(child_rect, kCSSGreen); | 109 CreateSolidColorLayer(child_rect, kCSSGreen); |
77 background->AddChild(green_lane); | 110 background->AddChild(green_lane); |
78 green_lane->SetBlendMode(kBlendModes[i]); | 111 green_lane->SetBlendMode(kBlendModes[i]); |
79 } | 112 } |
80 | 113 |
81 RunPixelTest(type, | 114 RunPixelTest(type, |
82 root, | 115 root, |
83 base::FilePath(FILE_PATH_LITERAL("blending_transparent.png"))); | 116 base::FilePath(FILE_PATH_LITERAL("blending_transparent.png"))); |
84 } | 117 } |
| 118 |
| 119 scoped_refptr<Layer> CreateColorfulBackdropLayer(int width, int height) { |
| 120 // Draw the backdrop with horizontal lanes. |
| 121 const int kLaneWidth = width; |
| 122 const int kLaneHeight = height / kCSSTestColorsCount; |
| 123 SkBitmap backing_store; |
| 124 backing_store.allocN32Pixels(width, height); |
| 125 SkCanvas canvas(backing_store); |
| 126 canvas.clear(SK_ColorTRANSPARENT); |
| 127 for (int i = 0; i < kCSSTestColorsCount; ++i) { |
| 128 SkPaint paint; |
| 129 paint.setColor(kCSSTestColors[i]); |
| 130 canvas.drawRect( |
| 131 SkRect::MakeXYWH(0, i * kLaneHeight, kLaneWidth, kLaneHeight), paint); |
| 132 } |
| 133 scoped_refptr<ImageLayer> layer = ImageLayer::Create(); |
| 134 layer->SetIsDrawable(true); |
| 135 layer->SetBounds(gfx::Size(width, height)); |
| 136 layer->SetBitmap(backing_store); |
| 137 return layer; |
| 138 } |
| 139 |
| 140 void SetupMaskLayer(scoped_refptr<Layer> layer) { |
| 141 const int kMaskOffset = 5; |
| 142 gfx::Size bounds = layer->bounds(); |
| 143 scoped_refptr<ImageLayer> mask = ImageLayer::Create(); |
| 144 mask->SetIsDrawable(true); |
| 145 mask->SetIsMask(true); |
| 146 mask->SetBounds(bounds); |
| 147 |
| 148 SkBitmap bitmap; |
| 149 bitmap.allocN32Pixels(bounds.width(), bounds.height()); |
| 150 SkCanvas canvas(bitmap); |
| 151 SkPaint paint; |
| 152 paint.setColor(SK_ColorWHITE); |
| 153 canvas.clear(SK_ColorTRANSPARENT); |
| 154 canvas.drawRect(SkRect::MakeXYWH(kMaskOffset, |
| 155 kMaskOffset, |
| 156 bounds.width() - kMaskOffset * 2, |
| 157 bounds.height() - kMaskOffset * 2), |
| 158 paint); |
| 159 mask->SetBitmap(bitmap); |
| 160 layer->SetMaskLayer(mask.get()); |
| 161 } |
| 162 |
| 163 void SetupColorMatrix(scoped_refptr<Layer> layer) { |
| 164 FilterOperations filter_operations; |
| 165 filter_operations.Append(FilterOperation::CreateSepiaFilter(1.f)); |
| 166 layer->SetFilters(filter_operations); |
| 167 } |
| 168 |
| 169 void CreateBlendingColorLayers(int width, |
| 170 int height, |
| 171 scoped_refptr<Layer> background, |
| 172 RenderPassOptions flags) { |
| 173 const int kLanesCount = kBlendModesCount + 4; |
| 174 int lane_width = width / kLanesCount; |
| 175 const SkColor kMiscOpaqueColor = 0xffc86464; |
| 176 const SkColor kMiscTransparentColor = 0x80c86464; |
| 177 const SkXfermode::Mode kCoeffBlendMode = SkXfermode::kScreen_Mode; |
| 178 const SkXfermode::Mode kShaderBlendMode = SkXfermode::kColorBurn_Mode; |
| 179 // add vertical lanes with each of the blend modes |
| 180 for (int i = 0; i < kLanesCount; ++i) { |
| 181 gfx::Rect child_rect(i * lane_width, 0, lane_width, height); |
| 182 SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode; |
| 183 float opacity = 1.f; |
| 184 SkColor color = kMiscOpaqueColor; |
| 185 |
| 186 if (i < kBlendModesCount) { |
| 187 blend_mode = kBlendModes[i]; |
| 188 } else if (i == kBlendModesCount) { |
| 189 blend_mode = kCoeffBlendMode; |
| 190 opacity = 0.5f; |
| 191 } else if (i == kBlendModesCount + 1) { |
| 192 blend_mode = kCoeffBlendMode; |
| 193 color = kMiscTransparentColor; |
| 194 } else if (i == kBlendModesCount + 2) { |
| 195 blend_mode = kShaderBlendMode; |
| 196 opacity = 0.5f; |
| 197 } else if (i == kBlendModesCount + 3) { |
| 198 blend_mode = kShaderBlendMode; |
| 199 color = kMiscTransparentColor; |
| 200 } |
| 201 |
| 202 scoped_refptr<SolidColorLayer> lane = |
| 203 CreateSolidColorLayer(child_rect, color); |
| 204 lane->SetBlendMode(blend_mode); |
| 205 lane->SetOpacity(opacity); |
| 206 lane->SetForceRenderSurface(true); |
| 207 if (flags & kUseMasks) |
| 208 SetupMaskLayer(lane); |
| 209 if (flags & kUseColorMatrix) { |
| 210 SetupColorMatrix(lane); |
| 211 } |
| 212 background->AddChild(lane); |
| 213 } |
| 214 } |
| 215 |
| 216 void RunBlendingWithRenderPass(PixelTestType type, |
| 217 const base::FilePath::CharType* expected_path, |
| 218 RenderPassOptions flags) { |
| 219 const int kRootSize = 400; |
| 220 |
| 221 scoped_refptr<SolidColorLayer> root = |
| 222 CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), SK_ColorWHITE); |
| 223 scoped_refptr<Layer> background = |
| 224 CreateColorfulBackdropLayer(kRootSize, kRootSize); |
| 225 |
| 226 background->SetIsRootForIsolatedGroup(true); |
| 227 root->AddChild(background); |
| 228 |
| 229 CreateBlendingColorLayers(kRootSize, kRootSize, background.get(), flags); |
| 230 |
| 231 this->impl_side_painting_ = false; |
| 232 this->force_antialiasing_ = (flags & kUseAntialiasing); |
| 233 |
| 234 if ((flags & kUseAntialiasing) && (type == GL_WITH_BITMAP)) { |
| 235 // Anti aliasing causes differences up to 7 pixels at the edges. |
| 236 int large_error_allowed = 7; |
| 237 // Blending results might differ with one pixel. |
| 238 int small_error_allowed = 1; |
| 239 // Most of the errors are one pixel errors. |
| 240 float percentage_pixels_small_error = 12.5f; |
| 241 // Because of anti-aliasing, around 3% of pixels (at the edges) have |
| 242 // bigger errors (from small_error_allowed + 1 to large_error_allowed). |
| 243 float percentage_pixels_error = 15.0f; |
| 244 // The average error is still close to 1. |
| 245 float average_error_allowed_in_bad_pixels = 1.3f; |
| 246 |
| 247 // The sepia filter generates more small errors, but the number of large |
| 248 // errors remains around 3%. |
| 249 if (flags & kUseColorMatrix) { |
| 250 percentage_pixels_small_error = 26.f; |
| 251 percentage_pixels_error = 29.f; |
| 252 } |
| 253 |
| 254 // Anti-aliased pixels in combination with non-separable blend modes and |
| 255 // a white background produces several black pixels (6 for these tests). |
| 256 // Having a mask will hide the black pixels. |
| 257 // TODO(rosca): fix this issue for non-separable blend modes. |
| 258 if (!(flags & kUseMasks)) |
| 259 large_error_allowed = 255; |
| 260 |
| 261 pixel_comparator_.reset( |
| 262 new FuzzyPixelComparator(false, // discard_alpha |
| 263 percentage_pixels_error, |
| 264 percentage_pixels_small_error, |
| 265 average_error_allowed_in_bad_pixels, |
| 266 large_error_allowed, |
| 267 small_error_allowed)); |
| 268 } else if ((flags & kUseColorMatrix) && (type == GL_WITH_BITMAP)) { |
| 269 float percentage_pixels_error = 100.f; |
| 270 float percentage_pixels_small_error = 0.f; |
| 271 float average_error_allowed_in_bad_pixels = 1.f; |
| 272 int large_error_allowed = 2; |
| 273 int small_error_allowed = 0; |
| 274 pixel_comparator_.reset( |
| 275 new FuzzyPixelComparator(false, // discard_alpha |
| 276 percentage_pixels_error, |
| 277 percentage_pixels_small_error, |
| 278 average_error_allowed_in_bad_pixels, |
| 279 large_error_allowed, |
| 280 small_error_allowed)); |
| 281 } |
| 282 |
| 283 RunPixelTest(type, root, base::FilePath(expected_path)); |
| 284 } |
| 285 |
| 286 bool force_antialiasing_ = false; |
85 }; | 287 }; |
86 | 288 |
87 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) { | 289 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) { |
88 RunBlendingWithRootPixelTestType(GL_WITH_BITMAP); | 290 RunBlendingWithRootPixelTestType(GL_WITH_BITMAP); |
89 } | 291 } |
90 | 292 |
91 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_Software) { | 293 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_Software) { |
92 RunBlendingWithRootPixelTestType(SOFTWARE_WITH_BITMAP); | 294 RunBlendingWithRootPixelTestType(SOFTWARE_WITH_BITMAP); |
93 } | 295 } |
94 | 296 |
(...skipping 26 matching lines...) Expand all Loading... |
121 } | 323 } |
122 | 324 |
123 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_GL) { | 325 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_GL) { |
124 RunBlendingWithTransparentPixelTestType(GL_WITH_BITMAP); | 326 RunBlendingWithTransparentPixelTestType(GL_WITH_BITMAP); |
125 } | 327 } |
126 | 328 |
127 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_Software) { | 329 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_Software) { |
128 RunBlendingWithTransparentPixelTestType(SOFTWARE_WITH_BITMAP); | 330 RunBlendingWithTransparentPixelTestType(SOFTWARE_WITH_BITMAP); |
129 } | 331 } |
130 | 332 |
| 333 // Tests for render passes |
| 334 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_GL) { |
| 335 RunBlendingWithRenderPass( |
| 336 GL_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0); |
| 337 } |
| 338 |
| 339 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_Software) { |
| 340 RunBlendingWithRenderPass( |
| 341 SOFTWARE_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0); |
| 342 } |
| 343 |
| 344 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_GL) { |
| 345 RunBlendingWithRenderPass(GL_WITH_BITMAP, |
| 346 FILE_PATH_LITERAL("blending_render_pass.png"), |
| 347 kUseAntialiasing); |
| 348 } |
| 349 |
| 350 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_Software) { |
| 351 RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP, |
| 352 FILE_PATH_LITERAL("blending_render_pass.png"), |
| 353 kUseAntialiasing); |
| 354 } |
| 355 |
| 356 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMask_GL) { |
| 357 RunBlendingWithRenderPass(GL_WITH_BITMAP, |
| 358 FILE_PATH_LITERAL("blending_render_pass_mask.png"), |
| 359 kUseMasks); |
| 360 } |
| 361 |
| 362 TEST_F(LayerTreeHostBlendingPixelTest, |
| 363 BlendingWithRenderPassWithMask_Software) { |
| 364 RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP, |
| 365 FILE_PATH_LITERAL("blending_render_pass_mask.png"), |
| 366 kUseMasks); |
| 367 } |
| 368 |
| 369 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskAA_GL) { |
| 370 RunBlendingWithRenderPass(GL_WITH_BITMAP, |
| 371 FILE_PATH_LITERAL("blending_render_pass_mask.png"), |
| 372 kUseMasks | kUseAntialiasing); |
| 373 } |
| 374 |
| 375 TEST_F(LayerTreeHostBlendingPixelTest, |
| 376 BlendingWithRenderPassWithMaskAA_Software) { |
| 377 RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP, |
| 378 FILE_PATH_LITERAL("blending_render_pass_mask.png"), |
| 379 kUseMasks | kUseAntialiasing); |
| 380 } |
| 381 |
| 382 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) { |
| 383 RunBlendingWithRenderPass(GL_WITH_BITMAP, |
| 384 FILE_PATH_LITERAL("blending_render_pass_cm.png"), |
| 385 kUseColorMatrix); |
| 386 } |
| 387 |
| 388 TEST_F(LayerTreeHostBlendingPixelTest, |
| 389 BlendingWithRenderPassColorMatrix_Software) { |
| 390 RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP, |
| 391 FILE_PATH_LITERAL("blending_render_pass_cm.png"), |
| 392 kUseColorMatrix); |
| 393 } |
| 394 |
| 395 TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) { |
| 396 RunBlendingWithRenderPass(GL_WITH_BITMAP, |
| 397 FILE_PATH_LITERAL("blending_render_pass_cm.png"), |
| 398 kUseAntialiasing | kUseColorMatrix); |
| 399 } |
| 400 |
| 401 TEST_F(LayerTreeHostBlendingPixelTest, |
| 402 BlendingWithRenderPassColorMatrixAA_Software) { |
| 403 RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP, |
| 404 FILE_PATH_LITERAL("blending_render_pass_cm.png"), |
| 405 kUseAntialiasing | kUseColorMatrix); |
| 406 } |
| 407 |
| 408 TEST_F(LayerTreeHostBlendingPixelTest, |
| 409 BlendingWithRenderPassWithMaskColorMatrix_GL) { |
| 410 RunBlendingWithRenderPass( |
| 411 GL_WITH_BITMAP, |
| 412 FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"), |
| 413 kUseMasks | kUseColorMatrix); |
| 414 } |
| 415 |
| 416 TEST_F(LayerTreeHostBlendingPixelTest, |
| 417 BlendingWithRenderPassWithMaskColorMatrix_Software) { |
| 418 RunBlendingWithRenderPass( |
| 419 SOFTWARE_WITH_BITMAP, |
| 420 FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"), |
| 421 kUseMasks | kUseColorMatrix); |
| 422 } |
| 423 |
| 424 TEST_F(LayerTreeHostBlendingPixelTest, |
| 425 BlendingWithRenderPassWithMaskColorMatrixAA_GL) { |
| 426 RunBlendingWithRenderPass( |
| 427 GL_WITH_BITMAP, |
| 428 FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"), |
| 429 kUseMasks | kUseAntialiasing | kUseColorMatrix); |
| 430 } |
| 431 |
| 432 TEST_F(LayerTreeHostBlendingPixelTest, |
| 433 BlendingWithRenderPassWithMaskColorMatrixAA_Software) { |
| 434 RunBlendingWithRenderPass( |
| 435 SOFTWARE_WITH_BITMAP, |
| 436 FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"), |
| 437 kUseMasks | kUseAntialiasing | kUseColorMatrix); |
| 438 } |
| 439 |
131 } // namespace | 440 } // namespace |
132 } // namespace cc | 441 } // namespace cc |
133 | 442 |
134 #endif // OS_ANDROID | 443 #endif // OS_ANDROID |
OLD | NEW |