Index: cc/picture_layer_impl.cc |
diff --git a/cc/picture_layer_impl.cc b/cc/picture_layer_impl.cc |
index 5a6f111d7a30cc560fc687a68027d4f00f363e5e..de06993e83da725b8a3382a3f4b3aaff62662c25 100644 |
--- a/cc/picture_layer_impl.cc |
+++ b/cc/picture_layer_impl.cc |
@@ -17,6 +17,10 @@ |
#include "ui/gfx/quad_f.h" |
#include "ui/gfx/size_conversions.h" |
+namespace { |
+const float kMaxScaleRatioDuringPinch = 2.0f; |
+} |
+ |
namespace cc { |
PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* treeImpl, int id) |
@@ -24,6 +28,8 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* treeImpl, int id) |
tilings_(this), |
pile_(PicturePileImpl::Create()), |
last_update_time_(0), |
+ last_content_scale_(0), |
+ ideal_contents_scale_(0), |
is_mask_(false) { |
} |
@@ -53,7 +59,8 @@ void PictureLayerImpl::appendQuads(QuadSink& quadSink, |
if (showDebugBorders()) { |
for (PictureLayerTilingSet::Iterator iter(&tilings_, |
contentsScaleX(), |
- rect); |
+ rect, |
+ ideal_contents_scale_); |
iter; |
++iter) { |
SkColor color; |
@@ -74,7 +81,14 @@ void PictureLayerImpl::appendQuads(QuadSink& quadSink, |
} |
} |
- for (PictureLayerTilingSet::Iterator iter(&tilings_, contentsScaleX(), rect); |
+ // Keep track of the tilings that were used so that tilings that are |
+ // unused can be considered for removal. |
+ std::vector<PictureLayerTiling*> seen_tilings; |
+ |
+ for (PictureLayerTilingSet::Iterator iter(&tilings_, |
+ contentsScaleX(), |
+ rect, |
+ ideal_contents_scale_); |
iter; |
++iter) { |
ResourceProvider::ResourceId resource = 0; |
@@ -122,7 +136,15 @@ void PictureLayerImpl::appendQuads(QuadSink& quadSink, |
outside_right_edge && useAA, |
outside_bottom_edge && useAA); |
quadSink.append(quad.PassAs<DrawQuad>(), appendQuadsData); |
+ |
+ if (!seen_tilings.size() || seen_tilings.back() != iter.CurrentTiling()) |
+ seen_tilings.push_back(iter.CurrentTiling()); |
} |
+ |
+ // During a pinch, a user could zoom in and out, so throwing away a tiling may |
+ // be premature. |
+ if (!layerTreeImpl()->PinchGestureActive()) |
+ CleanUpUnusedTilings(seen_tilings); |
} |
void PictureLayerImpl::dumpLayerProperties(std::string*, int indent) const { |
@@ -137,16 +159,15 @@ void PictureLayerImpl::didUpdateTransforms() { |
double time_delta = 0; |
if (last_update_time_ != 0 && last_bounds_ == bounds() && |
last_content_bounds_ == contentBounds() && |
- last_content_scale_x_ == contentsScaleX() && |
- last_content_scale_y_ == contentsScaleY()) { |
+ last_content_scale_ == contentsScaleX()) { |
time_delta = current_time - last_update_time_; |
} |
WhichTree tree = layerTreeImpl()->IsActiveTree() ? ACTIVE_TREE : PENDING_TREE; |
tilings_.UpdateTilePriorities( |
tree, |
layerTreeImpl()->device_viewport_size(), |
+ last_content_scale_, |
contentsScaleX(), |
- contentsScaleY(), |
last_screen_space_transform_, |
current_screen_space_transform, |
time_delta); |
@@ -155,8 +176,7 @@ void PictureLayerImpl::didUpdateTransforms() { |
last_update_time_ = current_time; |
last_bounds_ = bounds(); |
last_content_bounds_ = contentBounds(); |
- last_content_scale_x_ = contentsScaleX(); |
- last_content_scale_y_ = contentsScaleY(); |
+ last_content_scale_ = contentsScaleX(); |
} |
void PictureLayerImpl::calculateContentsScale( |
@@ -170,9 +190,9 @@ void PictureLayerImpl::calculateContentsScale( |
} |
float min_contents_scale = layerTreeImpl()->settings().minimumContentsScale; |
- ideal_contents_scale = std::max(ideal_contents_scale, min_contents_scale); |
+ ideal_contents_scale_ = std::max(ideal_contents_scale, min_contents_scale); |
- ManageTilings(ideal_contents_scale); |
+ ManageTilings(ideal_contents_scale_); |
// The content scale and bounds for a PictureLayerImpl is somewhat fictitious. |
// There are (usually) several tilings at different scales. However, the |
@@ -237,13 +257,16 @@ void PictureLayerImpl::SetIsMask(bool is_mask) { |
if (is_mask_ == is_mask) |
return; |
is_mask_ = is_mask; |
- tilings_.Reset(); |
+ tilings_.RemoveAllTiles(); |
} |
ResourceProvider::ResourceId PictureLayerImpl::contentsResourceId() const { |
gfx::Rect content_rect(gfx::Point(), contentBounds()); |
float scale = contentsScaleX(); |
- for (PictureLayerTilingSet::Iterator iter(&tilings_, scale, content_rect); |
+ for (PictureLayerTilingSet::Iterator iter(&tilings_, |
+ scale, |
+ content_rect, |
+ ideal_contents_scale_); |
iter; |
++iter) { |
// Mask resource not ready yet. |
@@ -257,25 +280,26 @@ ResourceProvider::ResourceId PictureLayerImpl::contentsResourceId() const { |
return 0; |
} |
-void PictureLayerImpl::AddTiling(float contents_scale, gfx::Size tile_size) { |
+PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) { |
if (contents_scale < layerTreeImpl()->settings().minimumContentsScale) |
- return; |
+ return NULL; |
- const PictureLayerTiling* tiling = tilings_.AddTiling( |
+ PictureLayerTiling* tiling = tilings_.AddTiling( |
contents_scale, |
- tile_size); |
+ TileSize()); |
// If a new tiling is created on the active tree, sync it to the pending tree |
// so that it can share the same tiles. |
if (layerTreeImpl()->IsPendingTree()) |
- return; |
+ return tiling; |
PictureLayerImpl* pending_twin = static_cast<PictureLayerImpl*>( |
layerTreeImpl()->FindPendingTreeLayerById(id())); |
if (!pending_twin) |
- return; |
+ return tiling; |
DCHECK_EQ(id(), pending_twin->id()); |
pending_twin->SyncTiling(tiling); |
+ return tiling; |
} |
gfx::Size PictureLayerImpl::TileSize() const { |
@@ -289,18 +313,110 @@ gfx::Size PictureLayerImpl::TileSize() const { |
return layerTreeImpl()->settings().defaultTileSize; |
} |
+namespace { |
+ |
+inline float PositiveRatio(float float1, float float2) { |
+ DCHECK(float1 > 0); |
+ DCHECK(float2 > 0); |
+ return float1 > float2 ? float1 / float2 : float2 / float1; |
+} |
+ |
+inline bool IsCloserToThan( |
+ PictureLayerTiling* layer1, |
+ PictureLayerTiling* layer2, |
+ float contents_scale) { |
+ // Absolute value for ratios. |
+ float ratio1 = PositiveRatio(layer1->contents_scale(), contents_scale); |
+ float ratio2 = PositiveRatio(layer2->contents_scale(), contents_scale); |
+ return ratio1 < ratio2; |
+} |
+ |
+} // namespace |
+ |
void PictureLayerImpl::ManageTilings(float ideal_contents_scale) { |
- if (drawsContent()) { |
- // TODO(enne): Add tilings during pinch zoom |
- // TODO(enne): Consider culling old tilings after pinch finishes. |
- if (!tilings_.num_tilings()) { |
- AddTiling(ideal_contents_scale, TileSize()); |
- // TODO(enne): Add a low-res tiling as well. |
+ DCHECK(ideal_contents_scale); |
+ float low_res_factor = layerTreeImpl()->settings().lowResContentsScaleFactor; |
+ float low_res_contents_scale = ideal_contents_scale * low_res_factor; |
+ |
+ // Remove any tilings from the pending tree that don't exactly match the |
+ // contents scale. The pending tree should always come in crisp. However, |
+ // don't do this during a pinch, to avoid throwing away a tiling that should |
+ // have been kept. |
+ if (layerTreeImpl()->IsPendingTree() && |
+ !layerTreeImpl()->PinchGestureActive()) { |
+ std::vector<PictureLayerTiling*> remove_list; |
+ for (size_t i = 0; i < tilings_.num_tilings(); ++i) { |
+ PictureLayerTiling* tiling = tilings_.tiling_at(i); |
+ if (tiling->contents_scale() == ideal_contents_scale) |
+ continue; |
+ if (tiling->contents_scale() == low_res_contents_scale) |
+ continue; |
+ remove_list.push_back(tiling); |
} |
- } else { |
- // TODO(enne): This should be unnecessary once there are two trees. |
- tilings_.Reset(); |
+ |
+ for (size_t i = 0; i < remove_list.size(); ++i) |
+ tilings_.Remove(remove_list[i]); |
} |
+ |
+ // Find existing tilings closest to ideal high / low res. |
+ PictureLayerTiling* high_res = NULL; |
+ PictureLayerTiling* low_res = NULL; |
+ for (size_t i = 0; i < tilings_.num_tilings(); ++i) { |
+ PictureLayerTiling* tiling = tilings_.tiling_at(i); |
+ if (!high_res || IsCloserToThan(tiling, high_res, ideal_contents_scale)) |
+ high_res = tiling; |
+ if (!low_res || IsCloserToThan(tiling, low_res, low_res_contents_scale)) |
+ low_res = tiling; |
+ |
+ // Reset all tilings to non-ideal until the end of this function. |
+ tiling->set_resolution(NON_IDEAL_RESOLUTION); |
+ } |
+ |
+ // The active tree always has calcDrawProperties called on it first, and |
+ // any tilings added to the active tree will be synced to the pending tree. |
+ // Therefore, only add tilings to the active tree. |
+ if (layerTreeImpl()->IsActiveTree()) { |
+ if (layerTreeImpl()->PinchGestureActive() && high_res) { |
+ // If zooming out, if only available high-res tiling is very high |
+ // resolution, create additional tilings closer to the ideal. |
+ // When zooming in, add some additional tilings so that content |
+ // "crisps up" prior to releasing pinch. |
+ float ratio = PositiveRatio( |
+ high_res->contents_scale(), |
+ ideal_contents_scale); |
+ if (ratio >= kMaxScaleRatioDuringPinch) |
+ high_res = AddTiling(ideal_contents_scale); |
+ } else { |
+ // When not pinching or if no tilings, add exact contents scales. |
+ if (!high_res || high_res->contents_scale() != ideal_contents_scale) |
+ high_res = AddTiling(ideal_contents_scale); |
+ if (!low_res || low_res->contents_scale() != low_res_contents_scale) |
+ low_res = AddTiling(low_res_contents_scale); |
+ } |
+ } |
+ |
+ if (high_res) |
+ high_res->set_resolution(HIGH_RESOLUTION); |
+ if (low_res && low_res != high_res) |
+ low_res->set_resolution(LOW_RESOLUTION); |
+} |
+ |
+void PictureLayerImpl::CleanUpUnusedTilings( |
+ std::vector<PictureLayerTiling*> used_tilings) { |
+ std::vector<PictureLayerTiling*> to_remove; |
+ |
+ for (size_t i = 0; i < tilings_.num_tilings(); ++i) { |
+ PictureLayerTiling* tiling = tilings_.tiling_at(i); |
+ // Don't remove the current high or low res tilinig. |
+ if (tiling->resolution() != NON_IDEAL_RESOLUTION) |
+ continue; |
+ if (std::find(used_tilings.begin(), used_tilings.end(), tiling) == |
+ used_tilings.end()) |
+ to_remove.push_back(tiling); |
+ } |
+ |
+ for (size_t i = 0; i < to_remove.size(); ++i) |
+ tilings_.Remove(to_remove[i]); |
} |
} // namespace cc |