Merge from Chromium at DEPS revision 33.0.1750.22

This commit was generated by merge_to_master.py.

Change-Id: I6921ac363bb1e55bc9e48d25552106ad8d723ca7
diff --git a/android_webview/browser/net/aw_url_request_context_getter.cc b/android_webview/browser/net/aw_url_request_context_getter.cc
index a738672..4b72924 100644
--- a/android_webview/browser/net/aw_url_request_context_getter.cc
+++ b/android_webview/browser/net/aw_url_request_context_getter.cc
@@ -25,6 +25,7 @@
 #include "net/cookies/cookie_store.h"
 #include "net/dns/mapped_host_resolver.h"
 #include "net/http/http_cache.h"
+#include "net/http/http_stream_factory.h"
 #include "net/proxy/proxy_service.h"
 #include "net/url_request/data_protocol_handler.h"
 #include "net/url_request/file_protocol_handler.h"
@@ -196,6 +197,7 @@
   }
   PopulateNetworkSessionParams(url_request_context_.get(),
                                &network_session_params);
+
   net::HttpCache* main_cache = new net::HttpCache(
       network_session_params,
       new net::HttpCache::DefaultBackend(
@@ -210,6 +212,10 @@
 
   job_factory_ = CreateJobFactory(&protocol_handlers_);
   url_request_context_->set_job_factory(job_factory_.get());
+
+  // TODO(sgurun) remove once crbug.com/329681 is fixed. Should be
+  // called only once.
+  net::HttpStreamFactory::EnableNpnSpdy31();
 }
 
 net::URLRequestContext* AwURLRequestContextGetter::GetURLRequestContext() {
diff --git a/ash/wm/window_manager_unittest.cc b/ash/wm/window_manager_unittest.cc
index af21613..2b97e52 100644
--- a/ash/wm/window_manager_unittest.cc
+++ b/ash/wm/window_manager_unittest.cc
@@ -704,10 +704,10 @@
   env_filter->RemoveHandler(f2.get());
 }
 
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+// A keypress and/or touch only hides the cursor on ChromeOS (crbug.com/304296).
+#if defined(OS_CHROMEOS)
 // We should show and hide the cursor in response to mouse and touch events as
-// requested. ChromeOS and Windows are the only platforms which hide the cursor
-// in response to touch (crbug.com/322250).
+// requested.
 TEST_F(WindowManagerTest, UpdateCursorVisibility) {
   aura::test::EventGenerator& generator = GetEventGenerator();
   views::corewm::CursorManager* cursor_manager =
@@ -726,11 +726,7 @@
   EXPECT_TRUE(cursor_manager->IsCursorVisible());
   EXPECT_TRUE(cursor_manager->IsMouseEventsEnabled());
 }
-#endif  // defined(OS_CHROMEOS) || defined(OS_WIN)
 
-#if defined(OS_CHROMEOS)
-// ChromeOS is the only platform for which the cursor is hidden on both
-// touch and keypress (crbug.com/304296).
 TEST_F(WindowManagerTest, UpdateCursorVisibilityOnKeyEvent) {
   aura::test::EventGenerator& generator = GetEventGenerator();
   views::corewm::CursorManager* cursor_manager =
@@ -814,6 +810,6 @@
   EXPECT_FALSE(observer_b.did_visibility_change());
   EXPECT_TRUE(observer_a.is_cursor_visible());
 }
-#endif  // defined(OS_CHROMEOS)
+#endif
 
 }  // namespace ash
diff --git a/base/android/jni_android.cc b/base/android/jni_android.cc
index 0ec6f9a..59f25e2 100644
--- a/base/android/jni_android.cc
+++ b/base/android/jni_android.cc
@@ -17,10 +17,6 @@
 using base::android::ScopedJavaLocalRef;
 
 JavaVM* g_jvm = NULL;
-
-// NOTE: This variable is only used for debugging http://crbug.com/322200
-const JNIInvokeInterface* g_jvm_functions = NULL;
-
 // Leak the global app context, as it is used from a non-joinable worker thread
 // that may still be running at shutdown. There is no harm in doing this.
 base::LazyInstance<base::android::ScopedJavaGlobalRef<jobject> >::Leaky
@@ -80,10 +76,7 @@
 JNIEnv* AttachCurrentThread() {
   DCHECK(g_jvm);
   JNIEnv* env = NULL;
-  // See http://crbug.com/322200 for the reasons for these CHECKs.
-  CHECK(g_jvm);
-  CHECK_EQ(g_jvm_functions, g_jvm->functions);
-  jint ret = g_jvm_functions->AttachCurrentThread(g_jvm, &env, NULL);
+  jint ret = g_jvm->AttachCurrentThread(&env, NULL);
   DCHECK_EQ(JNI_OK, ret);
   return env;
 }
@@ -91,18 +84,13 @@
 void DetachFromVM() {
   // Ignore the return value, if the thread is not attached, DetachCurrentThread
   // will fail. But it is ok as the native thread may never be attached.
-  if (g_jvm) {
-    // See http://crbug.com/322200 for the reasons for these CHECKs.
-    CHECK(g_jvm);
-    CHECK_EQ(g_jvm_functions, g_jvm->functions);
+  if (g_jvm)
     g_jvm->DetachCurrentThread();
-  }
 }
 
 void InitVM(JavaVM* vm) {
   DCHECK(!g_jvm);
   g_jvm = vm;
-  g_jvm_functions = vm->functions;
 }
 
 bool IsVMInitialized() {
diff --git a/base/process/memory_mac.mm b/base/process/memory_mac.mm
index d1518fa..3e281cd 100644
--- a/base/process/memory_mac.mm
+++ b/base/process/memory_mac.mm
@@ -117,10 +117,23 @@
 
   // Out of memory is certainly not heap corruption, and not necessarily
   // something for which the process should be terminated. Leave that decision
-  // to the OOM killer.  The EBADF case comes up because the malloc library
-  // attempts to log to ASL (syslog) before calling this code, which fails
-  // accessing a Unix-domain socket because of sandboxing.
-  if (errno == ENOMEM || (errno == EBADF && g_unchecked_alloc.Get().Get()))
+  // to the OOM killer.
+  if (errno == ENOMEM)
+    return;
+
+  // The malloc library attempts to log to ASL (syslog) before calling this
+  // code, which fails accessing a Unix-domain socket when sandboxed.  The
+  // failed socket results in writing to a -1 fd, leaving EBADF in errno.  If
+  // UncheckedMalloc() is on the stack, for large allocations (15k and up) only
+  // an OOM failure leads here.  Smaller allocations could also arrive here due
+  // to freelist corruption, but there is no way to distinguish that from OOM at
+  // this point.
+  //
+  // NOTE(shess): I hypothesize that EPERM case in 10.9 is the same root cause
+  // as EBADF.  Unfortunately, 10.9's opensource releases don't include malloc
+  // source code at this time.
+  // <http://crbug.com/312234>
+  if ((errno == EBADF || errno == EPERM) && g_unchecked_alloc.Get().Get())
     return;
 
   // A unit test checks this error message, so it needs to be in release builds.
diff --git a/build/util/LASTCHANGE b/build/util/LASTCHANGE
index 2e7a297..c021799 100644
--- a/build/util/LASTCHANGE
+++ b/build/util/LASTCHANGE
@@ -1 +1 @@
-LASTCHANGE=243220
+LASTCHANGE=243718
diff --git a/build/util/LASTCHANGE.blink b/build/util/LASTCHANGE.blink
index 24409f9..70a71c0 100644
--- a/build/util/LASTCHANGE.blink
+++ b/build/util/LASTCHANGE.blink
@@ -1 +1 @@
-LASTCHANGE=164524
+LASTCHANGE=164719
diff --git a/cc/cc.gyp b/cc/cc.gyp
index 6c0e4b5..7af063d 100644
--- a/cc/cc.gyp
+++ b/cc/cc.gyp
@@ -382,8 +382,6 @@
         'resources/texture_mailbox_deleter.h',
         'resources/tile.cc',
         'resources/tile.h',
-        'resources/tile_bundle.cc',
-        'resources/tile_bundle.h',
         'resources/tile_manager.cc',
         'resources/tile_manager.h',
         'resources/tile_priority.cc',
diff --git a/cc/cc.target.darwin-arm.mk b/cc/cc.target.darwin-arm.mk
index 66ac98a..f1f676d 100644
--- a/cc/cc.target.darwin-arm.mk
+++ b/cc/cc.target.darwin-arm.mk
@@ -190,7 +190,6 @@
 	cc/resources/texture_mailbox.cc \
 	cc/resources/texture_mailbox_deleter.cc \
 	cc/resources/tile.cc \
-	cc/resources/tile_bundle.cc \
 	cc/resources/tile_manager.cc \
 	cc/resources/tile_priority.cc \
 	cc/resources/transferable_resource.cc \
diff --git a/cc/cc.target.darwin-mips.mk b/cc/cc.target.darwin-mips.mk
index 320267f..f97efc9 100644
--- a/cc/cc.target.darwin-mips.mk
+++ b/cc/cc.target.darwin-mips.mk
@@ -190,7 +190,6 @@
 	cc/resources/texture_mailbox.cc \
 	cc/resources/texture_mailbox_deleter.cc \
 	cc/resources/tile.cc \
-	cc/resources/tile_bundle.cc \
 	cc/resources/tile_manager.cc \
 	cc/resources/tile_priority.cc \
 	cc/resources/transferable_resource.cc \
diff --git a/cc/cc.target.darwin-x86.mk b/cc/cc.target.darwin-x86.mk
index 26fff27..ab3893c 100644
--- a/cc/cc.target.darwin-x86.mk
+++ b/cc/cc.target.darwin-x86.mk
@@ -190,7 +190,6 @@
 	cc/resources/texture_mailbox.cc \
 	cc/resources/texture_mailbox_deleter.cc \
 	cc/resources/tile.cc \
-	cc/resources/tile_bundle.cc \
 	cc/resources/tile_manager.cc \
 	cc/resources/tile_priority.cc \
 	cc/resources/transferable_resource.cc \
diff --git a/cc/cc.target.linux-arm.mk b/cc/cc.target.linux-arm.mk
index 66ac98a..f1f676d 100644
--- a/cc/cc.target.linux-arm.mk
+++ b/cc/cc.target.linux-arm.mk
@@ -190,7 +190,6 @@
 	cc/resources/texture_mailbox.cc \
 	cc/resources/texture_mailbox_deleter.cc \
 	cc/resources/tile.cc \
-	cc/resources/tile_bundle.cc \
 	cc/resources/tile_manager.cc \
 	cc/resources/tile_priority.cc \
 	cc/resources/transferable_resource.cc \
diff --git a/cc/cc.target.linux-mips.mk b/cc/cc.target.linux-mips.mk
index 320267f..f97efc9 100644
--- a/cc/cc.target.linux-mips.mk
+++ b/cc/cc.target.linux-mips.mk
@@ -190,7 +190,6 @@
 	cc/resources/texture_mailbox.cc \
 	cc/resources/texture_mailbox_deleter.cc \
 	cc/resources/tile.cc \
-	cc/resources/tile_bundle.cc \
 	cc/resources/tile_manager.cc \
 	cc/resources/tile_priority.cc \
 	cc/resources/transferable_resource.cc \
diff --git a/cc/cc.target.linux-x86.mk b/cc/cc.target.linux-x86.mk
index 26fff27..ab3893c 100644
--- a/cc/cc.target.linux-x86.mk
+++ b/cc/cc.target.linux-x86.mk
@@ -190,7 +190,6 @@
 	cc/resources/texture_mailbox.cc \
 	cc/resources/texture_mailbox_deleter.cc \
 	cc/resources/tile.cc \
-	cc/resources/tile_bundle.cc \
 	cc/resources/tile_manager.cc \
 	cc/resources/tile_priority.cc \
 	cc/resources/transferable_resource.cc \
diff --git a/cc/cc_tests.gyp b/cc/cc_tests.gyp
index 4ef05e8..4974ad3 100644
--- a/cc/cc_tests.gyp
+++ b/cc/cc_tests.gyp
@@ -68,7 +68,6 @@
       'resources/resource_update_controller_unittest.cc',
       'resources/scoped_resource_unittest.cc',
       'resources/texture_mailbox_deleter_unittest.cc',
-      'resources/tile_bundle_unittest.cc',
       'resources/tile_manager_unittest.cc',
       'resources/tile_priority_unittest.cc',
       'resources/video_resource_updater_unittest.cc',
diff --git a/cc/layers/picture_image_layer_impl_unittest.cc b/cc/layers/picture_image_layer_impl_unittest.cc
index af61bed..2910da1 100644
--- a/cc/layers/picture_image_layer_impl_unittest.cc
+++ b/cc/layers/picture_image_layer_impl_unittest.cc
@@ -10,8 +10,6 @@
 #include "cc/test/fake_layer_tree_host_impl.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_picture_layer_tiling_client.h"
-#include "cc/test/fake_tile_manager.h"
-#include "cc/test/fake_tile_manager_client.h"
 #include "cc/test/impl_side_painting_settings.h"
 #include "cc/test/mock_quad_culler.h"
 #include "cc/trees/layer_tree_impl.h"
@@ -34,9 +32,7 @@
 class PictureImageLayerImplTest : public testing::Test {
  public:
   PictureImageLayerImplTest()
-      : host_impl_(ImplSidePaintingSettings(), &proxy_),
-        tile_manager_(&tile_manager_client_),
-        tiling_client_(&tile_manager_) {
+      : host_impl_(ImplSidePaintingSettings(), &proxy_) {
     tiling_client_.SetTileSize(ImplSidePaintingSettings().default_tile_size);
     host_impl_.CreatePendingTree();
     host_impl_.InitializeRenderer(CreateFakeOutputSurface());
@@ -72,8 +68,6 @@
  protected:
   FakeImplProxy proxy_;
   FakeLayerTreeHostImpl host_impl_;
-  FakeTileManagerClient tile_manager_client_;
-  FakeTileManager tile_manager_;
   FakePictureLayerTilingClient tiling_client_;
 };
 
diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 666b72d..c4dd1f1 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -173,10 +173,10 @@
         } else if (mode == ManagedTileState::TileVersion::PICTURE_PILE_MODE) {
           color = DebugColors::PictureTileBorderColor();
           width = DebugColors::PictureTileBorderWidth(layer_tree_impl());
-        } else if (iter.priority().resolution == HIGH_RESOLUTION) {
+        } else if (iter->priority(ACTIVE_TREE).resolution == HIGH_RESOLUTION) {
           color = DebugColors::HighResTileBorderColor();
           width = DebugColors::HighResTileBorderWidth(layer_tree_impl());
-        } else if (iter.priority().resolution == LOW_RESOLUTION) {
+        } else if (iter->priority(ACTIVE_TREE).resolution == LOW_RESOLUTION) {
           color = DebugColors::LowResTileBorderColor();
           width = DebugColors::LowResTileBorderWidth(layer_tree_impl());
         } else if (iter->contents_scale() > contents_scale_x()) {
@@ -484,14 +484,6 @@
       flags);
 }
 
-scoped_refptr<TileBundle> PictureLayerImpl::CreateTileBundle(int offset_x,
-                                                             int offset_y,
-                                                             int width,
-                                                             int height) {
-  return layer_tree_impl()->tile_manager()->CreateTileBundle(
-      offset_x, offset_y, width, height);
-}
-
 void PictureLayerImpl::UpdatePile(Tile* tile) {
   tile->set_picture_pile(pile_);
 }
@@ -725,7 +717,7 @@
       // This iteration is over the visible content rect which is potentially
       // less conservative than projecting the viewport into the layer.
       // Ignore tiles that are know to be outside the viewport.
-      if (iter.priority().distance_to_visible_in_pixels != 0)
+      if (iter->priority(PENDING_TREE).distance_to_visible_in_pixels != 0)
         continue;
 
       missing_region.Subtract(iter.geometry_rect());
@@ -794,7 +786,7 @@
     // This iteration is over the visible content rect which is potentially
     // less conservative than projecting the viewport into the layer.
     // Ignore tiles that are know to be outside the viewport.
-    if (iter.priority().distance_to_visible_in_pixels != 0)
+    if (tile->priority(PENDING_TREE).distance_to_visible_in_pixels != 0)
       continue;
 
     // If the missing region doesn't cover it, this tile is fully
@@ -806,8 +798,7 @@
     // that it is outside the visible tile rect) or this tile is shared between
     // with the twin, then this tile isn't required to prevent flashing.
     if (optional_twin_tiling) {
-      Tile* twin_tile =
-          optional_twin_tiling->TileAt(ACTIVE_TREE, iter.i(), iter.j());
+      Tile* twin_tile = optional_twin_tiling->TileAt(iter.i(), iter.j());
       if (!twin_tile || twin_tile == tile) {
         twin_had_missing_tile = true;
         continue;
@@ -1015,8 +1006,8 @@
   raster_source_scale_ = ideal_source_scale_;
 
   bool is_pinching = layer_tree_impl()->PinchGestureActive();
-  if (!is_pinching) {
-    // When not pinching, we use ideal scale:
+  if (!is_pinching || raster_contents_scale_ == 0.f) {
+    // When not pinching or when we have no previous scale, we use ideal scale:
     raster_page_scale_ = ideal_page_scale_;
     raster_contents_scale_ = ideal_contents_scale_;
   } else {
@@ -1031,6 +1022,9 @@
     raster_page_scale_ = raster_contents_scale_ / raster_device_scale_;
   }
 
+  raster_contents_scale_ =
+      std::max(raster_contents_scale_, MinimumContentsScale());
+
   // Don't allow animating CSS scales to drop below 1.  This is needed because
   // changes in raster source scale aren't handled.  See the comment in
   // ShouldAdjustRasterScale.
diff --git a/cc/layers/picture_layer_impl.h b/cc/layers/picture_layer_impl.h
index 10d3f6d..ab6aad7 100644
--- a/cc/layers/picture_layer_impl.h
+++ b/cc/layers/picture_layer_impl.h
@@ -55,10 +55,6 @@
   // PictureLayerTilingClient overrides.
   virtual scoped_refptr<Tile> CreateTile(PictureLayerTiling* tiling,
                                          gfx::Rect content_rect) OVERRIDE;
-  virtual scoped_refptr<TileBundle> CreateTileBundle(int offset_x,
-                                                     int offset_y,
-                                                     int width,
-                                                     int height) OVERRIDE;
   virtual void UpdatePile(Tile* tile) OVERRIDE;
   virtual gfx::Size CalculateTileSize(
       gfx::Size content_bounds) const OVERRIDE;
diff --git a/cc/layers/picture_layer_impl_unittest.cc b/cc/layers/picture_layer_impl_unittest.cc
index d4b0280..553080a 100644
--- a/cc/layers/picture_layer_impl_unittest.cc
+++ b/cc/layers/picture_layer_impl_unittest.cc
@@ -93,9 +93,9 @@
 
   void CreateHighLowResAndSetAllTilesVisible() {
     // Active layer must get updated first so pending layer can share from it.
-    active_layer_->CreateDefaultTilingsAndTiles(ACTIVE_TREE);
+    active_layer_->CreateDefaultTilingsAndTiles();
     active_layer_->SetAllTilesVisible();
-    pending_layer_->CreateDefaultTilingsAndTiles(PENDING_TREE);
+    pending_layer_->CreateDefaultTilingsAndTiles();
     pending_layer_->SetAllTilesVisible();
   }
 
@@ -103,16 +103,11 @@
     active_layer_->AddTiling(2.3f);
     active_layer_->AddTiling(1.0f);
     active_layer_->AddTiling(0.5f);
-    for (size_t i = 0; i < active_layer_->tilings()->num_tilings(); ++i) {
-      active_layer_->tilings()->tiling_at(i)->CreateTilesForTesting(
-          ACTIVE_TREE);
-    }
+    for (size_t i = 0; i < active_layer_->tilings()->num_tilings(); ++i)
+      active_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
     pending_layer_->set_invalidation(invalidation);
-    for (size_t i = 0; i < pending_layer_->tilings()->num_tilings(); ++i) {
-      pending_layer_->tilings()
-          ->tiling_at(i)
-          ->CreateTilesForTesting(PENDING_TREE);
-    }
+    for (size_t i = 0; i < pending_layer_->tilings()->num_tilings(); ++i)
+      pending_layer_->tilings()->tiling_at(i)->CreateAllTilesForTesting();
   }
 
   void SetupPendingTree(
@@ -174,14 +169,14 @@
   }
 
   void AssertAllTilesRequired(PictureLayerTiling* tiling) {
-    std::vector<Tile*> tiles = tiling->TilesForTesting(PENDING_TREE);
+    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
     for (size_t i = 0; i < tiles.size(); ++i)
       EXPECT_TRUE(tiles[i]->required_for_activation()) << "i: " << i;
     EXPECT_GT(tiles.size(), 0u);
   }
 
   void AssertNoTilesRequired(PictureLayerTiling* tiling) {
-    std::vector<Tile*> tiles = tiling->TilesForTesting(PENDING_TREE);
+    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
     for (size_t i = 0; i < tiles.size(); ++i)
       EXPECT_FALSE(tiles[i]->required_for_activation()) << "i: " << i;
     EXPECT_GT(tiles.size(), 0u);
@@ -1222,6 +1217,7 @@
        ++iter) {
     if (!*iter)
       continue;
+    Tile* tile = *iter;
     TilePriority priority;
     priority.resolution = HIGH_RESOLUTION;
     if (++tile_count % 2) {
@@ -1231,7 +1227,7 @@
       priority.time_to_visible_in_seconds = 1.f;
       priority.distance_to_visible_in_pixels = 1.f;
     }
-    iter.SetPriorityForTesting(priority);
+    tile->SetPriority(PENDING_TREE, priority);
   }
 
   pending_layer_->MarkVisibleResourcesAsRequired();
@@ -1248,7 +1244,7 @@
     if (!*iter)
       continue;
     const Tile* tile = *iter;
-    if (iter.priority().distance_to_visible_in_pixels == 0.f) {
+    if (tile->priority(PENDING_TREE).distance_to_visible_in_pixels == 0.f) {
       EXPECT_TRUE(tile->required_for_activation());
       num_visible++;
     } else {
@@ -1319,8 +1315,7 @@
   // Active layer has tilings, but no tiles due to missing recordings.
   EXPECT_TRUE(active_layer_->CanHaveTilings());
   EXPECT_EQ(active_layer_->tilings()->num_tilings(), 2u);
-  EXPECT_EQ(active_layer_->HighResTiling()->TilesForTesting(ACTIVE_TREE).size(),
-            0u);
+  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.  This is attempting to simulate
@@ -1425,6 +1420,53 @@
   EXPECT_EQ(0u, active_layer_->num_tilings());
 }
 
+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);
+
+  ASSERT_GE(pending_layer_->num_tilings(), 0u);
+  EXPECT_FLOAT_EQ(high_res_scale,
+                  pending_layer_->HighResTiling()->contents_scale());
+}
+
+TEST_F(PictureLayerImplTest, FirstTilingTooSmall) {
+  SetupDefaultTrees(gfx::Size(10, 10));
+  host_impl_.PinchGestureBegin();
+  float high_res_scale = 0.0001f;
+  EXPECT_GT(pending_layer_->MinimumContentsScale(), high_res_scale);
+
+  SetContentsScaleOnBothLayers(high_res_scale, 1.f, 1.f, false);
+
+  ASSERT_GE(pending_layer_->num_tilings(), 0u);
+  EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
+                  pending_layer_->HighResTiling()->contents_scale());
+}
+
+TEST_F(PictureLayerImplTest, PinchingTooSmall) {
+  SetupDefaultTrees(gfx::Size(10, 10));
+
+  float contents_scale = 0.15f;
+  SetContentsScaleOnBothLayers(contents_scale, 1.f, 1.f, false);
+
+  ASSERT_GE(pending_layer_->num_tilings(), 0u);
+  EXPECT_FLOAT_EQ(contents_scale,
+                  pending_layer_->HighResTiling()->contents_scale());
+
+  host_impl_.PinchGestureBegin();
+
+  float page_scale = 0.0001f;
+  EXPECT_LT(page_scale * contents_scale,
+            pending_layer_->MinimumContentsScale());
+
+
+  SetContentsScaleOnBothLayers(contents_scale, 1.f, page_scale, false);
+  ASSERT_GE(pending_layer_->num_tilings(), 0u);
+  EXPECT_FLOAT_EQ(pending_layer_->MinimumContentsScale(),
+                  pending_layer_->HighResTiling()->contents_scale());
+}
+
 class DeferredInitPictureLayerImplTest : public PictureLayerImplTest {
  public:
   DeferredInitPictureLayerImplTest()
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 6802e55..1aa3567 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -17,29 +17,6 @@
 
 namespace cc {
 
-namespace {
-
-const int kTileBundleWidth = 2;
-const int kTileBundleHeight = 2;
-
-std::pair<int, int> ComputeTileBundleIndex(int i, int j) {
-  return std::make_pair(i / kTileBundleWidth, j / kTileBundleHeight);
-}
-
-gfx::Size ComputeBundleTextureSize(gfx::Size tile_size,
-                                   const TilingData& tiling_data) {
-  int border_texels = tiling_data.border_texels();
-
-  int inner_tile_width = tile_size.width() - 2 * border_texels;
-  int bundle_width = inner_tile_width * kTileBundleWidth + 2 * border_texels;
-
-  int inner_tile_height = tile_size.height() - 2 * border_texels;
-  int bundle_height = inner_tile_height * kTileBundleHeight + 2 * border_texels;
-  return gfx::Size(bundle_width, bundle_height);
-}
-
-}  // namespace
-
 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
     float contents_scale,
     gfx::Size layer_bounds,
@@ -57,8 +34,6 @@
       resolution_(NON_IDEAL_RESOLUTION),
       client_(client),
       tiling_data_(gfx::Size(), gfx::Size(), true),
-      bundle_tiling_data_(gfx::Size(), gfx::Size(), true),
-      current_tree_(PENDING_TREE),
       last_impl_frame_time_in_seconds_(0.0) {
   gfx::Size content_bounds =
       gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
@@ -72,13 +47,9 @@
 
   tiling_data_.SetTotalSize(content_bounds);
   tiling_data_.SetMaxTextureSize(tile_size);
-  bundle_tiling_data_.SetTotalSize(content_bounds);
-  bundle_tiling_data_.SetMaxTextureSize(
-      ComputeBundleTextureSize(tile_size, tiling_data_));
 }
 
 PictureLayerTiling::~PictureLayerTiling() {
-  SetLiveTilesRect(gfx::Rect());
 }
 
 void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
@@ -93,103 +64,41 @@
   return gfx::ScaleSize(layer_bounds_, contents_scale_);
 }
 
-TileBundle* PictureLayerTiling::CreateBundleForTileAt(
-    int i,
-    int j,
-    const PictureLayerTiling* twin_tiling) {
-  TileBundleMapKey key = ComputeTileBundleIndex(i, j);
-  DCHECK(tile_bundles_.find(key) == tile_bundles_.end());
-
-  scoped_refptr<TileBundle> candidate_bundle = NULL;
-
-  // Always try to get the twin bundle first. TileBundles are always shared
-  // between trees.
-  if (twin_tiling &&
-      tiling_data_.max_texture_size() ==
-      twin_tiling->tiling_data_.max_texture_size()) {
-    candidate_bundle = twin_tiling->TileBundleAt(key.first, key.second);
-  }
-
-  // If we couldn't get a tile bundle, create a new one.
-  if (!candidate_bundle) {
-    candidate_bundle = client_->CreateTileBundle(key.first * kTileBundleWidth,
-                                                 key.second * kTileBundleHeight,
-                                                 kTileBundleWidth,
-                                                 kTileBundleHeight);
-  }
-  candidate_bundle->SwapTilesIfRequired();
-  tile_bundles_[key] = candidate_bundle;
-  return candidate_bundle.get();
-}
-
-TileBundle* PictureLayerTiling::TileBundleContainingTileAt(int i, int j) const {
-  TileBundleMapKey key = ComputeTileBundleIndex(i, j);
-  return TileBundleAt(key.first, key.second);
-}
-
-TileBundle* PictureLayerTiling::TileBundleAt(int i, int j) const {
-  TileBundleMapKey key(i, j);
-  TileBundleMap::const_iterator it = tile_bundles_.find(key);
-  if (it == tile_bundles_.end())
+Tile* PictureLayerTiling::TileAt(int i, int j) const {
+  TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j));
+  if (iter == tiles_.end())
     return NULL;
-  it->second->SwapTilesIfRequired();
-  return it->second.get();
+  return iter->second.get();
 }
 
-Tile* PictureLayerTiling::TileAt(WhichTree tree, int i, int j) const {
-  TileBundle* bundle = TileBundleContainingTileAt(i, j);
-  if (!bundle)
-    return NULL;
-  return bundle->TileAt(tree, i, j);
-}
-
-void PictureLayerTiling::CreateTile(WhichTree tree,
-                                    int i,
+void PictureLayerTiling::CreateTile(int i,
                                     int j,
                                     const PictureLayerTiling* twin_tiling) {
-  TileBundle* bundle = TileBundleContainingTileAt(i, j);
-  if (!bundle)
-    bundle = CreateBundleForTileAt(i, j, twin_tiling);
+  TileMapKey key(i, j);
+  DCHECK(tiles_.find(key) == tiles_.end());
 
   gfx::Rect paint_rect = tiling_data_.TileBoundsWithBorder(i, j);
   gfx::Rect tile_rect = paint_rect;
   tile_rect.set_size(tiling_data_.max_texture_size());
 
   // Check our twin for a valid tile.
-  WhichTree twin_tree = (tree == ACTIVE_TREE) ? PENDING_TREE : ACTIVE_TREE;
-  if (Tile* candidate_tile = bundle->TileAt(twin_tree, i, j)) {
-    gfx::Rect rect =
-        gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
-    if (!client_->GetInvalidation()->Intersects(rect)) {
-      bundle->AddTileAt(tree, i, j, candidate_tile);
-      return;
+  if (twin_tiling &&
+      tiling_data_.max_texture_size() ==
+      twin_tiling->tiling_data_.max_texture_size()) {
+    if (Tile* candidate_tile = twin_tiling->TileAt(i, j)) {
+      gfx::Rect rect =
+          gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
+      if (!client_->GetInvalidation()->Intersects(rect)) {
+        tiles_[key] = candidate_tile;
+        return;
+      }
     }
   }
 
   // Create a new tile because our twin didn't have a valid one.
   scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect);
   if (tile.get())
-    bundle->AddTileAt(tree, i, j, tile);
-}
-
-bool PictureLayerTiling::RemoveTile(WhichTree tree, int i, int j) {
-  TileBundleMapKey key = ComputeTileBundleIndex(i, j);
-  TileBundleMap::iterator it = tile_bundles_.find(key);
-  if (it == tile_bundles_.end())
-    return false;
-
-  it->second->SwapTilesIfRequired();
-  return it->second->RemoveTileAt(tree, i, j);
-}
-
-void PictureLayerTiling::RemoveBundleContainingTileAtIfEmpty(int i, int j) {
-  TileBundleMapKey key = ComputeTileBundleIndex(i, j);
-  TileBundleMap::iterator it = tile_bundles_.find(key);
-  if (it == tile_bundles_.end())
-    return;
-
-  if (it->second->IsEmpty())
-    tile_bundles_.erase(it);
+    tiles_[key] = tile;
 }
 
 Region PictureLayerTiling::OpaqueRegionInContentRect(
@@ -200,30 +109,19 @@
 }
 
 void PictureLayerTiling::SetCanUseLCDText(bool can_use_lcd_text) {
-  // TODO(vmpstr): This can be done per bundle with results used
-  // in tile manager.
-  for (TileBundleMap::iterator it = tile_bundles_.begin();
-       it != tile_bundles_.end();
-       ++it) {
-    for (TileBundle::Iterator tile_it(it->second, current_tree_);
-         tile_it;
-         ++tile_it)
-      tile_it->set_can_use_lcd_text(can_use_lcd_text);
-  }
+  for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+    it->second->set_can_use_lcd_text(can_use_lcd_text);
 }
 
 void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
-  DCHECK(current_tree_ == PENDING_TREE);
-
   const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
   for (TilingData::Iterator iter(&tiling_data_, live_tiles_rect_); iter;
        ++iter) {
-    int tile_x = iter.index_x();
-    int tile_y = iter.index_y();
-    Tile* tile = TileAt(PENDING_TREE, tile_x, tile_y);
-    if (tile)
+    TileMapKey key = iter.index();
+    TileMap::iterator find = tiles_.find(key);
+    if (find != tiles_.end())
       continue;
-    CreateTile(PENDING_TREE, tile_x, tile_y, twin_tiling);
+    CreateTile(key.first, key.second, twin_tiling);
   }
 }
 
@@ -231,7 +129,6 @@
   if (layer_bounds_ == layer_bounds)
     return;
 
-  DCHECK(current_tree_ == PENDING_TREE);
   DCHECK(!layer_bounds.IsEmpty());
 
   gfx::Size old_layer_bounds = layer_bounds_;
@@ -244,9 +141,6 @@
   if (tile_size != tiling_data_.max_texture_size()) {
     tiling_data_.SetTotalSize(content_bounds);
     tiling_data_.SetMaxTextureSize(tile_size);
-    bundle_tiling_data_.SetTotalSize(content_bounds);
-    bundle_tiling_data_.SetMaxTextureSize(
-        ComputeBundleTextureSize(tile_size, tiling_data_));
     Reset();
     return;
   }
@@ -256,7 +150,6 @@
   bounded_live_tiles_rect.Intersect(gfx::Rect(content_bounds));
   SetLiveTilesRect(bounded_live_tiles_rect);
   tiling_data_.SetTotalSize(content_bounds);
-  bundle_tiling_data_.SetTotalSize(content_bounds);
 
   // Create tiles for newly exposed areas.
   Region layer_region((gfx::Rect(layer_bounds_)));
@@ -265,9 +158,7 @@
 }
 
 void PictureLayerTiling::Invalidate(const Region& layer_region) {
-  DCHECK(current_tree_ == PENDING_TREE);
-
-  std::vector<std::pair<int, int> > new_tile_keys;
+  std::vector<TileMapKey> new_tile_keys;
   for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
     gfx::Rect layer_rect = iter.rect();
     gfx::Rect content_rect =
@@ -276,23 +167,18 @@
     if (content_rect.IsEmpty())
       continue;
     for (TilingData::Iterator iter(&tiling_data_, content_rect); iter; ++iter) {
-      int tile_x = iter.index_x();
-      int tile_y = iter.index_y();
-
-      // If there is no bundle for the given tile, we can skip.
-      bool deleted = RemoveTile(PENDING_TREE, tile_x, tile_y);
-      if (deleted)
-        new_tile_keys.push_back(std::make_pair(tile_x, tile_y));
+      TileMapKey key(iter.index());
+      TileMap::iterator find = tiles_.find(key);
+      if (find == tiles_.end())
+        continue;
+      tiles_.erase(find);
+      new_tile_keys.push_back(key);
     }
   }
 
   const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
-  for (size_t i = 0; i < new_tile_keys.size(); ++i) {
-    CreateTile(PENDING_TREE,
-               new_tile_keys[i].first,
-               new_tile_keys[i].second,
-               twin_tiling);
-  }
+  for (size_t i = 0; i < new_tile_keys.size(); ++i)
+    CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
 }
 
 PictureLayerTiling::CoverageIterator::CoverageIterator()
