Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / cc / layers / scrollbar_layer_unittest.cc
index 2d01af7..25fa708 100644 (file)
 #include "cc/test/fake_scrollbar.h"
 #include "cc/test/geometry_test_utils.h"
 #include "cc/test/layer_tree_test.h"
-#include "cc/test/mock_quad_culler.h"
+#include "cc/test/mock_occlusion_tracker.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_host.h"
 #include "cc/trees/layer_tree_impl.h"
+#include "cc/trees/occlusion_tracker.h"
 #include "cc/trees/single_thread_proxy.h"
 #include "cc/trees/tree_synchronizer.h"
 #include "testing/gmock/include/gmock/gmock.h"
 namespace cc {
 namespace {
 
-LayerImpl* LayerImplForScrollAreaAndScrollbar(
-    FakeLayerTreeHost* host,
-    scoped_ptr<Scrollbar> scrollbar,
-    bool reverse_order,
-    bool use_solid_color_scrollbar,
-    int thumb_thickness) {
+LayerImpl* LayerImplForScrollAreaAndScrollbar(FakeLayerTreeHost* host,
+                                              scoped_ptr<Scrollbar> scrollbar,
+                                              bool reverse_order,
+                                              bool use_solid_color_scrollbar,
+                                              int thumb_thickness,
+                                              int track_start) {
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
   scoped_refptr<Layer> child1 = Layer::Create();
   scoped_refptr<Layer> child2;
   if (use_solid_color_scrollbar) {
     const bool kIsLeftSideVerticalScrollbar = false;
-    child2 = SolidColorScrollbarLayer::Create(
-        scrollbar->Orientation(), thumb_thickness,
-        kIsLeftSideVerticalScrollbar, child1->id());
+    child2 = SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
+                                              thumb_thickness,
+                                              track_start,
+                                              kIsLeftSideVerticalScrollbar,
+                                              child1->id());
   } else {
     child2 = PaintedScrollbarLayer::Create(scrollbar.Pass(), child1->id());
   }
+  child2->ToScrollbarLayer()->SetClipLayer(layer_tree_root->id());
   layer_tree_root->AddChild(child1);
   layer_tree_root->InsertChild(child2, reverse_order ? 0 : 1);
   host->SetRootLayer(layer_tree_root);
@@ -56,10 +60,11 @@ LayerImpl* LayerImplForScrollAreaAndScrollbar(
 }
 
 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, false, 0);
+      host.get(), scrollbar.Pass(), false, false, 0, 0);
 
   LayerImpl* cc_child1 = layer_impl_tree_root->children()[0];
   PaintedScrollbarLayerImpl* cc_child2 =
@@ -71,10 +76,11 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer) {
 }
 
 TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), true, false, 0);
+      host.get(), scrollbar.Pass(), true, false, 0, 0);
 
   PaintedScrollbarLayerImpl* cc_child1 =
       static_cast<PaintedScrollbarLayerImpl*>(
@@ -86,12 +92,13 @@ TEST(ScrollbarLayerTest, ResolveScrollLayerPointer_ReverseOrder) {
 }
 
 TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
 
   // Create and attach a non-overlay scrollbar.
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, false, 0);
+      host.get(), scrollbar.Pass(), false, false, 0, 0);
   PaintedScrollbarLayerImpl* scrollbar_layer_impl =
       static_cast<PaintedScrollbarLayerImpl*>(
           layer_impl_tree_root->children()[1]);
@@ -107,7 +114,7 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
   scrollbar.reset(new FakeScrollbar(false, false, true));
 
   layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, false, 0);
+      host.get(), scrollbar.Pass(), false, false, 0, 0);
   scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>(
       layer_impl_tree_root->children()[1]);
 
@@ -119,7 +126,8 @@ TEST(ScrollbarLayerTest, ShouldScrollNonOverlayOnMainThread) {
 }
 
 TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
 
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar);
   scoped_refptr<Layer> layer_tree_root = Layer::Create();
@@ -131,7 +139,7 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
   // Choose bounds to give max_scroll_offset = (30, 50).
   layer_tree_root->SetBounds(gfx::Size(70, 150));
   scroll_layer->SetScrollClipLayerId(layer_tree_root->id());
