Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / cc / layers / picture_layer_impl_unittest.cc
index c606be4..38e968e 100644 (file)
@@ -4,11 +4,15 @@
 
 #include "cc/layers/picture_layer_impl.h"
 
+#include <algorithm>
+#include <limits>
 #include <set>
 #include <utility>
 
+#include "cc/base/math_util.h"
 #include "cc/layers/append_quads_data.h"
 #include "cc/layers/picture_layer.h"
+#include "cc/quads/draw_quad.h"
 #include "cc/test/fake_content_layer_client.h"
 #include "cc/test/fake_impl_proxy.h"
 #include "cc/test/fake_layer_tree_host_impl.h"
 #include "cc/test/fake_picture_layer_impl.h"
 #include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/geometry_test_utils.h"
-#include "cc/test/gpu_rasterization_settings.h"
-#include "cc/test/hybrid_rasterization_settings.h"
 #include "cc/test/impl_side_painting_settings.h"
-#include "cc/test/mock_quad_culler.h"
+#include "cc/test/layer_test_common.h"
 #include "cc/test/test_shared_bitmap_manager.h"
 #include "cc/test/test_web_graphics_context_3d.h"
 #include "cc/trees/layer_tree_impl.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/rect_conversions.h"
+#include "ui/gfx/size_conversions.h"
 
 namespace cc {
 namespace {
@@ -48,7 +51,10 @@ class PictureLayerImplTest : public testing::Test {
         host_impl_(ImplSidePaintingSettings(),
                    &proxy_,
                    &shared_bitmap_manager_),
-        id_(7) {}
+        id_(7),
+        pending_layer_(NULL),
+        old_pending_layer_(NULL),
+        active_layer_(NULL) {}
 
   explicit PictureLayerImplTest(const LayerTreeSettings& settings)
       : proxy_(base::MessageLoopProxy::current()),
@@ -79,8 +85,10 @@ class PictureLayerImplTest : public testing::Test {
   }
 
   void ActivateTree() {
-    host_impl_.ActivatePendingTree();
+    host_impl_.ActivateSyncTree();
     CHECK(!host_impl_.pending_tree());
+    CHECK(host_impl_.recycle_tree());
+    old_pending_layer_ = pending_layer_;
     pending_layer_ = NULL;
     active_layer_ = static_cast<FakePictureLayerImpl*>(
         host_impl_.active_tree()->LayerById(id_));
@@ -120,9 +128,9 @@ class PictureLayerImplTest : public testing::Test {
       pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
   }
 
-  void SetupPendingTree(
-      scoped_refptr<PicturePileImpl> pile) {
+  void SetupPendingTree(scoped_refptr<PicturePileImpl> pile) {
     host_impl_.CreatePendingTree();
+    host_impl_.pending_tree()->SetPageScaleFactorAndLimits(1.f, 0.25f, 100.f);
     LayerTreeImpl* pending_tree = host_impl_.pending_tree();
     // Clear recycled tree.
     pending_tree->DetachLayerTree();
@@ -137,11 +145,28 @@ class PictureLayerImplTest : public testing::Test {
     pending_layer_->DoPostCommitInitializationIfNeeded();
   }
 
+  void SetupDrawPropertiesAndUpdateTiles(FakePictureLayerImpl* layer,
+                                         float ideal_contents_scale,
+                                         float device_scale_factor,
+                                         float page_scale_factor,
+                                         float maximum_animation_contents_scale,
+                                         bool animating_transform_to_screen) {
+    layer->draw_properties().ideal_contents_scale = ideal_contents_scale;
+    layer->draw_properties().device_scale_factor = device_scale_factor;
+    layer->draw_properties().page_scale_factor = page_scale_factor;
+    layer->draw_properties().maximum_animation_contents_scale =
+        maximum_animation_contents_scale;
+    layer->draw_properties().screen_space_transform_is_animating =
+        animating_transform_to_screen;
+    layer->UpdateTiles(NULL);
+  }
   static void VerifyAllTilesExistAndHavePile(
       const PictureLayerTiling* tiling,
       PicturePileImpl* pile) {
-    for (PictureLayerTiling::CoverageIterator
-             iter(tiling, tiling->contents_scale(), tiling->ContentRect());
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             tiling->contents_scale(),
+             gfx::Rect(tiling->tiling_size()));
          iter;
          ++iter) {
       EXPECT_TRUE(*iter);
@@ -152,25 +177,21 @@ class PictureLayerImplTest : public testing::Test {
   void SetContentsScaleOnBothLayers(float contents_scale,
                                     float device_scale_factor,
                                     float page_scale_factor,
+                                    float maximum_animation_contents_scale,
                                     bool animating_transform) {
-    float result_scale_x, result_scale_y;
-    gfx::Size result_bounds;
-    pending_layer_->CalculateContentsScale(
-        contents_scale,
-        device_scale_factor,
-        page_scale_factor,
-        animating_transform,
-        &result_scale_x,
-        &result_scale_y,
-        &result_bounds);
-    active_layer_->CalculateContentsScale(
-        contents_scale,
-        device_scale_factor,
-        page_scale_factor,
-        animating_transform,
-        &result_scale_x,
-        &result_scale_y,
-        &result_bounds);
+    SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                      contents_scale,
+                                      device_scale_factor,
+                                      page_scale_factor,
+                                      maximum_animation_contents_scale,
+                                      animating_transform);
+
+    SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                      contents_scale,
+                                      device_scale_factor,
+                                      page_scale_factor,
+                                      maximum_animation_contents_scale,
+                                      animating_transform);
   }
 
   void ResetTilingsAndRasterScales() {
@@ -207,10 +228,7 @@ class PictureLayerImplTest : public testing::Test {
 
     SetupTrees(pending_pile, active_pile);
 
-    float result_scale_x, result_scale_y;
-    gfx::Size result_bounds;
-    active_layer_->CalculateContentsScale(
-        1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+    SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
 
     // Add 1x1 rects at the centers of each tile, then re-record pile contents
     active_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -250,6 +268,7 @@ class PictureLayerImplTest : public testing::Test {
   FakeLayerTreeHostImpl host_impl_;
   int id_;
   FakePictureLayerImpl* pending_layer_;
+  FakePictureLayerImpl* old_pending_layer_;
   FakePictureLayerImpl* active_layer_;
 
  private:
@@ -289,7 +308,10 @@ TEST_F(PictureLayerImplTest, CloneNoInvalidation) {
     VerifyAllTilesExistAndHavePile(tilings->tiling_at(i), active_pile.get());
 }
 
-TEST_F(PictureLayerImplTest, TileManagerRegisterUnregister) {
+TEST_F(PictureLayerImplTest, ExternalViewportRectForPrioritizingTiles) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
 
@@ -300,73 +322,96 @@ TEST_F(PictureLayerImplTest, TileManagerRegisterUnregister) {
 
   SetupTrees(pending_pile, active_pile);
 
-  std::vector<TileManager::PairedPictureLayer> paired_layers;
-  host_impl_.tile_manager()->GetPairedPictureLayers(&paired_layers);
-  EXPECT_EQ(0u, paired_layers.size());
-
-  // Update tile priorities will force the layer to register itself.
-  float dummy_contents_scale_x;
-  float dummy_contents_scale_y;
-  gfx::Size dummy_content_bounds;
-  active_layer_->CalculateContentsScale(1.f,
-                                        1.f,
-                                        1.f,
-                                        false,
-                                        &dummy_contents_scale_x,
-                                        &dummy_contents_scale_y,
-                                        &dummy_content_bounds);
-  active_layer_->UpdateTilePriorities();
-  host_impl_.pending_tree()->UpdateDrawProperties();
-  pending_layer_->CalculateContentsScale(1.f,
-                                         1.f,
-                                         1.f,
-                                         false,
-                                         &dummy_contents_scale_x,
-                                         &dummy_contents_scale_y,
-                                         &dummy_content_bounds);
-  pending_layer_->UpdateTilePriorities();
-
-  host_impl_.tile_manager()->GetPairedPictureLayers(&paired_layers);
-  EXPECT_EQ(1u, paired_layers.size());
-  EXPECT_EQ(active_layer_, paired_layers[0].active_layer);
-  EXPECT_EQ(pending_layer_, paired_layers[0].pending_layer);
-
-  // Destroy and recreate tile manager.
-  host_impl_.DidLoseOutputSurface();
-  scoped_ptr<TestWebGraphicsContext3D> context =
-      TestWebGraphicsContext3D::Create();
-  host_impl_.InitializeRenderer(
-      FakeOutputSurface::Create3d(context.Pass()).PassAs<OutputSurface>());
-
-  host_impl_.tile_manager()->GetPairedPictureLayers(&paired_layers);
-  EXPECT_EQ(0u, paired_layers.size());
-
-  active_layer_->CalculateContentsScale(1.f,
-                                        1.f,
-                                        1.f,
-                                        false,
-                                        &dummy_contents_scale_x,
-                                        &dummy_contents_scale_y,
-                                        &dummy_content_bounds);
-  active_layer_->UpdateTilePriorities();
-  host_impl_.pending_tree()->UpdateDrawProperties();
-  pending_layer_->CalculateContentsScale(1.f,
-                                         1.f,
-                                         1.f,
-                                         false,
-                                         &dummy_contents_scale_x,
-                                         &dummy_contents_scale_y,
-                                         &dummy_content_bounds);
-  pending_layer_->UpdateTilePriorities();
-
-  host_impl_.tile_manager()->GetPairedPictureLayers(&paired_layers);
-  EXPECT_EQ(1u, paired_layers.size());
-  EXPECT_EQ(active_layer_, paired_layers[0].active_layer);
-  EXPECT_EQ(pending_layer_, paired_layers[0].pending_layer);
-}
-
-TEST_F(PictureLayerImplTest, SuppressUpdateTilePriorities) {
+  Region invalidation;
+  AddDefaultTilingsWithInvalidation(invalidation);
+  SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+  // Update tiles with viewport for tile priority as (0, 0, 100, 100) and the
+  // identify transform for tile priority.
+  bool resourceless_software_draw = false;
+  gfx::Rect viewport = gfx::Rect(layer_bounds),
+            viewport_rect_for_tile_priority = gfx::Rect(0, 0, 100, 100);
+  gfx::Transform transform, transform_for_tile_priority;
+
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport_rect_for_tile_priority,
+                                        transform_for_tile_priority,
+                                        resourceless_software_draw);
+  active_layer_->draw_properties().visible_content_rect = viewport;
+  active_layer_->draw_properties().screen_space_transform = transform;
+  active_layer_->UpdateTiles(NULL);
+
+  gfx::Rect viewport_rect_for_tile_priority_in_view_space =
+      viewport_rect_for_tile_priority;
+
+  // Verify the viewport rect for tile priority is used in picture layer impl.
+  EXPECT_EQ(active_layer_->viewport_rect_for_tile_priority(),
+            viewport_rect_for_tile_priority_in_view_space);
+
+  // Verify the viewport rect for tile priority is used in picture layer tiling.
+  PictureLayerTilingSet* tilings = active_layer_->tilings();
+  for (size_t i = 0; i < tilings->num_tilings(); i++) {
+    PictureLayerTiling* tiling = tilings->tiling_at(i);
+    EXPECT_EQ(
+        tiling->GetCurrentVisibleRectForTesting(),
+        gfx::ScaleToEnclosingRect(viewport_rect_for_tile_priority_in_view_space,
+                                  tiling->contents_scale()));
+  }
+
+  // Update tiles with viewport for tile priority as (200, 200, 100, 100) in
+  // screen space and the transform for tile priority is translated and
+  // rotated. The actual viewport for tile priority used by PictureLayerImpl
+  // should be (200, 200, 100, 100) applied with the said transform.
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+  viewport_rect_for_tile_priority = gfx::Rect(200, 200, 100, 100);
+  transform_for_tile_priority.Translate(100, 100);
+  transform_for_tile_priority.Rotate(45);
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport_rect_for_tile_priority,
+                                        transform_for_tile_priority,
+                                        resourceless_software_draw);
+  active_layer_->draw_properties().visible_content_rect = viewport;
+  active_layer_->draw_properties().screen_space_transform = transform;
+  active_layer_->UpdateTiles(NULL);
+
+  gfx::Transform screen_to_view(gfx::Transform::kSkipInitialization);
+  bool success = transform_for_tile_priority.GetInverse(&screen_to_view);
+  EXPECT_TRUE(success);
+
+  viewport_rect_for_tile_priority_in_view_space =
+      gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
+          screen_to_view, viewport_rect_for_tile_priority));
+
+  // Verify the viewport rect for tile priority is used in PictureLayerImpl.
+  EXPECT_EQ(active_layer_->viewport_rect_for_tile_priority(),
+            viewport_rect_for_tile_priority_in_view_space);
+
+  // Interset viewport_rect_for_tile_priority_in_view_space with the layer
+  // bounds and the result should be used in PictureLayerTiling.
+  viewport_rect_for_tile_priority_in_view_space.Intersect(
+      gfx::Rect(layer_bounds));
+  tilings = active_layer_->tilings();
+  for (size_t i = 0; i < tilings->num_tilings(); i++) {
+    PictureLayerTiling* tiling = tilings->tiling_at(i);
+    EXPECT_EQ(
+        tiling->GetCurrentVisibleRectForTesting(),
+        gfx::ScaleToEnclosingRect(viewport_rect_for_tile_priority_in_view_space,
+                                  tiling->contents_scale()));
+  }
+}
+
+TEST_F(PictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
   base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
   host_impl_.SetCurrentFrameTimeTicks(time_ticks);
 
   gfx::Size tile_size(100, 100);
@@ -381,44 +426,110 @@ TEST_F(PictureLayerImplTest, SuppressUpdateTilePriorities) {
 
   Region invalidation;
   AddDefaultTilingsWithInvalidation(invalidation);
-  float dummy_contents_scale_x;
-  float dummy_contents_scale_y;
-  gfx::Size dummy_content_bounds;
-  active_layer_->CalculateContentsScale(1.f,
-                                        1.f,
-                                        1.f,
-                                        false,
-                                        &dummy_contents_scale_x,
-                                        &dummy_contents_scale_y,
-                                        &dummy_content_bounds);
-
-  EXPECT_TRUE(host_impl_.manage_tiles_needed());
-  active_layer_->UpdateTilePriorities();
-  host_impl_.ManageTiles();
-  EXPECT_FALSE(host_impl_.manage_tiles_needed());
-
+  SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+
+  // UpdateTiles with valid viewport. Should update tile viewport.
+  // Note viewport is considered invalid if and only if in resourceless
+  // software draw.
+  bool resourceless_software_draw = false;
+  gfx::Rect viewport = gfx::Rect(layer_bounds);
+  gfx::Transform transform;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        transform,
+                                        resourceless_software_draw);
+  active_layer_->draw_properties().visible_content_rect = viewport;
+  active_layer_->draw_properties().screen_space_transform = transform;
+  active_layer_->UpdateTiles(NULL);
+
+  gfx::Rect visible_rect_for_tile_priority =
+      active_layer_->visible_rect_for_tile_priority();
+  EXPECT_FALSE(visible_rect_for_tile_priority.IsEmpty());
+  gfx::Rect viewport_rect_for_tile_priority =
+      active_layer_->viewport_rect_for_tile_priority();
+  EXPECT_FALSE(viewport_rect_for_tile_priority.IsEmpty());
+  gfx::Transform screen_space_transform_for_tile_priority =
+      active_layer_->screen_space_transform_for_tile_priority();
+
+  // Expand viewport and set it as invalid for prioritizing tiles.
+  // Should not update tile viewport.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentFrameTimeTicks(time_ticks);
-
-  // Setting this boolean should cause an early out in UpdateTilePriorities.
-  bool valid_for_tile_management = false;
-  host_impl_.SetExternalDrawConstraints(gfx::Transform(),
-                                        gfx::Rect(layer_bounds),
-                                        gfx::Rect(layer_bounds),
-                                        valid_for_tile_management);
-  active_layer_->UpdateTilePriorities();
-  EXPECT_FALSE(host_impl_.manage_tiles_needed());
-
+  resourceless_software_draw = true;
+  viewport = gfx::ScaleToEnclosingRect(viewport, 2);
+  transform.Translate(1.f, 1.f);
+  active_layer_->draw_properties().visible_content_rect = viewport;
+  active_layer_->draw_properties().screen_space_transform = transform;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        transform,
+                                        resourceless_software_draw);
+  active_layer_->UpdateTiles(NULL);
+
+  EXPECT_RECT_EQ(visible_rect_for_tile_priority,
+                 active_layer_->visible_rect_for_tile_priority());
+  EXPECT_RECT_EQ(viewport_rect_for_tile_priority,
+                 active_layer_->viewport_rect_for_tile_priority());
+  EXPECT_TRANSFORMATION_MATRIX_EQ(
+      screen_space_transform_for_tile_priority,
+      active_layer_->screen_space_transform_for_tile_priority());
+
+  // Keep expanded viewport but mark it valid. Should update tile viewport.
   time_ticks += base::TimeDelta::FromMilliseconds(200);
   host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  resourceless_software_draw = false;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        transform,
+                                        resourceless_software_draw);
+  active_layer_->UpdateTiles(NULL);
+
+  EXPECT_FALSE(visible_rect_for_tile_priority ==
+               active_layer_->visible_rect_for_tile_priority());
+  EXPECT_FALSE(viewport_rect_for_tile_priority ==
+               active_layer_->viewport_rect_for_tile_priority());
+  EXPECT_FALSE(screen_space_transform_for_tile_priority ==
+               active_layer_->screen_space_transform_for_tile_priority());
+}
+
+TEST_F(PictureLayerImplTest, InvalidViewportAfterReleaseResources) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(400, 400);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupTrees(pending_pile, active_pile);
+
+  Region invalidation;
+  AddDefaultTilingsWithInvalidation(invalidation);
+
+  bool resourceless_software_draw = true;
+  gfx::Rect viewport = gfx::Rect(layer_bounds);
+  gfx::Transform identity = gfx::Transform();
+  host_impl_.SetExternalDrawConstraints(identity,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        identity,
+                                        resourceless_software_draw);
+  ResetTilingsAndRasterScales();
+  host_impl_.pending_tree()->UpdateDrawProperties();
+  host_impl_.active_tree()->UpdateDrawProperties();
+  EXPECT_TRUE(active_layer_->HighResTiling());
 
-  valid_for_tile_management = true;
-  host_impl_.SetExternalDrawConstraints(gfx::Transform(),
-                                        gfx::Rect(layer_bounds),
-                                        gfx::Rect(layer_bounds),
-                                        valid_for_tile_management);
-  active_layer_->UpdateTilePriorities();
-  EXPECT_TRUE(host_impl_.manage_tiles_needed());
+  size_t num_tilings = active_layer_->num_tilings();
+  active_layer_->UpdateTiles(NULL);
+  pending_layer_->AddTiling(0.5f);
+  EXPECT_EQ(num_tilings + 1, active_layer_->num_tilings());
 }
 
 TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
@@ -443,10 +554,10 @@ TEST_F(PictureLayerImplTest, ClonePartialInvalidation) {
     gfx::Rect content_invalidation = gfx::ScaleToEnclosingRect(
         layer_invalidation,
         tiling->contents_scale());
-    for (PictureLayerTiling::CoverageIterator
-             iter(tiling,
-                  tiling->contents_scale(),
-                  tiling->ContentRect());
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             tiling->contents_scale(),
+             gfx::Rect(tiling->tiling_size()));
          iter;
          ++iter) {
       EXPECT_TRUE(*iter);
@@ -506,10 +617,10 @@ TEST_F(PictureLayerImplTest, NoInvalidationBoundsChange) {
     gfx::Rect active_content_bounds = gfx::ScaleToEnclosingRect(
         gfx::Rect(active_layer_bounds),
         tiling->contents_scale());
-    for (PictureLayerTiling::CoverageIterator
-             iter(tiling,
-                  tiling->contents_scale(),
-                  tiling->ContentRect());
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             tiling->contents_scale(),
+             gfx::Rect(tiling->tiling_size()));
          iter;
          ++iter) {
       EXPECT_TRUE(*iter);
@@ -562,10 +673,10 @@ TEST_F(PictureLayerImplTest, AddTilesFromNewRecording) {
   for (size_t i = 0; i < tilings->num_tilings(); ++i) {
     const PictureLayerTiling* tiling = tilings->tiling_at(i);
 
-    for (PictureLayerTiling::CoverageIterator
-             iter(tiling,
-                  tiling->contents_scale(),
-                  tiling->ContentRect());
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             tiling->contents_scale(),
+             gfx::Rect(tiling->tiling_size()));
          iter;
          ++iter) {
       EXPECT_FALSE(iter.full_tile_geometry_rect().IsEmpty());
@@ -594,13 +705,9 @@ TEST_F(PictureLayerImplTest, ManageTilingsWithNoRecording) {
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
 
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
-
   SetupTrees(pending_pile, active_pile);
 
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
 
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 }
@@ -614,95 +721,63 @@ TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) {
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
-
   SetupTrees(pending_pile, active_pile);
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   EXPECT_LT(low_res_factor, 1.f);
 
-  pending_layer_->CalculateContentsScale(1.3f,  // ideal contents scale
-                                         1.7f,  // device scale
-                                         3.2f,  // page cale
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
-  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      1.3f,
-      pending_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      1.3f * low_res_factor,
-      pending_layer_->tilings()->tiling_at(1)->contents_scale());
-
-  // If we change the layer's CSS scale factor, then we should not get new
-  // tilings.
-  pending_layer_->CalculateContentsScale(1.8f,  // ideal contents scale
-                                         1.7f,  // device scale
-                                         3.2f,  // page cale
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    6.f,  // ideal contents scale
+                                    3.f,  // device scale
+                                    2.f,  // page scale
+                                    1.f,  // maximum animation scale
+                                    false);
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      1.3f,
-      pending_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      1.3f * low_res_factor,
-      pending_layer_->tilings()->tiling_at(1)->contents_scale());
+  EXPECT_FLOAT_EQ(6.f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(6.f * low_res_factor,
+                  pending_layer_->tilings()->tiling_at(1)->contents_scale());
 
   // If we change the page scale factor, then we should get new tilings.
-  pending_layer_->CalculateContentsScale(1.8f,  // ideal contents scale
-                                         1.7f,  // device scale
-                                         2.2f,  // page cale
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    6.6f,  // ideal contents scale
+                                    3.f,   // device scale
+                                    2.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
   ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      1.8f,
-      pending_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      1.8f * low_res_factor,
-      pending_layer_->tilings()->tiling_at(2)->contents_scale());
+  EXPECT_FLOAT_EQ(6.6f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(6.6f * low_res_factor,
+                  pending_layer_->tilings()->tiling_at(2)->contents_scale());
 
   // If we change the device scale factor, then we should get new tilings.
-  pending_layer_->CalculateContentsScale(1.9f,  // ideal contents scale
-                                         1.4f,  // device scale
-                                         2.2f,  // page cale
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    7.26f,  // ideal contents scale
+                                    3.3f,   // device scale
+                                    2.2f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
   ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      1.9f,
-      pending_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      1.9f * low_res_factor,
-      pending_layer_->tilings()->tiling_at(3)->contents_scale());
+  EXPECT_FLOAT_EQ(7.26f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+                  pending_layer_->tilings()->tiling_at(3)->contents_scale());
 
   // If we change the device scale factor, but end up at the same total scale
   // factor somehow, then we don't get new tilings.
-  pending_layer_->CalculateContentsScale(1.9f,  // ideal contents scale
-                                         2.2f,  // device scale
-                                         1.4f,  // page cale
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    7.26f,  // ideal contents scale
+                                    2.2f,   // device scale
+                                    3.3f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
   ASSERT_EQ(6u, pending_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      1.9f,
-      pending_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      1.9f * low_res_factor,
-      pending_layer_->tilings()->tiling_at(3)->contents_scale());
+  EXPECT_FLOAT_EQ(7.26f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(7.26f * low_res_factor,
+                  pending_layer_->tilings()->tiling_at(3)->contents_scale());
 }
 
 TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
@@ -724,17 +799,15 @@ TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
   float low_res_scale = high_res_scale * low_res_factor;
   float device_scale = 1.7f;
   float page_scale = 3.2f;
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
+  float maximum_animation_scale = 1.f;
 
   SetupPendingTree(valid_pile);
-  pending_layer_->CalculateContentsScale(high_res_scale,
-                                         device_scale,
-                                         page_scale,
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    high_res_scale,
+                                    device_scale,
+                                    page_scale,
+                                    maximum_animation_scale,
+                                    false);
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(high_res_scale,
                   pending_layer_->HighResTiling()->contents_scale());
@@ -743,34 +816,33 @@ TEST_F(PictureLayerImplTest, CreateTilingsEvenIfTwinHasNone) {
 
   ActivateTree();
   SetupPendingTree(empty_pile);
-  pending_layer_->CalculateContentsScale(high_res_scale,
-                                         device_scale,
-                                         page_scale,
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  EXPECT_FALSE(pending_layer_->CanHaveTilings());
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    high_res_scale,
+                                    device_scale,
+                                    page_scale,
+                                    maximum_animation_scale,
+                                    false);
   ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
   ASSERT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
   ActivateTree();
-  active_layer_->CalculateContentsScale(high_res_scale,
-                                        device_scale,
-                                        page_scale,
-                                        false,
-                                        &result_scale_x,
-                                        &result_scale_y,
-                                        &result_bounds);
+  EXPECT_FALSE(active_layer_->CanHaveTilings());
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    high_res_scale,
+                                    device_scale,
+                                    page_scale,
+                                    maximum_animation_scale,
+                                    false);
   ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
 
   SetupPendingTree(valid_pile);
-  pending_layer_->CalculateContentsScale(high_res_scale,
-                                         device_scale,
-                                         page_scale,
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    high_res_scale,
+                                    device_scale,
+                                    page_scale,
+                                    maximum_animation_scale,
+                                    false);
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
   ASSERT_EQ(0u, active_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(high_res_scale,
@@ -791,10 +863,10 @@ TEST_F(PictureLayerImplTest, ZoomOutCrash) {
 
   SetupTrees(pending_pile, active_pile);
   EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
-  SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, false);
+  SetContentsScaleOnBothLayers(32.0f, 1.0f, 32.0f, 1.0f, false);
   host_impl_.PinchGestureBegin();
-  SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false);
-  SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false);
+  SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
+  SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, 1.0f, false);
   EXPECT_EQ(active_layer_->tilings()->NumHighResTilings(), 1);
 }
 
@@ -810,50 +882,89 @@ TEST_F(PictureLayerImplTest, PinchGestureTilings) {
   // Set up the high and low res tilings before pinch zoom.
   SetupTrees(pending_pile, active_pile);
   EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
-  SetContentsScaleOnBothLayers(1.0f, 1.0f, 1.0f, false);
+  SetContentsScaleOnBothLayers(2.0f, 1.0f, 1.0f, 1.0f, false);
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      1.0f,
-      active_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      1.0f * low_res_factor,
-      active_layer_->tilings()->tiling_at(1)->contents_scale());
+  EXPECT_FLOAT_EQ(2.0f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(2.0f * low_res_factor,
+                  active_layer_->tilings()->tiling_at(1)->contents_scale());
 
   // Start a pinch gesture.
   host_impl_.PinchGestureBegin();
 
   // Zoom out by a small amount. We should create a tiling at half
-  // the scale (1/kMaxScaleRatioDuringPinch).
-  SetContentsScaleOnBothLayers(0.90f, 1.0f, 0.9f, false);
+  // the scale (2/kMaxScaleRatioDuringPinch).
+  SetContentsScaleOnBothLayers(1.8f, 1.0f, 0.9f, 1.0f, false);
   EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      1.0f,
-      active_layer_->tilings()->tiling_at(0)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      0.5f,
-      active_layer_->tilings()->tiling_at(1)->contents_scale());
-  EXPECT_FLOAT_EQ(
-      1.0f * low_res_factor,
-      active_layer_->tilings()->tiling_at(2)->contents_scale());
+  EXPECT_FLOAT_EQ(2.0f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(1.0f,
+                  active_layer_->tilings()->tiling_at(1)->contents_scale());
+  EXPECT_FLOAT_EQ(2.0f * low_res_factor,
+                  active_layer_->tilings()->tiling_at(2)->contents_scale());
 
   // Zoom out further, close to our low-res scale factor. We should
   // use that tiling as high-res, and not create a new tiling.
-  SetContentsScaleOnBothLayers(low_res_factor, 1.0f, low_res_factor, false);
+  SetContentsScaleOnBothLayers(
+      low_res_factor, 1.0f, low_res_factor / 2.0f, 1.0f, false);
   EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
 
   // Zoom in a lot now. Since we increase by increments of
-  // kMaxScaleRatioDuringPinch, this will first use 0.5, then 1.0
-  // and then finally create a new tiling at 2.0.
-  SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false);
+  // kMaxScaleRatioDuringPinch, this will first use 1.0, then 2.0
+  // and then finally create a new tiling at 4.0.
+  SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
   EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
-  SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false);
+  SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
   EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
-  SetContentsScaleOnBothLayers(2.1f, 1.0f, 2.1f, false);
+  SetContentsScaleOnBothLayers(4.2f, 1.0f, 2.1f, 1.f, false);
   EXPECT_EQ(4u, active_layer_->tilings()->num_tilings());
-  EXPECT_FLOAT_EQ(
-      2.0f,
-      active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(4.0f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+}
+
+TEST_F(PictureLayerImplTest, SnappedTilingDuringZoom) {
+  gfx::Size tile_size(300, 300);
+  gfx::Size layer_bounds(2600, 3800);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  // Set up the high and low res tilings before pinch zoom.
+  SetupTrees(pending_pile, active_pile);
+  EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+  SetContentsScaleOnBothLayers(0.24f, 1.0f, 0.24f, 1.0f, false);
+  EXPECT_EQ(2u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(0.24f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(0.0625f,
+                  active_layer_->tilings()->tiling_at(1)->contents_scale());
+
+  // Start a pinch gesture.
+  host_impl_.PinchGestureBegin();
+
+  // Zoom out by a small amount. We should create a tiling at half
+  // the scale (1/kMaxScaleRatioDuringPinch).
+  SetContentsScaleOnBothLayers(0.2f, 1.0f, 0.2f, 1.0f, false);
+  EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(0.24f,
+                  active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_FLOAT_EQ(0.12f,
+                  active_layer_->tilings()->tiling_at(1)->contents_scale());
+  EXPECT_FLOAT_EQ(0.0625,
+                  active_layer_->tilings()->tiling_at(2)->contents_scale());
+
+  // Zoom out further, close to our low-res scale factor. We should
+  // use that tiling as high-res, and not create a new tiling.
+  SetContentsScaleOnBothLayers(0.1f, 1.0f, 0.1f, 1.0f, false);
+  EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
+
+  // Zoom in. 0.125(desired_scale) should be snapped to 0.12 during zoom-in
+  // because 0.125(desired_scale) is within the ratio(1.2)
+  SetContentsScaleOnBothLayers(0.5f, 1.0f, 0.5f, 1.0f, false);
+  EXPECT_EQ(3u, active_layer_->tilings()->num_tilings());
 }
 
 TEST_F(PictureLayerImplTest, CleanUpTilings) {
@@ -865,8 +976,6 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
   std::vector<PictureLayerTiling*> used_tilings;
 
   SetupTrees(pending_pile, active_pile);
@@ -877,8 +986,9 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
 
   float device_scale = 1.7f;
   float page_scale = 3.2f;
+  float scale = 1.f;
 
-  SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, false);
+  SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
   ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
 
   // We only have ideal tilings, so they aren't removed.
@@ -886,8 +996,12 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
   active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
   ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
 
+  host_impl_.PinchGestureBegin();
+
   // Changing the ideal but not creating new tilings.
-  SetContentsScaleOnBothLayers(1.5f, device_scale, page_scale, false);
+  scale *= 1.5f;
+  page_scale *= 1.5f;
+  SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
   ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
 
   // The tilings are still our target scale, so they aren't removed.
@@ -895,9 +1009,12 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
   active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
   ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
 
+  host_impl_.PinchGestureEnd();
+
   // Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
-  page_scale = 1.2f;
-  SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, false);
+  scale /= 4.f;
+  page_scale /= 4.f;
+  SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, false);
   ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
   EXPECT_FLOAT_EQ(
       1.f,
@@ -914,7 +1031,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
   ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
 
   // Now move the ideal scale to 0.5. Our target stays 1.2.
-  SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, false);
+  SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, false);
 
   // The high resolution tiling is between target and ideal, so is not
   // removed.  The low res tiling for the old ideal=1.0 scale is removed.
@@ -923,7 +1040,7 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
   ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
 
   // Now move the ideal scale to 1.0. Our target stays 1.2.
-  SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, false);
+  SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, false);
 
   // All the tilings are between are target and the ideal, so they are not
   // removed.
@@ -932,13 +1049,8 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
   ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
 
   // Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
-  active_layer_->CalculateContentsScale(1.1f,
-                                        device_scale,
-                                        page_scale,
-                                        false,
-                                        &result_scale_x,
-                                        &result_scale_y,
-                                        &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(
+      active_layer_, 1.1f, device_scale, page_scale, 1.f, false);
 
   // Because the pending layer's ideal scale is still 1.0, our tilings fall
   // in the range [1.0,1.2] and are kept.
@@ -948,13 +1060,8 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
 
   // Move the ideal scale on the pending layer to 1.1 as well. Our target stays
   // 1.2 still.
-  pending_layer_->CalculateContentsScale(1.1f,
-                                         device_scale,
-                                         page_scale,
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(
+      pending_layer_, 1.1f, device_scale, page_scale, 1.f, false);
 
   // Our 1.0 tiling now falls outside the range between our ideal scale and our
   // target raster scale. But it is in our used tilings set, so nothing is
@@ -973,8 +1080,14 @@ TEST_F(PictureLayerImplTest, CleanUpTilings) {
 
 #define EXPECT_BOTH_EQ(expression, x)         \
   do {                                        \
-    EXPECT_EQ(pending_layer_->expression, x); \
-    EXPECT_EQ(active_layer_->expression, x);  \
+    EXPECT_EQ(x, pending_layer_->expression); \
+    EXPECT_EQ(x, active_layer_->expression);  \
+  } while (false)
+
+#define EXPECT_BOTH_NE(expression, x)         \
+  do {                                        \
+    EXPECT_NE(x, pending_layer_->expression); \
+    EXPECT_NE(x, active_layer_->expression);  \
   } while (false)
 
 TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
@@ -990,18 +1103,25 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
   float contents_scale = 1.f;
   float device_scale = 1.f;
   float page_scale = 1.f;
+  float maximum_animation_scale = 1.f;
   bool animating_transform = true;
 
   // Animating, so don't create low res even if there isn't one already.
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
   EXPECT_BOTH_EQ(num_tilings(), 1u);
 
   // Stop animating, low res gets created.
   animating_transform = false;
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
   EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), low_res_factor);
   EXPECT_BOTH_EQ(num_tilings(), 2u);
@@ -1010,16 +1130,22 @@ TEST_F(PictureLayerImplTest, DontAddLowResDuringAnimation) {
   contents_scale = 2.f;
   page_scale = 2.f;
   animating_transform = true;
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
   EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), low_res_factor);
   EXPECT_BOTH_EQ(num_tilings(), 3u);
 
   // Stop animating, new low res gets created for final page scale.
   animating_transform = false;
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
   EXPECT_BOTH_EQ(LowResTiling()->contents_scale(), 2.f * low_res_factor);
   EXPECT_BOTH_EQ(num_tilings(), 4u);
@@ -1032,12 +1158,16 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
   float device_scale = 1.f;
   float page_scale = 1.f;
+  float maximum_animation_scale = 1.f;
   bool animating_transform = false;
 
   // Contents exactly fit on one tile at scale 1, no low res.
   float contents_scale = 1.f;
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
   EXPECT_BOTH_EQ(num_tilings(), 1u);
 
@@ -1045,8 +1175,11 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
 
   // Contents that are smaller than one tile, no low res.
   contents_scale = 0.123f;
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
   EXPECT_BOTH_EQ(num_tilings(), 1u);
 
@@ -1055,8 +1188,11 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
   // Any content bounds that would create more than one tile will
   // generate a low res tiling.
   contents_scale = 2.5f;
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
   EXPECT_BOTH_EQ(LowResTiling()->contents_scale(),
                  contents_scale * low_res_factor);
@@ -1065,14 +1201,64 @@ TEST_F(PictureLayerImplTest, DontAddLowResForSmallLayers) {
   ResetTilingsAndRasterScales();
 
   // Mask layers dont create low res since they always fit on one tile.
-  pending_layer_->SetIsMask(true);
-  active_layer_->SetIsMask(true);
-  SetContentsScaleOnBothLayers(
-      contents_scale, device_scale, page_scale, animating_transform);
+  pending_layer_->pile()->set_is_mask(true);
+  active_layer_->pile()->set_is_mask(true);
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
   EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), contents_scale);
   EXPECT_BOTH_EQ(num_tilings(), 1u);
 }
 
+TEST_F(PictureLayerImplTest, HugeMasksDontGetTiles) {
+  gfx::Size tile_size(100, 100);
+
+  scoped_refptr<FakePicturePileImpl> valid_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, gfx::Size(1000, 1000));
+  valid_pile->set_is_mask(true);
+  SetupPendingTree(valid_pile);
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+  EXPECT_EQ(1u, pending_layer_->num_tilings());
+
+  pending_layer_->HighResTiling()->CreateAllTilesForTesting();
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
+      pending_layer_->HighResTiling()->AllTilesForTesting());
+
+  ActivateTree();
+
+  // Mask layers have a tiling with a single tile in it.
+  EXPECT_EQ(1u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  // The mask resource exists.
+  EXPECT_NE(0u, active_layer_->ContentsResourceId());
+
+  // Resize larger than the max texture size.
+  int max_texture_size = host_impl_.GetRendererCapabilities().max_texture_size;
+  scoped_refptr<FakePicturePileImpl> huge_pile =
+      FakePicturePileImpl::CreateFilledPile(
+          tile_size, gfx::Size(max_texture_size + 1, 10));
+  huge_pile->set_is_mask(true);
+  SetupPendingTree(huge_pile);
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+  EXPECT_EQ(1.f, pending_layer_->HighResTiling()->contents_scale());
+  EXPECT_EQ(1u, pending_layer_->num_tilings());
+
+  pending_layer_->HighResTiling()->CreateAllTilesForTesting();
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(
+      pending_layer_->HighResTiling()->AllTilesForTesting());
+
+  ActivateTree();
+
+  // Mask layers have a tiling, but there should be no tiles in it.
+  EXPECT_EQ(0u, active_layer_->HighResTiling()->AllTilesForTesting().size());
+  // The mask resource is empty.
+  EXPECT_EQ(0u, active_layer_->ContentsResourceId());
+}
+
 TEST_F(PictureLayerImplTest, ReleaseResources) {
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1300, 1900);
@@ -1082,19 +1268,15 @@ TEST_F(PictureLayerImplTest, ReleaseResources) {
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
-
   SetupTrees(pending_pile, active_pile);
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
-  pending_layer_->CalculateContentsScale(1.3f,  // ideal contents scale
-                                         2.7f,  // device scale
-                                         3.2f,  // page cale
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    1.3f,  // ideal contents scale
+                                    2.7f,  // device scale
+                                    3.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
   EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
 
   // All tilings should be removed when losing output surface.
@@ -1104,13 +1286,12 @@ TEST_F(PictureLayerImplTest, ReleaseResources) {
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
   // This should create new tilings.
-  pending_layer_->CalculateContentsScale(1.3f,  // ideal contents scale
-                                         2.7f,  // device scale
-                                         3.2f,  // page cale
-                                         false,
-                                         &result_scale_x,
-                                         &result_scale_y,
-                                         &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    1.3f,  // ideal contents scale
+                                    2.7f,  // device scale
+                                    3.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
   EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
 }
 
@@ -1124,14 +1305,10 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
-
   SetupTrees(pending_pile, active_pile);
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
 
   pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1154,8 +1331,7 @@ TEST_F(PictureLayerImplTest, ClampTilesToToMaxTileSize) {
   host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
       context.Pass()).PassAs<OutputSurface>());
 
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
 
   pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1176,14 +1352,10 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
   scoped_refptr<FakePicturePileImpl> active_pile =
       FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
 
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
-
   SetupTrees(pending_pile, active_pile);
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
 
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
   ASSERT_LE(1u, pending_layer_->tilings()->num_tilings());
 
   pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1206,8 +1378,7 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
   host_impl_.InitializeRenderer(FakeOutputSurface::Create3d(
       context.Pass()).PassAs<OutputSurface>());
 
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
   ASSERT_LE(1u, pending_layer_->tilings()->num_tilings());
 
   pending_layer_->tilings()->tiling_at(0)->CreateAllTilesForTesting();
@@ -1224,7 +1395,8 @@ TEST_F(PictureLayerImplTest, ClampSingleTileToToMaxTileSize) {
 }
 
 TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) {
-  MockQuadCuller quad_culler;
+  MockOcclusionTracker<LayerImpl> occlusion_tracker;
+  scoped_ptr<RenderPass> render_pass = RenderPass::Create();
 
   gfx::Size tile_size(400, 400);
   gfx::Size layer_bounds(1300, 1900);
@@ -1236,7 +1408,6 @@ TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) {
 
   SetupTrees(pending_pile, active_pile);
 
-  active_layer_->SetContentBounds(layer_bounds);
   active_layer_->draw_properties().visible_content_rect =
       gfx::Rect(layer_bounds);
 
@@ -1246,11 +1417,11 @@ TEST_F(PictureLayerImplTest, DisallowTileDrawQuads) {
 
   AppendQuadsData data;
   active_layer_->WillDraw(DRAW_MODE_RESOURCELESS_SOFTWARE, NULL);
-  active_layer_->AppendQuads(&quad_culler, &data);
+  active_layer_->AppendQuads(render_pass.get(), occlusion_tracker, &data);
   active_layer_->DidDraw(NULL);
 
-  ASSERT_EQ(1U, quad_culler.quad_list().size());
-  EXPECT_EQ(DrawQuad::PICTURE_CONTENT, quad_culler.quad_list()[0]->material);
+  ASSERT_EQ(1U, render_pass->quad_list.size());
+  EXPECT_EQ(DrawQuad::PICTURE_CONTENT, render_pass->quad_list[0]->material);
 }
 
 TEST_F(PictureLayerImplTest, MarkRequiredNullTiles) {
@@ -1337,6 +1508,97 @@ TEST_F(PictureLayerImplTest, MarkRequiredOffscreenTiles) {
   EXPECT_GT(num_offscreen, 0);
 }
 
+TEST_F(PictureLayerImplTest, TileOutsideOfViewportForTilePriorityNotRequired) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(400, 400);
+  gfx::Rect external_viewport_for_tile_priority(400, 200);
+  gfx::Rect visible_content_rect(200, 400);
+
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupTrees(pending_pile, active_pile);
+
+  active_layer_->set_fixed_tile_size(tile_size);
+  pending_layer_->set_fixed_tile_size(tile_size);
+  ASSERT_TRUE(pending_layer_->CanHaveTilings());
+  PictureLayerTiling* tiling = pending_layer_->AddTiling(1.f);
+
+  // Set external viewport for tile priority.
+  gfx::Rect viewport = gfx::Rect(layer_bounds);
+  gfx::Transform transform;
+  gfx::Transform transform_for_tile_priority;
+  bool resourceless_software_draw = false;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        external_viewport_for_tile_priority,
+                                        transform_for_tile_priority,
+                                        resourceless_software_draw);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  // Set visible content rect that is different from
+  // external_viewport_for_tile_priority.
+  pending_layer_->draw_properties().visible_content_rect = visible_content_rect;
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  pending_layer_->UpdateTiles(NULL);
+
+  pending_layer_->MarkVisibleResourcesAsRequired();
+
+  // Intersect the two rects. Any tile outside should not be required for
+  // activation.
+  gfx::Rect viewport_for_tile_priority =
+      pending_layer_->GetViewportForTilePriorityInContentSpace();
+  viewport_for_tile_priority.Intersect(pending_layer_->visible_content_rect());
+
+  int num_inside = 0;
+  int num_outside = 0;
+  for (PictureLayerTiling::CoverageIterator iter(
+           tiling, pending_layer_->contents_scale_x(), gfx::Rect(layer_bounds));
+       iter;
+       ++iter) {
+    if (!*iter)
+      continue;
+    Tile* tile = *iter;
+    if (viewport_for_tile_priority.Intersects(iter.geometry_rect())) {
+      num_inside++;
+      // Mark everything in viewport for tile priority as ready to draw.
+      ManagedTileState::TileVersion& tile_version =
+          tile->GetTileVersionForTesting(
+              tile->DetermineRasterModeForTree(PENDING_TREE));
+      tile_version.SetSolidColorForTesting(SK_ColorRED);
+    } else {
+      num_outside++;
+      EXPECT_FALSE(tile->required_for_activation());
+    }
+  }
+
+  EXPECT_GT(num_inside, 0);
+  EXPECT_GT(num_outside, 0);
+
+  // Activate and draw active layer.
+  host_impl_.ActivateSyncTree();
+  host_impl_.active_tree()->UpdateDrawProperties();
+  active_layer_->draw_properties().visible_content_rect = visible_content_rect;
+
+  MockOcclusionTracker<LayerImpl> occlusion_tracker;
+  scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+  AppendQuadsData data;
+  active_layer_->WillDraw(DRAW_MODE_SOFTWARE, NULL);
+  active_layer_->AppendQuads(render_pass.get(), occlusion_tracker, &data);
+  active_layer_->DidDraw(NULL);
+
+  // All tiles in activation rect is ready to draw.
+  EXPECT_EQ(0u, data.num_missing_tiles);
+  EXPECT_EQ(0u, data.num_incomplete_tiles);
+}
+
 TEST_F(PictureLayerImplTest, HighResRequiredWhenUnsharedActiveAllReady) {
   gfx::Size layer_bounds(400, 400);
   gfx::Size tile_size(100, 100);
@@ -1450,6 +1712,25 @@ TEST_F(PictureLayerImplTest, HighResRequiredIfActiveCantHaveTiles) {
   AssertNoTilesRequired(pending_layer_->LowResTiling());
 }
 
+TEST_F(PictureLayerImplTest, HighResRequiredWhenActiveHasDifferentBounds) {
+  gfx::Size layer_bounds(200, 200);
+  gfx::Size tile_size(100, 100);
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+  gfx::Size pending_layer_bounds(400, 400);
+  pending_layer_->SetBounds(pending_layer_bounds);
+
+  CreateHighLowResAndSetAllTilesVisible();
+
+  active_layer_->SetAllTilesReady();
+
+  // Since the active layer has different bounds, the pending layer needs all
+  // high res tiles in order to activate.
+  pending_layer_->MarkVisibleResourcesAsRequired();
+  AssertAllTilesRequired(pending_layer_->HighResTiling());
+  AssertNoTilesRequired(pending_layer_->LowResTiling());
+}
+
 TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
   gfx::Size tile_size(100, 100);
   gfx::Size layer_bounds(400, 400);
@@ -1471,20 +1752,147 @@ TEST_F(PictureLayerImplTest, ActivateUninitializedLayer) {
   // by a sync from the active layer.  This could happen because if the
   // pending layer has not been post-commit initialized it will attempt
   // to sync from the active layer.
-  bool default_lcd_text_setting = pending_layer_->is_using_lcd_text();
-  pending_layer_->force_set_lcd_text(!default_lcd_text_setting);
+  float raster_page_scale = 10.f * pending_layer_->raster_page_scale();
+  pending_layer_->set_raster_page_scale(raster_page_scale);
   EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
 
-  host_impl_.ActivatePendingTree();
+  host_impl_.ActivateSyncTree();
 
   active_layer_ = static_cast<FakePictureLayerImpl*>(
       host_impl_.active_tree()->LayerById(id_));
 
   EXPECT_EQ(0u, active_layer_->num_tilings());
-  EXPECT_EQ(!default_lcd_text_setting, active_layer_->is_using_lcd_text());
+  EXPECT_EQ(raster_page_scale, active_layer_->raster_page_scale());
   EXPECT_FALSE(active_layer_->needs_post_commit_initialization());
 }
 
+TEST_F(PictureLayerImplTest, ShareTilesOnSync) {
+  SetupDefaultTrees(gfx::Size(1500, 1500));
+  AddDefaultTilingsWithInvalidation(gfx::Rect());
+
+  host_impl_.ActivateSyncTree();
+  host_impl_.CreatePendingTree();
+  active_layer_ = static_cast<FakePictureLayerImpl*>(
+      host_impl_.active_tree()->LayerById(id_));
+
+  // Force the active tree to sync to the pending tree "post-commit".
+  pending_layer_->DoPostCommitInitializationIfNeeded();
+
+  // Both invalidations should drop tiles from the pending tree.
+  EXPECT_EQ(3u, active_layer_->num_tilings());
+  EXPECT_EQ(3u, pending_layer_->num_tilings());
+  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
+    PictureLayerTiling* pending_tiling =
+        pending_layer_->tilings()->tiling_at(i);
+
+    ASSERT_TRUE(active_tiling);
+    ASSERT_TRUE(pending_tiling);
+
+    EXPECT_TRUE(active_tiling->TileAt(0, 0));
+    EXPECT_TRUE(active_tiling->TileAt(1, 0));
+    EXPECT_TRUE(active_tiling->TileAt(0, 1));
+    EXPECT_TRUE(active_tiling->TileAt(1, 1));
+
+    EXPECT_TRUE(pending_tiling->TileAt(0, 0));
+    EXPECT_TRUE(pending_tiling->TileAt(1, 0));
+    EXPECT_TRUE(pending_tiling->TileAt(0, 1));
+    EXPECT_TRUE(pending_tiling->TileAt(1, 1));
+
+    EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
+    EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
+    EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+    EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
+  }
+}
+
+TEST_F(PictureLayerImplTest, ShareInvalidActiveTreeTilesOnSync) {
+  SetupDefaultTrees(gfx::Size(1500, 1500));
+  AddDefaultTilingsWithInvalidation(gfx::Rect(0, 0, 1, 1));
+
+  // This activates the 0,0,1,1 invalidation.
+  host_impl_.ActivateSyncTree();
+  host_impl_.CreatePendingTree();
+  active_layer_ = static_cast<FakePictureLayerImpl*>(
+      host_impl_.active_tree()->LayerById(id_));
+
+  // Force the active tree to sync to the pending tree "post-commit".
+  pending_layer_->DoPostCommitInitializationIfNeeded();
+
+  // The active tree invalidation was handled by the active tiles, so they
+  // can be shared with the pending tree.
+  EXPECT_EQ(3u, active_layer_->num_tilings());
+  EXPECT_EQ(3u, pending_layer_->num_tilings());
+  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
+    PictureLayerTiling* pending_tiling =
+        pending_layer_->tilings()->tiling_at(i);
+
+    ASSERT_TRUE(active_tiling);
+    ASSERT_TRUE(pending_tiling);
+
+    EXPECT_TRUE(active_tiling->TileAt(0, 0));
+    EXPECT_TRUE(active_tiling->TileAt(1, 0));
+    EXPECT_TRUE(active_tiling->TileAt(0, 1));
+    EXPECT_TRUE(active_tiling->TileAt(1, 1));
+
+    EXPECT_TRUE(pending_tiling->TileAt(0, 0));
+    EXPECT_TRUE(pending_tiling->TileAt(1, 0));
+    EXPECT_TRUE(pending_tiling->TileAt(0, 1));
+    EXPECT_TRUE(pending_tiling->TileAt(1, 1));
+
+    EXPECT_EQ(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
+    EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
+    EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+    EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
+  }
+}
+
+TEST_F(PictureLayerImplTest, RemoveInvalidPendingTreeTilesOnSync) {
+  SetupDefaultTrees(gfx::Size(1500, 1500));
+  AddDefaultTilingsWithInvalidation(gfx::Rect());
+
+  host_impl_.ActivateSyncTree();
+  host_impl_.CreatePendingTree();
+  active_layer_ = static_cast<FakePictureLayerImpl*>(
+      host_impl_.active_tree()->LayerById(id_));
+
+  // Set some invalidation on the pending tree "during commit". We should
+  // replace raster tiles that touch this.
+  pending_layer_->set_invalidation(gfx::Rect(1, 1));
+
+  // Force the active tree to sync to the pending tree "post-commit".
+  pending_layer_->DoPostCommitInitializationIfNeeded();
+
+  // The pending tree invalidation means tiles can not be shared with the
+  // active tree.
+  EXPECT_EQ(3u, active_layer_->num_tilings());
+  EXPECT_EQ(3u, pending_layer_->num_tilings());
+  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* active_tiling = active_layer_->tilings()->tiling_at(i);
+    PictureLayerTiling* pending_tiling =
+        pending_layer_->tilings()->tiling_at(i);
+
+    ASSERT_TRUE(active_tiling);
+    ASSERT_TRUE(pending_tiling);
+
+    EXPECT_TRUE(active_tiling->TileAt(0, 0));
+    EXPECT_TRUE(active_tiling->TileAt(1, 0));
+    EXPECT_TRUE(active_tiling->TileAt(0, 1));
+    EXPECT_TRUE(active_tiling->TileAt(1, 1));
+
+    EXPECT_TRUE(pending_tiling->TileAt(0, 0));
+    EXPECT_TRUE(pending_tiling->TileAt(1, 0));
+    EXPECT_TRUE(pending_tiling->TileAt(0, 1));
+    EXPECT_TRUE(pending_tiling->TileAt(1, 1));
+
+    EXPECT_NE(active_tiling->TileAt(0, 0), pending_tiling->TileAt(0, 0));
+    EXPECT_EQ(active_tiling->TileAt(1, 0), pending_tiling->TileAt(1, 0));
+    EXPECT_EQ(active_tiling->TileAt(0, 1), pending_tiling->TileAt(0, 1));
+    EXPECT_EQ(active_tiling->TileAt(1, 1), pending_tiling->TileAt(1, 1));
+  }
+}
+
 TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) {
   SetupDefaultTrees(gfx::Size(10, 10));
   host_impl_.active_tree()->UpdateDrawProperties();
@@ -1493,33 +1901,124 @@ TEST_F(PictureLayerImplTest, SyncTilingAfterReleaseResource) {
   // Contrived unit test of a real crash. A layer is transparent during a
   // context loss, and later becomes opaque, causing active layer SyncTiling to
   // be called.
-  const float tile_scale = 2.f;
+  float new_scale = 1.f;
   active_layer_->ReleaseResources();
-  EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(tile_scale));
-  pending_layer_->AddTiling(2.f);
-  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(tile_scale));
+  pending_layer_->ReleaseResources();
+  EXPECT_FALSE(active_layer_->tilings()->TilingAtScale(new_scale));
+  pending_layer_->AddTiling(new_scale);
+  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(new_scale));
+
+  // UpdateDrawProperties early-outs if the tree doesn't need it.  It is also
+  // responsible for calling ManageTilings.  These checks verify that
+  // ReleaseResources has set needs update draw properties so that the
+  // new tiling gets the appropriate resolution set in ManageTilings.
+  EXPECT_TRUE(host_impl_.active_tree()->needs_update_draw_properties());
+  host_impl_.active_tree()->UpdateDrawProperties();
+  PictureLayerTiling* high_res =
+      active_layer_->tilings()->TilingAtScale(new_scale);
+  ASSERT_TRUE(!!high_res);
+  EXPECT_EQ(HIGH_RESOLUTION, high_res->resolution());
+}
+
+TEST_F(PictureLayerImplTest, SyncTilingAfterGpuRasterizationToggles) {
+  SetupDefaultTrees(gfx::Size(10, 10));
+
+  const float kScale = 1.f;
+  pending_layer_->AddTiling(kScale);
+  EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
+  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+
+  // Gpu rasterization is disabled by default.
+  EXPECT_FALSE(host_impl_.use_gpu_rasterization());
+  // Toggling the gpu rasterization clears all tilings on both trees.
+  host_impl_.SetUseGpuRasterization(true);
+  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+  EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+
+  // Make sure that we can still add tiling to the pending layer,
+  // that gets synced to the active layer.
+  pending_layer_->AddTiling(kScale);
+  EXPECT_TRUE(pending_layer_->tilings()->TilingAtScale(kScale));
+  EXPECT_TRUE(active_layer_->tilings()->TilingAtScale(kScale));
+
+  // Toggling the gpu rasterization clears all tilings on both trees.
+  EXPECT_TRUE(host_impl_.use_gpu_rasterization());
+  host_impl_.SetUseGpuRasterization(false);
+  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+  EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+}
+
+TEST_F(PictureLayerImplTest, HighResCreatedWhenBoundsShrink) {
+  SetupDefaultTrees(gfx::Size(10, 10));
+  host_impl_.active_tree()->UpdateDrawProperties();
+  EXPECT_FALSE(host_impl_.active_tree()->needs_update_draw_properties());
+
+  SetupDrawPropertiesAndUpdateTiles(
+      active_layer_, 0.5f, 0.5f, 0.5f, 0.5f, false);
+  active_layer_->tilings()->RemoveAllTilings();
+  PictureLayerTiling* tiling = active_layer_->tilings()->AddTiling(0.5f);
+  active_layer_->tilings()->AddTiling(1.5f);
+  active_layer_->tilings()->AddTiling(0.25f);
+  tiling->set_resolution(HIGH_RESOLUTION);
+
+  // Sanity checks.
+  ASSERT_EQ(3u, active_layer_->tilings()->num_tilings());
+  ASSERT_EQ(tiling, active_layer_->tilings()->TilingAtScale(0.5f));
+
+  // Now, set the bounds to be 1x1 (so that minimum contents scale becomes
+  // 1.0f). Note that we should also ensure that the pending layer needs post
+  // commit initialization, since this is what would happen during commit. In
+  // other words we want the pending layer to sync from the active layer.
+  pending_layer_->SetBounds(gfx::Size(1, 1));
+  pending_layer_->SetNeedsPostCommitInitialization();
+  pending_layer_->set_twin_layer(NULL);
+  active_layer_->set_twin_layer(NULL);
+  EXPECT_TRUE(pending_layer_->needs_post_commit_initialization());
+
+  // Update the draw properties: sync from active tree should happen here.
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  // Another sanity check.
+  ASSERT_EQ(1.f, pending_layer_->MinimumContentsScale());
+
+  // Now we should've synced 1.5f tiling, since that's the only one that doesn't
+  // violate minimum contents scale. At the same time, we should've created a
+  // new high res tiling at scale 1.0f.
+  EXPECT_EQ(2u, pending_layer_->tilings()->num_tilings());
+  ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.0f));
+  EXPECT_EQ(HIGH_RESOLUTION,
+            pending_layer_->tilings()->TilingAtScale(1.0f)->resolution());
+  ASSERT_TRUE(pending_layer_->tilings()->TilingAtScale(1.5f));
+  EXPECT_EQ(NON_IDEAL_RESOLUTION,
+            pending_layer_->tilings()->TilingAtScale(1.5f)->resolution());
 }
 
