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 "cc/layers/scrollbar_layer.h"
      6 
      7 #include "cc/animation/scrollbar_animation_controller.h"
      8 #include "cc/layers/append_quads_data.h"
      9 #include "cc/layers/scrollbar_layer_impl.h"
     10 #include "cc/quads/solid_color_draw_quad.h"
     11 #include "cc/resources/prioritized_resource_manager.h"
     12 #include "cc/resources/priority_calculator.h"
     13 #include "cc/resources/resource_update_queue.h"
     14 #include "cc/test/fake_impl_proxy.h"
     15 #include "cc/test/fake_layer_tree_host.h"
     16 #include "cc/test/fake_layer_tree_host_client.h"
     17 #include "cc/test/fake_layer_tree_host_impl.h"
     18 #include "cc/test/fake_scrollbar.h"
     19 #include "cc/test/geometry_test_utils.h"
     20 #include "cc/test/layer_tree_test.h"
     21 #include "cc/test/mock_quad_culler.h"
     22 #include "cc/test/test_web_graphics_context_3d.h"
     23 #include "cc/trees/layer_tree_impl.h"
     24 #include "cc/trees/single_thread_proxy.h"
     25 #include "cc/trees/tree_synchronizer.h"
     26 #include "testing/gmock/include/gmock/gmock.h"
     27 #include "testing/gtest/include/gtest/gtest.h"
     28 
     29 namespace cc {
     30 namespace {
     31 
     32 LayerImpl* LayerImplForScrollAreaAndScrollbar(
     33     FakeLayerTreeHost* host,
     34     scoped_ptr<Scrollbar> scrollbar,
     35     bool reverse_order) {
     36   scoped_refptr<Layer> layer_tree_root = Layer::Create();
     37   scoped_refptr<Layer> child1 = Layer::Create();
     38   scoped_refptr<Layer> child2 =
     39       ScrollbarLayer::Create(scrollbar.Pass(),
     40                              child1->id());
     41   layer_tree_root->AddChild(child1);
     42   layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
     43   host->SetRootLayer(layer_tree_root);
     44   return host->CommitAndCreateLayerImplTree();
     45 }
     46 
     47 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
     48   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
     49   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
     50   LayerImpl* layer_impl_tree_root =
     51       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
     52 
     53   LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
     54   ScrollbarLayerImpl* cc_child2 = static_cast<ScrollbarLayerImpl*>(
     55       layer_impl_tree_root->children()[1]);
     56 
     57   EXPECT_EQ(cc_child1->horizontal_scrollbar_layer(), cc_child2);
     58 }
     59 
     60 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
     61   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
     62   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
     63   LayerImpl* layer_impl_tree_root =
     64       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), true);
     65 
     66   ScrollbarLayerImpl* cc_child1 = static_cast<ScrollbarLayerImpl*>(
     67       layer_impl_tree_root->children()[0]);
     68   LayerImpl* cc_child2 = layer_impl_tree_root->children()[1];
     69 
     70   EXPECT_EQ(cc_child2->horizontal_scrollbar_layer(), cc_child1);
     71 }
     72 
     73 TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
     74   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
     75 
     76   // Create and attach a non-overlay scrollbar.
     77   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
     78   LayerImpl* layer_impl_tree_root =
     79       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
     80   ScrollbarLayerImpl* scrollbar_layer_impl =
     81       static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
     82 
     83   // When the scrollbar is not an overlay scrollbar, the scroll should be
     84   // responded to on the main thread as the compositor does not yet implement
     85   // scrollbar scrolling.
     86   EXPECT_EQ(InputHandler::ScrollOnMainThread,
     87             scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
     88                                             InputHandler::Gesture));
     89 
     90   // Create and attach an overlay scrollbar.
     91   scrollbar.reset(new FakeScrollbar(false, false, true));
     92 
     93   layer_impl_tree_root =
     94       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
     95   scrollbar_layer_impl =
     96       static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
     97 
     98   // The user shouldn't be able to drag an overlay scrollbar and the scroll
     99   // may be handled in the compositor.
    100   EXPECT_EQ(InputHandler::ScrollIgnored,
    101             scrollbar_layer_impl->TryScroll(gfx::Point(0, 0),
    102                                             InputHandler::Gesture));
    103 }
    104 
    105 TEST(ScrollbarLayerTest, ScrollOffsetSynchronization) {
    106   scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
    107 
    108   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
    109   scoped_refptr<Layer> layer_tree_root = Layer::Create();
    110   scoped_refptr<Layer> content_layer = Layer::Create();
    111   scoped_refptr<Layer> scrollbar_layer =
    112       ScrollbarLayer::Create(scrollbar.Pass(),
    113                              layer_tree_root->id());
    114 
    115   layer_tree_root->SetScrollable(true);
    116   layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
    117   layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50));
    118   layer_tree_root->SetBounds(gfx::Size(100, 200));
    119   content_layer->SetBounds(gfx::Size(100, 200));
    120 
    121   host->SetRootLayer(layer_tree_root);
    122   layer_tree_root->AddChild(content_layer);
    123   layer_tree_root->AddChild(scrollbar_layer);
    124 
    125   layer_tree_root->SavePaintProperties();
    126   content_layer->SavePaintProperties();
    127 
    128   LayerImpl* layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
    129 
    130   ScrollbarLayerImpl* cc_scrollbar_layer =
    131       static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
    132 
    133   EXPECT_EQ(10.f, cc_scrollbar_layer->CurrentPos());
    134   EXPECT_EQ(30, cc_scrollbar_layer->Maximum());
    135 
    136   layer_tree_root->SetScrollOffset(gfx::Vector2d(100, 200));
    137   layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(300, 500));
    138   layer_tree_root->SetBounds(gfx::Size(1000, 2000));
    139   layer_tree_root->SavePaintProperties();
    140   content_layer->SetBounds(gfx::Size(1000, 2000));
    141   content_layer->SavePaintProperties();
    142 
    143   ScrollbarAnimationController* scrollbar_controller =
    144       layer_impl_tree_root->scrollbar_animation_controller();
    145   layer_impl_tree_root = host->CommitAndCreateLayerImplTree();
    146   EXPECT_EQ(scrollbar_controller,
    147             layer_impl_tree_root->scrollbar_animation_controller());
    148 
    149   EXPECT_EQ(100.f, cc_scrollbar_layer->CurrentPos());
    150   EXPECT_EQ(300, cc_scrollbar_layer->Maximum());
    151 
    152   layer_impl_tree_root->ScrollBy(gfx::Vector2d(12, 34));
    153 
    154   EXPECT_EQ(112.f, cc_scrollbar_layer->CurrentPos());
    155   EXPECT_EQ(300, cc_scrollbar_layer->Maximum());
    156 }
    157 
    158 TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
    159   LayerTreeSettings layer_tree_settings;
    160   layer_tree_settings.solid_color_scrollbars = true;
    161   layer_tree_settings.solid_color_scrollbar_thickness_dip = 3;
    162   scoped_ptr<FakeLayerTreeHost> host =
    163       FakeLayerTreeHost::Create(layer_tree_settings);
    164 
    165   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
    166   LayerImpl* layer_impl_tree_root =
    167       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
    168   ScrollbarLayerImpl* scrollbar_layer_impl =
    169       static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
    170   scrollbar_layer_impl->SetThumbThickness(3);
    171   scrollbar_layer_impl->SetCurrentPos(10.f);
    172   scrollbar_layer_impl->SetMaximum(100);
    173   scrollbar_layer_impl->SetTrackLength(100);
    174   scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.4f);
    175 
    176   // Thickness should be overridden to 3.
    177   {
    178     MockQuadCuller quad_culler;
    179     AppendQuadsData data;
    180     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
    181 
    182     const QuadList& quads = quad_culler.quad_list();
    183     ASSERT_EQ(1u, quads.size());
    184     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
    185     EXPECT_RECT_EQ(gfx::Rect(6, 0, 40, 3), quads[0]->rect);
    186   }
    187 
    188   // Contents scale should scale the draw quad.
    189   scrollbar_layer_impl->draw_properties().contents_scale_x = 2.f;
    190   scrollbar_layer_impl->draw_properties().contents_scale_y = 2.f;
    191   {
    192     MockQuadCuller quad_culler;
    193     AppendQuadsData data;
    194     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
    195 
    196     const QuadList& quads = quad_culler.quad_list();
    197     ASSERT_EQ(1u, quads.size());
    198     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
    199     EXPECT_RECT_EQ(gfx::Rect(12, 0, 80, 6), quads[0]->rect);
    200   }
    201   scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f;
    202   scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f;
    203 
    204   // For solid color scrollbars, position and size should reflect the
    205   // current viewport state.
    206   scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.2f);
    207   {
    208     MockQuadCuller quad_culler;
    209     AppendQuadsData data;
    210     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
    211 
    212     const QuadList& quads = quad_culler.quad_list();
    213     ASSERT_EQ(1u, quads.size());
    214     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
    215     EXPECT_RECT_EQ(gfx::Rect(8, 0, 20, 3), quads[0]->rect);
    216   }
    217 }
    218 
    219 TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
    220   LayerTreeSettings layer_tree_settings;
    221   layer_tree_settings.solid_color_scrollbars = true;
    222   layer_tree_settings.solid_color_scrollbar_thickness_dip = 3;
    223   scoped_ptr<FakeLayerTreeHost> host =
    224       FakeLayerTreeHost::Create(layer_tree_settings);
    225 
    226   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
    227   LayerImpl* layer_impl_tree_root =
    228       LayerImplForScrollAreaAndScrollbar(host.get(), scrollbar.Pass(), false);
    229   ScrollbarLayerImpl* scrollbar_layer_impl =
    230       static_cast<ScrollbarLayerImpl*>(layer_impl_tree_root->children()[1]);
    231 
    232   scrollbar_layer_impl->SetThumbThickness(3);
    233   scrollbar_layer_impl->SetTrackLength(10);
    234   scrollbar_layer_impl->SetCurrentPos(4.f);
    235   scrollbar_layer_impl->SetMaximum(8);
    236 
    237   layer_impl_tree_root->SetScrollable(true);
    238   layer_impl_tree_root->SetHorizontalScrollbarLayer(scrollbar_layer_impl);
    239   layer_impl_tree_root->SetMaxScrollOffset(gfx::Vector2d(8, 8));
    240   layer_impl_tree_root->SetBounds(gfx::Size(2, 2));
    241   layer_impl_tree_root->ScrollBy(gfx::Vector2dF(4.f, 0.f));
    242 
    243   {
    244     MockQuadCuller quad_culler;
    245     AppendQuadsData data;
    246     scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
    247 
    248     const QuadList& quads = quad_culler.quad_list();
    249     ASSERT_EQ(1u, quads.size());
    250     EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
    251     EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads[0]->rect);
    252   }
    253 }
    254 
    255 class ScrollbarLayerSolidColorThumbTest : public testing::Test {
    256  public:
    257   ScrollbarLayerSolidColorThumbTest() {
    258     LayerTreeSettings layer_tree_settings;
    259     layer_tree_settings.solid_color_scrollbars = true;
    260     host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_));
    261 
    262     horizontal_scrollbar_layer_ = ScrollbarLayerImpl::Create(
    263         host_impl_->active_tree(), 1, HORIZONTAL);
    264     vertical_scrollbar_layer_ = ScrollbarLayerImpl::Create(
    265         host_impl_->active_tree(), 2, VERTICAL);
    266   }
    267 
    268  protected:
    269   FakeImplProxy proxy_;
    270   scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
    271   scoped_ptr<ScrollbarLayerImpl> horizontal_scrollbar_layer_;
    272   scoped_ptr<ScrollbarLayerImpl> vertical_scrollbar_layer_;
    273 };
    274 
    275 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbLength) {
    276   horizontal_scrollbar_layer_->SetCurrentPos(0);
    277   horizontal_scrollbar_layer_->SetMaximum(10);
    278   horizontal_scrollbar_layer_->SetThumbThickness(3);
    279 
    280   // Simple case - one third of the scrollable area is visible, so the thumb
    281   // should be one third as long as the track.
    282   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.33f);
    283   horizontal_scrollbar_layer_->SetTrackLength(100);
    284   EXPECT_EQ(33, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
    285 
    286   // The thumb's length should never be less than its thickness.
    287   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.01f);
    288   horizontal_scrollbar_layer_->SetTrackLength(100);
    289   EXPECT_EQ(3, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
    290 }
    291 
    292 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbPosition) {
    293   horizontal_scrollbar_layer_->SetTrackLength(100);
    294   horizontal_scrollbar_layer_->SetVisibleToTotalLengthRatio(0.1f);
    295   horizontal_scrollbar_layer_->SetThumbThickness(3);
    296 
    297   horizontal_scrollbar_layer_->SetCurrentPos(0);
    298   horizontal_scrollbar_layer_->SetMaximum(100);
    299   EXPECT_EQ(0, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
    300   EXPECT_EQ(10, horizontal_scrollbar_layer_->ComputeThumbQuadRect().width());
    301 
    302   horizontal_scrollbar_layer_->SetCurrentPos(100);
    303   // The thumb is 10px long and the track is 100px, so the maximum thumb
    304   // position is 90px.
    305   EXPECT_EQ(90, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
    306 
    307   horizontal_scrollbar_layer_->SetCurrentPos(80);
    308   // The scroll position is 80% of the maximum, so the thumb's position should
    309   // be at 80% of its maximum or 72px.
    310   EXPECT_EQ(72, horizontal_scrollbar_layer_->ComputeThumbQuadRect().x());
    311 }
    312 
    313 TEST_F(ScrollbarLayerSolidColorThumbTest, SolidColorThumbVerticalAdjust) {
    314   ScrollbarLayerImpl* layers[2] =
    315       { horizontal_scrollbar_layer_.get(), vertical_scrollbar_layer_.get() };
    316   for (size_t i = 0; i < 2; ++i) {
    317     layers[i]->SetTrackLength(100);
    318     layers[i]->SetVisibleToTotalLengthRatio(0.2f);
    319     layers[i]->SetThumbThickness(3);
    320     layers[i]->SetCurrentPos(25);
    321     layers[i]->SetMaximum(100);
    322   }
    323 
    324   EXPECT_RECT_EQ(gfx::RectF(20.f, 0.f, 20.f, 3.f),
    325                  horizontal_scrollbar_layer_->ComputeThumbQuadRect());
    326   EXPECT_RECT_EQ(gfx::RectF(0.f, 20.f, 3.f, 20.f),
    327                  vertical_scrollbar_layer_->ComputeThumbQuadRect());
    328 
    329   horizontal_scrollbar_layer_->SetVerticalAdjust(10.f);
    330   vertical_scrollbar_layer_->SetVerticalAdjust(10.f);
    331 
    332   // The vertical adjustment factor has two effects:
    333   // 1.) Moves the horizontal scrollbar down
    334   // 2.) Increases the vertical scrollbar's effective track length which both
    335   // increases the thumb's length and its position within the track.
    336   EXPECT_RECT_EQ(gfx::Rect(20.f, 10.f, 20.f, 3.f),
    337                  horizontal_scrollbar_layer_->ComputeThumbQuadRect());
    338   EXPECT_RECT_EQ(gfx::Rect(0.f, 22, 3.f, 22.f),
    339                  vertical_scrollbar_layer_->ComputeThumbQuadRect());
    340 }
    341 
    342 class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
    343  public:
    344   ScrollbarLayerTestMaxTextureSize() {}
    345 
    346   void SetScrollbarBounds(gfx::Size bounds) { bounds_ = bounds; }
    347 
    348   virtual void BeginTest() OVERRIDE {
    349     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
    350     scrollbar_layer_ = ScrollbarLayer::Create(scrollbar.Pass(), 1);
    351     scrollbar_layer_->SetLayerTreeHost(layer_tree_host());
    352     scrollbar_layer_->SetBounds(bounds_);
    353     layer_tree_host()->root_layer()->AddChild(scrollbar_layer_);
    354 
    355     scroll_layer_ = Layer::Create();
    356     scrollbar_layer_->SetScrollLayerId(scroll_layer_->id());
    357     layer_tree_host()->root_layer()->AddChild(scroll_layer_);
    358 
    359     PostSetNeedsCommitToMainThread();
    360   }
    361 
    362   virtual void DidCommitAndDrawFrame() OVERRIDE {
    363     const int kMaxTextureSize =
    364         layer_tree_host()->GetRendererCapabilities().max_texture_size;
    365 
    366     // Check first that we're actually testing something.
    367     EXPECT_GT(scrollbar_layer_->bounds().width(), kMaxTextureSize);
    368 
    369     EXPECT_EQ(scrollbar_layer_->content_bounds().width(),
    370               kMaxTextureSize - 1);
    371     EXPECT_EQ(scrollbar_layer_->content_bounds().height(),
    372               kMaxTextureSize - 1);
    373 
    374     EndTest();
    375   }
    376 
    377   virtual void AfterTest() OVERRIDE {}
    378 
    379  private:
    380   scoped_refptr<ScrollbarLayer> scrollbar_layer_;
    381   scoped_refptr<Layer> scroll_layer_;
    382   gfx::Size bounds_;
    383 };
    384 
    385 TEST_F(ScrollbarLayerTestMaxTextureSize, DirectRenderer) {
    386   scoped_ptr<TestWebGraphicsContext3D> context =
    387       TestWebGraphicsContext3D::Create();
    388   int max_size = 0;
    389   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
    390   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
    391   RunTest(true, false, true);
    392 }
    393 
    394 TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) {
    395   scoped_ptr<TestWebGraphicsContext3D> context =
    396       TestWebGraphicsContext3D::Create();
    397   int max_size = 0;
    398   context->getIntegerv(GL_MAX_TEXTURE_SIZE, &max_size);
    399   SetScrollbarBounds(gfx::Size(max_size + 100, max_size + 100));
    400   RunTest(true, true, true);
    401 }
    402 
    403 class MockLayerTreeHost : public LayerTreeHost {
    404  public:
    405   MockLayerTreeHost(LayerTreeHostClient* client,
    406                     const LayerTreeSettings& settings)
    407       : LayerTreeHost(client, settings) {
    408     Initialize(NULL);
    409   }
    410 };
    411 
    412 
    413 class ScrollbarLayerTestResourceCreation : public testing::Test {
    414  public:
    415   ScrollbarLayerTestResourceCreation()
    416       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
    417 
    418   void TestResourceUpload(size_t expected_resources) {
    419     layer_tree_host_.reset(
    420         new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
    421 
    422     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
    423     scoped_refptr<Layer> layer_tree_root = Layer::Create();
    424     scoped_refptr<Layer> content_layer = Layer::Create();
    425     scoped_refptr<Layer> scrollbar_layer =
    426         ScrollbarLayer::Create(scrollbar.Pass(), layer_tree_root->id());
    427     layer_tree_root->AddChild(content_layer);
    428     layer_tree_root->AddChild(scrollbar_layer);
    429 
    430     layer_tree_host_->InitializeOutputSurfaceIfNeeded();
    431     layer_tree_host_->contents_texture_manager()->
    432         SetMaxMemoryLimitBytes(1024 * 1024);
    433     layer_tree_host_->SetRootLayer(layer_tree_root);
    434 
    435     scrollbar_layer->SetIsDrawable(true);
    436     scrollbar_layer->SetBounds(gfx::Size(100, 100));
    437     layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
    438     layer_tree_root->SetMaxScrollOffset(gfx::Vector2d(30, 50));
    439     layer_tree_root->SetBounds(gfx::Size(100, 200));
    440     content_layer->SetBounds(gfx::Size(100, 200));
    441     scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200);
    442     scrollbar_layer->draw_properties().visible_content_rect =
    443         gfx::Rect(0, 0, 100, 200);
    444     scrollbar_layer->CreateRenderSurface();
    445     scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
    446 
    447     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    448     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
    449 
    450     PriorityCalculator calculator;
    451     ResourceUpdateQueue queue;
    452     OcclusionTracker occlusion_tracker(gfx::Rect(), false);
    453 
    454     scrollbar_layer->SavePaintProperties();
    455     scrollbar_layer->SetTexturePriorities(calculator);
    456     layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
    457     scrollbar_layer->Update(&queue, &occlusion_tracker);
    458     EXPECT_EQ(0u, queue.FullUploadSize());
    459     EXPECT_EQ(expected_resources, queue.PartialUploadSize());
    460 
    461     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    462 
    463     scrollbar_layer->ClearRenderSurface();
    464   }
    465 
    466  protected:
    467   FakeLayerTreeHostClient fake_client_;
    468   LayerTreeSettings layer_tree_settings_;
    469   scoped_ptr<MockLayerTreeHost> layer_tree_host_;
    470 };
    471 
    472 TEST_F(ScrollbarLayerTestResourceCreation, ResourceUpload) {
    473   layer_tree_settings_.solid_color_scrollbars = false;
    474   TestResourceUpload(2);
    475 }
    476 
    477 TEST_F(ScrollbarLayerTestResourceCreation, SolidColorNoResourceUpload) {
    478   layer_tree_settings_.solid_color_scrollbars = true;
    479   TestResourceUpload(0);
    480 }
    481 
    482 class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
    483  public:
    484   ScaledScrollbarLayerTestResourceCreation()
    485       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
    486 
    487   void TestResourceUpload(size_t expected_resources, const float test_scale) {
    488     layer_tree_host_.reset(
    489         new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
    490 
    491     gfx::Point scrollbar_location(0, 185);
    492     scoped_ptr<FakeScrollbar> scrollbar(new FakeScrollbar(false, true, false));
    493     scrollbar->set_location(scrollbar_location);
    494 
    495     scoped_refptr<Layer> layer_tree_root = Layer::Create();
    496     scoped_refptr<Layer> content_layer = Layer::Create();
    497     scoped_refptr<Layer> scrollbar_layer =
    498         ScrollbarLayer::Create(scrollbar.PassAs<cc::Scrollbar>(),
    499                                layer_tree_root->id());
    500     layer_tree_root->AddChild(content_layer);
    501     layer_tree_root->AddChild(scrollbar_layer);
    502 
    503     layer_tree_host_->InitializeOutputSurfaceIfNeeded();
    504     layer_tree_host_->contents_texture_manager()->
    505         SetMaxMemoryLimitBytes(1024 * 1024);
    506     layer_tree_host_->SetRootLayer(layer_tree_root);
    507 
    508     scrollbar_layer->SetIsDrawable(true);
    509     scrollbar_layer->SetBounds(gfx::Size(100, 15));
    510     scrollbar_layer->SetPosition(scrollbar_location);
    511     layer_tree_root->SetBounds(gfx::Size(100, 200));
    512     content_layer->SetBounds(gfx::Size(100, 200));
    513     gfx::SizeF scaled_size =
    514         gfx::ScaleSize(scrollbar_layer->bounds(), test_scale, test_scale);
    515     gfx::PointF scaled_location =
    516         gfx::ScalePoint(scrollbar_layer->position(), test_scale, test_scale);
    517     scrollbar_layer->draw_properties().content_bounds =
    518         gfx::Size(scaled_size.width(), scaled_size.height());
    519     scrollbar_layer->draw_properties().contents_scale_x = test_scale;
    520     scrollbar_layer->draw_properties().contents_scale_y = test_scale;
    521     scrollbar_layer->draw_properties().visible_content_rect =
    522         gfx::Rect(scaled_location.x(),
    523                   scaled_location.y(),
    524                   scaled_size.width(),
    525                   scaled_size.height());
    526     scrollbar_layer->CreateRenderSurface();
    527     scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
    528 
    529     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    530     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
    531 
    532     PriorityCalculator calculator;
    533     ResourceUpdateQueue queue;
    534     OcclusionTracker occlusion_tracker(gfx::Rect(), false);
    535 
    536     scrollbar_layer->SavePaintProperties();
    537     scrollbar_layer->SetTexturePriorities(calculator);
    538     layer_tree_host_->contents_texture_manager()->PrioritizeTextures();
    539     scrollbar_layer->Update(&queue, &occlusion_tracker);
    540     EXPECT_EQ(expected_resources, queue.PartialUploadSize());
    541 
    542     // Verify that we have not generated any content uploads that are larger
    543     // than their destination textures.
    544     while (queue.HasMoreUpdates()) {
    545       ResourceUpdate update = queue.TakeFirstPartialUpload();
    546       EXPECT_LE(update.texture->size().width(),
    547                 scrollbar_layer->content_bounds().width());
    548       EXPECT_LE(update.texture->size().height(),
    549                 scrollbar_layer->content_bounds().height());
    550 
    551       EXPECT_LE(update.dest_offset.x() + update.content_rect.width(),
    552                 update.texture->size().width());
    553       EXPECT_LE(update.dest_offset.y() + update.content_rect.height(),
    554                 update.texture->size().height());
    555     }
    556 
    557     testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
    558 
    559     scrollbar_layer->ClearRenderSurface();
    560   }
    561 
    562  protected:
    563   FakeLayerTreeHostClient fake_client_;
    564   LayerTreeSettings layer_tree_settings_;
    565   scoped_ptr<MockLayerTreeHost> layer_tree_host_;
    566 };
    567 
    568 TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
    569   layer_tree_settings_.solid_color_scrollbars = false;
    570   // Pick a test scale that moves the scrollbar's (non-zero) position to
    571   // a non-pixel-aligned location.
    572   TestResourceUpload(2, 1.41f);
    573 }
    574 
    575 }  // namespace
    576 }  // namespace cc
    577