diff options
author | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-02 04:26:48 +0000 |
---|---|---|
committer | danakj@chromium.org <danakj@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-02-02 04:26:48 +0000 |
commit | 8bc574c57115e9ffd0169f33131c0865997dcb35 (patch) | |
tree | 80ba5b6eac129604de092c2ac2358c1777fed3b4 | |
parent | 0a703911ec7c81384bd52e8e1e5ac4ce012f6f5d (diff) | |
download | chromium_src-8bc574c57115e9ffd0169f33131c0865997dcb35.zip chromium_src-8bc574c57115e9ffd0169f33131c0865997dcb35.tar.gz chromium_src-8bc574c57115e9ffd0169f33131c0865997dcb35.tar.bz2 |
cc: Allow non-ideal resolutions to activate the pending tree.
TODO(danakj): Rewrite this description.
BUG=172784,173236
NOTRY=true
Review URL: https://chromiumcodereview.appspot.com/12087043
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@180244 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | cc/picture_layer_impl.cc | 321 | ||||
-rw-r--r-- | cc/picture_layer_impl.h | 17 | ||||
-rw-r--r-- | cc/picture_layer_impl_unittest.cc | 234 |
3 files changed, 465 insertions, 107 deletions
diff --git a/cc/picture_layer_impl.cc b/cc/picture_layer_impl.cc index 4cba5bd..b7411e8 100644 --- a/cc/picture_layer_impl.cc +++ b/cc/picture_layer_impl.cc @@ -29,7 +29,14 @@ PictureLayerImpl::PictureLayerImpl(LayerTreeImpl* treeImpl, int id) pile_(PicturePileImpl::Create()), last_content_scale_(0), ideal_contents_scale_(0), - is_mask_(false) { + is_mask_(false), + ideal_page_scale_(0.f), + ideal_device_scale_(0.f), + ideal_source_scale_(0.f), + raster_page_scale_(0.f), + raster_device_scale_(0.f), + raster_source_scale_(0.f), + raster_source_scale_was_animating_(false) { } PictureLayerImpl::~PictureLayerImpl() { @@ -191,7 +198,7 @@ void PictureLayerImpl::appendQuads(QuadSink& quadSink, drawTransformIsAnimating() || screenSpaceTransformIsAnimating(); if (!is_animating) - CleanUpUnusedTilings(seen_tilings); + CleanUpTilingsOnActiveLayer(seen_tilings); } void PictureLayerImpl::dumpLayerProperties(std::string*, int indent) const { @@ -257,9 +264,22 @@ void PictureLayerImpl::calculateContentsScale( } float min_contents_scale = layerTreeImpl()->settings().minimumContentsScale; + float min_page_scale = layerTreeImpl()->min_page_scale_factor(); + float min_device_scale = 1.f; + float min_source_scale = + min_contents_scale / min_page_scale / min_device_scale; + + float ideal_page_scale = layerTreeImpl()->total_page_scale_factor(); + float ideal_device_scale = layerTreeImpl()->device_scale_factor(); + float ideal_source_scale = + ideal_contents_scale / ideal_page_scale / ideal_device_scale; + ideal_contents_scale_ = std::max(ideal_contents_scale, min_contents_scale); + ideal_page_scale_ = ideal_page_scale; + ideal_device_scale_ = ideal_device_scale; + ideal_source_scale_ = std::max(ideal_source_scale, min_source_scale); - ManageTilings(ideal_contents_scale_); + ManageTilings(); // The content scale and bounds for a PictureLayerImpl is somewhat fictitious. // There are (usually) several tilings at different scales. However, the @@ -313,11 +333,8 @@ void PictureLayerImpl::SyncFromActiveLayer() { // If there is an active tree version of this layer, get a copy of its // tiles. This needs to be done last, after setting invalidation and the // pile. - PictureLayerImpl* active_twin = static_cast<PictureLayerImpl*>( - layerTreeImpl()->FindActiveTreeLayerById(id())); - if (!active_twin) - return; - SyncFromActiveLayer(active_twin); + if (PictureLayerImpl* active_twin = ActiveTwin()) + SyncFromActiveLayer(active_twin); } void PictureLayerImpl::SyncFromActiveLayer(const PictureLayerImpl* other) { @@ -377,63 +394,88 @@ ResourceProvider::ResourceId PictureLayerImpl::contentsResourceId() const { } bool PictureLayerImpl::areVisibleResourcesReady() const { + DCHECK(ideal_contents_scale_); + const gfx::Rect& rect = visibleContentRect(); + float raster_contents_scale = + raster_page_scale_ * + raster_device_scale_ * + raster_source_scale_; + + float min_acceptable_scale = + std::min(raster_contents_scale, ideal_contents_scale_); + + if (layerTreeImpl()->IsPendingTree()) { + if (PictureLayerImpl* twin = ActiveTwin()) { + float twin_raster_contents_scale = + twin->raster_page_scale_ * + twin->raster_device_scale_ * + twin->raster_source_scale_; + + min_acceptable_scale = std::min( + min_acceptable_scale, + std::min(twin->ideal_contents_scale_, twin_raster_contents_scale)); + } + } + + Region missing_region = rect; for (size_t i = 0; i < tilings_->num_tilings(); ++i) { - const PictureLayerTiling* tiling = tilings_->tiling_at(i); + PictureLayerTiling* tiling = tilings_->tiling_at(i); - // Ignore non-high resolution tilings. - if (tiling->resolution() != HIGH_RESOLUTION) + if (tiling->contents_scale() < min_acceptable_scale) continue; for (PictureLayerTiling::Iterator iter(tiling, - tiling->contents_scale(), + contentsScaleX(), rect); iter; ++iter) { // A null tile (i.e. no recording) is considered "ready". - if (*iter && !iter->GetResourceId()) - return false; + if (!*iter || iter->GetResourceId()) + missing_region.Subtract(iter.geometry_rect()); } - return true; } - return false; + + return missing_region.IsEmpty(); } PictureLayerTiling* PictureLayerImpl::AddTiling(float contents_scale) { - if (contents_scale < layerTreeImpl()->settings().minimumContentsScale) - return NULL; - - const Region& recorded = pile_->recorded_region(); - if (recorded.IsEmpty()) - return NULL; + DCHECK(contents_scale >= layerTreeImpl()->settings().minimumContentsScale); PictureLayerTiling* tiling = tilings_->AddTiling( contents_scale, TileSize()); + const Region& recorded = pile_->recorded_region(); + DCHECK(!recorded.IsEmpty()); + for (Region::Iterator iter(recorded); iter.has_rect(); iter.next()) tiling->CreateTilesFromLayerRect(iter.rect()); - PictureLayerImpl* twin; - const Region* pending_layer_invalidation = NULL; - if (layerTreeImpl()->IsPendingTree()) { - twin = static_cast<PictureLayerImpl*>( - layerTreeImpl()->FindActiveTreeLayerById(id())); - pending_layer_invalidation = &invalidation_; - } else { - twin = static_cast<PictureLayerImpl*>( - layerTreeImpl()->FindPendingTreeLayerById(id())); - pending_layer_invalidation = &twin->invalidation_; - } - + PictureLayerImpl* twin = + layerTreeImpl()->IsPendingTree() ? ActiveTwin() : PendingTwin(); if (!twin) return tiling; - DCHECK_EQ(id(), twin->id()); - twin->SyncTiling(tiling, *pending_layer_invalidation); + + if (layerTreeImpl()->IsPendingTree()) + twin->SyncTiling(tiling, invalidation_); + else + twin->SyncTiling(tiling, twin->invalidation_); + return tiling; } +void PictureLayerImpl::RemoveTiling(float contents_scale) { + for (size_t i = 0; i < tilings_->num_tilings(); ++i) { + PictureLayerTiling* tiling = tilings_->tiling_at(i); + if (tiling->contents_scale() == contents_scale) { + tilings_->Remove(tiling); + break; + } + } +} + gfx::Size PictureLayerImpl::TileSize() const { if (is_mask_) { int max_size = layerTreeImpl()->MaxTextureSize(); @@ -465,86 +507,92 @@ inline bool IsCloserToThan( } // namespace -void PictureLayerImpl::ManageTilings(float ideal_contents_scale) { - DCHECK(ideal_contents_scale); +void PictureLayerImpl::ManageTilings() { + DCHECK(ideal_contents_scale_); + DCHECK(ideal_page_scale_); + DCHECK(ideal_device_scale_); + DCHECK(ideal_source_scale_); + + if (pile_->recorded_region().IsEmpty()) + return; + float low_res_factor = layerTreeImpl()->settings().lowResContentsScaleFactor; - float low_res_contents_scale = ideal_contents_scale * low_res_factor; - bool is_animating = drawTransformIsAnimating() || + + bool is_active_layer = layerTreeImpl()->IsActiveTree(); + bool is_pinching = layerTreeImpl()->PinchGestureActive(); + bool is_animating = + drawTransformIsAnimating() || screenSpaceTransformIsAnimating(); - // 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() && !is_animating) { - 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); - } + bool change_target_tiling = false; + + if (!raster_page_scale_ || !raster_device_scale_ || !raster_source_scale_) + change_target_tiling = true; + + // TODO(danakj): Adjust raster_source_scale_ closer to ideal_source_scale_ at + // a throttled rate. Possibly make use of invalidation_.IsEmpty() on pending + // tree. This will allow CSS scale changes to get re-rastered at an + // appropriate rate. - for (size_t i = 0; i < remove_list.size(); ++i) - tilings_->Remove(remove_list[i]); + if (is_active_layer) { + if (raster_source_scale_was_animating_ && !is_animating) + change_target_tiling = true; + raster_source_scale_was_animating_ = is_animating; } + if (is_active_layer && is_pinching) { + // 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) + change_target_tiling = true; + } + + if (!is_pinching) { + // When not pinching, match the ideal page scale factor. + if (raster_page_scale_ != ideal_page_scale_) + change_target_tiling = true; + } + + // Always match the ideal device scale factor. + if (raster_device_scale_ != ideal_device_scale_) + change_target_tiling = true; + + if (!change_target_tiling) + return; + + raster_page_scale_ = ideal_page_scale_; + raster_device_scale_ = ideal_device_scale_; + raster_source_scale_ = ideal_source_scale_; + + // Don't allow animating CSS scales to drop below 1. + if (is_animating) + raster_source_scale_ = std::max(raster_source_scale_, 1.f); + + float raster_contents_scale = + raster_page_scale_ * raster_device_scale_ * raster_source_scale_; + float low_res_raster_contents_scale = std::max( + raster_contents_scale * low_res_factor, + layerTreeImpl()->settings().minimumContentsScale); + PictureLayerTiling* high_res = NULL; PictureLayerTiling* low_res = NULL; - PictureLayerTiling* old_high_res = NULL; - PictureLayerTiling* old_low_res = NULL; - // Find existing tilings closest to ideal high / low res. 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)) + if (tiling->contents_scale() == raster_contents_scale) high_res = tiling; - if (!low_res || IsCloserToThan(tiling, low_res, low_res_contents_scale)) + if (tiling->contents_scale() == low_res_raster_contents_scale) low_res = tiling; - if (tiling->resolution() == HIGH_RESOLUTION) - old_high_res = tiling; - else if (tiling->resolution() == LOW_RESOLUTION) - old_low_res = tiling; - // Reset all tilings to non-ideal until the end of this function. tiling->set_resolution(NON_IDEAL_RESOLUTION); } - if (is_animating && old_high_res) - high_res = old_high_res; - if (is_animating && old_low_res) - low_res = old_low_res; - - 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 { - bool high_res_mismatch = !is_animating && high_res && - high_res->contents_scale() != ideal_contents_scale; - bool low_res_mismatch = !is_animating && low_res && - low_res->contents_scale() != low_res_contents_scale; - - // Always make sure we have some tiling. - if (!high_res || high_res_mismatch) - high_res = AddTiling(ideal_contents_scale); - - // If we're not pinching then add a low res tiling at the exact scale. - if (!layerTreeImpl()->PinchGestureActive()) { - if (!low_res || low_res_mismatch) - low_res = AddTiling(low_res_contents_scale); - } - } + if (!high_res) + high_res = AddTiling(raster_contents_scale); + if (!low_res && low_res != high_res) + low_res = AddTiling(low_res_raster_contents_scale); if (high_res) high_res->set_resolution(HIGH_RESOLUTION); @@ -552,22 +600,85 @@ void PictureLayerImpl::ManageTilings(float ideal_contents_scale) { low_res->set_resolution(LOW_RESOLUTION); } -void PictureLayerImpl::CleanUpUnusedTilings( +void PictureLayerImpl::CleanUpTilingsOnActiveLayer( std::vector<PictureLayerTiling*> used_tilings) { - std::vector<PictureLayerTiling*> to_remove; + DCHECK(layerTreeImpl()->IsActiveTree()); + float raster_contents_scale = + raster_page_scale_ * raster_device_scale_ * raster_source_scale_; + + float min_acceptable_high_res_scale = std::min( + raster_contents_scale, ideal_contents_scale_); + float max_acceptable_high_res_scale = std::max( + raster_contents_scale, ideal_contents_scale_); + + PictureLayerImpl* twin = PendingTwin(); + if (twin) { + float twin_raster_contents_scale = + twin->raster_page_scale_ * + twin->raster_device_scale_ * + twin->raster_source_scale_; + + min_acceptable_high_res_scale = std::min( + min_acceptable_high_res_scale, + std::min(twin_raster_contents_scale, twin->ideal_contents_scale_)); + max_acceptable_high_res_scale = std::max( + max_acceptable_high_res_scale, + std::max(twin_raster_contents_scale, twin->ideal_contents_scale_)); + } + + float low_res_factor = layerTreeImpl()->settings().lowResContentsScaleFactor; + + float min_acceptable_low_res_scale = + low_res_factor * min_acceptable_high_res_scale; + float max_acceptable_low_res_scale = + low_res_factor * max_acceptable_high_res_scale; + + 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) + + if (tiling->contents_scale() >= min_acceptable_high_res_scale && + tiling->contents_scale() <= max_acceptable_high_res_scale) + continue; + + if (tiling->contents_scale() >= min_acceptable_low_res_scale && + tiling->contents_scale() <= max_acceptable_low_res_scale) continue; - if (std::find(used_tilings.begin(), used_tilings.end(), tiling) == + + // Don't remove tilings that are being used and expected to stay around. + if (std::find(used_tilings.begin(), used_tilings.end(), tiling) != used_tilings.end()) - to_remove.push_back(tiling); + continue; + + to_remove.push_back(tiling); } - for (size_t i = 0; i < to_remove.size(); ++i) + for (size_t i = 0; i < to_remove.size(); ++i) { + if (twin) + twin->RemoveTiling(to_remove[i]->contents_scale()); tilings_->Remove(to_remove[i]); + } +} + +PictureLayerImpl* PictureLayerImpl::PendingTwin() const { + DCHECK(layerTreeImpl()->IsActiveTree()); + + PictureLayerImpl* twin = static_cast<PictureLayerImpl*>( + layerTreeImpl()->FindPendingTreeLayerById(id())); + if (twin) + DCHECK_EQ(id(), twin->id()); + return twin; +} + +PictureLayerImpl* PictureLayerImpl::ActiveTwin() const { + DCHECK(layerTreeImpl()->IsPendingTree()); + + PictureLayerImpl* twin = static_cast<PictureLayerImpl*>( + layerTreeImpl()->FindActiveTreeLayerById(id())); + if (twin) + DCHECK_EQ(id(), twin->id()); + return twin; } void PictureLayerImpl::getDebugBorderProperties( diff --git a/cc/picture_layer_impl.h b/cc/picture_layer_impl.h index 243548a..bedf457 100644 --- a/cc/picture_layer_impl.h +++ b/cc/picture_layer_impl.h @@ -67,10 +67,14 @@ public: protected: PictureLayerImpl(LayerTreeImpl* treeImpl, int id); PictureLayerTiling* AddTiling(float contents_scale); + void RemoveTiling(float contents_scale); void SyncFromActiveLayer(const PictureLayerImpl* other); gfx::Size TileSize() const; - void ManageTilings(float ideal_contents_scale); - void CleanUpUnusedTilings(std::vector<PictureLayerTiling*> used_tilings); + void ManageTilings(); + void CleanUpTilingsOnActiveLayer( + std::vector<PictureLayerTiling*> used_tilings); + PictureLayerImpl* PendingTwin() const; + PictureLayerImpl* ActiveTwin() const; virtual void getDebugBorderProperties( SkColor* color, float* width) const OVERRIDE; @@ -86,6 +90,15 @@ protected: float ideal_contents_scale_; bool is_mask_; + float ideal_page_scale_; + float ideal_device_scale_; + float ideal_source_scale_; + + float raster_page_scale_; + float raster_device_scale_; + float raster_source_scale_; + bool raster_source_scale_was_animating_; + friend class PictureLayer; DISALLOW_COPY_AND_ASSIGN(PictureLayerImpl); }; diff --git a/cc/picture_layer_impl_unittest.cc b/cc/picture_layer_impl_unittest.cc index 3e0cba1..9ead881 100644 --- a/cc/picture_layer_impl_unittest.cc +++ b/cc/picture_layer_impl_unittest.cc @@ -29,6 +29,7 @@ class TestablePictureLayerImpl : public PictureLayerImpl { Region& invalidation() { return invalidation_; } using PictureLayerImpl::AddTiling; + using PictureLayerImpl::CleanUpTilingsOnActiveLayer; private: TestablePictureLayerImpl( @@ -172,6 +173,15 @@ class PictureLayerImplTest : public testing::Test { } } + void SetContentsScaleOnBothLayers(float scale) { + float result_scale_x, result_scale_y; + gfx::Size result_bounds; + pending_layer_->calculateContentsScale( + scale, &result_scale_x, &result_scale_y, &result_bounds); + active_layer_->calculateContentsScale( + scale, &result_scale_x, &result_scale_y, &result_bounds); + } + protected: FakeImplProxy proxy_; FakeLayerTreeHostImpl host_impl_; @@ -360,5 +370,229 @@ TEST_F(PictureLayerImplTest, addTilesFromNewRecording) { } } +TEST_F(PictureLayerImplTest, ManageTilingsWithNoRecording) { + gfx::Size tile_size(400, 400); + gfx::Size layer_bounds(1300, 1900); + + scoped_refptr<TestablePicturePileImpl> pending_pile = + TestablePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds); + scoped_refptr<TestablePicturePileImpl> active_pile = + TestablePicturePileImpl::CreateEmptyPile(tile_size, layer_bounds); + + float result_scale_x, result_scale_y; + gfx::Size result_bounds; + + SetupTrees(pending_pile, active_pile); + + // These are included in the scale given to the layer. + host_impl_.setDeviceScaleFactor(1.f); + host_impl_.pendingTree()->SetPageScaleFactorAndLimits(1.f, 1.f, 1.f); + + pending_layer_->calculateContentsScale( + 1.f, &result_scale_x, &result_scale_y, &result_bounds); + + EXPECT_EQ(0u, pending_layer_->tilings().num_tilings()); +} + +TEST_F(PictureLayerImplTest, ManageTilingsCreatesTilings) { + gfx::Size tile_size(400, 400); + gfx::Size layer_bounds(1300, 1900); + + scoped_refptr<TestablePicturePileImpl> pending_pile = + TestablePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<TestablePicturePileImpl> active_pile = + TestablePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + float result_scale_x, result_scale_y; + gfx::Size result_bounds; + + SetupTrees(pending_pile, active_pile); + EXPECT_EQ(0u, pending_layer_->tilings().num_tilings()); + + float low_res_factor = host_impl_.settings().lowResContentsScaleFactor; + EXPECT_LT(low_res_factor, 1.f); + + // These are included in the scale given to the layer. + host_impl_.setDeviceScaleFactor(1.7f); + host_impl_.pendingTree()->SetPageScaleFactorAndLimits(3.2f, 3.2f, 3.2f); + + pending_layer_->calculateContentsScale( + 1.3f, &result_scale_x, &result_scale_y, &result_bounds); + ASSERT_EQ(2u, pending_layer_->tilings().num_tilings()); + EXPECT_FLOAT_EQ( + 1.3f, + pending_layer_->tilings().tiling_at(0)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.3f * low_res_factor, + pending_layer_->tilings().tiling_at(1)->contents_scale()); + + // If we change the layer's CSS scale factor, then we should not get new + // tilings. + pending_layer_->calculateContentsScale( + 1.8f, &result_scale_x, &result_scale_y, &result_bounds); + ASSERT_EQ(2u, pending_layer_->tilings().num_tilings()); + EXPECT_FLOAT_EQ( + 1.3f, + pending_layer_->tilings().tiling_at(0)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.3f * low_res_factor, + pending_layer_->tilings().tiling_at(1)->contents_scale()); + + // If we change the page scale factor, then we should get new tilings. + host_impl_.pendingTree()->SetPageScaleFactorAndLimits(2.2f, 2.2f, 2.2f); + + pending_layer_->calculateContentsScale( + 1.8f, &result_scale_x, &result_scale_y, &result_bounds); + ASSERT_EQ(4u, pending_layer_->tilings().num_tilings()); + EXPECT_FLOAT_EQ( + 1.8f, + pending_layer_->tilings().tiling_at(0)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.8f * low_res_factor, + pending_layer_->tilings().tiling_at(2)->contents_scale()); + + // If we change the device scale factor, then we should get new tilings. + host_impl_.setDeviceScaleFactor(1.4f); + + pending_layer_->calculateContentsScale( + 1.9f, &result_scale_x, &result_scale_y, &result_bounds); + ASSERT_EQ(6u, pending_layer_->tilings().num_tilings()); + EXPECT_FLOAT_EQ( + 1.9f, + pending_layer_->tilings().tiling_at(0)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.9f * low_res_factor, + pending_layer_->tilings().tiling_at(3)->contents_scale()); + + // If we change the device scale factor, but end up at the same total scale + // factor somehow, then we don't get new tilings. + host_impl_.setDeviceScaleFactor(2.2f); + host_impl_.pendingTree()->SetPageScaleFactorAndLimits(1.4f, 1.4f, 1.4f); + + pending_layer_->calculateContentsScale( + 1.9f, &result_scale_x, &result_scale_y, &result_bounds); + ASSERT_EQ(6u, pending_layer_->tilings().num_tilings()); + EXPECT_FLOAT_EQ( + 1.9f, + pending_layer_->tilings().tiling_at(0)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.9f * low_res_factor, + pending_layer_->tilings().tiling_at(3)->contents_scale()); +} + +TEST_F(PictureLayerImplTest, CleanUpTilings) { + gfx::Size tile_size(400, 400); + gfx::Size layer_bounds(1300, 1900); + + scoped_refptr<TestablePicturePileImpl> pending_pile = + TestablePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + scoped_refptr<TestablePicturePileImpl> active_pile = + TestablePicturePileImpl::CreateFilledPile(tile_size, layer_bounds); + + float result_scale_x, result_scale_y; + gfx::Size result_bounds; + std::vector<PictureLayerTiling*> used_tilings; + + SetupTrees(pending_pile, active_pile); + EXPECT_EQ(0u, pending_layer_->tilings().num_tilings()); + + float low_res_factor = host_impl_.settings().lowResContentsScaleFactor; + EXPECT_LT(low_res_factor, 1.f); + + // These are included in the scale given to the layer. + host_impl_.setDeviceScaleFactor(1.7f); + host_impl_.pendingTree()->SetPageScaleFactorAndLimits(3.2f, 3.2f, 3.2f); + host_impl_.activeTree()->SetPageScaleFactorAndLimits(3.2f, 3.2f, 3.2f); + + SetContentsScaleOnBothLayers(1.f); + ASSERT_EQ(2u, active_layer_->tilings().num_tilings()); + + // We only have ideal tilings, so they aren't removed. + used_tilings.clear(); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(2u, active_layer_->tilings().num_tilings()); + + // Changing the ideal but not creating new tilings. + SetContentsScaleOnBothLayers(1.5f); + ASSERT_EQ(2u, active_layer_->tilings().num_tilings()); + + // The tilings are still our target scale, so they aren't removed. + used_tilings.clear(); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(2u, active_layer_->tilings().num_tilings()); + + // Create a 1.2 scale tiling. Now we have 1.0 and 1.2 tilings. Ideal = 1.2. + host_impl_.pendingTree()->SetPageScaleFactorAndLimits(1.2f, 1.2f, 1.2f); + host_impl_.activeTree()->SetPageScaleFactorAndLimits(1.2f, 1.2f, 1.2f); + SetContentsScaleOnBothLayers(1.2f); + ASSERT_EQ(4u, active_layer_->tilings().num_tilings()); + EXPECT_FLOAT_EQ( + 1.f, + active_layer_->tilings().tiling_at(1)->contents_scale()); + EXPECT_FLOAT_EQ( + 1.f * low_res_factor, + active_layer_->tilings().tiling_at(3)->contents_scale()); + + // Mark the non-ideal tilings as used. They won't be removed. + used_tilings.clear(); + used_tilings.push_back(active_layer_->tilings().tiling_at(1)); + used_tilings.push_back(active_layer_->tilings().tiling_at(3)); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(4u, active_layer_->tilings().num_tilings()); + + // Now move the ideal scale to 0.5. Our target stays 1.2. + SetContentsScaleOnBothLayers(0.5f); + + // All the tilings are between are target and the ideal, so they are not + // removed. + used_tilings.clear(); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(4u, active_layer_->tilings().num_tilings()); + + // Now move the ideal scale to 1.0. Our target stays 1.2. + SetContentsScaleOnBothLayers(1.f); + + // All the tilings are between are target and the ideal, so they are not + // removed. + used_tilings.clear(); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(4u, active_layer_->tilings().num_tilings()); + + // Now move the ideal scale to 1.1 on the active layer. Our target stays 1.2. + active_layer_->calculateContentsScale( + 1.1f, &result_scale_x, &result_scale_y, &result_bounds); + + // Because the pending layer's ideal scale is still 1.0, our tilings fall + // in the range [1.0,1.2] and are kept. + used_tilings.clear(); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(4u, active_layer_->tilings().num_tilings()); + + // Move the ideal scale on the pending layer to 1.1 as well. Our target stays + // 1.2 still. + pending_layer_->calculateContentsScale( + 1.1f, &result_scale_x, &result_scale_y, &result_bounds); + + // Our 1.0 tiling now falls outside the range between our ideal scale and our + // target raster scale. But it is in our used tilings set, so nothing is + // deleted. + used_tilings.clear(); + used_tilings.push_back(active_layer_->tilings().tiling_at(1)); + used_tilings.push_back(active_layer_->tilings().tiling_at(3)); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(4u, active_layer_->tilings().num_tilings()); + + // If we remove it from our used tilings set, it is outside the range to keep + // so it is deleted. Try one tiling at a time. + used_tilings.clear(); + used_tilings.push_back(active_layer_->tilings().tiling_at(1)); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(3u, active_layer_->tilings().num_tilings()); + used_tilings.clear(); + active_layer_->CleanUpTilingsOnActiveLayer(used_tilings); + ASSERT_EQ(2u, active_layer_->tilings().num_tilings()); + +} + } // namespace } // namespace cc |