@@ -319,8 +205,7 @@
       left_(0),
       top_(0),
       right_(-1),
-      bottom_(-1),
-      tree_(tiling->current_tree_) {
+      bottom_(-1) {
   DCHECK(tiling_);
   if (dest_rect_.IsEmpty())
     return;
@@ -375,7 +260,7 @@
     }
   }
 
-  current_tile_ = tiling_->TileAt(tree_, tile_i_, tile_j_);
+  current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
 
   // Calculate the current geometry rect.  Due to floating point rounding
   // and ToEnclosingRect, tiles might overlap in destination space on the
@@ -431,19 +316,6 @@
   return rect;
 }
 
-TilePriority PictureLayerTiling::CoverageIterator::priority() {
-  TileBundle* bundle = tiling_->TileBundleContainingTileAt(tile_i_, tile_j_);
-  if (bundle)
-    return bundle->GetPriority(tree_);
-  return TilePriority();
-}
-
-void PictureLayerTiling::CoverageIterator::SetPriorityForTesting(
-    const TilePriority& priority) {
-  TileBundle* bundle = tiling_->TileBundleContainingTileAt(tile_i_, tile_j_);
-  bundle->SetPriority(tree_, priority);
-}
-
 gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
   gfx::PointF tex_origin =
       tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin();
@@ -464,7 +336,7 @@
 
 void PictureLayerTiling::Reset() {
   live_tiles_rect_ = gfx::Rect();
-  tile_bundles_.clear();
+  tiles_.clear();
 }
 
 void PictureLayerTiling::UpdateTilePriorities(
@@ -480,10 +352,6 @@
     const gfx::Transform& current_screen_transform,
     double current_frame_time_in_seconds,
     size_t max_tiles_for_interest_area) {
-  if (!has_ever_been_updated())
-    current_tree_ = tree;
-
-  DCHECK_EQ(tree, current_tree_);
   if (!NeedsUpdateForFrameAtTime(current_frame_time_in_seconds)) {
     // This should never be zero for the purposes of has_ever_been_updated().
     DCHECK_NE(current_frame_time_in_seconds, 0.0);
@@ -539,22 +407,23 @@
         last_screen_transform.matrix().get(0, 3),
         last_screen_transform.matrix().get(1, 3));
 
-    for (TilingData::Iterator iter(&bundle_tiling_data_, interest_rect);
+    for (TilingData::Iterator iter(&tiling_data_, interest_rect);
          iter; ++iter) {
-      int bundle_x = iter.index_x();
-      int bundle_y = iter.index_y();
-      TileBundle* bundle = TileBundleAt(bundle_x, bundle_y);
-      if (!bundle)
+      TileMap::iterator find = tiles_.find(iter.index());
+      if (find == tiles_.end())
         continue;
+      Tile* tile = find->second.get();
 
-      gfx::Rect bundle_bounds =
-          bundle_tiling_data_.TileBounds(bundle_x, bundle_y);
-      gfx::RectF current_screen_rect =
-          gfx::ScaleRect(bundle_bounds, current_scale, current_scale) +
-          current_offset;
-      gfx::RectF last_screen_rect =
-          gfx::ScaleRect(bundle_bounds, last_scale, last_scale) +
-          last_offset;
+      gfx::Rect tile_bounds =
+          tiling_data_.TileBounds(iter.index_x(), iter.index_y());
+      gfx::RectF current_screen_rect = gfx::ScaleRect(
+          tile_bounds,
+          current_scale,
+          current_scale) + current_offset;
+      gfx::RectF last_screen_rect = gfx::ScaleRect(
+          tile_bounds,
+          last_scale,
+          last_scale) + last_offset;
 
       float distance_to_visible_in_pixels =
           current_screen_rect.ManhattanInternalDistance(view_rect);
@@ -566,8 +435,7 @@
           resolution_,
           time_to_visible_in_seconds,
           distance_to_visible_in_pixels);
-
-      bundle->SetPriority(tree, priority);
+      tile->SetPriority(tree, priority);
     }
   } else if (!last_screen_transform.HasPerspective() &&
              !current_screen_transform.HasPerspective()) {
@@ -587,57 +455,55 @@
         last_screen_transform.matrix().get(0, 3),
         last_screen_transform.matrix().get(1, 3));
 
-    float current_bundle_width =
-        bundle_tiling_data_.TileSizeX(0) * current_scale;
-    float last_bundle_width =
-        bundle_tiling_data_.TileSizeX(0) * last_scale;
-    float current_bundle_height =
-        bundle_tiling_data_.TileSizeY(0) * current_scale;
-    float last_bundle_height =
-        bundle_tiling_data_.TileSizeY(0) * last_scale;
+    float current_tile_width = tiling_data_.TileSizeX(0) * current_scale;
+    float last_tile_width = tiling_data_.TileSizeX(0) * last_scale;
+    float current_tile_height = tiling_data_.TileSizeY(0) * current_scale;
+    float last_tile_height = tiling_data_.TileSizeY(0) * last_scale;
 
     // Apply screen space transform to local basis vectors (tile_width, 0) and
     // (0, tile_height); the math simplifies and can be initialized directly.
     gfx::Vector2dF current_horizontal(
-        current_screen_transform.matrix().get(0, 0) * current_bundle_width,
-        current_screen_transform.matrix().get(1, 0) * current_bundle_width);
+        current_screen_transform.matrix().get(0, 0) * current_tile_width,
+        current_screen_transform.matrix().get(1, 0) * current_tile_width);
     gfx::Vector2dF current_vertical(
-        current_screen_transform.matrix().get(0, 1) * current_bundle_height,
-        current_screen_transform.matrix().get(1, 1) * current_bundle_height);
+        current_screen_transform.matrix().get(0, 1) * current_tile_height,
+        current_screen_transform.matrix().get(1, 1) * current_tile_height);
 
     gfx::Vector2dF last_horizontal(
-        last_screen_transform.matrix().get(0, 0) * last_bundle_width,
-        last_screen_transform.matrix().get(1, 0) * last_bundle_width);
+        last_screen_transform.matrix().get(0, 0) * last_tile_width,
+        last_screen_transform.matrix().get(1, 0) * last_tile_width);
     gfx::Vector2dF last_vertical(
-        last_screen_transform.matrix().get(0, 1) * last_bundle_height,
-        last_screen_transform.matrix().get(1, 1) * last_bundle_height);
+        last_screen_transform.matrix().get(0, 1) * last_tile_height,
+        last_screen_transform.matrix().get(1, 1) * last_tile_height);
 
-    for (TilingData::Iterator iter(&bundle_tiling_data_, interest_rect);
+    for (TilingData::Iterator iter(&tiling_data_, interest_rect);
          iter; ++iter) {
-      int bundle_x = iter.index_x();
-      int bundle_y = iter.index_y();
-      TileBundle* bundle = TileBundleAt(bundle_x, bundle_y);
-      if (!bundle)
+      TileMap::iterator find = tiles_.find(iter.index());
+      if (find == tiles_.end())
         continue;
 
-      gfx::PointF current_bundle_origin = current_screen_space_origin +
-              ScaleVector2d(current_horizontal, bundle_x) +
-              ScaleVector2d(current_vertical, bundle_y);
-      gfx::PointF last_bundle_origin = last_screen_space_origin +
-              ScaleVector2d(last_horizontal, bundle_x) +
-              ScaleVector2d(last_vertical, bundle_y);
+      Tile* tile = find->second.get();
+
+      int i = iter.index_x();
+      int j = iter.index_y();
+      gfx::PointF current_tile_origin = current_screen_space_origin +
+              ScaleVector2d(current_horizontal, i) +
+              ScaleVector2d(current_vertical, j);
+      gfx::PointF last_tile_origin = last_screen_space_origin +
+              ScaleVector2d(last_horizontal, i) +
+              ScaleVector2d(last_vertical, j);
 
       gfx::RectF current_screen_rect = gfx::QuadF(
-          current_bundle_origin,
-          current_bundle_origin + current_horizontal,
-          current_bundle_origin + current_horizontal + current_vertical,
-          current_bundle_origin + current_vertical).BoundingBox();
+          current_tile_origin,
+          current_tile_origin + current_horizontal,
+          current_tile_origin + current_horizontal + current_vertical,
+          current_tile_origin + current_vertical).BoundingBox();
 
       gfx::RectF last_screen_rect = gfx::QuadF(
-          last_bundle_origin,
-          last_bundle_origin + last_horizontal,
-          last_bundle_origin + last_horizontal + last_vertical,
-          last_bundle_origin + last_vertical).BoundingBox();
+          last_tile_origin,
+          last_tile_origin + last_horizontal,
+          last_tile_origin + last_horizontal + last_vertical,
+          last_tile_origin + last_vertical).BoundingBox();
 
       float distance_to_visible_in_pixels =
           current_screen_rect.ManhattanInternalDistance(view_rect);
@@ -649,28 +515,26 @@
           resolution_,
           time_to_visible_in_seconds,
           distance_to_visible_in_pixels);
-
-      bundle->SetPriority(tree, priority);
+      tile->SetPriority(tree, priority);
     }
   } else {
-    for (TilingData::Iterator iter(&bundle_tiling_data_, interest_rect);
+    for (TilingData::Iterator iter(&tiling_data_, interest_rect);
          iter; ++iter) {
-      int bundle_x = iter.index_x();
-      int bundle_y = iter.index_y();
-      TileBundle* bundle = TileBundleAt(bundle_x, bundle_y);
-      if (!bundle)
+      TileMap::iterator find = tiles_.find(iter.index());
+      if (find == tiles_.end())
         continue;
+      Tile* tile = find->second.get();
 
-      gfx::Rect bundle_bounds =
-          bundle_tiling_data_.TileBounds(bundle_x, bundle_y);
+      gfx::Rect tile_bounds =
+          tiling_data_.TileBounds(iter.index_x(), iter.index_y());
       gfx::RectF current_layer_content_rect = gfx::ScaleRect(
-          bundle_bounds,
+          tile_bounds,
           current_scale,
           current_scale);
       gfx::RectF current_screen_rect = MathUtil::MapClippedRect(
           current_screen_transform, current_layer_content_rect);
       gfx::RectF last_layer_content_rect = gfx::ScaleRect(
-          bundle_bounds,
+          tile_bounds,
           last_scale,
           last_scale);
       gfx::RectF last_screen_rect  = MathUtil::MapClippedRect(
@@ -687,15 +551,15 @@
           resolution_,
           time_to_visible_in_seconds,
           distance_to_visible_in_pixels);
-
-      bundle->SetPriority(tree, priority);
+      tile->SetPriority(tree, priority);
     }
   }
 
   last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
 }
 
-void PictureLayerTiling::SetLiveTilesRect(gfx::Rect new_live_tiles_rect) {
+void PictureLayerTiling::SetLiveTilesRect(
+    gfx::Rect new_live_tiles_rect) {
   DCHECK(new_live_tiles_rect.IsEmpty() ||
          ContentRect().Contains(new_live_tiles_rect));
   if (live_tiles_rect_ == new_live_tiles_rect)
@@ -707,18 +571,12 @@
                                            new_live_tiles_rect);
        iter;
        ++iter) {
-    int tile_x = iter.index_x();
-    int tile_y = iter.index_y();
-
+    TileMapKey key(iter.index());
+    TileMap::iterator found = tiles_.find(key);
     // If the tile was outside of the recorded region, it won't exist even
     // though it was in the live rect.
-    RemoveTile(current_tree_, tile_x, tile_y);
-    RemoveBundleContainingTileAtIfEmpty(tile_x, tile_y);
-  }
-
-  if (new_live_tiles_rect.IsEmpty()) {
-    live_tiles_rect_ = new_live_tiles_rect;
-    return;
+    if (found != tiles_.end())
+      tiles_.erase(found);
   }
 
   const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
@@ -729,7 +587,8 @@
                                            live_tiles_rect_);
        iter;
        ++iter) {
-    CreateTile(current_tree_, iter.index_x(), iter.index_y(), twin_tiling);
+    TileMapKey key(iter.index());
+    CreateTile(key.first, key.second, twin_tiling);
   }
 
   live_tiles_rect_ = new_live_tiles_rect;
@@ -740,52 +599,35 @@
   // still in the tree. Calling this first on an active tiling that is becoming
   // recycled takes care of tiles that are no longer in the active tree (eg.
   // due to a pending invalidation).
-  for (TileBundleMap::const_iterator it = tile_bundles_.begin();
-       it != tile_bundles_.end();
-       ++it) {
-    it->second->DidBecomeRecycled();
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    it->second->SetPriority(ACTIVE_TREE, TilePriority());
   }
-  // Note that recycled tree would not be accessed, and the next tree
-  // stage after recycled in pending, so we can just set the state to
-  // pending here.
-  current_tree_ = PENDING_TREE;
 }
 
 void PictureLayerTiling::DidBecomeActive() {
-  for (TileBundleMap::const_iterator it = tile_bundles_.begin();
-       it != tile_bundles_.end();
-       ++it) {
-    it->second->DidBecomeActive();
-    for (TileBundle::Iterator tile_it(it->second.get(), ACTIVE_TREE);
-         tile_it;
-         ++tile_it) {
-      // Tile holds a ref onto a picture pile. If the tile never gets
-      // invalidated and recreated, then that picture pile ref could exist
-      // indefinitely.  To prevent this, ask the client to update the pile to
-      // its own ref.  This will cause PicturePileImpls and their clones to get
-      // deleted once the corresponding PictureLayerImpl and any in flight
-      // raster jobs go out of scope.
-      client_->UpdatePile(*tile_it);
-    }
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    it->second->SetPriority(ACTIVE_TREE, it->second->priority(PENDING_TREE));
+    it->second->SetPriority(PENDING_TREE, TilePriority());
+
+    // Tile holds a ref onto a picture pile. If the tile never gets invalidated
+    // and recreated, then that picture pile ref could exist indefinitely.  To
+    // prevent this, ask the client to update the pile to its own ref.  This
+    // will cause PicturePileImpls and their clones to get deleted once the
+    // corresponding PictureLayerImpl and any in flight raster jobs go out of
+    // scope.
+    client_->UpdatePile(it->second.get());
   }
-  current_tree_ = ACTIVE_TREE;
 }
 
 void PictureLayerTiling::UpdateTilesToCurrentPile() {
-  for (TileBundleMap::const_iterator it = tile_bundles_.begin();
-       it != tile_bundles_.end();
-       ++it) {
-    for (TileBundle::Iterator tile_it(it->second.get(), PENDING_TREE);
-         tile_it;
-         ++tile_it) {
-      client_->UpdatePile(*tile_it);
-    }
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    client_->UpdatePile(it->second.get());
   }
 }
 
 scoped_ptr<base::Value> PictureLayerTiling::AsValue() const {
   scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
-  state->SetInteger("num_tile_bundles", tile_bundles_.size());
+  state->SetInteger("num_tiles", tiles_.size());
   state->SetDouble("content_scale", contents_scale_);
   state->Set("content_bounds",
              MathUtil::AsValue(ContentRect().size()).release());
@@ -794,11 +636,9 @@
 
 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
   size_t amount = 0;
-  for (TileBundleMap::const_iterator it = tile_bundles_.begin();
-       it != tile_bundles_.end();
-       ++it) {
-    for (TileBundle::Iterator tile_it(it->second.get()); tile_it; ++tile_it)
-      amount += tile_it->GPUMemoryUsageInBytes();
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    const Tile* tile = it->second.get();
+    amount += tile->GPUMemoryUsageInBytes();
   }
   return amount;
 }
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index 8a539a8..dae6272 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -15,7 +15,6 @@
 #include "cc/base/region.h"
 #include "cc/base/tiling_data.h"
 #include "cc/resources/tile.h"
-#include "cc/resources/tile_bundle.h"
 #include "cc/resources/tile_priority.h"
 #include "ui/gfx/rect.h"
 
@@ -30,10 +29,6 @@
   virtual scoped_refptr<Tile> CreateTile(
     PictureLayerTiling* tiling,
     gfx::Rect content_rect) = 0;
-  virtual scoped_refptr<TileBundle> CreateTileBundle(int offset_x,
-                                                     int offset_y,
-                                                     int width,
-                                                     int height) = 0;
   virtual void UpdatePile(Tile* tile) = 0;
   virtual gfx::Size CalculateTileSize(
     gfx::Size content_bounds) const = 0;
@@ -71,49 +66,15 @@
   gfx::Size tile_size() const { return tiling_data_.max_texture_size(); }
   float contents_scale() const { return contents_scale_; }
 
-  Tile* TileAt(WhichTree tree, int, int) const;
-
-  void SetTreeForTesting(WhichTree tree) {
-    current_tree_ = tree;
-  }
   void CreateAllTilesForTesting() {
-    current_tree_ = ACTIVE_TREE;
-    SetLiveTilesRect(gfx::Rect(tiling_data_.total_size()));
-    live_tiles_rect_ = gfx::Rect();
-    current_tree_ = PENDING_TREE;
     SetLiveTilesRect(gfx::Rect(tiling_data_.total_size()));
   }
-  void CreateTilesForTesting(WhichTree tree) {
-    current_tree_ = tree;
-    SetLiveTilesRect(gfx::Rect(tiling_data_.total_size()));
-  }
+
   std::vector<Tile*> AllTilesForTesting() const {
     std::vector<Tile*> all_tiles;
-    for (TileBundleMap::const_iterator it = tile_bundles_.begin();
-         it != tile_bundles_.end(); ++it) {
-      for (TileBundle::Iterator tile_it(it->second.get()); tile_it; ++tile_it)
-        all_tiles.push_back(*tile_it);
-    }
-    return all_tiles;
-  }
-  std::vector<TileBundle*> AllTileBundlesForTesting() const {
-    std::vector<TileBundle*> all_bundles;
-    for (TileBundleMap::const_iterator it = tile_bundles_.begin();
-         it != tile_bundles_.end(); ++it) {
-      all_bundles.push_back(it->second.get());
-    }
-    return all_bundles;
-  }
-  std::vector<Tile*> TilesForTesting(WhichTree tree) const {
-    std::vector<Tile*> all_tiles;
-    for (TileBundleMap::const_iterator it = tile_bundles_.begin();
-         it != tile_bundles_.end(); ++it) {
-      for (TileBundle::Iterator tile_it(it->second.get(), tree);
-           tile_it;
-           ++tile_it) {
-        all_tiles.push_back(*tile_it);
-      }
-    }
+    for (TileMap::const_iterator it = tiles_.begin();
+         it != tiles_.end(); ++it)
+      all_tiles.push_back(it->second.get());
     return all_tiles;
   }
 
@@ -145,9 +106,6 @@
     Tile* operator->() const { return current_tile_; }
     Tile* operator*() const { return current_tile_; }
 
-    TilePriority priority();
-    void SetPriorityForTesting(const TilePriority& priority);
-
     CoverageIterator& operator++();
     operator bool() const { return tile_j_ <= bottom_; }
 
@@ -167,7 +125,6 @@
     int top_;
     int right_;
     int bottom_;
-    WhichTree tree_;
 
     friend class PictureLayerTiling;
   };
@@ -232,28 +189,14 @@
   }
 
  protected:
-  friend class CoverageIterator;
-  friend class TileBundle;
-
-  typedef std::pair<int, int> TileBundleMapKey;
-  typedef base::hash_map<TileBundleMapKey, scoped_refptr<TileBundle> >
-      TileBundleMap;
+  typedef std::pair<int, int> TileMapKey;
+  typedef base::hash_map<TileMapKey, scoped_refptr<Tile> > TileMap;
 
   PictureLayerTiling(float contents_scale,
                      gfx::Size layer_bounds,
                      PictureLayerTilingClient* client);
   void SetLiveTilesRect(gfx::Rect live_tiles_rect);
-  void CreateTile(WhichTree tree,
-                  int i,
-                  int j,
-                  const PictureLayerTiling* twin_tiling);
-  bool RemoveTile(WhichTree tree, int i, int j);
-  void RemoveBundleContainingTileAtIfEmpty(int i, int j);
-  TileBundle* TileBundleContainingTileAt(int, int) const;
-  TileBundle* CreateBundleForTileAt(int,
-                                    int,
-                                    const PictureLayerTiling* twin_tiling);
-  TileBundle* TileBundleAt(int, int) const;
+  void CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
 
   // Given properties.
   float contents_scale_;
@@ -263,15 +206,14 @@
 
   // Internal data.
   TilingData tiling_data_;
-  TilingData bundle_tiling_data_;
-  // It is not legal to have a NULL tile bundle in the tile_bundles_ map.
-  TileBundleMap tile_bundles_;
+  TileMap tiles_;  // It is not legal to have a NULL tile in the tiles_ map.
   gfx::Rect live_tiles_rect_;
-  WhichTree current_tree_;
 
   // State saved for computing velocities based upon finite differences.
   double last_impl_frame_time_in_seconds_;
 
+  friend class CoverageIterator;
+
  private:
   DISALLOW_ASSIGN(PictureLayerTiling);
 
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index c981a0a..7a9b8df 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -4,8 +4,6 @@
 
 #include "cc/resources/picture_layer_tiling.h"
 #include "cc/test/fake_picture_layer_tiling_client.h"
-#include "cc/test/fake_tile_manager.h"
-#include "cc/test/fake_tile_manager_client.h"
 
 #include "testing/gtest/include/gtest/gtest.h"
 #include "testing/perf/perf_test.h"
@@ -20,17 +18,13 @@
 
 class PictureLayerTilingPerfTest : public testing::Test {
  public:
-  PictureLayerTilingPerfTest() : num_runs_(0) {
-    tile_manager_ = make_scoped_ptr(new FakeTileManager(&tile_manager_client_));
-    picture_layer_tiling_client_ =
-        make_scoped_ptr(new FakePictureLayerTilingClient(tile_manager_.get()));
-  }
+  PictureLayerTilingPerfTest() : num_runs_(0) {}
 
   virtual void SetUp() OVERRIDE {
-    picture_layer_tiling_client_->SetTileSize(gfx::Size(256, 256));
+    picture_layer_tiling_client_.SetTileSize(gfx::Size(256, 256));
     picture_layer_tiling_ = PictureLayerTiling::Create(
-        1, gfx::Size(256 * 50, 256 * 50), picture_layer_tiling_client_.get());
-    picture_layer_tiling_->CreateTilesForTesting(PENDING_TREE);
+        1, gfx::Size(256 * 50, 256 * 50), &picture_layer_tiling_client_);
+    picture_layer_tiling_->CreateAllTilesForTesting();
   }
 
   virtual void TearDown() OVERRIDE {
@@ -76,7 +70,7 @@
     gfx::Size layer_bounds(50 * 256, 50 * 256);
     do {
       picture_layer_tiling_->UpdateTilePriorities(
-        PENDING_TREE,
+        ACTIVE_TREE,
         layer_bounds,
         gfx::Rect(layer_bounds),
         gfx::Rect(layer_bounds),
@@ -110,7 +104,7 @@
     const int maxOffsetCount = 1000;
     do {
       picture_layer_tiling_->UpdateTilePriorities(
-        PENDING_TREE,
+        ACTIVE_TREE,
         viewport_size,
         viewport_rect,
         gfx::Rect(layer_bounds),
@@ -140,9 +134,7 @@
   }
 
  private:
-  FakeTileManagerClient tile_manager_client_;
-  scoped_ptr<FakeTileManager> tile_manager_;
-  scoped_ptr<FakePictureLayerTilingClient> picture_layer_tiling_client_;
+  FakePictureLayerTilingClient picture_layer_tiling_client_;
   scoped_ptr<PictureLayerTiling> picture_layer_tiling_;
 
   base::TimeTicks start_time_;
diff --git a/cc/resources/picture_layer_tiling_set.cc b/cc/resources/picture_layer_tiling_set.cc
index 654b180..5ad2650 100644
--- a/cc/resources/picture_layer_tiling_set.cc
+++ b/cc/resources/picture_layer_tiling_set.cc
@@ -212,12 +212,6 @@
   return *tiling_iter_;
 }
 
-TilePriority PictureLayerTilingSet::CoverageIterator::priority() {
-  if (!tiling_iter_)
-    return TilePriority();
-  return tiling_iter_.priority();
-}
-
 PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() {
   if (current_tiling_ < 0)
     return NULL;
diff --git a/cc/resources/picture_layer_tiling_set.h b/cc/resources/picture_layer_tiling_set.h
index 29a3c58..29e6bf4 100644
--- a/cc/resources/picture_layer_tiling_set.h
+++ b/cc/resources/picture_layer_tiling_set.h
@@ -95,8 +95,6 @@
     Tile* operator->() const;
     Tile* operator*() const;
 
-    TilePriority priority();
-
     CoverageIterator& operator++();
     operator bool() const;
 
diff --git a/cc/resources/picture_layer_tiling_set_unittest.cc b/cc/resources/picture_layer_tiling_set_unittest.cc
index 0ab1c66..96129c6 100644
--- a/cc/resources/picture_layer_tiling_set_unittest.cc
+++ b/cc/resources/picture_layer_tiling_set_unittest.cc
@@ -12,7 +12,6 @@
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_picture_layer_tiling_client.h"
-#include "cc/test/fake_tile_manager.h"
 #include "cc/test/fake_tile_manager_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/size_conversions.h"
@@ -21,9 +20,7 @@
 namespace {
 
 TEST(PictureLayerTilingSetTest, NoResources) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   gfx::Size layer_bounds(1000, 800);
   PictureLayerTilingSet set(&client, layer_bounds);
   client.SetTileSize(gfx::Size(256, 256));
@@ -71,10 +68,7 @@
     scoped_ptr<ResourceProvider> resource_provider =
         ResourceProvider::Create(output_surface.get(), NULL, 0, false, 1);
 
-    FakeTileManagerClient tile_manager_client;
-    FakeTileManager tile_manager(&tile_manager_client, resource_provider.get());
-
-    FakePictureLayerTilingClient client(&tile_manager);
+    FakePictureLayerTilingClient client(resource_provider.get());
     client.SetTileSize(gfx::Size(256, 256));
     gfx::Size layer_bounds(1000, 800);
     PictureLayerTilingSet set(&client, layer_bounds);
@@ -156,24 +150,10 @@
       : tile_size_(gfx::Size(10, 10)),
         source_bounds_(gfx::Size(30, 20)),
         target_bounds_(gfx::Size(30, 30)) {
-    output_surface_ = FakeOutputSurface::Create3d();
-    CHECK(output_surface_->BindToClient(&output_surface_client_));
-    resource_provider_ =
-        ResourceProvider::Create(output_surface_.get(), NULL, 0, false, 1);
-    tile_manager_ = make_scoped_ptr(
-        new FakeTileManager(&tile_manager_client_, resource_provider_.get()));
-    source_client_ =
-        make_scoped_ptr(new FakePictureLayerTilingClient(tile_manager_.get()));
-    target_client_ =
-        make_scoped_ptr(new FakePictureLayerTilingClient(tile_manager_.get()));
-
-    source_client_->SetTileSize(tile_size_);
-    target_client_->SetTileSize(tile_size_);
-
-    source_.reset(
-        new PictureLayerTilingSet(source_client_.get(), source_bounds_));
-    target_.reset(
-        new PictureLayerTilingSet(target_client_.get(), target_bounds_));
+    source_client_.SetTileSize(tile_size_);
+    target_client_.SetTileSize(tile_size_);
+    source_.reset(new PictureLayerTilingSet(&source_client_, source_bounds_));
+    target_.reset(new PictureLayerTilingSet(&target_client_, target_bounds_));
   }
 
   // Sync from source to target.
@@ -181,9 +161,9 @@
                    const Region& invalidation,
                    float minimum_scale) {
     for (size_t i = 0; i < source_->num_tilings(); ++i)
-      source_->tiling_at(i)->CreateTilesForTesting(ACTIVE_TREE);
+      source_->tiling_at(i)->CreateAllTilesForTesting();
     for (size_t i = 0; i < target_->num_tilings(); ++i)
-      target_->tiling_at(i)->CreateTilesForTesting(PENDING_TREE);
+      target_->tiling_at(i)->CreateAllTilesForTesting();
 
     target_->SyncTilings(
         *source_.get(), new_bounds, invalidation, minimum_scale);
@@ -215,8 +195,8 @@
                 target_tiling->contents_scale());
     }
 
-    EXPECT_EQ(source_->client(), source_client_.get());
-    EXPECT_EQ(target_->client(), target_client_.get());
+    EXPECT_EQ(source_->client(), &source_client_);
+    EXPECT_EQ(target_->client(), &target_client_);
     ValidateTargetTilingSet();
   }
 
@@ -232,7 +212,7 @@
     }
 
     for (size_t i = 0; i < target_->num_tilings(); ++i)
-      ValidateTiling(target_->tiling_at(i), target_client_->pile());
+      ValidateTiling(target_->tiling_at(i), target_client_.pile());
   }
 
   void ValidateTiling(const PictureLayerTiling* tiling,
@@ -242,7 +222,7 @@
     else if (!tiling->live_tiles_rect().IsEmpty())
       EXPECT_TRUE(tiling->ContentRect().Contains(tiling->live_tiles_rect()));
 
-    std::vector<Tile*> tiles = tiling->TilesForTesting(PENDING_TREE);
+    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
     for (size_t i = 0; i < tiles.size(); ++i) {
       const Tile* tile = tiles[i];
       ASSERT_TRUE(!!tile);
@@ -259,19 +239,13 @@
     }
   }
 