-TEST_F(PictureLayerImplTest, TilingWithoutGpuRasterization) {
+TEST_F(PictureLayerImplTest, NoLowResTilingWithGpuRasterization) {
   gfx::Size default_tile_size(host_impl_.settings().default_tile_size);
   gfx::Size layer_bounds(default_tile_size.width() * 4,
                          default_tile_size.height() * 4);
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
 
   SetupDefaultTrees(layer_bounds);
-  EXPECT_FALSE(pending_layer_->ShouldUseGpuRasterization());
+  EXPECT_FALSE(host_impl_.use_gpu_rasterization());
   EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
   // Should have a low-res and a high-res tiling.
   ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+
+  ResetTilingsAndRasterScales();
+
+  host_impl_.SetUseGpuRasterization(true);
+  EXPECT_TRUE(host_impl_.use_gpu_rasterization());
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 1.f, 1.f, 1.f, 1.f, false);
+
+  // Should only have the high-res tiling.
+  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
 }
 
 TEST_F(PictureLayerImplTest, NoTilingIfDoesNotDrawContent) {
   // Set up layers with tilings.
   SetupDefaultTrees(gfx::Size(10, 10));
-  SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, false);
+  SetContentsScaleOnBothLayers(1.f, 1.f, 1.f, 1.f, false);
   pending_layer_->PushPropertiesTo(active_layer_);
   EXPECT_TRUE(pending_layer_->DrawsContent());
   EXPECT_TRUE(pending_layer_->CanHaveTilings());
