// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "build/build_config.h" #include "cc/layers/solid_color_layer.h" #include "cc/test/layer_tree_pixel_test.h" #include "cc/test/pixel_comparator.h" #include "third_party/skia/include/effects/SkColorFilterImageFilter.h" #include "third_party/skia/include/effects/SkColorMatrixFilter.h" #if !defined(OS_ANDROID) namespace cc { namespace { class LayerTreeHostFiltersPixelTest : public LayerTreePixelTest {}; TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlur) { scoped_refptr background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); // The green box is entirely behind a layer with background blur, so it // should appear blurred on its edges. scoped_refptr green = CreateSolidColorLayer( gfx::Rect(50, 50, 100, 100), kCSSGreen); scoped_refptr blur = CreateSolidColorLayer( gfx::Rect(30, 30, 140, 140), SK_ColorTRANSPARENT); background->AddChild(green); background->AddChild(blur); FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(2.f)); blur->SetBackgroundFilters(filters); #if defined(OS_WIN) // Windows has 436 pixels off by 1: crbug.com/259915 float percentage_pixels_large_error = 1.09f; // 436px / (200*200) float percentage_pixels_small_error = 0.0f; float average_error_allowed_in_bad_pixels = 1.f; int large_error_allowed = 1; int small_error_allowed = 0; pixel_comparator_.reset(new FuzzyPixelComparator( true, // discard_alpha percentage_pixels_large_error, percentage_pixels_small_error, average_error_allowed_in_bad_pixels, large_error_allowed, small_error_allowed)); #endif RunPixelTest(PIXEL_TEST_GL, background, base::FilePath(FILE_PATH_LITERAL("background_filter_blur.png"))); } TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOutsets) { scoped_refptr background = CreateSolidColorLayer( gfx::Rect(200, 200), SK_ColorWHITE); // The green border is outside the layer with background blur, but the // background blur should use pixels from outside its layer borders, up to the // radius of the blur effect. So the border should be blurred underneath the // top layer causing the green to bleed under the transparent layer, but not // in the 1px region between the transparent layer and the green border. scoped_refptr green_border = CreateSolidColorLayerWithBorder( gfx::Rect(1, 1, 198, 198), SK_ColorWHITE, 10, kCSSGreen); scoped_refptr blur = CreateSolidColorLayer( gfx::Rect(12, 12, 176, 176), SK_ColorTRANSPARENT); background->AddChild(green_border); background->AddChild(blur); FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(5.f)); blur->SetBackgroundFilters(filters); #if defined(OS_WIN) // Windows has 2596 pixels off by at most 2: crbug.com/259922 float percentage_pixels_large_error = 6.5f; // 2596px / (200*200), rounded up float percentage_pixels_small_error = 0.0f; float average_error_allowed_in_bad_pixels = 1.f; int large_error_allowed = 2; int small_error_allowed = 0; pixel_comparator_.reset(new FuzzyPixelComparator( true, // discard_alpha percentage_pixels_large_error, percentage_pixels_small_error, average_error_allowed_in_bad_pixels, large_error_allowed, small_error_allowed)); #endif RunPixelTest( PIXEL_TEST_GL, background, base::FilePath(FILE_PATH_LITERAL("background_filter_blur_outsets.png"))); } TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) { scoped_refptr background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorTRANSPARENT); // This verifies that the perspective of the clear layer (with black border) // does not influence the blending of the green box behind it. Also verifies // that the blur is correctly clipped inside the transformed clear layer. scoped_refptr green = CreateSolidColorLayer( gfx::Rect(50, 50, 100, 100), kCSSGreen); scoped_refptr blur = CreateSolidColorLayerWithBorder( gfx::Rect(30, 30, 120, 120), SK_ColorTRANSPARENT, 1, SK_ColorBLACK); background->AddChild(green); background->AddChild(blur); background->SetShouldFlattenTransform(false); background->Set3dSortingContextId(1); green->SetShouldFlattenTransform(false); green->Set3dSortingContextId(1); gfx::Transform background_transform; background_transform.ApplyPerspectiveDepth(200.0); background->SetTransform(background_transform); blur->SetShouldFlattenTransform(false); blur->Set3dSortingContextId(1); for (size_t i = 0; i < blur->children().size(); ++i) blur->children()[i]->Set3dSortingContextId(1); gfx::Transform blur_transform; blur_transform.Translate(55.0, 65.0); blur_transform.RotateAboutXAxis(85.0); blur_transform.RotateAboutYAxis(180.0); blur_transform.RotateAboutZAxis(20.0); blur_transform.Translate(-60.0, -60.0); blur->SetTransform(blur_transform); FilterOperations filters; filters.Append(FilterOperation::CreateBlurFilter(2.f)); blur->SetBackgroundFilters(filters); #if defined(OS_WIN) // Windows has 116 pixels off by at most 2: crbug.com/225027 float percentage_pixels_large_error = 0.3f; // 116px / (200*200), rounded up float percentage_pixels_small_error = 0.0f; float average_error_allowed_in_bad_pixels = 1.f; int large_error_allowed = 2; int small_error_allowed = 0; pixel_comparator_.reset(new FuzzyPixelComparator( true, // discard_alpha percentage_pixels_large_error, percentage_pixels_small_error, average_error_allowed_in_bad_pixels, large_error_allowed, small_error_allowed)); #endif RunPixelTest( PIXEL_TEST_GL, background, base::FilePath(FILE_PATH_LITERAL("background_filter_blur_off_axis.png"))); } class LayerTreeHostFiltersScaledPixelTest : public LayerTreeHostFiltersPixelTest { void InitializeSettings(LayerTreeSettings* settings) override { // Required so that device scale is inherited by content scale. settings->layer_transforms_should_scale_layer_contents = true; } void SetupTree() override { layer_tree_host()->SetDeviceScaleFactor(device_scale_factor_); LayerTreePixelTest::SetupTree(); } protected: void RunPixelTestType(int content_size, float device_scale_factor, PixelTestType test_type) { int half_content = content_size / 2; scoped_refptr root = CreateSolidColorLayer( gfx::Rect(0, 0, content_size, content_size), SK_ColorWHITE); scoped_refptr background = CreateSolidColorLayer( gfx::Rect(0, 0, content_size, content_size), SK_ColorGREEN); root->AddChild(background); // Add a blue layer that completely covers the green layer. scoped_refptr foreground = CreateSolidColorLayer( gfx::Rect(0, 0, content_size, content_size), SK_ColorBLUE); background->AddChild(foreground); // Add an alpha threshold filter to the blue layer which will filter out // everything except the lower right corner. FilterOperations filters; SkRegion alpha_region; alpha_region.setRect( half_content, half_content, content_size, content_size); filters.Append( FilterOperation::CreateAlphaThresholdFilter(alpha_region, 1.f, 0.f)); foreground->SetFilters(filters); device_scale_factor_ = device_scale_factor; RunPixelTest( test_type, background, base::FilePath(FILE_PATH_LITERAL("green_small_with_blue_corner.png"))); } float device_scale_factor_; }; TEST_F(LayerTreeHostFiltersScaledPixelTest, StandardDpi_GL) { RunPixelTestType(100, 1.f, PIXEL_TEST_GL); } TEST_F(LayerTreeHostFiltersScaledPixelTest, StandardDpi_Software) { RunPixelTestType(100, 1.f, PIXEL_TEST_SOFTWARE); } TEST_F(LayerTreeHostFiltersScaledPixelTest, HiDpi_GL) { RunPixelTestType(50, 2.f, PIXEL_TEST_GL); } TEST_F(LayerTreeHostFiltersScaledPixelTest, HiDpi_Software) { RunPixelTestType(50, 2.f, PIXEL_TEST_SOFTWARE); } class ImageFilterClippedPixelTest : public LayerTreeHostFiltersPixelTest { protected: void RunPixelTestType(PixelTestType test_type) { scoped_refptr root = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK); scoped_refptr background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorYELLOW); root->AddChild(background); scoped_refptr foreground = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorRED); background->AddChild(foreground); SkScalar matrix[20]; memset(matrix, 0, 20 * sizeof(matrix[0])); // This filter does a red-blue swap, so the foreground becomes blue. matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1; skia::RefPtr colorFilter( skia::AdoptRef(SkColorMatrixFilter::Create(matrix))); // We filter only the bottom 200x100 pixels of the foreground. SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100)); skia::RefPtr filter = skia::AdoptRef( SkColorFilterImageFilter::Create(colorFilter.get(), NULL, &crop_rect)); FilterOperations filters; filters.Append(FilterOperation::CreateReferenceFilter(filter)); // Make the foreground layer's render surface be clipped by the background // layer. background->SetMasksToBounds(true); foreground->SetFilters(filters); // Then we translate the foreground up by 100 pixels in Y, so the cropped // region is moved to to the top. This ensures that the crop rect is being // correctly transformed in skia by the amount of clipping that the // compositor performs. gfx::Transform transform; transform.Translate(0.0, -100.0); foreground->SetTransform(transform); RunPixelTest(test_type, background, base::FilePath(FILE_PATH_LITERAL("blue_yellow.png"))); } }; TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_GL) { RunPixelTestType(PIXEL_TEST_GL); } TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_Software) { RunPixelTestType(PIXEL_TEST_SOFTWARE); } TEST_F(LayerTreeHostFiltersPixelTest, ImageFilterScaled_GL) { scoped_refptr background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE); gfx::Rect rect(50, 50, 100, 100); const int kInset = 3; for (int i = 0; !rect.IsEmpty(); ++i) { scoped_refptr layer = CreateSolidColorLayer(rect, (i & 1) ? SK_ColorWHITE : SK_ColorRED); gfx::Transform transform; transform.Translate(rect.width() / 2.0, rect.height() / 2.0); transform.RotateAboutZAxis(30.0); transform.Translate(-rect.width() / 2.0, -rect.height() / 2.0); layer->SetTransform(transform); background->AddChild(layer); rect.Inset(kInset, kInset); } scoped_refptr filter = CreateSolidColorLayer(gfx::Rect(100, 0, 100, 200), SK_ColorTRANSPARENT); background->AddChild(filter); // Apply a scale to |background| so that we can see any scaling artifacts that // may appear. gfx::Transform background_transform; static float scale = 1.1f; background_transform.Scale(scale, scale); background->SetTransform(background_transform); FilterOperations filters; filters.Append(FilterOperation::CreateGrayscaleFilter(1.0f)); filter->SetBackgroundFilters(filters); #if defined(OS_WIN) // Windows has 153 pixels off by at most 2: crbug.com/225027 float percentage_pixels_large_error = 0.3825f; // 153px / (200*200) float percentage_pixels_small_error = 0.0f; float average_error_allowed_in_bad_pixels = 1.f; int large_error_allowed = 2; int small_error_allowed = 0; pixel_comparator_.reset(new FuzzyPixelComparator( true, // discard_alpha percentage_pixels_large_error, percentage_pixels_small_error, average_error_allowed_in_bad_pixels, large_error_allowed, small_error_allowed)); #endif // TODO(hendrikw): Enable test in software as well: crbug.com/432157 RunPixelTest(PIXEL_TEST_GL, background, base::FilePath(FILE_PATH_LITERAL("filter_on_scaled_layer.png"))); } class ImageScaledRenderSurface : public LayerTreeHostFiltersPixelTest { protected: void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) { // A filter will cause a render surface to be used. Here we force the // render surface on, and scale the result to make sure that we rasterize at // the correct resolution. scoped_refptr background = CreateSolidColorLayer(gfx::Rect(300, 300), SK_ColorBLUE); scoped_refptr render_surface_layer = CreateSolidColorLayer(gfx::Rect(0, 0, 200, 200), SK_ColorWHITE); gfx::Rect rect(50, 50, 100, 100); scoped_refptr child = CreateSolidColorLayer(rect, SK_ColorRED); gfx::Transform transform; transform.Translate(rect.width() / 2.0, rect.height() / 2.0); transform.RotateAboutZAxis(30.0); transform.Translate(-rect.width() / 2.0, -rect.height() / 2.0); child->SetTransform(transform); render_surface_layer->AddChild(child); gfx::Transform render_surface_transform; render_surface_transform.Scale(1.5f, 1.5f); render_surface_layer->SetTransform(render_surface_transform); render_surface_layer->SetForceRenderSurface(true); background->AddChild(render_surface_layer); // Software has some huge differences in the AA'd pixels on the different // trybots. See crbug.com/452198. float percentage_pixels_large_error = 0.686f; float percentage_pixels_small_error = 0.0f; float average_error_allowed_in_bad_pixels = 16.f; int large_error_allowed = 17; int small_error_allowed = 0; pixel_comparator_.reset(new FuzzyPixelComparator( true, // discard_alpha percentage_pixels_large_error, percentage_pixels_small_error, average_error_allowed_in_bad_pixels, large_error_allowed, small_error_allowed)); RunPixelTest(test_type, background, image_name); } }; TEST_F(ImageScaledRenderSurface, ImageRenderSurfaceScaled_GL) { RunPixelTestType( PIXEL_TEST_GL, base::FilePath(FILE_PATH_LITERAL("scaled_render_surface_layer_gl.png"))); } TEST_F(ImageScaledRenderSurface, ImageRenderSurfaceScaled_Software) { RunPixelTestType( PIXEL_TEST_SOFTWARE, base::FilePath(FILE_PATH_LITERAL("scaled_render_surface_layer_sw.png"))); } class EnlargedTextureWithAlphaThresholdFilter : public LayerTreeHostFiltersPixelTest { protected: void RunPixelTestType(PixelTestType test_type, base::FilePath image_name) { // Rectangles choosen so that if flipped, the test will fail. gfx::Rect rect1(10, 10, 10, 15); gfx::Rect rect2(20, 25, 70, 65); scoped_refptr child1 = CreateSolidColorLayer(rect1, SK_ColorRED); scoped_refptr child2 = CreateSolidColorLayer(rect2, SK_ColorGREEN); scoped_refptr background = CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLUE); scoped_refptr filter_layer = CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE); // Make sure a transformation does not cause misregistration of the filter // and source texture. gfx::Transform filter_transform; filter_transform.Scale(2.f, 2.f); filter_layer->SetTransform(filter_transform); filter_layer->AddChild(child1); filter_layer->AddChild(child2); rect1.Inset(-5, -5); rect2.Inset(-5, -5); SkRegion alpha_region; SkIRect rects[2] = {gfx::RectToSkIRect(rect1), gfx::RectToSkIRect(rect2)}; alpha_region.setRects(rects, 2); FilterOperations filters; filters.Append( FilterOperation::CreateAlphaThresholdFilter(alpha_region, 0.f, 0.f)); filter_layer->SetFilters(filters); background->AddChild(filter_layer); // Force the allocation a larger textures. set_enlarge_texture_amount(gfx::Vector2d(50, 50)); RunPixelTest(test_type, background, image_name); } }; TEST_F(EnlargedTextureWithAlphaThresholdFilter, GL) { RunPixelTestType( PIXEL_TEST_GL, base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_threshold.png"))); } TEST_F(EnlargedTextureWithAlphaThresholdFilter, Software) { RunPixelTestType( PIXEL_TEST_SOFTWARE, base::FilePath(FILE_PATH_LITERAL("enlarged_texture_on_threshold.png"))); } } // namespace } // namespace cc #endif // OS_ANDROID