-  scoped_ptr<FakeOutputSurface> output_surface_;
-  FakeOutputSurfaceClient output_surface_client_;
-
   gfx::Size tile_size_;
-  scoped_ptr<ResourceProvider> resource_provider_;
-  scoped_ptr<FakeTileManager> tile_manager_;
-  FakeTileManagerClient tile_manager_client_;
 
-  scoped_ptr<FakePictureLayerTilingClient> source_client_;
+  FakePictureLayerTilingClient source_client_;
   gfx::Size source_bounds_;
   scoped_ptr<PictureLayerTilingSet> source_;
 
-  scoped_ptr<FakePictureLayerTilingClient> target_client_;
+  FakePictureLayerTilingClient target_client_;
   gfx::Size target_bounds_;
   scoped_ptr<PictureLayerTilingSet> target_;
 };
@@ -374,7 +348,7 @@
 TEST_F(PictureLayerTilingSetSyncTest, Invalidation) {
   source_->AddTiling(2.f);
   target_->AddTiling(2.f);
-  target_->tiling_at(0)->CreateTilesForTesting(PENDING_TREE);
+  target_->tiling_at(0)->CreateAllTilesForTesting();
 
   Region layer_invalidation;
   layer_invalidation.Union(gfx::Rect(0, 0, 1, 1));
@@ -418,7 +392,7 @@
       target_->tiling_at(0)->AllTilesForTesting();
   EXPECT_GT(original_tiles.size(), 0u);
   gfx::Size new_tile_size(100, 100);
-  target_client_->SetTileSize(new_tile_size);
+  target_client_.SetTileSize(new_tile_size);
   EXPECT_NE(target_->tiling_at(0)->tile_size().ToString(),
             new_tile_size.ToString());
 
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index 530ccc8..6adc611 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -5,13 +5,10 @@
 #include "cc/resources/picture_layer_tiling.h"
 
 #include <limits>
-#include <set>
 
 #include "cc/base/math_util.h"
 #include "cc/resources/picture_layer_tiling_set.h"
 #include "cc/test/fake_picture_layer_tiling_client.h"
-#include "cc/test/fake_tile_manager.h"
-#include "cc/test/fake_tile_manager_client.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/rect_conversions.h"
 #include "ui/gfx/size_conversions.h"
@@ -19,12 +16,6 @@
 namespace cc {
 namespace {
 
-const int kTileBundleWidth = 2;
-const int kTileBundleHeight = 2;
-std::pair<int, int> ComputeTileBundleIndex(int i, int j) {
-  return std::make_pair(i / kTileBundleWidth, j / kTileBundleHeight);
-}
-
 static gfx::Rect ViewportInLayerSpace(
     const gfx::Transform& transform,
     gfx::Size device_viewport) {
@@ -43,7 +34,6 @@
  public:
   using PictureLayerTiling::SetLiveTilesRect;
   using PictureLayerTiling::TileAt;
-  using PictureLayerTiling::TileBundleAt;
 
   static scoped_ptr<TestablePictureLayerTiling> Create(
       float contents_scale,
@@ -55,9 +45,6 @@
         client));
   }
 
-  TilingData tiling_data() const { return tiling_data_; }
-  TilingData bundle_tiling_data() const { return bundle_tiling_data_; }
-
  protected:
   TestablePictureLayerTiling(float contents_scale,
                              gfx::Size layer_bounds,
@@ -67,9 +54,7 @@
 
 class PictureLayerTilingIteratorTest : public testing::Test {
  public:
-  PictureLayerTilingIteratorTest()
-      : tile_manager_(&tile_manager_client_), client_(&tile_manager_) {}
-
+  PictureLayerTilingIteratorTest() {}
   virtual ~PictureLayerTilingIteratorTest() {}
 
   void Initialize(gfx::Size tile_size,
@@ -82,7 +67,6 @@
   }
 
   void SetLiveRectAndVerifyTiles(gfx::Rect live_tiles_rect) {
-    tiling_->SetTreeForTesting(ACTIVE_TREE);
     tiling_->SetLiveTilesRect(live_tiles_rect);
 
     std::vector<Tile*> tiles = tiling_->AllTilesForTesting();
@@ -169,8 +153,6 @@
   }
 
  protected:
-  FakeTileManagerClient tile_manager_client_;
-  FakeTileManager tile_manager_;
   FakePictureLayerTilingClient client_;
   scoped_ptr<TestablePictureLayerTiling> tiling_;
 
@@ -279,107 +261,6 @@
   VerifyTilesCoverNonContainedRect(0.5f, gfx::Rect(-1000, 100, 2000, 100));
 }
 
-TEST(PictureLayerTilingTest, BundleAtContainsTileAt) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
-
-  gfx::Size current_layer_bounds(400, 400);
-  client.SetTileSize(gfx::Size(100, 100));
-  scoped_ptr<TestablePictureLayerTiling> tiling =
-      TestablePictureLayerTiling::Create(1.0f, current_layer_bounds, &client);
-
-  tiling->CreateTilesForTesting(ACTIVE_TREE);
-  for (int bundle_y = 0;
-       bundle_y < (current_layer_bounds.height() / (kTileBundleHeight * 100));
-       ++bundle_y) {
-    for (int bundle_x = 0;
-         bundle_x < (current_layer_bounds.width() / (kTileBundleWidth * 100));
-         ++bundle_x) {
-      EXPECT_TRUE(tiling->TileBundleAt(bundle_x, bundle_y))
-          << "bundle_x " << bundle_x << " bundle_y " << bundle_y;
-
-      TileBundle* bundle = tiling->TileBundleAt(bundle_x, bundle_y);
-      for (int tile_y = 0; tile_y < kTileBundleWidth; ++tile_y) {
-        for (int tile_x = 0; tile_x < kTileBundleHeight; ++tile_x) {
-          int global_tile_x = bundle_x * kTileBundleWidth + tile_x;
-          int global_tile_y = bundle_y * kTileBundleHeight + tile_y;
-
-          EXPECT_TRUE(tiling->TileAt(ACTIVE_TREE, global_tile_x, global_tile_y))
-              << "x " << global_tile_x << " y " << global_tile_y;
-          EXPECT_EQ(tiling->TileAt(ACTIVE_TREE, global_tile_x, global_tile_y),
-                    bundle->TileAt(ACTIVE_TREE, global_tile_x, global_tile_y))
-              << "x " << global_tile_x << " y " << global_tile_y;
-        }
-      }
-    }
-  }
-}
-
-TEST(PictureLayerTilingTest, TilesCleanedUp) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
-  FakePictureLayerTilingClient twin_client(&tile_manager);
-
-  gfx::Size current_layer_bounds(400, 400);
-  client.SetTileSize(gfx::Size(100, 100));
-  twin_client.SetTileSize(gfx::Size(100, 100));
-  scoped_ptr<TestablePictureLayerTiling> tiling =
-      TestablePictureLayerTiling::Create(1.0f, current_layer_bounds, &client);
-  scoped_ptr<TestablePictureLayerTiling> twin_tiling =
-      TestablePictureLayerTiling::Create(
-          1.0f, current_layer_bounds, &twin_client);
-
-  client.set_twin_tiling(twin_tiling.get());
-  twin_client.set_twin_tiling(tiling.get());
-
-  tiling->CreateTilesForTesting(ACTIVE_TREE);
-  twin_tiling->CreateTilesForTesting(PENDING_TREE);
-  for (int tile_y = 0; tile_y < 4; ++tile_y) {
-    for (int tile_x = 0; tile_x < 4; ++tile_x) {
-      EXPECT_TRUE(tiling->TileAt(ACTIVE_TREE, tile_x, tile_y) ==
-                  twin_tiling->TileAt(ACTIVE_TREE, tile_x, tile_y));
-      EXPECT_TRUE(tiling->TileAt(PENDING_TREE, tile_x, tile_y) ==
-                  twin_tiling->TileAt(PENDING_TREE, tile_x, tile_y));
-    }
-  }
-
-  client.set_twin_tiling(NULL);
-  twin_tiling.reset();
-
-  for (int tile_y = 0; tile_y < 4; ++tile_y) {
-    for (int tile_x = 0; tile_x < 4; ++tile_x) {
-      EXPECT_TRUE(tiling->TileAt(ACTIVE_TREE, tile_x, tile_y) != NULL);
-      EXPECT_TRUE(tiling->TileAt(PENDING_TREE, tile_x, tile_y) == NULL);
-    }
-  }
-}
-
-TEST(PictureLayerTilingTest, DidBecomeActiveSwapsTiles) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
-
-  gfx::Size current_layer_bounds(400, 400);
-  client.SetTileSize(gfx::Size(100, 100));
-  scoped_ptr<TestablePictureLayerTiling> tiling =
-      TestablePictureLayerTiling::Create(1.0f, current_layer_bounds, &client);
-
-  tiling->CreateTilesForTesting(ACTIVE_TREE);
-  std::vector<Tile*> old_active_tiles = tiling->TilesForTesting(ACTIVE_TREE);
-  tiling->DidBecomeActive();
-  std::vector<Tile*> pending_tiles = tiling->TilesForTesting(PENDING_TREE);
-  EXPECT_EQ(old_active_tiles.size(), pending_tiles.size());
-  std::vector<Tile*>::const_iterator old_it = old_active_tiles.begin();
-  for (std::vector<Tile*>::const_iterator it = pending_tiles.begin();
-       it != pending_tiles.end();
-       ++it) {
-    EXPECT_EQ(*it, *old_it);
-    ++old_it;
-  }
-}
-
 TEST(PictureLayerTilingTest, ExpandRectEqual) {
   gfx::Rect in(40, 50, 100, 200);
   gfx::Rect bounds(-1000, -1000, 10000, 10000);
@@ -851,64 +732,11 @@
               base::Bind(&TileExists, true));
 }
 
-TEST_F(PictureLayerTilingIteratorTest, BundlesAndTilesAlign) {
-  Initialize(gfx::Size(100, 100), 1, gfx::Size(850, 850));
-  for (int y = -20; y <= 102; ++y) {
-    for (int x = 0; x <= 103; ++x) {
-      for (int size = 1; size <= 201; size += 50) {
-        gfx::Rect rect(x, y, size, size);
-
-        TilingData tiling_data = tiling_->tiling_data();
-
-        std::set<std::pair<int, int> > tile_positions;
-        std::set<std::pair<int, int> > predicted_bundle_positions;
-        size_t iteration_count = 0;
-        for (TilingData::Iterator iter(&tiling_data, rect); iter; ++iter) {
-          ++iteration_count;
-          tile_positions.insert(std::make_pair(iter.index_x(), iter.index_y()));
-          predicted_bundle_positions.insert(
-              ComputeTileBundleIndex(iter.index_x(), iter.index_y()));
-        }
-
-        ASSERT_EQ(tile_positions.size(), iteration_count) << rect.ToString();
-
-        TilingData bundle_tiling_data = tiling_->bundle_tiling_data();
-        std::set<std::pair<int, int> > bundle_positions;
-        iteration_count = 0;
-        for (TilingData::Iterator iter(&bundle_tiling_data, rect);
-             iter;
-             ++iter) {
-          ++iteration_count;
-          bundle_positions.insert(
-              std::make_pair(iter.index_x(), iter.index_y()));
-        }
-
-        ASSERT_EQ(bundle_positions.size(), iteration_count) << rect.ToString();
-        ASSERT_EQ(predicted_bundle_positions.size(), iteration_count)
-            << rect.ToString();
-
-        std::set<std::pair<int, int> >::const_iterator predicted_iterator =
-            predicted_bundle_positions.begin();
-        for (std::set<std::pair<int, int> >::const_iterator actual_iterator =
-                 bundle_positions.begin();
-             actual_iterator != bundle_positions.end();
-             ++actual_iterator) {
-          ASSERT_EQ(*actual_iterator, *predicted_iterator) << rect.ToString();
-          ++predicted_iterator;
-        }
-      }
-    }
-  }
-}
-
-
 TEST(UpdateTilePrioritiesTest, VisibleTiles) {
   // The TilePriority of visible tiles should have zero distance_to_visible
   // and time_to_visible.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
@@ -944,13 +772,24 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 0, 0));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 0, 1));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 1, 0));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 1, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
+  EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
+  EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+  EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
+  EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
+
+  priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
   EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
 }
@@ -959,15 +798,13 @@
   // The TilePriority of offscreen tiles (without movement) should have nonzero
   // distance_to_visible and infinite time_to_visible.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
   gfx::Rect visible_layer_rect(0, 0, 0, 0);  // offscreen; nothing is visible.
-  gfx::Size last_layer_bounds(400, 400);
-  gfx::Size current_layer_bounds(400, 400);
+  gfx::Size last_layer_bounds(200, 200);
+  gfx::Size current_layer_bounds(200, 200);
   float last_layer_contents_scale = 1.f;
   float current_layer_contents_scale = 1.f;
   gfx::Transform last_screen_transform;
@@ -1000,34 +837,40 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 0, 0));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 0, 1));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 1, 0));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 1, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 2, 2));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 2, 3));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 3, 2));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 3, 3));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 1));
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+  EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
+  EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
+                  priority.time_to_visible_in_seconds);
 
-  // Furthermore, in this scenario bundles on the right hand side should have a
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+  EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
+  EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
+                  priority.time_to_visible_in_seconds);
+
+  priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
+  EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
+  EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
+                  priority.time_to_visible_in_seconds);
+
+  // Furthermore, in this scenario tiles on the right hand side should have a
   // larger distance to visible.
-  TilePriority left = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
-  TilePriority right = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+  TilePriority right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(right.distance_to_visible_in_pixels,
             left.distance_to_visible_in_pixels);
 
-  left = tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
-  right = tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+  right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(right.distance_to_visible_in_pixels,
             left.distance_to_visible_in_pixels);
 }
@@ -1036,15 +879,13 @@
   // Sanity check that a layer with some tiles visible and others offscreen has
   // correct TilePriorities for each tile.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
   gfx::Rect visible_layer_rect(0, 0, 100, 100);  // only top quarter.
-  gfx::Size last_layer_bounds(400, 400);
-  gfx::Size current_layer_bounds(400, 400);
+  gfx::Size last_layer_bounds(200, 200);
+  gfx::Size current_layer_bounds(200, 200);
   float last_layer_contents_scale = 1.f;
   float current_layer_contents_scale = 1.f;
   gfx::Transform last_screen_transform;
@@ -1077,30 +918,26 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 0, 0));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 0, 1));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 1, 0));
-  ASSERT_TRUE(tiling->TileAt(ACTIVE_TREE, 1, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 1));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
   EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
   EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
@@ -1111,15 +948,13 @@
   // that UpdateTilePriorities correctly accounts for the transform between
   // layer space and screen space.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
   gfx::Rect visible_layer_rect(0, 0, 100, 100);  // only top-left quarter.
-  gfx::Size last_layer_bounds(400, 400);
-  gfx::Size current_layer_bounds(400, 400);
+  gfx::Size last_layer_bounds(200, 200);
+  gfx::Size current_layer_bounds(200, 200);
   float last_layer_contents_scale = 1.f;
   float current_layer_contents_scale = 1.f;
   gfx::Transform last_screen_transform;
@@ -1155,38 +990,36 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 1));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
   EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
   EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
   // Furthermore, in this scenario the bottom-right tile should have the larger
   // distance to visible.
-  TilePriority top_left = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
-  TilePriority top_right = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
-  TilePriority bottom_left =
-      tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
-  TilePriority bottom_right =
-      tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  TilePriority top_left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+  TilePriority top_right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+  TilePriority bottom_left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+  TilePriority bottom_right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(top_right.distance_to_visible_in_pixels,
             top_left.distance_to_visible_in_pixels);
   EXPECT_GT(bottom_left.distance_to_visible_in_pixels,
@@ -1202,15 +1035,13 @@
   // Perspective transforms need to take a different code path.
   // This test checks tile priorities of a perspective layer.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
   gfx::Rect visible_layer_rect(0, 0, 0, 0);  // offscreen.
-  gfx::Size last_layer_bounds(400, 400);
-  gfx::Size current_layer_bounds(400, 400);
+  gfx::Size last_layer_bounds(200, 200);
+  gfx::Size current_layer_bounds(200, 200);
   float last_layer_contents_scale = 1.f;
   float current_layer_contents_scale = 1.f;
   gfx::Transform last_screen_transform;
@@ -1261,29 +1092,29 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 1));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
   // All tiles will have a positive distance_to_visible
   // and an infinite time_to_visible.
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
@@ -1291,12 +1122,10 @@
   // Furthermore, in this scenario the top-left distance_to_visible
   // will be smallest, followed by top-right. The bottom layers
   // will of course be further than the top layers.
-  TilePriority top_left = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
-  TilePriority top_right = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
-  TilePriority bottom_left =
-      tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
-  TilePriority bottom_right =
-      tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  TilePriority top_left = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
+  TilePriority top_right = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
+  TilePriority bottom_left = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
+  TilePriority bottom_right = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(top_right.distance_to_visible_in_pixels,
             top_left.distance_to_visible_in_pixels);
 
@@ -1311,15 +1140,13 @@
   // Perspective transforms need to take a different code path.
   // This test checks tile priorities of a perspective layer.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
   gfx::Rect visible_layer_rect(0, 0, 0, 0);  // offscreen.
-  gfx::Size last_layer_bounds(400, 400);
-  gfx::Size current_layer_bounds(400, 400);
+  gfx::Size last_layer_bounds(200, 200);
+  gfx::Size current_layer_bounds(200, 200);
   float last_layer_contents_scale = 1.f;
   float current_layer_contents_scale = 1.f;
   gfx::Transform last_screen_transform;
@@ -1335,22 +1162,22 @@
   // Translate layer to offscreen
   current_screen_transform.Translate(400.0, 970.0);
   // Apply perspective and rotation about the center of the layer
-  current_screen_transform.Translate(200.0, 200.0);
+  current_screen_transform.Translate(100.0, 100.0);
   current_screen_transform.ApplyPerspectiveDepth(10.0);
   current_screen_transform.RotateAboutYAxis(10.0);
-  current_screen_transform.Translate(-200.0, -200.0);
+  current_screen_transform.Translate(-100.0, -100.0);
   last_screen_transform = current_screen_transform;
 
   // Sanity check that this transform does cause w<0 clipping for the left side
   // of the layer, but not the right side.
   bool clipped;
   MathUtil::MapQuad(current_screen_transform,
-                    gfx::QuadF(gfx::RectF(0, 0, 200, 400)),
+                    gfx::QuadF(gfx::RectF(0, 0, 100, 200)),
                     &clipped);
   ASSERT_TRUE(clipped);
 
   MathUtil::MapQuad(current_screen_transform,
-                    gfx::QuadF(gfx::RectF(200, 0, 200, 400)),
+                    gfx::QuadF(gfx::RectF(100, 0, 100, 200)),
                     &clipped);
   ASSERT_FALSE(clipped);
 
@@ -1376,29 +1203,29 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 1));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
   // Left-side tiles will be clipped by the transform, so we have to assume
   // they are visible just in case.
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
   EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
   EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
   EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
   EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
 
   // Right-side tiles will have a positive distance_to_visible
   // and an infinite time_to_visible.
-  priority = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
@@ -1408,9 +1235,7 @@
   // Test that time_to_visible is computed correctly when
   // there is some motion.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
@@ -1432,7 +1257,7 @@
   gfx::Rect viewport_in_layer_space = ViewportInLayerSpace(
       current_screen_transform, device_viewport);
 
-  client.SetTileSize(gfx::Size(50, 50));
+  client.SetTileSize(gfx::Size(100, 100));
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
                                               current_layer_bounds,
                                               &client);
@@ -1467,32 +1292,31 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 1));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(1.f,
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(1.f,
                   priority.time_to_visible_in_seconds);
 
-  // time_to_visible for the right hand side layers needs an extra 0.097
-  // seconds because this bundle is
-  // |(50 - 2 * border_texels) * 2 + border_texels| = 97 pixels further away.
-  priority = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
+  // time_to_visible for the right hand side layers needs an extra 0.099
+  // seconds because this tile is 99 pixels further away.
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
-  EXPECT_FLOAT_EQ(1.097f,
+  EXPECT_FLOAT_EQ(1.099f,
                   priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(1, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
-  EXPECT_FLOAT_EQ(1.097f,
+  EXPECT_FLOAT_EQ(1.099f,
                   priority.time_to_visible_in_seconds);
 }
 
@@ -1501,9 +1325,7 @@
   // that UpdateTilePriorities correctly accounts for the transform between
   // layer space and screen space.
 
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  FakePictureLayerTilingClient client(&tile_manager);
+  FakePictureLayerTilingClient client;
   scoped_ptr<TestablePictureLayerTiling> tiling;
 
   gfx::Size device_viewport(800, 600);
@@ -1533,7 +1355,7 @@
   gfx::Rect viewport_in_layer_space = ViewportInLayerSpace(
       current_screen_transform, device_viewport);
 
-  client.SetTileSize(gfx::Size(50, 50));
+  client.SetTileSize(gfx::Size(100, 100));
   tiling = TestablePictureLayerTiling::Create(1.0f,  // contents_scale
                                               current_layer_bounds,
                                               &client);
@@ -1568,20 +1390,20 @@
       current_frame_time_in_seconds,
       max_tiles_for_interest_area);
 
-  ASSERT_TRUE(tiling->TileBundleAt(0, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(0, 1));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 0));
-  ASSERT_TRUE(tiling->TileBundleAt(1, 1));
+  ASSERT_TRUE(tiling->TileAt(0, 0));
+  ASSERT_TRUE(tiling->TileAt(0, 1));
+  ASSERT_TRUE(tiling->TileAt(1, 0));
+  ASSERT_TRUE(tiling->TileAt(1, 1));
 
-  TilePriority priority = tiling->TileBundleAt(0, 0)->GetPriority(ACTIVE_TREE);
+  TilePriority priority = tiling->TileAt(0, 0)->priority(ACTIVE_TREE);
   EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible_in_pixels);
   EXPECT_FLOAT_EQ(0.f, priority.time_to_visible_in_seconds);
 
-  priority = tiling->TileBundleAt(0, 1)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(0, 1)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_GT(priority.time_to_visible_in_seconds, 0.f);
 
-  priority = tiling->TileBundleAt(1, 0)->GetPriority(ACTIVE_TREE);
+  priority = tiling->TileAt(1, 0)->priority(ACTIVE_TREE);
   EXPECT_GT(priority.distance_to_visible_in_pixels, 0.f);
   EXPECT_FLOAT_EQ(std::numeric_limits<float>::infinity(),
                   priority.time_to_visible_in_seconds);
diff --git a/cc/resources/prioritized_resource_manager.cc b/cc/resources/prioritized_resource_manager.cc
index 43d4f52..da8f055 100644
--- a/cc/resources/prioritized_resource_manager.cc
+++ b/cc/resources/prioritized_resource_manager.cc
@@ -326,10 +326,14 @@
       continue;
     wasted_memory += (*it)->bytes();
   }
-  size_t ten_percent_of_memory = memory_available_bytes_ / 10;
-  if (wasted_memory > ten_percent_of_memory)
+  size_t wasted_memory_to_allow = memory_available_bytes_ / 10;
+  // If the external priority cutoff indicates that unused memory should be
+  // freed, then do not allow any memory for texture recycling.
+  if (external_priority_cutoff_ != PriorityCalculator::AllowEverythingCutoff())
+    wasted_memory_to_allow = 0;
+  if (wasted_memory > wasted_memory_to_allow)
     EvictBackingsToReduceMemory(MemoryUseBytes() -
-                                (wasted_memory - ten_percent_of_memory),
+                                (wasted_memory - wasted_memory_to_allow),
                                 PriorityCalculator::AllowEverythingCutoff(),
                                 EVICT_ONLY_RECYCLABLE,
                                 DO_NOT_UNLINK_BACKINGS,
diff --git a/cc/resources/prioritized_tile_set_unittest.cc b/cc/resources/prioritized_tile_set_unittest.cc
index 4526341..b51eb00 100644
--- a/cc/resources/prioritized_tile_set_unittest.cc
+++ b/cc/resources/prioritized_tile_set_unittest.cc
@@ -8,7 +8,6 @@
 #include "cc/resources/managed_tile_state.h"
 #include "cc/resources/prioritized_tile_set.h"
 #include "cc/resources/tile.h"
-#include "cc/resources/tile_bundle.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_picture_pile_impl.h"
@@ -79,18 +78,6 @@
                                      Tile::USE_LCD_TEXT);
   }
 
-  scoped_refptr<Tile> CreateTileWithPriority(
-      const TilePriority& priority) {
-    scoped_refptr<TileBundle> bundle =
-        tile_manager_->CreateTileBundle(0, 0, 1, 1);
-    scoped_refptr<Tile> tile = CreateTile();
-    bundle->AddTileAt(ACTIVE_TREE, 0, 0, tile);
-    bundle->AddTileAt(PENDING_TREE, 0, 0, tile);
-    bundle->SetPriority(ACTIVE_TREE, priority);
-    bundle->SetPriority(PENDING_TREE, priority);
-    return tile;
-  }
-
  private:
   LayerTreeSettings settings_;
   FakeOutputSurfaceClient output_surface_client_;
@@ -136,7 +123,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, NOW_AND_READY_TO_DRAW_BIN);
     }
@@ -166,7 +155,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, NOW_BIN);
     }
@@ -198,7 +189,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, SOON_BIN);
     }
@@ -231,7 +224,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, SOON_BIN);
     }
@@ -260,7 +255,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, EVENTUALLY_AND_ACTIVE_BIN);
     }
@@ -292,7 +289,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, EVENTUALLY_BIN);
     }
@@ -324,7 +323,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, AT_LAST_AND_ACTIVE_BIN);
     }
@@ -356,7 +357,9 @@
   std::vector<scoped_refptr<Tile> > tiles;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
       tiles.push_back(tile);
       set.InsertTile(tile, AT_LAST_BIN);
     }
@@ -436,7 +439,9 @@
   PrioritizedTileSet set;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
 
       now_and_ready_to_draw_bins.push_back(tile);
       now_bins.push_back(tile);
@@ -545,7 +550,9 @@
   PrioritizedTileSet set;
   for (int priority = 0; priority < 4; ++priority) {
     for (int i = 0; i < 5; ++i) {
-      scoped_refptr<Tile> tile = CreateTileWithPriority(priorities[priority]);
+      scoped_refptr<Tile> tile = CreateTile();
+      tile->SetPriority(ACTIVE_TREE, priorities[priority]);
+      tile->SetPriority(PENDING_TREE, priorities[priority]);
 
       now_and_ready_to_draw_bins.push_back(tile);
       now_bins.push_back(tile);
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index c9ec154..2097806 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -31,8 +31,6 @@
     layer_id_(layer_id),
     source_frame_number_(source_frame_number),
     flags_(flags),
-    required_for_activation_(false),
-    is_visible_(false),
     id_(s_next_id_++) {
   set_picture_pile(picture_pile);
 }
@@ -43,11 +41,19 @@
       "cc::Tile", this);
 }
 
-void Tile::MarkRequiredForActivation() {
-  if (required_for_activation_)
+void Tile::SetPriority(WhichTree tree, const TilePriority& priority) {
+  if (priority == priority_[tree])
     return;
 
-  required_for_activation_ = true;
+  priority_[tree] = priority;
+  tile_manager_->DidChangeTilePriority(this);
+}
+
+void Tile::MarkRequiredForActivation() {
+  if (priority_[PENDING_TREE].required_for_activation)
+    return;
+
+  priority_[PENDING_TREE].required_for_activation = true;
   tile_manager_->DidChangeTilePriority(this);
 }
 
@@ -60,10 +66,11 @@
   res->SetDouble("contents_scale", contents_scale_);
   res->Set("content_rect", MathUtil::AsValue(content_rect_).release());
   res->SetInteger("layer_id", layer_id_);
+  res->Set("active_priority", priority_[ACTIVE_TREE].AsValue().release());
+  res->Set("pending_priority", priority_[PENDING_TREE].AsValue().release());
   res->Set("managed_state", managed_state_.AsValue().release());
   res->SetBoolean("can_use_lcd_text", can_use_lcd_text());
   res->SetBoolean("use_gpu_rasterization", use_gpu_rasterization());
-  res->SetBoolean("required_for_activation", required_for_activation_);
   return res.PassAs<base::Value>();
 }
 
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index 548d9c9..e7c9636 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -11,7 +11,7 @@
 #include "cc/base/ref_counted_managed.h"
 #include "cc/resources/managed_tile_state.h"
 #include "cc/resources/raster_mode.h"
-#include "cc/resources/tile_bundle.h"
+#include "cc/resources/tile_priority.h"
 #include "ui/gfx/rect.h"
 #include "ui/gfx/size.h"
 
@@ -40,10 +40,21 @@
     return picture_pile_.get();
   }
 
+  const TilePriority& priority(WhichTree tree) const {
+    return priority_[tree];
+  }
+
+  TilePriority combined_priority() const {
+    return TilePriority(priority_[ACTIVE_TREE],
+                        priority_[PENDING_TREE]);
+  }
+
+  void SetPriority(WhichTree tree, const TilePriority& priority);
+
   void MarkRequiredForActivation();
 
   bool required_for_activation() const {
-    return required_for_activation_;
+    return priority_[PENDING_TREE].required_for_activation;
   }
 
   void set_can_use_lcd_text(bool can_use_lcd_text) {
@@ -68,14 +79,6 @@
     return !!(flags_ & USE_GPU_RASTERIZATION);
   }
 
