Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / cc / resources / picture_layer_tiling.cc
index 5a41951..ee17dc8 100644 (file)
@@ -7,8 +7,11 @@
 #include <algorithm>
 #include <cmath>
 #include <limits>
+#include <set>
 
 #include "base/debug/trace_event.h"
+#include "base/debug/trace_event_argument.h"
+#include "base/logging.h"
 #include "cc/base/math_util.h"
 #include "cc/resources/tile.h"
 #include "cc/resources/tile_priority.h"
@@ -34,16 +37,30 @@ class TileEvictionOrder {
     const TilePriority& b_priority =
         b->priority_for_tree_priority(tree_priority_);
 
-    if (a_priority.priority_bin == b_priority.priority_bin &&
-        a->required_for_activation() != b->required_for_activation()) {
-      return b->required_for_activation();
-    }
-    return b_priority.IsHigherPriorityThan(a_priority);
+    DCHECK(a_priority.priority_bin == b_priority.priority_bin);
+    DCHECK(a->required_for_activation() == b->required_for_activation());
+
+    // Or if a is occluded and b is unoccluded.
+    bool a_is_occluded = a->is_occluded_for_tree_priority(tree_priority_);
+    bool b_is_occluded = b->is_occluded_for_tree_priority(tree_priority_);
+    if (a_is_occluded != b_is_occluded)
+      return a_is_occluded;
+
+    // Or if a is farther away from visible.
+    return a_priority.distance_to_visible > b_priority.distance_to_visible;
   }
 
  private:
   TreePriority tree_priority_;
 };
+
+void ReleaseTile(Tile* tile, WhichTree tree) {
+  // Reset priority as tile is ref-counted and might still be used
+  // even though we no longer hold a reference to it here anymore.
+  tile->SetPriority(tree, TilePriority());
+  tile->set_shared(false);
+}
+
 }  // namespace
 
 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