@@ -1540,7 +2039,7 @@ TEST_F(PictureLayerImplTest, FirstTilingDuringPinch) {
   SetupDefaultTrees(gfx::Size(10, 10));
   host_impl_.PinchGestureBegin();
   float high_res_scale = 2.3f;
-  SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, false);
+  SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
 
   ASSERT_GE(pending_layer_->num_tilings(), 0u);
   EXPECT_FLOAT_EQ(high_res_scale,
@@ -1553,7 +2052,7 @@ TEST_F(PictureLayerImplTest, FirstTilingTooSmall) {
   float high_res_scale = 0.0001f;
   EXPECT_GT(pending_layer_->MinimumContentsScale(), high_res_scale);
 
-  SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, false);
+  SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, 1.f, false);
 
   ASSERT_GE(pending_layer_->num_tilings(), 0u);
   EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
@@ -1564,7 +2063,7 @@ TEST_F(PictureLayerImplTest, PinchingTooSmall) {
   SetupDefaultTrees(gfx::Size(10, 10));
 
   float contents_scale = 0.15f;
-  SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, false);
+  SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, 1.f, false);
 
   ASSERT_GE(pending_layer_->num_tilings(), 0u);
   EXPECT_FLOAT_EQ(contents_scale,
@@ -1576,8 +2075,7 @@ TEST_F(PictureLayerImplTest, PinchingTooSmall) {
   EXPECT_LT(page_scale * contents_scale,
             pending_layer_->MinimumContentsScale());
 
-
-  SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, false);
+  SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, 1.f, false);
   ASSERT_GE(pending_layer_->num_tilings(), 0u);
   EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
                   pending_layer_->HighResTiling()->contents_scale());