-  scroll_layer->SetScrollOffset(gfx::Vector2d(10, 20));
+  scroll_layer->SetScrollOffset(gfx::ScrollOffset(10, 20));
   scroll_layer->SetBounds(gfx::Size(100, 200));
   content_layer->SetBounds(gfx::Size(100, 200));
 
@@ -157,7 +165,7 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
   layer_tree_root->SetBounds(gfx::Size(700, 1500));
   layer_tree_root->SavePaintProperties();
   scroll_layer->SetBounds(gfx::Size(1000, 2000));
-  scroll_layer->SetScrollOffset(gfx::Vector2d(100, 200));
+  scroll_layer->SetScrollOffset(gfx::ScrollOffset(100, 200));
   scroll_layer->SavePaintProperties();
   content_layer->SetBounds(gfx::Size(1000, 2000));
   content_layer->SavePaintProperties();
@@ -185,11 +193,57 @@ TEST(PaintedScrollbarLayerTest, ScrollOffsetSynchronization) {
     root_layer_impl = root_clip_layer_impl->children()[0];          \
     scrollbar_layer_impl = static_cast<PaintedScrollbarLayerImpl*>( \
         root_layer_impl->children()[1]);                            \
-    scrollbar_layer_impl->ScrollbarParametersDidChange();           \
+    scrollbar_layer_impl->ScrollbarParametersDidChange(false);      \
   } while (false)
 
