1// Copyright 2012 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "cc/resources/picture_layer_tiling_set.h" 6 7#include <limits> 8 9namespace cc { 10 11namespace { 12 13class LargestToSmallestScaleFunctor { 14 public: 15 bool operator() (PictureLayerTiling* left, PictureLayerTiling* right) { 16 return left->contents_scale() > right->contents_scale(); 17 } 18}; 19 20} // namespace 21 22 23PictureLayerTilingSet::PictureLayerTilingSet( 24 PictureLayerTilingClient* client, 25 const gfx::Size& layer_bounds) 26 : client_(client), 27 layer_bounds_(layer_bounds) { 28} 29 30PictureLayerTilingSet::~PictureLayerTilingSet() { 31} 32 33void PictureLayerTilingSet::SetClient(PictureLayerTilingClient* client) { 34 client_ = client; 35 for (size_t i = 0; i < tilings_.size(); ++i) 36 tilings_[i]->SetClient(client_); 37} 38 39bool PictureLayerTilingSet::SyncTilings(const PictureLayerTilingSet& other, 40 const gfx::Size& new_layer_bounds, 41 const Region& layer_invalidation, 42 float minimum_contents_scale) { 43 if (new_layer_bounds.IsEmpty()) { 44 RemoveAllTilings(); 45 layer_bounds_ = new_layer_bounds; 46 return false; 47 } 48 49 tilings_.reserve(other.tilings_.size()); 50 51 // Remove any tilings that aren't in |other| or don't meet the minimum. 52 for (size_t i = 0; i < tilings_.size(); ++i) { 53 float scale = tilings_[i]->contents_scale(); 54 if (scale >= minimum_contents_scale && !!other.TilingAtScale(scale)) 55 continue; 56 // Swap with the last element and remove it. 57 tilings_.swap(tilings_.begin() + i, tilings_.end() - 1); 58 tilings_.pop_back(); 59 --i; 60 } 61 62 bool have_high_res_tiling = false; 63 64 // Add any missing tilings from |other| that meet the minimum. 65 for (size_t i = 0; i < other.tilings_.size(); ++i) { 66 float contents_scale = other.tilings_[i]->contents_scale(); 67 if (contents_scale < minimum_contents_scale) 68 continue; 69 if (PictureLayerTiling* this_tiling = TilingAtScale(contents_scale)) { 70 this_tiling->set_resolution(other.tilings_[i]->resolution()); 71 72 // These two calls must come before updating the pile, because they may 73 // destroy tiles that the new pile cannot raster. 74 this_tiling->SetLayerBounds(new_layer_bounds); 75 this_tiling->Invalidate(layer_invalidation); 76 77 this_tiling->UpdateTilesToCurrentPile(); 78 this_tiling->CreateMissingTilesInLiveTilesRect(); 79 if (this_tiling->resolution() == HIGH_RESOLUTION) 80 have_high_res_tiling = true; 81 82 DCHECK(this_tiling->tile_size() == 83 client_->CalculateTileSize(this_tiling->TilingRect().size())); 84 continue; 85 } 86 scoped_ptr<PictureLayerTiling> new_tiling = PictureLayerTiling::Create( 87 contents_scale, 88 new_layer_bounds, 89 client_); 90 new_tiling->set_resolution(other.tilings_[i]->resolution()); 91 if (new_tiling->resolution() == HIGH_RESOLUTION) 92 have_high_res_tiling = true; 93 tilings_.push_back(new_tiling.Pass()); 94 } 95 tilings_.sort(LargestToSmallestScaleFunctor()); 96 97 layer_bounds_ = new_layer_bounds; 98 return have_high_res_tiling; 99} 100 101void PictureLayerTilingSet::RemoveTilesInRegion(const Region& region) { 102 for (size_t i = 0; i < tilings_.size(); ++i) 103 tilings_[i]->RemoveTilesInRegion(region); 104} 105 106PictureLayerTiling* PictureLayerTilingSet::AddTiling(float contents_scale) { 107 for (size_t i = 0; i < tilings_.size(); ++i) 108 DCHECK_NE(tilings_[i]->contents_scale(), contents_scale); 109 110 tilings_.push_back(PictureLayerTiling::Create(contents_scale, 111 layer_bounds_, 112 client_)); 113 PictureLayerTiling* appended = tilings_.back(); 114 115 tilings_.sort(LargestToSmallestScaleFunctor()); 116 return appended; 117} 118 119int PictureLayerTilingSet::NumHighResTilings() const { 120 int num_high_res = 0; 121 for (size_t i = 0; i < tilings_.size(); ++i) { 122 if (tilings_[i]->resolution() == HIGH_RESOLUTION) 123 num_high_res++; 124 } 125 return num_high_res; 126} 127 128PictureLayerTiling* PictureLayerTilingSet::TilingAtScale(float scale) const { 129 for (size_t i = 0; i < tilings_.size(); ++i) { 130 if (tilings_[i]->contents_scale() == scale) 131 return tilings_[i]; 132 } 133 return NULL; 134} 135 136void PictureLayerTilingSet::RemoveAllTilings() { 137 tilings_.clear(); 138} 139 140void PictureLayerTilingSet::Remove(PictureLayerTiling* tiling) { 141 ScopedPtrVector<PictureLayerTiling>::iterator iter = 142 std::find(tilings_.begin(), tilings_.end(), tiling); 143 if (iter == tilings_.end()) 144 return; 145 tilings_.erase(iter); 146} 147 148void PictureLayerTilingSet::RemoveAllTiles() { 149 for (size_t i = 0; i < tilings_.size(); ++i) 150 tilings_[i]->Reset(); 151} 152 153PictureLayerTilingSet::CoverageIterator::CoverageIterator( 154 const PictureLayerTilingSet* set, 155 float contents_scale, 156 const gfx::Rect& content_rect, 157 float ideal_contents_scale) 158 : set_(set), 159 contents_scale_(contents_scale), 160 ideal_contents_scale_(ideal_contents_scale), 161 current_tiling_(-1) { 162 missing_region_.Union(content_rect); 163 164 for (ideal_tiling_ = 0; 165 static_cast<size_t>(ideal_tiling_) < set_->tilings_.size(); 166 ++ideal_tiling_) { 167 PictureLayerTiling* tiling = set_->tilings_[ideal_tiling_]; 168 if (tiling->contents_scale() < ideal_contents_scale_) { 169 if (ideal_tiling_ > 0) 170 ideal_tiling_--; 171 break; 172 } 173 } 174 175 DCHECK_LE(set_->tilings_.size(), 176 static_cast<size_t>(std::numeric_limits<int>::max())); 177 178 int num_tilings = set_->tilings_.size(); 179 if (ideal_tiling_ == num_tilings && ideal_tiling_ > 0) 180 ideal_tiling_--; 181 182 ++(*this); 183} 184 185PictureLayerTilingSet::CoverageIterator::~CoverageIterator() { 186} 187 188gfx::Rect PictureLayerTilingSet::CoverageIterator::geometry_rect() const { 189 if (!tiling_iter_) { 190 if (!region_iter_.has_rect()) 191 return gfx::Rect(); 192 return region_iter_.rect(); 193 } 194 return tiling_iter_.geometry_rect(); 195} 196 197gfx::RectF PictureLayerTilingSet::CoverageIterator::texture_rect() const { 198 if (!tiling_iter_) 199 return gfx::RectF(); 200 return tiling_iter_.texture_rect(); 201} 202 203gfx::Size PictureLayerTilingSet::CoverageIterator::texture_size() const { 204 if (!tiling_iter_) 205 return gfx::Size(); 206 return tiling_iter_.texture_size(); 207} 208 209Tile* PictureLayerTilingSet::CoverageIterator::operator->() const { 210 if (!tiling_iter_) 211 return NULL; 212 return *tiling_iter_; 213} 214 215Tile* PictureLayerTilingSet::CoverageIterator::operator*() const { 216 if (!tiling_iter_) 217 return NULL; 218 return *tiling_iter_; 219} 220 221PictureLayerTiling* PictureLayerTilingSet::CoverageIterator::CurrentTiling() { 222 if (current_tiling_ < 0) 223 return NULL; 224 if (static_cast<size_t>(current_tiling_) >= set_->tilings_.size()) 225 return NULL; 226 return set_->tilings_[current_tiling_]; 227} 228 229int PictureLayerTilingSet::CoverageIterator::NextTiling() const { 230 // Order returned by this method is: 231 // 1. Ideal tiling index 232 // 2. Tiling index < Ideal in decreasing order (higher res than ideal) 233 // 3. Tiling index > Ideal in increasing order (lower res than ideal) 234 // 4. Tiling index > tilings.size() (invalid index) 235 if (current_tiling_ < 0) 236 return ideal_tiling_; 237 else if (current_tiling_ > ideal_tiling_) 238 return current_tiling_ + 1; 239 else if (current_tiling_) 240 return current_tiling_ - 1; 241 else 242 return ideal_tiling_ + 1; 243} 244 245PictureLayerTilingSet::CoverageIterator& 246PictureLayerTilingSet::CoverageIterator::operator++() { 247 bool first_time = current_tiling_ < 0; 248 249 if (!*this && !first_time) 250 return *this; 251 252 if (tiling_iter_) 253 ++tiling_iter_; 254 255 // Loop until we find a valid place to stop. 256 while (true) { 257 while (tiling_iter_ && 258 (!*tiling_iter_ || !tiling_iter_->IsReadyToDraw())) { 259 missing_region_.Union(tiling_iter_.geometry_rect()); 260 ++tiling_iter_; 261 } 262 if (tiling_iter_) 263 return *this; 264 265 // If the set of current rects for this tiling is done, go to the next 266 // tiling and set up to iterate through all of the remaining holes. 267 // This will also happen the first time through the loop. 268 if (!region_iter_.has_rect()) { 269 current_tiling_ = NextTiling(); 270 current_region_.Swap(&missing_region_); 271 missing_region_.Clear(); 272 region_iter_ = Region::Iterator(current_region_); 273 274 // All done and all filled. 275 if (!region_iter_.has_rect()) { 276 current_tiling_ = set_->tilings_.size(); 277 return *this; 278 } 279 280 // No more valid tiles, return this checkerboard rect. 281 if (current_tiling_ >= static_cast<int>(set_->tilings_.size())) 282 return *this; 283 } 284 285 // Pop a rect off. If there are no more tilings, then these will be 286 // treated as geometry with null tiles that the caller can checkerboard. 287 gfx::Rect last_rect = region_iter_.rect(); 288 region_iter_.next(); 289 290 // Done, found next checkerboard rect to return. 291 if (current_tiling_ >= static_cast<int>(set_->tilings_.size())) 292 return *this; 293 294 // Construct a new iterator for the next tiling, but we need to loop 295 // again until we get to a valid one. 296 tiling_iter_ = PictureLayerTiling::CoverageIterator( 297 set_->tilings_[current_tiling_], 298 contents_scale_, 299 last_rect); 300 } 301 302 return *this; 303} 304 305PictureLayerTilingSet::CoverageIterator::operator bool() const { 306 return current_tiling_ < static_cast<int>(set_->tilings_.size()) || 307 region_iter_.has_rect(); 308} 309 310void PictureLayerTilingSet::DidBecomeActive() { 311 for (size_t i = 0; i < tilings_.size(); ++i) 312 tilings_[i]->DidBecomeActive(); 313} 314 315void PictureLayerTilingSet::DidBecomeRecycled() { 316 for (size_t i = 0; i < tilings_.size(); ++i) 317 tilings_[i]->DidBecomeRecycled(); 318} 319 320scoped_ptr<base::Value> PictureLayerTilingSet::AsValue() const { 321 scoped_ptr<base::ListValue> state(new base::ListValue()); 322 for (size_t i = 0; i < tilings_.size(); ++i) 323 state->Append(tilings_[i]->AsValue().release()); 324 return state.PassAs<base::Value>(); 325} 326 327size_t PictureLayerTilingSet::GPUMemoryUsageInBytes() const { 328 size_t amount = 0; 329 for (size_t i = 0; i < tilings_.size(); ++i) 330 amount += tilings_[i]->GPUMemoryUsageInBytes(); 331 return amount; 332} 333 334} // namespace cc 335