Home | History | Annotate | Download | only in layers
      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_occlusion_tracker.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/occlusion_tracker.h"
     28 #include "cc/trees/single_thread_proxy.h"
     29 #include "cc/trees/tree_synchronizer.h"
     30 #include "testing/gmock/include/gmock/gmock.h"
     31 #include "testing/gtest/include/gtest/gtest.h"
     32 
     33 namespace cc {
     34 namespace {
     35 
     36 LayerImpl* LayerImplForScrollAreaAndScrollbar(FakeLayerTreeHost* host,
     37                                               scoped_ptr<Scrollbar> scrollbar,
     38                                               bool reverse_order,
     39                                               bool use_solid_color_scrollbar,
     40                                               int thumb_thickness,
     41                                               int track_start) {
     42   scoped_refptr<Layer> layer_tree_root = Layer::Create();
     43   scoped_refptr<Layer> child1 = Layer::Create();
     44   scoped_refptr<Layer> child2;
     45   if (use_solid_color_scrollbar) {
     46     const bool kIsLeftSideVerticalScrollbar = false;
     47     child2 = SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
     48                                               thumb_thickness,
     49                                               track_start,
     50                                               kIsLeftSideVerticalScrollbar,
     51                                               child1->id());
     52   } else {
     53     child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id());
     54   }
     55   child2->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
     56   layer_tree_root->AddChild(child1);
     57   layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
     58   host->SetRootLayer(layer_tree_root);
     59   return host->CommitAndCreateLayerImplTree();
     60 }
     61 
     62 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
     63   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
     64   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
     65   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
     66   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
     67       host.get(), scrollbar.Pass(), false, false, 0, 0);
     68 
     69   LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
     70   PaintedScrollbarLayerImpl* cc_child2 =
     71       static_cast<PaintedScrollbarLayerImpl*>(
     72           layer_impl_tree_root->children()[1]);
     73 
     74   EXPECT_EQ(cc_child1->scrollbars()->size(), 1UL);
     75   EXPECT_EQ(*(cc_child1->scrollbars()->begin()), cc_child2);
     76 }
     77 
     78 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
     79   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
     80   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
     81   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
     82   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
     83       host.get(), scrollbar.Pass(), true, false, 0, 0);
     84 
     85   PaintedScrollbarLayerImpl* cc_child1 =
     86       static_cast<PaintedScrollbarLayerImpl*>(
     87           layer_impl_tree_root->children()[0]);
     88   LayerImpl* cc_child2 = layer_impl_tree_root->children()[1];
     89 
     90   EXPECT_EQ(cc_child2->scrollbars()->size(), 1UL);
     91   EXPECT_EQ(*(cc_child2->scrollbars()->begin()), cc_child1);
     92 }
     93 
     94 TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
     95   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
     96   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
     97 
     98   // Create and attach a non-overlay scrollbar.
     99   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
    100   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
    101       host.get(), scrollbar.Pass(), false, false, 0, 0);
    102   PaintedScrollbarLayerImpl* scrollbar_layer_impl =
    103       static_cast<PaintedScrollbarLayerImpl*>(
    104           layer_impl_tree_root->children()[1]);
    105 
    106   // When the scrollbar is not an overlay scrollbar, the scroll should be
    107   // responded to on the main thread as the compositor does not yet implement
    108   // scrollbar scrolling.
    109   EXPECT_EQ(InputHandler::ScrollOnMainThread,
    110             scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
    111                                             InputHandler::Gesture));
    112 
    113   // Create and attach an overlay scrollbar.
    114   scrollbar.reset(new FakeScrollbar(false, false, true));
    115 
    116   layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
    117       host.get(), scrollbar.Pass(), false, false, 0, 0);
    118   scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
    119       layer_impl_tree_root->children()[1]);
    120 
    121   // The user shouldn't be able to drag an overlay scrollbar and the scroll
    122   // may be handled in the compositor.
    123   EXPECT_EQ(InputHandler::ScrollIgnored,
    124             scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
    125                                             InputHandler::Gesture));
    126 }
    127 
    128 TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
    129   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
    130   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
    131 
    132   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
    133   scoped_refptr<Layer> layer_tree_root = Layer::Create();
    134   scoped_refptr<Layer> scroll_layer = Layer::Create();
    135   scoped_refptr<Layer> content_layer = Layer::Create();
    136   scoped_refptr<Layer> scrollbar_layer =
    137       PaintedScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
    138 
    139   // Choose bounds to give max_scroll_offset = (30, 50).
    140   layer_tree_root->SetBounds(gfx::Size(70, 150));
    141   scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
    142   scroll_layer->SetScrollOffset(gfx::Vector2d(10, 20));
    143   scroll_layer->SetBounds(gfx::Size(100, 200));
    144   content_layer->SetBounds(gfx::Size(100, 200));
    145 
    146   host->SetRootLayer(layer_tree_root);
    147   layer_tree_root->AddChild(scroll_layer);
    148   scroll_layer->AddChild(content_layer);
    149   layer_tree_root->AddChild(scrollbar_layer);
    150   scrollbar_layer->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
    151   scrollbar_layer->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
    152 
    153   layer_tree_root->SavePaintProperties();
    154   content_layer->SavePaintProperties();
    155 
    156   LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
    157 
    158   ScrollbarLayerImplBase* cc_scrollbar_layer =
    159       static_cast<PaintedScrollbarLayerImpl*>(
    160           layer_impl_tree_root->children()[1]);
    161 
    162   EXPECT_EQ(10.f, cc_scrollbar_layer->current_pos());
    163   EXPECT_EQ(30, cc_scrollbar_layer->maximum());
    164 
    165   layer_tree_root->SetBounds(gfx::Size(700, 1500));
    166   layer_tree_root->SavePaintProperties();
    167   scroll_layer->SetBounds(gfx::Size(1000, 2000));
    168   scroll_layer->SetScrollOffset(gfx::Vector2d(100, 200));
    169   scroll_layer->SavePaintProperties();
    170   content_layer->SetBounds(gfx::Size(1000, 2000));
    171   content_layer->SavePaintProperties();
    172 
    173   ScrollbarAnimationController* scrollbar_controller =
    174       layer_impl_tree_root->scrollbar_animation_controller();
    175   layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
    176   EXPECT_EQ(scrollbar_controller,
    177             layer_impl_tree_root->scrollbar_animation_controller());
    178 
    179   EXPECT_EQ(100.f, cc_scrollbar_layer->current_pos());
    180   EXPECT_EQ(300, cc_scrollbar_layer->maximum());
    181 
    182   LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
    183   scroll_layer_impl->ScrollBy(gfx::Vector2d(12, 34));
    184 
    185   EXPECT_EQ(112.f, cc_scrollbar_layer->current_pos());
    186   EXPECT_EQ(300, cc_scrollbar_layer->maximum());
    187 }
    188 
    189 #define UPDATE_AND_EXTRACT_LAYER_POINTERS()                         \
    190   do {                                                              \
    191     scrollbar_layer->UpdateThumbAndTrackGeometry();                 \
    192     root_clip_layer_impl = host->CommitAndCreateLayerImplTree();    \
    193     root_layer_impl = root_clip_layer_impl->children()[0];          \
    194     scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
    195         root_layer_impl->children()[1]);                            \
    196     scrollbar_layer_impl->ScrollbarParametersDidChange();           \
    197   } while (false)
    198 
    199 TEST(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
    200   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
    201   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
    202   scoped_refptr<Layer> root_clip_layer = Layer::Create();
    203   scoped_refptr<Layer> root_layer = Layer::Create();
    204   scoped_refptr<Layer> content_layer = Layer::Create();
    205   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
    206       FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
    207 
    208   root_layer->SetScrollClipLayerId(root_clip_layer->id());
    209   // Give the root-clip a size that will result in MaxScrollOffset = (80, 0).
    210   root_clip_layer->SetBounds(gfx::Size(20, 50));
    211   root_layer->SetBounds(gfx::Size(100, 50));
    212   content_layer->SetBounds(gfx::Size(100, 50));
    213 
    214   host->SetRootLayer(root_clip_layer);
    215   root_clip_layer->AddChild(root_layer);
    216   root_layer->AddChild(content_layer);
    217   root_layer->AddChild(scrollbar_layer);
    218 
    219   root_layer->SetScrollOffset(gfx::Vector2d(0, 0));
    220   scrollbar_layer->SetBounds(gfx::Size(70, 10));
    221   scrollbar_layer->SetScrollLayer(root_layer->id());
    222   scrollbar_layer->SetClipLayer(root_clip_layer->id());
    223   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
    224   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
    225   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
    226   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
    227 
    228   scrollbar_layer->UpdateThumbAndTrackGeometry();
    229   LayerImpl* root_clip_layer_impl = NULL;
    230   LayerImpl* root_layer_impl = NULL;
    231   PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL;
    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   scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
    238 
    239   UPDATE_AND_EXTRACT_LAYER_POINTERS();
    240   EXPECT_EQ(gfx::Rect(10, 0, 0, 0).ToString(),
    241             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
    242 }
    243 
    244 TEST(ScrollbarLayerTest, ThumbRect) {
    245   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
    246   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
    247   scoped_refptr<Layer> root_clip_layer = Layer::Create();
    248   scoped_refptr<Layer> root_layer = Layer::Create();
    249   scoped_refptr<Layer> content_layer = Layer::Create();
    250   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
    251       FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
    252 
    253   root_layer->SetScrollClipLayerId(root_clip_layer->id());
    254   // Give the root-clip a size that will result in MaxScrollOffset = (80, 0).
    255   root_clip_layer->SetBounds(gfx::Size(20, 50));
    256   root_layer->SetBounds(gfx::Size(100, 50));
    257   content_layer->SetBounds(gfx::Size(100, 50));
    258 
    259   host->SetRootLayer(root_clip_layer);
    260   root_clip_layer->AddChild(root_layer);
    261   root_layer->AddChild(content_layer);
    262   root_layer->AddChild(scrollbar_layer);
    263 
    264   root_layer->SetScrollOffset(gfx::Vector2d(0, 0));
    265   scrollbar_layer->SetBounds(gfx::Size(70, 10));
    266   scrollbar_layer->SetScrollLayer(root_layer->id());
    267   scrollbar_layer->SetClipLayer(root_clip_layer->id());
    268   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
    269   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
    270   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
    271   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
    272   scrollbar_layer->UpdateThumbAndTrackGeometry();
    273   LayerImpl* root_clip_layer_impl = NULL;
    274   LayerImpl* root_layer_impl = NULL;
    275   PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL;
    276 
    277   // Thumb is at the edge of the scrollbar (should be inset to
    278   // the start of the track within the scrollbar layer's
    279   // position).
    280   UPDATE_AND_EXTRACT_LAYER_POINTERS();
    281   EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
    282             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
    283 
    284   // Under-scroll (thumb position should clamp and be unchanged).
    285   root_layer->SetScrollOffset(gfx::Vector2d(-5, 0));
    286 
    287   UPDATE_AND_EXTRACT_LAYER_POINTERS();
    288   EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
    289             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
    290 
    291   // Over-scroll (thumb position should clamp on the far side).
    292   root_layer->SetScrollOffset(gfx::Vector2d(85, 0));
    293 
    294   UPDATE_AND_EXTRACT_LAYER_POINTERS();
    295   EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
    296             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
    297 
    298   // Change thumb thickness and length.
    299   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(4);
    300   scrollbar_layer->fake_scrollbar()->set_thumb_length(6);
    301 
    302   UPDATE_AND_EXTRACT_LAYER_POINTERS();
    303   EXPECT_EQ(gfx::Rect(54, 0, 6, 4).ToString(),
    304             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
    305 
    306   // Shrink the scrollbar layer to cover only the track.
    307   scrollbar_layer->SetBounds(gfx::Size(50, 10));
    308   scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(30, 10));
    309   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
    310 
    311   UPDATE_AND_EXTRACT_LAYER_POINTERS();
    312   EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
    313             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
    314 
    315   // Shrink the track in the non-scrolling dimension so that it only covers the
    316   // middle third of the scrollbar layer (this does not affect the thumb
    317   // position).
    318   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 12, 50, 6));
    319 
    320   UPDATE_AND_EXTRACT_LAYER_POINTERS();
    321   EXPECT_EQ(gfx::Rect(44, 0, 6, 4).ToString(),
    322             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
    323 }
    324 
    325 TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
    326   const int kThumbThickness = 3;
    327   const int kTrackStart = 1;
    328   const int kTrackLength = 100;
    329 
    330   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
    331   LayerTreeSettings layer_tree_settings;
    332   scoped_ptr<FakeLayerTreeHost> host =
    333       FakeLayerTreeHost::Create(&client, layer_tree_settings);
    334 
    335   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
    336   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
    337       host.get(), scrollbar.Pass(), false, true, kThumbThickness, kTrackStart);
    338   ScrollbarLayerImplBase* scrollbar_layer_impl =
    339       static_cast<SolidColorScrollbarLayerImpl*>(
    340           layer_impl_tree_root->children()[1]);
    341   scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
    342   scrollbar_layer_impl->SetCurrentPos(10.f);
    343   scrollbar_layer_impl->SetMaximum(100);
    344   scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.4f);
    345 
    346   // Thickness should be overridden to 3.
    347   {
    348     MockOcclusionTracker<LayerImpl> occlusion_tracker;
    349     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
    350     AppendQuadsData data;
    351     scrollbar_layer_impl->AppendQuads(
    352         render_pass.get(), occlusion_tracker, &data);
    353 
    354     const QuadList& quads = render_pass->quad_list;
    355     ASSERT_EQ(1u, quads.size());
    356     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
    357     EXPECT_RECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
    358   }
    359 
    360   // Contents scale should scale the draw quad.
    361   scrollbar_layer_impl->draw_properties().contents_scale_x = 2.f;
    362   scrollbar_layer_impl->draw_properties().contents_scale_y = 2.f;
    363   {
    364     MockOcclusionTracker<LayerImpl> occlusion_tracker;
    365     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
    366     AppendQuadsData data;
    367     scrollbar_layer_impl->AppendQuads(
    368         render_pass.get(), occlusion_tracker, &data);
    369 
    370     const QuadList& quads = render_pass->quad_list;
    371     ASSERT_EQ(1u, quads.size());
    372     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
    373     EXPECT_RECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect);
    374   }
    375   scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f;
    376   scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f;
    377 
    378   // For solid color scrollbars, position and size should reflect the
    379   // current viewport state.
    380   scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.2f);
    381   {
    382     MockOcclusionTracker<LayerImpl> occlusion_tracker;
    383     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
    384     AppendQuadsData data;
    385     scrollbar_layer_impl->AppendQuads(
    386         render_pass.get(), occlusion_tracker, &data);
    387 
    388     const QuadList& quads = render_pass->quad_list;
    389     ASSERT_EQ(1u, quads.size());
    390     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
    391     EXPECT_RECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
    392   }
    393 
    394   // We shouldn't attempt div-by-zero when the maximum is zero.
    395   scrollbar_layer_impl->SetCurrentPos(0.f);
    396   scrollbar_layer_impl->SetMaximum(0);
    397   {
    398     MockOcclusionTracker<LayerImpl> occlusion_tracker;
    399     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
    400     AppendQuadsData data;
    401     scrollbar_layer_impl->AppendQuads(
    402         render_pass.get(), occlusion_tracker, &data);
    403 
    404     const QuadList& quads = render_pass->quad_list;
    405     ASSERT_EQ(1u, quads.size());
    406     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
    407     EXPECT_RECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect);
    408   }
    409 }
    410 
    411 TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
    412   const int kThumbThickness = 3;
    413   const int kTrackStart = 0;
    414   const int kTrackLength = 10;
    415 
    416   FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
    417   LayerTreeSettings layer_tree_settings;
    418   scoped_ptr<FakeLayerTreeHost> host =
    419       FakeLayerTreeHost::Create(&client, layer_tree_settings);
    420 
    421   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
    422 
    423   {
    424     scoped_refptr<Layer> layer_tree_root = Layer::Create();
    425     scoped_refptr<Layer> scroll_layer = Layer::Create();
    426     scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
    427     scoped_refptr<Layer> child1 = Layer::Create();
    428     scoped_refptr<Layer> child2;
    429     const bool kIsLeftSideVerticalScrollbar = false;
    430     child2 = SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
    431                                               kThumbThickness,
    432                                               kTrackStart,
    433                                               kIsLeftSideVerticalScrollbar,
    434                                               child1->id());
    435     child2->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
    436     child2->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
    437     scroll_layer->AddChild(child1);
    438     scroll_layer->InsertChild(child2, 1);
    439     layer_tree_root->AddChild(scroll_layer);
    440     host->SetRootLayer(layer_tree_root);
    441   }
    442   LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
    443   LayerImpl* scroll_layer_impl = layer_impl_tree_root->children()[0];
    444 
    445   ScrollbarLayerImplBase* scrollbar_layer_impl =
    446       static_cast<PaintedScrollbarLayerImpl*>(scroll_layer_impl->children()[1]);
    447 
    448   // Choose layer bounds to give max_scroll_offset = (8, 8).
    449   layer_impl_tree_root->SetBounds(gfx::Size(2, 2));
    450   scroll_layer_impl->SetBounds(gfx::Size(10, 10));
    451   scroll_layer_impl->ScrollBy(gfx::Vector2dF(4.f, 0.f));
    452 
    453   scrollbar_layer_impl->SetBounds(gfx::Size(kTrackLength, kThumbThickness));
    454   scrollbar_layer_impl->SetCurrentPos(4.f);
    455   scrollbar_layer_impl->SetMaximum(8);
    456 
    457   {
    458     MockOcclusionTracker<LayerImpl> occlusion_tracker;
    459     scoped_ptr<RenderPass> render_pass = RenderPass::Create();
    460 
    461     AppendQuadsData data;
    462     scrollbar_layer_impl->AppendQuads(
    463         render_pass.get(), occlusion_tracker, &data);
    464 
    465     const QuadList& quads = render_pass->quad_list;
    466     ASSERT_EQ(1u, quads.size());
    467     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
    468     EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
    469   }
    470 }
    471 
    472 class ScrollbarLayerSolidColorThumbTest : public testing::Test {
    473  public:
    474   ScrollbarLayerSolidColorThumbTest() {
    475     LayerTreeSettings layer_tree_settings;
    476     host_impl_.reset(new FakeLayerTreeHostImpl(
    477         layer_tree_settings, &proxy_, &shared_bitmap_manager_));
    478 
    479     const int kThumbThickness = 3;
    480     const int kTrackStart = 0;
    481     const bool kIsLeftSideVerticalScrollbar = false;
    482     const bool kIsOverlayScrollbar = false;
    483 
    484     horizontal_scrollbar_layer_ =
    485         SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
    486                                              1,
    487                                              HORIZONTAL,
    488                                              kThumbThickness,
    489                                              kTrackStart,
    490                                              kIsLeftSideVerticalScrollbar,
    491                                              kIsOverlayScrollbar);
    492     vertical_scrollbar_layer_ =
    493         SolidColorScrollbarLayerImpl::Create(host_impl_->active_tree(),
    494                                              2,
    495                                              VERTICAL,
    496                                              kThumbThickness,
    497                                              kTrackStart,
    498                                              kIsLeftSideVerticalScrollbar,
    499                                              kIsOverlayScrollbar);
    500   }
    501 
    502  protected:
    503   FakeImplProxy proxy_;
    504   TestSharedBitmapManager shared_bitmap_manager_;
    505   scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
    506   scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
    507   scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
    508 };
    509 
    510 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbLength) {
    511   horizontal_scrollbar_layer_->SetCurrentPos(0);
    512   horizontal_scrollbar_layer_->SetMaximum(10);
    513 
    514   // Simple case - one third of the scrollable area is visible, so the thumb
    515   // should be one third as long as the track.
    516   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.33f);
    517   horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
    518   EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
    519 
    520   // The thumb's length should never be less than its thickness.
    521   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.01f);
    522   horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
    523   EXPECT_EQ(3, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
    524 }
    525 
    526 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) {
    527   horizontal_scrollbar_layer_->SetBounds(gfx::Size(100, 3));
    528   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.1f);
    529 
    530   horizontal_scrollbar_layer_->SetCurrentPos(0);
    531   horizontal_scrollbar_layer_->SetMaximum(100);
    532   EXPECT_EQ(0, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
    533   EXPECT_EQ(10, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
    534 
    535   horizontal_scrollbar_layer_->SetCurrentPos(100);
    536   // The thumb is 10px long and the track is 100px, so the maximum thumb
    537   // position is 90px.
    538   EXPECT_EQ(90, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
    539 
    540   horizontal_scrollbar_layer_->SetCurrentPos(80);
    541   // The scroll position is 80% of the maximum, so the thumb's position should
    542   // be at 80% of its maximum or 72px.
    543   EXPECT_EQ(72, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
    544 }
    545 
    546 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
    547   SolidColorScrollbarLayerImpl* layers[2] =
    548       { horizontal_scrollbar_layer_.get(), vertical_scrollbar_layer_.get() };
    549   for (size_t i = 0; i < 2; ++i) {
    550     layers[i]->SetVisibleToTotalLengthRatio(0.2f);
    551     layers[i]->SetCurrentPos(25);
    552     layers[i]->SetMaximum(100);
    553   }
    554   layers[0]->SetBounds(gfx::Size(100, 3));
    555   layers[1]->SetBounds(gfx::Size(3, 100));
    556 
    557   EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
    558                  horizontal_scrollbar_layer_->ComputeThumbQuadRect());
    559   EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
    560                  vertical_scrollbar_layer_->ComputeThumbQuadRect());
    561 
    562   horizontal_scrollbar_layer_->SetVerticalAdjust(10.f);
    563   vertical_scrollbar_layer_->SetVerticalAdjust(10.f);
    564 
    565   // The vertical adjustment factor has two effects:
    566   // 1.) Moves the horizontal scrollbar down
    567   // 2.) Increases the vertical scrollbar's effective track length which both
    568   // increases the thumb's length and its position within the track.
    569   EXPECT_RECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
    570                  horizontal_scrollbar_layer_->ComputeThumbQuadRect());
    571   EXPECT_RECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
    572                  vertical_scrollbar_layer_->ComputeThumbQuadRect());
    573 }
    574 
    575 class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
    576  public:
    577   ScrollbarLayerTestMaxTextureSize() {}
    578 
    579   void SetScrollbarBounds(const gfx::Size& bounds) { bounds_ = bounds; }
    580 
    581   virtual void BeginTest() OVERRIDE {
    582     scroll_layer_ = Layer::Create();
    583     layer_tree_host()->root_layer()->AddChild(scroll_layer_);
    584 
    585     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
    586     scrollbar_layer_ =
    587         PaintedScrollbarLayer::Create(scrollbar.Pass(), scroll_layer_->id());
    588     scrollbar_layer_->SetScrollLayer(scroll_layer_->id());
    589     scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
    590     scrollbar_layer_->SetBounds(bounds_);
    591     layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
    592 
    593     PostSetNeedsCommitToMainThread();
    594   }
    595 
    596   virtual void DidCommitAndDrawFrame() OVERRIDE {
    597     const int kMaxTextureSize =
    598         layer_tree_host()->GetRendererCapabilities().max_texture_size;
    599 
    600     // Check first that we're actually testing something.
    601     EXPECT_GT(scrollbar_layer_->bounds().width(), kMaxTextureSize);
    602 
    603     EXPECT_EQ(scrollbar_layer_->content_bounds().width(),
    604               kMaxTextureSize - 1);
    605     EXPECT_EQ(scrollbar_layer_->content_bounds().height(),
    606               kMaxTextureSize - 1);
    607 
    608     EndTest();
    609   }
    610 
    611   virtual void AfterTest() OVERRIDE {}
    612 
    613  private:
    614   scoped_refptr<PaintedScrollbarLayer> scrollbar_layer_;
    615   scoped_refptr<Layer> scroll_layer_;
    616   gfx::Size bounds_;
    617 };
    618 
    619 TEST_F(ScrollbarLayerTestMaxTextureSize, DirectRenderer) {
    620   scoped_ptr<TestWebGraphicsContext3D> context =
    621       TestWebGraphicsContext3D::Create();
    622   int max_size = 0;
    623   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
    624   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
    625   RunTest(true, false, true);
    626 }
    627 
    628 TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) {
    629   scoped_ptr<TestWebGraphicsContext3D> context =
    630       TestWebGraphicsContext3D::Create();
    631   int max_size = 0;
    632   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
    633   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
    634   RunTest(true, true, true);
    635 }
    636 
    637 class FakeLayerTreeHost : public LayerTreeHost {
    638  public:
    639   FakeLayerTreeHost(FakeLayerTreeHostClient* client,
    640                     const LayerTreeSettings& settings)
    641       : LayerTreeHost(client, NULL, settings),
    642         next_id_(1),
    643         total_ui_resource_created_(0),
    644         total_ui_resource_deleted_(0) {
    645     InitializeSingleThreaded(client, base::MessageLoopProxy::current());
    646   }
    647 
    648   virtual UIResourceId CreateUIResource(UIResourceClient* content) OVERRIDE {
    649     total_ui_resource_created_++;
    650     UIResourceId nid = next_id_++;
    651     ui_resource_bitmap_map_.insert(
    652         std::make_pair(nid, content->GetBitmap(nid, false)));
    653     return nid;
    654   }
    655 
    656   // Deletes a UI resource.  May safely be called more than once.
    657   virtual void DeleteUIResource(UIResourceId id) OVERRIDE {
    658     UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
    659     if (iter != ui_resource_bitmap_map_.end()) {
    660       ui_resource_bitmap_map_.erase(iter);
    661       total_ui_resource_deleted_++;
    662     }
    663   }
    664 
    665   size_t UIResourceCount() { return ui_resource_bitmap_map_.size(); }
    666   int TotalUIResourceDeleted() { return total_ui_resource_deleted_; }
    667   int TotalUIResourceCreated() { return total_ui_resource_created_; }
    668 
    669   gfx::Size ui_resource_size(UIResourceId id) {
    670     UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
    671     if (iter != ui_resource_bitmap_map_.end())
    672       return iter->second.GetSize();
    673     return gfx::Size();
    674   }
    675 
    676   UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
    677     UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
    678     if (iter != ui_resource_bitmap_map_.end())
    679       return &iter->second;
    680     return NULL;
    681   }
    682 
    683  private:
    684   typedef base::hash_map<UIResourceId, UIResourceBitmap>
    685       UIResourceBitmapMap;
    686   UIResourceBitmapMap ui_resource_bitmap_map_;
    687 
    688   int next_id_;
    689   int total_ui_resource_created_;
    690   int total_ui_resource_deleted_;
    691 };
    692 
    693 class ScrollbarLayerTestResourceCreationAndRelease : public testing::Test {
    694  public:
    695   ScrollbarLayerTestResourceCreationAndRelease()
    696       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
    697 
    698   void TestResourceUpload(int num_updates,
    699                           size_t expected_resources,
    700                           int expected_created,
    701                           int expected_deleted,
    702                           bool use_solid_color_scrollbar) {
    703     layer_tree_host_.reset(
    704         new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
    705 
    706     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
    707     scoped_refptr<Layer> layer_tree_root = Layer::Create();
    708     scoped_refptr<Layer> content_layer = Layer::Create();
    709     scoped_refptr<Layer> scrollbar_layer;
    710     if (use_solid_color_scrollbar) {
    711       const int kThumbThickness = 3;
    712       const int kTrackStart = 0;
    713       const bool kIsLeftSideVerticalScrollbar = false;
    714       scrollbar_layer =
    715           SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
    716                                            kThumbThickness,
    717                                            kTrackStart,
    718                                            kIsLeftSideVerticalScrollbar,
    719                                            layer_tree_root->id());
    720     } else {
    721       scrollbar_layer = PaintedScrollbarLayer::Create(scrollbar.Pass(),
    722                                                       layer_tree_root->id());
    723     }
    724     layer_tree_root->AddChild(content_layer);
    725     layer_tree_root->AddChild(scrollbar_layer);
    726 
    727     layer_tree_host_->SetRootLayer(layer_tree_root);
    728 
    729     scrollbar_layer->SetIsDrawable(true);
    730     scrollbar_layer->SetBounds(gfx::Size(100, 100));
    731     layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
    732     layer_tree_root->SetBounds(gfx::Size(100, 200));
    733     content_layer->SetBounds(gfx::Size(100, 200));
    734     scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200);
    735     scrollbar_layer->draw_properties().visible_content_rect =
    736         gfx::Rect(0, 0, 100, 200);
    737     scrollbar_layer->CreateRenderSurface();
    738     scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
    739 
    740     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    741     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
    742 
    743     ResourceUpdateQueue queue;
    744     gfx::Rect screen_space_clip_rect;
    745     OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
    746 
    747     scrollbar_layer->SavePaintProperties();
    748     for (int update_counter = 0; update_counter < num_updates; update_counter++)
    749       scrollbar_layer->Update(&queue, &occlusion_tracker);
    750 
    751     // A non-solid-color scrollbar should have requested two textures.
    752     EXPECT_EQ(expected_resources, layer_tree_host_->UIResourceCount());
    753     EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    754     EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    755 
    756     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    757 
    758     scrollbar_layer->ClearRenderSurface();
    759   }
    760 
    761  protected:
    762   FakeLayerTreeHostClient fake_client_;
    763   LayerTreeSettings layer_tree_settings_;
    764   scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
    765 };
    766 
    767 TEST_F(ScrollbarLayerTestResourceCreationAndRelease, ResourceUpload) {
    768   bool use_solid_color_scrollbars = false;
    769   TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
    770   int num_updates[3] = {1, 5, 10};
    771   for (int j = 0; j < 3; j++) {
    772     TestResourceUpload(num_updates[j],
    773                        2,
    774                        num_updates[j] * 2,
    775                        (num_updates[j] - 1) * 2,
    776                        use_solid_color_scrollbars);
    777   }
    778 }
    779 
    780 TEST_F(ScrollbarLayerTestResourceCreationAndRelease,
    781        SolidColorNoResourceUpload) {
    782   bool use_solid_color_scrollbars = true;
    783   TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
    784   TestResourceUpload(1, 0, 0, 0, use_solid_color_scrollbars);
    785 }
    786 
    787 TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
    788   FakeLayerTreeHostClient fake_client_(FakeLayerTreeHostClient::DIRECT_3D);
    789   LayerTreeSettings layer_tree_settings_;
    790   scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
    791 
    792   layer_tree_host_.reset(
    793       new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
    794 
    795   gfx::Point scrollbar_location(0, 185);
    796   scoped_refptr<Layer> layer_tree_root = Layer::Create();
    797   scoped_refptr<Layer> content_layer = Layer::Create();
    798   scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
    799       FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
    800 
    801   layer_tree_root->AddChild(content_layer);
    802   layer_tree_root->AddChild(scrollbar_layer);
    803 
    804   layer_tree_host_->SetRootLayer(layer_tree_root);
    805 
    806   scrollbar_layer->SetIsDrawable(true);
    807   scrollbar_layer->SetBounds(gfx::Size(100, 15));
    808   scrollbar_layer->SetPosition(scrollbar_location);
    809   layer_tree_root->SetBounds(gfx::Size(100, 200));
    810   content_layer->SetBounds(gfx::Size(100, 200));
    811 
    812   scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200);
    813   scrollbar_layer->draw_properties().visible_content_rect =
    814       gfx::Rect(0, 0, 100, 200);
    815 
    816   scrollbar_layer->CreateRenderSurface();
    817   scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
    818 
    819   testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    820   EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
    821 
    822   ResourceUpdateQueue queue;
    823   gfx::Rect screen_space_clip_rect;
    824   size_t resource_count;
    825   int expected_created, expected_deleted;
    826   OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
    827   scrollbar_layer->SavePaintProperties();
    828 
    829   resource_count = 2;
    830   expected_created = 2;
    831   expected_deleted = 0;
    832   EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    833   EXPECT_NE(0, scrollbar_layer->track_resource_id());
    834   EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
    835   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    836   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    837   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    838 
    839   resource_count = 0;
    840   expected_created = 2;
    841   expected_deleted = 2;
    842   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
    843   EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    844   EXPECT_EQ(0, scrollbar_layer->track_resource_id());
    845   EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
    846   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    847   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    848   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    849 
    850   resource_count = 0;
    851   expected_created = 2;
    852   expected_deleted = 2;
    853   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
    854   EXPECT_FALSE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    855   EXPECT_EQ(0, scrollbar_layer->track_resource_id());
    856   EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
    857   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    858   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    859   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    860 
    861   resource_count = 2;
    862   expected_created = 4;
    863   expected_deleted = 2;
    864   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
    865   EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    866   EXPECT_NE(0, scrollbar_layer->track_resource_id());
    867   EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
    868   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    869   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    870   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    871 
    872   resource_count = 1;
    873   expected_created = 5;
    874   expected_deleted = 4;
    875   scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
    876   EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    877   EXPECT_NE(0, scrollbar_layer->track_resource_id());
    878   EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
    879   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    880   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    881   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    882 
    883   resource_count = 0;
    884   expected_created = 5;
    885   expected_deleted = 5;
    886   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
    887   EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    888   EXPECT_EQ(0, scrollbar_layer->track_resource_id());
    889   EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
    890   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    891   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    892   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    893 
    894   resource_count = 2;
    895   expected_created = 7;
    896   expected_deleted = 5;
    897   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
    898   scrollbar_layer->fake_scrollbar()->set_has_thumb(true);
    899   EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    900   EXPECT_NE(0, scrollbar_layer->track_resource_id());
    901   EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
    902 
    903   resource_count = 1;
    904   expected_created = 8;
    905   expected_deleted = 7;
    906   scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
    907   scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
    908   scrollbar_layer->SetBounds(gfx::Size(90, 15));
    909   EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    910   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    911   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    912   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    913   EXPECT_EQ(
    914       gfx::Size(90, 15),
    915       layer_tree_host_->ui_resource_size(scrollbar_layer->track_resource_id()));
    916 
    917   scrollbar_layer->ResetNeedsDisplayForTesting();
    918   EXPECT_FALSE(scrollbar_layer->Update(&queue, &occlusion_tracker));
    919   EXPECT_NE(0, scrollbar_layer->track_resource_id());
    920   EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
    921   EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
    922   EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
    923   EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
    924 
    925   testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    926   scrollbar_layer->ClearRenderSurface();
    927 }
    928 
    929 class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
    930  public:
    931   ScaledScrollbarLayerTestResourceCreation()
    932       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
    933 
    934   void TestResourceUpload(const float test_scale) {
    935     layer_tree_host_.reset(
    936         new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
    937 
    938     gfx::Point scrollbar_location(0, 185);
    939     scoped_refptr<Layer> layer_tree_root = Layer::Create();
    940     scoped_refptr<Layer> content_layer = Layer::Create();
    941     scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
    942         FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
    943 
    944     layer_tree_root->AddChild(content_layer);
    945     layer_tree_root->AddChild(scrollbar_layer);
    946 
    947     layer_tree_host_->SetRootLayer(layer_tree_root);
    948 
    949     scrollbar_layer->SetIsDrawable(true);
    950     scrollbar_layer->SetBounds(gfx::Size(100, 15));
    951     scrollbar_layer->SetPosition(scrollbar_location);
    952     layer_tree_root->SetBounds(gfx::Size(100, 200));
    953     content_layer->SetBounds(gfx::Size(100, 200));
    954     gfx::SizeF scaled_size =
    955         gfx::ScaleSize(scrollbar_layer->bounds(), test_scale, test_scale);
    956     gfx::PointF scaled_location =
    957         gfx::ScalePoint(scrollbar_layer->position(), test_scale, test_scale);
    958     scrollbar_layer->draw_properties().content_bounds =
    959         gfx::Size(scaled_size.width(), scaled_size.height());
    960     scrollbar_layer->draw_properties().contents_scale_x = test_scale;
    961     scrollbar_layer->draw_properties().contents_scale_y = test_scale;
    962     scrollbar_layer->draw_properties().visible_content_rect =
    963         gfx::Rect(scaled_location.x(),
    964                   scaled_location.y(),
    965                   scaled_size.width(),
    966                   scaled_size.height());
    967     scrollbar_layer->CreateRenderSurface();
    968     scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
    969 
    970     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    971     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
    972 
    973     ResourceUpdateQueue queue;
    974     gfx::Rect screen_space_clip_rect;
    975     OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
    976     scrollbar_layer->SavePaintProperties();
    977     scrollbar_layer->Update(&queue, &occlusion_tracker);
    978 
    979     // Verify that we have not generated any content uploads that are larger
    980     // than their destination textures.
    981 
    982     gfx::Size track_size = layer_tree_host_->ui_resource_size(
    983         scrollbar_layer->track_resource_id());
    984     gfx::Size thumb_size = layer_tree_host_->ui_resource_size(
    985         scrollbar_layer->thumb_resource_id());
    986 
    987     EXPECT_LE(track_size.width(), scrollbar_layer->content_bounds().width());
    988     EXPECT_LE(track_size.height(), scrollbar_layer->content_bounds().height());
    989     EXPECT_LE(thumb_size.width(), scrollbar_layer->content_bounds().width());
    990     EXPECT_LE(thumb_size.height(), scrollbar_layer->content_bounds().height());
    991 
    992     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    993 
    994     scrollbar_layer->ClearRenderSurface();
    995   }
    996 
    997  protected:
    998   FakeLayerTreeHostClient fake_client_;
    999   LayerTreeSettings layer_tree_settings_;
   1000   scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
   1001 };
   1002 
   1003 TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
   1004   // Pick a test scale that moves the scrollbar's (non-zero) position to
   1005   // a non-pixel-aligned location.
   1006   TestResourceUpload(.041f);
   1007   TestResourceUpload(1.41f);
   1008   TestResourceUpload(4.1f);
   1009 }
   1010 
   1011 class ScaledScrollbarLayerTestScaledRasterization : public testing::Test {
   1012  public:
   1013   ScaledScrollbarLayerTestScaledRasterization()
   1014       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
   1015 
   1016   void TestScale(const gfx::Rect scrollbar_rect, const float test_scale) {
   1017     layer_tree_host_.reset(
   1018         new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
   1019 
   1020     bool paint_during_update = true;
   1021     bool has_thumb = false;
   1022     scoped_refptr<Layer> layer_tree_root = Layer::Create();
   1023     scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
   1024         FakePaintedScrollbarLayer::Create(paint_during_update,
   1025                                           has_thumb,
   1026                                           layer_tree_root->id());
   1027 
   1028     layer_tree_root->AddChild(scrollbar_layer);
   1029 
   1030     layer_tree_host_->SetRootLayer(layer_tree_root);
   1031 
   1032     scrollbar_layer->SetBounds(scrollbar_rect.size());
   1033     scrollbar_layer->SetPosition(scrollbar_rect.origin());
   1034     scrollbar_layer->fake_scrollbar()->set_location(scrollbar_rect.origin());
   1035     scrollbar_layer->fake_scrollbar()->set_track_rect(scrollbar_rect);
   1036     gfx::SizeF scaled_size =
   1037         gfx::ScaleSize(scrollbar_layer->bounds(), test_scale, test_scale);
   1038     gfx::PointF scaled_location =
   1039         gfx::ScalePoint(scrollbar_layer->position(), test_scale, test_scale);
   1040     scrollbar_layer->draw_properties().content_bounds =
   1041         gfx::Size(scaled_size.width(), scaled_size.height());
   1042     scrollbar_layer->draw_properties().contents_scale_x = test_scale;
   1043     scrollbar_layer->draw_properties().contents_scale_y = test_scale;
   1044     scrollbar_layer->draw_properties().visible_content_rect =
   1045         gfx::Rect(scaled_location.x(),
   1046                   scaled_location.y(),
   1047                   scaled_size.width(),
   1048                   scaled_size.height());
   1049 
   1050     ResourceUpdateQueue queue;
   1051     gfx::Rect screen_space_clip_rect;
   1052     OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
   1053     scrollbar_layer->SavePaintProperties();
   1054 
   1055     scrollbar_layer->Update(&queue, &occlusion_tracker);
   1056 
   1057     UIResourceBitmap* bitmap = layer_tree_host_->ui_resource_bitmap(
   1058         scrollbar_layer->track_resource_id());
   1059 
   1060     DCHECK(bitmap);
   1061 
   1062     AutoLockUIResourceBitmap locked_bitmap(*bitmap);
   1063 
   1064     const SkColor* pixels =
   1065         reinterpret_cast<const SkColor*>(locked_bitmap.GetPixels());
   1066     SkColor color = argb_to_skia(
   1067         scrollbar_layer->fake_scrollbar()->paint_fill_color());
   1068     int width = bitmap->GetSize().width();
   1069     int height = bitmap->GetSize().height();
   1070 
   1071     // Make sure none of the corners of the bitmap were inadvertently clipped.
   1072     EXPECT_EQ(color, pixels[0])
   1073         << "Top left pixel doesn't match scrollbar color.";
   1074 
   1075     EXPECT_EQ(color, pixels[width - 1])
   1076         << "Top right pixel doesn't match scrollbar color.";
   1077 
   1078     EXPECT_EQ(color, pixels[width * (height - 1)])
   1079         << "Bottom left pixel doesn't match scrollbar color.";
   1080 
   1081     EXPECT_EQ(color, pixels[width * height - 1])
   1082         << "Bottom right pixel doesn't match scrollbar color.";
   1083   }
   1084 
   1085  protected:
   1086   // On Android, Skia uses ABGR
   1087   static SkColor argb_to_skia(SkColor c) {
   1088       return (SkColorGetA(c) << SK_A32_SHIFT) |
   1089              (SkColorGetR(c) << SK_R32_SHIFT) |
   1090              (SkColorGetG(c) << SK_G32_SHIFT) |
   1091              (SkColorGetB(c) << SK_B32_SHIFT);
   1092   }
   1093 
   1094   FakeLayerTreeHostClient fake_client_;
   1095   LayerTreeSettings layer_tree_settings_;
   1096   scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
   1097 };
   1098 
   1099 TEST_F(ScaledScrollbarLayerTestScaledRasterization, TestLostPrecisionInClip) {
   1100   // Try rasterization at coordinates and scale that caused problematic
   1101   // rounding and clipping errors.
   1102   // Vertical Scrollbars.
   1103   TestScale(gfx::Rect(1240, 0, 15, 1333), 2.7754839f);
   1104   TestScale(gfx::Rect(1240, 0, 15, 677), 2.46677136f);
   1105 
   1106   // Horizontal Scrollbars.
   1107   TestScale(gfx::Rect(0, 1240, 1333, 15), 2.7754839f);
   1108   TestScale(gfx::Rect(0, 1240, 677, 15), 2.46677136f);
   1109 }
   1110 
   1111 }  // namespace
   1112 }  // namespace cc
   1113