-  bool is_visible() const {
-    return is_visible_;
-  }
-
-  void set_is_visible(bool is_visible) {
-    is_visible_ = is_visible;
-  }
-
   scoped_ptr<base::Value> AsValue() const;
 
   inline bool IsReadyToDraw() const {
@@ -151,12 +154,11 @@
   float contents_scale_;
   gfx::Rect opaque_rect_;
 
+  TilePriority priority_[NUM_TREES];
   ManagedTileState managed_state_;
   int layer_id_;
   int source_frame_number_;
   int flags_;
-  bool required_for_activation_;
-  bool is_visible_;
 
   Id id_;
   static Id s_next_id_;
diff --git a/cc/resources/tile_bundle.cc b/cc/resources/tile_bundle.cc
deleted file mode 100644
index e99b9f2..0000000
--- a/cc/resources/tile_bundle.cc
+++ /dev/null
@@ -1,181 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/tile_bundle.h"
-
-#include <algorithm>
-
-#include "cc/resources/picture_layer_tiling.h"
-#include "cc/resources/tile.h"
-#include "cc/resources/tile_manager.h"
-
-namespace cc {
-
-TileBundle::Id TileBundle::s_next_id_ = 0;
-
-TileBundle::TileBundle(TileManager* tile_manager,
-                       int offset_x,
-                       int offset_y,
-                       int width,
-                       int height)
-    : RefCountedManaged<TileBundle>(tile_manager),
-      tile_manager_(tile_manager),
-      index_offset_x_(offset_x),
-      index_offset_y_(offset_y),
-      index_count_x_(width),
-      index_count_y_(height),
-      conservative_tile_count_(0),
-      needs_tile_swap_(false),
-      id_(s_next_id_++) {
-  tiles_[ACTIVE_TREE].resize(index_count_y_);
-  for (int i = 0; i < index_count_y_; ++i)
-    tiles_[ACTIVE_TREE][i].resize(index_count_x_);
-
-  tiles_[PENDING_TREE].resize(index_count_y_);
-  for (int i = 0; i < index_count_y_; ++i)
-    tiles_[PENDING_TREE][i].resize(index_count_x_);
-}
-
-TileBundle::~TileBundle() {}
-
-Tile* TileBundle::TileAt(WhichTree tree, int index_x, int index_y) {
-  DCHECK(!needs_tile_swap_);
-
-  UpdateToLocalIndex(&index_x, &index_y);
-  return TileAtLocalIndex(tree, index_x, index_y);
-}
-
-Tile* TileBundle::TileAtLocalIndex(WhichTree tree, int index_x, int index_y) {
-  return tiles_[tree][index_y][index_x].get();
-}
-
-void TileBundle::SetPriority(WhichTree tree, const TilePriority& priority) {
-  DCHECK(!needs_tile_swap_);
-
-  if (priority_[tree] == priority)
-    return;
-
-  priority_[tree] = priority;
-  tile_manager_->DidChangeTileBundlePriority(this);
-}
-
-TilePriority TileBundle::GetPriority(WhichTree tree) const {
-  return priority_[tree];
-}
-
-bool TileBundle::RemoveTileAt(WhichTree tree, int index_x, int index_y) {
-  DCHECK(!needs_tile_swap_);
-
-  UpdateToLocalIndex(&index_x, &index_y);
-  bool removed = !!tiles_[tree][index_y][index_x];
-  tiles_[tree][index_y][index_x] = NULL;
-  if (removed)
-    --conservative_tile_count_;
-  return removed;
-}
-
-void TileBundle::AddTileAt(WhichTree tree,
-                           int index_x,
-                           int index_y,
-                           scoped_refptr<Tile> tile) {
-  DCHECK(!needs_tile_swap_);
-
-  UpdateToLocalIndex(&index_x, &index_y);
-  DCHECK(!tiles_[tree][index_y][index_x]);
-  tiles_[tree][index_y][index_x] = tile;
-  ++conservative_tile_count_;
-}
-
-void TileBundle::DidBecomeRecycled() {
-  priority_[ACTIVE_TREE] = TilePriority();
-  needs_tile_swap_ = !needs_tile_swap_;
-}
-
-void TileBundle::DidBecomeActive() {
-  priority_[ACTIVE_TREE] = priority_[PENDING_TREE];
-  priority_[PENDING_TREE] = TilePriority();
-  tiles_[ACTIVE_TREE].swap(tiles_[PENDING_TREE]);
-  needs_tile_swap_ = false;
-}
-
-void TileBundle::UpdateToLocalIndex(int* index_x, int* index_y) {
-  DCHECK(index_x);
-  DCHECK(index_y);
-
-  *index_x -= index_offset_x_;
-  *index_y -= index_offset_y_;
-
-  DCHECK_GE(*index_x, 0);
-  DCHECK_GE(*index_y, 0);
-  DCHECK_LT(*index_x, index_count_x_);
-  DCHECK_LT(*index_x, index_count_y_);
-}
-
-void TileBundle::SwapTilesIfRequired() {
-  if (!needs_tile_swap_)
-    return;
-
-  std::swap(priority_[ACTIVE_TREE], priority_[PENDING_TREE]);
-  tiles_[ACTIVE_TREE].swap(tiles_[PENDING_TREE]);
-  needs_tile_swap_ = false;
-}
-
-TileBundle::Iterator::Iterator(TileBundle* bundle)
-    : bundle_(bundle),
-      current_tile_(NULL),
-      index_x_(0),
-      index_y_(0),
-      current_tree_(ACTIVE_TREE),
-      min_tree_(ACTIVE_TREE),
-      max_tree_(PENDING_TREE) {
-  if (!InitializeNewTile())
-    ++(*this);
-}
-
-TileBundle::Iterator::Iterator(TileBundle* bundle, WhichTree tree)
-    : bundle_(bundle),
-      current_tile_(NULL),
-      index_x_(0),
-      index_y_(0),
-      current_tree_(tree),
-      min_tree_(tree),
-      max_tree_(tree) {
-  if (!InitializeNewTile())
-    ++(*this);
-}
-
-TileBundle::Iterator::~Iterator() {}
-
-TileBundle::Iterator& TileBundle::Iterator::operator++() {
-  do {
-    current_tree_ = static_cast<WhichTree>(current_tree_ + 1);
-    if (current_tree_ > max_tree_) {
-      current_tree_ = min_tree_;
-      ++index_x_;
-      if (index_x_ >= bundle_->index_count_x_) {
-        index_x_ = 0;
-        ++index_y_;
-        if (index_y_ >= bundle_->index_count_y_)
-          break;
-      }
-    }
-  } while (!InitializeNewTile());
-
-  return *this;
-}
-
-bool TileBundle::Iterator::InitializeNewTile() {
-  Tile* tile = bundle_->TileAtLocalIndex(current_tree_, index_x_, index_y_);
-
-  // We succeed only if we have a tile and it is different
-  // from what we currently have. This is to avoid the iterator
-  // returning the same tile twice when it's shared between trees.
-  if (!tile || tile == current_tile_)
-    return false;
-
-  current_tile_ = tile;
-  return true;
-}
-
-}  // namespace cc
diff --git a/cc/resources/tile_bundle.h b/cc/resources/tile_bundle.h
deleted file mode 100644
index ba113df..0000000
--- a/cc/resources/tile_bundle.h
+++ /dev/null
@@ -1,115 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CC_RESOURCES_TILE_BUNDLE_H_
-#define CC_RESOURCES_TILE_BUNDLE_H_
-
-#include <utility>
-#include <vector>
-
-#include "base/memory/ref_counted.h"
-#include "cc/base/ref_counted_managed.h"
-#include "cc/resources/tile_priority.h"
-
-namespace cc {
-
-class TileManager;
-class Tile;
-class PictureLayerTiling;
-
-class CC_EXPORT TileBundle : public RefCountedManaged<TileBundle> {
- public:
-  typedef uint64 Id;
-  typedef std::vector<scoped_refptr<Tile> > TileVector;
-  typedef std::vector<TileVector> TileGrid;
-
-  inline Id id() const { return id_; }
-
-  Tile* TileAt(WhichTree tree, int index_x, int index_y);
-  bool RemoveTileAt(WhichTree tree, int index_x, int index_y);
-  void AddTileAt(WhichTree tree,
-                 int index_x,
-                 int index_y,
-                 scoped_refptr<Tile> tile);
-  bool IsEmpty() const { return conservative_tile_count_ == 0; }
-
-  void DidBecomeRecycled();
-  void DidBecomeActive();
-
-  void SetPriority(WhichTree tree, const TilePriority& priority);
-  TilePriority GetPriority(WhichTree tree) const;
-
-  void SwapTilesIfRequired();
-
-  class CC_EXPORT Iterator {
-   public:
-    explicit Iterator(TileBundle* bundle);
-    Iterator(TileBundle* bundle, WhichTree tree);
-    ~Iterator();
-
-    Iterator& operator++();
-
-    inline Tile* operator*() { return current_tile_; }
-    inline Tile* operator->() { return current_tile_; }
-    inline operator bool() const {
-      return index_y_ < bundle_->index_count_y_;
-    }
-
-    inline int index_x() {
-      return index_x_ + bundle_->index_offset_x_;
-    }
-    inline int index_y() {
-      return index_y_ + bundle_->index_offset_y_;
-    }
-
-    TilePriority priority(WhichTree tree) const {
-      return bundle_->GetPriority(tree);
-    }
-
-   private:
-    bool InitializeNewTile();
-
-    TileBundle* bundle_;
-    Tile* current_tile_;
-    int index_x_;
-    int index_y_;
-    WhichTree current_tree_;
-
-    WhichTree min_tree_;
-    WhichTree max_tree_;
-  };
-
- private:
-  friend class TileManager;
-  friend class Iterator;
-
-  TileBundle(TileManager* tile_manager,
-             int offset_x,
-             int offset_y,
-             int width,
-             int height);
-  ~TileBundle();
-
-  void UpdateToLocalIndex(int* index_x, int* index_y);
-  Tile* TileAtLocalIndex(WhichTree tree, int x, int y);
-
-  TileManager* tile_manager_;
-
-  TileGrid tiles_[NUM_TREES];
-  int index_offset_x_;
-  int index_offset_y_;
-  int index_count_x_;
-  int index_count_y_;
-
-  TilePriority priority_[NUM_TREES];
-  int conservative_tile_count_;
-  bool needs_tile_swap_;
-
-  Id id_;
-  static Id s_next_id_;
-};
-
-}  // namespace cc
-
-#endif  // CC_RESOURCES_TILE_BUNDLE_H_
diff --git a/cc/resources/tile_bundle_unittest.cc b/cc/resources/tile_bundle_unittest.cc
deleted file mode 100644
index 268bdc4..0000000
--- a/cc/resources/tile_bundle_unittest.cc
+++ /dev/null
@@ -1,257 +0,0 @@
-// Copyright 2013 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "cc/resources/tile_bundle.h"
-
-#include <set>
-
-#include "cc/test/fake_picture_pile_impl.h"
-#include "cc/test/fake_tile_manager.h"
-#include "cc/test/fake_tile_manager_client.h"
-#include "testing/gtest/include/gtest/gtest.h"
-
-namespace cc {
-namespace {
-
-TEST(TileBundle, AddRemoveTile) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  scoped_refptr<PicturePileImpl> picture_pile =
-      FakePicturePileImpl::CreatePile();
-
-  scoped_refptr<Tile> tile = tile_manager.CreateTile(picture_pile.get(),
-                                                     gfx::Size(256, 256),
-                                                     gfx::Rect(),
-                                                     gfx::Rect(),
-                                                     1.0,
-                                                     0,
-                                                     0,
-                                                     true);
-  scoped_refptr<TileBundle> bundle = tile_manager.CreateTileBundle(0, 0, 2, 2);
-
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 1));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 1));
-  EXPECT_TRUE(bundle->IsEmpty());
-
-  bundle->AddTileAt(ACTIVE_TREE, 0, 1, tile);
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 0));
-  EXPECT_TRUE(bundle->TileAt(ACTIVE_TREE, 0, 1));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 1));
-  EXPECT_FALSE(bundle->IsEmpty());
-
-  bundle->AddTileAt(ACTIVE_TREE, 1, 1, tile);
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 0));
-  EXPECT_TRUE(bundle->TileAt(ACTIVE_TREE, 0, 1));
-  EXPECT_TRUE(bundle->TileAt(ACTIVE_TREE, 1, 1));
-  EXPECT_FALSE(bundle->IsEmpty());
-
-  bundle->RemoveTileAt(ACTIVE_TREE, 0, 1);
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 1));
-  EXPECT_TRUE(bundle->TileAt(ACTIVE_TREE, 1, 1));
-  EXPECT_FALSE(bundle->IsEmpty());
-
-  bundle->RemoveTileAt(ACTIVE_TREE, 0, 1);
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 1));
-  EXPECT_TRUE(bundle->TileAt(ACTIVE_TREE, 1, 1));
-  EXPECT_FALSE(bundle->IsEmpty());
-
-  bundle->RemoveTileAt(ACTIVE_TREE, 1, 1);
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 0));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 1));
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 1));
-  EXPECT_TRUE(bundle->IsEmpty());
-}
-
-TEST(TileBundle, DidBecomeActiveSwapsTiles) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  scoped_refptr<PicturePileImpl> picture_pile =
-      FakePicturePileImpl::CreatePile();
-
-  scoped_refptr<Tile> tile = tile_manager.CreateTile(picture_pile.get(),
-                                                     gfx::Size(256, 256),
-                                                     gfx::Rect(),
-                                                     gfx::Rect(),
-                                                     1.0,
-                                                     0,
-                                                     0,
-                                                     true);
-  scoped_refptr<Tile> other_tile = tile_manager.CreateTile(picture_pile.get(),
-                                                           gfx::Size(256, 256),
-                                                           gfx::Rect(),
-                                                           gfx::Rect(),
-                                                           1.0,
-                                                           0,
-                                                           0,
-                                                           true);
-
-  scoped_refptr<TileBundle> bundle = tile_manager.CreateTileBundle(0, 0, 2, 2);
-  bundle->AddTileAt(ACTIVE_TREE, 0, 0, tile);
-  bundle->AddTileAt(PENDING_TREE, 1, 1, other_tile);
-
-  EXPECT_EQ(bundle->TileAt(ACTIVE_TREE, 0, 0), tile.get());
-  EXPECT_EQ(bundle->TileAt(PENDING_TREE, 1, 1), other_tile.get());
-
-  bundle->DidBecomeActive();
-
-  EXPECT_EQ(bundle->TileAt(PENDING_TREE, 0, 0), tile.get());
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_EQ(bundle->TileAt(ACTIVE_TREE, 1, 1), other_tile.get());
-  EXPECT_FALSE(bundle->TileAt(PENDING_TREE, 1, 1));
-
-  bundle->SwapTilesIfRequired();
-
-  EXPECT_EQ(bundle->TileAt(PENDING_TREE, 0, 0), tile.get());
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_EQ(bundle->TileAt(ACTIVE_TREE, 1, 1), other_tile.get());
-  EXPECT_FALSE(bundle->TileAt(PENDING_TREE, 1, 1));
-}
-
-TEST(TileBundle, DidBecomeRecycledMarksTilesForSwap) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  scoped_refptr<PicturePileImpl> picture_pile =
-      FakePicturePileImpl::CreatePile();
-
-  scoped_refptr<Tile> tile = tile_manager.CreateTile(picture_pile.get(),
-                                                     gfx::Size(256, 256),
-                                                     gfx::Rect(),
-                                                     gfx::Rect(),
-                                                     1.0,
-                                                     0,
-                                                     0,
-                                                     true);
-  scoped_refptr<Tile> other_tile = tile_manager.CreateTile(picture_pile.get(),
-                                                           gfx::Size(256, 256),
-                                                           gfx::Rect(),
-                                                           gfx::Rect(),
-                                                           1.0,
-                                                           0,
-                                                           0,
-                                                           true);
-
-  scoped_refptr<TileBundle> bundle = tile_manager.CreateTileBundle(0, 0, 2, 2);
-  bundle->AddTileAt(ACTIVE_TREE, 0, 0, tile);
-  bundle->AddTileAt(PENDING_TREE, 1, 1, other_tile);
-
-  EXPECT_EQ(bundle->TileAt(ACTIVE_TREE, 0, 0), tile.get());
-  EXPECT_EQ(bundle->TileAt(PENDING_TREE, 1, 1), other_tile.get());
-
-  bundle->DidBecomeRecycled();
-  bundle->DidBecomeRecycled();
-
-  EXPECT_EQ(bundle->TileAt(ACTIVE_TREE, 0, 0), tile.get());
-  EXPECT_FALSE(bundle->TileAt(PENDING_TREE, 0, 0));
-  EXPECT_EQ(bundle->TileAt(PENDING_TREE, 1, 1), other_tile.get());
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 1, 1));
-
-  bundle->DidBecomeRecycled();
-  bundle->SwapTilesIfRequired();
-
-  EXPECT_EQ(bundle->TileAt(PENDING_TREE, 0, 0), tile.get());
-  EXPECT_FALSE(bundle->TileAt(ACTIVE_TREE, 0, 0));
-  EXPECT_EQ(bundle->TileAt(ACTIVE_TREE, 1, 1), other_tile.get());
-  EXPECT_FALSE(bundle->TileAt(PENDING_TREE, 1, 1));
-}
-
-TEST(TileBundle, EmptyIterator) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  scoped_refptr<TileBundle> bundle = tile_manager.CreateTileBundle(0, 0, 2, 2);
-
-  TileBundle::Iterator it(bundle.get());
-  EXPECT_FALSE(it);
-
-  TileBundle::Iterator active_it(bundle.get(), ACTIVE_TREE);
-  EXPECT_FALSE(active_it);
-
-  TileBundle::Iterator pending_it(bundle.get(), PENDING_TREE);
-  EXPECT_FALSE(pending_it);
-}
-
-TEST(TileBundle, NonEmptyIterator) {
-  FakeTileManagerClient tile_manager_client;
-  FakeTileManager tile_manager(&tile_manager_client);
-  scoped_refptr<PicturePileImpl> picture_pile =
-      FakePicturePileImpl::CreatePile();
-  scoped_refptr<TileBundle> bundle = tile_manager.CreateTileBundle(0, 0, 2, 2);
-
-  scoped_refptr<Tile> tile = tile_manager.CreateTile(picture_pile.get(),
-                                                     gfx::Size(256, 256),
-                                                     gfx::Rect(),
-                                                     gfx::Rect(),
-                                                     1.0,
-                                                     0,
-                                                     0,
-                                                     true);
-  scoped_refptr<Tile> other_tile = tile_manager.CreateTile(picture_pile.get(),
-                                                           gfx::Size(256, 256),
-                                                           gfx::Rect(),
-                                                           gfx::Rect(),
-                                                           1.0,
-                                                           0,
-                                                           0,
-                                                           true);
-  scoped_refptr<Tile> third_tile = tile_manager.CreateTile(picture_pile.get(),
-                                                           gfx::Size(256, 256),
-                                                           gfx::Rect(),
-                                                           gfx::Rect(),
-                                                           1.0,
-                                                           0,
-                                                           0,
-                                                           true);
-
-  bundle->AddTileAt(ACTIVE_TREE, 0, 0, tile);
-  bundle->AddTileAt(PENDING_TREE, 1, 1, other_tile);
-  bundle->AddTileAt(ACTIVE_TREE, 1, 1, third_tile);
-
-  TileBundle::Iterator it(bundle.get());
-  EXPECT_TRUE(it);
-  std::set<Tile*> tiles;
-  size_t count = 0;
-  while (it) {
-    tiles.insert(*it);
-    ++it;
-    ++count;
-  }
-
-  EXPECT_EQ(count, tiles.size());
-  EXPECT_TRUE(tiles.count(tile.get()));
-  EXPECT_TRUE(tiles.count(other_tile.get()));
-  EXPECT_TRUE(tiles.count(third_tile.get()));
-
-  TileBundle::Iterator active_it(bundle.get(), ACTIVE_TREE);
-  EXPECT_TRUE(active_it);
-  count = 0;
-  tiles.clear();
-  while (active_it) {
-    tiles.insert(*active_it);
-    ++active_it;
-    ++count;
-  }
-
-  EXPECT_EQ(count, tiles.size());
-  EXPECT_TRUE(tiles.count(tile.get()));
-  EXPECT_FALSE(tiles.count(other_tile.get()));
-  EXPECT_TRUE(tiles.count(third_tile.get()));
-
-  TileBundle::Iterator pending_it(bundle.get(), PENDING_TREE);
-  EXPECT_TRUE(pending_it);
-  EXPECT_EQ(*pending_it, other_tile.get());
-  ++pending_it;
-  EXPECT_FALSE(pending_it);
-}
-
-
-}  // namespace
-}  // namespace cc
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index 17f4525..2fbb6d1 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -224,7 +224,6 @@
   global_state_ = GlobalStateThatImpactsTilePriority();
 
   CleanUpReleasedTiles();
-  DCHECK_EQ(0u, bundles_.size());
   DCHECK_EQ(0u, tiles_.size());
 
   RasterWorkerPool::RasterTask::Queue empty;
@@ -244,35 +243,15 @@
   released_tiles_.push_back(tile);
 }
 
-void TileManager::Release(TileBundle* bundle) {
-  released_tile_bundles_.push_back(bundle);
-}
-
 void TileManager::DidChangeTilePriority(Tile* tile) {
   prioritized_tiles_dirty_ = true;
 }
 
-void TileManager::DidChangeTileBundlePriority(TileBundle* bundle) {
-  prioritized_tiles_dirty_ = true;
-}
-
 bool TileManager::ShouldForceTasksRequiredForActivationToComplete() const {
   return global_state_.tree_priority != SMOOTHNESS_TAKES_PRIORITY;
 }
 
 void TileManager::CleanUpReleasedTiles() {
-  // Clean up bundles first, since they might have tiles that will become
-  // released as well.
-  for (std::vector<TileBundle*>::iterator it = released_tile_bundles_.begin();
-       it != released_tile_bundles_.end();
-       ++it) {
-    TileBundle* bundle = *it;
-    DCHECK(bundles_.find(bundle->id()) != bundles_.end());
-    bundles_.erase(bundle->id());
-    delete bundle;
-  }
-  released_tile_bundles_.clear();
-
   for (std::vector<Tile*>::iterator it = released_tiles_.begin();
        it != released_tiles_.end();
        ++it) {
@@ -293,6 +272,7 @@
 
     delete tile;
   }
+
   released_tiles_.clear();
 }
 
@@ -378,130 +358,126 @@
   const TreePriority tree_priority = global_state_.tree_priority;
 
   // For each tree, bin into different categories of tiles.
-  for (TileBundleMap::iterator bundle_it = bundles_.begin();
-       bundle_it != bundles_.end();
-       ++bundle_it) {
-    for (TileBundle::Iterator it(bundle_it->second); it; ++it) {
-      Tile* tile = *it;
-      ManagedTileState& mts = tile->managed_state();
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    Tile* tile = it->second;
+    ManagedTileState& mts = tile->managed_state();
 
-      const ManagedTileState::TileVersion& tile_version =
-          tile->GetTileVersionForDrawing();
-      bool tile_is_ready_to_draw = tile_version.IsReadyToDraw();
-      bool tile_is_active =
-          tile_is_ready_to_draw ||
-          !mts.tile_versions[mts.raster_mode].raster_task_.is_null();
+    const ManagedTileState::TileVersion& tile_version =
+        tile->GetTileVersionForDrawing();
+    bool tile_is_ready_to_draw = tile_version.IsReadyToDraw();
+    bool tile_is_active =
+        tile_is_ready_to_draw ||
+        !mts.tile_versions[mts.raster_mode].raster_task_.is_null();
 
-      // Get the active priority and bin.
-      TilePriority active_priority = it.priority(ACTIVE_TREE);
-      ManagedTileBin active_bin = BinFromTilePriority(active_priority);
+    // Get the active priority and bin.
+    TilePriority active_priority = tile->priority(ACTIVE_TREE);
+    ManagedTileBin active_bin = BinFromTilePriority(active_priority);
 
-      // Get the pending priority and bin.
-      TilePriority pending_priority = it.priority(PENDING_TREE);
-      ManagedTileBin pending_bin = BinFromTilePriority(pending_priority);
+    // Get the pending priority and bin.
+    TilePriority pending_priority = tile->priority(PENDING_TREE);
+    ManagedTileBin pending_bin = BinFromTilePriority(pending_priority);
 
-      bool pending_is_low_res =
-          pending_priority.resolution == LOW_RESOLUTION;
-      bool pending_is_non_ideal =
-          pending_priority.resolution == NON_IDEAL_RESOLUTION;
-      bool active_is_non_ideal =
-          active_priority.resolution == NON_IDEAL_RESOLUTION;
+    bool pending_is_low_res =
+        pending_priority.resolution == LOW_RESOLUTION;
+    bool pending_is_non_ideal =
+        pending_priority.resolution == NON_IDEAL_RESOLUTION;
+    bool active_is_non_ideal =
+        active_priority.resolution == NON_IDEAL_RESOLUTION;
 
-      // Adjust pending bin state for low res tiles. This prevents
-      // pending tree low-res tiles from being initialized before
-      // high-res tiles.
-      if (pending_is_low_res)
-        pending_bin = std::max(pending_bin, EVENTUALLY_BIN);
+    // Adjust pending bin state for low res tiles. This prevents
+    // pending tree low-res tiles from being initialized before
+    // high-res tiles.
+    if (pending_is_low_res)
+      pending_bin = std::max(pending_bin, EVENTUALLY_BIN);
 
-      // Adjust bin state based on if ready to draw.
-      active_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][active_bin];
-      pending_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][pending_bin];
+    // Adjust bin state based on if ready to draw.
+    active_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][active_bin];
+    pending_bin = kBinReadyToDrawMap[tile_is_ready_to_draw][pending_bin];
 
-      // Adjust bin state based on if active.
-      active_bin = kBinIsActiveMap[tile_is_active][active_bin];
-      pending_bin = kBinIsActiveMap[tile_is_active][pending_bin];
+    // Adjust bin state based on if active.
+    active_bin = kBinIsActiveMap[tile_is_active][active_bin];
+    pending_bin = kBinIsActiveMap[tile_is_active][pending_bin];
 
-      // We never want to paint new non-ideal tiles, as we always have
-      // a high-res tile covering that content (paint that instead).
-      if (!tile_is_ready_to_draw && active_is_non_ideal)
-        active_bin = NEVER_BIN;
-      if (!tile_is_ready_to_draw && pending_is_non_ideal)
-        pending_bin = NEVER_BIN;
+    // We never want to paint new non-ideal tiles, as we always have
+    // a high-res tile covering that content (paint that instead).
+    if (!tile_is_ready_to_draw && active_is_non_ideal)
+      active_bin = NEVER_BIN;
+    if (!tile_is_ready_to_draw && pending_is_non_ideal)
+      pending_bin = NEVER_BIN;
 
-      // Compute combined bin.
-      ManagedTileBin combined_bin = std::min(active_bin, pending_bin);
+    // Compute combined bin.
+    ManagedTileBin combined_bin = std::min(active_bin, pending_bin);
 
-      ManagedTileBin tree_bin[NUM_TREES];
-      tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin];
-      tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin];
+    ManagedTileBin tree_bin[NUM_TREES];
+    tree_bin[ACTIVE_TREE] = kBinPolicyMap[memory_policy][active_bin];
+    tree_bin[PENDING_TREE] = kBinPolicyMap[memory_policy][pending_bin];
 
-      // The bin that the tile would have if the GPU memory manager had
-      // a maximally permissive policy, send to the GPU memory manager
-      // to determine policy.
-      ManagedTileBin gpu_memmgr_stats_bin = NEVER_BIN;
-      TilePriority tile_priority;
+    // The bin that the tile would have if the GPU memory manager had
+    // a maximally permissive policy, send to the GPU memory manager
+    // to determine policy.
+    ManagedTileBin gpu_memmgr_stats_bin = NEVER_BIN;
+    TilePriority tile_priority;
 
-      switch (tree_priority) {
-        case SAME_PRIORITY_FOR_BOTH_TREES:
-          mts.bin = kBinPolicyMap[memory_policy][combined_bin];
-          gpu_memmgr_stats_bin = combined_bin;
-          tile_priority = TilePriority(active_priority, pending_priority);
-          break;
-        case SMOOTHNESS_TAKES_PRIORITY:
-          mts.bin = tree_bin[ACTIVE_TREE];
-          gpu_memmgr_stats_bin = active_bin;
-          tile_priority = active_priority;
-          break;
-        case NEW_CONTENT_TAKES_PRIORITY:
-          mts.bin = tree_bin[PENDING_TREE];
-          gpu_memmgr_stats_bin = pending_bin;
-          tile_priority = pending_priority;
-          break;
-      }
-
-      if (!tile_is_ready_to_draw || tile_version.requires_resource()) {
-        if ((gpu_memmgr_stats_bin == NOW_BIN) ||
-            (gpu_memmgr_stats_bin == NOW_AND_READY_TO_DRAW_BIN))
-          memory_required_bytes_ += BytesConsumedIfAllocated(tile);
-        if (gpu_memmgr_stats_bin != NEVER_BIN)
-          memory_nice_to_have_bytes_ += BytesConsumedIfAllocated(tile);
-      }
-
-      // Bump up the priority if we determined it's NEVER_BIN on one tree,
-      // but is still required on the other tree.
-      bool is_in_never_bin_on_both_trees =
-          tree_bin[ACTIVE_TREE] == NEVER_BIN &&
-          tree_bin[PENDING_TREE] == NEVER_BIN;
-
-      if (mts.bin == NEVER_BIN && !is_in_never_bin_on_both_trees)
-        mts.bin = tile_is_active ? AT_LAST_AND_ACTIVE_BIN : AT_LAST_BIN;
-
-      mts.resolution = tile_priority.resolution;
-      mts.time_to_needed_in_seconds = tile_priority.time_to_visible_in_seconds;
-      mts.distance_to_visible_in_pixels =
-          tile_priority.distance_to_visible_in_pixels;
-      mts.required_for_activation = tile_priority.required_for_activation;
-
-      mts.visible_and_ready_to_draw =
-          tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN;
-
-      if (mts.bin == NEVER_BIN) {
-        FreeResourcesForTile(tile);
-        continue;
-      }
-
-      // Note that if the tile is visible_and_ready_to_draw, then we always want
-      // the priority to be NOW_AND_READY_TO_DRAW_BIN, even if HIGH_PRIORITY_BIN
-      // is something different. The reason for this is that if we're
-      // prioritizing the pending tree, we still want visible tiles to take the
-      // highest priority.
-      ManagedTileBin priority_bin = mts.visible_and_ready_to_draw
-                                    ? NOW_AND_READY_TO_DRAW_BIN
-                                    : mts.bin;
-
-      // Insert the tile into a priority set.
-      tiles->InsertTile(tile, priority_bin);
+    switch (tree_priority) {
+      case SAME_PRIORITY_FOR_BOTH_TREES:
+        mts.bin = kBinPolicyMap[memory_policy][combined_bin];
+        gpu_memmgr_stats_bin = combined_bin;
+        tile_priority = tile->combined_priority();
+        break;
+      case SMOOTHNESS_TAKES_PRIORITY:
+        mts.bin = tree_bin[ACTIVE_TREE];
+        gpu_memmgr_stats_bin = active_bin;
+        tile_priority = active_priority;
+        break;
+      case NEW_CONTENT_TAKES_PRIORITY:
+        mts.bin = tree_bin[PENDING_TREE];
+        gpu_memmgr_stats_bin = pending_bin;
+        tile_priority = pending_priority;
+        break;
     }
+
+    if (!tile_is_ready_to_draw || tile_version.requires_resource()) {
+      if ((gpu_memmgr_stats_bin == NOW_BIN) ||
+          (gpu_memmgr_stats_bin == NOW_AND_READY_TO_DRAW_BIN))
+        memory_required_bytes_ += BytesConsumedIfAllocated(tile);
+      if (gpu_memmgr_stats_bin != NEVER_BIN)
+        memory_nice_to_have_bytes_ += BytesConsumedIfAllocated(tile);
+    }
+
+    // Bump up the priority if we determined it's NEVER_BIN on one tree,
+    // but is still required on the other tree.
+    bool is_in_never_bin_on_both_trees =
+        tree_bin[ACTIVE_TREE] == NEVER_BIN &&
+        tree_bin[PENDING_TREE] == NEVER_BIN;
+
+    if (mts.bin == NEVER_BIN && !is_in_never_bin_on_both_trees)
+      mts.bin = tile_is_active ? AT_LAST_AND_ACTIVE_BIN : AT_LAST_BIN;
+
+    mts.resolution = tile_priority.resolution;
+    mts.time_to_needed_in_seconds = tile_priority.time_to_visible_in_seconds;
+    mts.distance_to_visible_in_pixels =
+        tile_priority.distance_to_visible_in_pixels;
+    mts.required_for_activation = tile_priority.required_for_activation;
+
+    mts.visible_and_ready_to_draw =
+        tree_bin[ACTIVE_TREE] == NOW_AND_READY_TO_DRAW_BIN;
+
+    if (mts.bin == NEVER_BIN) {
+      FreeResourcesForTile(tile);
+      continue;
+    }
+
+    // Note that if the tile is visible_and_ready_to_draw, then we always want
+    // the priority to be NOW_AND_READY_TO_DRAW_BIN, even if HIGH_PRIORITY_BIN
+    // is something different. The reason for this is that if we're prioritizing
+    // the pending tree, we still want visible tiles to take the highest
+    // priority.
+    ManagedTileBin priority_bin = mts.visible_and_ready_to_draw
+                                  ? NOW_AND_READY_TO_DRAW_BIN
+                                  : mts.bin;
+
+    // Insert the tile into a priority set.
+    tiles->InsertTile(tile, priority_bin);
   }
 }
 
@@ -983,7 +959,7 @@
   }
 
   FreeUnusedResourcesForTile(tile);
-  if (tile->is_visible())
+  if (tile->priority(ACTIVE_TREE).distance_to_visible_in_pixels == 0)
     did_initialize_visible_tile_ = true;
 }
 
@@ -1012,14 +988,4 @@
   return tile;
 }
 
-scoped_refptr<TileBundle> TileManager::CreateTileBundle(int offset_x,
-                                                        int offset_y,
-                                                        int width,
-                                                        int height) {
-  scoped_refptr<TileBundle> bundle = make_scoped_refptr(
-      new TileBundle(this, offset_x, offset_y, width, height));
-  bundles_[bundle->id()] = bundle;
-  return bundle;
-}
-
 }  // namespace cc
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index 98a66f8..78beb1b 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -21,7 +21,6 @@
 #include "cc/resources/raster_worker_pool.h"
 #include "cc/resources/resource_pool.h"
 #include "cc/resources/tile.h"
