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.
4
5#include "build/build_config.h"
6#include "cc/layers/solid_color_layer.h"
7#include "cc/test/layer_tree_pixel_test.h"
8#include "cc/test/pixel_comparator.h"
9#include "third_party/skia/include/effects/SkColorFilterImageFilter.h"
10#include "third_party/skia/include/effects/SkColorMatrixFilter.h"
11
12#if !defined(OS_ANDROID)
13
14namespace cc {
15namespace {
16
17class LayerTreeHostFiltersPixelTest : public LayerTreePixelTest {};
18
19TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlur) {
20  scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
21      gfx::Rect(200, 200), SK_ColorWHITE);
22
23  // The green box is entirely behind a layer with background blur, so it
24  // should appear blurred on its edges.
25  scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
26      gfx::Rect(50, 50, 100, 100), kCSSGreen);
27  scoped_refptr<SolidColorLayer> blur = CreateSolidColorLayer(
28      gfx::Rect(30, 30, 140, 140), SK_ColorTRANSPARENT);
29  background->AddChild(green);
30  background->AddChild(blur);
31
32  FilterOperations filters;
33  filters.Append(FilterOperation::CreateBlurFilter(2.f));
34  blur->SetBackgroundFilters(filters);
35
36#if defined(OS_WIN)
37  // Windows has 436 pixels off by 1: crbug.com/259915
38  float percentage_pixels_large_error = 1.09f;  // 436px / (200*200)
39  float percentage_pixels_small_error = 0.0f;
40  float average_error_allowed_in_bad_pixels = 1.f;
41  int large_error_allowed = 1;
42  int small_error_allowed = 0;
43  pixel_comparator_.reset(new FuzzyPixelComparator(
44      true,  // discard_alpha
45      percentage_pixels_large_error,
46      percentage_pixels_small_error,
47      average_error_allowed_in_bad_pixels,
48      large_error_allowed,
49      small_error_allowed));
50#endif
51
52  RunPixelTest(GL_WITH_BITMAP,
53               background,
54               base::FilePath(FILE_PATH_LITERAL("background_filter_blur.png")));
55}
56
57TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOutsets) {
58  scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
59      gfx::Rect(200, 200), SK_ColorWHITE);
60
61  // The green border is outside the layer with background blur, but the
62  // background blur should use pixels from outside its layer borders, up to the
63  // radius of the blur effect. So the border should be blurred underneath the
64  // top layer causing the green to bleed under the transparent layer, but not
65  // in the 1px region between the transparent layer and the green border.
66  scoped_refptr<SolidColorLayer> green_border = CreateSolidColorLayerWithBorder(
67      gfx::Rect(1, 1, 198, 198), SK_ColorWHITE, 10, kCSSGreen);
68  scoped_refptr<SolidColorLayer> blur = CreateSolidColorLayer(
69      gfx::Rect(12, 12, 176, 176), SK_ColorTRANSPARENT);
70  background->AddChild(green_border);
71  background->AddChild(blur);
72
73  FilterOperations filters;
74  filters.Append(FilterOperation::CreateBlurFilter(5.f));
75  blur->SetBackgroundFilters(filters);
76
77#if defined(OS_WIN)
78  // Windows has 2596 pixels off by at most 2: crbug.com/259922
79  float percentage_pixels_large_error = 6.5f;  // 2596px / (200*200), rounded up
80  float percentage_pixels_small_error = 0.0f;
81  float average_error_allowed_in_bad_pixels = 1.f;
82  int large_error_allowed = 2;
83  int small_error_allowed = 0;
84  pixel_comparator_.reset(new FuzzyPixelComparator(
85      true,  // discard_alpha
86      percentage_pixels_large_error,
87      percentage_pixels_small_error,
88      average_error_allowed_in_bad_pixels,
89      large_error_allowed,
90      small_error_allowed));
91#endif
92
93  RunPixelTest(GL_WITH_BITMAP,
94               background,
95               base::FilePath(FILE_PATH_LITERAL(
96                   "background_filter_blur_outsets.png")));
97}
98
99TEST_F(LayerTreeHostFiltersPixelTest, BackgroundFilterBlurOffAxis) {
100  scoped_refptr<SolidColorLayer> background = CreateSolidColorLayer(
101      gfx::Rect(200, 200), SK_ColorWHITE);
102
103  // This verifies that the perspective of the clear layer (with black border)
104  // does not influence the blending of the green box behind it. Also verifies
105  // that the blur is correctly clipped inside the transformed clear layer.
106  scoped_refptr<SolidColorLayer> green = CreateSolidColorLayer(
107      gfx::Rect(50, 50, 100, 100), kCSSGreen);
108  scoped_refptr<SolidColorLayer> blur = CreateSolidColorLayerWithBorder(
109      gfx::Rect(30, 30, 120, 120), SK_ColorTRANSPARENT, 1, SK_ColorBLACK);
110  background->AddChild(green);
111  background->AddChild(blur);
112
113  background->SetShouldFlattenTransform(false);
114  background->Set3dSortingContextId(1);
115  green->SetShouldFlattenTransform(false);
116  green->Set3dSortingContextId(1);
117  gfx::Transform background_transform;
118  background_transform.ApplyPerspectiveDepth(200.0);
119  background->SetTransform(background_transform);
120
121  blur->SetShouldFlattenTransform(false);
122  blur->Set3dSortingContextId(1);
123  for (size_t i = 0; i < blur->children().size(); ++i)
124    blur->children()[i]->Set3dSortingContextId(1);
125
126  gfx::Transform blur_transform;
127  blur_transform.Translate(55.0, 65.0);
128  blur_transform.RotateAboutXAxis(85.0);
129  blur_transform.RotateAboutYAxis(180.0);
130  blur_transform.RotateAboutZAxis(20.0);
131  blur_transform.Translate(-60.0, -60.0);
132  blur->SetTransform(blur_transform);
133
134  FilterOperations filters;
135  filters.Append(FilterOperation::CreateBlurFilter(2.f));
136  blur->SetBackgroundFilters(filters);
137
138#if defined(OS_WIN)
139  // Windows has 153 pixels off by at most 2: crbug.com/225027
140  float percentage_pixels_large_error = 0.3825f;  // 153px / (200*200)
141  float percentage_pixels_small_error = 0.0f;
142  float average_error_allowed_in_bad_pixels = 1.f;
143  int large_error_allowed = 2;
144  int small_error_allowed = 0;
145  pixel_comparator_.reset(new FuzzyPixelComparator(
146      true,  // discard_alpha
147      percentage_pixels_large_error,
148      percentage_pixels_small_error,
149      average_error_allowed_in_bad_pixels,
150      large_error_allowed,
151      small_error_allowed));
152#endif
153
154  RunPixelTest(GL_WITH_BITMAP,
155               background,
156               base::FilePath(FILE_PATH_LITERAL(
157                   "background_filter_blur_off_axis.png")));
158}
159
160class ImageFilterClippedPixelTest : public LayerTreeHostFiltersPixelTest {
161 protected:
162  void RunPixelTestType(PixelTestType test_type) {
163    scoped_refptr<SolidColorLayer> root =
164        CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorBLACK);
165
166    scoped_refptr<SolidColorLayer> background =
167        CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorYELLOW);
168    root->AddChild(background);
169
170    scoped_refptr<SolidColorLayer> foreground =
171        CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorRED);
172    background->AddChild(foreground);
173
174    SkScalar matrix[20];
175    memset(matrix, 0, 20 * sizeof(matrix[0]));
176    // This filter does a red-blue swap, so the foreground becomes blue.
177    matrix[2] = matrix[6] = matrix[10] = matrix[18] = SK_Scalar1;
178    skia::RefPtr<SkColorFilter> colorFilter(
179        skia::AdoptRef(SkColorMatrixFilter::Create(matrix)));
180    // We filter only the bottom 200x100 pixels of the foreground.
181    SkImageFilter::CropRect crop_rect(SkRect::MakeXYWH(0, 100, 200, 100));
182    skia::RefPtr<SkImageFilter> filter = skia::AdoptRef(
183        SkColorFilterImageFilter::Create(colorFilter.get(), NULL, &crop_rect));
184    FilterOperations filters;
185    filters.Append(FilterOperation::CreateReferenceFilter(filter));
186
187    // Make the foreground layer's render surface be clipped by the background
188    // layer.
189    background->SetMasksToBounds(true);
190    foreground->SetFilters(filters);
191
192    // Then we translate the foreground up by 100 pixels in Y, so the cropped
193    // region is moved to to the top. This ensures that the crop rect is being
194    // correctly transformed in skia by the amount of clipping that the
195    // compositor performs.
196    gfx::Transform transform;
197    transform.Translate(0.0, -100.0);
198    foreground->SetTransform(transform);
199
200    RunPixelTest(test_type,
201                 background,
202                 base::FilePath(FILE_PATH_LITERAL("blue_yellow.png")));
203  }
204};
205
206TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_GL) {
207  RunPixelTestType(GL_WITH_BITMAP);
208}
209
210TEST_F(ImageFilterClippedPixelTest, ImageFilterClipped_Software) {
211  RunPixelTestType(SOFTWARE_WITH_BITMAP);
212}
213
214}  // namespace
215}  // namespace cc
216
217#endif  // OS_ANDROID
218