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/debug/debug_rect_history.h"
6
7#include "cc/base/math_util.h"
8#include "cc/layers/layer_impl.h"
9#include "cc/layers/layer_iterator.h"
10#include "cc/layers/layer_utils.h"
11#include "cc/layers/render_surface_impl.h"
12#include "cc/trees/damage_tracker.h"
13#include "cc/trees/layer_tree_host.h"
14#include "cc/trees/layer_tree_host_common.h"
15#include "ui/gfx/geometry/rect_conversions.h"
16
17namespace cc {
18
19// static
20scoped_ptr<DebugRectHistory> DebugRectHistory::Create() {
21  return make_scoped_ptr(new DebugRectHistory());
22}
23
24DebugRectHistory::DebugRectHistory() {}
25
26DebugRectHistory::~DebugRectHistory() {}
27
28void DebugRectHistory::SaveDebugRectsForCurrentFrame(
29    LayerImpl* root_layer,
30    LayerImpl* hud_layer,
31    const LayerImplList& render_surface_layer_list,
32    const std::vector<gfx::Rect>& occluding_screen_space_rects,
33    const std::vector<gfx::Rect>& non_occluding_screen_space_rects,
34    const LayerTreeDebugState& debug_state) {
35  // For now, clear all rects from previous frames. In the future we may want to
36  // store all debug rects for a history of many frames.
37  debug_rects_.clear();
38
39  if (debug_state.show_touch_event_handler_rects)
40    SaveTouchEventHandlerRects(root_layer);
41
42  if (debug_state.show_wheel_event_handler_rects)
43    SaveWheelEventHandlerRects(root_layer);
44
45  if (debug_state.show_scroll_event_handler_rects)
46    SaveScrollEventHandlerRects(root_layer);
47
48  if (debug_state.show_non_fast_scrollable_rects)
49    SaveNonFastScrollableRects(root_layer);
50
51  if (debug_state.show_paint_rects)
52    SavePaintRects(root_layer);
53
54  if (debug_state.show_property_changed_rects)
55    SavePropertyChangedRects(render_surface_layer_list, hud_layer);
56
57  if (debug_state.show_surface_damage_rects)
58    SaveSurfaceDamageRects(render_surface_layer_list);
59
60  if (debug_state.show_screen_space_rects)
61    SaveScreenSpaceRects(render_surface_layer_list);
62
63  if (debug_state.show_occluding_rects)
64    SaveOccludingRects(occluding_screen_space_rects);
65
66  if (debug_state.show_non_occluding_rects)
67    SaveNonOccludingRects(non_occluding_screen_space_rects);
68
69  if (debug_state.show_layer_animation_bounds_rects)
70    SaveLayerAnimationBoundsRects(render_surface_layer_list);
71}
72
73void DebugRectHistory::SavePaintRects(LayerImpl* layer) {
74  // We would like to visualize where any layer's paint rect (update rect) has
75  // changed, regardless of whether this layer is skipped for actual drawing or
76  // not. Therefore we traverse recursively over all layers, not just the render
77  // surface list.
78
79  if (!layer->update_rect().IsEmpty() && layer->DrawsContent()) {
80    float width_scale = layer->content_bounds().width() /
81                        static_cast<float>(layer->bounds().width());
82    float height_scale = layer->content_bounds().height() /
83                         static_cast<float>(layer->bounds().height());
84    gfx::Rect update_content_rect = gfx::ScaleToEnclosingRect(
85        gfx::ToEnclosingRect(layer->update_rect()), width_scale, height_scale);
86    debug_rects_.push_back(
87        DebugRect(PAINT_RECT_TYPE,
88                  MathUtil::MapEnclosingClippedRect(
89                      layer->screen_space_transform(), update_content_rect)));
90  }
91
92  for (unsigned i = 0; i < layer->children().size(); ++i)
93    SavePaintRects(layer->children()[i]);
94}
95
96void DebugRectHistory::SavePropertyChangedRects(
97    const LayerImplList& render_surface_layer_list,
98    LayerImpl* hud_layer) {
99  for (int surface_index = render_surface_layer_list.size() - 1;
100       surface_index >= 0;
101       --surface_index) {
102    LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
103    RenderSurfaceImpl* render_surface = render_surface_layer->render_surface();
104    DCHECK(render_surface);
105
106    const LayerImplList& layer_list = render_surface->layer_list();
107    for (unsigned layer_index = 0;
108         layer_index < layer_list.size();
109         ++layer_index) {
110      LayerImpl* layer = layer_list[layer_index];
111
112      if (LayerTreeHostCommon::RenderSurfaceContributesToTarget<LayerImpl>(
113              layer, render_surface_layer->id()))
114        continue;
115
116      if (layer == hud_layer)
117        continue;
118
119      if (!layer->LayerPropertyChanged())
120        continue;
121
122      debug_rects_.push_back(
123          DebugRect(PROPERTY_CHANGED_RECT_TYPE,
124                    MathUtil::MapEnclosingClippedRect(
125                        layer->screen_space_transform(),
126                        gfx::Rect(layer->content_bounds()))));
127    }
128  }
129}
130
131void DebugRectHistory::SaveSurfaceDamageRects(
132    const LayerImplList& render_surface_layer_list) {
133  for (int surface_index = render_surface_layer_list.size() - 1;
134       surface_index >= 0;
135       --surface_index) {
136    LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
137    RenderSurfaceImpl* render_surface = render_surface_layer->render_surface();
138    DCHECK(render_surface);
139
140    debug_rects_.push_back(DebugRect(
141        SURFACE_DAMAGE_RECT_TYPE,
142        MathUtil::MapEnclosingClippedRect(
143            render_surface->screen_space_transform(),
144            render_surface->damage_tracker()->current_damage_rect())));
145  }
146}
147
148void DebugRectHistory::SaveScreenSpaceRects(
149    const LayerImplList& render_surface_layer_list) {
150  for (int surface_index = render_surface_layer_list.size() - 1;
151       surface_index >= 0;
152       --surface_index) {
153    LayerImpl* render_surface_layer = render_surface_layer_list[surface_index];
154    RenderSurfaceImpl* render_surface = render_surface_layer->render_surface();
155    DCHECK(render_surface);
156
157    debug_rects_.push_back(
158        DebugRect(SCREEN_SPACE_RECT_TYPE,
159                  MathUtil::MapEnclosingClippedRect(
160                      render_surface->screen_space_transform(),
161                      render_surface->content_rect())));
162
163    if (render_surface_layer->replica_layer()) {
164      debug_rects_.push_back(
165          DebugRect(REPLICA_SCREEN_SPACE_RECT_TYPE,
166                    MathUtil::MapEnclosingClippedRect(
167                        render_surface->replica_screen_space_transform(),
168                        render_surface->content_rect())));
169    }
170  }
171}
172
173void DebugRectHistory::SaveOccludingRects(
174    const std::vector<gfx::Rect>& occluding_rects) {
175  for (size_t i = 0; i < occluding_rects.size(); ++i)
176    debug_rects_.push_back(DebugRect(OCCLUDING_RECT_TYPE, occluding_rects[i]));
177}
178
179void DebugRectHistory::SaveNonOccludingRects(
180    const std::vector<gfx::Rect>& non_occluding_rects) {
181  for (size_t i = 0; i < non_occluding_rects.size(); ++i) {
182    debug_rects_.push_back(
183        DebugRect(NONOCCLUDING_RECT_TYPE, non_occluding_rects[i]));
184  }
185}
186
187void DebugRectHistory::SaveTouchEventHandlerRects(LayerImpl* layer) {
188  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
189      layer,
190      base::Bind(&DebugRectHistory::SaveTouchEventHandlerRectsCallback,
191                 base::Unretained(this)));
192}
193
194void DebugRectHistory::SaveTouchEventHandlerRectsCallback(LayerImpl* layer) {
195  for (Region::Iterator iter(layer->touch_event_handler_region());
196       iter.has_rect();
197       iter.next()) {
198    gfx::Rect touch_rect = gfx::ScaleToEnclosingRect(
199        iter.rect(), layer->contents_scale_x(), layer->contents_scale_y());
200    debug_rects_.push_back(
201        DebugRect(TOUCH_EVENT_HANDLER_RECT_TYPE,
202                  MathUtil::MapEnclosingClippedRect(
203                      layer->screen_space_transform(), touch_rect)));
204  }
205}
206
207void DebugRectHistory::SaveWheelEventHandlerRects(LayerImpl* layer) {
208  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
209      layer,
210      base::Bind(&DebugRectHistory::SaveWheelEventHandlerRectsCallback,
211                 base::Unretained(this)));
212}
213
214void DebugRectHistory::SaveWheelEventHandlerRectsCallback(LayerImpl* layer) {
215  if (!layer->have_wheel_event_handlers())
216    return;
217
218  gfx::Rect wheel_rect =
219      gfx::ScaleToEnclosingRect(gfx::Rect(layer->content_bounds()),
220                                layer->contents_scale_x(),
221                                layer->contents_scale_y());
222  debug_rects_.push_back(
223      DebugRect(WHEEL_EVENT_HANDLER_RECT_TYPE,
224                MathUtil::MapEnclosingClippedRect(
225                    layer->screen_space_transform(), wheel_rect)));
226}
227
228void DebugRectHistory::SaveScrollEventHandlerRects(LayerImpl* layer) {
229  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
230      layer,
231      base::Bind(&DebugRectHistory::SaveScrollEventHandlerRectsCallback,
232                 base::Unretained(this)));
233}
234
235void DebugRectHistory::SaveScrollEventHandlerRectsCallback(LayerImpl* layer) {
236  if (!layer->have_scroll_event_handlers())
237    return;
238
239  gfx::Rect scroll_rect =
240      gfx::ScaleToEnclosingRect(gfx::Rect(layer->content_bounds()),
241                                layer->contents_scale_x(),
242                                layer->contents_scale_y());
243  debug_rects_.push_back(
244      DebugRect(SCROLL_EVENT_HANDLER_RECT_TYPE,
245                MathUtil::MapEnclosingClippedRect(
246                    layer->screen_space_transform(), scroll_rect)));
247}
248
249void DebugRectHistory::SaveNonFastScrollableRects(LayerImpl* layer) {
250  LayerTreeHostCommon::CallFunctionForSubtree<LayerImpl>(
251      layer,
252      base::Bind(&DebugRectHistory::SaveNonFastScrollableRectsCallback,
253                 base::Unretained(this)));
254}
255
256void DebugRectHistory::SaveNonFastScrollableRectsCallback(LayerImpl* layer) {
257  for (Region::Iterator iter(layer->non_fast_scrollable_region());
258       iter.has_rect();
259       iter.next()) {
260    gfx::Rect scroll_rect = gfx::ScaleToEnclosingRect(
261        iter.rect(), layer->contents_scale_x(), layer->contents_scale_y());
262    debug_rects_.push_back(
263        DebugRect(NON_FAST_SCROLLABLE_RECT_TYPE,
264                  MathUtil::MapEnclosingClippedRect(
265                      layer->screen_space_transform(), scroll_rect)));
266  }
267}
268
269void DebugRectHistory::SaveLayerAnimationBoundsRects(
270    const LayerImplList& render_surface_layer_list) {
271  typedef LayerIterator<LayerImpl> LayerIteratorType;
272  LayerIteratorType end = LayerIteratorType::End(&render_surface_layer_list);
273  for (LayerIteratorType it =
274           LayerIteratorType::Begin(&render_surface_layer_list);
275       it != end; ++it) {
276    if (!it.represents_itself())
277      continue;
278
279    // TODO(avallee): Figure out if we should show something for a layer who's
280    // animating bounds but that we can't compute them.
281    gfx::BoxF inflated_bounds;
282    if (!LayerUtils::GetAnimationBounds(**it, &inflated_bounds))
283      continue;
284
285    debug_rects_.push_back(
286        DebugRect(ANIMATION_BOUNDS_RECT_TYPE,
287                  gfx::ToEnclosingRect(gfx::RectF(inflated_bounds.x(),
288                                                  inflated_bounds.y(),
289                                                  inflated_bounds.width(),
290                                                  inflated_bounds.height()))));
291  }
292}
293
294}  // namespace cc
295