@@ -1586,9 +2084,11 @@ TEST_F(PictureLayerImplTest, PinchingTooSmall) {
 class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
  public:
   virtual void InitializeRenderer() OVERRIDE {
-    host_impl_.InitializeRenderer(FakeOutputSurface::CreateDeferredGL(
-        scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice))
-                                      .PassAs<OutputSurface>());
+    bool delegated_rendering = false;
+    host_impl_.InitializeRenderer(
+        FakeOutputSurface::CreateDeferredGL(
+            scoped_ptr<SoftwareOutputDevice>(new SoftwareOutputDevice),
+            delegated_rendering).PassAs<OutputSurface>());
   }
 
   virtual void SetUp() OVERRIDE {
@@ -1611,8 +2111,7 @@ class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
 // that trees need update draw properties after deferred initialization.
 // However, this is also a regression test for PictureLayerImpl in that
 // not having this update will cause a crash.
-TEST_F(DeferredInitPictureLayerImplTest,
-       PreventUpdateTilePrioritiesDuringLostContext) {
+TEST_F(DeferredInitPictureLayerImplTest, PreventUpdateTilesDuringLostContext) {
   host_impl_.pending_tree()->UpdateDrawProperties();
   host_impl_.active_tree()->UpdateDrawProperties();
   EXPECT_FALSE(host_impl_.pending_tree()->needs_update_draw_properties());
@@ -1621,7 +2120,7 @@ TEST_F(DeferredInitPictureLayerImplTest,
   FakeOutputSurface* fake_output_surface =
       static_cast<FakeOutputSurface*>(host_impl_.output_surface());
   ASSERT_TRUE(fake_output_surface->InitializeAndSetContext3d(
-      TestContextProvider::Create(), NULL));
+      TestContextProvider::Create()));
 
   // These will crash PictureLayerImpl if this is not true.
   ASSERT_TRUE(host_impl_.pending_tree()->needs_update_draw_properties());
@@ -1629,66 +2128,146 @@ TEST_F(DeferredInitPictureLayerImplTest,
   host_impl_.active_tree()->UpdateDrawProperties();
 }
 
-class HybridRasterizationPictureLayerImplTest : public PictureLayerImplTest {
- public:
-  HybridRasterizationPictureLayerImplTest()
-      : PictureLayerImplTest(HybridRasterizationSettings()) {}
-};
+TEST_F(PictureLayerImplTest, HighResTilingDuringAnimationForCpuRasterization) {
+  gfx::Size layer_bounds(100, 100);
+  gfx::Size viewport_size(1000, 1000);
+  SetupDefaultTrees(layer_bounds);
+  host_impl_.SetViewportSize(viewport_size);
 
-TEST_F(HybridRasterizationPictureLayerImplTest, Tiling) {
-  gfx::Size default_tile_size(host_impl_.settings().default_tile_size);
-  gfx::Size layer_bounds(default_tile_size.width() * 4,
-                         default_tile_size.height() * 4);
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
+  float contents_scale = 1.f;
+  float device_scale = 1.3f;
+  float page_scale = 1.4f;
+  float maximum_animation_scale = 1.f;
+  bool animating_transform = false;
 
-  SetupDefaultTrees(layer_bounds);
-  EXPECT_FALSE(pending_layer_->ShouldUseGpuRasterization());
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
-  // Should have a low-res and a high-res tiling.
-  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
 
-  pending_layer_->SetHasGpuRasterizationHint(true);
-  EXPECT_TRUE(pending_layer_->ShouldUseGpuRasterization());
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
-  // Should only have the high-res tiling.
-  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
-}
+  // Since we're CPU-rasterizing, starting an animation should cause tiling
+  // resolution to get set to the maximum animation scale factor.
+  animating_transform = true;
+  maximum_animation_scale = 3.f;
+  contents_scale = 2.f;
 
-class GpuRasterizationPictureLayerImplTest : public PictureLayerImplTest {
- public:
-  GpuRasterizationPictureLayerImplTest()
-      : PictureLayerImplTest(GpuRasterizationSettings()) {}
-};
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
+
+  // Further changes to scale during the animation should not cause a new
+  // high-res tiling to get created.
+  contents_scale = 4.f;
+  maximum_animation_scale = 5.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 3.f);
+
+  // Once we stop animating, a new high-res tiling should be created.
+  animating_transform = false;
 
-TEST_F(GpuRasterizationPictureLayerImplTest, Tiling) {
-  gfx::Size default_tile_size(host_impl_.settings().default_tile_size);
-  gfx::Size layer_bounds(default_tile_size.width() * 4,
-                         default_tile_size.height() * 4);
-  float result_scale_x, result_scale_y;
-  gfx::Size result_bounds;
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
 
-  SetupDefaultTrees(layer_bounds);
-  pending_layer_->SetHasGpuRasterizationHint(true);
-  EXPECT_TRUE(pending_layer_->ShouldUseGpuRasterization());
-  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
-  // Should only have the high-res tiling.
-  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
+  // When animating with an unknown maximum animation scale factor, a new
+  // high-res tiling should be created at the animation's initial scale.
+  animating_transform = true;
+  contents_scale = 2.f;
+  maximum_animation_scale = 0.f;
 
-  pending_layer_->SetHasGpuRasterizationHint(false);
-  EXPECT_TRUE(pending_layer_->ShouldUseGpuRasterization());
-  // Should still have the high-res tiling.
-  EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
-  pending_layer_->CalculateContentsScale(
-      1.f, 1.f, 1.f, false, &result_scale_x, &result_scale_y, &result_bounds);
-  // Should still only have the high-res tiling.
-  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+  // Further changes to scale during the animation should not cause a new
+  // high-res tiling to get created.
+  contents_scale = 3.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+  // Once we stop animating, a new high-res tiling should be created.
+  animating_transform = false;
+  contents_scale = 4.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 4.f);
+
+  // When animating with a maxmium animation scale factor that is so large
+  // that the layer grows larger than the viewport at this scale, a new
+  // high-res tiling should get created at the animation's initial scale, not
+  // at its maximum scale.
+  animating_transform = true;
+  contents_scale = 2.f;
+  maximum_animation_scale = 11.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+  // Once we stop animating, a new high-res tiling should be created.
+  animating_transform = false;
+  contents_scale = 11.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f);
+
+  // When animating with a maxmium animation scale factor that is so large
+  // that the layer grows larger than the viewport at this scale, and where
+  // the intial source scale is < 1, a new high-res tiling should get created
+  // at source scale 1.
+  animating_transform = true;
+  contents_scale = 0.1f;
+  maximum_animation_scale = 11.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), device_scale * page_scale);
+
+  // Once we stop animating, a new high-res tiling should be created.
+  animating_transform = false;
+  contents_scale = 11.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 11.f);
 }
 
 TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
