blob: 8db7b52293d843deea7a43337cdc5227e25e5c52 [file] [log] [blame]
danakjd63f8a62016-08-24 03:26:481// Copyright 2016 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 <stddef.h>
6
7#include "base/memory/ptr_util.h"
8#include "build/build_config.h"
9#include "cc/input/scrollbar.h"
bokane7a058a2017-03-02 22:42:5110#include "cc/layers/painted_overlay_scrollbar_layer.h"
danakjd63f8a62016-08-24 03:26:4811#include "cc/layers/painted_scrollbar_layer.h"
12#include "cc/layers/solid_color_layer.h"
enne34f6084c2017-02-02 22:39:0813#include "cc/paint/paint_canvas.h"
14#include "cc/paint/paint_flags.h"
danakjd63f8a62016-08-24 03:26:4815#include "cc/test/layer_tree_pixel_test.h"
16#include "cc/test/test_in_process_context_provider.h"
bokane7a058a2017-03-02 22:42:5117#include "cc/trees/layer_tree_impl.h"
danakjd63f8a62016-08-24 03:26:4818#include "gpu/command_buffer/client/gles2_interface.h"
19
20#if !defined(OS_ANDROID)
21
22namespace cc {
23namespace {
24
25class LayerTreeHostScrollbarsPixelTest : public LayerTreePixelTest {
26 protected:
27 LayerTreeHostScrollbarsPixelTest() = default;
28
29 void InitializeSettings(LayerTreeSettings* settings) override {
30 settings->layer_transforms_should_scale_layer_contents = true;
31 }
32
33 void SetupTree() override {
khushalsagarb69ba9452017-01-27 22:20:0734 layer_tree_host()->SetDeviceScaleFactor(device_scale_factor_);
danakjd63f8a62016-08-24 03:26:4835 LayerTreePixelTest::SetupTree();
36 }
37
38 float device_scale_factor_ = 1.f;
39};
40
41class PaintedScrollbar : public Scrollbar {
42 public:
43 ~PaintedScrollbar() override = default;
44
45 ScrollbarOrientation Orientation() const override { return VERTICAL; }
46 bool IsLeftSideVerticalScrollbar() const override { return false; }
47 gfx::Point Location() const override { return gfx::Point(); }
48 bool IsOverlay() const override { return false; }
49 bool HasThumb() const override { return thumb_; }
50 int ThumbThickness() const override { return rect_.width(); }
51 int ThumbLength() const override { return rect_.height(); }
52 gfx::Rect TrackRect() const override { return rect_; }
53 float ThumbOpacity() const override { return 1.f; }
54 bool NeedsPaintPart(ScrollbarPart part) const override { return true; }
enne34f6084c2017-02-02 22:39:0855 void PaintPart(PaintCanvas* canvas,
danakjd63f8a62016-08-24 03:26:4856 ScrollbarPart part,
57 const gfx::Rect& content_rect) override {
ennebb7c4bcf2017-02-07 17:59:4958 PaintFlags flags;
59 flags.setStyle(PaintFlags::kStroke_Style);
60 flags.setStrokeWidth(SkIntToScalar(paint_scale_));
61 flags.setColor(color_);
danakjd63f8a62016-08-24 03:26:4862
63 gfx::Rect inset_rect = content_rect;
64 while (!inset_rect.IsEmpty()) {
65 int big = paint_scale_ + 2;
66 int small = paint_scale_;
67 inset_rect.Inset(big, big, small, small);
ennebb7c4bcf2017-02-07 17:59:4968 canvas->drawRect(RectToSkRect(inset_rect), flags);
danakjd63f8a62016-08-24 03:26:4869 inset_rect.Inset(big, big, small, small);
70 }
71 }
bokane7a058a2017-03-02 22:42:5172 bool UsesNinePatchThumbResource() const override { return false; }
73 gfx::Size NinePatchThumbCanvasSize() const override { return gfx::Size(); }
74 gfx::Rect NinePatchThumbAperture() const override { return gfx::Rect(); }
danakjd63f8a62016-08-24 03:26:4875
76 void set_paint_scale(int scale) { paint_scale_ = scale; }
77
78 private:
79 int paint_scale_ = 4;
80 bool thumb_ = false;
81 SkColor color_ = SK_ColorGREEN;
82 gfx::Rect rect_;
83};
84
85TEST_F(LayerTreeHostScrollbarsPixelTest, NoScale) {
86 scoped_refptr<SolidColorLayer> background =
87 CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
88
Jeremy Roman909d927b2017-08-27 18:34:0989 auto scrollbar = std::make_unique<PaintedScrollbar>();
danakjd63f8a62016-08-24 03:26:4890 scoped_refptr<PaintedScrollbarLayer> layer =
pdr75a6cc52017-04-20 19:21:1491 PaintedScrollbarLayer::Create(std::move(scrollbar));
danakjd63f8a62016-08-24 03:26:4892 layer->SetIsDrawable(true);
93 layer->SetBounds(gfx::Size(200, 200));
94 background->AddChild(layer);
95
96 RunPixelTest(PIXEL_TEST_GL, background,
97 base::FilePath(FILE_PATH_LITERAL("spiral.png")));
98}
99
100TEST_F(LayerTreeHostScrollbarsPixelTest, DeviceScaleFactor) {
101 // With a device scale of 2, the scrollbar should still be rendered
102 // pixel-perfect, not show scaling artifacts
103 device_scale_factor_ = 2.f;
104
105 scoped_refptr<SolidColorLayer> background =
106 CreateSolidColorLayer(gfx::Rect(100, 100), SK_ColorWHITE);
107
Jeremy Roman909d927b2017-08-27 18:34:09108 auto scrollbar = std::make_unique<PaintedScrollbar>();
danakjd63f8a62016-08-24 03:26:48109 scoped_refptr<PaintedScrollbarLayer> layer =
pdr75a6cc52017-04-20 19:21:14110 PaintedScrollbarLayer::Create(std::move(scrollbar));
danakjd63f8a62016-08-24 03:26:48111 layer->SetIsDrawable(true);
112 layer->SetBounds(gfx::Size(100, 100));
113 background->AddChild(layer);
114
115 RunPixelTest(PIXEL_TEST_GL, background,
116 base::FilePath(FILE_PATH_LITERAL("spiral_double_scale.png")));
117}
118
119TEST_F(LayerTreeHostScrollbarsPixelTest, TransformScale) {
120 scoped_refptr<SolidColorLayer> background =
121 CreateSolidColorLayer(gfx::Rect(200, 200), SK_ColorWHITE);
122
Jeremy Roman909d927b2017-08-27 18:34:09123 auto scrollbar = std::make_unique<PaintedScrollbar>();
danakjd63f8a62016-08-24 03:26:48124 scoped_refptr<PaintedScrollbarLayer> layer =
pdr75a6cc52017-04-20 19:21:14125 PaintedScrollbarLayer::Create(std::move(scrollbar));
danakjd63f8a62016-08-24 03:26:48126 layer->SetIsDrawable(true);
127 layer->SetBounds(gfx::Size(100, 100));
128 background->AddChild(layer);
129
130 // This has a scale of 2, it should still be rendered pixel-perfect, not show
131 // scaling artifacts
132 gfx::Transform scale_transform;
133 scale_transform.Scale(2.0, 2.0);
134 layer->SetTransform(scale_transform);
135
136 RunPixelTest(PIXEL_TEST_GL, background,
137 base::FilePath(FILE_PATH_LITERAL("spiral_double_scale.png")));
138}
139
140TEST_F(LayerTreeHostScrollbarsPixelTest, HugeTransformScale) {
141 scoped_refptr<SolidColorLayer> background =
142 CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE);
143
Jeremy Roman909d927b2017-08-27 18:34:09144 auto scrollbar = std::make_unique<PaintedScrollbar>();
danakjd63f8a62016-08-24 03:26:48145 scrollbar->set_paint_scale(1);
146 scoped_refptr<PaintedScrollbarLayer> layer =
pdr75a6cc52017-04-20 19:21:14147 PaintedScrollbarLayer::Create(std::move(scrollbar));
danakjd63f8a62016-08-24 03:26:48148 layer->SetIsDrawable(true);
149 layer->SetBounds(gfx::Size(10, 400));
150 background->AddChild(layer);
151
152 scoped_refptr<TestInProcessContextProvider> context(
153 new TestInProcessContextProvider(nullptr));
154 context->BindToCurrentThread();
155 int max_texture_size = 0;
156 context->ContextGL()->GetIntegerv(GL_MAX_TEXTURE_SIZE, &max_texture_size);
157
158 // We want a scale that creates a texture taller than the max texture size. If
159 // there's no clamping, the texture will be invalid and we'll just get black.
160 double scale = 64.0;
161 ASSERT_GT(scale * layer->bounds().height(), max_texture_size);
162
163 // Let's show the bottom right of the layer, so we know the texture wasn't
164 // just cut off.
165 layer->SetPosition(
166 gfx::PointF(-10.f * scale + 400.f, -400.f * scale + 400.f));
167
168 gfx::Transform scale_transform;
169 scale_transform.Scale(scale, scale);
170 layer->SetTransform(scale_transform);
171
danakjd63f8a62016-08-24 03:26:48172 RunPixelTest(PIXEL_TEST_GL, background,
173 base::FilePath(FILE_PATH_LITERAL("spiral_64_scale.png")));
174}
175
bokane7a058a2017-03-02 22:42:51176class LayerTreeHostOverlayScrollbarsPixelTest
177 : public LayerTreeHostScrollbarsPixelTest {
178 protected:
179 LayerTreeHostOverlayScrollbarsPixelTest() = default;
180
181 void DidActivateTreeOnThread(LayerTreeHostImpl* host_impl) override {
182 LayerImpl* layer = host_impl->active_tree()->LayerById(scrollbar_layer_id_);
183 ScrollbarLayerImplBase* scrollbar = layer->ToScrollbarLayer();
184 scrollbar->SetThumbThicknessScaleFactor(thickness_scale_);
185 }
186
187 int scrollbar_layer_id_;
188 float thickness_scale_;
189};
190
191class PaintedOverlayScrollbar : public PaintedScrollbar {
192 public:
193 ~PaintedOverlayScrollbar() override = default;
194
195 int ThumbThickness() const override { return 15; }
196 int ThumbLength() const override { return 50; }
197 gfx::Rect TrackRect() const override { return gfx::Rect(0, 0, 15, 400); }
198 bool HasThumb() const override { return true; }
199 bool IsOverlay() const override { return true; }
200 void PaintPart(PaintCanvas* canvas,
201 ScrollbarPart part,
202 const gfx::Rect& content_rect) override {
203 // The outside of the rect will be painted with a 1 pixel black, red, then
204 // blue border. The inside will be solid blue. This will allow the test to
205 // ensure that scaling the thumb doesn't scale the border at all. Note
206 // that the inside of the border must be the same color as the center tile
207 // to prevent an interpolation from being applied.
208 PaintFlags flags;
209 flags.setStyle(PaintFlags::kFill_Style);
210 flags.setStrokeWidth(SkIntToScalar(1));
211 flags.setColor(SK_ColorBLACK);
212
213 gfx::Rect inset_rect = content_rect;
214
215 canvas->drawRect(RectToSkRect(inset_rect), flags);
216
217 flags.setColor(SK_ColorRED);
218 inset_rect.Inset(1, 1);
219 canvas->drawRect(RectToSkRect(inset_rect), flags);
220
221 flags.setColor(SK_ColorBLUE);
222 inset_rect.Inset(1, 1);
223 canvas->drawRect(RectToSkRect(inset_rect), flags);
224 }
225 bool UsesNinePatchThumbResource() const override { return true; }
226 gfx::Size NinePatchThumbCanvasSize() const override {
227 return gfx::Size(7, 7);
228 }
229 gfx::Rect NinePatchThumbAperture() const override {
230 return gfx::Rect(3, 3, 1, 1);
231 }
232};
233
234// Simulate increasing the thickness of a painted overlay scrollbar. Ensure that
235// the scrollbar border remains crisp.
236TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledUp) {
237 scoped_refptr<SolidColorLayer> background =
238 CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE);
239
Jeremy Roman909d927b2017-08-27 18:34:09240 auto scrollbar = std::make_unique<PaintedOverlayScrollbar>();
bokane7a058a2017-03-02 22:42:51241 scoped_refptr<PaintedOverlayScrollbarLayer> layer =
pdr75a6cc52017-04-20 19:21:14242 PaintedOverlayScrollbarLayer::Create(std::move(scrollbar));
bokane7a058a2017-03-02 22:42:51243
244 scrollbar_layer_id_ = layer->id();
245 thickness_scale_ = 5.f;
246
247 layer->SetIsDrawable(true);
248 layer->SetBounds(gfx::Size(10, 300));
249 background->AddChild(layer);
250
251 layer->SetPosition(gfx::PointF(185, 10));
252
253 RunPixelTest(
254 PIXEL_TEST_GL, background,
255 base::FilePath(FILE_PATH_LITERAL("overlay_scrollbar_scaled_up.png")));
256}
257
258// Simulate decreasing the thickness of a painted overlay scrollbar. Ensure that
259// the scrollbar border remains crisp.
260TEST_F(LayerTreeHostOverlayScrollbarsPixelTest, NinePatchScrollbarScaledDown) {
261 scoped_refptr<SolidColorLayer> background =
262 CreateSolidColorLayer(gfx::Rect(400, 400), SK_ColorWHITE);
263
Jeremy Roman909d927b2017-08-27 18:34:09264 auto scrollbar = std::make_unique<PaintedOverlayScrollbar>();
bokane7a058a2017-03-02 22:42:51265 scoped_refptr<PaintedOverlayScrollbarLayer> layer =
pdr75a6cc52017-04-20 19:21:14266 PaintedOverlayScrollbarLayer::Create(std::move(scrollbar));
bokane7a058a2017-03-02 22:42:51267
268 scrollbar_layer_id_ = layer->id();
269 thickness_scale_ = 0.4f;
270
271 layer->SetIsDrawable(true);
272 layer->SetBounds(gfx::Size(10, 300));
273 background->AddChild(layer);
274
275 layer->SetPosition(gfx::PointF(185, 10));
276
277 RunPixelTest(
278 PIXEL_TEST_GL, background,
279 base::FilePath(FILE_PATH_LITERAL("overlay_scrollbar_scaled_down.png")));
280}
281
danakjd63f8a62016-08-24 03:26:48282} // namespace
283} // namespace cc
284
285#endif // OS_ANDROID