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.
5 #include "cc/resources/picture_layer_tiling.h"
11 #include "base/debug/trace_event.h"
12 #include "cc/base/math_util.h"
13 #include "cc/resources/tile.h"
14 #include "cc/resources/tile_priority.h"
15 #include "ui/gfx/point_conversions.h"
16 #include "ui/gfx/rect_conversions.h"
17 #include "ui/gfx/safe_integer_conversions.h"
18 #include "ui/gfx/size_conversions.h"
23 const float kSoonBorderDistanceInScreenPixels = 312.f;
25 class TileEvictionOrder {
27 explicit TileEvictionOrder(TreePriority tree_priority)
28 : tree_priority_(tree_priority) {}
29 ~TileEvictionOrder() {}
31 bool operator()(const Tile* a, const Tile* b) {
32 const TilePriority& a_priority =
33 a->priority_for_tree_priority(tree_priority_);
34 const TilePriority& b_priority =
35 b->priority_for_tree_priority(tree_priority_);
37 if (a_priority.priority_bin == b_priority.priority_bin &&
38 a->required_for_activation() != b->required_for_activation()) {
39 return b->required_for_activation();
41 return b_priority.IsHigherPriorityThan(a_priority);
45 TreePriority tree_priority_;
49 scoped_ptr<PictureLayerTiling> PictureLayerTiling::Create(
51 const gfx::Size& layer_bounds,
52 PictureLayerTilingClient* client) {
53 return make_scoped_ptr(new PictureLayerTiling(contents_scale,
58 PictureLayerTiling::PictureLayerTiling(float contents_scale,
59 const gfx::Size& layer_bounds,
60 PictureLayerTilingClient* client)
61 : contents_scale_(contents_scale),
62 layer_bounds_(layer_bounds),
63 resolution_(NON_IDEAL_RESOLUTION),
65 tiling_data_(gfx::Size(), gfx::Rect(), true),
66 last_impl_frame_time_in_seconds_(0.0),
67 eviction_tiles_cache_valid_(false),
68 eviction_cache_tree_priority_(SAME_PRIORITY_FOR_BOTH_TREES) {
69 gfx::Size content_bounds =
70 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds, contents_scale));
71 gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
73 DCHECK(!gfx::ToFlooredSize(
74 gfx::ScaleSize(layer_bounds, contents_scale)).IsEmpty()) <<
75 "Tiling created with scale too small as contents become empty." <<
76 " Layer bounds: " << layer_bounds.ToString() <<
77 " Contents scale: " << contents_scale;
79 tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
80 tiling_data_.SetMaxTextureSize(tile_size);
83 PictureLayerTiling::~PictureLayerTiling() {
86 void PictureLayerTiling::SetClient(PictureLayerTilingClient* client) {
90 gfx::Rect PictureLayerTiling::TilingRect() const {
91 return tiling_data_.tiling_rect();
94 Tile* PictureLayerTiling::CreateTile(int i,
96 const PictureLayerTiling* twin_tiling) {
98 DCHECK(tiles_.find(key) == tiles_.end());
100 gfx::Rect paint_rect = tiling_data_.TileBoundsWithBorder(i, j);
101 gfx::Rect tile_rect = paint_rect;
102 tile_rect.set_size(tiling_data_.max_texture_size());
104 // Check our twin for a valid tile.
106 tiling_data_.max_texture_size() ==
107 twin_tiling->tiling_data_.max_texture_size()) {
108 if (Tile* candidate_tile = twin_tiling->TileAt(i, j)) {
110 gfx::ScaleToEnclosingRect(paint_rect, 1.0f / contents_scale_);
111 if (!client_->GetInvalidation()->Intersects(rect)) {
112 tiles_[key] = candidate_tile;
113 return candidate_tile;
118 // Create a new tile because our twin didn't have a valid one.
119 scoped_refptr<Tile> tile = client_->CreateTile(this, tile_rect);
125 Region PictureLayerTiling::OpaqueRegionInContentRect(
126 const gfx::Rect& content_rect) const {
127 Region opaque_region;
128 // TODO(enne): implement me
129 return opaque_region;
132 void PictureLayerTiling::SetCanUseLCDText(bool can_use_lcd_text) {
133 for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it)
134 it->second->set_can_use_lcd_text(can_use_lcd_text);
137 void PictureLayerTiling::CreateMissingTilesInLiveTilesRect() {
138 const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
139 bool include_borders = true;
140 for (TilingData::Iterator iter(
141 &tiling_data_, live_tiles_rect_, include_borders);
144 TileMapKey key = iter.index();
145 TileMap::iterator find = tiles_.find(key);
146 if (find != tiles_.end())
148 CreateTile(key.first, key.second, twin_tiling);
152 void PictureLayerTiling::SetLayerBounds(const gfx::Size& layer_bounds) {
153 if (layer_bounds_ == layer_bounds)
156 DCHECK(!layer_bounds.IsEmpty());
158 gfx::Size old_layer_bounds = layer_bounds_;
159 layer_bounds_ = layer_bounds;
160 gfx::Size content_bounds =
161 gfx::ToCeiledSize(gfx::ScaleSize(layer_bounds_, contents_scale_));
163 gfx::Size tile_size = client_->CalculateTileSize(content_bounds);
164 if (tile_size != tiling_data_.max_texture_size()) {
165 tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
166 tiling_data_.SetMaxTextureSize(tile_size);
171 // Any tiles outside our new bounds are invalid and should be dropped.
172 gfx::Rect bounded_live_tiles_rect(live_tiles_rect_);
173 bounded_live_tiles_rect.Intersect(gfx::Rect(content_bounds));
174 SetLiveTilesRect(bounded_live_tiles_rect);
175 tiling_data_.SetTilingRect(gfx::Rect(content_bounds));
177 // Create tiles for newly exposed areas.
178 Region layer_region((gfx::Rect(layer_bounds_)));
179 layer_region.Subtract(gfx::Rect(old_layer_bounds));
180 Invalidate(layer_region);
183 void PictureLayerTiling::RemoveTilesInRegion(const Region& layer_region) {
184 DoInvalidate(layer_region, false /* recreate_tiles */);
187 void PictureLayerTiling::Invalidate(const Region& layer_region) {
188 DoInvalidate(layer_region, true /* recreate_tiles */);
191 void PictureLayerTiling::DoInvalidate(const Region& layer_region,
192 bool recreate_tiles) {
193 std::vector<TileMapKey> new_tile_keys;
194 gfx::Rect expanded_live_tiles_rect(
195 tiling_data_.ExpandRectToTileBoundsWithBorders(live_tiles_rect_));
196 for (Region::Iterator iter(layer_region); iter.has_rect(); iter.next()) {
197 gfx::Rect layer_rect = iter.rect();
198 gfx::Rect content_rect =
199 gfx::ScaleToEnclosingRect(layer_rect, contents_scale_);
200 // Avoid needless work by not bothering to invalidate where there aren't
202 content_rect.Intersect(expanded_live_tiles_rect);
203 if (content_rect.IsEmpty())
205 bool include_borders = true;
206 for (TilingData::Iterator iter(
207 &tiling_data_, content_rect, include_borders);
210 TileMapKey key(iter.index());
211 TileMap::iterator find = tiles_.find(key);
212 if (find == tiles_.end())
216 new_tile_keys.push_back(key);
220 if (recreate_tiles) {
221 const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
222 for (size_t i = 0; i < new_tile_keys.size(); ++i)
223 CreateTile(new_tile_keys[i].first, new_tile_keys[i].second, twin_tiling);
227 PictureLayerTiling::CoverageIterator::CoverageIterator()
238 PictureLayerTiling::CoverageIterator::CoverageIterator(
239 const PictureLayerTiling* tiling,
241 const gfx::Rect& dest_rect)
243 dest_rect_(dest_rect),
244 dest_to_content_scale_(0),
253 if (dest_rect_.IsEmpty())
256 dest_to_content_scale_ = tiling_->contents_scale_ / dest_scale;
258 gfx::Rect content_rect =
259 gfx::ScaleToEnclosingRect(dest_rect_,
260 dest_to_content_scale_,
261 dest_to_content_scale_);
262 // IndexFromSrcCoord clamps to valid tile ranges, so it's necessary to
263 // check for non-intersection first.
264 content_rect.Intersect(tiling_->TilingRect());
265 if (content_rect.IsEmpty())
268 left_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(content_rect.x());
269 top_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(content_rect.y());
270 right_ = tiling_->tiling_data_.TileXIndexFromSrcCoord(
271 content_rect.right() - 1);
272 bottom_ = tiling_->tiling_data_.TileYIndexFromSrcCoord(
273 content_rect.bottom() - 1);
280 PictureLayerTiling::CoverageIterator::~CoverageIterator() {
283 PictureLayerTiling::CoverageIterator&
284 PictureLayerTiling::CoverageIterator::operator++() {
285 if (tile_j_ > bottom_)
288 bool first_time = tile_i_ < left_;
289 bool new_row = false;
291 if (tile_i_ > right_) {
295 if (tile_j_ > bottom_) {
296 current_tile_ = NULL;
301 current_tile_ = tiling_->TileAt(tile_i_, tile_j_);
303 // Calculate the current geometry rect. Due to floating point rounding
304 // and ToEnclosingRect, tiles might overlap in destination space on the
306 gfx::Rect last_geometry_rect = current_geometry_rect_;
308 gfx::Rect content_rect = tiling_->tiling_data_.TileBounds(tile_i_, tile_j_);
310 current_geometry_rect_ =
311 gfx::ScaleToEnclosingRect(content_rect,
312 1 / dest_to_content_scale_,
313 1 / dest_to_content_scale_);
315 current_geometry_rect_.Intersect(dest_rect_);
320 // Iteration happens left->right, top->bottom. Running off the bottom-right
321 // edge is handled by the intersection above with dest_rect_. Here we make
322 // sure that the new current geometry rect doesn't overlap with the last.
326 min_left = dest_rect_.x();
327 min_top = last_geometry_rect.bottom();
329 min_left = last_geometry_rect.right();
330 min_top = last_geometry_rect.y();
333 int inset_left = std::max(0, min_left - current_geometry_rect_.x());
334 int inset_top = std::max(0, min_top - current_geometry_rect_.y());
335 current_geometry_rect_.Inset(inset_left, inset_top, 0, 0);
338 DCHECK_EQ(last_geometry_rect.right(), current_geometry_rect_.x());
339 DCHECK_EQ(last_geometry_rect.bottom(), current_geometry_rect_.bottom());
340 DCHECK_EQ(last_geometry_rect.y(), current_geometry_rect_.y());
346 gfx::Rect PictureLayerTiling::CoverageIterator::geometry_rect() const {
347 return current_geometry_rect_;
351 PictureLayerTiling::CoverageIterator::full_tile_geometry_rect() const {
352 gfx::Rect rect = tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_);
353 rect.set_size(tiling_->tiling_data_.max_texture_size());
357 gfx::RectF PictureLayerTiling::CoverageIterator::texture_rect() const {
358 gfx::PointF tex_origin =
359 tiling_->tiling_data_.TileBoundsWithBorder(tile_i_, tile_j_).origin();
361 // Convert from dest space => content space => texture space.
362 gfx::RectF texture_rect(current_geometry_rect_);
363 texture_rect.Scale(dest_to_content_scale_,
364 dest_to_content_scale_);
365 texture_rect.Intersect(tiling_->TilingRect());
366 if (texture_rect.IsEmpty())
368 texture_rect.Offset(-tex_origin.OffsetFromOrigin());
373 gfx::Size PictureLayerTiling::CoverageIterator::texture_size() const {
374 return tiling_->tiling_data_.max_texture_size();
377 void PictureLayerTiling::Reset() {
378 live_tiles_rect_ = gfx::Rect();
382 gfx::Rect PictureLayerTiling::ComputeSkewport(
383 double current_frame_time_in_seconds,
384 const gfx::Rect& visible_rect_in_content_space) const {
385 gfx::Rect skewport = visible_rect_in_content_space;
386 if (last_impl_frame_time_in_seconds_ == 0.0)
390 current_frame_time_in_seconds - last_impl_frame_time_in_seconds_;
391 if (time_delta == 0.0)
394 float skewport_target_time_in_seconds =
395 client_->GetSkewportTargetTimeInSeconds();
396 double extrapolation_multiplier =
397 skewport_target_time_in_seconds / time_delta;
399 int old_x = last_visible_rect_in_content_space_.x();
400 int old_y = last_visible_rect_in_content_space_.y();
401 int old_right = last_visible_rect_in_content_space_.right();
402 int old_bottom = last_visible_rect_in_content_space_.bottom();
404 int new_x = visible_rect_in_content_space.x();
405 int new_y = visible_rect_in_content_space.y();
406 int new_right = visible_rect_in_content_space.right();
407 int new_bottom = visible_rect_in_content_space.bottom();
409 int skewport_limit = client_->GetSkewportExtrapolationLimitInContentPixels();
411 // Compute the maximum skewport based on |skewport_limit|.
412 gfx::Rect max_skewport = skewport;
414 -skewport_limit, -skewport_limit, -skewport_limit, -skewport_limit);
416 // Inset the skewport by the needed adjustment.
417 skewport.Inset(extrapolation_multiplier * (new_x - old_x),
418 extrapolation_multiplier * (new_y - old_y),
419 extrapolation_multiplier * (old_right - new_right),
420 extrapolation_multiplier * (old_bottom - new_bottom));
422 // Clip the skewport to |max_skewport|.
423 skewport.Intersect(max_skewport);
425 // Finally, ensure that visible rect is contained in the skewport.
426 skewport.Union(visible_rect_in_content_space);
430 void PictureLayerTiling::UpdateTilePriorities(
432 const gfx::Rect& visible_layer_rect,
433 float layer_contents_scale,
434 double current_frame_time_in_seconds) {
435 if (!NeedsUpdateForFrameAtTime(current_frame_time_in_seconds)) {
436 // This should never be zero for the purposes of has_ever_been_updated().
437 DCHECK_NE(current_frame_time_in_seconds, 0.0);
441 gfx::Rect visible_rect_in_content_space =
442 gfx::ScaleToEnclosingRect(visible_layer_rect, contents_scale_);
444 if (TilingRect().IsEmpty()) {
445 last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
446 last_visible_rect_in_content_space_ = visible_rect_in_content_space;
450 size_t max_tiles_for_interest_area = client_->GetMaxTilesForInterestArea();
452 gfx::Size tile_size = tiling_data_.max_texture_size();
453 int64 eventually_rect_area =
454 max_tiles_for_interest_area * tile_size.width() * tile_size.height();
456 gfx::Rect skewport = ComputeSkewport(current_frame_time_in_seconds,
457 visible_rect_in_content_space);
458 DCHECK(skewport.Contains(visible_rect_in_content_space));
460 gfx::Rect eventually_rect =
461 ExpandRectEquallyToAreaBoundedBy(visible_rect_in_content_space,
462 eventually_rect_area,
466 DCHECK(eventually_rect.IsEmpty() || TilingRect().Contains(eventually_rect));
468 SetLiveTilesRect(eventually_rect);
470 last_impl_frame_time_in_seconds_ = current_frame_time_in_seconds;
471 last_visible_rect_in_content_space_ = visible_rect_in_content_space;
473 current_visible_rect_in_content_space_ = visible_rect_in_content_space;
474 current_skewport_ = skewport;
475 current_eventually_rect_ = eventually_rect;
476 eviction_tiles_cache_valid_ = false;
478 TilePriority now_priority(resolution_, TilePriority::NOW, 0);
479 float content_to_screen_scale =
480 1.0f / (contents_scale_ * layer_contents_scale);
482 // Assign now priority to all visible tiles.
483 bool include_borders = true;
484 for (TilingData::Iterator iter(
485 &tiling_data_, visible_rect_in_content_space, include_borders);
488 TileMap::iterator find = tiles_.find(iter.index());
489 if (find == tiles_.end())
491 Tile* tile = find->second.get();
493 tile->SetPriority(tree, now_priority);
496 // Assign soon priority to skewport tiles.
497 for (TilingData::DifferenceIterator iter(
498 &tiling_data_, skewport, visible_rect_in_content_space);
501 TileMap::iterator find = tiles_.find(iter.index());
502 if (find == tiles_.end())
504 Tile* tile = find->second.get();
506 gfx::Rect tile_bounds =
507 tiling_data_.TileBounds(iter.index_x(), iter.index_y());
509 float distance_to_visible =
510 visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) *
511 content_to_screen_scale;
513 TilePriority priority(resolution_, TilePriority::SOON, distance_to_visible);
514 tile->SetPriority(tree, priority);
517 // Assign eventually priority to interest rect tiles.
518 for (TilingData::DifferenceIterator iter(
519 &tiling_data_, eventually_rect, skewport);
522 TileMap::iterator find = tiles_.find(iter.index());
523 if (find == tiles_.end())
525 Tile* tile = find->second.get();
527 gfx::Rect tile_bounds =
528 tiling_data_.TileBounds(iter.index_x(), iter.index_y());
530 float distance_to_visible =
531 visible_rect_in_content_space.ManhattanInternalDistance(tile_bounds) *
532 content_to_screen_scale;
533 TilePriority priority(
534 resolution_, TilePriority::EVENTUALLY, distance_to_visible);
535 tile->SetPriority(tree, priority);
538 // Upgrade the priority on border tiles to be SOON.
539 current_soon_border_rect_ = visible_rect_in_content_space;
540 float border = kSoonBorderDistanceInScreenPixels / content_to_screen_scale;
541 current_soon_border_rect_.Inset(-border, -border, -border, -border);
542 for (TilingData::DifferenceIterator iter(
543 &tiling_data_, current_soon_border_rect_, skewport);
546 TileMap::iterator find = tiles_.find(iter.index());
547 if (find == tiles_.end())
549 Tile* tile = find->second.get();
551 TilePriority priority(resolution_,
553 tile->priority(tree).distance_to_visible);
554 tile->SetPriority(tree, priority);
558 void PictureLayerTiling::SetLiveTilesRect(
559 const gfx::Rect& new_live_tiles_rect) {
560 DCHECK(new_live_tiles_rect.IsEmpty() ||
561 TilingRect().Contains(new_live_tiles_rect));
562 if (live_tiles_rect_ == new_live_tiles_rect)
565 // Iterate to delete all tiles outside of our new live_tiles rect.
566 for (TilingData::DifferenceIterator iter(&tiling_data_,
568 new_live_tiles_rect);
571 TileMapKey key(iter.index());
572 TileMap::iterator found = tiles_.find(key);
573 // If the tile was outside of the recorded region, it won't exist even
574 // though it was in the live rect.
575 if (found != tiles_.end())
579 const PictureLayerTiling* twin_tiling = client_->GetTwinTiling(this);
581 // Iterate to allocate new tiles for all regions with newly exposed area.
582 for (TilingData::DifferenceIterator iter(&tiling_data_,
587 TileMapKey key(iter.index());
588 CreateTile(key.first, key.second, twin_tiling);
591 live_tiles_rect_ = new_live_tiles_rect;
594 void PictureLayerTiling::DidBecomeRecycled() {
595 // DidBecomeActive below will set the active priority for tiles that are
596 // still in the tree. Calling this first on an active tiling that is becoming
597 // recycled takes care of tiles that are no longer in the active tree (eg.
598 // due to a pending invalidation).
599 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
600 it->second->SetPriority(ACTIVE_TREE, TilePriority());
604 void PictureLayerTiling::DidBecomeActive() {
605 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
606 it->second->SetPriority(ACTIVE_TREE, it->second->priority(PENDING_TREE));
607 it->second->SetPriority(PENDING_TREE, TilePriority());
609 // Tile holds a ref onto a picture pile. If the tile never gets invalidated
610 // and recreated, then that picture pile ref could exist indefinitely. To
611 // prevent this, ask the client to update the pile to its own ref. This
612 // will cause PicturePileImpls and their clones to get deleted once the
613 // corresponding PictureLayerImpl and any in flight raster jobs go out of
615 client_->UpdatePile(it->second.get());
619 void PictureLayerTiling::UpdateTilesToCurrentPile() {
620 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
621 client_->UpdatePile(it->second.get());
625 scoped_ptr<base::Value> PictureLayerTiling::AsValue() const {
626 scoped_ptr<base::DictionaryValue> state(new base::DictionaryValue());
627 state->SetInteger("num_tiles", tiles_.size());
628 state->SetDouble("content_scale", contents_scale_);
629 state->Set("tiling_rect", MathUtil::AsValue(TilingRect()).release());
630 return state.PassAs<base::Value>();
633 size_t PictureLayerTiling::GPUMemoryUsageInBytes() const {
635 for (TileMap::const_iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
636 const Tile* tile = it->second.get();
637 amount += tile->GPUMemoryUsageInBytes();
642 PictureLayerTiling::RectExpansionCache::RectExpansionCache()
643 : previous_target(0) {
648 // This struct represents an event at which the expending rect intersects
649 // one of its boundaries. 4 intersection events will occur during expansion.
651 enum { BOTTOM, TOP, LEFT, RIGHT } edge;
656 // Compute the delta to expand from edges to cover target_area.
657 int ComputeExpansionDelta(int num_x_edges, int num_y_edges,
658 int width, int height,
660 // Compute coefficients for the quadratic equation:
661 // a*x^2 + b*x + c = 0
662 int a = num_y_edges * num_x_edges;
663 int b = num_y_edges * width + num_x_edges * height;
664 int64 c = static_cast<int64>(width) * height - target_area;
666 // Compute the delta for our edges using the quadratic equation.
667 return a == 0 ? -c / b :
668 (-b + static_cast<int>(
669 std::sqrt(static_cast<int64>(b) * b - 4.0 * a * c))) / (2 * a);
674 gfx::Rect PictureLayerTiling::ExpandRectEquallyToAreaBoundedBy(
675 const gfx::Rect& starting_rect,
677 const gfx::Rect& bounding_rect,
678 RectExpansionCache* cache) {
679 if (starting_rect.IsEmpty())
680 return starting_rect;
683 cache->previous_start == starting_rect &&
684 cache->previous_bounds == bounding_rect &&
685 cache->previous_target == target_area)
686 return cache->previous_result;
689 cache->previous_start = starting_rect;
690 cache->previous_bounds = bounding_rect;
691 cache->previous_target = target_area;
694 DCHECK(!bounding_rect.IsEmpty());
695 DCHECK_GT(target_area, 0);
697 // Expand the starting rect to cover target_area, if it is smaller than it.
698 int delta = ComputeExpansionDelta(
699 2, 2, starting_rect.width(), starting_rect.height(), target_area);
700 gfx::Rect expanded_starting_rect = starting_rect;
702 expanded_starting_rect.Inset(-delta, -delta);
704 gfx::Rect rect = IntersectRects(expanded_starting_rect, bounding_rect);
705 if (rect.IsEmpty()) {
706 // The starting_rect and bounding_rect are far away.
708 cache->previous_result = rect;
711 if (delta >= 0 && rect == expanded_starting_rect) {
712 // The starting rect already covers the entire bounding_rect and isn't too
713 // large for the target_area.
715 cache->previous_result = rect;
719 // Continue to expand/shrink rect to let it cover target_area.
721 // These values will be updated by the loop and uses as the output.
722 int origin_x = rect.x();
723 int origin_y = rect.y();
724 int width = rect.width();
725 int height = rect.height();
727 // In the beginning we will consider 2 edges in each dimension.
731 // Create an event list.
732 EdgeEvent events[] = {
733 { EdgeEvent::BOTTOM, &num_y_edges, rect.y() - bounding_rect.y() },
734 { EdgeEvent::TOP, &num_y_edges, bounding_rect.bottom() - rect.bottom() },
735 { EdgeEvent::LEFT, &num_x_edges, rect.x() - bounding_rect.x() },
736 { EdgeEvent::RIGHT, &num_x_edges, bounding_rect.right() - rect.right() }
739 // Sort the events by distance (closest first).
740 if (events[0].distance > events[1].distance) std::swap(events[0], events[1]);
741 if (events[2].distance > events[3].distance) std::swap(events[2], events[3]);
742 if (events[0].distance > events[2].distance) std::swap(events[0], events[2]);
743 if (events[1].distance > events[3].distance) std::swap(events[1], events[3]);
744 if (events[1].distance > events[2].distance) std::swap(events[1], events[2]);
746 for (int event_index = 0; event_index < 4; event_index++) {
747 const EdgeEvent& event = events[event_index];
749 int delta = ComputeExpansionDelta(
750 num_x_edges, num_y_edges, width, height, target_area);
752 // Clamp delta to our event distance.
753 if (delta > event.distance)
754 delta = event.distance;
756 // Adjust the edge count for this kind of edge.
759 // Apply the delta to the edges and edge events.
760 for (int i = event_index; i < 4; i++) {
761 switch (events[i].edge) {
762 case EdgeEvent::BOTTOM:
769 case EdgeEvent::LEFT:
773 case EdgeEvent::RIGHT:
777 events[i].distance -= delta;
780 // If our delta is less then our event distance, we're done.
781 if (delta < event.distance)
785 gfx::Rect result(origin_x, origin_y, width, height);
787 cache->previous_result = result;
791 void PictureLayerTiling::UpdateEvictionCacheIfNeeded(
792 TreePriority tree_priority) {
793 if (eviction_tiles_cache_valid_ &&
794 eviction_cache_tree_priority_ == tree_priority)
797 eviction_tiles_cache_.clear();
798 eviction_tiles_cache_.reserve(tiles_.size());
799 for (TileMap::iterator it = tiles_.begin(); it != tiles_.end(); ++it) {
800 // TODO(vmpstr): This should update the priority if UpdateTilePriorities
801 // changes not to do this.
802 eviction_tiles_cache_.push_back(it->second);
805 std::sort(eviction_tiles_cache_.begin(),
806 eviction_tiles_cache_.end(),
807 TileEvictionOrder(tree_priority));
808 eviction_tiles_cache_valid_ = true;
809 eviction_cache_tree_priority_ = tree_priority;
812 PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator()
813 : tiling_(NULL), current_tile_(NULL) {}
815 PictureLayerTiling::TilingRasterTileIterator::TilingRasterTileIterator(
816 PictureLayerTiling* tiling,
819 type_(TilePriority::NOW),
820 visible_rect_in_content_space_(
821 tiling_->current_visible_rect_in_content_space_),
822 skewport_in_content_space_(tiling_->current_skewport_),
823 eventually_rect_in_content_space_(tiling_->current_eventually_rect_),
824 soon_border_rect_in_content_space_(tiling_->current_soon_border_rect_),
827 visible_iterator_(&tiling->tiling_data_,
828 visible_rect_in_content_space_,
829 true /* include_borders */),
830 spiral_iterator_(&tiling->tiling_data_,
831 skewport_in_content_space_,
832 visible_rect_in_content_space_,
833 visible_rect_in_content_space_),
834 skewport_processed_(false) {
835 if (!visible_iterator_) {
841 tiling_->TileAt(visible_iterator_.index_x(), visible_iterator_.index_y());
842 if (!current_tile_ || !TileNeedsRaster(current_tile_))
846 PictureLayerTiling::TilingRasterTileIterator::~TilingRasterTileIterator() {}
848 void PictureLayerTiling::TilingRasterTileIterator::AdvancePhase() {
849 DCHECK_LT(type_, TilePriority::EVENTUALLY);
852 type_ = static_cast<TilePriority::PriorityBin>(type_ + 1);
853 if (type_ == TilePriority::EVENTUALLY) {
854 spiral_iterator_ = TilingData::SpiralDifferenceIterator(
855 &tiling_->tiling_data_,
856 eventually_rect_in_content_space_,
857 skewport_in_content_space_,
858 visible_rect_in_content_space_);
861 while (spiral_iterator_) {
862 current_tile_ = tiling_->TileAt(spiral_iterator_.index_x(),
863 spiral_iterator_.index_y());
864 if (current_tile_ && TileNeedsRaster(current_tile_))
869 if (!spiral_iterator_ && type_ == TilePriority::EVENTUALLY)
871 } while (!spiral_iterator_);
874 PictureLayerTiling::TilingRasterTileIterator&
875 PictureLayerTiling::TilingRasterTileIterator::
877 current_tile_ = NULL;
878 while (!current_tile_ || !TileNeedsRaster(current_tile_)) {
879 std::pair<int, int> next_index;
881 case TilePriority::NOW:
883 if (!visible_iterator_) {
887 next_index = visible_iterator_.index();
889 case TilePriority::SOON:
891 if (!spiral_iterator_) {
892 if (skewport_processed_) {
896 skewport_processed_ = true;
897 spiral_iterator_ = TilingData::SpiralDifferenceIterator(
898 &tiling_->tiling_data_,
899 soon_border_rect_in_content_space_,
900 skewport_in_content_space_,
901 visible_rect_in_content_space_);
902 if (!spiral_iterator_) {
907 next_index = spiral_iterator_.index();
909 case TilePriority::EVENTUALLY:
911 if (!spiral_iterator_)
913 next_index = spiral_iterator_.index();
916 current_tile_ = tiling_->TileAt(next_index.first, next_index.second);
921 PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator()
922 : is_valid_(false), tiling_(NULL) {}
924 PictureLayerTiling::TilingEvictionTileIterator::TilingEvictionTileIterator(
925 PictureLayerTiling* tiling,
926 TreePriority tree_priority)
927 : is_valid_(false), tiling_(tiling), tree_priority_(tree_priority) {}
929 PictureLayerTiling::TilingEvictionTileIterator::~TilingEvictionTileIterator() {}
931 PictureLayerTiling::TilingEvictionTileIterator::operator bool() {
935 return IsValid() && tile_iterator_ != tiling_->eviction_tiles_cache_.end();
938 Tile* PictureLayerTiling::TilingEvictionTileIterator::operator*() {
943 return *tile_iterator_;
946 PictureLayerTiling::TilingEvictionTileIterator&
947 PictureLayerTiling::TilingEvictionTileIterator::
952 } while (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
953 (!(*tile_iterator_)->HasResources()));
958 void PictureLayerTiling::TilingEvictionTileIterator::Initialize() {
962 tiling_->UpdateEvictionCacheIfNeeded(tree_priority_);
963 tile_iterator_ = tiling_->eviction_tiles_cache_.begin();
965 if (tile_iterator_ != tiling_->eviction_tiles_cache_.end() &&
966 !(*tile_iterator_)->HasResources()) {