@@ -62,13 +79,21 @@ PictureLayerTiling::PictureLayerTiling(float contents_scale,
       layer_bounds_(layer_bounds),
       resolution_(NON_IDEAL_RESOLUTION),
       client_(client),
-      tiling_data_(gfx::Size(), gfx::Rect(), true),
+      tiling_data_(gfx::Size(), gfx::Size(), true),
       last_impl_frame_time_in_seconds_(0.0),
+      has_visible_rect_tiles_(false),
+      has_skewport_rect_tiles_(false),
+      has_soon_border_rect_tiles_(false),
+      has_eventually_rect_tiles_(false),
       eviction_tiles_cache_valid_(false),
       eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) {
   gfx::Size content_bounds =
       gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
   gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
+  if (tile_size.IsEmpty()) {
+    layer_bounds_ = gfx::Size();
+    content_bounds = gfx::Size();
+  }
 
   DCHECK(!gfx::ToFlooredSize(
       gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) <<
@@ -76,21 +101,19 @@ PictureLayerTiling::PictureLayerTiling(float contents_scale,
       " Layer bounds: " << layer_bounds.ToString() <<
       " Contents scale: " << contents_scale;
 
-  tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
+  tiling_data_.SetTilingSize(content_bounds);
   tiling_data_.SetMaxTextureSize(tile_size);
 }
 
 PictureLayerTiling::~PictureLayerTiling() {
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+    ReleaseTile(it->second.get(), client_->GetTree());
 }
 
 void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
   client_ = client;
 }
 
-gfx::Rect PictureLayerTiling::TilingRect() const {
-  return tiling_data_.tiling_rect();
-}
-
 Tile* PictureLayerTiling::CreateTile(int i,
                                      int j,
                                      const PictureLayerTiling* twin_tiling) {
@@ -109,6 +132,8 @@ Tile* PictureLayerTiling::CreateTile(int i,
       gfx::Rect rect =
           gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
       if (!client_->GetInvalidation()->Intersects(rect)) {
+        DCHECK(!candidate_tile->is_shared());
+        candidate_tile->set_shared(true);
         tiles_[key] = candidate_tile;
         return candidate_tile;
       }
@@ -117,14 +142,16 @@ Tile* PictureLayerTiling::CreateTile(int i,
 
   // 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())
+  if (tile.get()) {
+    DCHECK(!tile->is_shared());
     tiles_[key] = tile;
+  }
   return tile.get();
 }
 
 void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
   const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
-  bool include_borders = true;
+  bool include_borders = false;
   for (TilingData::Iterator iter(
            &tiling_data_, live_tiles_rect_, include_borders);
        iter;
@@ -135,80 +162,151 @@ void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
       continue;
     CreateTile(key.first, key.second, twin_tiling);
   }
+
+  VerifyLiveTilesRect();
 }
 
-void PictureLayerTiling::SetLayerBounds(const gfx::Size& layer_bounds) {
-  if (layer_bounds_ == layer_bounds)
-    return;
+void PictureLayerTiling::UpdateTilesToCurrentPile(
+    const Region& layer_invalidation,
+    const gfx::Size& new_layer_bounds) {
+  DCHECK(!new_layer_bounds.IsEmpty());
 
-  DCHECK(!layer_bounds.IsEmpty());
+  gfx::Size tile_size = tiling_data_.max_texture_size();
 
-  gfx::Size old_layer_bounds = layer_bounds_;
-  layer_bounds_ = layer_bounds;
-  gfx::Size content_bounds =
-      gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_));
+  if (new_layer_bounds != layer_bounds_) {
+    gfx::Size content_bounds =
+        gfx::ToCeiledSize(gfx::ScaleSize(new_layer_bounds, contents_scale_));
+
+    tile_size = client_->CalculateTileSize(content_bounds);
+    if (tile_size.IsEmpty()) {
+      layer_bounds_ = gfx::Size();
+      content_bounds = gfx::Size();
+    } else {
+      layer_bounds_ = new_layer_bounds;
+    }
+
+    // The SetLiveTilesRect() method would drop tiles outside the new bounds,
+    // but may do so incorrectly if resizing the tiling causes the number of
+    // tiles in the tiling_data_ to change.
+    gfx::Rect content_rect(content_bounds);
+    int before_left = tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.x());
+    int before_top = tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.y());
+    int before_right =
+        tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+    int before_bottom =
+        tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+
+    // The live_tiles_rect_ is clamped to stay within the tiling size as we
+    // change it.
+    live_tiles_rect_.Intersect(content_rect);
+    tiling_data_.SetTilingSize(content_bounds);
+
+    int after_right = -1;
+    int after_bottom = -1;
+    if (!live_tiles_rect_.IsEmpty()) {
+      after_right =
+          tiling_data_.TileXIndexFromSrcCoord(live_tiles_rect_.right() - 1);
+      after_bottom =
+          tiling_data_.TileYIndexFromSrcCoord(live_tiles_rect_.bottom() - 1);
+    }
+
+    // There is no recycled twin since this is run on the pending tiling.
+    PictureLayerTiling* recycled_twin = NULL;
+    DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
+    DCHECK_EQ(PENDING_TREE, client_->GetTree());
+
+    // Drop tiles outside the new layer bounds if the layer shrank.
+    for (int i = after_right + 1; i <= before_right; ++i) {
+      for (int j = before_top; j <= before_bottom; ++j)
+        RemoveTileAt(i, j, recycled_twin);
+    }
+    for (int i = before_left; i <= after_right; ++i) {
+      for (int j = after_bottom + 1; j <= before_bottom; ++j)
+        RemoveTileAt(i, j, recycled_twin);
+    }
+
+    // If the layer grew, the live_tiles_rect_ is not changed, but a new row
+    // and/or column of tiles may now exist inside the same live_tiles_rect_.
+    const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
+    if (after_right > before_right) {
+      DCHECK_EQ(after_right, before_right + 1);
+      for (int j = before_top; j <= after_bottom; ++j)
+        CreateTile(after_right, j, twin_tiling);
+    }
+    if (after_bottom > before_bottom) {
+      DCHECK_EQ(after_bottom, before_bottom + 1);
+      for (int i = before_left; i <= before_right; ++i)
+        CreateTile(i, after_bottom, twin_tiling);
+    }
+  }
 
-  gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
   if (tile_size != tiling_data_.max_texture_size()) {
-    tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
     tiling_data_.SetMaxTextureSize(tile_size);
+    // When the tile size changes, the TilingData positions no longer work
+    // as valid keys to the TileMap, so just drop all tiles.
     Reset();
-    return;
+  } else {
+    Invalidate(layer_invalidation);
   }
 
-  // Any tiles outside our new bounds are invalid and should be dropped.
-  gfx::Rect bounded_live_tiles_rect(live_tiles_rect_);
-  bounded_live_tiles_rect.Intersect(gfx::Rect(content_bounds));
-  SetLiveTilesRect(bounded_live_tiles_rect);
-  tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
-
-  // Create tiles for newly exposed areas.
-  Region layer_region((gfx::Rect(layer_bounds_)));
-  layer_region.Subtract(gfx::Rect(old_layer_bounds));
-  Invalidate(layer_region);
+  PicturePileImpl* pile = client_->GetPile();
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+    it->second->set_picture_pile(pile);
+  VerifyLiveTilesRect();
 }
 
 void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
