| OLD | NEW |
| (Empty) |
| 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/picture_layer_tiling.h" | |
| 6 | |
| 7 #include <cmath> | |
| 8 | |
| 9 #include "base/debug/trace_event.h" | |
| 10 #include "cc/base/math_util.h" | |
| 11 #include "ui/gfx/point_conversions.h" | |
| 12 #include "ui/gfx/rect_conversions.h" | |
| 13 #include "ui/gfx/safe_integer_conversions.h" | |
| 14 #include "ui/gfx/size_conversions.h" | |
| 15 | |
| 16 namespace cc { | |
| 17 | |
| 18 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create( | |
| 19 float contents_scale) { | |
| 20 return make_scoped_ptr(new PictureLayerTiling(contents_scale)); | |
| 21 } | |
| 22 | |
| 23 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Clone() const { | |
| 24 return make_scoped_ptr(new PictureLayerTiling(*this)); | |
| 25 } | |
| 26 | |
| 27 PictureLayerTiling::PictureLayerTiling(float contents_scale) | |
| 28 : client_(NULL), | |
| 29 contents_scale_(contents_scale), | |
| 30 tiling_data_(gfx::Size(), gfx::Size(), true), | |
| 31 resolution_(NON_IDEAL_RESOLUTION), | |
| 32 last_source_frame_number_(0), | |
| 33 last_impl_frame_time_(0) { | |
| 34 } | |
| 35 | |
| 36 PictureLayerTiling::~PictureLayerTiling() { | |
| 37 } | |
| 38 | |
| 39 void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) { | |
| 40 client_ = client; | |
| 41 } | |
| 42 | |
| 43 gfx::Rect PictureLayerTiling::ContentRect() const { | |
| 44 return gfx::Rect(tiling_data_.total_size()); | |
| 45 } | |
| 46 | |
| 47 gfx::SizeF PictureLayerTiling::ContentSizeF() const { | |
| 48 return gfx::ScaleSize(layer_bounds_, contents_scale_); | |
| 49 } | |
| 50 | |
| 51 Tile* PictureLayerTiling::TileAt(int i, int j) const { | |
| 52 TileMap::const_iterator iter = tiles_.find(TileMapKey(i, j)); | |
| 53 if (iter == tiles_.end()) | |
| 54 return NULL; | |
| 55 return iter->second.get(); | |
| 56 } | |
| 57 | |
| 58 void PictureLayerTiling::CreateTile(int i, int j) { | |
| 59 gfx::Rect tile_rect = tiling_data_.TileBoundsWithBorder(i, j); | |
| 60 tile_rect.set_size(tiling_data_.max_texture_size()); | |
| 61 TileMapKey key(i, j); | |
| 62 DCHECK(tiles_.find(key) == tiles_.end()); | |
| 63 scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect); | |
| 64 if (tile) | |
| 65 tiles_[key] = tile; | |
| 66 } | |
| 67 | |
| 68 Region PictureLayerTiling::OpaqueRegionInContentRect( | |
| 69 const gfx::Rect& content_rect) const { | |
| 70 Region opaque_region; | |
| 71 // TODO(enne): implement me | |
| 72 return opaque_region; | |
| 73 } | |
| 74 | |
| 75 void PictureLayerTiling::SetLayerBounds(gfx::Size layer_bounds) { | |
| 76 if (layer_bounds_ == layer_bounds) | |
| 77 return; | |
| 78 | |
| 79 gfx::Size old_layer_bounds = layer_bounds_; | |
| 80 layer_bounds_ = layer_bounds; | |
| 81 gfx::Size old_content_bounds = tiling_data_.total_size(); | |
| 82 gfx::Size content_bounds = | |
| 83 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_)); | |
| 84 | |
| 85 tiling_data_.SetTotalSize(content_bounds); | |
| 86 if (layer_bounds_.IsEmpty()) { | |
| 87 tiles_.clear(); | |
| 88 return; | |
| 89 } | |
| 90 | |
| 91 gfx::Size tile_size = client_->CalculateTileSize( | |
| 92 tiling_data_.max_texture_size(), | |
| 93 content_bounds); | |
| 94 if (tile_size != tiling_data_.max_texture_size()) { | |
| 95 tiling_data_.SetMaxTextureSize(tile_size); | |
| 96 tiles_.clear(); | |
| 97 CreateTilesFromLayerRect(gfx::Rect(layer_bounds_)); | |
| 98 return; | |
| 99 } | |
| 100 | |
| 101 // Any tiles outside our new bounds are invalid and should be dropped. | |
| 102 if (old_content_bounds.width() > content_bounds.width() || | |
| 103 old_content_bounds.height() > content_bounds.height()) { | |
| 104 int right = | |
| 105 tiling_data_.TileXIndexFromSrcCoord(content_bounds.width() - 1); | |
| 106 int bottom = | |
| 107 tiling_data_.TileYIndexFromSrcCoord(content_bounds.height() - 1); | |
| 108 | |
| 109 std::vector<TileMapKey> invalid_tile_keys; | |
| 110 for (TileMap::const_iterator it = tiles_.begin(); | |
| 111 it != tiles_.end(); ++it) { | |
| 112 if (it->first.first > right || it->first.second > bottom) | |
| 113 invalid_tile_keys.push_back(it->first); | |
| 114 } | |
| 115 for (size_t i = 0; i < invalid_tile_keys.size(); ++i) | |
| 116 tiles_.erase(invalid_tile_keys[i]); | |
| 117 } | |
| 118 | |
| 119 // Create tiles for newly exposed areas. | |
| 120 Region layer_region((gfx::Rect(layer_bounds_))); | |
| 121 layer_region.Subtract(gfx::Rect(old_layer_bounds)); | |
| 122 for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) { | |
| 123 Invalidate(iter.rect()); | |
| 124 CreateTilesFromLayerRect(iter.rect()); | |
| 125 } | |
| 126 } | |
| 127 | |
| 128 void PictureLayerTiling::Invalidate(const Region& layer_invalidation) { | |
| 129 std::vector<TileMapKey> new_tiles; | |
| 130 | |
| 131 for (Region::Iterator region_iter(layer_invalidation); | |
| 132 region_iter.has_rect(); | |
| 133 region_iter.next()) { | |
| 134 | |
| 135 gfx::Rect layer_invalidation = region_iter.rect(); | |
| 136 layer_invalidation.Intersect(gfx::Rect(layer_bounds_)); | |
| 137 gfx::Rect rect = | |
| 138 gfx::ToEnclosingRect(ScaleRect(layer_invalidation, contents_scale_)); | |
| 139 | |
| 140 for (PictureLayerTiling::Iterator tile_iter(this, contents_scale_, rect, | |
| 141 PictureLayerTiling::LayerDeviceA
lignmentUnknown); | |
| 142 tile_iter; | |
| 143 ++tile_iter) { | |
| 144 TileMapKey key(tile_iter.tile_i_, tile_iter.tile_j_); | |
| 145 TileMap::iterator found = tiles_.find(key); | |
| 146 if (found == tiles_.end()) | |
| 147 continue; | |
| 148 | |
| 149 tiles_.erase(found); | |
| 150 new_tiles.push_back(key); | |
| 151 } | |
| 152 } | |
| 153 | |
| 154 for (size_t i = 0; i < new_tiles.size(); ++i) | |
| 155 CreateTile(new_tiles[i].first, new_tiles[i].second); | |
| 156 } | |
| 157 | |
| 158 void PictureLayerTiling::CreateTilesFromLayerRect(gfx::Rect layer_rect) { | |
| 159 gfx::Rect content_rect = | |
| 160 gfx::ToEnclosingRect(ScaleRect(layer_rect, contents_scale_)); | |
| 161 CreateTilesFromContentRect(content_rect); | |
| 162 } | |
| 163 | |
| 164 void PictureLayerTiling::CreateTilesFromContentRect(gfx::Rect content_rect) { | |
| 165 for (TilingData::Iterator iter(&tiling_data_, content_rect); iter; ++iter) { | |
| 166 TileMap::iterator found = | |
| 167 tiles_.find(TileMapKey(iter.index_x(), iter.index_y())); | |
| 168 // Ignore any tiles that already exist. | |
| 169 if (found != tiles_.end()) | |
| 170 continue; | |
| 171 CreateTile(iter.index_x(), iter.index_y()); | |
| 172 } | |
| 173 } | |
| 174 | |
| 175 PictureLayerTiling::Iterator::Iterator() | |
| 176 : tiling_(NULL), | |
| 177 current_tile_(NULL), | |
| 178 tile_i_(0), | |
| 179 tile_j_(0), | |
| 180 left_(0), | |
| 181 top_(0), | |
| 182 right_(-1), | |
| 183 bottom_(-1) { | |
| 184 } | |
| 185 | |
| 186 PictureLayerTiling::Iterator::Iterator(const PictureLayerTiling* tiling, | |
| 187 float dest_scale, | |
| 188 gfx::Rect dest_rect, | |
| 189 LayerDeviceAlignment layerDeviceAlignment
) | |
| 190 : tiling_(tiling), | |
| 191 dest_rect_(dest_rect), | |
| 192 dest_to_content_scale_(0), | |
| 193 current_tile_(NULL), | |
| 194 tile_i_(0), | |
| 195 tile_j_(0), | |
| 196 left_(0), | |
| 197 top_(0), | |
| 198 right_(-1), | |
| 199 bottom_(-1) { | |
| 200 DCHECK(tiling_); | |
| 201 if (dest_rect_.IsEmpty()) | |
| 202 return; | |
| 203 | |
| 204 dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale; | |
| 205 // This is the maximum size that the dest rect can be, given the content size. | |
| 206 gfx::Size dest_content_size = gfx::ToCeiledSize(gfx::ScaleSize( | |
| 207 tiling_->ContentRect().size(), | |
| 208 1 / dest_to_content_scale_, | |
| 209 1 / dest_to_content_scale_)); | |
| 210 | |
| 211 gfx::Rect content_rect = | |
| 212 gfx::ToEnclosingRect(gfx::ScaleRect(dest_rect_, | |
| 213 dest_to_content_scale_, | |
| 214 dest_to_content_scale_)); | |
| 215 // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to | |
| 216 // check for non-intersection first. | |
| 217 content_rect.Intersect(gfx::Rect(tiling_->tiling_data_.total_size())); | |
| 218 if (content_rect.IsEmpty()) | |
| 219 return; | |
| 220 | |
| 221 left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x()); | |
| 222 top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y()); | |
| 223 right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord( | |
| 224 content_rect.right() - 1); | |
| 225 bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord( | |
| 226 content_rect.bottom() - 1); | |
| 227 | |
| 228 tile_i_ = left_ - 1; | |
| 229 tile_j_ = top_; | |
| 230 ++(*this); | |
| 231 } | |
| 232 | |
| 233 PictureLayerTiling::Iterator::~Iterator() { | |
| 234 } | |
| 235 | |
| 236 PictureLayerTiling::Iterator& PictureLayerTiling::Iterator::operator++() { | |
| 237 if (tile_j_ > bottom_) | |
| 238 return *this; | |
| 239 | |
| 240 bool first_time = tile_i_ < left_; | |
| 241 bool new_row = false; | |
| 242 tile_i_++; | |
| 243 if (tile_i_ > right_) { | |
| 244 tile_i_ = left_; | |
| 245 tile_j_++; | |
| 246 new_row = true; | |
| 247 if (tile_j_ > bottom_) { | |
| 248 current_tile_ = NULL; | |
| 249 return *this; | |
| 250 } | |
| 251 } | |
| 252 | |
| 253 current_tile_ = tiling_->TileAt(tile_i_, tile_j_); | |
| 254 | |
| 255 // Calculate the current geometry rect. Due to floating point rounding | |
| 256 // and ToEnclosingRect, tiles might overlap in destination space on the | |
| 257 // edges. | |
| 258 gfx::Rect last_geometry_rect = current_geometry_rect_; | |
| 259 | |
| 260 gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_); | |
| 261 | |
| 262 current_geometry_rect_ = gfx::ToEnclosingRect( | |
| 263 gfx::ScaleRect(content_rect, 1 / dest_to_content_scale_, | |
| 264 1 / dest_to_content_scale_)); | |
| 265 | |
| 266 current_geometry_rect_.Intersect(dest_rect_); | |
| 267 | |
| 268 if (first_time) | |
| 269 return *this; | |
| 270 | |
| 271 // Iteration happens left->right, top->bottom. Running off the bottom-right | |
| 272 // edge is handled by the intersection above with dest_rect_. Here we make | |
| 273 // sure that the new current geometry rect doesn't overlap with the last. | |
| 274 int min_left; | |
| 275 int min_top; | |
| 276 if (new_row) { | |
| 277 min_left = dest_rect_.x(); | |
| 278 min_top = last_geometry_rect.bottom(); | |
| 279 } else { | |
| 280 min_left = last_geometry_rect.right(); | |
| 281 min_top = last_geometry_rect.y(); | |
| 282 } | |
| 283 | |
| 284 int inset_left = std::max(0, min_left - current_geometry_rect_.x()); | |
| 285 int inset_top = std::max(0, min_top - current_geometry_rect_.y()); | |
| 286 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0); | |
| 287 | |
| 288 if (!new_row) { | |
| 289 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x()); | |
| 290 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom()); | |
| 291 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y()); | |
| 292 } | |
| 293 | |
| 294 return *this; | |
| 295 } | |
| 296 | |
| 297 gfx::Rect PictureLayerTiling::Iterator::geometry_rect() const { | |
| 298 return current_geometry_rect_; | |
| 299 } | |
| 300 | |
| 301 gfx::Rect PictureLayerTiling::Iterator::full_tile_geometry_rect() const { | |
| 302 gfx::Rect rect = tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_); | |
| 303 rect.set_size(tiling_->tiling_data_.max_texture_size()); | |
| 304 return rect; | |
| 305 } | |
| 306 | |
| 307 gfx::RectF PictureLayerTiling::Iterator::texture_rect() const { | |
| 308 gfx::PointF tex_origin = | |
| 309 tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin(); | |
| 310 | |
| 311 // Convert from dest space => content space => texture space. | |
| 312 gfx::RectF texture_rect(current_geometry_rect_); | |
| 313 texture_rect.Scale(dest_to_content_scale_, | |
| 314 dest_to_content_scale_); | |
| 315 texture_rect.Offset(-tex_origin.OffsetFromOrigin()); | |
| 316 texture_rect.Intersect(tiling_->ContentRect()); | |
| 317 | |
| 318 return texture_rect; | |
| 319 } | |
| 320 | |
| 321 gfx::Size PictureLayerTiling::Iterator::texture_size() const { | |
| 322 return tiling_->tiling_data_.max_texture_size(); | |
| 323 } | |
| 324 | |
| 325 void PictureLayerTiling::UpdateTilePriorities( | |
| 326 WhichTree tree, | |
| 327 gfx::Size device_viewport, | |
| 328 const gfx::RectF& viewport_in_layer_space, | |
| 329 gfx::Size last_layer_bounds, | |
| 330 gfx::Size current_layer_bounds, | |
| 331 float last_layer_contents_scale, | |
| 332 float current_layer_contents_scale, | |
| 333 const gfx::Transform& last_screen_transform, | |
| 334 const gfx::Transform& current_screen_transform, | |
| 335 int current_source_frame_number, | |
| 336 double current_frame_time, | |
| 337 bool store_screen_space_quads_on_tiles) { | |
| 338 if (ContentRect().IsEmpty()) | |
| 339 return; | |
| 340 | |
| 341 bool first_update_in_new_source_frame = | |
| 342 current_source_frame_number != last_source_frame_number_; | |
| 343 | |
| 344 bool first_update_in_new_impl_frame = | |
| 345 current_frame_time != last_impl_frame_time_; | |
| 346 | |
| 347 // In pending tree, this is always called. We update priorities: | |
| 348 // - Immediately after a commit (first_update_in_new_source_frame). | |
| 349 // - On animation ticks after the first frame in the tree | |
| 350 // (first_update_in_new_impl_frame). | |
| 351 // In active tree, this is only called during draw. We update priorities: | |
| 352 // - On draw if properties were not already computed by the pending tree | |
| 353 // and activated for the frame (first_update_in_new_impl_frame). | |
| 354 if (!first_update_in_new_impl_frame && !first_update_in_new_source_frame) | |
| 355 return; | |
| 356 | |
| 357 double time_delta = 0; | |
| 358 if (last_impl_frame_time_ != 0 && last_layer_bounds == current_layer_bounds) | |
| 359 time_delta = current_frame_time - last_impl_frame_time_; | |
| 360 | |
| 361 gfx::Rect viewport_in_content_space = | |
| 362 gfx::ToEnclosingRect(gfx::ScaleRect(viewport_in_layer_space, | |
| 363 contents_scale_)); | |
| 364 | |
| 365 gfx::Size tile_size = tiling_data_.max_texture_size(); | |
| 366 int64 prioritized_rect_area = | |
| 367 TilePriority::kNumTilesToCoverWithInflatedViewportRectForPrioritization * | |
| 368 tile_size.width() * tile_size.height(); | |
| 369 | |
| 370 gfx::Rect prioritized_rect = ExpandRectEquallyToAreaBoundedBy( | |
| 371 viewport_in_content_space, | |
| 372 prioritized_rect_area, | |
| 373 ContentRect()); | |
| 374 DCHECK(ContentRect().Contains(prioritized_rect)); | |
| 375 | |
| 376 // Iterate through all of the tiles that were live last frame but will | |
| 377 // not be live this frame, and mark them as being dead. | |
| 378 for (TilingData::DifferenceIterator iter(&tiling_data_, | |
| 379 last_prioritized_rect_, | |
| 380 prioritized_rect); | |
| 381 iter; | |
| 382 ++iter) { | |
| 383 TileMap::iterator find = tiles_.find(iter.index()); | |
| 384 if (find == tiles_.end()) | |
| 385 continue; | |
| 386 | |
| 387 TilePriority priority; | |
| 388 DCHECK(!priority.is_live); | |
| 389 Tile* tile = find->second.get(); | |
| 390 tile->SetPriority(tree, priority); | |
| 391 } | |
| 392 last_prioritized_rect_ = prioritized_rect; | |
| 393 | |
| 394 gfx::Rect view_rect(device_viewport); | |
| 395 float current_scale = current_layer_contents_scale / contents_scale_; | |
| 396 float last_scale = last_layer_contents_scale / contents_scale_; | |
| 397 | |
| 398 // Fast path tile priority calculation when both transforms are translations. | |
| 399 if (last_screen_transform.IsIdentityOrTranslation() && | |
| 400 current_screen_transform.IsIdentityOrTranslation()) | |
| 401 { | |
| 402 gfx::Vector2dF current_offset( | |
| 403 current_screen_transform.matrix().get(0, 3), | |
| 404 current_screen_transform.matrix().get(1, 3)); | |
| 405 gfx::Vector2dF last_offset( | |
| 406 last_screen_transform.matrix().get(0, 3), | |
| 407 last_screen_transform.matrix().get(1, 3)); | |
| 408 | |
| 409 for (TilingData::Iterator iter(&tiling_data_, prioritized_rect); | |
| 410 iter; ++iter) { | |
| 411 TileMap::iterator find = tiles_.find(iter.index()); | |
| 412 if (find == tiles_.end()) | |
| 413 continue; | |
| 414 Tile* tile = find->second.get(); | |
| 415 | |
| 416 gfx::Rect tile_bounds = | |
| 417 tiling_data_.TileBounds(iter.index_x(), iter.index_y()); | |
| 418 gfx::RectF current_screen_rect = gfx::ScaleRect( | |
| 419 tile_bounds, | |
| 420 current_scale, | |
| 421 current_scale) + current_offset; | |
| 422 gfx::RectF last_screen_rect = gfx::ScaleRect( | |
| 423 tile_bounds, | |
| 424 last_scale, | |
| 425 last_scale) + last_offset; | |
| 426 | |
| 427 float distance_to_visible_in_pixels = | |
| 428 TilePriority::manhattanDistance(current_screen_rect, view_rect); | |
| 429 | |
| 430 float time_to_visible_in_seconds = | |
| 431 TilePriority::TimeForBoundsToIntersect( | |
| 432 last_screen_rect, current_screen_rect, time_delta, view_rect); | |
| 433 TilePriority priority( | |
| 434 resolution_, | |
| 435 time_to_visible_in_seconds, | |
| 436 distance_to_visible_in_pixels); | |
| 437 if (store_screen_space_quads_on_tiles) | |
| 438 priority.set_current_screen_quad(gfx::QuadF(current_screen_rect)); | |
| 439 tile->SetPriority(tree, priority); | |
| 440 } | |
| 441 } else { | |
| 442 for (TilingData::Iterator iter(&tiling_data_, prioritized_rect); | |
| 443 iter; ++iter) { | |
| 444 TileMap::iterator find = tiles_.find(iter.index()); | |
| 445 if (find == tiles_.end()) | |
| 446 continue; | |
| 447 Tile* tile = find->second.get(); | |
| 448 | |
| 449 gfx::Rect tile_bounds = | |
| 450 tiling_data_.TileBounds(iter.index_x(), iter.index_y()); | |
| 451 gfx::RectF current_layer_content_rect = gfx::ScaleRect( | |
| 452 tile_bounds, | |
| 453 current_scale, | |
| 454 current_scale); | |
| 455 gfx::RectF current_screen_rect = MathUtil::MapClippedRect( | |
| 456 current_screen_transform, current_layer_content_rect); | |
| 457 gfx::RectF last_layer_content_rect = gfx::ScaleRect( | |
| 458 tile_bounds, | |
| 459 last_scale, | |
| 460 last_scale); | |
| 461 gfx::RectF last_screen_rect = MathUtil::MapClippedRect( | |
| 462 last_screen_transform, last_layer_content_rect); | |
| 463 | |
| 464 float distance_to_visible_in_pixels = | |
| 465 TilePriority::manhattanDistance(current_screen_rect, view_rect); | |
| 466 | |
| 467 float time_to_visible_in_seconds = | |
| 468 TilePriority::TimeForBoundsToIntersect( | |
| 469 last_screen_rect, current_screen_rect, time_delta, view_rect); | |
| 470 | |
| 471 TilePriority priority( | |
| 472 resolution_, | |
| 473 time_to_visible_in_seconds, | |
| 474 distance_to_visible_in_pixels); | |
| 475 if (store_screen_space_quads_on_tiles) { | |
| 476 bool clipped; | |
| 477 priority.set_current_screen_quad( | |
| 478 MathUtil::MapQuad(current_screen_transform, | |
| 479 gfx::QuadF(current_layer_content_rect), | |
| 480 &clipped)); | |
| 481 } | |
| 482 tile->SetPriority(tree, priority); | |
| 483 } | |
| 484 } | |
| 485 | |
| 486 last_source_frame_number_ = current_source_frame_number; | |
| 487 last_impl_frame_time_ = current_frame_time; | |
| 488 } | |
| 489 | |
| 490 void PictureLayerTiling::DidBecomeActive() { | |
| 491 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) { | |
| 492 it->second->SetPriority(ACTIVE_TREE, it->second->priority(PENDING_TREE)); | |
| 493 it->second->SetPriority(PENDING_TREE, TilePriority()); | |
| 494 | |
| 495 // Tile holds a ref onto a picture pile. If the tile never gets invalidated | |
| 496 // and recreated, then that picture pile ref could exist indefinitely. To | |
| 497 // prevent this, ask the client to update the pile to its own ref. This | |
| 498 // will cause PicturePileImpls and their clones to get deleted once the | |
| 499 // corresponding PictureLayerImpl and any in flight raster jobs go out of | |
| 500 // scope. | |
| 501 client_->UpdatePile(it->second); | |
| 502 } | |
| 503 } | |
| 504 | |
| 505 scoped_ptr<base::Value> PictureLayerTiling::AsValue() const { | |
| 506 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue()); | |
| 507 state->SetInteger("num_tiles", tiles_.size()); | |
| 508 state->SetDouble("content_scale", contents_scale_); | |
| 509 state->Set("content_bounds", | |
| 510 MathUtil::AsValue(ContentRect().size()).release()); | |
| 511 return state.PassAs<base::Value>(); | |
| 512 } | |
| 513 | |
| 514 namespace { | |
| 515 | |
| 516 int ComputeOffsetToExpand4EdgesEqually(int old_width, | |
| 517 int old_height, | |
| 518 int64 target_area) { | |
| 519 // We need to expand the rect in 4 directions, we can compute the | |
| 520 // amount to expand along each axis with a quadratic equation: | |
| 521 // (old_w + add) * (old_h + add) = target_area | |
| 522 // old_w * old_h + old_w * add + add * old_h + add * add = target_area | |
| 523 // add^2 + add * (old_w + old_h) - target_area + old_w * old_h = 0 | |
| 524 // Therefore, we solve the quadratic equation with: | |
| 525 // a = 1 | |
| 526 // b = old_w + old_h | |
| 527 // c = -target_area + old_w * old_h | |
| 528 int a = 1; | |
| 529 int64 b = old_width + old_height; | |
| 530 int64 c = -target_area + old_width * old_height; | |
| 531 int sqrt_part = std::sqrt(b * b - 4.0 * a * c); | |
| 532 int add_each_axis = (-b + sqrt_part) / 2 / a; | |
| 533 return add_each_axis / 2; | |
| 534 } | |
| 535 | |
| 536 int ComputeOffsetToExpand3EdgesEqually(int old_width, | |
| 537 int old_height, | |
| 538 int64 target_area, | |
| 539 bool left_complete, | |
| 540 bool top_complete, | |
| 541 bool right_complete, | |
| 542 bool bottom_complete) { | |
| 543 // We need to expand the rect in three directions, so we will have to | |
| 544 // expand along one axis twice as much as the other. Otherwise, this | |
| 545 // is very similar to the case where we expand in all 4 directions. | |
| 546 | |
| 547 if (left_complete || right_complete) { | |
| 548 // Expanding twice as much vertically as horizontally. | |
| 549 // (old_w + add) * (old_h + add*2) = target_area | |
| 550 // old_w * old_h + old_w * add*2 + add * old_h + add * add*2 = target_area | |
| 551 // (add^2)*2 + add * (old_w*2 + old_h) - target_area + old_w * old_h = 0 | |
| 552 // Therefore, we solve the quadratic equation with: | |
| 553 // a = 2 | |
| 554 // b = old_w*2 + old_h | |
| 555 // c = -target_area + old_w * old_h | |
| 556 int a = 2; | |
| 557 int64 b = old_width * 2 + old_height; | |
| 558 int64 c = -target_area + old_width * old_height; | |
| 559 int sqrt_part = std::sqrt(b * b - 4.0 * a * c); | |
| 560 int add_each_direction = (-b + sqrt_part) / 2 / a; | |
| 561 return add_each_direction; | |
| 562 } else { | |
| 563 // Expanding twice as much horizontally as vertically. | |
| 564 // (old_w + add*2) * (old_h + add) = target_area | |
| 565 // old_w * old_h + old_w * add + add*2 * old_h + add*2 * add = target_area | |
| 566 // (add^2)*2 + add * (old_w + old_h*2) - target_area + old_w * old_h = 0 | |
| 567 // Therefore, we solve the quadratic equation with: | |
| 568 // a = 2 | |
| 569 // b = old_w + old_h*2 | |
| 570 // c = -target_area + old_w * old_h | |
| 571 int a = 2; | |
| 572 int64 b = old_width + old_height * 2; | |
| 573 int64 c = -target_area + old_width * old_height; | |
| 574 int sqrt_part = std::sqrt(b * b - 4.0 * a * c); | |
| 575 int add_each_direction = (-b + sqrt_part) / 2 / a; | |
| 576 return add_each_direction; | |
| 577 } | |
| 578 } | |
| 579 | |
| 580 int ComputeOffsetToExpand2EdgesEqually(int old_width, | |
| 581 int old_height, | |
| 582 int64 target_area, | |
| 583 bool left_complete, | |
| 584 bool top_complete, | |
| 585 bool right_complete, | |
| 586 bool bottom_complete) { | |
| 587 // We need to expand the rect along two directions. If the two directions | |
| 588 // are opposite from each other then we only need to compute a distance | |
| 589 // along a single axis. | |
| 590 if (left_complete && right_complete) { | |
| 591 // Expanding along the vertical axis only: | |
| 592 // old_w * (old_h + add) = target_area | |
| 593 // old_w * old_h + old_w * add = target_area | |
| 594 // add_vertically = (target_area - old_w * old_h) / old_w | |
| 595 int add_vertically = target_area / old_width - old_height; | |
| 596 return add_vertically / 2; | |
| 597 } else if (top_complete && bottom_complete) { | |
| 598 // Expanding along the horizontal axis only: | |
| 599 // (old_w + add) * old_h = target_area | |
| 600 // old_w * old_h + add * old_h = target_area | |
| 601 // add_horizontally = (target_area - old_w * old_h) / old_h | |
| 602 int add_horizontally = target_area / old_height - old_width; | |
| 603 return add_horizontally / 2; | |
| 604 } else { | |
| 605 // If we need to expand along both horizontal and vertical axes, we can use | |
| 606 // the same result as if we were expanding all four edges. But we apply the | |
| 607 // offset computed for opposing edges to a single edge. | |
| 608 int add_each_direction = ComputeOffsetToExpand4EdgesEqually( | |
| 609 old_width, old_height, target_area); | |
| 610 return add_each_direction * 2; | |
| 611 } | |
| 612 } | |
| 613 | |
| 614 int ComputeOffsetToExpand1Edge(int old_width, | |
| 615 int old_height, | |
| 616 int64 target_area, | |
| 617 bool left_complete, | |
| 618 bool top_complete, | |
| 619 bool right_complete, | |
| 620 bool bottom_complete) { | |
| 621 // We need to expand the rect in a single direction, so we are either | |
| 622 // moving just a verical edge, or just a horizontal edge. | |
| 623 if (!top_complete || !bottom_complete) { | |
| 624 // Moving a vertical edge: | |
| 625 // old_w * (old_h + add) = target_area | |
| 626 // old_w * old_h + old_w * add = target_area | |
| 627 // add_vertically = (target_area - old_w * old_h) / old_w | |
| 628 int add_vertically = target_area / old_width - old_height; | |
| 629 return add_vertically; | |
| 630 } else { | |
| 631 // Moving a horizontal edge: | |
| 632 // (old_w + add) * old_h = target_area | |
| 633 // old_w * old_h + add * old_h = target_area | |
| 634 // add_horizontally = (target_area - old_w * old_h) / old_h | |
| 635 int add_horizontally = target_area / old_height - old_width; | |
| 636 return add_horizontally; | |
| 637 } | |
| 638 } | |
| 639 | |
| 640 } // namespace | |
| 641 | |
| 642 // static | |
| 643 gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy( | |
| 644 gfx::Rect starting_rect, | |
| 645 int64 target_area, | |
| 646 gfx::Rect bounding_rect) { | |
| 647 | |
| 648 bool left_complete = false; | |
| 649 bool top_complete = false; | |
| 650 bool right_complete = false; | |
| 651 bool bottom_complete = false; | |
| 652 int num_edges_complete = 0; | |
| 653 | |
| 654 gfx::Rect working_rect = starting_rect; | |
| 655 for (int i = 0; i < 4; ++i) { | |
| 656 if (num_edges_complete != i) | |
| 657 continue; | |
| 658 int offset_for_each_edge = 0; | |
| 659 switch (num_edges_complete) { | |
| 660 case 0: | |
| 661 offset_for_each_edge = ComputeOffsetToExpand4EdgesEqually( | |
| 662 working_rect.width(), | |
| 663 working_rect.height(), | |
| 664 target_area); | |
| 665 break; | |
| 666 case 1: | |
| 667 offset_for_each_edge = ComputeOffsetToExpand3EdgesEqually( | |
| 668 working_rect.width(), | |
| 669 working_rect.height(), | |
| 670 target_area, | |
| 671 left_complete, | |
| 672 top_complete, | |
| 673 right_complete, | |
| 674 bottom_complete); | |
| 675 break; | |
| 676 case 2: | |
| 677 offset_for_each_edge = ComputeOffsetToExpand2EdgesEqually( | |
| 678 working_rect.width(), | |
| 679 working_rect.height(), | |
| 680 target_area, | |
| 681 left_complete, | |
| 682 top_complete, | |
| 683 right_complete, | |
| 684 bottom_complete); | |
| 685 break; | |
| 686 case 3: | |
| 687 offset_for_each_edge = ComputeOffsetToExpand1Edge( | |
| 688 working_rect.width(), | |
| 689 working_rect.height(), | |
| 690 target_area, | |
| 691 left_complete, | |
| 692 top_complete, | |
| 693 right_complete, | |
| 694 bottom_complete); | |
| 695 } | |
| 696 | |
| 697 working_rect.Inset((left_complete ? 0 : -offset_for_each_edge), | |
| 698 (top_complete ? 0 : -offset_for_each_edge), | |
| 699 (right_complete ? 0 : -offset_for_each_edge), | |
| 700 (bottom_complete ? 0 : -offset_for_each_edge)); | |
| 701 | |
| 702 if (bounding_rect.Contains(working_rect)) | |
| 703 return working_rect; | |
| 704 working_rect.Intersect(bounding_rect); | |
| 705 | |
| 706 if (working_rect.x() == bounding_rect.x()) left_complete = true; | |
| 707 if (working_rect.y() == bounding_rect.y()) top_complete = true; | |
| 708 if (working_rect.right() == bounding_rect.right()) right_complete = true; | |
| 709 if (working_rect.bottom() == bounding_rect.bottom()) bottom_complete = true; | |
| 710 | |
| 711 num_edges_complete = (left_complete ? 1 : 0) + | |
| 712 (top_complete ? 1 : 0) + | |
| 713 (right_complete ? 1 : 0) + | |
| 714 (bottom_complete ? 1 : 0); | |
| 715 if (num_edges_complete == 4) | |
| 716 return working_rect; | |
| 717 } | |
| 718 | |
| 719 NOTREACHED(); | |
| 720 return starting_rect; | |
| 721 } | |
| 722 | |
| 723 } // namespace cc | |
| OLD | NEW |