+TEST(ScrollbarLayerTest, UpdatePropertiesOfScrollBarWhenThumbRemoved) {
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
+  scoped_refptr<Layer> root_clip_layer = Layer::Create();
+  scoped_refptr<Layer> root_layer = Layer::Create();
+  scoped_refptr<Layer> content_layer = Layer::Create();
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
+      FakePaintedScrollbarLayer::Create(false, true, root_layer->id());
+
+  root_layer->SetScrollClipLayerId(root_clip_layer->id());
+  // Give the root-clip a size that will result in MaxScrollOffset = (80, 0).
+  root_clip_layer->SetBounds(gfx::Size(20, 50));
+  root_layer->SetBounds(gfx::Size(100, 50));
+  content_layer->SetBounds(gfx::Size(100, 50));
+
+  host->SetRootLayer(root_clip_layer);
+  root_clip_layer->AddChild(root_layer);
+  root_layer->AddChild(content_layer);
+  root_layer->AddChild(scrollbar_layer);
+
+  root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
+  scrollbar_layer->SetBounds(gfx::Size(70, 10));
+  scrollbar_layer->SetScrollLayer(root_layer->id());
+  scrollbar_layer->SetClipLayer(root_clip_layer->id());
+  scrollbar_layer->fake_scrollbar()->set_location(gfx::Point(20, 10));
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
+  scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
+
+  scrollbar_layer->UpdateThumbAndTrackGeometry();
+  LayerImpl* root_clip_layer_impl = nullptr;
+  LayerImpl* root_layer_impl = nullptr;
+  PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
+
+  UPDATE_AND_EXTRACT_LAYER_POINTERS();
+  EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+
+  scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
+
+  UPDATE_AND_EXTRACT_LAYER_POINTERS();
+  EXPECT_EQ(gfx::Rect(10, 0, 0, 0).ToString(),
+            scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
+}
+
 TEST(ScrollbarLayerTest, ThumbRect) {
-  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create();
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
+  scoped_ptr<FakeLayerTreeHost> host = FakeLayerTreeHost::Create(&client);
   scoped_refptr<Layer> root_clip_layer = Layer::Create();
   scoped_refptr<Layer> root_layer = Layer::Create();
   scoped_refptr<Layer> content_layer = Layer::Create();
@@ -207,7 +261,7 @@ TEST(ScrollbarLayerTest, ThumbRect) {
   root_layer->AddChild(content_layer);
   root_layer->AddChild(scrollbar_layer);
 
-  root_layer->SetScrollOffset(gfx::Vector2d(0, 0));
+  root_layer->SetScrollOffset(gfx::ScrollOffset(0, 0));
   scrollbar_layer->SetBounds(gfx::Size(70, 10));
   scrollbar_layer->SetScrollLayer(root_layer->id());
   scrollbar_layer->SetClipLayer(root_clip_layer->id());
@@ -216,9 +270,9 @@ TEST(ScrollbarLayerTest, ThumbRect) {
   scrollbar_layer->fake_scrollbar()->set_thumb_thickness(10);
   scrollbar_layer->fake_scrollbar()->set_thumb_length(4);
   scrollbar_layer->UpdateThumbAndTrackGeometry();
-  LayerImpl* root_clip_layer_impl = NULL;
-  LayerImpl* root_layer_impl = NULL;
-  PaintedScrollbarLayerImpl* scrollbar_layer_impl = NULL;
+  LayerImpl* root_clip_layer_impl = nullptr;
+  LayerImpl* root_layer_impl = nullptr;
+  PaintedScrollbarLayerImpl* scrollbar_layer_impl = nullptr;
 
   // Thumb is at the edge of the scrollbar (should be inset to
   // the start of the track within the scrollbar layer's
@@ -228,14 +282,14 @@ TEST(ScrollbarLayerTest, ThumbRect) {
             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
 
   // Under-scroll (thumb position should clamp and be unchanged).
-  root_layer->SetScrollOffset(gfx::Vector2d(-5, 0));
+  root_layer->SetScrollOffset(gfx::ScrollOffset(-5, 0));
 
   UPDATE_AND_EXTRACT_LAYER_POINTERS();
   EXPECT_EQ(gfx::Rect(10, 0, 4, 10).ToString(),
             scrollbar_layer_impl->ComputeThumbQuadRect().ToString());
 
   // Over-scroll (thumb position should clamp on the far side).
-  root_layer->SetScrollOffset(gfx::Vector2d(85, 0));
+  root_layer->SetScrollOffset(gfx::ScrollOffset(85, 0));
 
   UPDATE_AND_EXTRACT_LAYER_POINTERS();
   EXPECT_EQ(gfx::Rect(56, 0, 4, 10).ToString(),
@@ -270,15 +324,17 @@ TEST(ScrollbarLayerTest, ThumbRect) {
 
 TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
   const int kThumbThickness = 3;
+  const int kTrackStart = 1;
   const int kTrackLength = 100;
 
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
   LayerTreeSettings layer_tree_settings;
   scoped_ptr<FakeLayerTreeHost> host =
-      FakeLayerTreeHost::Create(layer_tree_settings);
+      FakeLayerTreeHost::Create(&client, layer_tree_settings);
 
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
   LayerImpl* layer_impl_tree_root = LayerImplForScrollAreaAndScrollbar(
-      host.get(), scrollbar.Pass(), false, true, kThumbThickness);
+      host.get(), scrollbar.Pass(), false, true, kThumbThickness, kTrackStart);
   ScrollbarLayerImplBase* scrollbar_layer_impl =
       static_cast<SolidColorScrollbarLayerImpl*>(
           layer_impl_tree_root->children()[1]);
@@ -289,28 +345,28 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
 
   // Thickness should be overridden to 3.
   {
-    MockQuadCuller quad_culler;
+    scoped_ptr<RenderPass> render_pass = RenderPass::Create();
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
 
-    const QuadList& quads = quad_culler.quad_list();
+    const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
-    EXPECT_RECT_EQ(gfx::Rect(6, 0, 40, 3), quads[0]->rect);
+    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_RECT_EQ(gfx::Rect(6, 0, 39, 3), quads.front()->rect);
   }
 
   // Contents scale should scale the draw quad.
   scrollbar_layer_impl->draw_properties().contents_scale_x = 2.f;
   scrollbar_layer_impl->draw_properties().contents_scale_y = 2.f;
   {
-    MockQuadCuller quad_culler;
+    scoped_ptr<RenderPass> render_pass = RenderPass::Create();
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
 
-    const QuadList& quads = quad_culler.quad_list();
+    const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
-    EXPECT_RECT_EQ(gfx::Rect(12, 0, 80, 6), quads[0]->rect);
+    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_RECT_EQ(gfx::Rect(12, 0, 78, 6), quads.front()->rect);
   }
   scrollbar_layer_impl->draw_properties().contents_scale_x = 1.f;
   scrollbar_layer_impl->draw_properties().contents_scale_y = 1.f;
@@ -319,24 +375,40 @@ TEST(ScrollbarLayerTest, SolidColorDrawQuads) {
   // current viewport state.
   scrollbar_layer_impl->SetVisibleToTotalLengthRatio(0.2f);
   {
-    MockQuadCuller quad_culler;
+    scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+    AppendQuadsData data;
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
+
+    const QuadList& quads = render_pass->quad_list;
+    ASSERT_EQ(1u, quads.size());
+    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_RECT_EQ(gfx::Rect(8, 0, 19, 3), quads.front()->rect);
+  }
+
+  // We shouldn't attempt div-by-zero when the maximum is zero.
+  scrollbar_layer_impl->SetCurrentPos(0.f);
+  scrollbar_layer_impl->SetMaximum(0);
+  {
+    scoped_ptr<RenderPass> render_pass = RenderPass::Create();
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
 
-    const QuadList& quads = quad_culler.quad_list();
+    const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
-    EXPECT_RECT_EQ(gfx::Rect(8, 0, 20, 3), quads[0]->rect);
+    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_RECT_EQ(gfx::Rect(1, 0, 19, 3), quads.front()->rect);
   }
 }
 
 TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
   const int kThumbThickness = 3;
+  const int kTrackStart = 0;
   const int kTrackLength = 10;
 
+  FakeLayerTreeHostClient client(FakeLayerTreeHostClient::DIRECT_3D);
   LayerTreeSettings layer_tree_settings;
   scoped_ptr<FakeLayerTreeHost> host =
-      FakeLayerTreeHost::Create(layer_tree_settings);
+      FakeLayerTreeHost::Create(&client, layer_tree_settings);
 
   scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, true));
 
@@ -349,6 +421,7 @@ TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
     const bool kIsLeftSideVerticalScrollbar = false;
     child2 = SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
                                               kThumbThickness,
+                                              kTrackStart,
                                               kIsLeftSideVerticalScrollbar,
                                               child1->id());
     child2->ToScrollbarLayer()->SetScrollLayer(scroll_layer->id());
@@ -374,14 +447,15 @@ TEST(ScrollbarLayerTest, LayerDrivenSolidColorDrawQuads) {
   scrollbar_layer_impl->SetMaximum(8);
 
   {
-    MockQuadCuller quad_culler;
+    scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+
     AppendQuadsData data;
-    scrollbar_layer_impl->AppendQuads(&quad_culler, &data);
+    scrollbar_layer_impl->AppendQuads(render_pass.get(), Occlusion(), &data);
 
-    const QuadList& quads = quad_culler.quad_list();
+    const QuadList& quads = render_pass->quad_list;
     ASSERT_EQ(1u, quads.size());
-    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads[0]->material);
-    EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads[0]->rect);
+    EXPECT_EQ(DrawQuad::SOLID_COLOR, quads.front()->material);
+    EXPECT_RECT_EQ(gfx::Rect(3, 0, 3, 3), quads.front()->rect);
   }
 }
 
@@ -389,9 +463,11 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
  public:
   ScrollbarLayerSolidColorThumbTest() {
     LayerTreeSettings layer_tree_settings;
-    host_impl_.reset(new FakeLayerTreeHostImpl(layer_tree_settings, &proxy_));
+    host_impl_.reset(new FakeLayerTreeHostImpl(
+        layer_tree_settings, &proxy_, &shared_bitmap_manager_));
 
     const int kThumbThickness = 3;
+    const int kTrackStart = 0;
     const bool kIsLeftSideVerticalScrollbar = false;
     const bool kIsOverlayScrollbar = false;
 
@@ -400,6 +476,7 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
                                              1,
                                              HORIZONTAL,
                                              kThumbThickness,
+                                             kTrackStart,
                                              kIsLeftSideVerticalScrollbar,
                                              kIsOverlayScrollbar);
     vertical_scrollbar_layer_ =
@@ -407,12 +484,14 @@ class ScrollbarLayerSolidColorThumbTest : public testing::Test {
                                              2,
                                              VERTICAL,
                                              kThumbThickness,
+                                             kTrackStart,
                                              kIsLeftSideVerticalScrollbar,
                                              kIsOverlayScrollbar);
   }
 
  protected:
   FakeImplProxy proxy_;