-#include "cc/resources/tile_bundle.h"
 
 namespace cc {
 class ResourceProvider;
@@ -48,8 +47,7 @@
 // by layers; they automatically register with the manager when they are
 // created, and unregister from the manager when they are deleted.
 class CC_EXPORT TileManager : public RasterWorkerPoolClient,
-                              public RefCountedManager<Tile>,
-                              public RefCountedManager<TileBundle> {
+                              public RefCountedManager<Tile> {
  public:
   static scoped_ptr<TileManager> Create(
       TileManagerClient* client,
@@ -76,11 +74,6 @@
                                  int source_frame_number,
                                  int flags);
 
-  scoped_refptr<TileBundle> CreateTileBundle(int offset_x,
-                                             int offset_y,
-                                             int width,
-                                             int height);
-
   scoped_ptr<base::Value> BasicStateAsValue() const;
   scoped_ptr<base::Value> AllTilesAsValue() const;
   void GetMemoryStats(size_t* memory_required_bytes,
@@ -131,22 +124,16 @@
               size_t max_raster_usage_bytes,
               RenderingStatsInstrumentation* rendering_stats_instrumentation);
 
-  // Methods called by Tile and TileBundle
-  friend class TileBundle;
+  // Methods called by Tile
   friend class Tile;
-
   void DidChangeTilePriority(Tile* tile);
-  void DidChangeTileBundlePriority(TileBundle* bundle);
 
   void CleanUpReleasedTiles();
 
-  // Overridden from RefCountedManager<Tile>:
+  // Overriden from RefCountedManager<Tile>:
   virtual void Release(Tile* tile) OVERRIDE;
 
-  // Overridden from RefCountedManager<TileBundle>:
-  virtual void Release(TileBundle* bundle) OVERRIDE;
-
-  // Overridden from RasterWorkerPoolClient:
+  // Overriden from RasterWorkerPoolClient:
   virtual bool ShouldForceTasksRequiredForActivationToComplete() const
       OVERRIDE;
   virtual void DidFinishRunningTasks() OVERRIDE;
@@ -198,9 +185,6 @@
   typedef base::hash_map<Tile::Id, Tile*> TileMap;
   TileMap tiles_;
 
-  typedef base::hash_map<TileBundle::Id, TileBundle*> TileBundleMap;
-  TileBundleMap bundles_;
-
   PrioritizedTileSet prioritized_tiles_;
   bool prioritized_tiles_dirty_;
 
@@ -232,7 +216,6 @@
   RasterTaskCompletionStats update_visible_tiles_stats_;
 
   std::vector<Tile*> released_tiles_;
-  std::vector<TileBundle*> released_tile_bundles_;
 
   DISALLOW_COPY_AND_ASSIGN(TileManager);
 };
diff --git a/cc/resources/tile_manager_perftest.cc b/cc/resources/tile_manager_perftest.cc
index 5da12d0..9a651a2 100644
--- a/cc/resources/tile_manager_perftest.cc
+++ b/cc/resources/tile_manager_perftest.cc
@@ -7,7 +7,6 @@
 #include "cc/resources/tile_priority.h"
 #include "cc/test/fake_output_surface.h"
 #include "cc/test/fake_output_surface_client.h"
-#include "cc/test/fake_picture_layer_tiling_client.h"
 #include "cc/test/fake_picture_pile_impl.h"
 #include "cc/test/fake_tile_manager.h"
 #include "cc/test/fake_tile_manager_client.h"
@@ -27,8 +26,8 @@
 
 class TileManagerPerfTest : public testing::Test {
  public:
-  typedef std::vector<std::pair<scoped_refptr<TileBundle>, ManagedTileBin> >
-      TileBundleBinVector;
+  typedef std::vector<std::pair<scoped_refptr<Tile>, ManagedTileBin> >
+      TileBinVector;
 
   TileManagerPerfTest()
       : timer_(kWarmupRuns,
@@ -48,8 +47,6 @@
                             resource_provider_.get(),
                             raster_task_limit_bytes));
     picture_pile_ = FakePicturePileImpl::CreatePile();
-    picture_layer_tiling_client_ =
-        make_scoped_ptr(new FakePictureLayerTilingClient(tile_manager_.get()));
   }
 
   GlobalStateThatImpactsTilePriority GlobalStateForTest() {
@@ -65,7 +62,6 @@
   }
 
   virtual void TearDown() OVERRIDE {
-    picture_layer_tiling_client_.reset(NULL);
     tile_manager_.reset(NULL);
     picture_pile_ = NULL;
   }
@@ -110,38 +106,30 @@
     }
   }
 
-  void CreateBinTileBundles(int count,
-                            ManagedTileBin bin,
-                            TileBundleBinVector* bundles) {
+  void CreateBinTiles(int count, ManagedTileBin bin, TileBinVector* tiles) {
     for (int i = 0; i < count; ++i) {
-      scoped_refptr<TileBundle> bundle =
-          picture_layer_tiling_client_->CreateTileBundle(0, 0, 2, 2);
-      bundle->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin));
-      bundle->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin));
-      for (int j = 0; j < 4; ++j) {
-        scoped_refptr<Tile> tile =
-            tile_manager_->CreateTile(picture_pile_.get(),
-                                      settings_.default_tile_size,
-                                      gfx::Rect(),
-                                      gfx::Rect(),
-                                      1.0,
-                                      0,
-                                      0,
-                                      Tile::USE_LCD_TEXT);
-        bundle->AddTileAt(ACTIVE_TREE, j % 2, j / 2, tile);
-        bundle->AddTileAt(PENDING_TREE, j % 2, j / 2, tile);
-      }
-      bundles->push_back(std::make_pair(bundle, bin));
+      scoped_refptr<Tile> tile =
+          tile_manager_->CreateTile(picture_pile_.get(),
+                                    settings_.default_tile_size,
+                                    gfx::Rect(),
+                                    gfx::Rect(),
+                                    1.0,
+                                    0,
+                                    0,
+                                    Tile::USE_LCD_TEXT);
+      tile->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin));
+      tile->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin));
+      tiles->push_back(std::make_pair(tile, bin));
     }
   }
 
-  void CreateBundles(int count, TileBundleBinVector* bundles) {
+  void CreateTiles(int count, TileBinVector* tiles) {
     // Roughly an equal amount of all bins.
     int count_per_bin = count / NUM_BINS;
-    CreateBinTileBundles(count_per_bin, NOW_BIN, bundles);
-    CreateBinTileBundles(count_per_bin, SOON_BIN, bundles);
-    CreateBinTileBundles(count_per_bin, EVENTUALLY_BIN, bundles);
-    CreateBinTileBundles(count - 3 * count_per_bin, NEVER_BIN, bundles);
+    CreateBinTiles(count_per_bin, NOW_BIN, tiles);
+    CreateBinTiles(count_per_bin, SOON_BIN, tiles);
+    CreateBinTiles(count_per_bin, EVENTUALLY_BIN, tiles);
+    CreateBinTiles(count - 3 * count_per_bin, NEVER_BIN, tiles);
   }
 
   void RunManageTilesTest(const std::string& test_name,
@@ -150,21 +138,19 @@
     DCHECK_GE(tile_count, 100u);
     DCHECK_GE(priority_change_percent, 0);
     DCHECK_LE(priority_change_percent, 100);
-    TileBundleBinVector bundles;
-
-    unsigned bundle_count = tile_count / 4;
-    CreateBundles(bundle_count, &bundles);
+    TileBinVector tiles;
+    CreateTiles(tile_count, &tiles);
     timer_.Reset();
     do {
       if (priority_change_percent > 0) {
         for (unsigned i = 0;
-             i < bundle_count;
+             i < tile_count;
              i += 100 / priority_change_percent) {
-          TileBundle* bundle = bundles[i].first.get();
-          ManagedTileBin bin = GetNextBin(bundles[i].second);
-          bundle->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin));
-          bundle->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin));
-          bundles[i].second = bin;
+          Tile* tile = tiles[i].first.get();
+          ManagedTileBin bin = GetNextBin(tiles[i].second);
+          tile->SetPriority(ACTIVE_TREE, GetTilePriorityFromBin(bin));
+          tile->SetPriority(PENDING_TREE, GetTilePriorityFromBin(bin));
+          tiles[i].second = bin;
         }
       }
 
@@ -179,7 +165,6 @@
 
  private:
   FakeTileManagerClient tile_manager_client_;
-  scoped_ptr<FakePictureLayerTilingClient> picture_layer_tiling_client_;
   LayerTreeSettings settings_;
   scoped_ptr<FakeTileManager> tile_manager_;
   scoped_refptr<FakePicturePileImpl> picture_pile_;
diff --git a/cc/resources/tile_manager_unittest.cc b/cc/resources/tile_manager_unittest.cc
index fd74c3f..8339bd0 100644
--- a/cc/resources/tile_manager_unittest.cc
+++ b/cc/resources/tile_manager_unittest.cc
@@ -67,7 +67,6 @@
   }
 
   virtual void TearDown() OVERRIDE {
-    bundles_.clear();
     tile_manager_.reset(NULL);
     picture_pile_ = NULL;
 
@@ -88,14 +87,9 @@
                                                            0,
                                                            0,
                                                            Tile::USE_LCD_TEXT);
-      scoped_refptr<TileBundle> bundle =
-          tile_manager_->CreateTileBundle(0, 0, 1, 1);
-      bundle->SetPriority(ACTIVE_TREE, active_priority);
-      bundle->SetPriority(PENDING_TREE, pending_priority);
-      bundle->AddTileAt(ACTIVE_TREE, 0, 0, tile);
-      bundle->AddTileAt(PENDING_TREE, 0, 0, tile);
+      tile->SetPriority(ACTIVE_TREE, active_priority);
+      tile->SetPriority(PENDING_TREE, pending_priority);
       tiles.push_back(tile);
-      bundles_.push_back(bundle);
     }
     return tiles;
   }
@@ -148,7 +142,6 @@
   scoped_ptr<ResourceProvider> resource_provider_;
   TileMemoryLimitPolicy memory_limit_policy_;
   int max_memory_tiles_;
-  std::vector<scoped_refptr<TileBundle> > bundles_;
 };
 
 TEST_P(TileManagerTest, EnoughMemoryAllowAnything) {
@@ -535,4 +528,3 @@
 
 }  // namespace
 }  // namespace cc
-
diff --git a/cc/test/fake_picture_layer_impl.cc b/cc/test/fake_picture_layer_impl.cc
index b92b807..6e9ffde 100644
--- a/cc/test/fake_picture_layer_impl.cc
+++ b/cc/test/fake_picture_layer_impl.cc
@@ -77,14 +77,14 @@
   for (size_t tiling_idx = 0; tiling_idx < tilings_->num_tilings();
        ++tiling_idx) {
     PictureLayerTiling* tiling = tilings_->tiling_at(tiling_idx);
-    std::vector<TileBundle*> bundles = tiling->AllTileBundlesForTesting();
-    for (size_t bundle_idx = 0; bundle_idx < bundles.size(); ++bundle_idx) {
-      TileBundle* bundle = bundles[bundle_idx];
+    std::vector<Tile*> tiles = tiling->AllTilesForTesting();
+    for (size_t tile_idx = 0; tile_idx < tiles.size(); ++tile_idx) {
+      Tile* tile = tiles[tile_idx];
       TilePriority priority;
       priority.resolution = HIGH_RESOLUTION;
       priority.time_to_visible_in_seconds = 0.f;
       priority.distance_to_visible_in_pixels = 0.f;
-      bundle->SetPriority(tree, priority);
+      tile->SetPriority(tree, priority);
     }
   }
 }
@@ -109,22 +109,15 @@
   }
 }
 
-void FakePictureLayerImpl::CreateDefaultTilingsAndTiles(WhichTree tree) {
+void FakePictureLayerImpl::CreateDefaultTilingsAndTiles() {
   layer_tree_impl()->UpdateDrawProperties();
 
   if (CanHaveTilings()) {
     DCHECK_EQ(tilings()->num_tilings(), 2u);
     DCHECK_EQ(tilings()->tiling_at(0)->resolution(), HIGH_RESOLUTION);
     DCHECK_EQ(tilings()->tiling_at(1)->resolution(), LOW_RESOLUTION);
-    if (tree == ACTIVE_TREE) {
-      DCHECK(layer_tree_impl()->IsActiveTree());
-      HighResTiling()->CreateTilesForTesting(ACTIVE_TREE);
-      LowResTiling()->CreateTilesForTesting(ACTIVE_TREE);
-    } else {
-      DCHECK(layer_tree_impl()->IsPendingTree());
-      HighResTiling()->CreateTilesForTesting(PENDING_TREE);
-      LowResTiling()->CreateTilesForTesting(PENDING_TREE);
-    }
+    HighResTiling()->CreateAllTilesForTesting();
+    LowResTiling()->CreateAllTilesForTesting();
   } else {
     DCHECK_EQ(tilings()->num_tilings(), 0u);
   }
diff --git a/cc/test/fake_picture_layer_impl.h b/cc/test/fake_picture_layer_impl.h
index eb1059b..a289934 100644
--- a/cc/test/fake_picture_layer_impl.h
+++ b/cc/test/fake_picture_layer_impl.h
@@ -33,6 +33,7 @@
   using PictureLayerImpl::CanHaveTilings;
   using PictureLayerImpl::MarkVisibleResourcesAsRequired;
   using PictureLayerImpl::DoPostCommitInitializationIfNeeded;
+  using PictureLayerImpl::MinimumContentsScale;
 
   bool needs_post_commit_initialization() const {
     return needs_post_commit_initialization_;
@@ -55,7 +56,7 @@
 
   void set_fixed_tile_size(gfx::Size size) { fixed_tile_size_ = size; }
 
-  void CreateDefaultTilingsAndTiles(WhichTree tree);
+  void CreateDefaultTilingsAndTiles();
   void SetAllTilesVisible();
   void SetAllTilesReady();
   void SetAllTilesReadyInTiling(PictureLayerTiling* tiling);
diff --git a/cc/test/fake_picture_layer_tiling_client.cc b/cc/test/fake_picture_layer_tiling_client.cc
index c202364..e217336 100644
--- a/cc/test/fake_picture_layer_tiling_client.cc
+++ b/cc/test/fake_picture_layer_tiling_client.cc
@@ -23,14 +23,19 @@
   virtual ~FakeInfinitePicturePileImpl() {}
 };
 
-FakePictureLayerTilingClient::FakePictureLayerTilingClient(
-    TileManager* tile_manager)
-    : tile_manager_(tile_manager),
+FakePictureLayerTilingClient::FakePictureLayerTilingClient()
+    : tile_manager_(new FakeTileManager(&tile_manager_client_)),
       pile_(new FakeInfinitePicturePileImpl()),
       twin_tiling_(NULL),
-      allow_create_tile_(true),
-      is_active_(false),
-      is_pending_(false) {}
+      allow_create_tile_(true) {}
+
+FakePictureLayerTilingClient::FakePictureLayerTilingClient(
+    ResourceProvider* resource_provider)
+    : tile_manager_(
+          new FakeTileManager(&tile_manager_client_, resource_provider)),
+      pile_(new FakeInfinitePicturePileImpl()),
+      twin_tiling_(NULL),
+      allow_create_tile_(true) {}
 
 FakePictureLayerTilingClient::~FakePictureLayerTilingClient() {
 }
@@ -40,18 +45,10 @@
     gfx::Rect rect) {
   if (!allow_create_tile_)
     return scoped_refptr<Tile>();
-  return tile_manager()->CreateTile(
+  return tile_manager_->CreateTile(
       pile_.get(), tile_size_, rect, gfx::Rect(), 1, 0, 0, Tile::USE_LCD_TEXT);
 }
 
-scoped_refptr<TileBundle> FakePictureLayerTilingClient::CreateTileBundle(
-    int offset_x,
-    int offset_y,
-    int width,
-    int height) {
-  return tile_manager()->CreateTileBundle(offset_x, offset_y, width, height);
-}
-
 void FakePictureLayerTilingClient::SetTileSize(gfx::Size tile_size) {
   tile_size_ = tile_size;
 }
diff --git a/cc/test/fake_picture_layer_tiling_client.h b/cc/test/fake_picture_layer_tiling_client.h
index bd4f443..4b092e8 100644
--- a/cc/test/fake_picture_layer_tiling_client.h
+++ b/cc/test/fake_picture_layer_tiling_client.h
@@ -16,16 +16,13 @@
 
 class FakePictureLayerTilingClient : public PictureLayerTilingClient {
  public:
-  explicit FakePictureLayerTilingClient(TileManager* tile_manager);
+  FakePictureLayerTilingClient();
+  explicit FakePictureLayerTilingClient(ResourceProvider* resource_provider);
   virtual ~FakePictureLayerTilingClient();
 
   // PictureLayerTilingClient implementation.
   virtual scoped_refptr<Tile> CreateTile(
       PictureLayerTiling* tiling, gfx::Rect rect) OVERRIDE;
-  virtual scoped_refptr<TileBundle> CreateTileBundle(int offset_x,
-                                                     int offset_y,
-                                                     int width,
-                                                     int height) OVERRIDE;
   virtual void UpdatePile(Tile* tile) OVERRIDE {}
   virtual gfx::Size CalculateTileSize(
       gfx::Size content_bounds) const OVERRIDE;
@@ -45,19 +42,18 @@
   void set_invalidation(const Region& region) { invalidation_ = region; }
 
   TileManager* tile_manager() const {
-    return tile_manager_;
+    return tile_manager_.get();
   }
 
  protected:
-  TileManager* tile_manager_;
+  FakeTileManagerClient tile_manager_client_;
+  scoped_ptr<TileManager> tile_manager_;
   scoped_refptr<PicturePileImpl> pile_;
   gfx::Size tile_size_;
   PictureLayerTiling* twin_tiling_;
   gfx::Rect text_rect_;
   bool allow_create_tile_;
   Region invalidation_;
-  bool is_active_;
-  bool is_pending_;
 };
 
 }  // namespace cc
diff --git a/cc/test/fake_tile_manager.cc b/cc/test/fake_tile_manager.cc
index 907e0fa..6523060 100644
--- a/cc/test/fake_tile_manager.cc
+++ b/cc/test/fake_tile_manager.cc
@@ -55,8 +55,7 @@
                   make_scoped_ptr<RasterWorkerPool>(new FakeRasterWorkerPool),
                   1,
                   std::numeric_limits<unsigned>::max(),
-                  NULL),
-      in_bundle_cleanup_(false) {}
+                  NULL) {}
 
 FakeTileManager::FakeTileManager(TileManagerClient* client,
                                  ResourceProvider* resource_provider)
@@ -65,8 +64,7 @@
                   make_scoped_ptr<RasterWorkerPool>(new FakeRasterWorkerPool),
                   1,
                   std::numeric_limits<unsigned>::max(),
-                  NULL),
-      in_bundle_cleanup_(false) {}
+                  NULL) {}
 
 FakeTileManager::FakeTileManager(TileManagerClient* client,
                                  ResourceProvider* resource_provider,
@@ -76,8 +74,7 @@
                   make_scoped_ptr<RasterWorkerPool>(new FakeRasterWorkerPool),
                   1,
                   raster_task_limit_bytes,
-                  NULL),
-      in_bundle_cleanup_(false) {}
+                  NULL) {}
 
 FakeTileManager::~FakeTileManager() {}
 
@@ -103,15 +100,7 @@
 
 void FakeTileManager::Release(Tile* tile) {
   TileManager::Release(tile);
-  if (!in_bundle_cleanup_)
-    CleanUpReleasedTiles();
-}
-
-void FakeTileManager::Release(TileBundle* bundle) {
-  TileManager::Release(bundle);
-  in_bundle_cleanup_ = true;
   CleanUpReleasedTiles();
-  in_bundle_cleanup_ = false;
 }
 
 }  // namespace cc
diff --git a/cc/test/fake_tile_manager.h b/cc/test/fake_tile_manager.h
index 032870d..552c0f8 100644
--- a/cc/test/fake_tile_manager.h
+++ b/cc/test/fake_tile_manager.h
@@ -30,13 +30,9 @@
   virtual ~FakeTileManager();
 
   virtual void Release(Tile* tile) OVERRIDE;
-  virtual void Release(TileBundle* bundle) OVERRIDE;
 
   std::vector<Tile*> tiles_for_raster;
   PrioritizedTileSet all_tiles;
-
- private:
-  bool in_bundle_cleanup_;
 };
 
 }  // namespace cc
diff --git a/chrome/VERSION b/chrome/VERSION
index 18930b2..d8eda9a 100644
--- a/chrome/VERSION
+++ b/chrome/VERSION
@@ -1,4 +1,4 @@
 MAJOR=33
 MINOR=0
 BUILD=1750
-PATCH=16
+PATCH=22
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd
index 01627d9..ce70189 100644
--- a/chrome/app/generated_resources.grd
+++ b/chrome/app/generated_resources.grd
@@ -5591,13 +5591,6 @@
       <message name="IDS_FLAGS_FORCE_UNIVERSAL_ACCELERATED_OVERFLOW_SCROLL_MODE_DESCRIPTION" desc="Description of the 'Universal accelerated overflow scroll mode' lab.">
         Puts scrolling content in composited layers, even in those cases where promoting the overflow scrolling element to a stacking context and a containing block would have broken stacking or clipping.
       </message>
-      <message name="IDS_FLAGS_LAYER_SQUASHING_NAME" desc="Name of the 'Layer squashing' lab.">
-        Layer squashing
-      </message>
-      <message name="IDS_FLAGS_LAYER_SQUASHING_DESCRIPTION" desc="Description of the 'layer squashing' lab.">
-        Layers that overlap other composited content need to be composited as well, to ensure correct paint order. This feature enables Blink to paint multiple RenderLayer
-        subtrees into one composited layer so that we may be able to avoid unnecessarily large number of composited layers.
-      </message>
       <message name="IDS_FLAGS_ENABLE_DIRECT_WRITE_NAME" desc="Name of the 'Enable DirectWrite' lab.">
         Enable DirectWrite
       </message>
diff --git a/chrome/browser/about_flags.cc b/chrome/browser/about_flags.cc
index f90c6cc..c2d3283 100644
--- a/chrome/browser/about_flags.cc
+++ b/chrome/browser/about_flags.cc
@@ -454,15 +454,6 @@
          switches::kDisableUniversalAcceleratedOverflowScroll)
   },
   {
-    "enable-layer-squashing",
-    IDS_FLAGS_LAYER_SQUASHING_NAME,
-    IDS_FLAGS_LAYER_SQUASHING_DESCRIPTION,
-    kOsAll,
-    ENABLE_DISABLE_VALUE_TYPE(
-        switches::kEnableLayerSquashing,
-        switches::kDisableLayerSquashing)
-  },
-  {
     "present-with-GDI",
     IDS_FLAGS_PRESENT_WITH_GDI_NAME,
     IDS_FLAGS_PRESENT_WITH_GDI_DESCRIPTION,
diff --git a/chrome/browser/chromeos/login/fake_user_manager.cc b/chrome/browser/chromeos/login/fake_user_manager.cc
index 851256a..023a51a 100644
--- a/chrome/browser/chromeos/login/fake_user_manager.cc
+++ b/chrome/browser/chromeos/login/fake_user_manager.cc
@@ -27,11 +27,12 @@
   }
 }
 
-void FakeUserManager::AddUser(const std::string& email) {
+const User* FakeUserManager::AddUser(const std::string& email) {
   User* user = User::CreateRegularUser(email);
   user->set_username_hash(email + kUserIdHashSuffix);
   user->SetStubImage(User::kProfileImageIndex, false);
   user_list_.push_back(user);
+  return user;
 }
 
 void FakeUserManager::AddKioskAppUser(const std::string& kiosk_app_username) {
@@ -44,6 +45,10 @@
   UserLoggedIn(email, email + kUserIdHashSuffix, false);
 }
 
+void FakeUserManager::SetProfileForUser(const User* user, Profile* profile) {
+  user_to_profile_[user] = profile;
+}
+
 const UserList& FakeUserManager::GetUsers() const {
   return user_list_;
 }
@@ -173,8 +178,9 @@
 }
 
 Profile* FakeUserManager::GetProfileByUser(const User* user) const {
-  NOTIMPLEMENTED();
-  return NULL;
+  std::map<const User*, Profile*>::const_iterator it =
+      user_to_profile_.find(user);
+  return it == user_to_profile_.end() ? NULL : it->second;
 }
 
 base::string16 FakeUserManager::GetUserDisplayName(
diff --git a/chrome/browser/chromeos/login/fake_user_manager.h b/chrome/browser/chromeos/login/fake_user_manager.h
index 4e5d0ea..31ab136 100644
--- a/chrome/browser/chromeos/login/fake_user_manager.h
+++ b/chrome/browser/chromeos/login/fake_user_manager.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_LOGIN_FAKE_USER_MANAGER_H_
 #define CHROME_BROWSER_CHROMEOS_LOGIN_FAKE_USER_MANAGER_H_
 
+#include <map>
 #include <string>
 
 #include "base/memory/scoped_ptr.h"
@@ -25,7 +26,7 @@
   virtual ~FakeUserManager();
 
   // Create and add a new user.
-  void AddUser(const std::string& email);
+  const User* AddUser(const std::string& email);
 
   // Create and add a kiosk app user.
   void AddKioskAppUser(const std::string& kiosk_app_username);
@@ -33,6 +34,9 @@
    // Calculates the user name hash and calls UserLoggedIn to login a user.
    void LoginUser(const std::string& email);
 
+   // Associates |profile| with |user|, for GetProfileByUser().
+   void SetProfileForUser(const User* user, Profile* profile);
+
   // UserManager overrides.
   virtual const UserList& GetUsers() const OVERRIDE;
   virtual UserList GetUsersAdmittedForMultiProfile() const OVERRIDE;
@@ -136,6 +140,7 @@
   UserList logged_in_users_;
   std::string owner_email_;
   User* primary_user_;
+  std::map<const User*, Profile*> user_to_profile_;
 
   // If set this is the active user. If empty, the first created user is the
   // active user.
diff --git a/chrome/browser/chromeos/login/multi_profile_user_controller.cc b/chrome/browser/chromeos/login/multi_profile_user_controller.cc
index 1290663..8c3dc8d 100644
--- a/chrome/browser/chromeos/login/multi_profile_user_controller.cc
+++ b/chrome/browser/chromeos/login/multi_profile_user_controller.cc
@@ -11,7 +11,10 @@
 #include "base/prefs/pref_service.h"
 #include "base/prefs/scoped_user_pref_update.h"
 #include "chrome/browser/chromeos/login/multi_profile_user_controller_delegate.h"
+#include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/prefs/pref_service_syncable.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
@@ -67,9 +70,10 @@
   UserManager* user_manager = UserManager::Get();
   CHECK(user_manager);
 
+  const User* primary_user = user_manager->GetPrimaryUser();
   std::string primary_user_email;
-  if (user_manager->GetPrimaryUser())
-    primary_user_email = user_manager->GetPrimaryUser()->email();
+  if (primary_user)
+    primary_user_email = primary_user->email();
 
   // Always allow if there is no primary user or user being checked is the
   // primary user.
@@ -80,6 +84,30 @@
   if (user_manager->GetOwnerEmail() == user_email)
     return false;
 
+  // Don't allow profiles potentially tainted by data fetched with policy-pushed
+  // certificates to join a multiprofile session.
+  if (policy::PolicyCertServiceFactory::UsedPolicyCertificates(user_email))
+    return false;
+
+  // Don't allow any secondary profiles if the primary profile is tainted.
+  if (policy::PolicyCertServiceFactory::UsedPolicyCertificates(
+          primary_user_email)) {
+    // Check directly in local_state before checking if the primary user has
+    // a PolicyCertService. His profile may have been tainted previously though
+    // he didn't get a PolicyCertService created for this session.
+    return false;
+  }
+
+  // If the primary profile already has policy certificates installed but hasn't
+  // used them yet then it can become tainted at any time during this session;
+  // disable secondary profiles in this case too.
+  Profile* profile =
+      primary_user ? user_manager->GetProfileByUser(primary_user) : NULL;
+  policy::PolicyCertService* service =
+      profile ? policy::PolicyCertServiceFactory::GetForProfile(profile) : NULL;
+  if (service && service->has_policy_certificates())
+    return false;
+
   // No user is allowed if the primary user policy forbids it.
   const std::string primary_user_behavior = GetCachedValue(primary_user_email);
   if (primary_user_behavior == kBehaviorNotAllowed)
@@ -107,11 +135,12 @@
   OnUserPrefChanged(user_profile);
 }
 
-void MultiProfileUserController::RemoveCachedValue(
+void MultiProfileUserController::RemoveCachedValues(
     const std::string& user_email) {
   DictionaryPrefUpdate update(local_state_,
                               prefs::kCachedMultiProfileUserBehavior);
   update->RemoveWithoutPathExpansion(user_email, NULL);
+  policy::PolicyCertServiceFactory::ClearUsedPolicyCertificates(user_email);
 }
 
 std::string MultiProfileUserController::GetCachedValue(
diff --git a/chrome/browser/chromeos/login/multi_profile_user_controller.h b/chrome/browser/chromeos/login/multi_profile_user_controller.h
index 0e86e7e..4c1a907 100644
--- a/chrome/browser/chromeos/login/multi_profile_user_controller.h
+++ b/chrome/browser/chromeos/login/multi_profile_user_controller.h
@@ -43,8 +43,8 @@
   // Starts to observe the multiprofile user behavior pref of the given profile.
   void StartObserving(Profile* user_profile);
 
-  // Removes the cached value for the given user.
-  void RemoveCachedValue(const std::string& user_email);
+  // Removes the cached values for the given user.
+  void RemoveCachedValues(const std::string& user_email);
 
   // Possible behavior values.
   static const char kBehaviorUnrestricted[];
diff --git a/chrome/browser/chromeos/login/multi_profile_user_controller_unittest.cc b/chrome/browser/chromeos/login/multi_profile_user_controller_unittest.cc
index a5e1a2a..cf4d33b 100644
--- a/chrome/browser/chromeos/login/multi_profile_user_controller_unittest.cc
+++ b/chrome/browser/chromeos/login/multi_profile_user_controller_unittest.cc
@@ -5,10 +5,14 @@
 #include "chrome/browser/chromeos/login/multi_profile_user_controller.h"
 
 #include "base/memory/scoped_ptr.h"
+#include "base/run_loop.h"
 #include "base/strings/utf_string_conversions.h"
 #include "chrome/browser/chromeos/login/fake_user_manager.h"
 #include "chrome/browser/chromeos/login/multi_profile_user_controller_delegate.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
+#include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
 #include "chrome/browser/prefs/browser_prefs.h"
 #include "chrome/common/pref_names.h"
 #include "chrome/test/base/scoped_testing_local_state.h"
@@ -16,6 +20,8 @@
 #include "chrome/test/base/testing_pref_service_syncable.h"
 #include "chrome/test/base/testing_profile.h"
 #include "chrome/test/base/testing_profile_manager.h"
+#include "content/public/test/test_browser_thread_bundle.h"
+#include "net/cert/x509_certificate.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
 namespace chromeos {
@@ -78,6 +84,15 @@
   },
 };
 
+policy::PolicyCertVerifier* g_policy_cert_verifier_for_factory = NULL;
+
+BrowserContextKeyedService* TestPolicyCertServiceFactory(
+    content::BrowserContext* context) {
+  return policy::PolicyCertService::CreateForTesting(
+      kUsers[0], g_policy_cert_verifier_for_factory, UserManager::Get())
+      .release();
+}
+
 }  // namespace
 
 class MultiProfileUserControllerTest
@@ -98,13 +113,15 @@
 
     for (size_t i = 0; i < arraysize(kUsers); ++i) {
       const std::string user_email(kUsers[i]);
-      fake_user_manager_->AddUser(user_email);
+      const User* user = fake_user_manager_->AddUser(user_email);
 
       // Note that user profiles are created after user login in reality.
       TestingProfile* user_profile =
           profile_manager_.CreateTestingProfile(user_email);
       user_profile->set_profile_name(user_email);
       user_profiles_.push_back(user_profile);
+
+      fake_user_manager_->SetProfileForUser(user, user_profile);
     }
   }
 
