Use multiline attribute to check for IA2_STATE_MULTILINE.
[chromium-blink-merge.git] / cc / layers / tiled_layer.cc
blob55143befe9305b55ef351dd7f7ae7d2ce77ce233
1 // Copyright 2011 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/layers/tiled_layer.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/auto_reset.h"
11 #include "base/basictypes.h"
12 #include "build/build_config.h"
13 #include "cc/base/simple_enclosed_region.h"
14 #include "cc/layers/layer_impl.h"
15 #include "cc/layers/tiled_layer_impl.h"
16 #include "cc/resources/layer_updater.h"
17 #include "cc/resources/prioritized_resource.h"
18 #include "cc/resources/priority_calculator.h"
19 #include "cc/trees/layer_tree_host.h"
20 #include "cc/trees/occlusion_tracker.h"
21 #include "ui/gfx/geometry/rect_conversions.h"
23 namespace cc {
25 // Maximum predictive expansion of the visible area.
26 static const int kMaxPredictiveTilesCount = 2;
28 // Number of rows/columns of tiles to pre-paint.
29 // We should increase these further as all textures are
30 // prioritized and we insure performance doesn't suffer.
31 static const int kPrepaintRows = 4;
32 static const int kPrepaintColumns = 2;
34 class UpdatableTile : public LayerTilingData::Tile {
35 public:
36 static scoped_ptr<UpdatableTile> Create(
37 scoped_ptr<LayerUpdater::Resource> updater_resource) {
38 return make_scoped_ptr(new UpdatableTile(updater_resource.Pass()));
41 LayerUpdater::Resource* updater_resource() { return updater_resource_.get(); }
42 PrioritizedResource* managed_resource() {
43 return updater_resource_->texture();
46 bool is_dirty() const { return !dirty_rect.IsEmpty(); }
48 // Reset update state for the current frame. This should occur before painting
49 // for all layers. Since painting one layer can invalidate another layer after
50 // it has already painted, mark all non-dirty tiles as valid before painting
51 // such that invalidations during painting won't prevent them from being
52 // pushed.
53 void ResetUpdateState() {
54 update_rect = gfx::Rect();
55 occluded = false;
56 partial_update = false;
57 valid_for_frame = !is_dirty();
60 // This promises to update the tile and therefore also guarantees the tile
61 // will be valid for this frame. dirty_rect is copied into update_rect so we
62 // can continue to track re-entrant invalidations that occur during painting.
63 void MarkForUpdate() {
64 valid_for_frame = true;
65 update_rect = dirty_rect;
66 dirty_rect = gfx::Rect();
69 gfx::Rect dirty_rect;
70 gfx::Rect update_rect;
71 bool partial_update;
72 bool valid_for_frame;
73 bool occluded;
75 private:
76 explicit UpdatableTile(scoped_ptr<LayerUpdater::Resource> updater_resource)
77 : partial_update(false),
78 valid_for_frame(false),
79 occluded(false),
80 updater_resource_(updater_resource.Pass()) {}
82 scoped_ptr<LayerUpdater::Resource> updater_resource_;
84 DISALLOW_COPY_AND_ASSIGN(UpdatableTile);
87 TiledLayer::TiledLayer()
88 : ContentsScalingLayer(),
89 texture_format_(RGBA_8888),
90 skips_draw_(false),
91 failed_update_(false),
92 tiling_option_(AUTO_TILE) {
93 tiler_ =
94 LayerTilingData::Create(gfx::Size(), LayerTilingData::HAS_BORDER_TEXELS);
97 TiledLayer::~TiledLayer() {}
99 scoped_ptr<LayerImpl> TiledLayer::CreateLayerImpl(LayerTreeImpl* tree_impl) {
100 return TiledLayerImpl::Create(tree_impl, id());
103 void TiledLayer::UpdateTileSizeAndTilingOption() {
104 DCHECK(layer_tree_host());
106 gfx::Size default_tile_size = layer_tree_host()->settings().default_tile_size;
107 gfx::Size max_untiled_layer_size =
108 layer_tree_host()->settings().max_untiled_layer_size;
109 int layer_width = content_bounds().width();
110 int layer_height = content_bounds().height();
112 gfx::Size tile_size(std::min(default_tile_size.width(), layer_width),
113 std::min(default_tile_size.height(), layer_height));
115 // Tile if both dimensions large, or any one dimension large and the other
116 // extends into a second tile but the total layer area isn't larger than that
117 // of the largest possible untiled layer. This heuristic allows for long
118 // skinny layers (e.g. scrollbars) that are Nx1 tiles to minimize wasted
119 // texture space but still avoids creating very large tiles.
120 bool any_dimension_large = layer_width > max_untiled_layer_size.width() ||
121 layer_height > max_untiled_layer_size.height();
122 bool any_dimension_one_tile =
123 (layer_width <= default_tile_size.width() ||
124 layer_height <= default_tile_size.height()) &&
125 (layer_width * layer_height) <= (max_untiled_layer_size.width() *
126 max_untiled_layer_size.height());
127 bool auto_tiled = any_dimension_large && !any_dimension_one_tile;
129 bool is_tiled;
130 if (tiling_option_ == ALWAYS_TILE)
131 is_tiled = true;
132 else if (tiling_option_ == NEVER_TILE)
133 is_tiled = false;
134 else
135 is_tiled = auto_tiled;
137 gfx::Size requested_size = is_tiled ? tile_size : content_bounds();
138 const int max_size =
139 layer_tree_host()->GetRendererCapabilities().max_texture_size;
140 requested_size.SetToMin(gfx::Size(max_size, max_size));
141 SetTileSize(requested_size);
144 void TiledLayer::UpdateBounds() {
145 gfx::Size old_tiling_size = tiler_->tiling_size();
146 gfx::Size new_tiling_size = content_bounds();
147 if (old_tiling_size == new_tiling_size)
148 return;
149 tiler_->SetTilingSize(new_tiling_size);
151 // Invalidate any areas that the new bounds exposes.
152 Region new_region =
153 SubtractRegions(gfx::Rect(new_tiling_size), gfx::Rect(old_tiling_size));
154 for (Region::Iterator new_rects(new_region); new_rects.has_rect();
155 new_rects.next())
156 InvalidateContentRect(new_rects.rect());
157 UpdateDrawsContent(HasDrawableContent());
160 void TiledLayer::SetTileSize(const gfx::Size& size) {
161 tiler_->SetTileSize(size);
162 UpdateDrawsContent(HasDrawableContent());
165 void TiledLayer::SetBorderTexelOption(
166 LayerTilingData::BorderTexelOption border_texel_option) {
167 tiler_->SetBorderTexelOption(border_texel_option);
168 UpdateDrawsContent(HasDrawableContent());
171 bool TiledLayer::HasDrawableContent() const {
172 bool has_more_than_one_tile =
173 (tiler_->num_tiles_x() > 1) || (tiler_->num_tiles_y() > 1);
175 return !(tiling_option_ == NEVER_TILE && has_more_than_one_tile) &&
176 ContentsScalingLayer::HasDrawableContent();
179 void TiledLayer::ReduceMemoryUsage() {
180 if (Updater())
181 Updater()->ReduceMemoryUsage();
184 void TiledLayer::SetIsMask(bool is_mask) {
185 set_tiling_option(is_mask ? NEVER_TILE : AUTO_TILE);
188 void TiledLayer::PushPropertiesTo(LayerImpl* layer) {
189 ContentsScalingLayer::PushPropertiesTo(layer);
191 TiledLayerImpl* tiled_layer = static_cast<TiledLayerImpl*>(layer);
193 tiled_layer->set_skips_draw(skips_draw_);
194 tiled_layer->SetTilingData(*tiler_);
195 std::vector<UpdatableTile*> invalid_tiles;
197 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
198 iter != tiler_->tiles().end();
199 ++iter) {
200 int i = iter->first.first;
201 int j = iter->first.second;
202 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
203 // TODO(enne): This should not ever be null.
204 if (!tile)
205 continue;
207 if (!tile->managed_resource()->have_backing_texture()) {
208 // Evicted tiles get deleted from both layers
209 invalid_tiles.push_back(tile);
210 continue;
213 if (!tile->valid_for_frame) {
214 // Invalidated tiles are set so they can get different debug colors.
215 tiled_layer->PushInvalidTile(i, j);
216 continue;
219 tiled_layer->PushTileProperties(
222 tile->managed_resource()->resource_id(),
223 tile->managed_resource()->contents_swizzled());
225 for (std::vector<UpdatableTile*>::const_iterator iter = invalid_tiles.begin();
226 iter != invalid_tiles.end();
227 ++iter)
228 tiler_->TakeTile((*iter)->i(), (*iter)->j());
230 // TiledLayer must push properties every frame, since viewport state and
231 // occlusion from anywhere in the tree can change what the layer decides to
232 // push to the impl tree.
233 needs_push_properties_ = true;
236 PrioritizedResourceManager* TiledLayer::ResourceManager() {
237 if (!layer_tree_host())
238 return nullptr;
239 return layer_tree_host()->contents_texture_manager();
242 const PrioritizedResource* TiledLayer::ResourceAtForTesting(int i,
243 int j) const {
244 UpdatableTile* tile = TileAt(i, j);
245 if (!tile)
246 return nullptr;
247 return tile->managed_resource();
250 void TiledLayer::SetLayerTreeHost(LayerTreeHost* host) {
251 if (host && host != layer_tree_host()) {
252 for (LayerTilingData::TileMap::const_iterator
253 iter = tiler_->tiles().begin();
254 iter != tiler_->tiles().end();
255 ++iter) {
256 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
257 // TODO(enne): This should not ever be null.
258 if (!tile)
259 continue;
260 tile->managed_resource()->SetTextureManager(
261 host->contents_texture_manager());
264 ContentsScalingLayer::SetLayerTreeHost(host);
267 UpdatableTile* TiledLayer::TileAt(int i, int j) const {
268 return static_cast<UpdatableTile*>(tiler_->TileAt(i, j));
271 UpdatableTile* TiledLayer::CreateTile(int i, int j) {
272 CreateUpdaterIfNeeded();
274 scoped_ptr<UpdatableTile> tile(
275 UpdatableTile::Create(Updater()->CreateResource(ResourceManager())));
276 tile->managed_resource()->SetDimensions(tiler_->tile_size(), texture_format_);
278 UpdatableTile* added_tile = tile.get();
279 tiler_->AddTile(tile.Pass(), i, j);
281 added_tile->dirty_rect = tiler_->TileRect(added_tile);
283 // Temporary diagnostic crash.
284 CHECK(added_tile);
285 CHECK(TileAt(i, j));
287 return added_tile;
290 void TiledLayer::SetNeedsDisplayRect(const gfx::Rect& dirty_rect) {
291 InvalidateContentRect(LayerRectToContentRect(dirty_rect));
292 ContentsScalingLayer::SetNeedsDisplayRect(dirty_rect);
295 void TiledLayer::InvalidateContentRect(const gfx::Rect& content_rect) {
296 UpdateBounds();
297 if (tiler_->is_empty() || content_rect.IsEmpty() || skips_draw_)
298 return;
300 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
301 iter != tiler_->tiles().end();
302 ++iter) {
303 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
304 DCHECK(tile);
305 // TODO(enne): This should not ever be null.
306 if (!tile)
307 continue;
308 gfx::Rect bound = tiler_->TileRect(tile);
309 bound.Intersect(content_rect);
310 tile->dirty_rect.Union(bound);
314 // Returns true if tile is dirty and only part of it needs to be updated.
315 bool TiledLayer::TileOnlyNeedsPartialUpdate(UpdatableTile* tile) {
316 return !tile->dirty_rect.Contains(tiler_->TileRect(tile)) &&
317 tile->managed_resource()->have_backing_texture();
320 bool TiledLayer::UpdateTiles(int left,
321 int top,
322 int right,
323 int bottom,
324 ResourceUpdateQueue* queue,
325 const OcclusionTracker<Layer>* occlusion,
326 bool* updated) {
327 CreateUpdaterIfNeeded();
329 bool ignore_occlusions = !occlusion;
330 if (!HaveTexturesForTiles(left, top, right, bottom, ignore_occlusions)) {
331 failed_update_ = true;
332 return false;
335 gfx::Rect update_rect;
336 gfx::Rect paint_rect;
337 MarkTilesForUpdate(
338 &update_rect, &paint_rect, left, top, right, bottom, ignore_occlusions);
340 if (paint_rect.IsEmpty())
341 return true;
343 *updated = true;
344 UpdateTileTextures(
345 update_rect, paint_rect, left, top, right, bottom, queue, occlusion);
346 return true;
349 void TiledLayer::MarkOcclusionsAndRequestTextures(
350 int left,
351 int top,
352 int right,
353 int bottom,
354 const OcclusionTracker<Layer>* occlusion) {
355 int occluded_tile_count = 0;
356 bool succeeded = true;
357 for (int j = top; j <= bottom; ++j) {
358 for (int i = left; i <= right; ++i) {
359 UpdatableTile* tile = TileAt(i, j);
360 DCHECK(tile); // Did SetTexturePriorities get skipped?
361 // TODO(enne): This should not ever be null.
362 if (!tile)
363 continue;
364 // Did ResetUpdateState get skipped? Are we doing more than one occlusion
365 // pass?
366 DCHECK(!tile->occluded);
367 gfx::Rect visible_tile_rect = gfx::IntersectRects(
368 tiler_->tile_bounds(i, j), visible_content_rect());
369 if (!draw_transform_is_animating() && occlusion &&
370 occlusion->GetCurrentOcclusionForLayer(draw_transform())
371 .IsOccluded(visible_tile_rect)) {
372 tile->occluded = true;
373 occluded_tile_count++;
374 } else {
375 succeeded &= tile->managed_resource()->RequestLate();
381 bool TiledLayer::HaveTexturesForTiles(int left,
382 int top,
383 int right,
384 int bottom,
385 bool ignore_occlusions) {
386 for (int j = top; j <= bottom; ++j) {
387 for (int i = left; i <= right; ++i) {
388 UpdatableTile* tile = TileAt(i, j);
389 DCHECK(tile); // Did SetTexturePriorites get skipped?
390 // TODO(enne): This should not ever be null.
391 if (!tile)
392 continue;
394 // Ensure the entire tile is dirty if we don't have the texture.
395 if (!tile->managed_resource()->have_backing_texture())
396 tile->dirty_rect = tiler_->TileRect(tile);
398 // If using occlusion and the visible region of the tile is occluded,
399 // don't reserve a texture or update the tile.
400 if (tile->occluded && !ignore_occlusions)
401 continue;
403 if (!tile->managed_resource()->can_acquire_backing_texture())
404 return false;
407 return true;
410 void TiledLayer::MarkTilesForUpdate(gfx::Rect* update_rect,
411 gfx::Rect* paint_rect,
412 int left,
413 int top,
414 int right,
415 int bottom,
416 bool ignore_occlusions) {
417 for (int j = top; j <= bottom; ++j) {
418 for (int i = left; i <= right; ++i) {
419 UpdatableTile* tile = TileAt(i, j);
420 DCHECK(tile); // Did SetTexturePriorites get skipped?
421 // TODO(enne): This should not ever be null.
422 if (!tile)
423 continue;
424 if (tile->occluded && !ignore_occlusions)
425 continue;
427 // Prepare update rect from original dirty rects.
428 update_rect->Union(tile->dirty_rect);
430 // TODO(reveman): Decide if partial update should be allowed based on cost
431 // of update. https://bugs.webkit.org/show_bug.cgi?id=77376
432 if (tile->is_dirty() &&
433 !layer_tree_host()->AlwaysUsePartialTextureUpdates()) {
434 // If we get a partial update, we use the same texture, otherwise return
435 // the current texture backing, so we don't update visible textures
436 // non-atomically. If the current backing is in-use, it won't be
437 // deleted until after the commit as the texture manager will not allow
438 // deletion or recycling of in-use textures.
439 if (TileOnlyNeedsPartialUpdate(tile) &&
440 layer_tree_host()->RequestPartialTextureUpdate()) {
441 tile->partial_update = true;
442 } else {
443 tile->dirty_rect = tiler_->TileRect(tile);
444 tile->managed_resource()->ReturnBackingTexture();
448 paint_rect->Union(tile->dirty_rect);
449 tile->MarkForUpdate();
454 void TiledLayer::UpdateTileTextures(const gfx::Rect& update_rect,
455 const gfx::Rect& paint_rect,
456 int left,
457 int top,
458 int right,
459 int bottom,
460 ResourceUpdateQueue* queue,
461 const OcclusionTracker<Layer>* occlusion) {
462 // The update_rect should be in layer space. So we have to convert the
463 // paint_rect from content space to layer space.
464 float width_scale = 1 / draw_properties().contents_scale_x;
465 float height_scale = 1 / draw_properties().contents_scale_y;
466 update_rect_ =
467 gfx::ScaleToEnclosingRect(update_rect, width_scale, height_scale);
469 // Calling PrepareToUpdate() calls into WebKit to paint, which may have the
470 // side effect of disabling compositing, which causes our reference to the
471 // texture updater to be deleted. However, we can't free the memory backing
472 // the SkCanvas until the paint finishes, so we grab a local reference here to
473 // hold the updater alive until the paint completes.
474 scoped_refptr<LayerUpdater> protector(Updater());
475 Updater()->PrepareToUpdate(content_bounds(),
476 paint_rect,
477 tiler_->tile_size(),
478 1.f / width_scale,
479 1.f / height_scale);
481 for (int j = top; j <= bottom; ++j) {
482 for (int i = left; i <= right; ++i) {
483 UpdatableTile* tile = TileAt(i, j);
484 DCHECK(tile); // Did SetTexturePriorites get skipped?
485 // TODO(enne): This should not ever be null.
486 if (!tile)
487 continue;
489 gfx::Rect tile_rect = tiler_->tile_bounds(i, j);
491 // Use update_rect as the above loop copied the dirty rect for this frame
492 // to update_rect.
493 gfx::Rect dirty_rect = tile->update_rect;
494 if (dirty_rect.IsEmpty())
495 continue;
497 // source_rect starts as a full-sized tile with border texels included.
498 gfx::Rect source_rect = tiler_->TileRect(tile);
499 source_rect.Intersect(dirty_rect);
500 // Paint rect not guaranteed to line up on tile boundaries, so
501 // make sure that source_rect doesn't extend outside of it.
502 source_rect.Intersect(paint_rect);
504 tile->update_rect = source_rect;
506 if (source_rect.IsEmpty())
507 continue;
509 const gfx::Point anchor = tiler_->TileRect(tile).origin();
511 // Calculate tile-space rectangle to upload into.
512 gfx::Vector2d dest_offset = source_rect.origin() - anchor;
513 CHECK_GE(dest_offset.x(), 0);
514 CHECK_GE(dest_offset.y(), 0);
516 // Offset from paint rectangle to this tile's dirty rectangle.
517 gfx::Vector2d paint_offset = source_rect.origin() - paint_rect.origin();
518 CHECK_GE(paint_offset.x(), 0);
519 CHECK_GE(paint_offset.y(), 0);
520 CHECK_LE(paint_offset.x() + source_rect.width(), paint_rect.width());
521 CHECK_LE(paint_offset.y() + source_rect.height(), paint_rect.height());
523 tile->updater_resource()->Update(
524 queue, source_rect, dest_offset, tile->partial_update);
529 // This picks a small animated layer to be anything less than one viewport. This
530 // is specifically for page transitions which are viewport-sized layers. The
531 // extra tile of padding is due to these layers being slightly larger than the
532 // viewport in some cases.
533 bool TiledLayer::IsSmallAnimatedLayer() const {
534 if (!draw_transform_is_animating() && !screen_space_transform_is_animating())
535 return false;
536 gfx::Size viewport_size =
537 layer_tree_host() ? layer_tree_host()->device_viewport_size()
538 : gfx::Size();
539 gfx::Rect content_rect(content_bounds());
540 return content_rect.width() <=
541 viewport_size.width() + tiler_->tile_size().width() &&
542 content_rect.height() <=
543 viewport_size.height() + tiler_->tile_size().height();
546 namespace {
547 // TODO(epenner): Remove this and make this based on distance once distance can
548 // be calculated for offscreen layers. For now, prioritize all small animated
549 // layers after 512 pixels of pre-painting.
550 void SetPriorityForTexture(const gfx::Rect& visible_rect,
551 const gfx::Rect& tile_rect,
552 bool draws_to_root,
553 bool is_small_animated_layer,
554 PrioritizedResource* texture) {
555 int priority = PriorityCalculator::LowestPriority();
556 if (!visible_rect.IsEmpty()) {
557 priority = PriorityCalculator::PriorityFromDistance(
558 visible_rect, tile_rect, draws_to_root);
561 if (is_small_animated_layer) {
562 priority = PriorityCalculator::max_priority(
563 priority, PriorityCalculator::SmallAnimatedLayerMinPriority());
566 if (priority != PriorityCalculator::LowestPriority())
567 texture->set_request_priority(priority);
569 } // namespace
571 void TiledLayer::SetTexturePriorities(const PriorityCalculator& priority_calc) {
572 UpdateBounds();
573 ResetUpdateState();
574 UpdateScrollPrediction();
576 if (tiler_->has_empty_bounds())
577 return;
579 bool draws_to_root = !render_target()->parent();
580 bool small_animated_layer = IsSmallAnimatedLayer();
582 // Minimally create the tiles in the desired pre-paint rect.
583 gfx::Rect create_tiles_rect = IdlePaintRect();
584 if (small_animated_layer)
585 create_tiles_rect = gfx::Rect(content_bounds());
586 if (!create_tiles_rect.IsEmpty()) {
587 int left, top, right, bottom;
588 tiler_->ContentRectToTileIndices(
589 create_tiles_rect, &left, &top, &right, &bottom);
590 for (int j = top; j <= bottom; ++j) {
591 for (int i = left; i <= right; ++i) {
592 if (!TileAt(i, j))
593 CreateTile(i, j);
598 // Now update priorities on all tiles we have in the layer, no matter where
599 // they are.
600 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
601 iter != tiler_->tiles().end();
602 ++iter) {
603 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
604 // TODO(enne): This should not ever be null.
605 if (!tile)
606 continue;
607 gfx::Rect tile_rect = tiler_->TileRect(tile);
608 SetPriorityForTexture(predicted_visible_rect_,
609 tile_rect,
610 draws_to_root,
611 small_animated_layer,
612 tile->managed_resource());
616 SimpleEnclosedRegion TiledLayer::VisibleContentOpaqueRegion() const {
617 if (skips_draw_)
618 return SimpleEnclosedRegion();
619 return Layer::VisibleContentOpaqueRegion();
622 void TiledLayer::ResetUpdateState() {
623 skips_draw_ = false;
624 failed_update_ = false;
626 LayerTilingData::TileMap::const_iterator end = tiler_->tiles().end();
627 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
628 iter != end;
629 ++iter) {
630 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
631 // TODO(enne): This should not ever be null.
632 if (!tile)
633 continue;
634 tile->ResetUpdateState();
638 namespace {
639 gfx::Rect ExpandRectByDelta(const gfx::Rect& rect, const gfx::Vector2d& delta) {
640 int width = rect.width() + std::abs(delta.x());
641 int height = rect.height() + std::abs(delta.y());
642 int x = rect.x() + ((delta.x() < 0) ? delta.x() : 0);
643 int y = rect.y() + ((delta.y() < 0) ? delta.y() : 0);
644 return gfx::Rect(x, y, width, height);
648 void TiledLayer::UpdateScrollPrediction() {
649 // This scroll prediction is very primitive and should be replaced by a
650 // a recursive calculation on all layers which uses actual scroll/animation
651 // velocities. To insure this doesn't miss-predict, we only use it to predict
652 // the visible_rect if:
653 // - content_bounds() hasn't changed.
654 // - visible_rect.size() hasn't changed.
655 // These two conditions prevent rotations, scales, pinch-zooms etc. where
656 // the prediction would be incorrect.
657 gfx::Vector2d delta = visible_content_rect().CenterPoint() -
658 previous_visible_rect_.CenterPoint();
659 predicted_scroll_ = -delta;
660 predicted_visible_rect_ = visible_content_rect();
661 if (previous_content_bounds_ == content_bounds() &&
662 previous_visible_rect_.size() == visible_content_rect().size()) {
663 // Only expand the visible rect in the major scroll direction, to prevent
664 // massive paints due to diagonal scrolls.
665 gfx::Vector2d major_scroll_delta =
666 (std::abs(delta.x()) > std::abs(delta.y())) ?
667 gfx::Vector2d(delta.x(), 0) :
668 gfx::Vector2d(0, delta.y());
669 predicted_visible_rect_ =
670 ExpandRectByDelta(visible_content_rect(), major_scroll_delta);
672 // Bound the prediction to prevent unbounded paints, and clamp to content
673 // bounds.
674 gfx::Rect bound = visible_content_rect();
675 bound.Inset(-tiler_->tile_size().width() * kMaxPredictiveTilesCount,
676 -tiler_->tile_size().height() * kMaxPredictiveTilesCount);
677 bound.Intersect(gfx::Rect(content_bounds()));
678 predicted_visible_rect_.Intersect(bound);
680 previous_content_bounds_ = content_bounds();
681 previous_visible_rect_ = visible_content_rect();
684 bool TiledLayer::Update(ResourceUpdateQueue* queue,
685 const OcclusionTracker<Layer>* occlusion) {
686 DCHECK(!skips_draw_ && !failed_update_); // Did ResetUpdateState get skipped?
688 // Tiled layer always causes commits to wait for activation, as it does
689 // not support pending trees.
690 SetNextCommitWaitsForActivation();
692 bool updated = false;
695 base::AutoReset<bool> ignore_set_needs_commit(&ignore_set_needs_commit_,
696 true);
698 updated |= ContentsScalingLayer::Update(queue, occlusion);
699 UpdateBounds();
702 if (tiler_->has_empty_bounds() || !DrawsContent())
703 return false;
705 // Animation pre-paint. If the layer is small, try to paint it all
706 // immediately whether or not it is occluded, to avoid paint/upload
707 // hiccups while it is animating.
708 if (IsSmallAnimatedLayer()) {
709 int left, top, right, bottom;
710 tiler_->ContentRectToTileIndices(gfx::Rect(content_bounds()),
711 &left,
712 &top,
713 &right,
714 &bottom);
715 UpdateTiles(left, top, right, bottom, queue, nullptr, &updated);
716 if (updated)
717 return updated;
718 // This was an attempt to paint the entire layer so if we fail it's okay,
719 // just fallback on painting visible etc. below.
720 failed_update_ = false;
723 if (predicted_visible_rect_.IsEmpty())
724 return updated;
726 // Visible painting. First occlude visible tiles and paint the non-occluded
727 // tiles.
728 int left, top, right, bottom;
729 tiler_->ContentRectToTileIndices(
730 predicted_visible_rect_, &left, &top, &right, &bottom);
731 MarkOcclusionsAndRequestTextures(left, top, right, bottom, occlusion);
732 skips_draw_ = !UpdateTiles(
733 left, top, right, bottom, queue, occlusion, &updated);
734 if (skips_draw_)
735 tiler_->reset();
736 if (skips_draw_ || updated)
737 return true;
739 // If we have already painting everything visible. Do some pre-painting while
740 // idle.
741 gfx::Rect idle_paint_content_rect = IdlePaintRect();
742 if (idle_paint_content_rect.IsEmpty())
743 return updated;
745 // Prepaint anything that was occluded but inside the layer's visible region.
746 if (!UpdateTiles(left, top, right, bottom, queue, nullptr, &updated) ||
747 updated)
748 return updated;
750 int prepaint_left, prepaint_top, prepaint_right, prepaint_bottom;
751 tiler_->ContentRectToTileIndices(idle_paint_content_rect,
752 &prepaint_left,
753 &prepaint_top,
754 &prepaint_right,
755 &prepaint_bottom);
757 // Then expand outwards one row/column at a time until we find a dirty
758 // row/column to update. Increment along the major and minor scroll directions
759 // first.
760 gfx::Vector2d delta = -predicted_scroll_;
761 delta = gfx::Vector2d(delta.x() == 0 ? 1 : delta.x(),
762 delta.y() == 0 ? 1 : delta.y());
763 gfx::Vector2d major_delta =
764 (std::abs(delta.x()) > std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
765 : gfx::Vector2d(0, delta.y());
766 gfx::Vector2d minor_delta =
767 (std::abs(delta.x()) <= std::abs(delta.y())) ? gfx::Vector2d(delta.x(), 0)
768 : gfx::Vector2d(0, delta.y());
769 gfx::Vector2d deltas[4] = { major_delta, minor_delta, -major_delta,
770 -minor_delta };
771 for (int i = 0; i < 4; i++) {
772 if (deltas[i].y() > 0) {
773 while (bottom < prepaint_bottom) {
774 ++bottom;
775 if (!UpdateTiles(
776 left, bottom, right, bottom, queue, nullptr, &updated) ||
777 updated)
778 return updated;
781 if (deltas[i].y() < 0) {
782 while (top > prepaint_top) {
783 --top;
784 if (!UpdateTiles(left, top, right, top, queue, nullptr, &updated) ||
785 updated)
786 return updated;
789 if (deltas[i].x() < 0) {
790 while (left > prepaint_left) {
791 --left;
792 if (!UpdateTiles(left, top, left, bottom, queue, nullptr, &updated) ||
793 updated)
794 return updated;
797 if (deltas[i].x() > 0) {
798 while (right < prepaint_right) {
799 ++right;
800 if (!UpdateTiles(right, top, right, bottom, queue, nullptr, &updated) ||
801 updated)
802 return updated;
806 return updated;
809 void TiledLayer::OnOutputSurfaceCreated() {
810 // Ensure that all textures are of the right format.
811 for (LayerTilingData::TileMap::const_iterator iter = tiler_->tiles().begin();
812 iter != tiler_->tiles().end();
813 ++iter) {
814 UpdatableTile* tile = static_cast<UpdatableTile*>(iter->second);
815 if (!tile)
816 continue;
817 PrioritizedResource* resource = tile->managed_resource();
818 resource->SetDimensions(resource->size(), texture_format_);
822 bool TiledLayer::NeedsIdlePaint() {
823 // Don't trigger more paints if we failed (as we'll just fail again).
824 if (failed_update_ || visible_content_rect().IsEmpty() ||
825 tiler_->has_empty_bounds() || !DrawsContent())
826 return false;
828 gfx::Rect idle_paint_content_rect = IdlePaintRect();
829 if (idle_paint_content_rect.IsEmpty())
830 return false;
832 int left, top, right, bottom;
833 tiler_->ContentRectToTileIndices(
834 idle_paint_content_rect, &left, &top, &right, &bottom);
836 for (int j = top; j <= bottom; ++j) {
837 for (int i = left; i <= right; ++i) {
838 UpdatableTile* tile = TileAt(i, j);
839 DCHECK(tile); // Did SetTexturePriorities get skipped?
840 if (!tile)
841 continue;
843 bool updated = !tile->update_rect.IsEmpty();
844 bool can_acquire =
845 tile->managed_resource()->can_acquire_backing_texture();
846 bool dirty =
847 tile->is_dirty() || !tile->managed_resource()->have_backing_texture();
848 if (!updated && can_acquire && dirty)
849 return true;
852 return false;
855 gfx::Rect TiledLayer::IdlePaintRect() {
856 // Don't inflate an empty rect.
857 if (visible_content_rect().IsEmpty())
858 return gfx::Rect();
860 gfx::Rect prepaint_rect = visible_content_rect();
861 prepaint_rect.Inset(-tiler_->tile_size().width() * kPrepaintColumns,
862 -tiler_->tile_size().height() * kPrepaintRows);
863 gfx::Rect content_rect(content_bounds());
864 prepaint_rect.Intersect(content_rect);
866 return prepaint_rect;
869 } // namespace cc