+  TestSharedBitmapManager shared_bitmap_manager_;
   scoped_ptr<FakeLayerTreeHostImpl> host_impl_;
   scoped_ptr<SolidColorScrollbarLayerImpl> horizontal_scrollbar_layer_;
   scoped_ptr<SolidColorScrollbarLayerImpl> vertical_scrollbar_layer_;
@@ -489,7 +568,7 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
 
   void SetScrollbarBounds(const gfx::Size& bounds) { bounds_ = bounds; }
 
-  virtual void BeginTest() OVERRIDE {
+  void BeginTest() override {
     scroll_layer_ = Layer::Create();
     layer_tree_host()->root_layer()->AddChild(scroll_layer_);
 
@@ -504,7 +583,7 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
     PostSetNeedsCommitToMainThread();
   }
 
-  virtual void DidCommitAndDrawFrame() OVERRIDE {
+  void DidCommitAndDrawFrame() override {
     const int kMaxTextureSize =
         layer_tree_host()->GetRendererCapabilities().max_texture_size;
 
@@ -519,7 +598,7 @@ class ScrollbarLayerTestMaxTextureSize : public LayerTreeTest {
     EndTest();
   }
 
-  virtual void AfterTest() OVERRIDE {}
+  void AfterTest() override {}
 
  private:
   scoped_refptr<PaintedScrollbarLayer> scrollbar_layer_;
@@ -545,18 +624,18 @@ TEST_F(ScrollbarLayerTestMaxTextureSize, DelegatingRenderer) {
   RunTest(true, true, true);
 }
 
-class MockLayerTreeHost : public LayerTreeHost {
+class FakeLayerTreeHost : public LayerTreeHost {
  public:
-  MockLayerTreeHost(FakeLayerTreeHostClient* client,
+  FakeLayerTreeHost(FakeLayerTreeHostClient* client,
                     const LayerTreeSettings& settings)
-      : LayerTreeHost(client, NULL, settings),
+      : LayerTreeHost(client, nullptr, nullptr, settings),
         next_id_(1),
         total_ui_resource_created_(0),
         total_ui_resource_deleted_(0) {
-    InitializeSingleThreaded(client);
+    InitializeSingleThreaded(client, base::MessageLoopProxy::current());
   }
 
-  virtual UIResourceId CreateUIResource(UIResourceClient* content) OVERRIDE {
+  UIResourceId CreateUIResource(UIResourceClient* content) override {
     total_ui_resource_created_++;
     UIResourceId nid = next_id_++;
     ui_resource_bitmap_map_.insert(
@@ -565,7 +644,7 @@ class MockLayerTreeHost : public LayerTreeHost {
   }
 
   // Deletes a UI resource.  May safely be called more than once.
-  virtual void DeleteUIResource(UIResourceId id) OVERRIDE {
+  void DeleteUIResource(UIResourceId id) override {
     UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
     if (iter != ui_resource_bitmap_map_.end()) {
       ui_resource_bitmap_map_.erase(iter);
@@ -584,6 +663,13 @@ class MockLayerTreeHost : public LayerTreeHost {
     return gfx::Size();
   }
 
+  UIResourceBitmap* ui_resource_bitmap(UIResourceId id) {
+    UIResourceBitmapMap::iterator iter = ui_resource_bitmap_map_.find(id);
+    if (iter != ui_resource_bitmap_map_.end())
+      return &iter->second;
+    return nullptr;
+  }
+
  private:
   typedef base::hash_map<UIResourceId, UIResourceBitmap>
       UIResourceBitmapMap;
@@ -594,10 +680,9 @@ class MockLayerTreeHost : public LayerTreeHost {
   int total_ui_resource_deleted_;
 };
 
-
-class ScrollbarLayerTestResourceCreation : public testing::Test {
+class ScrollbarLayerTestResourceCreationAndRelease : public testing::Test {
  public:
-  ScrollbarLayerTestResourceCreation()
+  ScrollbarLayerTestResourceCreationAndRelease()
       : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
 
   void TestResourceUpload(int num_updates,
@@ -606,7 +691,7 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
                           int expected_deleted,
                           bool use_solid_color_scrollbar) {
     layer_tree_host_.reset(
-        new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
+        new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
 
     scoped_ptr<Scrollbar> scrollbar(new FakeScrollbar(false, true, false));
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
@@ -614,10 +699,12 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
     scoped_refptr<Layer> scrollbar_layer;
     if (use_solid_color_scrollbar) {
       const int kThumbThickness = 3;
+      const int kTrackStart = 0;
       const bool kIsLeftSideVerticalScrollbar = false;
       scrollbar_layer =
           SolidColorScrollbarLayer::Create(scrollbar->Orientation(),
                                            kThumbThickness,
+                                           kTrackStart,
                                            kIsLeftSideVerticalScrollbar,
                                            layer_tree_root->id());
     } else {
@@ -631,7 +718,7 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
 
     scrollbar_layer->SetIsDrawable(true);
     scrollbar_layer->SetBounds(gfx::Size(100, 100));
-    layer_tree_root->SetScrollOffset(gfx::Vector2d(10, 20));
+    layer_tree_root->SetScrollOffset(gfx::ScrollOffset(10, 20));
     layer_tree_root->SetBounds(gfx::Size(100, 200));
     content_layer->SetBounds(gfx::Size(100, 200));
     scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200);
@@ -644,7 +731,8 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
 
     ResourceUpdateQueue queue;
-    OcclusionTracker occlusion_tracker(gfx::Rect(), false);
+    gfx::Rect screen_space_clip_rect;
+    OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
 
     scrollbar_layer->SavePaintProperties();
     for (int update_counter = 0; update_counter < num_updates; update_counter++)
@@ -663,10 +751,10 @@ class ScrollbarLayerTestResourceCreation : public testing::Test {
  protected:
   FakeLayerTreeHostClient fake_client_;
   LayerTreeSettings layer_tree_settings_;
-  scoped_ptr<MockLayerTreeHost> layer_tree_host_;
+  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
 };
 
-TEST_F(ScrollbarLayerTestResourceCreation, ResourceUpload) {
+TEST_F(ScrollbarLayerTestResourceCreationAndRelease, ResourceUpload) {
   bool use_solid_color_scrollbars = false;
   TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
   int num_updates[3] = {1, 5, 10};
@@ -679,12 +767,155 @@ TEST_F(ScrollbarLayerTestResourceCreation, ResourceUpload) {
   }
 }
 
-TEST_F(ScrollbarLayerTestResourceCreation, SolidColorNoResourceUpload) {
+TEST_F(ScrollbarLayerTestResourceCreationAndRelease,
+       SolidColorNoResourceUpload) {
   bool use_solid_color_scrollbars = true;
   TestResourceUpload(0, 0, 0, 0, use_solid_color_scrollbars);
   TestResourceUpload(1, 0, 0, 0, use_solid_color_scrollbars);
 }
 
+TEST_F(ScrollbarLayerTestResourceCreationAndRelease, TestResourceUpdate) {
+  FakeLayerTreeHostClient fake_client_(FakeLayerTreeHostClient::DIRECT_3D);
+  LayerTreeSettings layer_tree_settings_;
+  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
+
+  layer_tree_host_.reset(
+      new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
+
+  gfx::Point scrollbar_location(0, 185);
+  scoped_refptr<Layer> layer_tree_root = Layer::Create();
+  scoped_refptr<Layer> content_layer = Layer::Create();
+  scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
+      FakePaintedScrollbarLayer::Create(false, true, layer_tree_root->id());
+
+  layer_tree_root->AddChild(content_layer);
+  layer_tree_root->AddChild(scrollbar_layer);
+
+  layer_tree_host_->SetRootLayer(layer_tree_root);
+
+  scrollbar_layer->SetIsDrawable(true);
+  scrollbar_layer->SetBounds(gfx::Size(100, 15));
+  scrollbar_layer->SetPosition(scrollbar_location);
+  layer_tree_root->SetBounds(gfx::Size(100, 200));
+  content_layer->SetBounds(gfx::Size(100, 200));
+
+  scrollbar_layer->draw_properties().content_bounds = gfx::Size(100, 200);
+  scrollbar_layer->draw_properties().visible_content_rect =
+      gfx::Rect(0, 0, 100, 200);
+
+  scrollbar_layer->CreateRenderSurface();
+  scrollbar_layer->draw_properties().render_target = scrollbar_layer.get();
+
+  testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+  EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
+
+  ResourceUpdateQueue queue;
+  gfx::Rect screen_space_clip_rect;
+  size_t resource_count;
+  int expected_created, expected_deleted;
+  OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
+  scrollbar_layer->SavePaintProperties();
+
+  resource_count = 2;
+  expected_created = 2;
+  expected_deleted = 0;
+  EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_NE(0, scrollbar_layer->track_resource_id());
+  EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+
+  resource_count = 0;
+  expected_created = 2;
+  expected_deleted = 2;
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
+  EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_EQ(0, scrollbar_layer->track_resource_id());
+  EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+
+  resource_count = 0;
+  expected_created = 2;
+  expected_deleted = 2;
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
+  EXPECT_FALSE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_EQ(0, scrollbar_layer->track_resource_id());
+  EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+
+  resource_count = 2;
+  expected_created = 4;
+  expected_deleted = 2;
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_NE(0, scrollbar_layer->track_resource_id());
+  EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+
+  resource_count = 1;
+  expected_created = 5;
+  expected_deleted = 4;
+  scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
+  EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_NE(0, scrollbar_layer->track_resource_id());
+  EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+
+  resource_count = 0;
+  expected_created = 5;
+  expected_deleted = 5;
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(0, 0, 0, 0));
+  EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_EQ(0, scrollbar_layer->track_resource_id());
+  EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+
+  resource_count = 2;
+  expected_created = 7;
+  expected_deleted = 5;
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  scrollbar_layer->fake_scrollbar()->set_has_thumb(true);
+  EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_NE(0, scrollbar_layer->track_resource_id());
+  EXPECT_NE(0, scrollbar_layer->thumb_resource_id());
+
+  resource_count = 1;
+  expected_created = 8;
+  expected_deleted = 7;
+  scrollbar_layer->fake_scrollbar()->set_track_rect(gfx::Rect(30, 10, 50, 10));
+  scrollbar_layer->fake_scrollbar()->set_has_thumb(false);
+  scrollbar_layer->SetBounds(gfx::Size(90, 15));
+  EXPECT_TRUE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+  EXPECT_EQ(
+      gfx::Size(90, 15),
+      layer_tree_host_->ui_resource_size(scrollbar_layer->track_resource_id()));
+
+  scrollbar_layer->ResetNeedsDisplayForTesting();
+  EXPECT_FALSE(scrollbar_layer->Update(&queue, &occlusion_tracker));
+  EXPECT_NE(0, scrollbar_layer->track_resource_id());
+  EXPECT_EQ(0, scrollbar_layer->thumb_resource_id());
+  EXPECT_EQ(resource_count, layer_tree_host_->UIResourceCount());
+  EXPECT_EQ(expected_created, layer_tree_host_->TotalUIResourceCreated());
+  EXPECT_EQ(expected_deleted, layer_tree_host_->TotalUIResourceDeleted());
+
+  testing::Mock::VerifyAndClearExpectations(layer_tree_host_.get());
+  scrollbar_layer->ClearRenderSurface();
+}
+
 class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
  public:
   ScaledScrollbarLayerTestResourceCreation()
@@ -692,7 +923,7 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
 
   void TestResourceUpload(const float test_scale) {
     layer_tree_host_.reset(
-        new MockLayerTreeHost(&fake_client_, layer_tree_settings_));
+        new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
 
     gfx::Point scrollbar_location(0, 185);
     scoped_refptr<Layer> layer_tree_root = Layer::Create();
@@ -730,7 +961,8 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
     EXPECT_EQ(scrollbar_layer->layer_tree_host(), layer_tree_host_.get());
 
     ResourceUpdateQueue queue;
-    OcclusionTracker occlusion_tracker(gfx::Rect(), false);
+    gfx::Rect screen_space_clip_rect;
+    OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
     scrollbar_layer->SavePaintProperties();
     scrollbar_layer->Update(&queue, &occlusion_tracker);
 
@@ -755,7 +987,7 @@ class ScaledScrollbarLayerTestResourceCreation : public testing::Test {
  protected:
   FakeLayerTreeHostClient fake_client_;
   LayerTreeSettings layer_tree_settings_;
-  scoped_ptr<MockLayerTreeHost> layer_tree_host_;
+  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
 };
 
 TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
@@ -766,5 +998,105 @@ TEST_F(ScaledScrollbarLayerTestResourceCreation, ScaledResourceUpload) {
   TestResourceUpload(4.1f);
 }
 
+class ScaledScrollbarLayerTestScaledRasterization : public testing::Test {
+ public:
+  ScaledScrollbarLayerTestScaledRasterization()
+      : fake_client_(FakeLayerTreeHostClient::DIRECT_3D) {}
+
+  void TestScale(const gfx::Rect scrollbar_rect, const float test_scale) {
+    layer_tree_host_.reset(
+        new FakeLayerTreeHost(&fake_client_, layer_tree_settings_));
+
+    bool paint_during_update = true;
+    bool has_thumb = false;
+    scoped_refptr<Layer> layer_tree_root = Layer::Create();
+    scoped_refptr<FakePaintedScrollbarLayer> scrollbar_layer =
+        FakePaintedScrollbarLayer::Create(paint_during_update,
+                                          has_thumb,
+                                          layer_tree_root->id());
+
+    layer_tree_root->AddChild(scrollbar_layer);
+
+    layer_tree_host_->SetRootLayer(layer_tree_root);
+
+    scrollbar_layer->SetBounds(scrollbar_rect.size());
+    scrollbar_layer->SetPosition(scrollbar_rect.origin());
+    scrollbar_layer->fake_scrollbar()->set_location(scrollbar_rect.origin());
+    scrollbar_layer->fake_scrollbar()->set_track_rect(scrollbar_rect);
+    gfx::SizeF scaled_size =
+        gfx::ScaleSize(scrollbar_layer->bounds(), test_scale, test_scale);
+    gfx::PointF scaled_location =
+        gfx::ScalePoint(scrollbar_layer->position(), test_scale, test_scale);
+    scrollbar_layer->draw_properties().content_bounds =
+        gfx::Size(scaled_size.width(), scaled_size.height());
+    scrollbar_layer->draw_properties().contents_scale_x = test_scale;
+    scrollbar_layer->draw_properties().contents_scale_y = test_scale;
+    scrollbar_layer->draw_properties().visible_content_rect =
+        gfx::Rect(scaled_location.x(),
+                  scaled_location.y(),
+                  scaled_size.width(),
+                  scaled_size.height());
+
+    ResourceUpdateQueue queue;
+    gfx::Rect screen_space_clip_rect;
+    OcclusionTracker<Layer> occlusion_tracker(screen_space_clip_rect);
+    scrollbar_layer->SavePaintProperties();
+
+    scrollbar_layer->Update(&queue, &occlusion_tracker);
+
+    UIResourceBitmap* bitmap = layer_tree_host_->ui_resource_bitmap(
+        scrollbar_layer->track_resource_id());
+
+    DCHECK(bitmap);
+
+    AutoLockUIResourceBitmap locked_bitmap(*bitmap);
+
+    const SkColor* pixels =
+        reinterpret_cast<const SkColor*>(locked_bitmap.GetPixels());
+    SkColor color = argb_to_skia(
+        scrollbar_layer->fake_scrollbar()->paint_fill_color());
+    int width = bitmap->GetSize().width();
+    int height = bitmap->GetSize().height();
+
+    // Make sure none of the corners of the bitmap were inadvertently clipped.
+    EXPECT_EQ(color, pixels[0])
+        << "Top left pixel doesn't match scrollbar color.";
+
+    EXPECT_EQ(color, pixels[width - 1])
+        << "Top right pixel doesn't match scrollbar color.";
+
+    EXPECT_EQ(color, pixels[width * (height - 1)])
+        << "Bottom left pixel doesn't match scrollbar color.";
+
+    EXPECT_EQ(color, pixels[width * height - 1])
+        << "Bottom right pixel doesn't match scrollbar color.";
+  }
+
+ protected:
+  // On Android, Skia uses ABGR
+  static SkColor argb_to_skia(SkColor c) {
+      return (SkColorGetA(c) << SK_A32_SHIFT) |
+             (SkColorGetR(c) << SK_R32_SHIFT) |
+             (SkColorGetG(c) << SK_G32_SHIFT) |
+             (SkColorGetB(c) << SK_B32_SHIFT);
+  }
+
+  FakeLayerTreeHostClient fake_client_;
+  LayerTreeSettings layer_tree_settings_;
+  scoped_ptr<FakeLayerTreeHost> layer_tree_host_;
+};
+
+TEST_F(ScaledScrollbarLayerTestScaledRasterization, TestLostPrecisionInClip) {
+  // Try rasterization at coordinates and scale that caused problematic
+  // rounding and clipping errors.
+  // Vertical Scrollbars.
+  TestScale(gfx::Rect(1240, 0, 15, 1333), 2.7754839f);
+  TestScale(gfx::Rect(1240, 0, 15, 677), 2.46677136f);
+
+  // Horizontal Scrollbars.
+  TestScale(gfx::Rect(0, 1240, 1333, 15), 2.7754839f);
+  TestScale(gfx::Rect(0, 1240, 677, 15), 2.46677136f);
+}
+
 }  // namespace
 }  // namespace cc