@@ -148,7 +165,12 @@
   MultiProfileUserController* controller() { return controller_.get(); }
   int user_not_allowed_count() const { return user_not_allowed_count_; }
 
+  TestingProfile* profile(int index) {
+    return user_profiles_[index];
+  }
+
  private:
+  content::TestBrowserThreadBundle threads_;
   TestingProfileManager profile_manager_;
   FakeUserManager* fake_user_manager_;  // Not owned
   ScopedUserManagerEnabler user_manager_enabler_;
@@ -263,4 +285,75 @@
   EXPECT_EQ(1, user_not_allowed_count());
 }
 
+TEST_F(MultiProfileUserControllerTest,
+       UsedPolicyCertificatesAllowedForPrimary) {
+  // Verifies that any user can sign-in as the primary user, regardless of the
+  // tainted state.
+  policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[0]);
+  EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[0]));
+  EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[1]));
+}
+
+TEST_F(MultiProfileUserControllerTest,
+       UsedPolicyCertificatesDisallowedForSecondary) {
+  // Verifies that if a regular user is signed-in then other regular users can
+  // be added but tainted users can't.
+  LoginUser(1);
+  EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[0]));
+  policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[0]);
+  EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[0]));
+}
+
+TEST_F(MultiProfileUserControllerTest,
+       UsedPolicyCertificatesDisallowsSecondaries) {
+  // Verifies that if a tainted user is signed-in then no other users can
+  // be added.
+  policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[0]);
+  LoginUser(0);
+
+  // Double parenthesis to avoid http://en.wikipedia.org/wiki/Most_vexing_parse.
+  policy::PolicyCertVerifier verifier((base::Closure()));
+  g_policy_cert_verifier_for_factory = &verifier;
+  ASSERT_TRUE(
+      policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+          profile(0), TestPolicyCertServiceFactory));
+
+  EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[1]));
+  policy::PolicyCertServiceFactory::SetUsedPolicyCertificates(kUsers[1]);
+  EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[1]));
+
+  // Flush tasks posted to IO.
+  base::RunLoop().RunUntilIdle();
+}
+
+TEST_F(MultiProfileUserControllerTest,
+       PolicyCertificatesInMemoryDisallowsSecondaries) {
+  // Verifies that if a user is signed-in and has policy certificates installed
+  // then no other users can be added.
+  LoginUser(0);
+
+  // Double parenthesis to avoid http://en.wikipedia.org/wiki/Most_vexing_parse.
+  policy::PolicyCertVerifier verifier((base::Closure()));
+  g_policy_cert_verifier_for_factory = &verifier;
+  ASSERT_TRUE(
+      policy::PolicyCertServiceFactory::GetInstance()->SetTestingFactoryAndUse(
+          profile(0), TestPolicyCertServiceFactory));
+  policy::PolicyCertService* service =
+      policy::PolicyCertServiceFactory::GetForProfile(profile(0));
+  ASSERT_TRUE(service);
+
+  EXPECT_FALSE(service->has_policy_certificates());
+  EXPECT_TRUE(controller()->IsUserAllowedInSession(kUsers[1]));
+
+  net::CertificateList certificates;
+  certificates.push_back(new net::X509Certificate(
+      "subject", "issuer", base::Time(), base::Time()));
+  service->OnTrustAnchorsChanged(certificates);
+  EXPECT_TRUE(service->has_policy_certificates());
+  EXPECT_FALSE(controller()->IsUserAllowedInSession(kUsers[1]));
+
+  // Flush tasks posted to IO.
+  base::RunLoop().RunUntilIdle();
+}
+
 }  // namespace chromeos
diff --git a/chrome/browser/chromeos/login/user_manager_impl.cc b/chrome/browser/chromeos/login/user_manager_impl.cc
index f3cd10e..c1521cc 100644
--- a/chrome/browser/chromeos/login/user_manager_impl.cc
+++ b/chrome/browser/chromeos/login/user_manager_impl.cc
@@ -1380,7 +1380,7 @@
 
   supervised_user_manager_->RemoveNonCryptohomeData(user_id);
 
-  multi_profile_user_controller_->RemoveCachedValue(user_id);
+  multi_profile_user_controller_->RemoveCachedValues(user_id);
 }
 
 User* UserManagerImpl::RemoveRegularOrLocallyManagedUserFromList(
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.cc b/chrome/browser/chromeos/policy/policy_cert_service.cc
index 990702d..d966fdc 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service.cc
@@ -7,9 +7,9 @@
 #include "base/bind.h"
 #include "base/bind_helpers.h"
 #include "base/logging.h"
-#include "base/prefs/pref_service.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
-#include "chrome/common/pref_names.h"
 #include "content/public/browser/browser_thread.h"
 #include "net/cert/x509_certificate.h"
 
@@ -21,20 +21,32 @@
 }
 
 PolicyCertService::PolicyCertService(
+    const std::string& user_id,
     UserNetworkConfigurationUpdater* net_conf_updater,
-    PrefService* user_prefs)
+    chromeos::UserManager* user_manager)
     : cert_verifier_(NULL),
+      user_id_(user_id),
       net_conf_updater_(net_conf_updater),
-      user_prefs_(user_prefs),
+      user_manager_(user_manager),
+      has_trust_anchors_(false),
       weak_ptr_factory_(this) {
   DCHECK(net_conf_updater_);
-  DCHECK(user_prefs_);
+  DCHECK(user_manager_);
 }
 
