From 9318345aa982a45e264ec9682f056323e117e9c0 Mon Sep 17 00:00:00 2001
From: "epenner@chromium.org"
 <epenner@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>
Date: Mon, 25 Nov 2013 23:35:53 +0000
Subject: Reland: CC: Adjust tiling creation triggers during pinch-zoom.

We used to create tilings only when exceeding a certain scale
difference from the ideal scale. This meant that in the worst
case our only available high-res tiling was 2X the required
resolution.

This patch adjusts the creation of new tilings, to ensure we
always have a tiling option that is less-than-or-equal-to
the current ideal scale.

BUG=307206

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

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@237179 0039d316-1c4b-4281-b951-d872f2087c98
---
 cc/layers/picture_layer_impl.cc | 81 +++++++++++++++++++++++++++++------------
 1 file changed, 58 insertions(+), 23 deletions(-)

(limited to 'cc/layers/picture_layer_impl.cc')

diff --git a/cc/layers/picture_layer_impl.cc b/cc/layers/picture_layer_impl.cc
index 29f5110..a8fecb9 100644
--- a/cc/layers/picture_layer_impl.cc
+++ b/cc/layers/picture_layer_impl.cc
@@ -5,6 +5,7 @@
 #include "cc/layers/picture_layer_impl.h"
 
 #include <algorithm>
+#include <limits>
 
 #include "base/time/time.h"
 #include "cc/base/math_util.h"
@@ -27,6 +28,10 @@
 
 namespace {
 const float kMaxScaleRatioDuringPinch = 2.0f;
+
+// When creating a new tiling during pinch, snap to an existing
+// tiling's scale if the desired scale is within this ratio.
+const float kSnapToExistingTilingRatio = 0.2f;
 }
 
 namespace cc {
@@ -828,13 +833,7 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
   if (!layer_tree_impl()->device_viewport_valid_for_tile_management())
     return;
 
-  raster_page_scale_ = ideal_page_scale_;
-  raster_device_scale_ = ideal_device_scale_;
-  raster_source_scale_ = ideal_source_scale_;
-
-  CalculateRasterContentsScale(animating_transform_to_screen,
-                               &raster_contents_scale_,
-                               &low_res_raster_contents_scale_);
+  RecalculateRasterScales(animating_transform_to_screen);
 
   PictureLayerTiling* high_res = NULL;
   PictureLayerTiling* low_res = NULL;
@@ -867,12 +866,15 @@ void PictureLayerImpl::ManageTilings(bool animating_transform_to_screen) {
       low_res != high_res)
     low_res = AddTiling(low_res_raster_contents_scale_);
 
-  high_res->set_resolution(HIGH_RESOLUTION);
+  // Set low-res if we have one.
   if (!low_res)
     low_res = previous_low_res;
   if (low_res && low_res != high_res)
     low_res->set_resolution(LOW_RESOLUTION);
 
+  // Make sure we always have one high-res (even if high == low).
+  high_res->set_resolution(HIGH_RESOLUTION);
+
   SanityCheckTilingState();
 }
 
@@ -888,10 +890,12 @@ bool PictureLayerImpl::ShouldAdjustRasterScale(
 
   bool is_pinching = layer_tree_impl()->PinchGestureActive();
   if (is_pinching && raster_page_scale_) {
-    // If the page scale diverges too far during pinch, change raster target to
-    // the current page scale.
-    float ratio = PositiveRatio(ideal_page_scale_, raster_page_scale_);
-    if (ratio >= kMaxScaleRatioDuringPinch)
+    // We change our raster scale when it is:
+    // - Higher than ideal (need a lower-res tiling available)
+    // - Too far from ideal (need a higher-res tiling available)
+    float ratio = ideal_page_scale_ / raster_page_scale_;
+    if (raster_page_scale_ > ideal_page_scale_ ||
+        ratio > kMaxScaleRatioDuringPinch)
       return true;
   }
 
@@ -908,35 +912,66 @@ bool PictureLayerImpl::ShouldAdjustRasterScale(
   return false;
 }
 
-void PictureLayerImpl::CalculateRasterContentsScale(
-    bool animating_transform_to_screen,
-    float* raster_contents_scale,
-    float* low_res_raster_contents_scale) const {
-  *raster_contents_scale = ideal_contents_scale_;
+float PictureLayerImpl::SnappedContentsScale(float scale) {
+  // If a tiling exists within the max snapping ratio, snap to its scale.
+  float snapped_contents_scale = scale;
+  float snapped_ratio = kSnapToExistingTilingRatio;
+  for (size_t i = 0; i < tilings_->num_tilings(); ++i) {
+    float tiling_contents_scale = tilings_->tiling_at(i)->contents_scale();
+    float ratio = PositiveRatio(tiling_contents_scale, scale);
+    if (ratio < snapped_ratio) {
+      snapped_contents_scale = tiling_contents_scale;
+      snapped_ratio = ratio;
+    }
+  }
+  return snapped_contents_scale;
+}
+
+void PictureLayerImpl::RecalculateRasterScales(
+    bool animating_transform_to_screen) {
+  raster_device_scale_ = ideal_device_scale_;
+  raster_source_scale_ = ideal_source_scale_;
+
+  bool is_pinching = layer_tree_impl()->PinchGestureActive();
+  if (!is_pinching) {
+    // When not pinching, we use ideal scale:
+    raster_page_scale_ = ideal_page_scale_;
+    raster_contents_scale_ = ideal_contents_scale_;
+  } else {
+    // See ShouldAdjustRasterScale:
+    // - When zooming out, preemptively create new tiling at lower resolution.
+    // - When zooming in, approximate ideal using multiple of kMaxScaleRatio.
+    bool zooming_out = raster_page_scale_ > ideal_page_scale_;
+    float desired_contents_scale =
+        zooming_out ? raster_contents_scale_ / kMaxScaleRatioDuringPinch
+                    : raster_contents_scale_ * kMaxScaleRatioDuringPinch;
+    raster_contents_scale_ = SnappedContentsScale(desired_contents_scale);
+    raster_page_scale_ = raster_contents_scale_ / raster_device_scale_;
+  }
 
   // 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.
   if (animating_transform_to_screen) {
-    *raster_contents_scale = std::max(
-        *raster_contents_scale, 1.f * ideal_page_scale_ * ideal_device_scale_);
+    raster_contents_scale_ = std::max(
+        raster_contents_scale_, 1.f * ideal_page_scale_ * ideal_device_scale_);
   }
 
   // If this layer would only create one tile at this content scale,
   // don't create a low res tiling.
   gfx::Size content_bounds =
-      gfx::ToCeiledSize(gfx::ScaleSize(bounds(), *raster_contents_scale));
+      gfx::ToCeiledSize(gfx::ScaleSize(bounds(), raster_contents_scale_));
   gfx::Size tile_size = CalculateTileSize(content_bounds);
   if (tile_size.width() >= content_bounds.width() &&
       tile_size.height() >= content_bounds.height()) {
-    *low_res_raster_contents_scale = *raster_contents_scale;
+    low_res_raster_contents_scale_ = raster_contents_scale_;
     return;
   }
 
   float low_res_factor =
       layer_tree_impl()->settings().low_res_contents_scale_factor;
-  *low_res_raster_contents_scale = std::max(
-      *raster_contents_scale * low_res_factor,
+  low_res_raster_contents_scale_ = std::max(
+      raster_contents_scale_ * low_res_factor,
       MinimumContentsScale());
 }
 
-- 
cgit v1.1