-  DoInvalidate(layer_region, false /* recreate_tiles */);
+  bool recreate_invalidated_tiles = false;
+  DoInvalidate(layer_region, recreate_invalidated_tiles);
 }
 
 void PictureLayerTiling::Invalidate(const Region& layer_region) {
-  DoInvalidate(layer_region, true /* recreate_tiles */);
+  bool recreate_invalidated_tiles = true;
+  DoInvalidate(layer_region, recreate_invalidated_tiles);
 }
 
 void PictureLayerTiling::DoInvalidate(const Region& layer_region,
-                                      bool recreate_tiles) {
+                                      bool recreate_invalidated_tiles) {
   std::vector<TileMapKey> new_tile_keys;
-  gfx::Rect expanded_live_tiles_rect(
-      tiling_data_.ExpandRectToTileBoundsWithBorders(live_tiles_rect_));
+  gfx::Rect expanded_live_tiles_rect =
+      tiling_data_.ExpandRectIgnoringBordersToTileBounds(live_tiles_rect_);
   for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
     gfx::Rect layer_rect = iter.rect();
     gfx::Rect content_rect =
         gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
+    // Consider tiles inside the live tiles rect even if only their border
+    // pixels intersect the invalidation. But don't consider tiles outside
+    // the live tiles rect with the same conditions, as they won't exist.
+    int border_pixels = tiling_data_.border_texels();
+    content_rect.Inset(-border_pixels, -border_pixels);
     // Avoid needless work by not bothering to invalidate where there aren't
     // tiles.
     content_rect.Intersect(expanded_live_tiles_rect);
     if (content_rect.IsEmpty())
       continue;
-    bool include_borders = true;
+    // Since the content_rect includes border pixels already, don't include
+    // borders when iterating to avoid double counting them.
+    bool include_borders = false;
     for (TilingData::Iterator iter(
              &tiling_data_, content_rect, include_borders);
          iter;
          ++iter) {
-      TileMapKey key(iter.index());
-      TileMap::iterator find = tiles_.find(key);
-      if (find == tiles_.end())
-        continue;
-      tiles_.erase(find);
-      if (recreate_tiles)
-        new_tile_keys.push_back(key);
+      // There is no recycled twin since this is run on the pending tiling.
+      PictureLayerTiling* recycled_twin = NULL;
+      DCHECK_EQ(recycled_twin, client_->GetRecycledTwinTiling(this));
+      DCHECK_EQ(PENDING_TREE, client_->GetTree());
+      if (RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin))
+        new_tile_keys.push_back(iter.index());
     }
   }
 
-  if (recreate_tiles) {
-    const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
-    for (size_t i = 0; i < new_tile_keys.size(); ++i)
+  if (recreate_invalidated_tiles && !new_tile_keys.empty()) {
+    for (size_t i = 0; i < new_tile_keys.size(); ++i) {
+      // Don't try to share a tile with the twin layer, it's been invalidated so
+      // we have to make our own tile here.
+      const PictureLayerTiling* twin_tiling = NULL;
       CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
+    }
   }
 }
 
@@ -249,7 +347,7 @@ PictureLayerTiling::CoverageIterator::CoverageIterator(
                                 dest_to_content_scale_);
   // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
   // check for non-intersection first.
-  content_rect.Intersect(tiling_->TilingRect());
+  content_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
   if (content_rect.IsEmpty())
     return;
 
@@ -350,7 +448,7 @@ gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
   gfx::RectF texture_rect(current_geometry_rect_);
   texture_rect.Scale(dest_to_content_scale_,
                      dest_to_content_scale_);
-  texture_rect.Intersect(tiling_->TilingRect());
+  texture_rect.Intersect(gfx::Rect(tiling_->tiling_size()));
   if (texture_rect.IsEmpty())
     return texture_rect;
   texture_rect.Offset(-tex_origin.OffsetFromOrigin());
@@ -362,8 +460,29 @@ gfx::Size PictureLayerTiling::CoverageIterator::texture_size() const {
   return tiling_->tiling_data_.max_texture_size();
 }
 
