| Index: cc/trees/layer_tree_host_pixeltest_blending.cc
|
| diff --git a/cc/trees/layer_tree_host_pixeltest_blending.cc b/cc/trees/layer_tree_host_pixeltest_blending.cc
|
| index f01d426c614d58e2ac8d0b7808e0a0778bd02f9f..bebd6121ad72dec3c9576027686f2a63ddcb0843 100644
|
| --- a/cc/trees/layer_tree_host_pixeltest_blending.cc
|
| +++ b/cc/trees/layer_tree_host_pixeltest_blending.cc
|
| @@ -2,8 +2,8 @@
|
| // Use of this source code is governed by a BSD-style license that can be
|
| // found in the LICENSE file.
|
|
|
| +#include "cc/layers/image_layer.h"
|
| #include "cc/layers/solid_color_layer.h"
|
| -#include "cc/layers/texture_layer.h"
|
| #include "cc/test/layer_tree_pixel_test.h"
|
| #include "cc/test/pixel_comparator.h"
|
|
|
| @@ -22,7 +22,36 @@ SkXfermode::Mode const kBlendModes[] = {
|
| SkXfermode::kHue_Mode, SkXfermode::kSaturation_Mode,
|
| SkXfermode::kColor_Mode, SkXfermode::kLuminosity_Mode};
|
|
|
| +SkColor kCSSTestColors[] = {
|
| + 0xffff0000, // red
|
| + 0xff00ff00, // lime
|
| + 0xff0000ff, // blue
|
| + 0xff00ffff, // aqua
|
| + 0xffff00ff, // fuchsia
|
| + 0xffffff00, // yellow
|
| + 0xff008000, // green
|
| + 0xff800000, // maroon
|
| + 0xff000080, // navy
|
| + 0xff800080, // purple
|
| + 0xff808000, // olive
|
| + 0xff008080, // teal
|
| + 0xfffa8072, // salmon
|
| + 0xffc0c0c0, // silver
|
| + 0xff000000, // black
|
| + 0xff808080, // gray
|
| + 0x80000000, // black with transparency
|
| + 0xffffffff, // white
|
| + 0x80ffffff, // white with transparency
|
| + 0x00000000 // transparent
|
| +};
|
| +
|
| const int kBlendModesCount = arraysize(kBlendModes);
|
| +const int kCSSTestColorsCount = arraysize(kCSSTestColors);
|
| +
|
| +using RenderPassOptions = uint32;
|
| +const uint32 kUseMasks = 1 << 0;
|
| +const uint32 kUseAntialiasing = 1 << 1;
|
| +const uint32 kUseColorMatrix = 1 << 2;
|
|
|
| class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
|
| public:
|
| @@ -30,6 +59,10 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
|
| pixel_comparator_.reset(new FuzzyPixelOffByOneComparator(true));
|
| }
|
|
|
| + virtual void InitializeSettings(LayerTreeSettings* settings) override {
|
| + settings->force_antialiasing = force_antialiasing_;
|
| + }
|
| +
|
| protected:
|
| void RunBlendingWithRootPixelTestType(PixelTestType type) {
|
| const int kLaneWidth = 15;
|
| @@ -82,6 +115,175 @@ class LayerTreeHostBlendingPixelTest : public LayerTreePixelTest {
|
| root,
|
| base::FilePath(FILE_PATH_LITERAL("blending_transparent.png")));
|
| }
|
| +
|
| + scoped_refptr<Layer> CreateColorfulBackdropLayer(int width, int height) {
|
| + // Draw the backdrop with horizontal lanes.
|
| + const int kLaneWidth = width;
|
| + const int kLaneHeight = height / kCSSTestColorsCount;
|
| + SkBitmap backing_store;
|
| + backing_store.allocN32Pixels(width, height);
|
| + SkCanvas canvas(backing_store);
|
| + canvas.clear(SK_ColorTRANSPARENT);
|
| + for (int i = 0; i < kCSSTestColorsCount; ++i) {
|
| + SkPaint paint;
|
| + paint.setColor(kCSSTestColors[i]);
|
| + canvas.drawRect(
|
| + SkRect::MakeXYWH(0, i * kLaneHeight, kLaneWidth, kLaneHeight), paint);
|
| + }
|
| + scoped_refptr<ImageLayer> layer = ImageLayer::Create();
|
| + layer->SetIsDrawable(true);
|
| + layer->SetBounds(gfx::Size(width, height));
|
| + layer->SetBitmap(backing_store);
|
| + return layer;
|
| + }
|
| +
|
| + void SetupMaskLayer(scoped_refptr<Layer> layer) {
|
| + const int kMaskOffset = 5;
|
| + gfx::Size bounds = layer->bounds();
|
| + scoped_refptr<ImageLayer> mask = ImageLayer::Create();
|
| + mask->SetIsDrawable(true);
|
| + mask->SetIsMask(true);
|
| + mask->SetBounds(bounds);
|
| +
|
| + SkBitmap bitmap;
|
| + bitmap.allocN32Pixels(bounds.width(), bounds.height());
|
| + SkCanvas canvas(bitmap);
|
| + SkPaint paint;
|
| + paint.setColor(SK_ColorWHITE);
|
| + canvas.clear(SK_ColorTRANSPARENT);
|
| + canvas.drawRect(SkRect::MakeXYWH(kMaskOffset,
|
| + kMaskOffset,
|
| + bounds.width() - kMaskOffset * 2,
|
| + bounds.height() - kMaskOffset * 2),
|
| + paint);
|
| + mask->SetBitmap(bitmap);
|
| + layer->SetMaskLayer(mask.get());
|
| + }
|
| +
|
| + void SetupColorMatrix(scoped_refptr<Layer> layer) {
|
| + FilterOperations filter_operations;
|
| + filter_operations.Append(FilterOperation::CreateSepiaFilter(1.f));
|
| + layer->SetFilters(filter_operations);
|
| + }
|
| +
|
| + void CreateBlendingColorLayers(int width,
|
| + int height,
|
| + scoped_refptr<Layer> background,
|
| + RenderPassOptions flags) {
|
| + const int kLanesCount = kBlendModesCount + 4;
|
| + int lane_width = width / kLanesCount;
|
| + const SkColor kMiscOpaqueColor = 0xffc86464;
|
| + const SkColor kMiscTransparentColor = 0x80c86464;
|
| + const SkXfermode::Mode kCoeffBlendMode = SkXfermode::kScreen_Mode;
|
| + const SkXfermode::Mode kShaderBlendMode = SkXfermode::kColorBurn_Mode;
|
| + // add vertical lanes with each of the blend modes
|
| + for (int i = 0; i < kLanesCount; ++i) {
|
| + gfx::Rect child_rect(i * lane_width, 0, lane_width, height);
|
| + SkXfermode::Mode blend_mode = SkXfermode::kSrcOver_Mode;
|
| + float opacity = 1.f;
|
| + SkColor color = kMiscOpaqueColor;
|
| +
|
| + if (i < kBlendModesCount) {
|
| + blend_mode = kBlendModes[i];
|
| + } else if (i == kBlendModesCount) {
|
| + blend_mode = kCoeffBlendMode;
|
| + opacity = 0.5f;
|
| + } else if (i == kBlendModesCount + 1) {
|
| + blend_mode = kCoeffBlendMode;
|
| + color = kMiscTransparentColor;
|
| + } else if (i == kBlendModesCount + 2) {
|
| + blend_mode = kShaderBlendMode;
|
| + opacity = 0.5f;
|
| + } else if (i == kBlendModesCount + 3) {
|
| + blend_mode = kShaderBlendMode;
|
| + color = kMiscTransparentColor;
|
| + }
|
| +
|
| + scoped_refptr<SolidColorLayer> lane =
|
| + CreateSolidColorLayer(child_rect, color);
|
| + lane->SetBlendMode(blend_mode);
|
| + lane->SetOpacity(opacity);
|
| + lane->SetForceRenderSurface(true);
|
| + if (flags & kUseMasks)
|
| + SetupMaskLayer(lane);
|
| + if (flags & kUseColorMatrix) {
|
| + SetupColorMatrix(lane);
|
| + }
|
| + background->AddChild(lane);
|
| + }
|
| + }
|
| +
|
| + void RunBlendingWithRenderPass(PixelTestType type,
|
| + const base::FilePath::CharType* expected_path,
|
| + RenderPassOptions flags) {
|
| + const int kRootSize = 400;
|
| +
|
| + scoped_refptr<SolidColorLayer> root =
|
| + CreateSolidColorLayer(gfx::Rect(kRootSize, kRootSize), SK_ColorWHITE);
|
| + scoped_refptr<Layer> background =
|
| + CreateColorfulBackdropLayer(kRootSize, kRootSize);
|
| +
|
| + background->SetIsRootForIsolatedGroup(true);
|
| + root->AddChild(background);
|
| +
|
| + CreateBlendingColorLayers(kRootSize, kRootSize, background.get(), flags);
|
| +
|
| + this->impl_side_painting_ = false;
|
| + this->force_antialiasing_ = (flags & kUseAntialiasing);
|
| +
|
| + if ((flags & kUseAntialiasing) && (type == GL_WITH_BITMAP)) {
|
| + // Anti aliasing causes differences up to 7 pixels at the edges.
|
| + int large_error_allowed = 7;
|
| + // Blending results might differ with one pixel.
|
| + int small_error_allowed = 1;
|
| + // Most of the errors are one pixel errors.
|
| + float percentage_pixels_small_error = 12.5f;
|
| + // Because of anti-aliasing, around 3% of pixels (at the edges) have
|
| + // bigger errors (from small_error_allowed + 1 to large_error_allowed).
|
| + float percentage_pixels_error = 15.0f;
|
| + // The average error is still close to 1.
|
| + float average_error_allowed_in_bad_pixels = 1.3f;
|
| +
|
| + // The sepia filter generates more small errors, but the number of large
|
| + // errors remains around 3%.
|
| + if (flags & kUseColorMatrix) {
|
| + percentage_pixels_small_error = 26.f;
|
| + percentage_pixels_error = 29.f;
|
| + }
|
| +
|
| + // Anti-aliased pixels in combination with non-separable blend modes and
|
| + // a white background produces several black pixels (6 for these tests).
|
| + // Having a mask will hide the black pixels.
|
| + // TODO(rosca): fix this issue for non-separable blend modes.
|
| + if (!(flags & kUseMasks))
|
| + large_error_allowed = 255;
|
| +
|
| + pixel_comparator_.reset(
|
| + new FuzzyPixelComparator(false, // discard_alpha
|
| + percentage_pixels_error,
|
| + percentage_pixels_small_error,
|
| + average_error_allowed_in_bad_pixels,
|
| + large_error_allowed,
|
| + small_error_allowed));
|
| + } else if ((flags & kUseColorMatrix) && (type == GL_WITH_BITMAP)) {
|
| + float percentage_pixels_error = 100.f;
|
| + float percentage_pixels_small_error = 0.f;
|
| + float average_error_allowed_in_bad_pixels = 1.f;
|
| + int large_error_allowed = 2;
|
| + int small_error_allowed = 0;
|
| + pixel_comparator_.reset(
|
| + new FuzzyPixelComparator(false, // discard_alpha
|
| + percentage_pixels_error,
|
| + percentage_pixels_small_error,
|
| + average_error_allowed_in_bad_pixels,
|
| + large_error_allowed,
|
| + small_error_allowed));
|
| + }
|
| +
|
| + RunPixelTest(type, root, base::FilePath(expected_path));
|
| + }
|
| +
|
| + bool force_antialiasing_ = false;
|
| };
|
|
|
| TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRoot_GL) {
|
| @@ -128,6 +330,113 @@ TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithTransparent_Software) {
|
| RunBlendingWithTransparentPixelTestType(SOFTWARE_WITH_BITMAP);
|
| }
|
|
|
| +// Tests for render passes
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_GL) {
|
| + RunBlendingWithRenderPass(
|
| + GL_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPass_Software) {
|
| + RunBlendingWithRenderPass(
|
| + SOFTWARE_WITH_BITMAP, FILE_PATH_LITERAL("blending_render_pass.png"), 0);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_GL) {
|
| + RunBlendingWithRenderPass(GL_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass.png"),
|
| + kUseAntialiasing);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassAA_Software) {
|
| + RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass.png"),
|
| + kUseAntialiasing);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMask_GL) {
|
| + RunBlendingWithRenderPass(GL_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask.png"),
|
| + kUseMasks);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassWithMask_Software) {
|
| + RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask.png"),
|
| + kUseMasks);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassWithMaskAA_GL) {
|
| + RunBlendingWithRenderPass(GL_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask.png"),
|
| + kUseMasks | kUseAntialiasing);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassWithMaskAA_Software) {
|
| + RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask.png"),
|
| + kUseMasks | kUseAntialiasing);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrix_GL) {
|
| + RunBlendingWithRenderPass(GL_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_cm.png"),
|
| + kUseColorMatrix);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassColorMatrix_Software) {
|
| + RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_cm.png"),
|
| + kUseColorMatrix);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest, BlendingWithRenderPassColorMatrixAA_GL) {
|
| + RunBlendingWithRenderPass(GL_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_cm.png"),
|
| + kUseAntialiasing | kUseColorMatrix);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassColorMatrixAA_Software) {
|
| + RunBlendingWithRenderPass(SOFTWARE_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_cm.png"),
|
| + kUseAntialiasing | kUseColorMatrix);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassWithMaskColorMatrix_GL) {
|
| + RunBlendingWithRenderPass(
|
| + GL_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
|
| + kUseMasks | kUseColorMatrix);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassWithMaskColorMatrix_Software) {
|
| + RunBlendingWithRenderPass(
|
| + SOFTWARE_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
|
| + kUseMasks | kUseColorMatrix);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassWithMaskColorMatrixAA_GL) {
|
| + RunBlendingWithRenderPass(
|
| + GL_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
|
| + kUseMasks | kUseAntialiasing | kUseColorMatrix);
|
| +}
|
| +
|
| +TEST_F(LayerTreeHostBlendingPixelTest,
|
| + BlendingWithRenderPassWithMaskColorMatrixAA_Software) {
|
| + RunBlendingWithRenderPass(
|
| + SOFTWARE_WITH_BITMAP,
|
| + FILE_PATH_LITERAL("blending_render_pass_mask_cm.png"),
|
| + kUseMasks | kUseAntialiasing | kUseColorMatrix);
|
| +}
|
| +
|
| } // namespace
|
| } // namespace cc
|
|
|
|
|