+PolicyCertService::PolicyCertService(const std::string& user_id,
+                                     PolicyCertVerifier* verifier,
+                                     chromeos::UserManager* user_manager)
+    : cert_verifier_(verifier),
+      user_id_(user_id),
+      net_conf_updater_(NULL),
+      user_manager_(user_manager),
+      has_trust_anchors_(false),
+      weak_ptr_factory_(this) {}
+
 scoped_ptr<PolicyCertVerifier> PolicyCertService::CreatePolicyCertVerifier() {
-  base::Closure callback =
-      base::Bind(&PolicyCertService::SetUsedPolicyCertificatesOnce,
-                 weak_ptr_factory_.GetWeakPtr());
+  base::Closure callback = base::Bind(
+      &PolicyCertServiceFactory::SetUsedPolicyCertificates, user_id_);
   cert_verifier_ = new PolicyCertVerifier(
       base::Bind(base::IgnoreResult(&content::BrowserThread::PostTask),
                  content::BrowserThread::UI,
@@ -55,6 +67,19 @@
 void PolicyCertService::OnTrustAnchorsChanged(
     const net::CertificateList& trust_anchors) {
   DCHECK(cert_verifier_);
+
+  // Do not use certificates installed via ONC policy if the current session has
+  // multiple profiles. This is important to make sure that any possibly tainted
+  // data is absolutely confined to the managed profile and never, ever leaks to
+  // any other profile.
+  if (!trust_anchors.empty() && user_manager_->GetLoggedInUsers().size() > 1u) {
+    LOG(ERROR) << "Ignoring ONC-pushed certificates update because multiple "
+               << "users are logged in.";
+    return;
+  }
+
+  has_trust_anchors_ = !trust_anchors.empty();
+
   // It's safe to use base::Unretained here, because it's guaranteed that
   // |cert_verifier_| outlives this object (see description of
   // CreatePolicyCertVerifier).
@@ -69,19 +94,24 @@
 }
 
 bool PolicyCertService::UsedPolicyCertificates() const {
-  return user_prefs_->GetBoolean(prefs::kUsedPolicyCertificatesOnce);
+  return PolicyCertServiceFactory::UsedPolicyCertificates(user_id_);
 }
 
 void PolicyCertService::Shutdown() {
   weak_ptr_factory_.InvalidateWeakPtrs();
-  net_conf_updater_->RemoveTrustedCertsObserver(this);
+  if (net_conf_updater_)
+    net_conf_updater_->RemoveTrustedCertsObserver(this);
   OnTrustAnchorsChanged(net::CertificateList());
   net_conf_updater_ = NULL;
-  user_prefs_ = NULL;
 }
 
-void PolicyCertService::SetUsedPolicyCertificatesOnce() {
-  user_prefs_->SetBoolean(prefs::kUsedPolicyCertificatesOnce, true);
+// static
+scoped_ptr<PolicyCertService> PolicyCertService::CreateForTesting(
+    const std::string& user_id,
+    PolicyCertVerifier* verifier,
+    chromeos::UserManager* user_manager) {
+  return make_scoped_ptr(
+      new PolicyCertService(user_id, verifier, user_manager));
 }
 
 }  // namespace policy
diff --git a/chrome/browser/chromeos/policy/policy_cert_service.h b/chrome/browser/chromeos/policy/policy_cert_service.h
index a32040f..464e89e 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service.h
+++ b/chrome/browser/chromeos/policy/policy_cert_service.h
@@ -5,6 +5,7 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERT_SERVICE_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERT_SERVICE_H_
 
+#include <string>
 #include <vector>
 
 #include "base/basictypes.h"
@@ -15,7 +16,9 @@
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
 #include "components/browser_context_keyed_service/browser_context_keyed_service.h"
 
-class PrefService;
+namespace chromeos {
+class UserManager;
+}
 
 namespace net {
 class X509Certificate;
@@ -35,19 +38,22 @@
     : public BrowserContextKeyedService,
       public UserNetworkConfigurationUpdater::WebTrustedCertsObserver {
  public:
-  PolicyCertService(UserNetworkConfigurationUpdater* net_conf_updater,
-                    PrefService* user_prefs);
+  PolicyCertService(const std::string& user_id,
+                    UserNetworkConfigurationUpdater* net_conf_updater,
+                    chromeos::UserManager* user_manager);
   virtual ~PolicyCertService();
 
   // Creates an associated PolicyCertVerifier. The returned object must only be
   // used on the IO thread and must outlive this object.
   scoped_ptr<PolicyCertVerifier> CreatePolicyCertVerifier();
 
-  // Returns true if the profile with |user_prefs| has used certificates
+  // Returns true if the profile that owns this service has used certificates
   // installed via policy to establish a secure connection before. This means
   // that it may have cached content from an untrusted source.
   bool UsedPolicyCertificates() const;
 
+  bool has_policy_certificates() const { return has_trust_anchors_; }
+
   // UserNetworkConfigurationUpdater::WebTrustedCertsObserver:
   virtual void OnTrustAnchorsChanged(const net::CertificateList& trust_anchors)
       OVERRIDE;
@@ -55,12 +61,21 @@
   // BrowserContextKeyedService:
   virtual void Shutdown() OVERRIDE;
 
+  static scoped_ptr<PolicyCertService> CreateForTesting(
+      const std::string& user_id,
+      PolicyCertVerifier* verifier,
+      chromeos::UserManager* user_manager);
+
  private:
-  void SetUsedPolicyCertificatesOnce();
+  PolicyCertService(const std::string& user_id,
+                    PolicyCertVerifier* verifier,
+                    chromeos::UserManager* user_manager);
 
   PolicyCertVerifier* cert_verifier_;
+  std::string user_id_;
   UserNetworkConfigurationUpdater* net_conf_updater_;
-  PrefService* user_prefs_;
+  chromeos::UserManager* user_manager_;
+  bool has_trust_anchors_;
 
   // Weak pointers to handle callbacks from PolicyCertVerifier on the IO thread.
   // The factory and the created WeakPtrs must only be used on the UI thread.
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
index f0e3d8e..9b5d5f0 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.cc
@@ -5,9 +5,15 @@
 #include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 
 #include "base/memory/singleton.h"
+#include "base/prefs/pref_registry_simple.h"
+#include "base/prefs/pref_service.h"
+#include "base/prefs/scoped_user_pref_update.h"
+#include "chrome/browser/browser_process.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/policy/policy_cert_service.h"
 #include "chrome/browser/chromeos/policy/policy_cert_verifier.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
+#include "chrome/browser/lifetime/application_lifetime.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/common/pref_names.h"
@@ -38,6 +44,42 @@
   return Singleton<PolicyCertServiceFactory>::get();
 }
 
+// static
+void PolicyCertServiceFactory::SetUsedPolicyCertificates(
+    const std::string& user_id) {
+  if (UsedPolicyCertificates(user_id))
+    return;
+  ListPrefUpdate update(g_browser_process->local_state(),
+                        prefs::kUsedPolicyCertificates);
+  update->AppendString(user_id);
+}
+
+// static
+void PolicyCertServiceFactory::ClearUsedPolicyCertificates(
+    const std::string& user_id) {
+  ListPrefUpdate update(g_browser_process->local_state(),
+                        prefs::kUsedPolicyCertificates);
+  update->Remove(base::StringValue(user_id), NULL);
+}
+
+// static
+bool PolicyCertServiceFactory::UsedPolicyCertificates(
+    const std::string& user_id) {
+  base::StringValue value(user_id);
+  const base::ListValue* list =
+      g_browser_process->local_state()->GetList(prefs::kUsedPolicyCertificates);
+  if (!list) {
+    NOTREACHED();
+    return false;
+  }
+  return list->Find(value) != list->end();
+}
+
+// static
+void PolicyCertServiceFactory::RegisterPrefs(PrefRegistrySimple* local_state) {
+  local_state->RegisterListPref(prefs::kUsedPolicyCertificates);
+}
+
 PolicyCertServiceFactory::PolicyCertServiceFactory()
     : BrowserContextKeyedServiceFactory(
           "PolicyCertService",
@@ -50,15 +92,41 @@
 BrowserContextKeyedService* PolicyCertServiceFactory::BuildServiceInstanceFor(
     content::BrowserContext* context) const {
   Profile* profile = static_cast<Profile*>(context);
+
+  chromeos::UserManager* user_manager = chromeos::UserManager::Get();
+  chromeos::User* user =
+      user_manager->GetUserByProfile(profile->GetOriginalProfile());
+  if (!user)
+    return NULL;
+
+  // Backwards compatibility: profiles that used policy-pushed certificates used
+  // to have this condition marked in their prefs. This signal has moved to
+  // local_state though, to support checking it before the profile is loaded.
+  // Check the profile here and update the local_state, if appropriate.
+  // TODO(joaodasilva): remove this, eventually.
+  PrefService* prefs = profile->GetOriginalProfile()->GetPrefs();
+  if (prefs->GetBoolean(prefs::kUsedPolicyCertificatesOnce)) {
+    SetUsedPolicyCertificates(user->email());
+    prefs->ClearPref(prefs::kUsedPolicyCertificatesOnce);
+
+    if (user_manager->GetLoggedInUsers().size() > 1u) {
+      // This login should not have been allowed. After rebooting, local_state
+      // will contain the updated list of users that used policy-pushed
+      // certificates and this won't happen again.
+      // Note that a user becomes logged in before his profile is created.
+      LOG(ERROR) << "Shutdown session because a tainted profile was added.";
+      g_browser_process->local_state()->CommitPendingWrite();
+      prefs->CommitPendingWrite();
+      chrome::AttemptUserExit();
+    }
+  }
+
   UserNetworkConfigurationUpdater* net_conf_updater =
       UserNetworkConfigurationUpdaterFactory::GetForProfile(profile);
   if (!net_conf_updater)
     return NULL;
 
-  // In case of usage of additional trust anchors from an incognito profile, the
-  // prefs of the original profile have to be marked.
-  return new PolicyCertService(net_conf_updater,
-                               profile->GetOriginalProfile()->GetPrefs());
+  return new PolicyCertService(user->email(), net_conf_updater, user_manager);
 }
 
 content::BrowserContext* PolicyCertServiceFactory::GetBrowserContextToUse(
@@ -68,6 +136,8 @@
 
 void PolicyCertServiceFactory::RegisterProfilePrefs(
     user_prefs::PrefRegistrySyncable* registry) {
+  // TODO(joaodasilva): this is used for backwards compatibility.
+  // Remove once it's not necessary anymore.
   registry->RegisterBooleanPref(
       prefs::kUsedPolicyCertificatesOnce,
       false,
diff --git a/chrome/browser/chromeos/policy/policy_cert_service_factory.h b/chrome/browser/chromeos/policy/policy_cert_service_factory.h
index dc945aa..eaa269b 100644
--- a/chrome/browser/chromeos/policy/policy_cert_service_factory.h
+++ b/chrome/browser/chromeos/policy/policy_cert_service_factory.h
@@ -5,6 +5,8 @@
 #ifndef CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERT_SERVICE_FACTORY_H_
 #define CHROME_BROWSER_CHROMEOS_POLICY_POLICY_CERT_SERVICE_FACTORY_H_
 
+#include <string>
+
 #include "base/basictypes.h"
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
@@ -12,6 +14,7 @@
 
 template <typename T> struct DefaultSingletonTraits;
 
+class PrefRegistrySimple;
 class Profile;
 
 namespace policy {
@@ -37,6 +40,14 @@
 
   static PolicyCertServiceFactory* GetInstance();
 
+  // Used to mark or clear |user_id| as having used certificates pushed by
+  // policy before.
+  static void SetUsedPolicyCertificates(const std::string& user_id);
+  static void ClearUsedPolicyCertificates(const std::string& user_id);
+  static bool UsedPolicyCertificates(const std::string& user_id);
+
+  static void RegisterPrefs(PrefRegistrySimple* local_state);
+
  private:
   friend struct DefaultSingletonTraits<PolicyCertServiceFactory>;
 
diff --git a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
index b7f8037..fed3c77 100644
--- a/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
+++ b/chrome/browser/chromeos/policy/user_network_configuration_updater_factory.cc
@@ -5,12 +5,10 @@
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater_factory.h"
 
 #include "base/memory/singleton.h"
-#include "chrome/browser/browser_process.h"
 #include "chrome/browser/chromeos/login/user.h"
 #include "chrome/browser/chromeos/login/user_manager.h"
 #include "chrome/browser/chromeos/policy/user_network_configuration_updater.h"
 #include "chrome/browser/chromeos/profiles/profile_helper.h"
-#include "chrome/browser/policy/browser_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector.h"
 #include "chrome/browser/policy/profile_policy_connector_factory.h"
 #include "chrome/browser/profiles/incognito_helpers.h"
@@ -77,14 +75,7 @@
   if (user != user_manager->GetPrimaryUser())
     return NULL;
 
-  BrowserPolicyConnector* browser_connector =
-      g_browser_process->browser_policy_connector();
-
-  // Allow trusted certs from policy only for accounts with managed user
-  // affiliation, i.e users that are managed by the same domain as the device.
-  bool allow_trusted_certs_from_policy =
-      browser_connector->GetUserAffiliation(user->email()) ==
-          USER_AFFILIATION_MANAGED &&
+  const bool allow_trusted_certs_from_policy =
       user->GetType() == chromeos::User::USER_TYPE_REGULAR;
 
   ProfilePolicyConnector* profile_connector =
diff --git a/chrome/browser/media/media_capture_devices_dispatcher.cc b/chrome/browser/media/media_capture_devices_dispatcher.cc
index ac79ad2..7b4f2a5 100644
--- a/chrome/browser/media/media_capture_devices_dispatcher.cc
+++ b/chrome/browser/media/media_capture_devices_dispatcher.cc
@@ -64,12 +64,16 @@
 // 1. Virtual keyboard extension.
 // 2. Google Voice Search Hotword extension.
 // 3. Flutter gesture recognition extension.
+// 4. TODO(smus): Airbender experiment 1.
+// 5. TODO(smus): Airbender experiment 2.
 // Once http://crbug.com/292856 is fixed, remove this whitelist.
 bool IsMediaRequestWhitelistedForExtension(
     const extensions::Extension* extension) {
   return extension->id() == "mppnpdlheglhdfmldimlhpnegondlapf" ||
       extension->id() == "bepbmhgboaologfdajaanbcjmnhjmhfn" ||
-      extension->id() == "jokbpnebhdcladagohdnfgjcpejggllo";
+      extension->id() == "jokbpnebhdcladagohdnfgjcpejggllo" ||
+      extension->id() == "clffjmdilanldobdnedchkdbofoimcgb" ||
+      extension->id() == "nnckehldicaciogcbchegobnafnjkcne";
 }
 
 // This is a short-term solution to allow testing of the the Screen Capture API
diff --git a/chrome/browser/prefs/browser_prefs.cc b/chrome/browser/prefs/browser_prefs.cc
index 766c330..27dd0e5 100644
--- a/chrome/browser/prefs/browser_prefs.cc
+++ b/chrome/browser/prefs/browser_prefs.cc
@@ -153,6 +153,7 @@
 #include "chrome/browser/chromeos/policy/auto_enrollment_client.h"
 #include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
 #include "chrome/browser/chromeos/policy/device_status_collector.h"
+#include "chrome/browser/chromeos/policy/policy_cert_service_factory.h"
 #include "chrome/browser/chromeos/power/power_prefs.h"
 #include "chrome/browser/chromeos/preferences.h"
 #include "chrome/browser/chromeos/settings/device_oauth2_token_service.h"
@@ -305,6 +306,7 @@
   policy::AutoEnrollmentClient::RegisterPrefs(registry);
   policy::DeviceCloudPolicyManagerChromeOS::RegisterPrefs(registry);
   policy::DeviceStatusCollector::RegisterPrefs(registry);
+  policy::PolicyCertServiceFactory::RegisterPrefs(registry);
 #endif
 
 #if defined(OS_MACOSX)
diff --git a/chrome/browser/resources/options/manage_profile_overlay.css b/chrome/browser/resources/options/manage_profile_overlay.css
index a1a542b..760030d 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.css
+++ b/chrome/browser/resources/options/manage_profile_overlay.css
@@ -95,18 +95,19 @@
   -webkit-margin-end: 10px;
 }
 
-#delete-profile-message,
 #delete-managed-profile-addendum {
   -webkit-padding-start: 48px;
-  background-repeat: no-repeat;
-}
-
-#delete-managed-profile-addendum {
   margin-top: 10px;
 }
 
-html[dir='rtl'] #delete-profile-message {
-  background-position: right;
+html[dir='ltr'] #delete-profile-icon {
+  float: left;
+  margin-right: 10px;
+}
+
+html[dir='rtl'] #delete-profile-icon {
+  float: right;
+  margin-left: 10px;
 }
 
 #create-profile-managed-not-signed-in {
diff --git a/chrome/browser/resources/options/manage_profile_overlay.html b/chrome/browser/resources/options/manage_profile_overlay.html
index 94723c7..42ccfb2 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.html
+++ b/chrome/browser/resources/options/manage_profile_overlay.html
@@ -38,7 +38,10 @@
   <div id="manage-profile-overlay-delete" hidden>
     <h1 i18n-content="deleteProfileTitle"></h1>
     <div class="content-area">
-      <div id="delete-profile-message"></div>
+      <div id="delete-profile-message">
+        <img id="delete-profile-icon" class="profile-icon">
+        <div id="delete-profile-text"></div>
+      </div>
       <div id="delete-managed-profile-addendum"
           i18n-values=".innerHTML:deleteManagedProfileAddendum" hidden>
       </div>
diff --git a/chrome/browser/resources/options/manage_profile_overlay.js b/chrome/browser/resources/options/manage_profile_overlay.js
index 35d34df..2d6e64c 100644
--- a/chrome/browser/resources/options/manage_profile_overlay.js
+++ b/chrome/browser/resources/options/manage_profile_overlay.js
@@ -409,10 +409,10 @@
       $('manage-profile-overlay-create').hidden = true;
       $('manage-profile-overlay-manage').hidden = true;
       $('manage-profile-overlay-delete').hidden = false;
-      $('delete-profile-message').textContent =
-          loadTimeData.getStringF('deleteProfileMessage', profileInfo.name);
-      $('delete-profile-message').style.backgroundImage =
+      $('delete-profile-icon').style.content =
           imageset(profileInfo.iconURL + '@scalefactorx');
+      $('delete-profile-text').textContent =
+          loadTimeData.getStringF('deleteProfileMessage', profileInfo.name);
       $('delete-managed-profile-addendum').hidden = !profileInfo.isManaged;
 
       // Because this dialog isn't useful when refreshing or as part of the
diff --git a/chrome/browser/ui/views/toolbar/toolbar_button.cc b/chrome/browser/ui/views/toolbar/toolbar_button.cc
index af3e0e2..458cf24 100644
--- a/chrome/browser/ui/views/toolbar/toolbar_button.cc
+++ b/chrome/browser/ui/views/toolbar/toolbar_button.cc
@@ -33,12 +33,13 @@
 }
 
 void ToolbarButton::Init() {
-  SetFocusable(true);
+  SetFocusable(false);
+  SetAccessibilityFocusable(true);
   image()->EnableCanvasFlippingForRTLUI(true);
 
   // Provides the hover/pressed style used by buttons in the toolbar.
   views::LabelButtonBorder* border =
-      new views::LabelButtonBorder(views::Button::STYLE_BUTTON);
+      new views::LabelButtonBorder(views::Button::STYLE_TEXTBUTTON);
   const int kHoverImages[] = IMAGE_GRID(IDR_TOOLBAR_BUTTON_HOVER);
   border->SetPainter(false, views::Button::STATE_HOVERED,
                      views::Painter::CreateImageGridPainter(
@@ -47,8 +48,6 @@
   border->SetPainter(false, views::Button::STATE_PRESSED,
                      views::Painter::CreateImageGridPainter(
                          kPressedImages));
-  border->SetPainter(false, views::Button::STATE_NORMAL, NULL);
-  border->SetPainter(true, views::Button::STATE_NORMAL, NULL);
   set_border(border);
 }
 
diff --git a/chrome/common/extensions/api/_permission_features.json b/chrome/common/extensions/api/_permission_features.json
index 8483809..5ce98ed 100644
--- a/chrome/common/extensions/api/_permission_features.json
+++ b/chrome/common/extensions/api/_permission_features.json
@@ -90,7 +90,9 @@
       "whitelist": [
         // http://crbug.com/292856
         "3F50C3A83839D9C76334BCE81CDEC06174F266AF",
-        "09FDCB5851B8F3378DB630D06E316076E89C95A6"
+        "09FDCB5851B8F3378DB630D06E316076E89C95A6",
+        "39BE69F11F68E4EED080DA3DC2394F7885B7AFF9",
+        "FF78670081967CE21DB86A04AD94A0498F01E20A"
       ]
     }
   ],
@@ -263,7 +265,7 @@
     "extension_types": ["extension", "legacy_packaged_app"]
   },
   "declarativeContent": {
-    "channel": "dev",
+    "channel": "stable",
     "extension_types": ["extension"]
   },
   "declarativeWebRequest": [
diff --git a/chrome/common/pref_names.cc b/chrome/common/pref_names.cc
index 63ab434..71e8559 100644
--- a/chrome/common/pref_names.cc
+++ b/chrome/common/pref_names.cc
@@ -2259,6 +2259,10 @@
 // A boolean pref of the device registered flag (second part after first login).
 const char kDeviceRegistered[] = "DeviceRegistered";
 
+// List of usernames that used certificates pushed by policy before.
+// This is used to prevent these users from joining multiprofile sessions.
+const char kUsedPolicyCertificates[] = "policy.used_policy_certificates";
+
 #endif
 
 // Whether there is a Flash version installed that supports clearing LSO data.
diff --git a/chrome/common/pref_names.h b/chrome/common/pref_names.h
index d73915f..267c88d 100644
--- a/chrome/common/pref_names.h
+++ b/chrome/common/pref_names.h
@@ -776,6 +776,7 @@
 extern const char kInitialLocale[];
 extern const char kOobeComplete[];
 extern const char kDeviceRegistered[];
+extern const char kUsedPolicyCertificates[];
 #endif
 
 extern const char kClearPluginLSODataEnabled[];
diff --git a/components/autofill/core/browser/autofill_manager.cc b/components/autofill/core/browser/autofill_manager.cc
index b780de8..edaa35e 100644
--- a/components/autofill/core/browser/autofill_manager.cc
+++ b/components/autofill/core/browser/autofill_manager.cc
@@ -609,6 +609,10 @@
     const gfx::RectF& bounds,
     const std::vector<base::string16>& suggestions,
     const std::vector<base::string16>& realms) {
+  // Bail if the IPC message is corrupt.
+  if (suggestions.size() != realms.size())
+    return;
+
   external_delegate_->OnShowPasswordSuggestions(suggestions,
                                                 realms,
                                                 field,
@@ -617,6 +621,7 @@
 
 void AutofillManager::OnSetDataList(const std::vector<base::string16>& values,
                                     const std::vector<base::string16>& labels) {
+  // Bail if the IPC message is corrupt.
   if (values.size() != labels.size())
     return;
 
diff --git a/content/browser/aura/gpu_process_transport_factory.cc b/content/browser/aura/gpu_process_transport_factory.cc
index ee92513..38dc904 100644
--- a/content/browser/aura/gpu_process_transport_factory.cc
+++ b/content/browser/aura/gpu_process_transport_factory.cc
@@ -185,6 +185,11 @@
 
   scoped_refptr<ContextProviderCommandBuffer> context_provider;
 
+  // Software fallback does not happen on Chrome OS.
+#if defined(OS_CHROMEOS)
+  software_fallback = false;
+#endif
+
   CommandLine* command_line = CommandLine::ForCurrentProcess();
   if (!command_line->HasSwitch(switches::kUIEnableSoftwareCompositing) &&
       !software_fallback) {
diff --git a/content/browser/renderer_host/pepper/pepper_file_io_host.cc b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
index 29df532..041a28d 100644
--- a/content/browser/renderer_host/pepper/pepper_file_io_host.cc
+++ b/content/browser/renderer_host/pepper/pepper_file_io_host.cc
@@ -405,8 +405,10 @@
 
 int32_t PepperFileIOHost::OnHostMsgClose(
     ppapi::host::HostMessageContext* context) {
-  if (check_quota_)
+  if (check_quota_) {
     file_system_host_->CloseQuotaFile(this);
+    check_quota_ = false;
+  }
 
   if (file_ != base::kInvalidPlatformFileValue) {
     base::FileUtilProxy::Close(
diff --git a/content/common/gpu/gpu_memory_manager.cc b/content/common/gpu/gpu_memory_manager.cc
index e693627..5dfd3fb 100644
--- a/content/common/gpu/gpu_memory_manager.cc
+++ b/content/common/gpu/gpu_memory_manager.cc
@@ -54,6 +54,7 @@
       manage_immediate_scheduled_(false),
       max_surfaces_with_frontbuffer_soft_limit_(
           max_surfaces_with_frontbuffer_soft_limit),
+      priority_cutoff_(MemoryAllocation::CUTOFF_ALLOW_EVERYTHING),
       bytes_available_gpu_memory_(0),
       bytes_available_gpu_memory_overridden_(false),
       bytes_minimum_per_client_(0),
@@ -68,12 +69,23 @@
 {
   CommandLine* command_line = CommandLine::ForCurrentProcess();
 
+  // Use a more conservative memory allocation policy on Linux and Mac because
+  // the platform is unstable when under memory pressure.
+  // http://crbug.com/145600 (Linux)
+  // http://crbug.com/141377 (Mac)
+#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
+  priority_cutoff_ = MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
+#endif
+
 #if defined(OS_ANDROID)
   bytes_default_per_client_ = 8 * 1024 * 1024;
   bytes_minimum_per_client_ = 8 * 1024 * 1024;
 #elif defined(OS_CHROMEOS)
   bytes_default_per_client_ = 64 * 1024 * 1024;
   bytes_minimum_per_client_ = 4 * 1024 * 1024;
+#elif defined(OS_MACOSX)
+  bytes_default_per_client_ = 128 * 1024 * 1024;
+  bytes_minimum_per_client_ = 128 * 1024 * 1024;
 #else
   bytes_default_per_client_ = 64 * 1024 * 1024;
   bytes_minimum_per_client_ = 64 * 1024 * 1024;
@@ -659,16 +671,7 @@
 
     allocation.bytes_limit_when_visible =
         client_state->bytes_allocation_when_visible_;
-    // Use a more conservative memory allocation policy on Linux and Mac
-    // because the platform is unstable when under memory pressure.
-    // http://crbug.com/145600 (Linux)
-    // http://crbug.com/141377 (Mac)
-    allocation.priority_cutoff_when_visible =
-#if defined(OS_MACOSX) || (defined(OS_LINUX) && !defined(OS_CHROMEOS))
-        MemoryAllocation::CUTOFF_ALLOW_NICE_TO_HAVE;
-#else
-        MemoryAllocation::CUTOFF_ALLOW_EVERYTHING;
-#endif
+    allocation.priority_cutoff_when_visible = priority_cutoff_;
 
     client_state->client_->SetMemoryAllocation(allocation);
     client_state->client_->SuggestHaveFrontBuffer(!client_state->hibernated_);
diff --git a/content/common/gpu/gpu_memory_manager.h b/content/common/gpu/gpu_memory_manager.h
index a895968..255c20b 100644
--- a/content/common/gpu/gpu_memory_manager.h
+++ b/content/common/gpu/gpu_memory_manager.h
@@ -227,6 +227,9 @@
 
   uint64 max_surfaces_with_frontbuffer_soft_limit_;
 
+  // The priority cutoff used for all renderers.
+  gpu::MemoryAllocation::PriorityCutoff priority_cutoff_;
+
   // The maximum amount of memory that may be allocated for GPU resources
   uint64 bytes_available_gpu_memory_;
   bool bytes_available_gpu_memory_overridden_;
diff --git a/gpu/config/software_rendering_list_json.cc b/gpu/config/software_rendering_list_json.cc
index 08d100f..9af3694 100644
--- a/gpu/config/software_rendering_list_json.cc
+++ b/gpu/config/software_rendering_list_json.cc
@@ -18,7 +18,7 @@
 {
   "name": "software rendering list",
   // Please update the version number whenever you change this file.
-  "version": "6.19",
+  "version": "6.20",
   "entries": [
     {
       "id": 1,
@@ -1003,6 +1003,23 @@
       "features": [
         "all"
       ]
+    },
+    {
+      "id": 85,
+      "description": "Samsung Gaxlaxy S4 is too buggy to use for video decoding",
+      "cr_bugs": [329072],
+      "os": {
+        "type": "android"
+      },
+      "machine_model": {
+        "name": {
+          "op": "=",
+          "value": "SCH-I545"
+        }
+      },
+      "features": [
+        "accelerated_video_decode"
+      ]
     }
   ]
 }
diff --git a/media/filters/audio_renderer_impl.cc b/media/filters/audio_renderer_impl.cc
index fc5b7bf..2df537d 100644
--- a/media/filters/audio_renderer_impl.cc
+++ b/media/filters/audio_renderer_impl.cc
@@ -163,6 +163,9 @@
 
 void AudioRendererImpl::ResetDecoderDone() {
   base::AutoLock auto_lock(lock_);
+  if (state_ == kStopped)
+    return;
+
   DCHECK_EQ(state_, kPaused);
   DCHECK(!flush_cb_.is_null());
 
@@ -198,6 +201,7 @@
     init_cb_.Reset();
     underflow_cb_.Reset();
     time_cb_.Reset();
+    flush_cb_.Reset();
   }
 
   callback.Run();
diff --git a/media/filters/audio_renderer_impl_unittest.cc b/media/filters/audio_renderer_impl_unittest.cc
index 3878480..5adfbc4 100644
--- a/media/filters/audio_renderer_impl_unittest.cc
+++ b/media/filters/audio_renderer_impl_unittest.cc
@@ -798,4 +798,30 @@
   Preroll(1000, PIPELINE_OK);
 }
 
+TEST_F(AudioRendererImplTest, StopDuringFlush) {
+  Initialize();
+
+  Preroll();
+  Play();
+
+  // Partially drain internal buffer so we get a pending read.
+  EXPECT_TRUE(ConsumeBufferedData(frames_buffered() / 2, NULL));
+  WaitForPendingRead();
+
+  Pause();
+
+  EXPECT_TRUE(IsReadPending());
+
+  // Start flushing.
+  WaitableMessageLoopEvent flush_event;
+  renderer_->Flush(flush_event.GetClosure());
+
+  SatisfyPendingRead(kDataSize);
+
+  // Request a Stop() before the flush completes.
+  WaitableMessageLoopEvent stop_event;
+  renderer_->Stop(stop_event.GetClosure());
+  stop_event.RunAndWait();
+}
+
 }  // namespace media
diff --git a/net/http/transport_security_state_static.h b/net/http/transport_security_state_static.h
index f996c5e..0d127da 100644
--- a/net/http/transport_security_state_static.h
+++ b/net/http/transport_security_state_static.h
@@ -390,7 +390,7 @@
   {17, true, "\004goto\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
   {18, true, "\005cloud\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
   {18, true, "\005glass\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
-  {17, true, "\004play\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
+  {17, false, "\004play\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
   {20, true, "\006market\007android\003com", true, kGooglePins, DOMAIN_ANDROID_COM },
   {26, true, "\003ssl\020google-analytics\003com", true, kGooglePins, DOMAIN_GOOGLE_ANALYTICS_COM },
   {18, true, "\005drive\006google\003com", true, kGooglePins, DOMAIN_GOOGLE_COM },
diff --git a/net/http/transport_security_state_static.json b/net/http/transport_security_state_static.json
index f45b8c0..0b9c2ae 100644
--- a/net/http/transport_security_state_static.json
+++ b/net/http/transport_security_state_static.json
@@ -181,7 +181,8 @@
     { "name": "goto.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
     { "name": "cloud.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
     { "name": "glass.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
-    { "name": "play.google.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
+    // play.google.com doesn't have include_subdomains because of crbug.com/327834.
+    { "name": "play.google.com", "mode": "force-https", "pins": "google" },
 
     // Other Google-related domains that must use HTTPS.
     { "name": "market.android.com", "include_subdomains": true, "mode": "force-https", "pins": "google" },
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index dbf64af..0c73ec6 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -652,6 +652,14 @@
   bool HasPendingAsyncOperation();
   bool HasUnhandledReceivedData();
 
+  // Called on the network task runner.
+  // Causes the associated SSL/TLS session ID to be added to NSS's session
+  // cache, but only if the connection has not been False Started.
+  //
+  // This should only be called after the server's certificate has been
+  // verified, and may not be called within an NSS callback.
+  void CacheSessionIfNecessary();
+
  private:
   friend class base::RefCountedThreadSafe<Core>;
   ~Core();
@@ -1274,6 +1282,30 @@
   return unhandled_buffer_size_ != 0;
 }
 
+void SSLClientSocketNSS::Core::CacheSessionIfNecessary() {
+  // TODO(rsleevi): This should occur on the NSS task runner, due to the use of
+  // nss_fd_. However, it happens on the network task runner in order to match
+  // the buggy behavior of ExportKeyingMaterial.
+  //
+  // Once http://crbug.com/330360 is fixed, this should be moved to an
+  // implementation that exclusively does this work on the NSS TaskRunner. This
+  // is "safe" because it is only called during the certificate verification
+  // state machine of the main socket, which is safe because no underlying
+  // transport IO will be occuring in that state, and NSS will not be blocking
+  // on any PKCS#11 related locks that might block the Network TaskRunner.
+  DCHECK(OnNetworkTaskRunner());
+
+  // Only cache the session if the connection was not False Started, because
+  // sessions should only be cached *after* the peer's Finished message is
+  // processed.
+  // In the case of False Start, the session will be cached once the
+  // HandshakeCallback is called, which signals the receipt and processing of
+  // the Finished message, and which will happen during a call to
+  // PR_Read/PR_Write.
+  if (!false_started_)
+    SSL_CacheSession(nss_fd_);
+}
+
 bool SSLClientSocketNSS::Core::OnNSSTaskRunner() const {
   return nss_task_runner_->RunsTasksOnCurrentThread();
 }
@@ -1650,7 +1682,17 @@
   core->handshake_callback_called_ = true;
   if (core->false_started_) {
     core->false_started_ = false;
-    // If we False Started, DoHandshake already called HandshakeSucceeded.
+    // If the connection was False Started, then at the time of this callback,
+    // the peer's certificate will have been verified or the caller will have
+    // accepted the error.
+    // This is guaranteed when using False Start because this callback will
+    // not be invoked until processing the peer's Finished message, which
+    // will only happen in a PR_Read/PR_Write call, which can only happen
+    // after the peer's certificate is verified.
+    SSL_CacheSessionUnlocked(socket);
+
+    // Additionally, when False Starting, DoHandshake() will have already
+    // called HandshakeSucceeded(), so return now.
     return;
   }
   core->HandshakeSucceeded();
@@ -3519,6 +3561,9 @@
     // Only check Certificate Transparency if there were no other errors with
     // the connection.
     VerifyCT();
+
+    // Only cache the session if the certificate verified successfully.
+    core_->CacheSessionIfNecessary();
   }
 
   completed_handshake_ = true;
diff --git a/net/socket/ssl_client_socket_openssl.cc b/net/socket/ssl_client_socket_openssl.cc
index 4c426e3..fe62def 100644
--- a/net/socket/ssl_client_socket_openssl.cc
+++ b/net/socket/ssl_client_socket_openssl.cc
@@ -888,6 +888,7 @@
   if (result == OK) {
     // TODO(joth): Work out if we need to remember the intermediate CA certs
     // when the server sends them to us, and do so here.
+    SSLContext::GetInstance()->session_cache()->MarkSSLSessionAsGood(ssl_);
   } else {
     DVLOG(1) << "DoVerifyCertComplete error " << ErrorToString(result)
              << " (" << result << ")";
diff --git a/net/socket/ssl_session_cache_openssl.cc b/net/socket/ssl_session_cache_openssl.cc
index f973276..d16bb8d 100644
--- a/net/socket/ssl_session_cache_openssl.cc
+++ b/net/socket/ssl_session_cache_openssl.cc
@@ -24,14 +24,18 @@
 class SSLContextExIndex {
 public:
   SSLContextExIndex() {
-    index_ = SSL_CTX_get_ex_new_index(0, 0, 0, 0, 0);
-    DCHECK_NE(-1, index_);
+    context_index_ = SSL_CTX_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+    DCHECK_NE(-1, context_index_);
+    session_index_ = SSL_SESSION_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+    DCHECK_NE(-1, session_index_);
   }
 
-  int index() const { return index_; }
+  int context_index() const { return context_index_; }
+  int session_index() const { return session_index_; }
 
  private:
-  int index_;
+  int context_index_;
+  int session_index_;
 };
 
 // static
@@ -41,7 +45,13 @@
 // Retrieve the global EX_DATA index, created lazily on first call, to
 // be used with SSL_CTX_set_ex_data() and SSL_CTX_get_ex_data().
 static int GetSSLContextExIndex() {
-  return s_ssl_context_ex_instance.Get().index();
+  return s_ssl_context_ex_instance.Get().context_index();
+}
+
+// Retrieve the global EX_DATA index, created lazily on first call, to
+// be used with SSL_SESSION_set_ex_data() and SSL_SESSION_get_ex_data().
+static int GetSSLSessionExIndex() {
+  return s_ssl_context_ex_instance.Get().session_index();
 }
 
 // Helper struct used to store session IDs in a SessionIdIndex container
@@ -213,6 +223,11 @@
 
     DVLOG(2) << "Lookup session: " << session << " for " << cache_key;
 
+    void* session_is_good =
+        SSL_SESSION_get_ex_data(session, GetSSLSessionExIndex());
+    if (!session_is_good)
+      return false;  // Session has not yet been marked good. Treat as a miss.
+
     // Move to front of MRU list.
     ordering_.push_front(session);
     ordering_.erase(it->second);
@@ -221,6 +236,16 @@
     return SSL_set_session(ssl, session) == 1;
   }
 
+  void MarkSSLSessionAsGood(SSL* ssl) {
+    SSL_SESSION* session = SSL_get_session(ssl);
+    if (!session)
+      return;
+
+    // Mark the session as good, allowing it to be used for future connections.
+    SSL_SESSION_set_ex_data(
+        session, GetSSLSessionExIndex(), reinterpret_cast<void*>(1));
+  }
+
   // Flush all entries from the cache.
   void Flush() {
     base::AutoLock lock(lock_);
@@ -474,6 +499,10 @@
   return impl_->SetSSLSessionWithKey(ssl, cache_key);
 }
 
+void SSLSessionCacheOpenSSL::MarkSSLSessionAsGood(SSL* ssl) {
+  return impl_->MarkSSLSessionAsGood(ssl);
+}
+
 void SSLSessionCacheOpenSSL::Flush() { impl_->Flush(); }
 
 }  // namespace net
diff --git a/net/socket/ssl_session_cache_openssl.h b/net/socket/ssl_session_cache_openssl.h
index 4490e0a..bbd9659 100644
--- a/net/socket/ssl_session_cache_openssl.h
+++ b/net/socket/ssl_session_cache_openssl.h
@@ -113,6 +113,14 @@
   // Return true iff a cached session was associated with the |ssl| connection.
   bool SetSSLSessionWithKey(SSL* ssl, const std::string& cache_key);
 
+  // Indicates that the SSL session associated with |ssl| is "good" - that is,
+  // that all associated cryptographic parameters that were negotiated,
+  // including the peer's certificate, were successfully validated. Because
+  // OpenSSL does not provide an asynchronous certificate verification
+  // callback, it's necessary to manually manage the sessions to ensure that
+  // only validated sessions are resumed.
+  void MarkSSLSessionAsGood(SSL* ssl);
+
   // Flush removes all entries from the cache. This is typically called when
   // the system's certificate store has changed.
   void Flush();
@@ -130,4 +138,4 @@
 
 }  // namespace net
 
-#endif  // NET_SOCKET_SSL_SESSION_CACHE_OPENSSL_H
\ No newline at end of file
+#endif  // NET_SOCKET_SSL_SESSION_CACHE_OPENSSL_H
diff --git a/net/socket/ssl_session_cache_openssl_unittest.cc b/net/socket/ssl_session_cache_openssl_unittest.cc
index 8075d34..22c4fba 100644
--- a/net/socket/ssl_session_cache_openssl_unittest.cc
+++ b/net/socket/ssl_session_cache_openssl_unittest.cc
@@ -212,6 +212,9 @@
   AddToCache(ssl.get());
   EXPECT_EQ(2, session->references);
 
+  // Mark the session as good, so that it is re-used for the second connection.
+  cache_.MarkSSLSessionAsGood(ssl.get());
+
   ssl.reset(NULL);
   EXPECT_EQ(1, session->references);
 
@@ -227,6 +230,7 @@
   const std::string key("hello");
   ScopedSSL ssl(NewSSL(key));
   AddToCache(ssl.get());
+  cache_.MarkSSLSessionAsGood(ssl.get());
   ssl.reset(NULL);
 
   ScopedSSL ssl2(NewSSL(key));
@@ -252,6 +256,52 @@
   EXPECT_EQ(2, ssl2.get()->session->references);
 }
 
+// Check that when two connections have the same key, a new session is created
+// if the existing session has not yet been marked "good". Further, after the
+// first session completes, if the second session has replaced it in the cache,
+// new sessions should continue to fail until the currently cached session
+// succeeds.
+TEST_F(SSLSessionCacheOpenSSLTest, CheckSessionReplacementWhenNotGood) {
+  const std::string key("hello");
+  ScopedSSL ssl(NewSSL(key));
+
+  // First call should fail because the session is not in the cache.
+  EXPECT_FALSE(cache_.SetSSLSession(ssl.get()));
+  SSL_SESSION* session = ssl.get()->session;
+  ASSERT_TRUE(session);
+  EXPECT_EQ(1, session->references);
+
+  AddToCache(ssl.get());
+  EXPECT_EQ(2, session->references);
+
+  // Second call should find the session ID, but because it is not yet good,
+  // fail to associate it with |ssl2|.
+  ScopedSSL ssl2(NewSSL(key));
+  EXPECT_FALSE(cache_.SetSSLSession(ssl2.get()));
+  SSL_SESSION* session2 = ssl2.get()->session;
+  ASSERT_TRUE(session2);
+  EXPECT_EQ(1, session2->references);
+
+  EXPECT_NE(session, session2);
+
+  // Add the second connection to the cache. It should replace the first
+  // session, and the cache should hold on to the second session.
+  AddToCache(ssl2.get());
+  EXPECT_EQ(1, session->references);
+  EXPECT_EQ(2, session2->references);
+
+  // Mark the first session as good, simulating it completing.
+  cache_.MarkSSLSessionAsGood(ssl.get());
+
+  // Third call should find the session ID, but because the second session (the
+  // current cache entry) is not yet good, fail to associate it with |ssl3|.
+  ScopedSSL ssl3(NewSSL(key));
+  EXPECT_FALSE(cache_.SetSSLSession(ssl3.get()));
+  EXPECT_NE(session, ssl3.get()->session);
+  EXPECT_NE(session2, ssl3.get()->session);
+  EXPECT_EQ(1, ssl3.get()->session->references);
+}
+
 TEST_F(SSLSessionCacheOpenSSLTest, CheckEviction) {
   const size_t kMaxItems = 20;
   int local_id = 1;
diff --git a/net/third_party/nss/README.chromium b/net/third_party/nss/README.chromium
index 06d3e12..8c4e008 100644
--- a/net/third_party/nss/README.chromium
+++ b/net/third_party/nss/README.chromium
@@ -163,6 +163,16 @@
     https://bugzilla.mozilla.org/show_bug.cgi?id=930857
     patches/disableticketrenewal.patch
 
+  * Add explicit functions for managing the SSL/TLS session cache.
+    This is a temporary workaround until Chromium migrates to NSS's
+    asynchronous certificate verification.
+    patches/sessioncache.patch
+
+  * Remove static storage qualifier from variables in sslnonce.c. Due to
+    a clang codegen bug on Mac, this caused an infinite loop.
+    https://code.google.com/p/chromium/issues/detail?id=326011
+    patches/sslnoncestatics.patch
+
 Apply the patches to NSS by running the patches/applypatches.sh script.  Read
 the comments at the top of patches/applypatches.sh for instructions.
 
diff --git a/net/third_party/nss/patches/applypatches.sh b/net/third_party/nss/patches/applypatches.sh
index 33850e2..89d97bc 100755
--- a/net/third_party/nss/patches/applypatches.sh
+++ b/net/third_party/nss/patches/applypatches.sh
@@ -81,3 +81,7 @@
 patch -p4 < $patches_dir/fallbackscsv.patch
 
 patch -p4 < $patches_dir/disableticketrenewal.patch
+
+patch -p4 < $patches_dir/sessioncache.patch
+
+patch -p4 < $patches_dir/sslnoncestatics.patch
diff --git a/net/third_party/nss/patches/sessioncache.patch b/net/third_party/nss/patches/sessioncache.patch
new file mode 100644
index 0000000..11fd9fc
--- /dev/null
+++ b/net/third_party/nss/patches/sessioncache.patch
@@ -0,0 +1,100 @@
+diff --git a/net/third_party/nss/ssl/exports_win.def b/net/third_party/nss/ssl/exports_win.def
+index e0624f1..a1045bb 100644
+--- a/net/third_party/nss/ssl/exports_win.def
++++ b/net/third_party/nss/ssl/exports_win.def
+@@ -62,3 +62,5 @@ SSL_RestartHandshakeAfterChannelIDReq
+ SSL_GetChannelBinding
+ SSL_PeerSignedCertTimestamps
+ SSL_CipherOrderSet
++SSL_CacheSession
++SSL_CacheSessionUnlocked
+diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
+index bef33fc..6f7c988 100644
+--- a/net/third_party/nss/ssl/ssl.h
++++ b/net/third_party/nss/ssl/ssl.h
+@@ -872,6 +872,18 @@ SSL_IMPORT int SSL_DataPending(PRFileDesc *fd);
+ SSL_IMPORT SECStatus SSL_InvalidateSession(PRFileDesc *fd);
+ 
+ /*
++** Cache the SSL session associated with fd, if it has not already been cached.
++*/
++SSL_IMPORT SECStatus SSL_CacheSession(PRFileDesc *fd);
++
++/*
++** Cache the SSL session associated with fd, if it has not already been cached.
++** This function may only be called when processing within a callback assigned
++** via SSL_HandshakeCallback
++*/
++SSL_IMPORT SECStatus SSL_CacheSessionUnlocked(PRFileDesc *fd);
++
++/*
+ ** Return a SECItem containing the SSL session ID associated with the fd.
+ */
+ SSL_IMPORT SECItem *SSL_GetSessionID(PRFileDesc *fd);
+diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
+index 307a0fe..e2be5e6 100644
+--- a/net/third_party/nss/ssl/ssl3con.c
++++ b/net/third_party/nss/ssl/ssl3con.c
+@@ -11240,7 +11240,7 @@ ssl3_FinishHandshake(sslSocket * ss)
+     /* The first handshake is now completed. */
+     ss->handshake           = NULL;
+ 
+-    if (ss->ssl3.hs.cacheSID) {
++    if (ss->ssl3.hs.cacheSID && ss->sec.isServer) {
+ 	(*ss->sec.cache)(ss->sec.ci.sid);
+ 	ss->ssl3.hs.cacheSID = PR_FALSE;
+     }
+diff --git a/net/third_party/nss/ssl/sslsecur.c b/net/third_party/nss/ssl/sslsecur.c
+index 31c343f..99538e5 100644
+--- a/net/third_party/nss/ssl/sslsecur.c
++++ b/net/third_party/nss/ssl/sslsecur.c
+@@ -1474,6 +1474,49 @@ SSL_InvalidateSession(PRFileDesc *fd)
+     return rv;
+ }
+ 
++static void
++ssl3_CacheSessionUnlocked(sslSocket *ss)
++{
++    PORT_Assert(!ss->sec.isServer);
++
++    if (ss->ssl3.hs.cacheSID) {
++	ss->sec.cache(ss->sec.ci.sid);
++	ss->ssl3.hs.cacheSID = PR_FALSE;
++    }
++}
++
++SECStatus
++SSL_CacheSession(PRFileDesc *fd)
++{
++    sslSocket *   ss = ssl_FindSocket(fd);
++    SECStatus     rv = SECFailure;
++
++    if (ss) {
++	ssl_Get1stHandshakeLock(ss);
++	ssl_GetSSL3HandshakeLock(ss);
++
++	ssl3_CacheSessionUnlocked(ss);
++	rv = SECSuccess;
++
++	ssl_ReleaseSSL3HandshakeLock(ss);
++	ssl_Release1stHandshakeLock(ss);
++    }
++    return rv;
++}
++
++SECStatus
++SSL_CacheSessionUnlocked(PRFileDesc *fd)
++{
++    sslSocket *   ss = ssl_FindSocket(fd);
++    SECStatus     rv = SECFailure;
++
++    if (ss) {
++	ssl3_CacheSessionUnlocked(ss);
++	rv = SECSuccess;
++    }
++    return rv;
++}
++
+ SECItem *
+ SSL_GetSessionID(PRFileDesc *fd)
+ {
diff --git a/net/third_party/nss/patches/sslnoncestatics.patch b/net/third_party/nss/patches/sslnoncestatics.patch
new file mode 100644
index 0000000..336fe1d
--- /dev/null
+++ b/net/third_party/nss/patches/sslnoncestatics.patch
@@ -0,0 +1,15 @@
+diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c
+index 758aa4e..a3e6e0a 100644
+--- a/net/third_party/nss/ssl/sslnonce.c
++++ b/net/third_party/nss/ssl/sslnonce.c
+@@ -21,8 +21,8 @@
+ PRUint32 ssl_sid_timeout = 100;
+ PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
+ 
+-static sslSessionID *cache = NULL;
+-static PZLock *      cacheLock = NULL;
++sslSessionID *cache = NULL;
++PZLock *      cacheLock = NULL;
+ 
+ /* sids can be in one of 4 states:
+  *
diff --git a/net/third_party/nss/ssl/exports_win.def b/net/third_party/nss/ssl/exports_win.def
index e0624f1..a1045bb 100644
--- a/net/third_party/nss/ssl/exports_win.def
+++ b/net/third_party/nss/ssl/exports_win.def
@@ -62,3 +62,5 @@
 SSL_GetChannelBinding
 SSL_PeerSignedCertTimestamps
 SSL_CipherOrderSet
+SSL_CacheSession
+SSL_CacheSessionUnlocked
diff --git a/net/third_party/nss/ssl/ssl.h b/net/third_party/nss/ssl/ssl.h
index bef33fc..6f7c988 100644
--- a/net/third_party/nss/ssl/ssl.h
+++ b/net/third_party/nss/ssl/ssl.h
@@ -872,6 +872,18 @@
 SSL_IMPORT SECStatus SSL_InvalidateSession(PRFileDesc *fd);
 
 /*
+** Cache the SSL session associated with fd, if it has not already been cached.
+*/
+SSL_IMPORT SECStatus SSL_CacheSession(PRFileDesc *fd);
+
+/*
+** Cache the SSL session associated with fd, if it has not already been cached.
+** This function may only be called when processing within a callback assigned
+** via SSL_HandshakeCallback
+*/
+SSL_IMPORT SECStatus SSL_CacheSessionUnlocked(PRFileDesc *fd);
+
+/*
 ** Return a SECItem containing the SSL session ID associated with the fd.
 */
 SSL_IMPORT SECItem *SSL_GetSessionID(PRFileDesc *fd);
diff --git a/net/third_party/nss/ssl/ssl3con.c b/net/third_party/nss/ssl/ssl3con.c
index 307a0fe..e2be5e6 100644
--- a/net/third_party/nss/ssl/ssl3con.c
+++ b/net/third_party/nss/ssl/ssl3con.c
@@ -11240,7 +11240,7 @@
     /* The first handshake is now completed. */
     ss->handshake           = NULL;
 
-    if (ss->ssl3.hs.cacheSID) {
+    if (ss->ssl3.hs.cacheSID && ss->sec.isServer) {
 	(*ss->sec.cache)(ss->sec.ci.sid);
 	ss->ssl3.hs.cacheSID = PR_FALSE;
     }
diff --git a/net/third_party/nss/ssl/sslnonce.c b/net/third_party/nss/ssl/sslnonce.c
index 758aa4e..a3e6e0a 100644
--- a/net/third_party/nss/ssl/sslnonce.c
+++ b/net/third_party/nss/ssl/sslnonce.c
@@ -21,8 +21,8 @@
 PRUint32 ssl_sid_timeout = 100;
 PRUint32 ssl3_sid_timeout = 86400L; /* 24 hours */
 
-static sslSessionID *cache = NULL;
-static PZLock *      cacheLock = NULL;
+sslSessionID *cache = NULL;
+PZLock *      cacheLock = NULL;
 
 /* sids can be in one of 4 states:
  *
diff --git a/net/third_party/nss/ssl/sslsecur.c b/net/third_party/nss/ssl/sslsecur.c
index 31c343f..99538e5 100644
--- a/net/third_party/nss/ssl/sslsecur.c
+++ b/net/third_party/nss/ssl/sslsecur.c
@@ -1474,6 +1474,49 @@
     return rv;
 }
 
+static void
+ssl3_CacheSessionUnlocked(sslSocket *ss)
+{
+    PORT_Assert(!ss->sec.isServer);
+
+    if (ss->ssl3.hs.cacheSID) {
+	ss->sec.cache(ss->sec.ci.sid);
+	ss->ssl3.hs.cacheSID = PR_FALSE;
+    }
+}
+
+SECStatus
+SSL_CacheSession(PRFileDesc *fd)
+{
+    sslSocket *   ss = ssl_FindSocket(fd);
+    SECStatus     rv = SECFailure;
+
+    if (ss) {
+	ssl_Get1stHandshakeLock(ss);
+	ssl_GetSSL3HandshakeLock(ss);
+
+	ssl3_CacheSessionUnlocked(ss);
+	rv = SECSuccess;
+
+	ssl_ReleaseSSL3HandshakeLock(ss);
+	ssl_Release1stHandshakeLock(ss);
+    }
+    return rv;
+}
+
+SECStatus
+SSL_CacheSessionUnlocked(PRFileDesc *fd)
+{
+    sslSocket *   ss = ssl_FindSocket(fd);
+    SECStatus     rv = SECFailure;
+
+    if (ss) {
+	ssl3_CacheSessionUnlocked(ss);
+	rv = SECSuccess;
+    }
+    return rv;
+}
+
 SECItem *
 SSL_GetSessionID(PRFileDesc *fd)
 {
diff --git a/net/url_request/url_request_unittest.cc b/net/url_request/url_request_unittest.cc
index b90fecf..fbc90d2 100644
--- a/net/url_request/url_request_unittest.cc
+++ b/net/url_request/url_request_unittest.cc
@@ -44,6 +44,7 @@
 #include "net/base/upload_data_stream.h"
 #include "net/base/upload_file_element_reader.h"
 #include "net/cert/ev_root_ca_metadata.h"
+#include "net/cert/mock_cert_verifier.h"
 #include "net/cert/test_root_certs.h"
 #include "net/cookies/cookie_monster.h"
 #include "net/cookies/cookie_store_test_helpers.h"
@@ -6510,6 +6511,104 @@
   }
 }
 
+class HTTPSSessionTest : public testing::Test {
+ public:
+  HTTPSSessionTest() : default_context_(true) {
+    cert_verifier_.set_default_result(net::OK);
+
+    default_context_.set_network_delegate(&default_network_delegate_);
+    default_context_.set_cert_verifier(&cert_verifier_);
+    default_context_.Init();
+  }
+  virtual ~HTTPSSessionTest() {}
+
+ protected:
+  MockCertVerifier cert_verifier_;
+  TestNetworkDelegate default_network_delegate_;  // Must outlive URLRequest.
+  TestURLRequestContext default_context_;
+};
+
+// Tests that session resumption is not attempted if an invalid certificate
+// is presented.
+TEST_F(HTTPSSessionTest, DontResumeSessionsForInvalidCertificates) {
+  SpawnedTestServer::SSLOptions ssl_options;
+  ssl_options.record_resume = true;
+  SpawnedTestServer test_server(
+      SpawnedTestServer::TYPE_HTTPS,
+      ssl_options,
+      base::FilePath(FILE_PATH_LITERAL("net/data/ssl")));
+  ASSERT_TRUE(test_server.Start());
+
+  SSLClientSocket::ClearSessionCache();
+
+  // Simulate the certificate being expired and attempt a connection.
+  cert_verifier_.set_default_result(net::ERR_CERT_DATE_INVALID);
+  {
+    TestDelegate d;
+    URLRequest r(test_server.GetURL("ssl-session-cache"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &default_context_);
+
+    r.Start();
+    EXPECT_TRUE(r.is_pending());
+
+    base::RunLoop().Run();
+
+    EXPECT_EQ(1, d.response_started_count());
+  }
+
+  reinterpret_cast<HttpCache*>(default_context_.http_transaction_factory())->
+    CloseAllConnections();
+
+  // Now change the certificate to be acceptable (so that the response is
+  // loaded), and ensure that no session id is presented to the peer.
+  cert_verifier_.set_default_result(net::OK);
+  {
+    TestDelegate d;
+    URLRequest r(test_server.GetURL("ssl-session-cache"),
+                 DEFAULT_PRIORITY,
+                 &d,
+                 &default_context_);
+
+    r.Start();
+    EXPECT_TRUE(r.is_pending());
+
+    base::RunLoop().Run();
+
+    // The response will look like;
+    //   insert abc
+    //   insert xyz
+    //
+    // With a newline at the end which makes the split think that there are
+    // three lines.
+    //
+    // If a session was presented (eg: a bug), then the response would look
+    // like;
+    //   insert abc
+    //   lookup abc
+    //   insert xyz
+
+    EXPECT_EQ(1, d.response_started_count());
+    std::vector<std::string> lines;
+    base::SplitString(d.data_received(), '\n', &lines);
+    ASSERT_EQ(3u, lines.size()) << d.data_received();
+
+    std::string session_id;
+    for (size_t i = 0; i < 2; i++) {
+      std::vector<std::string> parts;
+      base::SplitString(lines[i], '\t', &parts);
+      ASSERT_EQ(2u, parts.size());
+      EXPECT_EQ("insert", parts[0]);
+      if (i == 0) {
+        session_id = parts[1];
+      } else {
+        EXPECT_NE(session_id, parts[1]);
+      }
+    }
+  }
+}
+
 class TestSSLConfigService : public SSLConfigService {
  public:
   TestSSLConfigService(bool ev_enabled,
diff --git a/ppapi/proxy/file_io_resource.cc b/ppapi/proxy/file_io_resource.cc
index 5ad2bbb..ad07187 100644
--- a/ppapi/proxy/file_io_resource.cc
+++ b/ppapi/proxy/file_io_resource.cc
@@ -18,10 +18,12 @@
 #include "ppapi/shared_impl/resource_tracker.h"
 #include "ppapi/thunk/enter.h"
 #include "ppapi/thunk/ppb_file_ref_api.h"
+#include "ppapi/thunk/ppb_file_system_api.h"
 
 using ppapi::thunk::EnterResourceNoLock;
 using ppapi::thunk::PPB_FileIO_API;
 using ppapi::thunk::PPB_FileRef_API;
+using ppapi::thunk::PPB_FileSystem_API;
 
 namespace {
 
@@ -80,11 +82,13 @@
 
 FileIOResource::FileIOResource(Connection connection, PP_Instance instance)
     : PluginResource(connection, instance),
-      file_system_type_(PP_FILESYSTEMTYPE_INVALID) {
+      file_system_type_(PP_FILESYSTEMTYPE_INVALID),
+      called_close_(false) {
   SendCreate(BROWSER, PpapiHostMsg_FileIO_Create());
 }
 
 FileIOResource::~FileIOResource() {
+  Close();
 }
 
 PPB_FileIO_API* FileIOResource::AsPPB_FileIO_API() {
@@ -94,30 +98,36 @@
 int32_t FileIOResource::Open(PP_Resource file_ref,
                              int32_t open_flags,
                              scoped_refptr<TrackedCallback> callback) {
-  EnterResourceNoLock<PPB_FileRef_API> enter(file_ref, true);
-  if (enter.failed())
+  EnterResourceNoLock<PPB_FileRef_API> enter_file_ref(file_ref, true);
+  if (enter_file_ref.failed())
     return PP_ERROR_BADRESOURCE;
 
-  PPB_FileRef_API* file_ref_api = enter.object();
+  PPB_FileRef_API* file_ref_api = enter_file_ref.object();
   const FileRefCreateInfo& create_info = file_ref_api->GetCreateInfo();
   if (!FileSystemTypeIsValid(create_info.file_system_type)) {
     NOTREACHED();
     return PP_ERROR_FAILED;
   }
-
   int32_t rv = state_manager_.CheckOperationState(
       FileIOStateManager::OPERATION_EXCLUSIVE, false);
   if (rv != PP_OK)
     return rv;
 
   file_system_type_ = create_info.file_system_type;
-  // Keep the FileSystem host alive by taking a reference to its resource. The
-  // FileIO host uses the FileSystem host for running tasks.
-  file_system_resource_ = create_info.file_system_plugin_resource;
+
+  if (create_info.file_system_plugin_resource) {
+    EnterResourceNoLock<PPB_FileSystem_API> enter_file_system(
+        create_info.file_system_plugin_resource, true);
+    if (enter_file_system.failed())
+      return PP_ERROR_FAILED;
+    // Take a reference on the FileSystem resource. The FileIO host uses the
+    // FileSystem host for running tasks and checking quota.
+    file_system_resource_ = enter_file_system.resource();
+  }
 
   // Take a reference on the FileRef resource while we're opening the file; we
   // don't want the plugin destroying it during the Open operation.
-  file_ref_ = enter.resource();
+  file_ref_ = enter_file_ref.resource();
 
   Call<PpapiPluginMsg_FileIO_OpenReply>(BROWSER,
       PpapiHostMsg_FileIO_Open(
@@ -279,9 +289,13 @@
 }
 
 void FileIOResource::Close() {
-  if (file_handle_) {
+  if (called_close_)
+    return;
+
+  called_close_ = true;
+  if (file_handle_)
     file_handle_ = NULL;
-  }
+
   Post(BROWSER, PpapiHostMsg_FileIO_Close());
 }
 
diff --git a/ppapi/proxy/file_io_resource.h b/ppapi/proxy/file_io_resource.h
index ee19848..bfdf24f 100644
--- a/ppapi/proxy/file_io_resource.h
+++ b/ppapi/proxy/file_io_resource.h
@@ -164,7 +164,8 @@
 
   scoped_refptr<FileHandleHolder> file_handle_;
   PP_FileSystemType file_system_type_;
-  ScopedPPResource file_system_resource_;
+  scoped_refptr<Resource> file_system_resource_;
+  bool called_close_;
   FileIOStateManager state_manager_;
 
   scoped_refptr<Resource> file_ref_;
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc
index 09d2660..51322be 100644
--- a/ui/compositor/layer.cc
+++ b/ui/compositor/layer.cc
@@ -56,6 +56,8 @@
       layer_brightness_(0.0f),
       layer_grayscale_(0.0f),
       layer_inverted_(false),
+      layer_mask_(NULL),
+      layer_mask_back_link_(NULL),
       zoom_(1),
       zoom_inset_(0),
       delegate_(NULL),
@@ -78,6 +80,8 @@
       layer_brightness_(0.0f),
       layer_grayscale_(0.0f),
       layer_inverted_(false),
+      layer_mask_(NULL),
+      layer_mask_back_link_(NULL),
       zoom_(1),
       zoom_inset_(0),
       delegate_(NULL),
@@ -96,10 +100,12 @@
   animator_ = NULL;
   if (compositor_)
     compositor_->SetRootLayer(NULL);
-  if (layer_mask_.get())
-    SetMaskLayer(scoped_ptr<Layer>());
   if (parent_)
     parent_->Remove(this);
+  if (layer_mask_)
+    SetMaskLayer(NULL);
+  if (layer_mask_back_link_)
+    layer_mask_back_link_->SetMaskLayer(NULL);
   for (size_t i = 0; i < children_.size(); ++i)
     children_[i]->parent_ = NULL;
   cc_layer_->RemoveLayerAnimationEventObserver(this);
@@ -274,18 +280,28 @@
   SetLayerFilters();
 }
 
-void Layer::SetMaskLayer(scoped_ptr<Layer> layer_mask) {
+void Layer::SetMaskLayer(Layer* layer_mask) {
   // The provided mask should not have a layer mask itself.
-  DCHECK(!layer_mask.get() ||
+  DCHECK(!layer_mask ||
          (!layer_mask->layer_mask_layer() &&
-          layer_mask->children().empty()));
-  if (layer_mask_.get() == layer_mask.get())
+          layer_mask->children().empty() &&
+          !layer_mask->layer_mask_back_link_));
+  DCHECK(!layer_mask_back_link_);
+  if (layer_mask_ == layer_mask)
     return;
-  layer_mask_ = layer_mask.Pass();
+  // We need to de-reference the currently linked object so that no problem
+  // arises if the mask layer gets deleted before this object.
+  if (layer_mask_)
+    layer_mask_->layer_mask_back_link_ = NULL;
+  layer_mask_ = layer_mask;
   cc_layer_->SetMaskLayer(
-      layer_mask_.get() ? layer_mask_->cc_layer() : NULL);
-  if (layer_mask_.get())
-    layer_mask_->OnDeviceScaleFactorChanged(device_scale_factor_);
+      layer_mask ? layer_mask->cc_layer() : NULL);
+  // We need to reference the linked object so that it can properly break the
+  // link to us when it gets deleted.
+  if (layer_mask) {
+    layer_mask->layer_mask_back_link_ = this;
+    layer_mask->OnDeviceScaleFactorChanged(device_scale_factor_);
+  }
 }
 
 void Layer::SetBackgroundZoom(float zoom, int inset) {
diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h
index 9ddeb56..0be0d93 100644
--- a/ui/compositor/layer.h
+++ b/ui/compositor/layer.h
@@ -198,10 +198,11 @@
 
   // Set a layer mask for a layer.
   // Note the provided layer mask can neither have a layer mask itself nor can
-  // it have any children.
+  // it have any children. The ownership of |layer_mask| will not be
+  // transferred with this call.
   // Furthermore: A mask layer can only be set to one layer.
-  void SetMaskLayer(scoped_ptr<Layer> layer_mask);
-  Layer* layer_mask_layer() { return layer_mask_.get(); }
+  void SetMaskLayer(Layer* layer_mask);
+  Layer* layer_mask_layer() { return layer_mask_; }
 
   // Sets the visibility of the Layer. A Layer may be visible but not
   // drawn. This happens if any ancestor of a Layer is not visible.
@@ -448,8 +449,12 @@
   float layer_grayscale_;
   bool layer_inverted_;
 
-  // The mask layer associated with this layer.
-  scoped_ptr<Layer> layer_mask_;
+  // The associated mask layer with this layer.
+  Layer* layer_mask_;
+  // The back link from the mask layer to it's associated masked layer.
+  // We keep this reference for the case that if the mask layer gets deleted
+  // while attached to the main layer before the main layer is deleted.
+  Layer* layer_mask_back_link_;
 
   // The zoom factor to scale the layer by.  Zooming is disabled when this is
   // set to 1.
diff --git a/ui/views/bubble/tray_bubble_view.cc b/ui/views/bubble/tray_bubble_view.cc
index 9259489..3f947ab 100644
--- a/ui/views/bubble/tray_bubble_view.cc
+++ b/ui/views/bubble/tray_bubble_view.cc
@@ -179,7 +179,7 @@
   explicit TrayBubbleContentMask(int corner_radius);
   virtual ~TrayBubbleContentMask();
 
-  void set_bounds(gfx::Rect bounds) { bounds_ = bounds; }
+  ui::Layer* layer() { return &layer_; }
 
   // Overridden from LayerDelegate.
   virtual void OnPaintLayer(gfx::Canvas* canvas) OVERRIDE;
@@ -187,22 +187,25 @@
   virtual base::Closure PrepareForLayerBoundsChange() OVERRIDE;
 
  private:
-  gfx::Rect bounds_;
+  ui::Layer layer_;
   SkScalar corner_radius_;
 
   DISALLOW_COPY_AND_ASSIGN(TrayBubbleContentMask);
 };
 
 TrayBubbleContentMask::TrayBubbleContentMask(int corner_radius)
-    : corner_radius_(corner_radius) {
+    : layer_(ui::LAYER_TEXTURED),
+      corner_radius_(corner_radius) {
+  layer_.set_delegate(this);
 }
 
 TrayBubbleContentMask::~TrayBubbleContentMask() {
+  layer_.set_delegate(NULL);
 }
 
 void TrayBubbleContentMask::OnPaintLayer(gfx::Canvas* canvas) {
   SkPath path;
-  path.addRoundRect(gfx::RectToSkRect(gfx::Rect(bounds_.size())),
+  path.addRoundRect(gfx::RectToSkRect(gfx::Rect(layer()->bounds().size())),
                     corner_radius_, corner_radius_);
   SkPaint paint;
   paint.setAlpha(255);
@@ -337,10 +340,6 @@
 
 TrayBubbleView::~TrayBubbleView() {
   mouse_watcher_.reset();
-
-  if (layer()->parent()->layer_mask_layer())
-    layer()->parent()->layer_mask_layer()->set_delegate(NULL);
-
   // Inform host items (models) that their views are being destroyed.
   if (delegate_)
     delegate_->BubbleViewDestroyed();
@@ -351,11 +350,8 @@
   SetAlignment(params_.arrow_alignment);
   bubble_border_->UpdateArrowOffset();
 
-  if (get_use_acceleration_when_possible()) {
-    scoped_ptr<ui::Layer> mask_layer(new ui::Layer(ui::LAYER_TEXTURED));
-    mask_layer->set_delegate(bubble_content_mask_.get());
-    layer()->parent()->SetMaskLayer(mask_layer.Pass());
-  }
+  if (get_use_acceleration_when_possible())
+    layer()->parent()->SetMaskLayer(bubble_content_mask_->layer());
 
   GetWidget()->Show();
   UpdateBubble();
@@ -363,11 +359,8 @@
 
 void TrayBubbleView::UpdateBubble() {
   SizeToContents();
-  if (get_use_acceleration_when_possible()) {
-    bubble_content_mask_->set_bounds(layer()->bounds());
-    if (layer()->parent()->layer_mask_layer())
-      layer()->parent()->layer_mask_layer()->SetBounds(layer()->bounds());
-  }
+  if (get_use_acceleration_when_possible())
+    bubble_content_mask_->layer()->SetBounds(layer()->bounds());
   GetWidget()->GetRootView()->SchedulePaint();
 }
 
diff --git a/ui/views/corewm/compound_event_filter.cc b/ui/views/corewm/compound_event_filter.cc
index f5fa2a4..efeca5c 100644
--- a/ui/views/corewm/compound_event_filter.cc
+++ b/ui/views/corewm/compound_event_filter.cc
@@ -72,12 +72,12 @@
 
 // Returns true if the cursor should be hidden on touch events.
 bool ShouldHideCursorOnTouch() {
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if defined(OS_CHROMEOS)
   return true;
 #else
-  // Linux Aura does not hide the cursor on touch by default.
-  // TODO(tdanderson): Change this if having consistency across
-  // all platforms which use Aura is desired.
+  // Not necessary on windows as windows does it for us. If we do need this
+  // funcionality on linux (non-chromeos) we need to make sure
+  // CompoundEventFilter shows on the right root (it currently doesn't always).
   return false;
 #endif
 }
diff --git a/ui/views/corewm/compound_event_filter_unittest.cc b/ui/views/corewm/compound_event_filter_unittest.cc
index 293e2d3..6b852e4 100644
--- a/ui/views/corewm/compound_event_filter_unittest.cc
+++ b/ui/views/corewm/compound_event_filter_unittest.cc
@@ -18,11 +18,11 @@
 
 namespace {
 
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
+#if defined(OS_CHROMEOS)
 base::TimeDelta GetTime() {
   return ui::EventTimeForNow();
 }
-#endif  // defined(OS_CHROMEOS) || defined(OS_WIN)
+#endif  // defined(OS_CHROMEOS)
 
 }
 
@@ -97,10 +97,7 @@
   dispatcher()->AsRootWindowHostDelegate()->OnHostMouseEvent(&exit);
   EXPECT_FALSE(cursor_client.IsCursorVisible());
 }
-#endif  // defined(OS_CHROMEOS)
 
-#if defined(OS_CHROMEOS) || defined(OS_WIN)
-// Touch only hides the cursor on ChromeOS and Windows (crbug.com/322250).
 TEST_F(CompoundEventFilterTest, TouchHidesCursor) {
   scoped_ptr<CompoundEventFilter> compound_filter(new CompoundEventFilter);
   aura::Env::GetInstance()->AddPreTargetHandler(compound_filter.get());
@@ -148,7 +145,7 @@
   EXPECT_FALSE(cursor_client.IsMouseEventsEnabled());
   aura::Env::GetInstance()->RemovePreTargetHandler(compound_filter.get());
 }
-#endif  // defined(OS_CHROMEOS) || defined(OS_WIN)
+#endif  // defined(OS_CHROMEOS)
 
 // Tests that if an event filter consumes a gesture, then it doesn't focus the
 // window.
diff --git a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
index ff116bc..599b625 100644
--- a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
+++ b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater.h
@@ -33,7 +33,7 @@
   static scoped_ptr<DesktopCursorLoaderUpdater> Create();
 
   // Called when a CursorLoader is created.
-  virtual void OnCreate(float device_scale_factor,
+  virtual void OnCreate(aura::RootWindow* window,
                         ui::CursorLoader* loader) = 0;
 
   // Called when the display has changed (as we may need to reload the cursor
diff --git a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc
index f57c694..80d99d1 100644
--- a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc
+++ b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.cc
@@ -53,9 +53,9 @@
 DesktopCursorLoaderUpdaterAuraLinux::~DesktopCursorLoaderUpdaterAuraLinux() {}
 
 void DesktopCursorLoaderUpdaterAuraLinux::OnCreate(
-    float device_scale_factor,
+    aura::RootWindow* window,
     ui::CursorLoader* loader) {
-  LoadImageCursors(device_scale_factor, loader);
+  LoadImageCursors(window->compositor()->device_scale_factor(), loader);
 }
 
 void DesktopCursorLoaderUpdaterAuraLinux::OnDisplayUpdated(
diff --git a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h
index c367518..02db2b2 100644
--- a/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h
+++ b/ui/views/widget/desktop_aura/desktop_cursor_loader_updater_auralinux.h
@@ -17,7 +17,7 @@
   virtual ~DesktopCursorLoaderUpdaterAuraLinux();
 
   // Overridden from DesktopCursorLoaderUpdater:
-  virtual void OnCreate(float device_scale_factor,
+  virtual void OnCreate(aura::RootWindow* window,
                         ui::CursorLoader* loader) OVERRIDE;
   virtual void OnDisplayUpdated(const gfx::Display& display,
                                 ui::CursorLoader* loader) OVERRIDE;
diff --git a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
index 71bfeca..911f775 100644
--- a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.cc
@@ -11,11 +11,13 @@
 namespace views {
 
 DesktopNativeCursorManager::DesktopNativeCursorManager(
+    aura::RootWindow* window,
     scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater)
-    : cursor_loader_updater_(cursor_loader_updater.Pass()),
+    : root_window_(window),
+      cursor_loader_updater_(cursor_loader_updater.Pass()),
       cursor_loader_(ui::CursorLoader::Create()) {
   if (cursor_loader_updater_.get())
-    cursor_loader_updater_->OnCreate(1.0f, cursor_loader_.get());
+    cursor_loader_updater_->OnCreate(root_window_, cursor_loader_.get());
 }
 
 DesktopNativeCursorManager::~DesktopNativeCursorManager() {
@@ -27,15 +29,6 @@
   return cursor;
 }
 
-void DesktopNativeCursorManager::AddRootWindow(aura::RootWindow* root_window) {
-  root_windows_.insert(root_window);
-}
-
-void DesktopNativeCursorManager::RemoveRootWindow(
-    aura::RootWindow* root_window) {
-  root_windows_.erase(root_window);
-}
-
 void DesktopNativeCursorManager::SetDisplay(
     const gfx::Display& display,
     views::corewm::NativeCursorManagerDelegate* delegate) {
@@ -55,13 +48,8 @@
   cursor_loader_->SetPlatformCursor(&new_cursor);
   delegate->CommitCursor(new_cursor);
 
-  if (delegate->IsCursorVisible()) {
-    for (RootWindows::const_iterator i = root_windows_.begin();
-         i != root_windows_.end();
-         ++i) {
-      (*i)->SetCursor(new_cursor);
-    }
-  }
+  if (delegate->IsCursorVisible())
+    root_window_->SetCursor(new_cursor);
 }
 
 void DesktopNativeCursorManager::SetVisibility(
@@ -74,18 +62,10 @@
   } else {
     gfx::NativeCursor invisible_cursor(ui::kCursorNone);
     cursor_loader_->SetPlatformCursor(&invisible_cursor);
-    for (RootWindows::const_iterator i = root_windows_.begin();
-         i != root_windows_.end();
-         ++i) {
-      (*i)->SetCursor(invisible_cursor);
-    }
+    root_window_->SetCursor(invisible_cursor);
   }
 
-  for (RootWindows::const_iterator i = root_windows_.begin();
-       i != root_windows_.end();
-       ++i) {
-    (*i)->OnCursorVisibilityChanged(visible);
-  }
+  root_window_->OnCursorVisibilityChanged(visible);
 }
 
 void DesktopNativeCursorManager::SetCursorSet(
@@ -110,11 +90,7 @@
 
   SetVisibility(delegate->IsCursorVisible(), delegate);
 
-  for (RootWindows::const_iterator i = root_windows_.begin();
-       i != root_windows_.end();
-       ++i) {
-    (*i)->OnMouseEventsEnableStateChanged(enabled);
-  }
+  root_window_->OnMouseEventsEnableStateChanged(enabled);
 }
 
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
index 18732b0..563131d 100644
--- a/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
+++ b/ui/views/widget/desktop_aura/desktop_native_cursor_manager.h
@@ -5,8 +5,6 @@
 #ifndef UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_
 #define UI_VIEWS_WIDGET_DESKTOP_AURA_DESKTOP_NATIVE_CURSOR_MANAGER_H_
 
-#include <set>
-
 #include "base/compiler_specific.h"
 #include "base/memory/scoped_ptr.h"
 #include "ui/views/corewm/native_cursor_manager.h"
@@ -27,25 +25,19 @@
 class NativeCursorManagerDelegate;
 }
 
-// A NativeCursorManager that performs the desktop-specific setting of cursor
-// state. Similar to AshNativeCursorManager, it also communicates these changes
-// to all root windows.
+// A NativeCursorManager that interacts with only one RootWindow. (Unlike the
+// one in ash, which interacts with all the RootWindows that ash knows about.)
 class VIEWS_EXPORT DesktopNativeCursorManager
     : public views::corewm::NativeCursorManager {
  public:
   DesktopNativeCursorManager(
+      aura::RootWindow* window,
       scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater);
   virtual ~DesktopNativeCursorManager();
 
   // Builds a cursor and sets the internal platform representation.
   gfx::NativeCursor GetInitializedCursor(int type);
 
-  // Adds |root_window| to the set |root_windows_|.
-  void AddRootWindow(aura::RootWindow* root_window);
-
-  // Removes |root_window| from the set |root_windows_|.
-  void RemoveRootWindow(aura::RootWindow* root_window);
-
  private:
   // Overridden from views::corewm::NativeCursorManager:
   virtual void SetDisplay(
@@ -67,10 +59,7 @@
       bool enabled,
       views::corewm::NativeCursorManagerDelegate* delegate) OVERRIDE;
 
-  // The set of root windows to notify of changes in cursor state.
-  typedef std::set<aura::RootWindow*> RootWindows;
-  RootWindows root_windows_;
-
+  aura::RootWindow* root_window_;
   scoped_ptr<DesktopCursorLoaderUpdater> cursor_loader_updater_;
   scoped_ptr<ui::CursorLoader> cursor_loader_;
 
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
index 8a008b5..70ba57a 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.cc
@@ -200,10 +200,6 @@
 ////////////////////////////////////////////////////////////////////////////////
 // DesktopNativeWidgetAura, public:
 
-DesktopNativeCursorManager* DesktopNativeWidgetAura::native_cursor_manager_ =
-    NULL;
-views::corewm::CursorManager* DesktopNativeWidgetAura::cursor_manager_ = NULL;
-
 DesktopNativeWidgetAura::DesktopNativeWidgetAura(
     internal::NativeWidgetDelegate* delegate)
     : ownership_(Widget::InitParams::NATIVE_WIDGET_OWNS_WIDGET),
@@ -289,7 +285,7 @@
   dispatcher_client_.reset();
 
   aura::client::SetCursorClient(root->window(), NULL);
-  native_cursor_manager_->RemoveRootWindow(root);
+  cursor_client_.reset();
 
   aura::client::SetScreenPositionClient(root->window(), NULL);
   position_client_.reset();
@@ -385,19 +381,6 @@
   // Pass ownership of the filter to the root_window.
   root_window_->window()->SetEventFilter(root_window_event_filter_);
 
-  // |root_window_| must be added to |native_cursor_manager_| before
-  // OnRootWindowCreated() is called.
-  if (!native_cursor_manager_) {
-    native_cursor_manager_ = new DesktopNativeCursorManager(
-        DesktopCursorLoaderUpdater::Create());
-  }
-  if (!cursor_manager_) {
-    cursor_manager_ = new views::corewm::CursorManager(
-        scoped_ptr<corewm::NativeCursorManager>(native_cursor_manager_));
-  }
-  native_cursor_manager_->AddRootWindow(root_window_.get());
-  aura::client::SetCursorClient(root_window_->window(), cursor_manager_);
-
   desktop_root_window_host_->OnRootWindowCreated(root_window_.get(), params);
 
   UpdateWindowTransparency();
@@ -415,6 +398,16 @@
   aura::client::SetDispatcherClient(root_window_->window(),
                                     dispatcher_client_.get());
 
+  DesktopNativeCursorManager* desktop_native_cursor_manager =
+      new views::DesktopNativeCursorManager(
+          root_window_.get(),
+          DesktopCursorLoaderUpdater::Create());
+  cursor_client_.reset(
+      new views::corewm::CursorManager(
+          scoped_ptr<corewm::NativeCursorManager>(
+              desktop_native_cursor_manager)));
+  aura::client::SetCursorClient(root_window_->window(), cursor_client_.get());
+
   position_client_.reset(new DesktopScreenPositionClient());
   aura::client::SetScreenPositionClient(root_window_->window(),
                                         position_client_.get());
@@ -422,7 +415,7 @@
   InstallInputMethodEventFilter();
 
   drag_drop_client_ = desktop_root_window_host_->CreateDragDropClient(
-      native_cursor_manager_);
+      desktop_native_cursor_manager);
   aura::client::SetDragDropClient(root_window_->window(),
                                   drag_drop_client_.get());
 
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
index ca4bca2..494dbc4 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura.h
@@ -41,7 +41,6 @@
 class DesktopCaptureClient;
 class DesktopDispatcherClient;
 class DesktopEventClient;
-class DesktopNativeCursorManager;
 class DesktopRootWindowHost;
 class DropHelper;
 class FocusManagerEventHandler;
@@ -78,9 +77,6 @@
   corewm::CompoundEventFilter* root_window_event_filter() {
     return root_window_event_filter_;
   }
-  aura::RootWindow* root_window() {
-    return root_window_.get();
-  }
 
   // Overridden from NativeWidget:
   virtual ui::EventHandler* GetEventHandler() OVERRIDE;
@@ -269,6 +265,7 @@
 
   scoped_ptr<aura::client::FocusClient> focus_client_;
   scoped_ptr<DesktopDispatcherClient> dispatcher_client_;
+  scoped_ptr<views::corewm::CursorManager> cursor_client_;
   scoped_ptr<aura::client::ScreenPositionClient> position_client_;
   scoped_ptr<aura::client::DragDropClient> drag_drop_client_;
   scoped_ptr<aura::client::WindowTreeClient> window_tree_client_;
@@ -295,8 +292,6 @@
   bool restore_focus_on_activate_;
 
   gfx::NativeCursor cursor_;
-  static views::corewm::CursorManager* cursor_manager_;
-  static views::DesktopNativeCursorManager* native_cursor_manager_;
 
   scoped_ptr<corewm::ShadowController> shadow_controller_;
 
diff --git a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
index 17a5f97..8390356 100644
--- a/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
+++ b/ui/views/widget/desktop_aura/desktop_native_widget_aura_unittest.cc
@@ -4,7 +4,6 @@
 
 #include "ui/views/widget/desktop_aura/desktop_native_widget_aura.h"
 
-#include "ui/aura/client/cursor_client.h"
 #include "ui/aura/root_window.h"
 #include "ui/aura/window.h"
 #include "ui/views/test/views_test_base.h"
@@ -68,95 +67,4 @@
   EXPECT_FALSE(widget.GetNativeView()->IsVisible());
 }
 
-// Verify that the cursor state is shared between two native widgets.
-TEST_F(DesktopNativeWidgetAuraTest, GlobalCursorState) {
-  // Create two native widgets, each owning different root windows.
-  Widget widget_a;
-  Widget::InitParams init_params_a =
-      CreateParams(Widget::InitParams::TYPE_WINDOW);
-  init_params_a.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  DesktopNativeWidgetAura* desktop_native_widget_aura_a =
-      new DesktopNativeWidgetAura(&widget_a);
-  init_params_a.native_widget = desktop_native_widget_aura_a;
-  widget_a.Init(init_params_a);
-
-  Widget widget_b;
-  Widget::InitParams init_params_b =
-      CreateParams(Widget::InitParams::TYPE_WINDOW);
-  init_params_b.ownership = Widget::InitParams::WIDGET_OWNS_NATIVE_WIDGET;
-  DesktopNativeWidgetAura* desktop_native_widget_aura_b =
-      new DesktopNativeWidgetAura(&widget_b);
-  init_params_b.native_widget = desktop_native_widget_aura_b;
-  widget_b.Init(init_params_b);
-
-  aura::client::CursorClient* cursor_client_a = aura::client::GetCursorClient(
-      desktop_native_widget_aura_a->root_window()->window());
-  aura::client::CursorClient* cursor_client_b = aura::client::GetCursorClient(
-      desktop_native_widget_aura_b->root_window()->window());
-
-  // Verify the cursor can be locked using one client and unlocked using
-  // another.
-  EXPECT_FALSE(cursor_client_a->IsCursorLocked());
-  EXPECT_FALSE(cursor_client_b->IsCursorLocked());
-
-  cursor_client_a->LockCursor();
-  EXPECT_TRUE(cursor_client_a->IsCursorLocked());
-  EXPECT_TRUE(cursor_client_b->IsCursorLocked());
-
-  cursor_client_b->UnlockCursor();
-  EXPECT_FALSE(cursor_client_a->IsCursorLocked());
-  EXPECT_FALSE(cursor_client_b->IsCursorLocked());
-
-  // Verify that mouse events can be disabled using one client and then
-  // re-enabled using another. Note that disabling mouse events should also
-  // have the side effect of making the cursor invisible.
-  EXPECT_TRUE(cursor_client_a->IsCursorVisible());
-  EXPECT_TRUE(cursor_client_b->IsCursorVisible());
-  EXPECT_TRUE(cursor_client_a->IsMouseEventsEnabled());
-  EXPECT_TRUE(cursor_client_b->IsMouseEventsEnabled());
-
-  cursor_client_b->DisableMouseEvents();
-  EXPECT_FALSE(cursor_client_a->IsCursorVisible());
-  EXPECT_FALSE(cursor_client_b->IsCursorVisible());
-  EXPECT_FALSE(cursor_client_a->IsMouseEventsEnabled());
-  EXPECT_FALSE(cursor_client_b->IsMouseEventsEnabled());
-
-  cursor_client_a->EnableMouseEvents();
-  EXPECT_TRUE(cursor_client_a->IsCursorVisible());
-  EXPECT_TRUE(cursor_client_b->IsCursorVisible());
-  EXPECT_TRUE(cursor_client_a->IsMouseEventsEnabled());
-  EXPECT_TRUE(cursor_client_b->IsMouseEventsEnabled());
-
-  // Verify that setting the cursor using one cursor client
-  // will set it for all root windows.
-  EXPECT_EQ(ui::kCursorNone, cursor_client_a->GetCursor().native_type());
-  EXPECT_EQ(ui::kCursorNone, cursor_client_b->GetCursor().native_type());
-
-  cursor_client_b->SetCursor(ui::kCursorPointer);
-  EXPECT_EQ(ui::kCursorPointer, cursor_client_a->GetCursor().native_type());
-  EXPECT_EQ(ui::kCursorPointer, cursor_client_b->GetCursor().native_type());
-
-  // Verify that hiding the cursor using one cursor client will
-  // hide it for all root windows. Note that hiding the cursor
-  // should not disable mouse events.
-  cursor_client_a->HideCursor();
-  EXPECT_FALSE(cursor_client_a->IsCursorVisible());
-  EXPECT_FALSE(cursor_client_b->IsCursorVisible());
-  EXPECT_TRUE(cursor_client_a->IsMouseEventsEnabled());
-  EXPECT_TRUE(cursor_client_b->IsMouseEventsEnabled());
-
-  // Verify that the visibility state cannot be changed using one
-  // cursor client when the cursor was locked using another.
-  cursor_client_b->LockCursor();
-  cursor_client_a->ShowCursor();
-  EXPECT_FALSE(cursor_client_a->IsCursorVisible());
-  EXPECT_FALSE(cursor_client_b->IsCursorVisible());
-
-  // Verify the cursor becomes visible on unlock (since a request
-  // to make it visible was queued up while the cursor was locked).
-  cursor_client_b->UnlockCursor();
-  EXPECT_TRUE(cursor_client_a->IsCursorVisible());
-  EXPECT_TRUE(cursor_client_b->IsCursorVisible());
-}
-
 }  // namespace views
diff --git a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
index c258f84..353c3ec 100644
--- a/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
+++ b/ui/views/widget/desktop_aura/desktop_root_window_host_win.cc
@@ -151,12 +151,6 @@
     const Widget::InitParams& params) {
   root_window_ = root;
 
-  // The cursor is not necessarily visible when the root window is created.
-  aura::client::CursorClient* cursor_client =
-      aura::client::GetCursorClient(root_window_->window());
-  if (cursor_client)
-    is_cursor_visible_ = cursor_client->IsCursorVisible();
-
   root_window_->window()->SetProperty(kContentWindowForRootWindow,
                                       content_window_);
   root_window_->window()->SetProperty(kDesktopRootWindowHostKey, this);