|  | // Copyright 2012 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "cc/debug/debug_rect_history.h" | 
|  |  | 
|  | #include "cc/base/math_util.h" | 
|  | #include "cc/layers/layer_impl.h" | 
|  | #include "cc/layers/layer_iterator.h" | 
|  | #include "cc/layers/layer_utils.h" | 
|  | #include "cc/layers/render_surface_impl.h" | 
|  | #include "cc/trees/damage_tracker.h" | 
|  | #include "cc/trees/layer_tree_host.h" | 
|  | #include "cc/trees/layer_tree_host_common.h" | 
|  | #include "ui/gfx/geometry/rect_conversions.h" | 
|  |  | 
|  | namespace cc { | 
|  |  | 
|  | // static | 
|  | scoped_ptr<DebugRectHistory> DebugRectHistory::Create() { | 
|  | return make_scoped_ptr(new DebugRectHistory()); | 
|  | } | 
|  |  | 
|  | DebugRectHistory::DebugRectHistory() {} | 
|  |  | 
|  | DebugRectHistory::~DebugRectHistory() {} | 
|  |  | 
|  | void DebugRectHistory::SaveDebugRectsForCurrentFrame( | 
|  | LayerImpl* root_layer, | 
|  | LayerImpl* hud_layer, | 
|  | const LayerImplList& render_surface_layer_list, | 
|  | const std::vector<gfx::Rect>& occluding_screen_space_rects, | 
|  | const std::vector<gfx::Rect>& non_occluding_screen_space_rects, | 
|  | const LayerTreeDebugState& debug_state) { | 
|  | // For now, clear all rects from previous frames. In the future we may want to | 
|  | // store all debug rects for a history of many frames. | 
|  | debug_rects_.clear(); | 
|  |  | 
|  | if (debug_state.show_touch_event_handler_rects) | 
|  | SaveTouchEventHandlerRects(root_layer); | 
|  |  | 
|  | if (debug_state.show_wheel_event_handler_rects) | 
|  | SaveWheelEventHandlerRects(root_layer); | 
|  |  | 
|  | if (debug_state.show_scroll_event_handler_rects) | 
|  | SaveScrollEventHandlerRects(root_layer); | 
|  |  | 
|  | if (debug_state.show_non_fast_scrollable_rects) | 
|  | SaveNonFastScrollableRects(root_layer); | 
|  |  | 
|  | if (debug_state.show_paint_rects) | 
|  | SavePaintRects(root_layer); | 
|  |  | 
|  | if (debug_state.show_property_changed_rects) | 
|  | SavePropertyChangedRects(render_surface_layer_list, hud_layer); | 
|  |  | 
|  | if (debug_state.show_surface_damage_rects) | 
|  | SaveSurfaceDamageRects(render_surface_layer_list); | 
|  |  | 
|  | if (debug_state.show_screen_space_rects) | 
|  | SaveScreenSpaceRects(render_surface_layer_list); | 
|  |  | 
|  | if (debug_state.show_occluding_rects) | 
|  | SaveOccludingRects(occluding_screen_space_rects); | 
|  |  | 
|  | if (debug_state.show_non_occluding_rects) | 
|  | SaveNonOccludingRects(non_occluding_screen_space_rects); | 
|  |  | 
|  | if (debug_state.show_layer_animation_bounds_rects) | 
|  | SaveLayerAnimationBoundsRects(render_surface_layer_list); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SavePaintRects(LayerImpl* layer) { | 
|  | // We would like to visualize where any layer's paint rect (update rect) has | 
|  | // changed, regardless of whether this layer is skipped for actual drawing or | 
|  | // not. Therefore we traverse recursively over all layers, not just the render | 
|  | // surface list. | 
|  |  | 
|  | if (!layer->update_rect().IsEmpty() && layer->DrawsContent()) { | 
|  | float width_scale = layer->content_bounds().width() / | 
|  | static_cast<float>(layer->bounds().width()); | 
|  | float height_scale = layer->content_bounds().height() / | 
|  | static_cast<float>(layer->bounds().height()); | 
|  | gfx::Rect update_content_rect = gfx::ScaleToEnclosingRect( | 
|  | layer->update_rect(), width_scale, height_scale); | 
|  | debug_rects_.push_back( | 
|  | DebugRect(PAINT_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | layer->screen_space_transform(), update_content_rect))); | 
|  | } | 
|  |  | 
|  | for (unsigned i = 0; i < layer->children().size(); ++i) | 
|  | SavePaintRects(layer->children()[i]); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SavePropertyChangedRects( | 
|  | const LayerImplList& render_surface_layer_list, | 
|  | LayerImpl* hud_layer) { | 
|  | for (int surface_index = render_surface_layer_list.size() - 1; | 
|  | surface_index >= 0; | 
|  | --surface_index) { | 
|  | LayerImpl* render_surface_layer = render_surface_layer_list[surface_index]; | 
|  | RenderSurfaceImpl* render_surface = render_surface_layer->render_surface(); | 
|  | DCHECK(render_surface); | 
|  |  | 
|  | const LayerImplList& layer_list = render_surface->layer_list(); | 
|  | for (unsigned layer_index = 0; | 
|  | layer_index < layer_list.size(); | 
|  | ++layer_index) { | 
|  | LayerImpl* layer = layer_list[layer_index]; | 
|  |  | 
|  | if (LayerTreeHostCommon::RenderSurfaceContributesToTarget<LayerImpl>( | 
|  | layer, render_surface_layer->id())) | 
|  | continue; | 
|  |  | 
|  | if (layer == hud_layer) | 
|  | continue; | 
|  |  | 
|  | if (!layer->LayerPropertyChanged()) | 
|  | continue; | 
|  |  | 
|  | debug_rects_.push_back( | 
|  | DebugRect(PROPERTY_CHANGED_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | layer->screen_space_transform(), | 
|  | gfx::Rect(layer->content_bounds())))); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveSurfaceDamageRects( | 
|  | const LayerImplList& render_surface_layer_list) { | 
|  | for (int surface_index = render_surface_layer_list.size() - 1; | 
|  | surface_index >= 0; | 
|  | --surface_index) { | 
|  | LayerImpl* render_surface_layer = render_surface_layer_list[surface_index]; | 
|  | RenderSurfaceImpl* render_surface = render_surface_layer->render_surface(); | 
|  | DCHECK(render_surface); | 
|  |  | 
|  | debug_rects_.push_back(DebugRect( | 
|  | SURFACE_DAMAGE_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | render_surface->screen_space_transform(), | 
|  | render_surface->damage_tracker()->current_damage_rect()))); | 
|  | } | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveScreenSpaceRects( | 
|  | const LayerImplList& render_surface_layer_list) { | 
|  | for (int surface_index = render_surface_layer_list.size() - 1; | 
|  | surface_index >= 0; | 
|  | --surface_index) { | 
|  | LayerImpl* render_surface_layer = render_surface_layer_list[surface_index]; | 
|  | RenderSurfaceImpl* render_surface = render_surface_layer->render_surface(); | 
|  | DCHECK(render_surface); | 
|  |  | 
|  | debug_rects_.push_back( | 
|  | DebugRect(SCREEN_SPACE_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | render_surface->screen_space_transform(), | 
|  | render_surface->content_rect()))); | 
|  |  | 
|  | if (render_surface_layer->replica_layer()) { | 
|  | debug_rects_.push_back( | 
|  | DebugRect(REPLICA_SCREEN_SPACE_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | render_surface->replica_screen_space_transform(), | 
|  | render_surface->content_rect()))); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveOccludingRects( | 
|  | const std::vector<gfx::Rect>& occluding_rects) { | 
|  | for (size_t i = 0; i < occluding_rects.size(); ++i) | 
|  | debug_rects_.push_back(DebugRect(OCCLUDING_RECT_TYPE, occluding_rects[i])); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveNonOccludingRects( | 
|  | const std::vector<gfx::Rect>& non_occluding_rects) { | 
|  | for (size_t i = 0; i < non_occluding_rects.size(); ++i) { | 
|  | debug_rects_.push_back( | 
|  | DebugRect(NONOCCLUDING_RECT_TYPE, non_occluding_rects[i])); | 
|  | } | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveTouchEventHandlerRects(LayerImpl* layer) { | 
|  | LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( | 
|  | layer, | 
|  | base::Bind(&DebugRectHistory::SaveTouchEventHandlerRectsCallback, | 
|  | base::Unretained(this))); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveTouchEventHandlerRectsCallback(LayerImpl* layer) { | 
|  | for (Region::Iterator iter(layer->touch_event_handler_region()); | 
|  | iter.has_rect(); | 
|  | iter.next()) { | 
|  | gfx::Rect touch_rect = gfx::ScaleToEnclosingRect( | 
|  | iter.rect(), layer->contents_scale_x(), layer->contents_scale_y()); | 
|  | debug_rects_.push_back( | 
|  | DebugRect(TOUCH_EVENT_HANDLER_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | layer->screen_space_transform(), touch_rect))); | 
|  | } | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveWheelEventHandlerRects(LayerImpl* layer) { | 
|  | LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( | 
|  | layer, | 
|  | base::Bind(&DebugRectHistory::SaveWheelEventHandlerRectsCallback, | 
|  | base::Unretained(this))); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveWheelEventHandlerRectsCallback(LayerImpl* layer) { | 
|  | if (!layer->have_wheel_event_handlers()) | 
|  | return; | 
|  |  | 
|  | gfx::Rect wheel_rect = | 
|  | gfx::ScaleToEnclosingRect(gfx::Rect(layer->content_bounds()), | 
|  | layer->contents_scale_x(), | 
|  | layer->contents_scale_y()); | 
|  | debug_rects_.push_back( | 
|  | DebugRect(WHEEL_EVENT_HANDLER_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | layer->screen_space_transform(), wheel_rect))); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveScrollEventHandlerRects(LayerImpl* layer) { | 
|  | LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( | 
|  | layer, | 
|  | base::Bind(&DebugRectHistory::SaveScrollEventHandlerRectsCallback, | 
|  | base::Unretained(this))); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveScrollEventHandlerRectsCallback(LayerImpl* layer) { | 
|  | if (!layer->have_scroll_event_handlers()) | 
|  | return; | 
|  |  | 
|  | gfx::Rect scroll_rect = | 
|  | gfx::ScaleToEnclosingRect(gfx::Rect(layer->content_bounds()), | 
|  | layer->contents_scale_x(), | 
|  | layer->contents_scale_y()); | 
|  | debug_rects_.push_back( | 
|  | DebugRect(SCROLL_EVENT_HANDLER_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | layer->screen_space_transform(), scroll_rect))); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveNonFastScrollableRects(LayerImpl* layer) { | 
|  | LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>( | 
|  | layer, | 
|  | base::Bind(&DebugRectHistory::SaveNonFastScrollableRectsCallback, | 
|  | base::Unretained(this))); | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) { | 
|  | for (Region::Iterator iter(layer->non_fast_scrollable_region()); | 
|  | iter.has_rect(); | 
|  | iter.next()) { | 
|  | gfx::Rect scroll_rect = gfx::ScaleToEnclosingRect( | 
|  | iter.rect(), layer->contents_scale_x(), layer->contents_scale_y()); | 
|  | debug_rects_.push_back( | 
|  | DebugRect(NON_FAST_SCROLLABLE_RECT_TYPE, | 
|  | MathUtil::MapEnclosingClippedRect( | 
|  | layer->screen_space_transform(), scroll_rect))); | 
|  | } | 
|  | } | 
|  |  | 
|  | void DebugRectHistory::SaveLayerAnimationBoundsRects( | 
|  | const LayerImplList& render_surface_layer_list) { | 
|  | typedef LayerIterator<LayerImpl> LayerIteratorType; | 
|  | LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list); | 
|  | for (LayerIteratorType it = | 
|  | LayerIteratorType::Begin(&render_surface_layer_list); | 
|  | it != end; ++it) { | 
|  | if (!it.represents_itself()) | 
|  | continue; | 
|  |  | 
|  | // TODO(avallee): Figure out if we should show something for a layer who's | 
|  | // animating bounds but that we can't compute them. | 
|  | gfx::BoxF inflated_bounds; | 
|  | if (!LayerUtils::GetAnimationBounds(**it, &inflated_bounds)) | 
|  | continue; | 
|  |  | 
|  | debug_rects_.push_back( | 
|  | DebugRect(ANIMATION_BOUNDS_RECT_TYPE, | 
|  | gfx::ToEnclosingRect(gfx::RectF(inflated_bounds.x(), | 
|  | inflated_bounds.y(), | 
|  | inflated_bounds.width(), | 
|  | inflated_bounds.height())))); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace cc |