@@ -1704,6 +2283,14 @@ TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
 
   float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
 
+  // Empty iterator
+  PictureLayerImpl::LayerRasterTileIterator it;
+  EXPECT_FALSE(it);
+
+  // No tilings.
+  it = PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
+  EXPECT_FALSE(it);
+
   pending_layer_->AddTiling(low_res_factor);
   pending_layer_->AddTiling(0.3f);
   pending_layer_->AddTiling(0.7f);
@@ -1713,9 +2300,6 @@ TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
   host_impl_.SetViewportSize(gfx::Size(500, 500));
   host_impl_.pending_tree()->UpdateDrawProperties();
 
-  PictureLayerImpl::LayerRasterTileIterator it;
-  EXPECT_FALSE(it);
-
   std::set<Tile*> unique_tiles;
   bool reached_prepaint = false;
   size_t non_ideal_tile_count = 0u;
@@ -1784,5 +2368,1581 @@ TEST_F(PictureLayerImplTest, LayerRasterTileIterator) {
   EXPECT_EQ(0u, high_res_tile_count);
 }
 
+TEST_F(PictureLayerImplTest, LayerEvictionTileIterator) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(1000, 1000);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupPendingTree(pending_pile);
+
+  ASSERT_TRUE(pending_layer_->CanHaveTilings());
+
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
+  std::vector<PictureLayerTiling*> tilings;
+  tilings.push_back(pending_layer_->AddTiling(low_res_factor));
+  tilings.push_back(pending_layer_->AddTiling(0.3f));
+  tilings.push_back(pending_layer_->AddTiling(0.7f));
+  tilings.push_back(pending_layer_->AddTiling(1.0f));
+  tilings.push_back(pending_layer_->AddTiling(2.0f));
+
+  host_impl_.SetViewportSize(gfx::Size(500, 500));
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  std::vector<Tile*> all_tiles;
+  for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
+           tilings.begin();
+       tiling_iterator != tilings.end();
+       ++tiling_iterator) {
+    std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
+    std::copy(tiles.begin(), tiles.end(), std::back_inserter(all_tiles));
+  }
+
+  std::set<Tile*> all_tiles_set(all_tiles.begin(), all_tiles.end());
+
+  bool mark_required = false;
+  size_t number_of_marked_tiles = 0u;
+  size_t number_of_unmarked_tiles = 0u;
+  for (size_t i = 0; i < tilings.size(); ++i) {
+    PictureLayerTiling* tiling = tilings.at(i);
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             pending_layer_->contents_scale_x(),
+             pending_layer_->visible_content_rect());
+         iter;
+         ++iter) {
+      if (mark_required) {
+        number_of_marked_tiles++;
+        iter->MarkRequiredForActivation();
+      } else {
+        number_of_unmarked_tiles++;
+      }
+      mark_required = !mark_required;
+    }
+  }
+
+  // Sanity checks.
+  EXPECT_EQ(91u, all_tiles.size());
+  EXPECT_EQ(91u, all_tiles_set.size());
+  EXPECT_GT(number_of_marked_tiles, 1u);
+  EXPECT_GT(number_of_unmarked_tiles, 1u);
+
+  // Empty iterator.
+  PictureLayerImpl::LayerEvictionTileIterator it;
+  EXPECT_FALSE(it);
+
+  // Tiles don't have resources yet.
+  it = PictureLayerImpl::LayerEvictionTileIterator(
+      pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
+  EXPECT_FALSE(it);
+
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
+
+  std::set<Tile*> unique_tiles;
+  float expected_scales[] = {2.0f, 0.3f, 0.7f, low_res_factor, 1.0f};
+  size_t scale_index = 0;
+  bool reached_visible = false;
+  Tile* last_tile = NULL;
+  for (it = PictureLayerImpl::LayerEvictionTileIterator(
+           pending_layer_, SAME_PRIORITY_FOR_BOTH_TREES);
+       it;
+       ++it) {
+    Tile* tile = *it;
+    if (!last_tile)
+      last_tile = tile;
+
+    EXPECT_TRUE(tile);
+
+    TilePriority priority = tile->priority(PENDING_TREE);
+
+    if (priority.priority_bin == TilePriority::NOW) {
+      reached_visible = true;
+      last_tile = tile;
+      break;
+    }
+
+    EXPECT_FALSE(tile->required_for_activation());
+
+    while (std::abs(tile->contents_scale() - expected_scales[scale_index]) >
+           std::numeric_limits<float>::epsilon()) {
+      ++scale_index;
+      ASSERT_LT(scale_index, arraysize(expected_scales));
+    }
+
+    EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
+    unique_tiles.insert(tile);
+
+    // If the tile is the same rough bin as last tile (same activation, bin, and
+    // scale), then distance should be decreasing.
+    if (tile->required_for_activation() ==
+            last_tile->required_for_activation() &&
+        priority.priority_bin ==
+            last_tile->priority(PENDING_TREE).priority_bin &&
+        std::abs(tile->contents_scale() - last_tile->contents_scale()) <
+            std::numeric_limits<float>::epsilon()) {
+      EXPECT_LE(priority.distance_to_visible,
+                last_tile->priority(PENDING_TREE).distance_to_visible);
+    }
+
+    last_tile = tile;
+  }
+
+  EXPECT_TRUE(reached_visible);
+  EXPECT_EQ(65u, unique_tiles.size());
+
+  scale_index = 0;
+  bool reached_required = false;
+  for (; it; ++it) {
+    Tile* tile = *it;
+    EXPECT_TRUE(tile);
+
+    TilePriority priority = tile->priority(PENDING_TREE);
+    EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
+
+    if (reached_required) {
+      EXPECT_TRUE(tile->required_for_activation());
+    } else if (tile->required_for_activation()) {
+      reached_required = true;
+      scale_index = 0;
+    }
+
+    while (std::abs(tile->contents_scale() - expected_scales[scale_index]) >
+           std::numeric_limits<float>::epsilon()) {
+      ++scale_index;
+      ASSERT_LT(scale_index, arraysize(expected_scales));
+    }
+
+    EXPECT_FLOAT_EQ(tile->contents_scale(), expected_scales[scale_index]);
+    unique_tiles.insert(tile);
+  }
+
+  EXPECT_TRUE(reached_required);
+  EXPECT_EQ(all_tiles_set.size(), unique_tiles.size());
+}
+
+TEST_F(PictureLayerImplTest, Occlusion) {
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+  gfx::Size viewport_size(1000, 1000);
+
+  LayerTestCommon::LayerImplTest impl;
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(layer_bounds, layer_bounds);
+  SetupPendingTree(pending_pile);
+  pending_layer_->SetBounds(layer_bounds);
+  ActivateTree();
+  active_layer_->set_fixed_tile_size(tile_size);
+
+  host_impl_.SetViewportSize(viewport_size);
+  host_impl_.active_tree()->UpdateDrawProperties();
+
+  std::vector<Tile*> tiles =
+      active_layer_->HighResTiling()->AllTilesForTesting();
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
+
+  {
+    SCOPED_TRACE("No occlusion");
+    gfx::Rect occluded;
+    impl.AppendQuadsWithOcclusion(active_layer_, occluded);
+
+    LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(),
+                                                 gfx::Rect(layer_bounds));
+    EXPECT_EQ(100u, impl.quad_list().size());
+  }
+
+  {
+    SCOPED_TRACE("Full occlusion");
+    gfx::Rect occluded(active_layer_->visible_content_rect());
+    impl.AppendQuadsWithOcclusion(active_layer_, occluded);
+
+    LayerTestCommon::VerifyQuadsExactlyCoverRect(impl.quad_list(), gfx::Rect());
+    EXPECT_EQ(impl.quad_list().size(), 0u);
+  }
+
+  {
+    SCOPED_TRACE("Partial occlusion");
+    gfx::Rect occluded(150, 0, 200, 1000);
+    impl.AppendQuadsWithOcclusion(active_layer_, occluded);
+
+    size_t partially_occluded_count = 0;
+    LayerTestCommon::VerifyQuadsCoverRectWithOcclusion(
+        impl.quad_list(),
+        gfx::Rect(layer_bounds),
+        occluded,
+        &partially_occluded_count);
+    // The layer outputs one quad, which is partially occluded.
+    EXPECT_EQ(100u - 10u, impl.quad_list().size());
+    EXPECT_EQ(10u + 10u, partially_occluded_count);
+  }
+}
+
+TEST_F(PictureLayerImplTest, RasterScaleChangeWithoutAnimation) {
+  gfx::Size tile_size(host_impl_.settings().default_tile_size);
+  SetupDefaultTrees(tile_size);
+
+  float contents_scale = 2.f;
+  float device_scale = 1.f;
+  float page_scale = 1.f;
+  float maximum_animation_scale = 1.f;
+  bool animating_transform = false;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 2.f);
+
+  // Changing the source scale without being in an animation will cause
+  // the layer to reset its source scale to 1.f.
+  contents_scale = 3.f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
+
+  // Further changes to the source scale will no longer be reflected in the
+  // contents scale.
+  contents_scale = 0.5f;
+
+  SetContentsScaleOnBothLayers(contents_scale,
+                               device_scale,
+                               page_scale,
+                               maximum_animation_scale,
+                               animating_transform);
+  EXPECT_BOTH_EQ(HighResTiling()->contents_scale(), 1.f);
+}
+
+TEST_F(PictureLayerImplTest, LowResReadyToDrawNotEnoughToActivate) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(1000, 1000);
+
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+  // Make sure some tiles are not shared.
+  pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
+
+  CreateHighLowResAndSetAllTilesVisible();
+  active_layer_->SetAllTilesReady();
+  pending_layer_->MarkVisibleResourcesAsRequired();
+
+  // All pending layer tiles required are not ready.
+  EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+  // Initialize all low-res tiles.
+  pending_layer_->SetAllTilesReadyInTiling(pending_layer_->LowResTiling());
+
+  // Low-res tiles should not be enough.
+  EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+  // Initialize remaining tiles.
+  pending_layer_->SetAllTilesReady();
+
+  EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+}
+
+TEST_F(PictureLayerImplTest, HighResReadyToDrawNotEnoughToActivate) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(1000, 1000);
+
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+  // Make sure some tiles are not shared.
+  pending_layer_->set_invalidation(gfx::Rect(gfx::Point(50, 50), tile_size));
+
+  CreateHighLowResAndSetAllTilesVisible();
+  active_layer_->SetAllTilesReady();
+  pending_layer_->MarkVisibleResourcesAsRequired();
+
+  // All pending layer tiles required are not ready.
+  EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+  // Initialize all high-res tiles.
+  pending_layer_->SetAllTilesReadyInTiling(pending_layer_->HighResTiling());
+
+  // High-res tiles should not be enough.
+  EXPECT_FALSE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+
+  // Initialize remaining tiles.
+  pending_layer_->SetAllTilesReady();
+
+  EXPECT_TRUE(pending_layer_->AllTilesRequiredForActivationAreReadyToDraw());
+}
+
+class NoLowResTilingsSettings : public ImplSidePaintingSettings {
+ public:
+  NoLowResTilingsSettings() { create_low_res_tiling = false; }
+};
+
+class NoLowResPictureLayerImplTest : public PictureLayerImplTest {
+ public:
+  NoLowResPictureLayerImplTest()
+      : PictureLayerImplTest(NoLowResTilingsSettings()) {}
+};
+
+TEST_F(NoLowResPictureLayerImplTest, ManageTilingsCreatesTilings) {
+  gfx::Size tile_size(400, 400);
+  gfx::Size layer_bounds(1300, 1900);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupTrees(pending_pile, active_pile);
+  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+  EXPECT_LT(low_res_factor, 1.f);
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    6.f,  // ideal contents scale
+                                    3.f,  // device scale
+                                    2.f,  // page scale
+                                    1.f,  // maximum animation scale
+                                    false);
+  ASSERT_EQ(1u, pending_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(6.f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+
+  // If we change the page scale factor, then we should get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    6.6f,  // ideal contents scale
+                                    3.f,   // device scale
+                                    2.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
+  ASSERT_EQ(2u, pending_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(6.6f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+
+  // If we change the device scale factor, then we should get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    7.26f,  // ideal contents scale
+                                    3.3f,   // device scale
+                                    2.2f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
+  ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(7.26f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+
+  // If we change the device scale factor, but end up at the same total scale
+  // factor somehow, then we don't get new tilings.
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    7.26f,  // ideal contents scale
+                                    2.2f,   // device scale
+                                    3.3f,   // page scale
+                                    1.f,    // maximum animation scale
+                                    false);
+  ASSERT_EQ(3u, pending_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(7.26f,
+                  pending_layer_->tilings()->tiling_at(0)->contents_scale());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, MarkRequiredNullTiles) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(1000, 1000);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds);
+  // Layers with entirely empty piles can't get tilings.
+  pending_pile->AddRecordingAt(0, 0);
+
+  SetupPendingTree(pending_pile);
+
+  ASSERT_TRUE(pending_layer_->CanHaveTilings());
+  pending_layer_->AddTiling(1.0f);
+  pending_layer_->AddTiling(2.0f);
+
+  // It should be safe to call this (and MarkVisibleResourcesAsRequired)
+  // on a layer with no recordings.
+  host_impl_.pending_tree()->UpdateDrawProperties();
+  pending_layer_->MarkVisibleResourcesAsRequired();
+}
+
+TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfAllHighResTilesShared) {
+  gfx::Size layer_bounds(400, 400);
+  gfx::Size tile_size(100, 100);
+  SetupDefaultTreesWithFixedTileSize(layer_bounds, tile_size);
+
+  CreateHighLowResAndSetAllTilesVisible();
+
+  Tile* some_active_tile =
+      active_layer_->HighResTiling()->AllTilesForTesting()[0];
+  EXPECT_FALSE(some_active_tile->IsReadyToDraw());
+
+  // All tiles shared (no invalidation), so even though the active tree's
+  // tiles aren't ready, there is nothing required.
+  pending_layer_->MarkVisibleResourcesAsRequired();
+  AssertNoTilesRequired(pending_layer_->HighResTiling());
+  if (host_impl_.settings().create_low_res_tiling) {
+    AssertNoTilesRequired(pending_layer_->LowResTiling());
+  }
+}
+
+TEST_F(NoLowResPictureLayerImplTest, NothingRequiredIfActiveMissingTiles) {
+  gfx::Size layer_bounds(400, 400);
+  gfx::Size tile_size(100, 100);
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  // This pile will create tilings, but has no recordings so will not create any
+  // tiles.  This is attempting to simulate scrolling past the end of recorded
+  // content on the active layer, where the recordings are so far away that
+  // no tiles are created.
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateEmptyPileThatThinksItHasRecordings(
+          tile_size, layer_bounds);
+  SetupTrees(pending_pile, active_pile);
+  pending_layer_->set_fixed_tile_size(tile_size);
+  active_layer_->set_fixed_tile_size(tile_size);
+
+  CreateHighLowResAndSetAllTilesVisible();
+
+  // Active layer has tilings, but no tiles due to missing recordings.
+  EXPECT_TRUE(active_layer_->CanHaveTilings());
+  EXPECT_EQ(active_layer_->tilings()->num_tilings(),
+            host_impl_.settings().create_low_res_tiling ? 2u : 1u);
+  EXPECT_EQ(active_layer_->HighResTiling()->AllTilesForTesting().size(), 0u);
+
+  // Since the active layer has no tiles at all, the pending layer doesn't
+  // need content in order to activate.
+  pending_layer_->MarkVisibleResourcesAsRequired();
+  AssertNoTilesRequired(pending_layer_->HighResTiling());
+  if (host_impl_.settings().create_low_res_tiling)
+    AssertNoTilesRequired(pending_layer_->LowResTiling());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, InvalidViewportForPrioritizingTiles) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(400, 400);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupTrees(pending_pile, active_pile);
+
+  Region invalidation;
+  AddDefaultTilingsWithInvalidation(invalidation);
+  SetupDrawPropertiesAndUpdateTiles(active_layer_, 1.f, 1.f, 1.f, 1.f, false);
+
+  // UpdateTiles with valid viewport. Should update tile viewport.
+  // Note viewport is considered invalid if and only if in resourceless
+  // software draw.
+  bool resourceless_software_draw = false;
+  gfx::Rect viewport = gfx::Rect(layer_bounds);
+  gfx::Transform transform;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        transform,
+                                        resourceless_software_draw);
+  active_layer_->draw_properties().visible_content_rect = viewport;
+  active_layer_->draw_properties().screen_space_transform = transform;
+  active_layer_->UpdateTiles(NULL);
+
+  gfx::Rect visible_rect_for_tile_priority =
+      active_layer_->visible_rect_for_tile_priority();
+  EXPECT_FALSE(visible_rect_for_tile_priority.IsEmpty());
+  gfx::Rect viewport_rect_for_tile_priority =
+      active_layer_->viewport_rect_for_tile_priority();
+  EXPECT_FALSE(viewport_rect_for_tile_priority.IsEmpty());
+  gfx::Transform screen_space_transform_for_tile_priority =
+      active_layer_->screen_space_transform_for_tile_priority();
+
+  // Expand viewport and set it as invalid for prioritizing tiles.
+  // Should not update tile viewport.
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  resourceless_software_draw = true;
+  viewport = gfx::ScaleToEnclosingRect(viewport, 2);
+  transform.Translate(1.f, 1.f);
+  active_layer_->draw_properties().visible_content_rect = viewport;
+  active_layer_->draw_properties().screen_space_transform = transform;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        transform,
+                                        resourceless_software_draw);
+  active_layer_->UpdateTiles(NULL);
+
+  EXPECT_RECT_EQ(visible_rect_for_tile_priority,
+                 active_layer_->visible_rect_for_tile_priority());
+  EXPECT_RECT_EQ(viewport_rect_for_tile_priority,
+                 active_layer_->viewport_rect_for_tile_priority());
+  EXPECT_TRANSFORMATION_MATRIX_EQ(
+      screen_space_transform_for_tile_priority,
+      active_layer_->screen_space_transform_for_tile_priority());
+
+  // Keep expanded viewport but mark it valid. Should update tile viewport.
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  resourceless_software_draw = false;
+  host_impl_.SetExternalDrawConstraints(transform,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        transform,
+                                        resourceless_software_draw);
+  active_layer_->UpdateTiles(NULL);
+
+  EXPECT_FALSE(visible_rect_for_tile_priority ==
+               active_layer_->visible_rect_for_tile_priority());
+  EXPECT_FALSE(viewport_rect_for_tile_priority ==
+               active_layer_->viewport_rect_for_tile_priority());
+  EXPECT_FALSE(screen_space_transform_for_tile_priority ==
+               active_layer_->screen_space_transform_for_tile_priority());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, InvalidViewportAfterReleaseResources) {
+  gfx::Size tile_size(100, 100);
+  gfx::Size layer_bounds(400, 400);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupTrees(pending_pile, active_pile);
+
+  Region invalidation;
+  AddDefaultTilingsWithInvalidation(invalidation);
+
+  bool resourceless_software_draw = true;
+  gfx::Rect viewport = gfx::Rect(layer_bounds);
+  gfx::Transform identity = gfx::Transform();
+  host_impl_.SetExternalDrawConstraints(identity,
+                                        viewport,
+                                        viewport,
+                                        viewport,
+                                        identity,
+                                        resourceless_software_draw);
+  ResetTilingsAndRasterScales();
+  host_impl_.pending_tree()->UpdateDrawProperties();
+  host_impl_.active_tree()->UpdateDrawProperties();
+  EXPECT_TRUE(active_layer_->HighResTiling());
+
+  size_t num_tilings = active_layer_->num_tilings();
+  active_layer_->UpdateTiles(NULL);
+  pending_layer_->AddTiling(0.5f);
+  EXPECT_EQ(num_tilings + 1, active_layer_->num_tilings());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, CleanUpTilings) {
+  gfx::Size tile_size(400, 400);
+  gfx::Size layer_bounds(1300, 1900);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  std::vector<PictureLayerTiling*> used_tilings;
+
+  SetupTrees(pending_pile, active_pile);
+  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+  EXPECT_LT(low_res_factor, 1.f);
+
+  float device_scale = 1.7f;
+  float page_scale = 3.2f;
+  float scale = 1.f;
+
+  SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
+  ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+  // We only have ideal tilings, so they aren't removed.
+  used_tilings.clear();
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+  host_impl_.PinchGestureBegin();
+
+  // Changing the ideal but not creating new tilings.
+  scale *= 1.5f;
+  page_scale *= 1.5f;
+  SetContentsScaleOnBothLayers(scale, device_scale, page_scale, 1.f, false);
+  ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+  // The tilings are still our target scale, so they aren't removed.
+  used_tilings.clear();
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+
+  host_impl_.PinchGestureEnd();
+
+  // Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2.
+  scale /= 4.f;
+  page_scale /= 4.f;
+  SetContentsScaleOnBothLayers(1.2f, device_scale, page_scale, 1.f, false);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+  EXPECT_FLOAT_EQ(1.f,
+                  active_layer_->tilings()->tiling_at(1)->contents_scale());
+
+  // Mark the non-ideal tilings as used. They won't be removed.
+  used_tilings.clear();
+  used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+  // Now move the ideal scale to 0.5. Our target stays 1.2.
+  SetContentsScaleOnBothLayers(0.5f, device_scale, page_scale, 1.f, false);
+
+  // The high resolution tiling is between target and ideal, so is not
+  // removed.  The low res tiling for the old ideal=1.0 scale is removed.
+  used_tilings.clear();
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+  // Now move the ideal scale to 1.0. Our target stays 1.2.
+  SetContentsScaleOnBothLayers(1.f, device_scale, page_scale, 1.f, false);
+
+  // All the tilings are between are target and the ideal, so they are not
+  // removed.
+  used_tilings.clear();
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+  // Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2.
+  SetupDrawPropertiesAndUpdateTiles(
+      active_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+
+  // Because the pending layer's ideal scale is still 1.0, our tilings fall
+  // in the range [1.0,1.2] and are kept.
+  used_tilings.clear();
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+  // Move the ideal scale on the pending layer to 1.1 as well. Our target stays
+  // 1.2 still.
+  SetupDrawPropertiesAndUpdateTiles(
+      pending_layer_, 1.1f, device_scale, page_scale, 1.f, false);
+
+  // Our 1.0 tiling now falls outside the range between our ideal scale and our
+  // target raster scale. But it is in our used tilings set, so nothing is
+  // deleted.
+  used_tilings.clear();
+  used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(2u, active_layer_->tilings()->num_tilings());
+
+  // If we remove it from our used tilings set, it is outside the range to keep
+  // so it is deleted.
+  used_tilings.clear();
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(1u, active_layer_->tilings()->num_tilings());
+}
+
+TEST_F(PictureLayerImplTest, ScaleCollision) {
+  gfx::Size tile_size(400, 400);
+  gfx::Size layer_bounds(1300, 1900);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  std::vector<PictureLayerTiling*> used_tilings;
+
+  SetupTrees(pending_pile, active_pile);
+
+  float pending_contents_scale = 1.f;
+  float active_contents_scale = 2.f;
+  float device_scale_factor = 1.f;
+  float page_scale_factor = 1.f;
+  float maximum_animation_contents_scale = 1.f;
+  bool animating_transform = false;
+
+  EXPECT_TRUE(host_impl_.settings().create_low_res_tiling);
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+  EXPECT_LT(low_res_factor, 1.f);
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    pending_contents_scale,
+                                    device_scale_factor,
+                                    page_scale_factor,
+                                    maximum_animation_contents_scale,
+                                    animating_transform);
+  SetupDrawPropertiesAndUpdateTiles(active_layer_,
+                                    active_contents_scale,
+                                    device_scale_factor,
+                                    page_scale_factor,
+                                    maximum_animation_contents_scale,
+                                    animating_transform);
+
+  ASSERT_EQ(4u, pending_layer_->tilings()->num_tilings());
+  ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
+
+  EXPECT_EQ(active_contents_scale,
+            pending_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_EQ(pending_contents_scale,
+            pending_layer_->tilings()->tiling_at(1)->contents_scale());
+  EXPECT_EQ(active_contents_scale * low_res_factor,
+            pending_layer_->tilings()->tiling_at(2)->contents_scale());
+  EXPECT_EQ(pending_contents_scale * low_res_factor,
+            pending_layer_->tilings()->tiling_at(3)->contents_scale());
+
+  EXPECT_EQ(active_contents_scale,
+            active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_EQ(pending_contents_scale,
+            active_layer_->tilings()->tiling_at(1)->contents_scale());
+  EXPECT_EQ(active_contents_scale * low_res_factor,
+            active_layer_->tilings()->tiling_at(2)->contents_scale());
+  EXPECT_EQ(pending_contents_scale * low_res_factor,
+            active_layer_->tilings()->tiling_at(3)->contents_scale());
+
+  // The unused low res tiling from the pending tree must be kept or we may add
+  // it again on the active tree and collide with the pending tree.
+  used_tilings.push_back(active_layer_->tilings()->tiling_at(1));
+  active_layer_->CleanUpTilingsOnActiveLayer(used_tilings);
+  ASSERT_EQ(4u, active_layer_->tilings()->num_tilings());
+
+  EXPECT_EQ(active_contents_scale,
+            active_layer_->tilings()->tiling_at(0)->contents_scale());
+  EXPECT_EQ(pending_contents_scale,
+            active_layer_->tilings()->tiling_at(1)->contents_scale());
+  EXPECT_EQ(active_contents_scale * low_res_factor,
+            active_layer_->tilings()->tiling_at(2)->contents_scale());
+  EXPECT_EQ(pending_contents_scale * low_res_factor,
+            active_layer_->tilings()->tiling_at(3)->contents_scale());
+}
+
+TEST_F(NoLowResPictureLayerImplTest, ReleaseResources) {
+  gfx::Size tile_size(400, 400);
+  gfx::Size layer_bounds(1300, 1900);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupTrees(pending_pile, active_pile);
+  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    1.3f,  // ideal contents scale
+                                    2.7f,  // device scale
+                                    3.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
+  EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+
+  // All tilings should be removed when losing output surface.
+  active_layer_->ReleaseResources();
+  EXPECT_EQ(0u, active_layer_->tilings()->num_tilings());
+  pending_layer_->ReleaseResources();
+  EXPECT_EQ(0u, pending_layer_->tilings()->num_tilings());
+
+  // This should create new tilings.
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_,
+                                    1.3f,  // ideal contents scale
+                                    2.7f,  // device scale
+                                    3.2f,  // page scale
+                                    1.f,   // maximum animation scale
+                                    false);
+  EXPECT_EQ(1u, pending_layer_->tilings()->num_tilings());
+}
+
+TEST_F(PictureLayerImplTest, SharedQuadStateContainsMaxTilingScale) {
+  MockOcclusionTracker<LayerImpl> occlusion_tracker;
+  scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+
+  gfx::Size tile_size(400, 400);
+  gfx::Size layer_bounds(1000, 2000);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+
+  SetupTrees(pending_pile, active_pile);
+
+  SetupDrawPropertiesAndUpdateTiles(pending_layer_, 2.5f, 1.f, 1.f, 1.f, false);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  active_layer_->draw_properties().visible_content_rect =
+      gfx::Rect(layer_bounds);
+  host_impl_.active_tree()->UpdateDrawProperties();
+
+  float max_contents_scale = active_layer_->MaximumTilingContentsScale();
+  gfx::Transform scaled_draw_transform = active_layer_->draw_transform();
+  scaled_draw_transform.Scale(SK_MScalar1 / max_contents_scale,
+                              SK_MScalar1 / max_contents_scale);
+
+  AppendQuadsData data;
+  active_layer_->AppendQuads(render_pass.get(), occlusion_tracker, &data);
+
+  // SharedQuadState should have be of size 1, as we are doing AppenQuad once.
+  EXPECT_EQ(1u, render_pass->shared_quad_state_list.size());
+  // The content_to_target_transform should be scaled by the
+  // MaximumTilingContentsScale on the layer.
+  EXPECT_EQ(scaled_draw_transform.ToString(),
+            render_pass->shared_quad_state_list[0]
+                ->content_to_target_transform.ToString());
+  // The content_bounds should be scaled by the
+  // MaximumTilingContentsScale on the layer.
+  EXPECT_EQ(gfx::Size(2500u, 5000u).ToString(),
+            render_pass->shared_quad_state_list[0]->content_bounds.ToString());
+  // The visible_content_rect should be scaled by the
+  // MaximumTilingContentsScale on the layer.
+  EXPECT_EQ(
+      gfx::Rect(0u, 0u, 2500u, 5000u).ToString(),
+      render_pass->shared_quad_state_list[0]->visible_content_rect.ToString());
+}
+
+TEST_F(PictureLayerImplTest, UpdateTilesForMasksWithNoVisibleContent) {
+  gfx::Size tile_size(400, 400);
+  gfx::Size bounds(100000, 100);
+
+  host_impl_.CreatePendingTree();
+
+  scoped_ptr<LayerImpl> root = LayerImpl::Create(host_impl_.pending_tree(), 1);
+
+  scoped_ptr<FakePictureLayerImpl> layer_with_mask =
+      FakePictureLayerImpl::Create(host_impl_.pending_tree(), 2);
+
+  layer_with_mask->SetBounds(bounds);
+  layer_with_mask->SetContentBounds(bounds);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, bounds);
+  pending_pile->set_is_mask(true);
+  scoped_ptr<FakePictureLayerImpl> mask = FakePictureLayerImpl::CreateWithPile(
+      host_impl_.pending_tree(), 3, pending_pile);
+
+  mask->SetBounds(bounds);
+  mask->SetContentBounds(bounds);
+  mask->SetDrawsContent(true);
+
+  FakePictureLayerImpl* pending_mask_content = mask.get();
+  layer_with_mask->SetMaskLayer(mask.PassAs<LayerImpl>());
+
+  scoped_ptr<FakePictureLayerImpl> child_of_layer_with_mask =
+      FakePictureLayerImpl::Create(host_impl_.pending_tree(), 4);
+
+  child_of_layer_with_mask->SetBounds(bounds);
+  child_of_layer_with_mask->SetContentBounds(bounds);
+  child_of_layer_with_mask->SetDrawsContent(true);
+
+  layer_with_mask->AddChild(child_of_layer_with_mask.PassAs<LayerImpl>());
+
+  root->AddChild(layer_with_mask.PassAs<LayerImpl>());
+
+  host_impl_.pending_tree()->SetRootLayer(root.Pass());
+
+  EXPECT_FALSE(pending_mask_content->tilings());
+  host_impl_.pending_tree()->UpdateDrawProperties();
+  EXPECT_NE(0u, pending_mask_content->num_tilings());
+}
+
+class PictureLayerImplTestWithDelegatingRenderer : public PictureLayerImplTest {
+ public:
+  PictureLayerImplTestWithDelegatingRenderer() : PictureLayerImplTest() {}
+
+  virtual void InitializeRenderer() OVERRIDE {
+    host_impl_.InitializeRenderer(
+        FakeOutputSurface::CreateDelegating3d().PassAs<OutputSurface>());
+  }
+};
+
+TEST_F(PictureLayerImplTestWithDelegatingRenderer,
+       DelegatingRendererWithTileOOM) {
+  // This test is added for crbug.com/402321, where quad should be produced when
+  // raster on demand is not allowed and tile is OOM.
+  gfx::Size tile_size = host_impl_.settings().default_tile_size;
+  gfx::Size layer_bounds(1000, 1000);
+
+  // Create tiles.
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pending_pile);
+  pending_layer_->SetBounds(layer_bounds);
+  host_impl_.SetViewportSize(layer_bounds);
+  ActivateTree();
+  host_impl_.active_tree()->UpdateDrawProperties();
+  std::vector<Tile*> tiles =
+      active_layer_->HighResTiling()->AllTilesForTesting();
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(tiles);
+
+  // Force tiles after max_tiles to be OOM. TileManager uses
+  // GlobalStateThatImpactsTilesPriority from LayerTreeHostImpl, and we cannot
+  // directly set state to host_impl_, so we set policy that would change the
+  // state. We also need to update tree priority separately.
+  GlobalStateThatImpactsTilePriority state;
+  size_t max_tiles = 1;
+  size_t memory_limit = max_tiles * 4 * tile_size.width() * tile_size.height();
+  size_t resource_limit = max_tiles;
+  ManagedMemoryPolicy policy(memory_limit,
+                             gpu::MemoryAllocation::CUTOFF_ALLOW_EVERYTHING,
+                             resource_limit);
+  host_impl_.SetMemoryPolicy(policy);
+  host_impl_.SetTreePriority(SAME_PRIORITY_FOR_BOTH_TREES);
+  host_impl_.ManageTiles();
+
+  MockOcclusionTracker<LayerImpl> occlusion_tracker;
+  scoped_ptr<RenderPass> render_pass = RenderPass::Create();
+  AppendQuadsData data;
+  active_layer_->WillDraw(DRAW_MODE_HARDWARE, NULL);
+  active_layer_->AppendQuads(render_pass.get(), occlusion_tracker, &data);
+  active_layer_->DidDraw(NULL);
+
+  // Even when OOM, quads should be produced, and should be different material
+  // from quads with resource.
+  EXPECT_LT(max_tiles, render_pass->quad_list.size());
+  EXPECT_EQ(DrawQuad::Material::TILED_CONTENT,
+            render_pass->quad_list.front()->material);
+  EXPECT_EQ(DrawQuad::Material::SOLID_COLOR,
+            render_pass->quad_list.back()->material);
+}
+
+class OcclusionTrackingSettings : public ImplSidePaintingSettings {
+ public:
+  OcclusionTrackingSettings() { use_occlusion_for_tile_prioritization = true; }
+};
+
+class OcclusionTrackingPictureLayerImplTest : public PictureLayerImplTest {
+ public:
+  OcclusionTrackingPictureLayerImplTest()
+      : PictureLayerImplTest(OcclusionTrackingSettings()) {}
+
+  void VerifyEvictionConsidersOcclusion(
+      PictureLayerImpl* layer,
+      size_t expected_occluded_tile_count[NUM_TREE_PRIORITIES]) {
+    for (int priority_count = 0; priority_count < NUM_TREE_PRIORITIES;
+         ++priority_count) {
+      TreePriority tree_priority = static_cast<TreePriority>(priority_count);
+      size_t occluded_tile_count = 0u;
+      Tile* last_tile = NULL;
+
+      for (PictureLayerImpl::LayerEvictionTileIterator it =
+               PictureLayerImpl::LayerEvictionTileIterator(layer,
+                                                           tree_priority);
+           it;
+           ++it) {
+        Tile* tile = *it;
+        if (!last_tile)
+          last_tile = tile;
+
+        // The only way we will encounter an occluded tile after an unoccluded
+        // tile is if the priorty bin decreased, the tile is required for
+        // activation, or the scale changed.
+        bool tile_is_occluded =
+            tile->is_occluded_for_tree_priority(tree_priority);
+        if (tile_is_occluded) {
+          occluded_tile_count++;
+
+          bool last_tile_is_occluded =
+              last_tile->is_occluded_for_tree_priority(tree_priority);
+          if (!last_tile_is_occluded) {
+            TilePriority::PriorityBin tile_priority_bin =
+                tile->priority_for_tree_priority(tree_priority).priority_bin;
+            TilePriority::PriorityBin last_tile_priority_bin =
+                last_tile->priority_for_tree_priority(tree_priority)
+                    .priority_bin;
+
+            EXPECT_TRUE(
+                (tile_priority_bin < last_tile_priority_bin) ||
+                tile->required_for_activation() ||
+                (tile->contents_scale() != last_tile->contents_scale()));
+          }
+        }
+        last_tile = tile;
+      }
+      EXPECT_EQ(expected_occluded_tile_count[priority_count],
+                occluded_tile_count);
+    }
+  }
+};
+
+TEST_F(OcclusionTrackingPictureLayerImplTest,
+       OccludedTilesSkippedDuringRasterization) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+  gfx::Size viewport_size(500, 500);
+  gfx::Point occluding_layer_position(310, 0);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pending_pile);
+  pending_layer_->set_fixed_tile_size(tile_size);
+
+  host_impl_.SetViewportSize(viewport_size);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  // No occlusion.
+  int unoccluded_tile_count = 0;
+  for (PictureLayerImpl::LayerRasterTileIterator it =
+           PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
+       it;
+       ++it) {
+    Tile* tile = *it;
+
+    // Occluded tiles should not be iterated over.
+    EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+
+    // Some tiles may not be visible (i.e. outside the viewport). The rest are
+    // visible and at least partially unoccluded, verified by the above expect.
+    bool tile_is_visible =
+        tile->content_rect().Intersects(pending_layer_->visible_content_rect());
+    if (tile_is_visible)
+      unoccluded_tile_count++;
+  }
+  EXPECT_EQ(unoccluded_tile_count, 25 + 4);
+
+  // Partial occlusion.
+  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
+  LayerImpl* layer1 = pending_layer_->children()[0];
+  layer1->SetBounds(layer_bounds);
+  layer1->SetContentBounds(layer_bounds);
+  layer1->SetDrawsContent(true);
+  layer1->SetContentsOpaque(true);
+  layer1->SetPosition(occluding_layer_position);
+
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  unoccluded_tile_count = 0;
+  for (PictureLayerImpl::LayerRasterTileIterator it =
+           PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
+       it;
+       ++it) {
+    Tile* tile = *it;
+
+    EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+
+    bool tile_is_visible =
+        tile->content_rect().Intersects(pending_layer_->visible_content_rect());
+    if (tile_is_visible)
+      unoccluded_tile_count++;
+  }
+  EXPECT_EQ(unoccluded_tile_count, 20 + 2);
+
+  // Full occlusion.
+  layer1->SetPosition(gfx::Point(0, 0));
+
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  unoccluded_tile_count = 0;
+  for (PictureLayerImpl::LayerRasterTileIterator it =
+           PictureLayerImpl::LayerRasterTileIterator(pending_layer_, false);
+       it;
+       ++it) {
+    Tile* tile = *it;
+
+    EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+
+    bool tile_is_visible =
+        tile->content_rect().Intersects(pending_layer_->visible_content_rect());
+    if (tile_is_visible)
+      unoccluded_tile_count++;
+  }
+  EXPECT_EQ(unoccluded_tile_count, 0);
+}
+
+TEST_F(OcclusionTrackingPictureLayerImplTest,
+       OccludedTilesNotMarkedAsRequired) {
+  base::TimeTicks time_ticks;
+  time_ticks += base::TimeDelta::FromMilliseconds(1);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+  gfx::Size viewport_size(500, 500);
+  gfx::Point occluding_layer_position(310, 0);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pending_pile);
+  pending_layer_->set_fixed_tile_size(tile_size);
+
+  host_impl_.SetViewportSize(viewport_size);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  // No occlusion.
+  int occluded_tile_count = 0;
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+
+    occluded_tile_count = 0;
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             pending_layer_->contents_scale_x(),
+             gfx::Rect(layer_bounds));
+         iter;
+         ++iter) {
+      if (!*iter)
+        continue;
+      const Tile* tile = *iter;
+
+      // Fully occluded tiles are not required for activation.
+      if (tile->is_occluded(PENDING_TREE)) {
+        EXPECT_FALSE(tile->required_for_activation());
+        occluded_tile_count++;
+      }
+    }
+    EXPECT_EQ(occluded_tile_count, 0);
+  }
+
+  // Partial occlusion.
+  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
+  LayerImpl* layer1 = pending_layer_->children()[0];
+  layer1->SetBounds(layer_bounds);
+  layer1->SetContentBounds(layer_bounds);
+  layer1->SetDrawsContent(true);
+  layer1->SetContentsOpaque(true);
+  layer1->SetPosition(occluding_layer_position);
+
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+
+    occluded_tile_count = 0;
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             pending_layer_->contents_scale_x(),
+             gfx::Rect(layer_bounds));
+         iter;
+         ++iter) {
+      if (!*iter)
+        continue;
+      const Tile* tile = *iter;
+
+      if (tile->is_occluded(PENDING_TREE)) {
+        EXPECT_FALSE(tile->required_for_activation());
+        occluded_tile_count++;
+      }
+    }
+    switch (i) {
+      case 0:
+        EXPECT_EQ(occluded_tile_count, 5);
+        break;
+      case 1:
+        EXPECT_EQ(occluded_tile_count, 2);
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+
+  // Full occlusion.
+  layer1->SetPosition(gfx::PointF(0, 0));
+
+  time_ticks += base::TimeDelta::FromMilliseconds(200);
+  host_impl_.SetCurrentFrameTimeTicks(time_ticks);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+
+    occluded_tile_count = 0;
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             pending_layer_->contents_scale_x(),
+             gfx::Rect(layer_bounds));
+         iter;
+         ++iter) {
+      if (!*iter)
+        continue;
+      const Tile* tile = *iter;
+
+      if (tile->is_occluded(PENDING_TREE)) {
+        EXPECT_FALSE(tile->required_for_activation());
+        occluded_tile_count++;
+      }
+    }
+    switch (i) {
+      case 0:
+        EXPECT_EQ(occluded_tile_count, 25);
+        break;
+      case 1:
+        EXPECT_EQ(occluded_tile_count, 4);
+        break;
+      default:
+        NOTREACHED();
+    }
+  }
+}
+
+TEST_F(OcclusionTrackingPictureLayerImplTest, OcclusionForDifferentScales) {
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+  gfx::Size viewport_size(500, 500);
+  gfx::Point occluding_layer_position(310, 0);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pending_pile);
+  pending_layer_->set_fixed_tile_size(tile_size);
+
+  ASSERT_TRUE(pending_layer_->CanHaveTilings());
+
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
+  std::vector<PictureLayerTiling*> tilings;
+  tilings.push_back(pending_layer_->AddTiling(low_res_factor));
+  tilings.push_back(pending_layer_->AddTiling(0.3f));
+  tilings.push_back(pending_layer_->AddTiling(0.7f));
+  tilings.push_back(pending_layer_->AddTiling(1.0f));
+  tilings.push_back(pending_layer_->AddTiling(2.0f));
+
+  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
+  LayerImpl* layer1 = pending_layer_->children()[0];
+  layer1->SetBounds(layer_bounds);
+  layer1->SetContentBounds(layer_bounds);
+  layer1->SetDrawsContent(true);
+  layer1->SetContentsOpaque(true);
+  layer1->SetPosition(occluding_layer_position);
+
+  host_impl_.SetViewportSize(viewport_size);
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  int tiling_count = 0;
+  int occluded_tile_count = 0;
+  for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
+           tilings.begin();
+       tiling_iterator != tilings.end();
+       ++tiling_iterator) {
+    std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
+
+    occluded_tile_count = 0;
+    for (size_t i = 0; i < tiles.size(); ++i) {
+      if (tiles[i]->is_occluded(PENDING_TREE)) {
+        gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
+            tiles[i]->content_rect(), 1.0f / tiles[i]->contents_scale());
+        EXPECT_GE(scaled_content_rect.x(), occluding_layer_position.x());
+        occluded_tile_count++;
+      }
+    }
+    switch (tiling_count) {
+      case 0:
+      case 1:
+        EXPECT_EQ(occluded_tile_count, 2);
+        break;
+      case 2:
+        EXPECT_EQ(occluded_tile_count, 4);
+        break;
+      case 3:
+        EXPECT_EQ(occluded_tile_count, 5);
+        break;
+      case 4:
+        EXPECT_EQ(occluded_tile_count, 30);
+        break;
+      default:
+        NOTREACHED();
+    }
+
+    tiling_count++;
+  }
+
+  EXPECT_EQ(tiling_count, 5);
+}
+
+TEST_F(OcclusionTrackingPictureLayerImplTest, DifferentOcclusionOnTrees) {
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+  gfx::Size viewport_size(1000, 1000);
+  gfx::Point occluding_layer_position(310, 0);
+  gfx::Rect invalidation_rect(230, 230, 102, 102);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupTrees(pending_pile, active_pile);
+
+  // Partially occlude the active layer.
+  active_layer_->AddChild(LayerImpl::Create(host_impl_.active_tree(), 2));
+  LayerImpl* layer1 = active_layer_->children()[0];
+  layer1->SetBounds(layer_bounds);
+  layer1->SetContentBounds(layer_bounds);
+  layer1->SetDrawsContent(true);
+  layer1->SetContentsOpaque(true);
+  layer1->SetPosition(occluding_layer_position);
+
+  // Partially invalidate the pending layer.
+  pending_layer_->set_invalidation(invalidation_rect);
+
+  host_impl_.SetViewportSize(viewport_size);
+
+  active_layer_->CreateDefaultTilingsAndTiles();
+  pending_layer_->CreateDefaultTilingsAndTiles();
+
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             pending_layer_->contents_scale_x(),
+             gfx::Rect(layer_bounds));
+         iter;
+         ++iter) {
+      if (!*iter)
+        continue;
+      const Tile* tile = *iter;
+
+      // All tiles are unoccluded on the pending tree.
+      EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+
+      Tile* twin_tile =
+          pending_layer_->GetTwinTiling(tiling)->TileAt(iter.i(), iter.j());
+      gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
+          tile->content_rect(), 1.0f / tile->contents_scale());
+
+      if (scaled_content_rect.Intersects(invalidation_rect)) {
+        // Tiles inside the invalidation rect are only on the pending tree.
+        EXPECT_NE(tile, twin_tile);
+
+        // Unshared tiles should be unoccluded on the active tree by default.
+        EXPECT_FALSE(tile->is_occluded(ACTIVE_TREE));
+      } else {
+        // Tiles outside the invalidation rect are shared between both trees.
+        EXPECT_EQ(tile, twin_tile);
+        // Shared tiles are occluded on the active tree iff they lie beneath the
+        // occluding layer.
+        EXPECT_EQ(tile->is_occluded(ACTIVE_TREE),
+                  scaled_content_rect.x() >= occluding_layer_position.x());
+      }
+    }
+  }
+
+  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
+
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             active_layer_->contents_scale_x(),
+             gfx::Rect(layer_bounds));
+         iter;
+         ++iter) {
+      if (!*iter)
+        continue;
+      const Tile* tile = *iter;
+
+      Tile* twin_tile =
+          active_layer_->GetTwinTiling(tiling)->TileAt(iter.i(), iter.j());
+      gfx::Rect scaled_content_rect = ScaleToEnclosingRect(
+          tile->content_rect(), 1.0f / tile->contents_scale());
+
+      // Since we've already checked the shared tiles, only consider tiles in
+      // the invalidation rect.
+      if (scaled_content_rect.Intersects(invalidation_rect)) {
+        // Tiles inside the invalidation rect are only on the active tree.
+        EXPECT_NE(tile, twin_tile);
+
+        // Unshared tiles should be unoccluded on the pending tree by default.
+        EXPECT_FALSE(tile->is_occluded(PENDING_TREE));
+
+        // Unshared tiles are occluded on the active tree iff they lie beneath
+        // the occluding layer.
+        EXPECT_EQ(tile->is_occluded(ACTIVE_TREE),
+                  scaled_content_rect.x() >= occluding_layer_position.x());
+      }
+    }
+  }
+}
+
+TEST_F(OcclusionTrackingPictureLayerImplTest,
+       OccludedTilesConsideredDuringEviction) {
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+  gfx::Size viewport_size(500, 500);
+  gfx::Point pending_occluding_layer_position(310, 0);
+  gfx::Point active_occluding_layer_position(0, 310);
+  gfx::Rect invalidation_rect(230, 230, 102, 102);
+
+  scoped_refptr<FakePicturePileImpl> pending_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  scoped_refptr<FakePicturePileImpl> active_pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupTrees(pending_pile, active_pile);
+
+  pending_layer_->set_fixed_tile_size(tile_size);
+  active_layer_->set_fixed_tile_size(tile_size);
+
+  float low_res_factor = host_impl_.settings().low_res_contents_scale_factor;
+
+  std::vector<PictureLayerTiling*> tilings;
+  tilings.push_back(pending_layer_->AddTiling(low_res_factor));
+  tilings.push_back(pending_layer_->AddTiling(0.3f));
+  tilings.push_back(pending_layer_->AddTiling(0.7f));
+  tilings.push_back(pending_layer_->AddTiling(1.0f));
+  tilings.push_back(pending_layer_->AddTiling(2.0f));
+
+  EXPECT_EQ(5u, pending_layer_->num_tilings());
+  EXPECT_EQ(5u, active_layer_->num_tilings());
+
+  // Partially occlude the pending layer.
+  pending_layer_->AddChild(LayerImpl::Create(host_impl_.pending_tree(), 1));
+  LayerImpl* pending_occluding_layer = pending_layer_->children()[0];
+  pending_occluding_layer->SetBounds(layer_bounds);
+  pending_occluding_layer->SetContentBounds(layer_bounds);
+  pending_occluding_layer->SetDrawsContent(true);
+  pending_occluding_layer->SetContentsOpaque(true);
+  pending_occluding_layer->SetPosition(pending_occluding_layer_position);
+
+  // Partially occlude the active layer.
+  active_layer_->AddChild(LayerImpl::Create(host_impl_.active_tree(), 2));
+  LayerImpl* active_occluding_layer = active_layer_->children()[0];
+  active_occluding_layer->SetBounds(layer_bounds);
+  active_occluding_layer->SetContentBounds(layer_bounds);
+  active_occluding_layer->SetDrawsContent(true);
+  active_occluding_layer->SetContentsOpaque(true);
+  active_occluding_layer->SetPosition(active_occluding_layer_position);
+
+  // Partially invalidate the pending layer. Tiles inside the invalidation rect
+  // are not shared between trees.
+  pending_layer_->set_invalidation(invalidation_rect);
+
+  host_impl_.SetViewportSize(viewport_size);
+  host_impl_.active_tree()->UpdateDrawProperties();
+  host_impl_.pending_tree()->UpdateDrawProperties();
+
+  // The expected number of occluded tiles on each of the 5 tilings for each of
+  // the 3 tree priorities.
+  size_t expected_occluded_tile_count_on_both[] = {9u, 1u, 1u, 1u, 1u};
+  size_t expected_occluded_tile_count_on_active[] = {30u, 5u, 4u, 2u, 2u};
+  size_t expected_occluded_tile_count_on_pending[] = {30u, 5u, 4u, 2u, 2u};
+
+  // The total expected number of occluded tiles on all tilings for each of the
+  // 3 tree priorities.
+  size_t total_expected_occluded_tile_count[] = {13u, 43u, 43u};
+
+  ASSERT_EQ(arraysize(total_expected_occluded_tile_count), NUM_TREE_PRIORITIES);
+
+  // Verify number of occluded tiles on the pending layer for each tiling.
+  for (size_t i = 0; i < pending_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = pending_layer_->tilings()->tiling_at(i);
+    tiling->CreateAllTilesForTesting();
+
+    size_t occluded_tile_count_on_pending = 0u;
+    size_t occluded_tile_count_on_active = 0u;
+    size_t occluded_tile_count_on_both = 0u;
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             pending_layer_->contents_scale_x(),
+             gfx::Rect(layer_bounds));
+         iter;
+         ++iter) {
+      Tile* tile = *iter;
+
+      if (tile->is_occluded(PENDING_TREE))
+        occluded_tile_count_on_pending++;
+      if (tile->is_occluded(ACTIVE_TREE))
+        occluded_tile_count_on_active++;
+      if (tile->is_occluded(PENDING_TREE) && tile->is_occluded(ACTIVE_TREE))
+        occluded_tile_count_on_both++;
+    }
+    EXPECT_EQ(expected_occluded_tile_count_on_pending[i],
+              occluded_tile_count_on_pending)
+        << i;
+    EXPECT_EQ(expected_occluded_tile_count_on_active[i],
+              occluded_tile_count_on_active)
+        << i;
+    EXPECT_EQ(expected_occluded_tile_count_on_both[i],
+              occluded_tile_count_on_both)
+        << i;
+  }
+
+  // Verify number of occluded tiles on the active layer for each tiling.
+  for (size_t i = 0; i < active_layer_->num_tilings(); ++i) {
+    PictureLayerTiling* tiling = active_layer_->tilings()->tiling_at(i);
+    tiling->CreateAllTilesForTesting();
+
+    size_t occluded_tile_count_on_pending = 0u;
+    size_t occluded_tile_count_on_active = 0u;
+    size_t occluded_tile_count_on_both = 0u;
+    for (PictureLayerTiling::CoverageIterator iter(
+             tiling,
+             pending_layer_->contents_scale_x(),
+             gfx::Rect(layer_bounds));
+         iter;
+         ++iter) {
+      Tile* tile = *iter;
+
+      if (tile->is_occluded(PENDING_TREE))
+        occluded_tile_count_on_pending++;
+      if (tile->is_occluded(ACTIVE_TREE))
+        occluded_tile_count_on_active++;
+      if (tile->is_occluded(PENDING_TREE) && tile->is_occluded(ACTIVE_TREE))
+        occluded_tile_count_on_both++;
+    }
+    EXPECT_EQ(expected_occluded_tile_count_on_pending[i],
+              occluded_tile_count_on_pending)
+        << i;
+    EXPECT_EQ(expected_occluded_tile_count_on_active[i],
+              occluded_tile_count_on_active)
+        << i;
+    EXPECT_EQ(expected_occluded_tile_count_on_both[i],
+              occluded_tile_count_on_both)
+        << i;
+  }
+
+  std::vector<Tile*> all_tiles;
+  for (std::vector<PictureLayerTiling*>::iterator tiling_iterator =
+           tilings.begin();
+       tiling_iterator != tilings.end();
+       ++tiling_iterator) {
+    std::vector<Tile*> tiles = (*tiling_iterator)->AllTilesForTesting();
+    std::copy(tiles.begin(), tiles.end(), std::back_inserter(all_tiles));
+  }
+
+  host_impl_.tile_manager()->InitializeTilesWithResourcesForTesting(all_tiles);
+
+  VerifyEvictionConsidersOcclusion(pending_layer_,
+                                   total_expected_occluded_tile_count);
+  VerifyEvictionConsidersOcclusion(active_layer_,
+                                   total_expected_occluded_tile_count);
+}
+
+TEST_F(PictureLayerImplTest, RecycledTwinLayer) {
+  gfx::Size tile_size(102, 102);
+  gfx::Size layer_bounds(1000, 1000);
+
+  scoped_refptr<FakePicturePileImpl> pile =
+      FakePicturePileImpl::CreateFilledPile(tile_size, layer_bounds);
+  SetupPendingTree(pile);
+  EXPECT_FALSE(pending_layer_->GetRecycledTwinLayer());
+
+  ActivateTree();
+  EXPECT_TRUE(active_layer_->GetRecycledTwinLayer());
+  EXPECT_EQ(old_pending_layer_, active_layer_->GetRecycledTwinLayer());
+
+  SetupPendingTree(pile);
+  EXPECT_FALSE(pending_layer_->GetRecycledTwinLayer());
+  EXPECT_FALSE(active_layer_->GetRecycledTwinLayer());
+
+  ActivateTree();
+  EXPECT_TRUE(active_layer_->GetRecycledTwinLayer());
+  EXPECT_EQ(old_pending_layer_, active_layer_->GetRecycledTwinLayer());
+
+  host_impl_.ResetRecycleTreeForTesting();
+  EXPECT_FALSE(active_layer_->GetRecycledTwinLayer());
+}
+
 }  // namespace
 }  // namespace cc