From 82791e0818dfa575391a3ea87686704055913501 Mon Sep 17 00:00:00 2001
From: "vmpstr@chromium.org"
 <vmpstr@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Fri, 14 Mar 2014 06:30:57 +0000
Subject: cc: Add tiling raster tile iterators.

This patch adds PictureLayerTiling::Tiling{Raster,Eviction}TileIterator
classes. This is required for a larger change to tile prioritization.

Currently, the classes are not used by anything except unit and perf
tests.


BUG=329686
R=enne@chromium.org, reveman@chromium.org

Review URL: https://codereview.chromium.org/183663003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@257041 0039d316-1c4b-4281-b951-d872f2087c98
---
 cc/base/tiling_data.cc                        |   7 +
 cc/base/tiling_data.h                         |   2 +
 cc/resources/managed_tile_state.h             |   5 +
 cc/resources/picture_layer_tiling.cc          | 127 +++++++++++++++---
 cc/resources/picture_layer_tiling.h           |  66 +++++++++-
 cc/resources/picture_layer_tiling_perftest.cc |  38 +++++-
 cc/resources/picture_layer_tiling_unittest.cc | 180 +++++++++++++++++++++++++-
 cc/resources/tile.cc                          |  25 ++++
 cc/resources/tile.h                           |  21 ++-
 cc/resources/tile_manager.cc                  |  21 +--
 cc/resources/tile_manager.h                   |   1 -
 11 files changed, 441 insertions(+), 52 deletions(-)

(limited to 'cc')

diff --git a/cc/base/tiling_data.cc b/cc/base/tiling_data.cc
index b369dde..1de106c 100644
--- a/cc/base/tiling_data.cc
+++ b/cc/base/tiling_data.cc
@@ -272,6 +272,8 @@ TilingData::BaseIterator::BaseIterator(const TilingData* tiling_data)
       index_y_(-1) {
 }
 
+TilingData::Iterator::Iterator() : BaseIterator(NULL) { done(); }
+
 TilingData::Iterator::Iterator(const TilingData* tiling_data,
                                const gfx::Rect& tiling_rect)
     : BaseIterator(tiling_data),
@@ -409,6 +411,11 @@ TilingData::DifferenceIterator& TilingData::DifferenceIterator::operator++() {
   return *this;
 }
 
+TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator()
+    : BaseIterator(NULL) {
+  done();
+}
+
 TilingData::SpiralDifferenceIterator::SpiralDifferenceIterator(
     const TilingData* tiling_data,
     const gfx::Rect& consider_rect,
diff --git a/cc/base/tiling_data.h b/cc/base/tiling_data.h
index 70c465c..ee3a51e 100644
--- a/cc/base/tiling_data.h
+++ b/cc/base/tiling_data.h
@@ -89,6 +89,7 @@ class CC_EXPORT TilingData {
   // Iterate through all indices whose bounds + border intersect with |rect|.
   class CC_EXPORT Iterator : public BaseIterator {
    public:
+    Iterator();
     Iterator(const TilingData* tiling_data, const gfx::Rect& tiling_rect);
     Iterator& operator++();
 
@@ -129,6 +130,7 @@ class CC_EXPORT TilingData {
   // order is a counterclockwise spiral around the given center.
   class CC_EXPORT SpiralDifferenceIterator : public BaseIterator {
    public:
+    SpiralDifferenceIterator();
     SpiralDifferenceIterator(const TilingData* tiling_data,
                              const gfx::Rect& consider_rect,
                              const gfx::Rect& ignore_rect,
diff --git a/cc/resources/managed_tile_state.h b/cc/resources/managed_tile_state.h
index 6445623..e457983 100644
--- a/cc/resources/managed_tile_state.h
+++ b/cc/resources/managed_tile_state.h
@@ -69,10 +69,15 @@ class CC_EXPORT ManagedTileState {
       return mode_ == RESOURCE_MODE || mode_ == PICTURE_PILE_MODE;
     }
 
+    inline bool has_resource() const { return !!resource_; }
+
     size_t GPUMemoryUsageInBytes() const;
 
     void SetSolidColorForTesting(SkColor color) { set_solid_color(color); }
     void SetHasTextForTesting(bool has_text) { has_text_ = has_text; }
+    void SetResourceForTesting(scoped_ptr<ScopedResource> resource) {
+      resource_ = resource.Pass();
+    }
 
    private:
     friend class TileManager;
diff --git a/cc/resources/picture_layer_tiling.cc b/cc/resources/picture_layer_tiling.cc
index 939e0b1..3604465 100644
--- a/cc/resources/picture_layer_tiling.cc
+++ b/cc/resources/picture_layer_tiling.cc
@@ -10,6 +10,8 @@
 
 #include "base/debug/trace_event.h"
 #include "cc/base/math_util.h"
+#include "cc/resources/tile.h"
+#include "cc/resources/tile_priority.h"
 #include "ui/gfx/point_conversions.h"
 #include "ui/gfx/rect_conversions.h"
 #include "ui/gfx/safe_integer_conversions.h"
@@ -64,16 +66,9 @@ gfx::SizeF PictureLayerTiling::ContentSizeF() const {
   return gfx::ScaleSize(layer_bounds_, contents_scale_);
 }
 
-Tile* PictureLayerTiling::TileAt(int i, int j) const {
-  TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j));
-  if (iter == tiles_.end())
-    return NULL;
-  return iter->second.get();
-}
-
-void PictureLayerTiling::CreateTile(int i,
-                                    int j,
-                                    const PictureLayerTiling* twin_tiling) {
+Tile* PictureLayerTiling::CreateTile(int i,
+                                     int j,
+                                     const PictureLayerTiling* twin_tiling) {
   TileMapKey key(i, j);
   DCHECK(tiles_.find(key) == tiles_.end());
 
@@ -90,7 +85,7 @@ void PictureLayerTiling::CreateTile(int i,
           gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
       if (!client_->GetInvalidation()->Intersects(rect)) {
         tiles_[key] = candidate_tile;
-        return;
+        return candidate_tile;
       }
     }
   }
@@ -99,6 +94,7 @@ void PictureLayerTiling::CreateTile(int i,
   scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect);
   if (tile.get())
     tiles_[key] = tile;
+  return tile.get();
 }
 
 Region PictureLayerTiling::OpaqueRegionInContentRect(
@@ -430,8 +426,15 @@ void PictureLayerTiling::UpdateTilePriorities(
   last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
   last_visible_rect_in_content_space_ = visible_rect_in_content_space;
 
-  // Assign now priority to all visible tiles.
+  current_visible_rect_in_content_space_ = visible_rect_in_content_space;
+  current_skewport_ = skewport;
+  current_eventually_rect_ = eventually_rect;
+
   TilePriority now_priority(resolution_, TilePriority::NOW, 0);
+  float content_to_screen_scale =
+      1.0f / (contents_scale_ * layer_contents_scale);
+
+  // Assign now priority to all visible tiles.
   for (TilingData::Iterator iter(&tiling_data_, visible_rect_in_content_space);
        iter;
        ++iter) {
@@ -443,9 +446,7 @@ void PictureLayerTiling::UpdateTilePriorities(
     tile->SetPriority(tree, now_priority);
   }
 
-  // Assign soon priority to all tiles in the skewport that are not visible.
-  float content_to_screen_scale =
-      1.0f / (contents_scale_ * layer_contents_scale);
+  // Assign soon priority to skewport tiles.
   for (TilingData::DifferenceIterator iter(
            &tiling_data_, skewport, visible_rect_in_content_space);
        iter;
@@ -466,8 +467,7 @@ void PictureLayerTiling::UpdateTilePriorities(
     tile->SetPriority(tree, priority);
   }
 
-  // Assign eventually priority to all tiles in the eventually rect that are not
-  // in the skewport.
+  // Assign eventually priority to interest rect tiles.
   for (TilingData::DifferenceIterator iter(
            &tiling_data_, eventually_rect, skewport);
        iter;
@@ -723,4 +723,97 @@ gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy(
   return result;
 }
 
+PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
+    : tiling_(NULL), current_tile_(NULL) {}
+
+PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
+    PictureLayerTiling* tiling,
+    WhichTree tree)
+    : tiling_(tiling),
+      type_(VISIBLE),
+      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_),
+      tree_(tree),
+      current_tile_(NULL),
+      visible_iterator_(&tiling->tiling_data_, visible_rect_in_content_space_),
+      spiral_iterator_(&tiling->tiling_data_,
+                       skewport_in_content_space_,
+                       visible_rect_in_content_space_,
+                       visible_rect_in_content_space_) {
+  if (!visible_iterator_) {
+    AdvancePhase();
+    return;
+  }
+
+  current_tile_ =
+      tiling_->TileAt(visible_iterator_.index_x(), visible_iterator_.index_y());
+  if (!current_tile_ || !TileNeedsRaster(current_tile_))
+    ++(*this);
+}
+
+PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {}
+
+void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
+  DCHECK_LT(type_, EVENTUALLY);
+
+  do {
+    type_ = static_cast<Type>(type_ + 1);
+    if (type_ == EVENTUALLY) {
+      spiral_iterator_ = TilingData::SpiralDifferenceIterator(
+          &tiling_->tiling_data_,
+          eventually_rect_in_content_space_,
+          skewport_in_content_space_,
+          visible_rect_in_content_space_);
+    }
+
+    while (spiral_iterator_) {
+      current_tile_ = tiling_->TileAt(spiral_iterator_.index_x(),
+                                      spiral_iterator_.index_y());
+      if (current_tile_ && TileNeedsRaster(current_tile_))
+        break;
+      ++spiral_iterator_;
+    }
+
+    if (!spiral_iterator_ && type_ == EVENTUALLY)
+      break;
+  } while (!spiral_iterator_);
+}
+
+PictureLayerTiling::TilingRasterTileIterator&
+PictureLayerTiling::TilingRasterTileIterator::
+operator++() {
+  current_tile_ = NULL;
+  while (!current_tile_ || !TileNeedsRaster(current_tile_)) {
+    std::pair<int, int> next_index;
+    switch (type_) {
+      case VISIBLE:
+        ++visible_iterator_;
+        if (!visible_iterator_) {
+          AdvancePhase();
+          return *this;
+        }
+        next_index = visible_iterator_.index();
+        break;
+      case SKEWPORT:
+        ++spiral_iterator_;
+        if (!spiral_iterator_) {
+          AdvancePhase();
+          return *this;
+        }
+        next_index = spiral_iterator_.index();
+        break;
+      case EVENTUALLY:
+        ++spiral_iterator_;
+        if (!spiral_iterator_)
+          return *this;
+        next_index = spiral_iterator_.index();
+        break;
+    }
+    current_tile_ = tiling_->TileAt(next_index.first, next_index.second);
+  }
+  return *this;
+}
+
 }  // namespace cc
diff --git a/cc/resources/picture_layer_tiling.h b/cc/resources/picture_layer_tiling.h
index 407a2ad..e79aa00 100644
--- a/cc/resources/picture_layer_tiling.h
+++ b/cc/resources/picture_layer_tiling.h
@@ -45,6 +45,55 @@ class CC_EXPORT PictureLayerTilingClient {
 
 class CC_EXPORT PictureLayerTiling {
  public:
+  class CC_EXPORT TilingRasterTileIterator {
+   public:
+    enum Type { VISIBLE, SKEWPORT, EVENTUALLY };
+
+    TilingRasterTileIterator();
+    TilingRasterTileIterator(PictureLayerTiling* tiling, WhichTree tree);
+    ~TilingRasterTileIterator();
+
+    operator bool() const {
+      return current_tile_ && TileNeedsRaster(current_tile_);
+    }
+    Tile* operator*() { return current_tile_; }
+    Type get_type() const { return type_; }
+
+    TilingRasterTileIterator& operator++();
+
+    gfx::Rect TileBounds() const {
+      DCHECK(*this);
+      if (type_ == VISIBLE) {
+        return tiling_->tiling_data_.TileBounds(visible_iterator_.index_x(),
+                                                visible_iterator_.index_y());
+      }
+      return tiling_->tiling_data_.TileBounds(spiral_iterator_.index_x(),
+                                              spiral_iterator_.index_y());
+    }
+
+   private:
+    void AdvancePhase();
+    bool TileNeedsRaster(Tile* tile) const {
+      RasterMode mode = tile->DetermineRasterModeForTree(tree_);
+      return tile->NeedsRasterForMode(mode);
+    };
+
+    void UpdateCurrentTilePriority();
+
+    PictureLayerTiling* tiling_;
+
+    Type type_;
+    gfx::Rect visible_rect_in_content_space_;
+    gfx::Rect skewport_in_content_space_;
+    gfx::Rect eventually_rect_in_content_space_;
+    WhichTree tree_;
+
+    Tile* current_tile_;
+    bool current_tile_priority_updated_;
+    TilingData::Iterator visible_iterator_;
+    TilingData::SpiralDifferenceIterator spiral_iterator_;
+  };
+
   ~PictureLayerTiling();
 
   // Create a tiling with no tiles.  CreateTiles must be called to add some.
@@ -69,6 +118,11 @@ class CC_EXPORT PictureLayerTiling {
   gfx::Size tile_size() const { return tiling_data_.max_texture_size(); }
   float contents_scale() const { return contents_scale_; }
 
+  Tile* TileAt(int i, int j) const {
+    TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j));
+    return (iter == tiles_.end()) ? NULL : iter->second.get();
+  }
+
   void CreateAllTilesForTesting() {
     SetLiveTilesRect(gfx::Rect(tiling_data_.total_size()));
   }
@@ -81,8 +135,6 @@ class CC_EXPORT PictureLayerTiling {
     return all_tiles;
   }
 
-  Tile* TileAt(int i, int j) const;
-
   // Iterate over all tiles to fill content_rect.  Even if tiles are invalid
   // (i.e. no valid resource) this tiling should still iterate over them.
   // The union of all geometry_rect calls for each element iterated over should
@@ -183,6 +235,8 @@ class CC_EXPORT PictureLayerTiling {
   }
 
  protected:
+  friend class TilingRasterTileIterator;
+
   typedef std::pair<int, int> TileMapKey;
   typedef base::hash_map<TileMapKey, scoped_refptr<Tile> > TileMap;
 
@@ -190,7 +244,7 @@ class CC_EXPORT PictureLayerTiling {
                      const gfx::Size& layer_bounds,
                      PictureLayerTilingClient* client);
   void SetLiveTilesRect(const gfx::Rect& live_tiles_rect);
-  void CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
+  Tile* CreateTile(int i, int j, const PictureLayerTiling* twin_tiling);
 
   // Computes a skewport. The calculation extrapolates the last visible
   // rect and the current visible rect to expand the skewport to where it
@@ -213,7 +267,11 @@ class CC_EXPORT PictureLayerTiling {
 
   // State saved for computing velocities based upon finite differences.
   double last_impl_frame_time_in_seconds_;
-  gfx::RectF last_visible_rect_in_content_space_;
+  gfx::Rect last_visible_rect_in_content_space_;
+
+  gfx::Rect current_visible_rect_in_content_space_;
+  gfx::Rect current_skewport_;
+  gfx::Rect current_eventually_rect_;
 
   friend class CoverageIterator;
 
diff --git a/cc/resources/picture_layer_tiling_perftest.cc b/cc/resources/picture_layer_tiling_perftest.cc
index 9253ce5..0e015b1 100644
--- a/cc/resources/picture_layer_tiling_perftest.cc
+++ b/cc/resources/picture_layer_tiling_perftest.cc
@@ -67,7 +67,6 @@ class PictureLayerTilingPerfTest : public testing::Test {
     start_time_ = base::TimeTicks();
     num_runs_ = 0;
 
-    gfx::Size layer_bounds(50 * 256, 50 * 256);
     gfx::Rect viewport_rect(0, 0, 1024, 768);
     do {
       picture_layer_tiling_->UpdateTilePriorities(
@@ -87,7 +86,6 @@ class PictureLayerTilingPerfTest : public testing::Test {
     start_time_ = base::TimeTicks();
     num_runs_ = 0;
 
-    gfx::Size layer_bounds(50 * 256, 50 * 256);
     gfx::Size viewport_size(1024, 768);
     gfx::Rect viewport_rect(viewport_size);
     int xoffsets[] = {10, 0, -10, 0};
@@ -118,6 +116,35 @@ class PictureLayerTilingPerfTest : public testing::Test {
                            true);
   }
 
+  void RunTilingRasterTileIteratorTest(const std::string& test_name,
+                                       int num_tiles,
+                                       const gfx::Rect& viewport) {
+    start_time_ = base::TimeTicks();
+    num_runs_ = 0;
+
+    gfx::Size bounds(10000, 10000);
+    picture_layer_tiling_ =
+        PictureLayerTiling::Create(1, bounds, &picture_layer_tiling_client_);
+    picture_layer_tiling_->UpdateTilePriorities(
+        ACTIVE_TREE, viewport, 1.0f, 1.0);
+    do {
+      int count = num_tiles;
+      for (PictureLayerTiling::TilingRasterTileIterator it(
+               picture_layer_tiling_.get(), ACTIVE_TREE);
+           it && count;
+           ++it) {
+        --count;
+      }
+    } while (DidRun());
+
+    perf_test::PrintResult("tiling_raster_tile_iterator",
+                           "",
+                           test_name,
+                           num_runs_ / elapsed_.InSecondsF(),
+                           "runs/s",
+                           true);
+  }
+
  private:
   FakePictureLayerTilingClient picture_layer_tiling_client_;
   scoped_ptr<PictureLayerTiling> picture_layer_tiling_;
@@ -158,6 +185,13 @@ TEST_F(PictureLayerTilingPerfTest, UpdateTilePriorities) {
   RunUpdateTilePrioritiesScrollingTest("perspective", transform);
 }
 
+TEST_F(PictureLayerTilingPerfTest, TilingRasterTileIterator) {
+  RunTilingRasterTileIteratorTest("32_100x100", 32, gfx::Rect(0, 0, 100, 100));
+  RunTilingRasterTileIteratorTest("32_500x500", 32, gfx::Rect(0, 0, 500, 500));
+  RunTilingRasterTileIteratorTest("64_100x100", 64, gfx::Rect(0, 0, 100, 100));
+  RunTilingRasterTileIteratorTest("64_500x500", 64, gfx::Rect(0, 0, 500, 500));
+}
+
 }  // namespace
 
 }  // namespace cc
diff --git a/cc/resources/picture_layer_tiling_unittest.cc b/cc/resources/picture_layer_tiling_unittest.cc
index 5fe1acd..837f647 100644
--- a/cc/resources/picture_layer_tiling_unittest.cc
+++ b/cc/resources/picture_layer_tiling_unittest.cc
@@ -5,10 +5,14 @@
 #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_output_surface.h"
+#include "cc/test/fake_output_surface_client.h"
 #include "cc/test/fake_picture_layer_tiling_client.h"
+#include "cc/test/test_context_provider.h"
 #include "testing/gtest/include/gtest/gtest.h"
 #include "ui/gfx/rect_conversions.h"
 #include "ui/gfx/size_conversions.h"
@@ -492,16 +496,22 @@ TEST(PictureLayerTilingTest, ViewportDistanceWithScale) {
       TilePriority priority = tile->priority(ACTIVE_TREE);
 
       if (viewport_in_content_space.Intersects(tile->content_rect())) {
-        EXPECT_EQ(TilePriority::NOW, priority.priority_bin);
-        EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible);
+        EXPECT_EQ(TilePriority::NOW, priority.priority_bin) << "i: " << i
+                                                            << " j: " << j;
+        EXPECT_FLOAT_EQ(0.f, priority.distance_to_visible) << "i: " << i
+                                                           << " j: " << j;
         have_now = true;
       } else if (skewport.Intersects(tile->content_rect())) {
-        EXPECT_EQ(TilePriority::SOON, priority.priority_bin);
-        EXPECT_GT(priority.distance_to_visible, 0.f);
+        EXPECT_EQ(TilePriority::SOON, priority.priority_bin) << "i: " << i
+                                                             << " j: " << j;
+        EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i
+                                                     << " j: " << j;
         have_soon = true;
       } else {
-        EXPECT_EQ(TilePriority::EVENTUALLY, priority.priority_bin);
-        EXPECT_GT(priority.distance_to_visible, 0.f);
+        EXPECT_EQ(TilePriority::EVENTUALLY, priority.priority_bin)
+            << "i: " << i << " j: " << j;
+        EXPECT_GT(priority.distance_to_visible, 0.f) << "i: " << i
+                                                     << " j: " << j;
         have_eventually = true;
       }
     }
@@ -751,6 +761,164 @@ TEST(PictureLayerTilingTest, EmptyStartingRect) {
   EXPECT_TRUE(out.IsEmpty());
 }
 
+TEST(PictureLayerTilingTest, TilingRasterTileIteratorStaticViewport) {
+  FakePictureLayerTilingClient client;
+  scoped_ptr<TestablePictureLayerTiling> tiling;
+
+  gfx::Rect viewport(50, 50, 100, 100);
+  gfx::Size layer_bounds(200, 200);
+
+  client.SetTileSize(gfx::Size(30, 30));
+
+  tiling = TestablePictureLayerTiling::Create(1.0f, layer_bounds, &client);
+  tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0);
+
+  PictureLayerTiling::TilingRasterTileIterator empty_iterator;
+  EXPECT_FALSE(empty_iterator);
+
+  std::vector<Tile*> all_tiles = tiling->AllTilesForTesting();
+
+  // Sanity check.
+  EXPECT_EQ(64u, all_tiles.size());
+
+  // The explanation of each iteration is as follows:
+  // 1. First iteration tests that we can get all of the tiles correctly.
+  // 2. Second iteration ensures that we can get all of the tiles again (first
+  //    iteration didn't change any tiles), as well set all tiles to be ready to
+  //    draw.
+  // 3. Third iteration ensures that no tiles are returned, since they were all
+  //    marked as ready to draw.
+  for (int i = 0; i < 3; ++i) {
+    PictureLayerTiling::TilingRasterTileIterator it(tiling.get(), ACTIVE_TREE);
+
+    // There are 3 bins in TilePriority.
+    bool have_tiles[3] = {};
+
+    // On the third iteration, we should get no tiles since everything was
+    // marked as ready to draw.
+    if (i == 2) {
+      EXPECT_FALSE(it);
+      continue;
+    }
+
+    EXPECT_TRUE(it);
+    std::set<Tile*> unique_tiles;
+    unique_tiles.insert(*it);
+    Tile* last_tile = *it;
+    have_tiles[last_tile->priority(ACTIVE_TREE).priority_bin] = true;
+
+    // On the second iteration, mark everything as ready to draw (solid color).
+    if (i == 1) {
+      ManagedTileState::TileVersion& tile_version =
+          last_tile->GetTileVersionForTesting(
+              last_tile->DetermineRasterModeForTree(ACTIVE_TREE));
+      tile_version.SetSolidColorForTesting(SK_ColorRED);
+    }
+    ++it;
+    int eventually_bin_order_correct_count = 0;
+    int eventually_bin_order_incorrect_count = 0;
+    while (it) {
+      Tile* new_tile = *it;
+      ++it;
+      unique_tiles.insert(new_tile);
+
+      TilePriority last_priority = last_tile->priority(ACTIVE_TREE);
+      TilePriority new_priority = new_tile->priority(ACTIVE_TREE);
+      EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
+      if (last_priority.priority_bin == new_priority.priority_bin) {
+        if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
+          bool order_correct = last_priority.distance_to_visible <=
+                               new_priority.distance_to_visible;
+          eventually_bin_order_correct_count += order_correct;
+          eventually_bin_order_incorrect_count += !order_correct;
+        } else {
+          EXPECT_LE(last_priority.distance_to_visible,
+                    new_priority.distance_to_visible);
+        }
+      }
+      have_tiles[new_priority.priority_bin] = true;
+
+      last_tile = new_tile;
+
+      // On the second iteration, mark everything as ready to draw (solid
+      // color).
+      if (i == 1) {
+        ManagedTileState::TileVersion& tile_version =
+            last_tile->GetTileVersionForTesting(
+                last_tile->DetermineRasterModeForTree(ACTIVE_TREE));
+        tile_version.SetSolidColorForTesting(SK_ColorRED);
+      }
+    }
+
+    EXPECT_GT(eventually_bin_order_correct_count,
+              eventually_bin_order_incorrect_count);
+
+    // We should have now and eventually tiles, but not soon tiles because the
+    // viewport is static.
+    EXPECT_TRUE(have_tiles[TilePriority::NOW]);
+    EXPECT_FALSE(have_tiles[TilePriority::SOON]);
+    EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
+
+    EXPECT_EQ(unique_tiles.size(), all_tiles.size());
+  }
+}
+
+TEST(PictureLayerTilingTest, TilingRasterTileIteratorMovingViewport) {
+  FakePictureLayerTilingClient client;
+  scoped_ptr<TestablePictureLayerTiling> tiling;
+
+  gfx::Rect viewport(50, 0, 100, 100);
+  gfx::Rect moved_viewport(50, 0, 100, 250);
+  gfx::Size layer_bounds(500, 500);
+
+  client.SetTileSize(gfx::Size(30, 30));
+
+  tiling = TestablePictureLayerTiling::Create(1.f, layer_bounds, &client);
+  tiling->UpdateTilePriorities(ACTIVE_TREE, viewport, 1.0f, 1.0);
+  tiling->UpdateTilePriorities(ACTIVE_TREE, moved_viewport, 1.0f, 2.0);
+
+  // There are 3 bins in TilePriority.
+  bool have_tiles[3] = {};
+  Tile* last_tile = NULL;
+  int eventually_bin_order_correct_count = 0;
+  int eventually_bin_order_incorrect_count = 0;
+  for (PictureLayerTiling::TilingRasterTileIterator it(tiling.get(),
+                                                       ACTIVE_TREE);
+       it;
+       ++it) {
+    if (!last_tile)
+      last_tile = *it;
+
+    Tile* new_tile = *it;
+
+    TilePriority last_priority = last_tile->priority(ACTIVE_TREE);
+    TilePriority new_priority = new_tile->priority(ACTIVE_TREE);
+
+    have_tiles[new_priority.priority_bin] = true;
+
+    EXPECT_LE(last_priority.priority_bin, new_priority.priority_bin);
+    if (last_priority.priority_bin == new_priority.priority_bin) {
+      if (last_priority.priority_bin == TilePriority::EVENTUALLY) {
+        bool order_correct = last_priority.distance_to_visible <=
+                             new_priority.distance_to_visible;
+        eventually_bin_order_correct_count += order_correct;
+        eventually_bin_order_incorrect_count += !order_correct;
+      } else {
+        EXPECT_LE(last_priority.distance_to_visible,
+                  new_priority.distance_to_visible);
+      }
+    }
+    last_tile = new_tile;
+  }
+
+  EXPECT_GT(eventually_bin_order_correct_count,
+            eventually_bin_order_incorrect_count);
+
+  EXPECT_TRUE(have_tiles[TilePriority::NOW]);
+  EXPECT_TRUE(have_tiles[TilePriority::SOON]);
+  EXPECT_TRUE(have_tiles[TilePriority::EVENTUALLY]);
+}
+
 static void TileExists(bool exists, Tile* tile,
                        const gfx::Rect& geometry_rect) {
   EXPECT_EQ(exists, tile != NULL) << geometry_rect.ToString();
diff --git a/cc/resources/tile.cc b/cc/resources/tile.cc
index 7b1f00a..65a1738 100644
--- a/cc/resources/tile.cc
+++ b/cc/resources/tile.cc
@@ -4,6 +4,8 @@
 
 #include "cc/resources/tile.h"
 
+#include <algorithm>
+
 #include "cc/base/math_util.h"
 #include "cc/debug/traced_value.h"
 #include "cc/resources/tile_manager.h"
@@ -81,4 +83,27 @@ size_t Tile::GPUMemoryUsageInBytes() const {
   return total_size;
 }
 
+RasterMode Tile::DetermineRasterModeForTree(WhichTree tree) const {
+  return DetermineRasterModeForResolution(priority(tree).resolution);
+}
+
+RasterMode Tile::DetermineOverallRasterMode() const {
+  return DetermineRasterModeForResolution(managed_state_.resolution);
+}
+
+RasterMode Tile::DetermineRasterModeForResolution(
+    TileResolution resolution) const {
+  RasterMode current_mode = managed_state_.raster_mode;
+  RasterMode raster_mode = HIGH_QUALITY_RASTER_MODE;
+  if (resolution == LOW_RESOLUTION)
+    raster_mode = LOW_QUALITY_RASTER_MODE;
+  else if (can_use_lcd_text())
+    raster_mode = HIGH_QUALITY_RASTER_MODE;
+  else if (managed_state_.tile_versions[current_mode].has_text_ ||
+           !managed_state_.tile_versions[current_mode].IsReadyToDraw())
+    raster_mode = HIGH_QUALITY_NO_LCD_RASTER_MODE;
+
+  return std::min(raster_mode, current_mode);
+}
+
 }  // namespace cc
diff --git a/cc/resources/tile.h b/cc/resources/tile.h
index c0ed843..138cad5 100644
--- a/cc/resources/tile.h
+++ b/cc/resources/tile.h
@@ -79,6 +79,18 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
     return !!(flags_ & USE_GPU_RASTERIZATION);
   }
 
+  bool NeedsRasterForMode(RasterMode mode) const {
+    return !managed_state_.tile_versions[mode].IsReadyToDraw();
+  }
+
+  bool HasResources() const {
+    for (int mode = 0; mode < NUM_RASTER_MODES; ++mode) {
+      if (managed_state_.tile_versions[mode].has_resource())
+        return true;
+    }
+    return false;
+  }
+
   scoped_ptr<base::Value> AsValue() const;
 
   inline bool IsReadyToDraw() const {
@@ -116,6 +128,12 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
 
   size_t GPUMemoryUsageInBytes() const;
 
+  gfx::Size size() const { return tile_size_.size(); }
+
+  RasterMode DetermineRasterModeForTree(WhichTree tree) const;
+  RasterMode DetermineOverallRasterMode() const;
+
+  // Functionality used in tests.
   RasterMode GetRasterModeForTesting() const {
     return managed_state().raster_mode;
   }
@@ -123,8 +141,6 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
     return managed_state_.tile_versions[mode];
   }
 
-  gfx::Size size() const { return tile_size_.size(); }
-
  private:
   friend class TileManager;
   friend class PrioritizedTileSet;
@@ -146,6 +162,7 @@ class CC_EXPORT Tile : public RefCountedManaged<Tile> {
 
   ManagedTileState& managed_state() { return managed_state_; }
   const ManagedTileState& managed_state() const { return managed_state_; }
+  RasterMode DetermineRasterModeForResolution(TileResolution resolution) const;
 
   TileManager* tile_manager_;
   scoped_refptr<PicturePileImpl> picture_pile_;
diff --git a/cc/resources/tile_manager.cc b/cc/resources/tile_manager.cc
index cc2a5ab..8a47fc4 100644
--- a/cc/resources/tile_manager.cc
+++ b/cc/resources/tile_manager.cc
@@ -595,25 +595,6 @@ scoped_ptr<base::Value> TileManager::GetMemoryRequirementsAsValue() const {
   return requirements.PassAs<base::Value>();
 }
 
-RasterMode TileManager::DetermineRasterMode(const Tile* tile) const {
-  DCHECK(tile);
-  DCHECK(tile->picture_pile());
-
-  const ManagedTileState& mts = tile->managed_state();
-  RasterMode current_mode = mts.raster_mode;
-
-  RasterMode raster_mode = HIGH_QUALITY_RASTER_MODE;
-  if (tile->managed_state().resolution == LOW_RESOLUTION)
-    raster_mode = LOW_QUALITY_RASTER_MODE;
-  else if (tile->can_use_lcd_text())
-    raster_mode = HIGH_QUALITY_RASTER_MODE;
-  else if (mts.tile_versions[current_mode].has_text_ ||
-           !mts.tile_versions[current_mode].IsReadyToDraw())
-    raster_mode = HIGH_QUALITY_NO_LCD_RASTER_MODE;
-
-  return std::min(raster_mode, current_mode);
-}
-
 void TileManager::AssignGpuMemoryToTiles(
     PrioritizedTileSet* tiles,
     TileVector* tiles_that_need_to_be_rasterized) {
@@ -673,7 +654,7 @@ void TileManager::AssignGpuMemoryToTiles(
 
     mts.scheduled_priority = schedule_priority++;
 
-    mts.raster_mode = DetermineRasterMode(tile);
+    mts.raster_mode = tile->DetermineOverallRasterMode();
 
     ManagedTileState::TileVersion& tile_version =
         mts.tile_versions[mts.raster_mode];
diff --git a/cc/resources/tile_manager.h b/cc/resources/tile_manager.h
index d691d035..dc6e777 100644
--- a/cc/resources/tile_manager.h
+++ b/cc/resources/tile_manager.h
@@ -174,7 +174,6 @@ class CC_EXPORT TileManager : public RasterWorkerPoolClient,
                                      raster_worker_pool_->GetResourceFormat());
   }
 
-  RasterMode DetermineRasterMode(const Tile* tile) const;
   void FreeResourceForTile(Tile* tile, RasterMode mode);
   void FreeResourcesForTile(Tile* tile);
   void FreeUnusedResourcesForTile(Tile* tile);
-- 
cgit v1.1