Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / cc / layers / scrollbar_layer_unittest.cc
1 // Copyright 2012 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 "base/containers/hash_tables.h"
6 #include "cc/animation/scrollbar_animation_controller.h"
7 #include "cc/layers/append_quads_data.h"
8 #include "cc/layers/painted_scrollbar_layer.h"
9 #include "cc/layers/painted_scrollbar_layer_impl.h"
10 #include "cc/layers/scrollbar_layer_interface.h"
11 #include "cc/layers/solid_color_scrollbar_layer.h"
12 #include "cc/layers/solid_color_scrollbar_layer_impl.h"
13 #include "cc/quads/solid_color_draw_quad.h"
14 #include "cc/resources/resource_update_queue.h"
15 #include "cc/test/fake_impl_proxy.h"
16 #include "cc/test/fake_layer_tree_host.h"
17 #include "cc/test/fake_layer_tree_host_client.h"
18 #include "cc/test/fake_layer_tree_host_impl.h"
19 #include "cc/test/fake_painted_scrollbar_layer.h"
20 #include "cc/test/fake_scrollbar.h"
21 #include "cc/test/geometry_test_utils.h"
22 #include "cc/test/layer_tree_test.h"
23 #include "cc/test/mock_quad_culler.h"
24 #include "cc/test/test_web_graphics_context_3d.h"
25 #include "cc/trees/layer_tree_host.h"
26 #include "cc/trees/layer_tree_impl.h"
27 #include "cc/trees/single_thread_proxy.h"
28 #include "cc/trees/tree_synchronizer.h"
29 #include "testing/gmock/include/gmock/gmock.h"
30 #include "testing/gtest/include/gtest/gtest.h"
31
32 namespace cc {
33 namespace {
34
35 LayerImpl* LayerImplForScrollAreaAndScrollbar(
36     FakeLayerTreeHost* host,
37     scoped_ptr<Scrollbar> scrollbar,
38     bool reverse_order,
39     bool use_solid_color_scrollbar,
40     int thumb_thickness) {
41   scoped_refptr<Layer> layer_tree_root = Layer::Create();
42   scoped_refptr<Layer> child1 = Layer::Create();
43   scoped_refptr<Layer> child2;
44   if (use_solid_color_scrollbar) {
45     const bool kIsLeftSideVerticalScrollbar = false;
46     child2 = SolidColorScrollbarLayer::Create(
47         scrollbar->Orientation(), thumb_thickness,
48         kIsLeftSideVerticalScrollbar, child1->id());
49   } else {
50     child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id());
51   }
52   layer_tree_root->AddChild(child1);
53   layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
54   host->SetRootLayer(layer_tree_root);
55   return host->CommitAndCreateLayerImplTree();
56 }
57
58 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
59   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
60   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
61   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
62       host.get(), scrollbar.Pass(), false, false, 0);
63
64   LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
65   PaintedScrollbarLayerImpl* cc_child2 =
66       static_cast<PaintedScrollbarLayerImpl*>(
67           layer_impl_tree_root->children()[1]);
68
69   EXPECT_EQ(cc_child1->scrollbars()->size(), 1UL);
70   EXPECT_EQ(*(cc_child1->scrollbars()->begin()), cc_child2);
71 }
72
73 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
74   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
75   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
76   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
77       host.get(), scrollbar.Pass(), true, false, 0);
78
79   PaintedScrollbarLayerImpl* cc_child1 =
80       static_cast<PaintedScrollbarLayerImpl*>(
81           layer_impl_tree_root->children()[0]);
82   LayerImpl* cc_child2 = layer_impl_tree_root->children()[1];
83
84   EXPECT_EQ(cc_child2->scrollbars()->size(), 1UL);
85   EXPECT_EQ(*(cc_child2->scrollbars()->begin()), cc_child1);
86 }
87
88 TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
89   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
90
91   // Create and attach a non-overlay scrollbar.
92   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
93   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
94       host.get(), scrollbar.Pass(), false, false, 0);
95   PaintedScrollbarLayerImpl* scrollbar_layer_impl =
96       static_cast<PaintedScrollbarLayerImpl*>(
97           layer_impl_tree_root->children()[1]);
98
99   // When the scrollbar is not an overlay scrollbar, the scroll should be
100   // responded to on the main thread as the compositor does not yet implement
101   // scrollbar scrolling.
102   EXPECT_EQ(InputHandler::ScrollOnMainThread,
103             scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
104                                             InputHandler::Gesture));
105
106   // Create and attach an overlay scrollbar.
107   scrollbar.reset(new FakeScrollbar(false, false, true));
108
109   layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
110       host.get(), scrollbar.Pass(), false, false, 0);
111   scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
112       layer_impl_tree_root->children()[1]);
113
114   // The user shouldn't be able to drag an overlay scrollbar and the scroll
115   // may be handled in the compositor.
116   EXPECT_EQ(InputHandler::ScrollIgnored,
117             scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
118                                             InputHandler::Gesture));
119 }
120
121 TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
122   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
123
124   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
125   scoped_refptr<Layer> layer_tree_root = Layer::Create();
126   scoped_refptr<Layer> scroll_layer = Layer::Create();
127   scoped_refptr<Layer> content_layer = Layer::Create();
128   scoped_refptr<Layer> scrollbar_layer =
129       PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
130
131   // Choose bounds to give max_scroll_offset = (30, 50).
132   layer_tree_root->SetBounds(gfx::Size(70, 150));
133   scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
134   scroll_layer->SetScrollOffset(gfx::Vector2d(10, 20));
135   scroll_layer->SetBounds(gfx::Size(100, 200));
136   content_layer->SetBounds(gfx::Size(100, 200));
137
138   host->SetRootLayer(layer_tree_root);
139   layer_tree_root->AddChild(scroll_layer);
140   scroll_layer->AddChild(content_layer);
141   layer_tree_root->AddChild(scrollbar_layer);
142   scrollbar_layer->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
143   scrollbar_layer->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
144
145   layer_tree_root->SavePaintProperties();
146   content_layer->SavePaintProperties();
147
148   LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
149
150   ScrollbarLayerImplBase* cc_scrollbar_layer =
151       static_cast<PaintedScrollbarLayerImpl*>(
152           layer_impl_tree_root->children()[1]);
153
154   EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos());
155   EXPECT_EQ(30, cc_scrollbar_layer->maximum());
156
157   layer_tree_root->SetBounds(gfx::Size(700, 1500));
158   layer_tree_root->SavePaintProperties();
159   scroll_layer->SetBounds(gfx::Size(1000, 2000));
160   scroll_layer->SetScrollOffset(gfx::Vector2d(100, 200));
161   scroll_layer->SavePaintProperties();
162   content_layer->SetBounds(gfx::Size(1000, 2000));
163   content_layer->SavePaintProperties();
164
165   ScrollbarAnimationController* scrollbar_controller =
166       layer_impl_tree_root->scrollbar_animation_controller();
167   layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
168   EXPECT_EQ(scrollbar_controller,
169             layer_impl_tree_root->scrollbar_animation_controller());
170
171   EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos());
172   EXPECT_EQ(300, cc_scrollbar_layer->maximum());
173
174   LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
175   scroll_layer_impl->ScrollBy(gfx::Vector2d(12, 34));
176
177   EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos());
178   EXPECT_EQ(300, cc_scrollbar_layer->maximum());
179 }
180
181 #define UPDATE_AND_EXTRACT_LAYER_POINTERS()                         \
182   do {                                                              \
183     scrollbar_layer->UpdateThumbAndTrackGeometry();                 \
184     root_clip_layer_impl = host->CommitAndCreateLayerImplTree();    \
185     root_layer_impl = root_clip_layer_impl->children()[0];          \
186     scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
187         root_layer_impl->children()[1]);                            \
188     scrollbar_layer_impl->ScrollbarParametersDidChange();           \
189   } while (false)
190
191 TEST(ScrollbarLayerTest, ThumbRect) {
192   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
193   scoped_refptr<Layer> root_clip_layer = Layer::Create();
194   scoped_refptr<Layer> root_layer = Layer::Create();
195   scoped_refptr<Layer> content_layer = Layer::Create();
196   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
197       FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
198
199   root_layer->SetScrollClipLayerId(root_clip_layer->id());
200   // Give the root-clip a size that will result in MaxScrollOffset = (80, 0).
201   root_clip_layer->SetBounds(gfx::Size(20, 50));
202   root_layer->SetBounds(gfx::Size(100, 50));
203   content_layer->SetBounds(gfx::Size(100, 50));
204
205   host->SetRootLayer(root_clip_layer);
206   root_clip_layer->AddChild(root_layer);
207   root_layer->AddChild(content_layer);
208   root_layer->AddChild(scrollbar_layer);
209
210   root_layer->SetScrollOffset(gfx::Vector2d(0, 0));
211   scrollbar_layer->SetBounds(gfx::Size(70, 10));
212   scrollbar_layer->SetScrollLayer(root_layer->id());
213   scrollbar_layer->SetClipLayer(root_clip_layer->id());
214   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
215   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
216   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
217   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
218   scrollbar_layer->UpdateThumbAndTrackGeometry();
219   LayerImpl* root_clip_layer_impl = NULL;
220   LayerImpl* root_layer_impl = NULL;
221   PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL;
222
223   // Thumb is at the edge of the scrollbar (should be inset to
224   // the start of the track within the scrollbar layer's
225   // position).
226   UPDATE_AND_EXTRACT_LAYER_POINTERS();
227   EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
228             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
229
230   // Under-scroll (thumb position should clamp and be unchanged).
231   root_layer->SetScrollOffset(gfx::Vector2d(-5, 0));
232
233   UPDATE_AND_EXTRACT_LAYER_POINTERS();
234   EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
235             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
236
237   // Over-scroll (thumb position should clamp on the far side).
238   root_layer->SetScrollOffset(gfx::Vector2d(85, 0));
239
240   UPDATE_AND_EXTRACT_LAYER_POINTERS();
241   EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
242             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
243
244   // Change thumb thickness and length.
245   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4);
246   scrollbar_layer->fake_scrollbar()->set_thumb_length(6);
247
248   UPDATE_AND_EXTRACT_LAYER_POINTERS();
249   EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(),
250             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
251
252   // Shrink the scrollbar layer to cover only the track.
253   scrollbar_layer->SetBounds(gfx::Size(50, 10));
254   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10));
255   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
256
257   UPDATE_AND_EXTRACT_LAYER_POINTERS();
258   EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
259             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
260
261   // Shrink the track in the non-scrolling dimension so that it only covers the
262   // middle third of the scrollbar layer (this does not affect the thumb
263   // position).
264   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6));
265
266   UPDATE_AND_EXTRACT_LAYER_POINTERS();
267   EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
268             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
269 }
270
271 TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
272   const int kThumbThickness = 3;
273   const int kTrackLength = 100;
274
275   LayerTreeSettings layer_tree_settings;
276   scoped_ptr<FakeLayerTreeHost> host =
277       FakeLayerTreeHost::Create(layer_tree_settings);
278
279   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
280   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
281       host.get(), scrollbar.Pass(), false, true, kThumbThickness);
282   ScrollbarLayerImplBase* scrollbar_layer_impl =
283       static_cast<SolidColorScrollbarLayerImpl*>(
284           layer_impl_tree_root->children()[1]);
285   scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
286   scrollbar_layer_impl->SetCurrentPos(10.f);
287   scrollbar_layer_impl->SetMaximum(100);
288   scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.4f);
289
290   // Thickness should be overridden to 3.
291   {
292     MockQuadCuller quad_culler;
293     AppendQuadsData data;
294     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
295
296     const QuadList& quads = quad_culler.quad_list();
297     ASSERT_EQ(1u, quads.size());
298     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
299     EXPECT_RECT_EQ(gfx::Rect(6, 0, 40, 3), quads[0]->rect);
300   }
301
302   // Contents scale should scale the draw quad.
303   scrollbar_layer_impl->draw_properties().contents_scale_x = 2.f;
304   scrollbar_layer_impl->draw_properties().contents_scale_y = 2.f;
305   {
306     MockQuadCuller quad_culler;
307     AppendQuadsData data;
308     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
309
310     const QuadList& quads = quad_culler.quad_list();
311     ASSERT_EQ(1u, quads.size());
312     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
313     EXPECT_RECT_EQ(gfx::Rect(12, 0, 80, 6), quads[0]->rect);
314   }
315   scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f;
316   scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f;
317
318   // For solid color scrollbars, position and size should reflect the
319   // current viewport state.
320   scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.2f);
321   {
322     MockQuadCuller quad_culler;
323     AppendQuadsData data;
324     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
325
326     const QuadList& quads = quad_culler.quad_list();
327     ASSERT_EQ(1u, quads.size());
328     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
329     EXPECT_RECT_EQ(gfx::Rect(8, 0, 20, 3), quads[0]->rect);
330   }
331 }
332
333 TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
334   const int kThumbThickness = 3;
335   const int kTrackLength = 10;
336
337   LayerTreeSettings layer_tree_settings;
338   scoped_ptr<FakeLayerTreeHost> host =
339       FakeLayerTreeHost::Create(layer_tree_settings);
340
341   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
342
343   {
344     scoped_refptr<Layer> layer_tree_root = Layer::Create();
345     scoped_refptr<Layer> scroll_layer = Layer::Create();
346     scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
347     scoped_refptr<Layer> child1 = Layer::Create();
348     scoped_refptr<Layer> child2;
349     const bool kIsLeftSideVerticalScrollbar = false;
350     child2 = SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
351                                               kThumbThickness,
352                                               kIsLeftSideVerticalScrollbar,
353                                               child1->id());
354     child2->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
355     child2->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
356     scroll_layer->AddChild(child1);
357     scroll_layer->InsertChild(child2, 1);
358     layer_tree_root->AddChild(scroll_layer);
359     host->SetRootLayer(layer_tree_root);
360   }
361   LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
362   LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
363
364   ScrollbarLayerImplBase* scrollbar_layer_impl =
365       static_cast<PaintedScrollbarLayerImpl*>(scroll_layer_impl->children()[1]);
366
367   // Choose layer bounds to give max_scroll_offset = (8, 8).
368   layer_impl_tree_root->SetBounds(gfx::Size(2, 2));
369   scroll_layer_impl->SetBounds(gfx::Size(10, 10));
370   scroll_layer_impl->ScrollBy(gfx::Vector2dF(4.f, 0.f));
371
372   scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
373   scrollbar_layer_impl->SetCurrentPos(4.f);
374   scrollbar_layer_impl->SetMaximum(8);
375
376   {
377     MockQuadCuller quad_culler;
378     AppendQuadsData data;
379     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
380
381     const QuadList& quads = quad_culler.quad_list();
382     ASSERT_EQ(1u, quads.size());
383     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
384     EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads[0]->rect);
385   }
386 }
387
388 class ScrollbarLayerSolidColorThumbTest : public testing::Test {
389  public:
390   ScrollbarLayerSolidColorThumbTest() {
391     LayerTreeSettings layer_tree_settings;
392     host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_));
393
394     const int kThumbThickness = 3;
395     const bool kIsLeftSideVerticalScrollbar = false;
396     const bool kIsOverlayScrollbar = false;
397
398     horizontal_scrollbar_layer_ =
399         SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
400                                              1,
401                                              HORIZONTAL,
402                                              kThumbThickness,
403                                              kIsLeftSideVerticalScrollbar,
404                                              kIsOverlayScrollbar);
405     vertical_scrollbar_layer_ =
406         SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
407                                              2,
408                                              VERTICAL,
409                                              kThumbThickness,
410                                              kIsLeftSideVerticalScrollbar,
411                                              kIsOverlayScrollbar);
412   }
413
414  protected:
415   FakeImplProxy proxy_;
416   scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
417   scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
418   scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
419 };
420
421 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbLength) {
422   horizontal_scrollbar_layer_->SetCurrentPos(0);
423   horizontal_scrollbar_layer_->SetMaximum(10);
424
425   // Simple case - one third of the scrollable area is visible, so the thumb
426   // should be one third as long as the track.
427   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.33f);
428   horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
429   EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
430
431   // The thumb's length should never be less than its thickness.
432   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.01f);
433   horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
434   EXPECT_EQ(3, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
435 }
436
437 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) {
438   horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
439   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.1f);
440
441   horizontal_scrollbar_layer_->SetCurrentPos(0);
442   horizontal_scrollbar_layer_->SetMaximum(100);
443   EXPECT_EQ(0, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
444   EXPECT_EQ(10, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
445
446   horizontal_scrollbar_layer_->SetCurrentPos(100);
447   // The thumb is 10px long and the track is 100px, so the maximum thumb
448   // position is 90px.
449   EXPECT_EQ(90, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
450
451   horizontal_scrollbar_layer_->SetCurrentPos(80);
452   // The scroll position is 80% of the maximum, so the thumb's position should
453   // be at 80% of its maximum or 72px.
454   EXPECT_EQ(72, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
455 }
456
457 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
458   SolidColorScrollbarLayerImpl* layers[2] =
459       { horizontal_scrollbar_layer_.get(), vertical_scrollbar_layer_.get() };
460   for (size_t i = 0; i < 2; ++i) {
461     layers[i]->SetVisibleToTotalLengthRatio(0.2f);
462     layers[i]->SetCurrentPos(25);
463     layers[i]->SetMaximum(100);
464   }
465   layers[0]->SetBounds(gfx::Size(100, 3));
466   layers[1]->SetBounds(gfx::Size(3, 100));
467
468   EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
469                  horizontal_scrollbar_layer_->ComputeThumbQuadRect());
470   EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
471                  vertical_scrollbar_layer_->ComputeThumbQuadRect());
472
473   horizontal_scrollbar_layer_->SetVerticalAdjust(10.f);
474   vertical_scrollbar_layer_->SetVerticalAdjust(10.f);
475
476   // The vertical adjustment factor has two effects:
477   // 1.) Moves the horizontal scrollbar down
478   // 2.) Increases the vertical scrollbar's effective track length which both
479   // increases the thumb's length and its position within the track.
480   EXPECT_RECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
481                  horizontal_scrollbar_layer_->ComputeThumbQuadRect());
482   EXPECT_RECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
483                  vertical_scrollbar_layer_->ComputeThumbQuadRect());
484 }
485
486 class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
487  public:
488   ScrollbarLayerTestMaxTextureSize() {}
489
490   void SetScrollbarBounds(const gfx::Size& bounds) { bounds_ = bounds; }
491
492   virtual void BeginTest() OVERRIDE {
493     scroll_layer_ = Layer::Create();
494     layer_tree_host()->root_layer()->AddChild(scroll_layer_);
495
496     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
497     scrollbar_layer_ =
498         PaintedScrollbarLayer::Create(scrollbar.Pass(), scroll_layer_->id());
499     scrollbar_layer_->SetScrollLayer(scroll_layer_->id());
500     scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
501     scrollbar_layer_->SetBounds(bounds_);
502     layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
503
504     PostSetNeedsCommitToMainThread();
505   }
506
507   virtual void DidCommitAndDrawFrame() OVERRIDE {
508     const int kMaxTextureSize =
509         layer_tree_host()->GetRendererCapabilities().max_texture_size;
510
511     // Check first that we're actually testing something.
512     EXPECT_GT(scrollbar_layer_->bounds().width(), kMaxTextureSize);
513
514     EXPECT_EQ(scrollbar_layer_->content_bounds().width(),
515               kMaxTextureSize - 1);
516     EXPECT_EQ(scrollbar_layer_->content_bounds().height(),
517               kMaxTextureSize - 1);
518
519     EndTest();
520   }
521
522   virtual void AfterTest() OVERRIDE {}
523
524  private:
525   scoped_refptr<PaintedScrollbarLayer> scrollbar_layer_;
526   scoped_refptr<Layer> scroll_layer_;
527   gfx::Size bounds_;
528 };
529
530 TEST_F(ScrollbarLayerTestMaxTextureSize, DirectRenderer) {
531   scoped_ptr<TestWebGraphicsContext3D> context =
532       TestWebGraphicsContext3D::Create();
533   int max_size = 0;
534   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
535   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
536   RunTest(true, false, true);
537 }
538
539 TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) {
540   scoped_ptr<TestWebGraphicsContext3D> context =
541       TestWebGraphicsContext3D::Create();
542   int max_size = 0;
543   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
544   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
545   RunTest(true, true, true);
546 }
547
548 class MockLayerTreeHost : public LayerTreeHost {
549  public:
550   MockLayerTreeHost(FakeLayerTreeHostClient* client,
551                     const LayerTreeSettings& settings)
552       : LayerTreeHost(client, NULL, settings),
553         next_id_(1),
554         total_ui_resource_created_(0),
555         total_ui_resource_deleted_(0) {
556     InitializeSingleThreaded(client);
557   }
558
559   virtual UIResourceId CreateUIResource(UIResourceClient* content) OVERRIDE {
560     total_ui_resource_created_++;
561     UIResourceId nid = next_id_++;
562     ui_resource_bitmap_map_.insert(
563         std::make_pair(nid, content->GetBitmap(nid, false)));
564     return nid;
565   }
566
567   // Deletes a UI resource.  May safely be called more than once.
568   virtual void DeleteUIResource(UIResourceId id) OVERRIDE {
569     UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
570     if (iter != ui_resource_bitmap_map_.end()) {
571       ui_resource_bitmap_map_.erase(iter);
572       total_ui_resource_deleted_++;
573     }
574   }
575
576   size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
577   int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
578   int TotalUIResourceCreated() { return total_ui_resource_created_; }
579
580   gfx::Size ui_resource_size(UIResourceId id) {
581     UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
582     if (iter != ui_resource_bitmap_map_.end())
583       return iter->second.GetSize();
584     return gfx::Size();
585   }
586
587  private:
588   typedef base::hash_map<UIResourceId, UIResourceBitmap>
589       UIResourceBitmapMap;
590   UIResourceBitmapMap ui_resource_bitmap_map_;
591
592   int next_id_;
593   int total_ui_resource_created_;
594   int total_ui_resource_deleted_;
595 };
596
597
598 class ScrollbarLayerTestResourceCreation : public testing::Test {
599  public:
600   ScrollbarLayerTestResourceCreation()
601       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
602
603   void TestResourceUpload(int num_updates,
604                           size_t expected_resources,
605                           int expected_created,
606                           int expected_deleted,
607                           bool use_solid_color_scrollbar) {
608     layer_tree_host_.reset(
609         new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
610
611     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
612     scoped_refptr<Layer> layer_tree_root = Layer::Create();
613     scoped_refptr<Layer> content_layer = Layer::Create();
614     scoped_refptr<Layer> scrollbar_layer;
615     if (use_solid_color_scrollbar) {
616       const int kThumbThickness = 3;
617       const bool kIsLeftSideVerticalScrollbar = false;
618       scrollbar_layer =
619           SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
620                                            kThumbThickness,
621                                            kIsLeftSideVerticalScrollbar,
622                                            layer_tree_root->id());
623     } else {
624       scrollbar_layer = PaintedScrollbarLayer::Create(scrollbar.Pass(),
625                                                       layer_tree_root->id());
626     }
627     layer_tree_root->AddChild(content_layer);
628     layer_tree_root->AddChild(scrollbar_layer);
629
630     layer_tree_host_->SetRootLayer(layer_tree_root);
631
632     scrollbar_layer->SetIsDrawable(true);
633     scrollbar_layer->SetBounds(gfx::Size(100, 100));
634     layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
635     layer_tree_root->SetBounds(gfx::Size(100, 200));
636     content_layer->SetBounds(gfx::Size(100, 200));
637     scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200);
638     scrollbar_layer->draw_properties().visible_content_rect =
639         gfx::Rect(0, 0, 100, 200);
640     scrollbar_layer->CreateRenderSurface();
641     scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
642
643     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
644     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
645
646     ResourceUpdateQueue queue;
647     OcclusionTracker occlusion_tracker(gfx::Rect(), false);
648
649     scrollbar_layer->SavePaintProperties();
650     for (int update_counter = 0; update_counter < num_updates; update_counter++)
651       scrollbar_layer->Update(&queue, &occlusion_tracker);
652
653     // A non-solid-color scrollbar should have requested two textures.
654     EXPECT_EQ(expected_resources, layer_tree_host_->UIResourceCount());
655     EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
656     EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
657
658     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
659
660     scrollbar_layer->ClearRenderSurface();
661   }
662
663  protected:
664   FakeLayerTreeHostClient fake_client_;
665   LayerTreeSettings layer_tree_settings_;
666   scoped_ptr<MockLayerTreeHost> layer_tree_host_;
667 };
668
669 TEST_F(ScrollbarLayerTestResourceCreation, ResourceUpload) {
670   bool use_solid_color_scrollbars = false;
671   TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
672   int num_updates[3] = {1, 5, 10};
673   for (int j = 0; j < 3; j++) {
674     TestResourceUpload(num_updates[j],
675                        2,
676                        num_updates[j] * 2,
677                        (num_updates[j] - 1) * 2,
678                        use_solid_color_scrollbars);
679   }
680 }
681
682 TEST_F(ScrollbarLayerTestResourceCreation, SolidColorNoResourceUpload) {
683   bool use_solid_color_scrollbars = true;
684   TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
685   TestResourceUpload(1, 0, 0, 0, use_solid_color_scrollbars);
686 }
687
688 class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
689  public:
690   ScaledScrollbarLayerTestResourceCreation()
691       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
692
693   void TestResourceUpload(const float test_scale) {
694     layer_tree_host_.reset(
695         new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
696
697     gfx::Point scrollbar_location(0, 185);
698     scoped_refptr<Layer> layer_tree_root = Layer::Create();
699     scoped_refptr<Layer> content_layer = Layer::Create();
700     scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
701         FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
702
703     layer_tree_root->AddChild(content_layer);
704     layer_tree_root->AddChild(scrollbar_layer);
705
706     layer_tree_host_->SetRootLayer(layer_tree_root);
707
708     scrollbar_layer->SetIsDrawable(true);
709     scrollbar_layer->SetBounds(gfx::Size(100, 15));
710     scrollbar_layer->SetPosition(scrollbar_location);
711     layer_tree_root->SetBounds(gfx::Size(100, 200));
712     content_layer->SetBounds(gfx::Size(100, 200));
713     gfx::SizeF scaled_size =
714         gfx::ScaleSize(scrollbar_layer->bounds(), test_scale, test_scale);
715     gfx::PointF scaled_location =
716         gfx::ScalePoint(scrollbar_layer->position(), test_scale, test_scale);
717     scrollbar_layer->draw_properties().content_bounds =
718         gfx::Size(scaled_size.width(), scaled_size.height());
719     scrollbar_layer->draw_properties().contents_scale_x = test_scale;
720     scrollbar_layer->draw_properties().contents_scale_y = test_scale;
721     scrollbar_layer->draw_properties().visible_content_rect =
722         gfx::Rect(scaled_location.x(),
723                   scaled_location.y(),
724                   scaled_size.width(),
725                   scaled_size.height());
726     scrollbar_layer->CreateRenderSurface();
727     scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
728
729     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
730     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
731
732     ResourceUpdateQueue queue;
733     OcclusionTracker occlusion_tracker(gfx::Rect(), false);
734     scrollbar_layer->SavePaintProperties();
735     scrollbar_layer->Update(&queue, &occlusion_tracker);
736
737     // Verify that we have not generated any content uploads that are larger
738     // than their destination textures.
739
740     gfx::Size track_size = layer_tree_host_->ui_resource_size(
741         scrollbar_layer->track_resource_id());
742     gfx::Size thumb_size = layer_tree_host_->ui_resource_size(
743         scrollbar_layer->thumb_resource_id());
744
745     EXPECT_LE(track_size.width(), scrollbar_layer->content_bounds().width());
746     EXPECT_LE(track_size.height(), scrollbar_layer->content_bounds().height());
747     EXPECT_LE(thumb_size.width(), scrollbar_layer->content_bounds().width());
748     EXPECT_LE(thumb_size.height(), scrollbar_layer->content_bounds().height());
749
750     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
751
752     scrollbar_layer->ClearRenderSurface();
753   }
754
755  protected:
756   FakeLayerTreeHostClient fake_client_;
757   LayerTreeSettings layer_tree_settings_;
758   scoped_ptr<MockLayerTreeHost> layer_tree_host_;
759 };
760
761 TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
762   // Pick a test scale that moves the scrollbar's (non-zero) position to
763   // a non-pixel-aligned location.
764   TestResourceUpload(.041f);
765   TestResourceUpload(1.41f);
766   TestResourceUpload(4.1f);
767 }
768
769 }  // namespace
770 }  // namespace cc