+bool PictureLayerTiling::RemoveTileAt(int i,
+                                      int j,
+                                      PictureLayerTiling* recycled_twin) {
+  TileMap::iterator found = tiles_.find(TileMapKey(i, j));
+  if (found == tiles_.end())
+    return false;
+  ReleaseTile(found->second.get(), client_->GetTree());
+  tiles_.erase(found);
+  if (recycled_twin) {
+    // Recycled twin does not also have a recycled twin, so pass NULL.
+    recycled_twin->RemoveTileAt(i, j, NULL);
+  }
+  return true;
+}
+
 void PictureLayerTiling::Reset() {
   live_tiles_rect_ = gfx::Rect();
+  PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    ReleaseTile(it->second.get(), client_->GetTree());
+    if (recycled_twin)
+      recycled_twin->RemoveTileAt(it->first.first, it->first.second, NULL);
+  }
   tiles_.clear();
 }
 
@@ -417,9 +536,10 @@ gfx::Rect PictureLayerTiling::ComputeSkewport(
 
 void PictureLayerTiling::UpdateTilePriorities(
     WhichTree tree,
-    const gfx::Rect& visible_layer_rect,
-    float layer_contents_scale,
-    double current_frame_time_in_seconds) {
+    const gfx::Rect& viewport_in_layer_space,
+    float ideal_contents_scale,
+    double current_frame_time_in_seconds,
+    const Occlusion& occlusion_in_layer_space) {
   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);
@@ -427,9 +547,9 @@ void PictureLayerTiling::UpdateTilePriorities(
   }
 
   gfx::Rect visible_rect_in_content_space =
-      gfx::ScaleToEnclosingRect(visible_layer_rect, contents_scale_);
+      gfx::ScaleToEnclosingRect(viewport_in_layer_space, contents_scale_);
 
-  if (TilingRect().IsEmpty()) {
+  if (tiling_size().IsEmpty()) {
     last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
     last_visible_rect_in_content_space_ = visible_rect_in_content_space;
     return;
@@ -448,27 +568,27 @@ void PictureLayerTiling::UpdateTilePriorities(
   gfx::Rect eventually_rect =
       ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
                                        eventually_rect_area,
-                                       TilingRect(),
+                                       gfx::Rect(tiling_size()),
                                        &expansion_cache_);
 
-  DCHECK(eventually_rect.IsEmpty() || TilingRect().Contains(eventually_rect));
+  DCHECK(eventually_rect.IsEmpty() ||
+         gfx::Rect(tiling_size()).Contains(eventually_rect))
+      << "tiling_size: " << tiling_size().ToString()
+      << " eventually_rect: " << eventually_rect.ToString();
 
   SetLiveTilesRect(eventually_rect);
 
   last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
   last_visible_rect_in_content_space_ = visible_rect_in_content_space;
 
-  current_visible_rect_in_content_space_ = visible_rect_in_content_space;
-  current_skewport_ = skewport;
-  current_eventually_rect_ = eventually_rect;
   eviction_tiles_cache_valid_ = false;
 
   TilePriority now_priority(resolution_, TilePriority::NOW, 0);
-  float content_to_screen_scale =
-      1.0f / (contents_scale_ * layer_contents_scale);
+  float content_to_screen_scale = ideal_contents_scale / contents_scale_;
 
   // Assign now priority to all visible tiles.
-  bool include_borders = true;
+  bool include_borders = false;
+  has_visible_rect_tiles_ = false;
   for (TilingData::Iterator iter(
            &tiling_data_, visible_rect_in_content_space, include_borders);
        iter;
@@ -476,12 +596,21 @@ void PictureLayerTiling::UpdateTilePriorities(
     TileMap::iterator find = tiles_.find(iter.index());
     if (find == tiles_.end())
       continue;
+    has_visible_rect_tiles_ = true;
     Tile* tile = find->second.get();
 
     tile->SetPriority(tree, now_priority);
+
+    // Set whether tile is occluded or not.
+    gfx::Rect tile_query_rect = ScaleToEnclosingRect(
+        IntersectRects(tile->content_rect(), visible_rect_in_content_space),
+        1.0f / contents_scale_);
+    bool is_occluded = occlusion_in_layer_space.IsOccluded(tile_query_rect);
+    tile->set_is_occluded(tree, is_occluded);
   }
 
   // Assign soon priority to skewport tiles.
+  has_skewport_rect_tiles_ = false;
   for (TilingData::DifferenceIterator iter(
            &tiling_data_, skewport, visible_rect_in_content_space);
        iter;
@@ -489,6 +618,7 @@ void PictureLayerTiling::UpdateTilePriorities(
     TileMap::iterator find = tiles_.find(iter.index());
     if (find == tiles_.end())
       continue;
+    has_skewport_rect_tiles_ = true;
     Tile* tile = find->second.get();
 
     gfx::Rect tile_bounds =
@@ -503,6 +633,7 @@ void PictureLayerTiling::UpdateTilePriorities(
   }
 
   // Assign eventually priority to interest rect tiles.
+  has_eventually_rect_tiles_ = false;
   for (TilingData::DifferenceIterator iter(
            &tiling_data_, eventually_rect, skewport);
        iter;
@@ -510,6 +641,7 @@ void PictureLayerTiling::UpdateTilePriorities(
     TileMap::iterator find = tiles_.find(iter.index());
     if (find == tiles_.end())
       continue;
+    has_eventually_rect_tiles_ = true;
     Tile* tile = find->second.get();
 
     gfx::Rect tile_bounds =
@@ -524,16 +656,18 @@ void PictureLayerTiling::UpdateTilePriorities(
   }
 
   // Upgrade the priority on border tiles to be SOON.
-  current_soon_border_rect_ = visible_rect_in_content_space;
+  gfx::Rect soon_border_rect = visible_rect_in_content_space;
   float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale;
-  current_soon_border_rect_.Inset(-border, -border, -border, -border);
+  soon_border_rect.Inset(-border, -border, -border, -border);
+  has_soon_border_rect_tiles_ = false;
   for (TilingData::DifferenceIterator iter(
-           &tiling_data_, current_soon_border_rect_, skewport);
+           &tiling_data_, soon_border_rect, skewport);
        iter;
        ++iter) {
     TileMap::iterator find = tiles_.find(iter.index());
     if (find == tiles_.end())
       continue;
+    has_soon_border_rect_tiles_ = true;
     Tile* tile = find->second.get();
 
     TilePriority priority(resolution_,
@@ -541,27 +675,31 @@ void PictureLayerTiling::UpdateTilePriorities(
                           tile->priority(tree).distance_to_visible);
     tile->SetPriority(tree, priority);
   }
+
+  // Update iteration rects.
+  current_visible_rect_ = visible_rect_in_content_space;
+  current_skewport_rect_ = skewport;
+  current_soon_border_rect_ = soon_border_rect;
+  current_eventually_rect_ = eventually_rect;
 }
 
 void PictureLayerTiling::SetLiveTilesRect(
     const gfx::Rect& new_live_tiles_rect) {
   DCHECK(new_live_tiles_rect.IsEmpty() ||
-         TilingRect().Contains(new_live_tiles_rect));
+         gfx::Rect(tiling_size()).Contains(new_live_tiles_rect))
+      << "tiling_size: " << tiling_size().ToString()
+      << " new_live_tiles_rect: " << new_live_tiles_rect.ToString();
   if (live_tiles_rect_ == new_live_tiles_rect)
     return;
 
   // Iterate to delete all tiles outside of our new live_tiles rect.
+  PictureLayerTiling* recycled_twin = client_->GetRecycledTwinTiling(this);
   for (TilingData::DifferenceIterator iter(&tiling_data_,
                                            live_tiles_rect_,
                                            new_live_tiles_rect);
        iter;
        ++iter) {
-    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.
-    if (found != tiles_.end())
-      tiles_.erase(found);
+    RemoveTileAt(iter.index_x(), iter.index_y(), recycled_twin);
   }
 
   const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
@@ -577,6 +715,30 @@ void PictureLayerTiling::SetLiveTilesRect(
   }
 
   live_tiles_rect_ = new_live_tiles_rect;
+  VerifyLiveTilesRect();
+}
+
+void PictureLayerTiling::VerifyLiveTilesRect() {
+#if DCHECK_IS_ON
+  for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
+    if (!it->second.get())
+      continue;
+    DCHECK(it->first.first < tiling_data_.num_tiles_x())
+        << this << " " << it->first.first << "," << it->first.second
+        << " num_tiles_x " << tiling_data_.num_tiles_x() << " live_tiles_rect "
+        << live_tiles_rect_.ToString();
+    DCHECK(it->first.second < tiling_data_.num_tiles_y())
+        << this << " " << it->first.first << "," << it->first.second
+        << " num_tiles_y " << tiling_data_.num_tiles_y() << " live_tiles_rect "
+        << live_tiles_rect_.ToString();
+    DCHECK(tiling_data_.TileBounds(it->first.first, it->first.second)
+               .Intersects(live_tiles_rect_))
+        << this << " " << it->first.first << "," << it->first.second
+        << " tile bounds "
+        << tiling_data_.TileBounds(it->first.first, it->first.second).ToString()
+        << " live_tiles_rect " << live_tiles_rect_.ToString();
+  }
+#endif
 }
 
 void PictureLayerTiling::DidBecomeRecycled() {
@@ -590,6 +752,7 @@ void PictureLayerTiling::DidBecomeRecycled() {
 }
 
 void PictureLayerTiling::DidBecomeActive() {
+  PicturePileImpl* active_pile = client_->GetPile();
   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());
@@ -597,25 +760,24 @@ void PictureLayerTiling::DidBecomeActive() {
     // 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());
+    // will cause PicturePileImpls to get deleted once the corresponding
+    // PictureLayerImpl and any in flight raster jobs go out of scope.
+    it->second->set_picture_pile(active_pile);
   }
 }
 
-void PictureLayerTiling::UpdateTilesToCurrentPile() {
-  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
-    client_->UpdatePile(it->second.get());
-  }
+void PictureLayerTiling::GetAllTilesForTracing(
+    std::set<const Tile*>* tiles) const {
+  for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it)
+    tiles->insert(it->second.get());
 }
 
-scoped_ptr<base::Value> PictureLayerTiling::AsValue() const {
-  scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
+void PictureLayerTiling::AsValueInto(base::debug::TracedValue* state) const {
   state->SetInteger("num_tiles", tiles_.size());
   state->SetDouble("content_scale", contents_scale_);
-  state->Set("tiling_rect", MathUtil::AsValue(TilingRect()).release());
-  return state.PassAs<base::Value>();
+  state->BeginDictionary("tiling_size");
+  MathUtil::AddToTracedValue(tiling_size(), state);
+  state->EndDictionary();
 }
 
 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
@@ -652,9 +814,11 @@ int ComputeExpansionDelta(int num_x_edges, int num_y_edges,
   int64 c = static_cast<int64>(width) * height - target_area;
 
   // Compute the delta for our edges using the quadratic equation.
-  return a == 0 ? -c / b :
-     (-b + static_cast<int>(
-         std::sqrt(static_cast<int64>(b) * b - 4.0 * a * c))) / (2 * a);
+  int delta =
+      (a == 0) ? -c / b : (-b + static_cast<int>(std::sqrt(
+                                    static_cast<int64>(b) * b - 4.0 * a * c))) /
+                              (2 * a);
+  return std::max(0, delta);
 }
 
 }  // namespace
@@ -782,44 +946,102 @@ void PictureLayerTiling::UpdateEvictionCacheIfNeeded(
       eviction_cache_tree_priority_ == tree_priority)
     return;
 
-  eviction_tiles_cache_.clear();
-  eviction_tiles_cache_.reserve(tiles_.size());
+  eviction_tiles_now_.clear();
+  eviction_tiles_now_and_required_for_activation_.clear();
+  eviction_tiles_soon_.clear();
+  eviction_tiles_soon_and_required_for_activation_.clear();
+  eviction_tiles_eventually_.clear();
+  eviction_tiles_eventually_and_required_for_activation_.clear();
+
   for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
     // TODO(vmpstr): This should update the priority if UpdateTilePriorities
     // changes not to do this.
-    eviction_tiles_cache_.push_back(it->second);
+    Tile* tile = it->second.get();
+    const TilePriority& priority =
+        tile->priority_for_tree_priority(tree_priority);
+    switch (priority.priority_bin) {
+      case TilePriority::EVENTUALLY:
+        if (tile->required_for_activation())
+          eviction_tiles_eventually_and_required_for_activation_.push_back(
+              tile);
+        else
+          eviction_tiles_eventually_.push_back(tile);
+        break;
+      case TilePriority::SOON:
+        if (tile->required_for_activation())
+          eviction_tiles_soon_and_required_for_activation_.push_back(tile);
+        else
+          eviction_tiles_soon_.push_back(tile);
+        break;
+      case TilePriority::NOW:
+        if (tile->required_for_activation())
+          eviction_tiles_now_and_required_for_activation_.push_back(tile);
+        else
+          eviction_tiles_now_.push_back(tile);
+        break;
+    }
   }
 
-  std::sort(eviction_tiles_cache_.begin(),
-            eviction_tiles_cache_.end(),
-            TileEvictionOrder(tree_priority));
+  // TODO(vmpstr): Do this lazily. One option is to have a "sorted" flag that
+  // can be updated for each of the queues.
+  TileEvictionOrder sort_order(tree_priority);
+  std::sort(eviction_tiles_now_.begin(), eviction_tiles_now_.end(), sort_order);
+  std::sort(eviction_tiles_now_and_required_for_activation_.begin(),
+            eviction_tiles_now_and_required_for_activation_.end(),
+            sort_order);
+  std::sort(
+      eviction_tiles_soon_.begin(), eviction_tiles_soon_.end(), sort_order);
+  std::sort(eviction_tiles_soon_and_required_for_activation_.begin(),
+            eviction_tiles_soon_and_required_for_activation_.end(),
+            sort_order);
+  std::sort(eviction_tiles_eventually_.begin(),
+            eviction_tiles_eventually_.end(),
+            sort_order);
+  std::sort(eviction_tiles_eventually_and_required_for_activation_.begin(),
+            eviction_tiles_eventually_and_required_for_activation_.end(),
+            sort_order);
+
   eviction_tiles_cache_valid_ = true;
   eviction_cache_tree_priority_ = tree_priority;
 }
 
+const std::vector<Tile*>* PictureLayerTiling::GetEvictionTiles(
+    TreePriority tree_priority,
+    EvictionCategory category) {
+  UpdateEvictionCacheIfNeeded(tree_priority);
+  switch (category) {
+    case EVENTUALLY:
+      return &eviction_tiles_eventually_;
+    case EVENTUALLY_AND_REQUIRED_FOR_ACTIVATION:
+      return &eviction_tiles_eventually_and_required_for_activation_;
+    case SOON:
+      return &eviction_tiles_soon_;
+    case SOON_AND_REQUIRED_FOR_ACTIVATION:
+      return &eviction_tiles_soon_and_required_for_activation_;
+    case NOW:
+      return &eviction_tiles_now_;
+    case NOW_AND_REQUIRED_FOR_ACTIVATION:
+      return &eviction_tiles_now_and_required_for_activation_;
+  }
+  NOTREACHED();
+  return &eviction_tiles_eventually_;
+}
+
 PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
     : tiling_(NULL), current_tile_(NULL) {}
 
 PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
     PictureLayerTiling* tiling,
     WhichTree tree)
-    : tiling_(tiling),
-      type_(TilePriority::NOW),
-      visible_rect_in_content_space_(
-          tiling_->current_visible_rect_in_content_space_),
-      skewport_in_content_space_(tiling_->current_skewport_),
-      eventually_rect_in_content_space_(tiling_->current_eventually_rect_),
-      soon_border_rect_in_content_space_(tiling_->current_soon_border_rect_),
-      tree_(tree),
-      current_tile_(NULL),
-      visible_iterator_(&tiling->tiling_data_,
-                        visible_rect_in_content_space_,
-                        true /* include_borders */),
-      spiral_iterator_(&tiling->tiling_data_,
-                       skewport_in_content_space_,
-                       visible_rect_in_content_space_,
-                       visible_rect_in_content_space_),
-      skewport_processed_(false) {
+    : tiling_(tiling), phase_(VISIBLE_RECT), tree_(tree), current_tile_(NULL) {
+  if (!tiling_->has_visible_rect_tiles_) {
+    AdvancePhase();
+    return;
+  }
+
+  visible_iterator_ = TilingData::Iterator(&tiling_->tiling_data_,
+                                           tiling_->current_visible_rect_,
+                                           false /* include_borders */);
   if (!visible_iterator_) {
     AdvancePhase();
     return;
@@ -834,16 +1056,46 @@ PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
 PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {}
 
 void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
-  DCHECK_LT(type_, TilePriority::EVENTUALLY);
+  DCHECK_LT(phase_, EVENTUALLY_RECT);
 
   do {
-    type_ = static_cast<TilePriority::PriorityBin>(type_ + 1);
-    if (type_ == TilePriority::EVENTUALLY) {
-      spiral_iterator_ = TilingData::SpiralDifferenceIterator(
-          &tiling_->tiling_data_,
-          eventually_rect_in_content_space_,
-          skewport_in_content_space_,
-          visible_rect_in_content_space_);
+    phase_ = static_cast<Phase>(phase_ + 1);
+    switch (phase_) {
+      case VISIBLE_RECT:
+        NOTREACHED();
+        return;
+      case SKEWPORT_RECT:
+        if (!tiling_->has_skewport_rect_tiles_)
+          continue;
+
+        spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+            &tiling_->tiling_data_,
+            tiling_->current_skewport_rect_,
+            tiling_->current_visible_rect_,
+            tiling_->current_visible_rect_);
+        break;
+      case SOON_BORDER_RECT:
+        if (!tiling_->has_soon_border_rect_tiles_)
+          continue;
+
+        spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+            &tiling_->tiling_data_,
+            tiling_->current_soon_border_rect_,
+            tiling_->current_skewport_rect_,
+            tiling_->current_visible_rect_);
+        break;
+      case EVENTUALLY_RECT:
+        if (!tiling_->has_eventually_rect_tiles_) {
+          current_tile_ = NULL;
+          return;
+        }
+
+        spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+            &tiling_->tiling_data_,
+            tiling_->current_eventually_rect_,
+            tiling_->current_skewport_rect_,
+            tiling_->current_soon_border_rect_);
+        break;
     }
 
     while (spiral_iterator_) {
@@ -854,7 +1106,7 @@ void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
       ++spiral_iterator_;
     }
 
-    if (!spiral_iterator_ && type_ == TilePriority::EVENTUALLY) {
+    if (!spiral_iterator_ && phase_ == EVENTUALLY_RECT) {
       current_tile_ = NULL;
       break;
     }
@@ -867,8 +1119,8 @@ operator++() {
   current_tile_ = NULL;
   while (!current_tile_ || !TileNeedsRaster(current_tile_)) {
     std::pair<int, int> next_index;
-    switch (type_) {
-      case TilePriority::NOW:
+    switch (phase_) {
+      case VISIBLE_RECT:
         ++visible_iterator_;
         if (!visible_iterator_) {
           AdvancePhase();
@@ -876,27 +1128,16 @@ operator++() {
         }
         next_index = visible_iterator_.index();
         break;
-      case TilePriority::SOON:
+      case SKEWPORT_RECT:
+      case SOON_BORDER_RECT:
         ++spiral_iterator_;
         if (!spiral_iterator_) {
-          if (skewport_processed_) {
-            AdvancePhase();
-            return *this;
-          }
-          skewport_processed_ = true;
-          spiral_iterator_ = TilingData::SpiralDifferenceIterator(
-              &tiling_->tiling_data_,
-              soon_border_rect_in_content_space_,
-              skewport_in_content_space_,
-              visible_rect_in_content_space_);
-          if (!spiral_iterator_) {
-            AdvancePhase();
-            return *this;
-          }
+          AdvancePhase();
+          return *this;
         }
         next_index = spiral_iterator_.index();
         break;
-      case TilePriority::EVENTUALLY:
+      case EVENTUALLY_RECT:
         ++spiral_iterator_;
         if (!spiral_iterator_) {
           current_tile_ = NULL;
@@ -911,28 +1152,37 @@ operator++() {
 }
 
 PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
-    : is_valid_(false), tiling_(NULL) {}
+    : eviction_tiles_(NULL), current_eviction_tiles_index_(0u) {
+}
 
 PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
     PictureLayerTiling* tiling,
-    TreePriority tree_priority)
-    : is_valid_(false), tiling_(tiling), tree_priority_(tree_priority) {}
-
-PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {}
+    TreePriority tree_priority,
+    EvictionCategory category)
+    : eviction_tiles_(tiling->GetEvictionTiles(tree_priority, category)),
+      // Note: initializing to "0 - 1" works as overflow is well defined for
+      // unsigned integers.
+      current_eviction_tiles_index_(static_cast<size_t>(0) - 1) {
+  DCHECK(eviction_tiles_);
+  ++(*this);
+}
 
-PictureLayerTiling::TilingEvictionTileIterator::operator bool() {
-  if (!IsValid())
-    Initialize();
+PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {
+}
 
-  return IsValid() && tile_iterator_ != tiling_->eviction_tiles_cache_.end();
+PictureLayerTiling::TilingEvictionTileIterator::operator bool() const {
+  return eviction_tiles_ &&
+         current_eviction_tiles_index_ != eviction_tiles_->size();
 }
 
 Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
-  if (!IsValid())
-    Initialize();
+  DCHECK(*this);
+  return (*eviction_tiles_)[current_eviction_tiles_index_];
+}
 
+const Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() const {
   DCHECK(*this);
-  return *tile_iterator_;
+  return (*eviction_tiles_)[current_eviction_tiles_index_];
 }
 
 PictureLayerTiling::TilingEvictionTileIterator&
@@ -940,24 +1190,11 @@ PictureLayerTiling::TilingEvictionTileIterator::
 operator++() {
   DCHECK(*this);
   do {
-    ++tile_iterator_;
-  } while (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
-           (!(*tile_iterator_)->HasResources()));
+    ++current_eviction_tiles_index_;
+  } while (current_eviction_tiles_index_ != eviction_tiles_->size() &&
+           !(*eviction_tiles_)[current_eviction_tiles_index_]->HasResources());
 
   return *this;
 }
 
-void PictureLayerTiling::TilingEvictionTileIterator::Initialize() {
-  if (!tiling_)
-    return;
-
-  tiling_->UpdateEvictionCacheIfNeeded(tree_priority_);
-  tile_iterator_ = tiling_->eviction_tiles_cache_.begin();
-  is_valid_ = true;
-  if (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
-      !(*tile_iterator_)->HasResources()) {
-    ++(*this);
-  }
-}
-
 }  // namespace cc