blob: 1120567471a662045908ef0bbff36ab554f8d16c [file] [log] [blame]
// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/trees/debug_rect_history.h"
#include <stddef.h>
#include "base/memory/ptr_util.h"
#include "cc/base/math_util.h"
#include "cc/layers/heads_up_display_layer_impl.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/layer_list_iterator.h"
#include "cc/layers/render_surface_impl.h"
#include "cc/paint/display_item_list.h"
#include "cc/trees/damage_tracker.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/scroll_node.h"
#include "ui/gfx/geometry/rect_conversions.h"
namespace cc {
// static
std::unique_ptr<DebugRectHistory> DebugRectHistory::Create() {
return base::WrapUnique(new DebugRectHistory());
}
DebugRectHistory::DebugRectHistory() = default;
DebugRectHistory::~DebugRectHistory() = default;
void DebugRectHistory::SaveDebugRectsForCurrentFrame(
LayerTreeImpl* tree_impl,
HeadsUpDisplayLayerImpl* hud_layer,
const RenderSurfaceList& render_surface_list,
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(tree_impl);
}
if (debug_state.show_wheel_event_handler_rects) {
SaveWheelEventHandlerRects(tree_impl);
}
if (debug_state.show_scroll_event_handler_rects) {
SaveScrollEventHandlerRects(tree_impl);
}
if (debug_state.show_main_thread_scroll_hit_test_rects) {
SaveMainThreadScrollHitTestRects(tree_impl);
}
if (debug_state.show_main_thread_scroll_repaint_rects) {
SaveMainThreadScrollRepaintOrRasterInducingScrollRects(
tree_impl, DebugRectType::kMainThreadScrollRepaint);
}
if (debug_state.show_raster_inducing_scroll_rects) {
SaveMainThreadScrollRepaintOrRasterInducingScrollRects(
tree_impl, DebugRectType::kRasterInducingScroll);
}
if (debug_state.show_layout_shift_regions) {
SaveLayoutShiftRects(hud_layer);
}
if (debug_state.show_paint_rects) {
SavePaintRects(tree_impl);
}
if (debug_state.show_property_changed_rects) {
SavePropertyChangedRects(tree_impl, hud_layer);
}
if (debug_state.show_surface_damage_rects) {
SaveSurfaceDamageRects(render_surface_list);
}
if (debug_state.show_screen_space_rects) {
SaveScreenSpaceRects(render_surface_list);
}
}
void DebugRectHistory::SaveLayoutShiftRects(HeadsUpDisplayLayerImpl* hud) {
// We store the layout shift rects on the hud layer. If we don't have the hud
// layer, then there is nothing to store.
if (!hud)
return;
for (gfx::Rect rect : hud->LayoutShiftRects()) {
debug_rects_.emplace_back(
DebugRectType::kLayoutShift,
MathUtil::MapEnclosingClippedRect(hud->ScreenSpaceTransform(), rect));
}
hud->ClearLayoutShiftRects();
}
void DebugRectHistory::SavePaintRects(LayerTreeImpl* tree_impl) {
// 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 over all layers, not just the render surface
// list.
for (auto* layer : *tree_impl) {
Region invalidation_region = layer->GetInvalidationRegionForDebugging();
if (invalidation_region.IsEmpty() || !layer->draws_content())
continue;
for (gfx::Rect rect : invalidation_region) {
debug_rects_.emplace_back(DebugRectType::kPaint,
MathUtil::MapEnclosingClippedRect(
layer->ScreenSpaceTransform(), rect));
}
}
}
void DebugRectHistory::SavePropertyChangedRects(LayerTreeImpl* tree_impl,
LayerImpl* hud_layer) {
for (LayerImpl* layer : *tree_impl) {
if (layer == hud_layer)
continue;
if (!layer->LayerPropertyChanged())
continue;
debug_rects_.emplace_back(
DebugRectType::kPropertyChanged,
MathUtil::MapEnclosingClippedRect(layer->ScreenSpaceTransform(),
gfx::Rect(layer->bounds())));
}
}
void DebugRectHistory::SaveSurfaceDamageRects(
const RenderSurfaceList& render_surface_list) {
for (size_t i = 0; i < render_surface_list.size(); ++i) {
size_t surface_index = render_surface_list.size() - 1 - i;
RenderSurfaceImpl* render_surface = render_surface_list[surface_index];
DCHECK(render_surface);
debug_rects_.emplace_back(DebugRectType::kSurfaceDamage,
MathUtil::MapEnclosingClippedRect(
render_surface->screen_space_transform(),
render_surface->GetDamageRect()));
}
}
void DebugRectHistory::SaveScreenSpaceRects(
const RenderSurfaceList& render_surface_list) {
for (size_t i = 0; i < render_surface_list.size(); ++i) {
size_t surface_index = render_surface_list.size() - 1 - i;
RenderSurfaceImpl* render_surface = render_surface_list[surface_index];
DCHECK(render_surface);
debug_rects_.emplace_back(DebugRectType::kScreenSpace,
MathUtil::MapEnclosingClippedRect(
render_surface->screen_space_transform(),
render_surface->content_rect()));
}
}
void DebugRectHistory::SaveTouchEventHandlerRects(LayerTreeImpl* tree_impl) {
for (auto* layer : *tree_impl) {
for (const auto& pair : layer->touch_action_region()) {
TouchAction touch_action = pair.first;
for (gfx::Rect rect : pair.second) {
debug_rects_.emplace_back(DebugRectType::kTouchEventHandler,
MathUtil::MapEnclosingClippedRect(
layer->ScreenSpaceTransform(), rect),
touch_action);
}
}
}
}
void DebugRectHistory::SaveWheelEventHandlerRects(LayerTreeImpl* tree_impl) {
// TODO(crbug.com/40724301): Need behavior confirmation.
// TODO(crbug.com/40724301): Need to check results in dev tools layer
// view.
for (auto* layer : *tree_impl) {
const Region& region = layer->wheel_event_handler_region();
for (gfx::Rect rect : region) {
debug_rects_.emplace_back(DebugRectType::kWheelEventHandler,
MathUtil::MapEnclosingClippedRect(
layer->ScreenSpaceTransform(), rect));
}
}
}
void DebugRectHistory::SaveScrollEventHandlerRects(LayerTreeImpl* tree_impl) {
for (auto* layer : *tree_impl) {
if (!layer->layer_tree_impl()->have_scroll_event_handlers()) {
continue;
}
debug_rects_.emplace_back(
DebugRectType::kScrollEventHandler,
MathUtil::MapEnclosingClippedRect(layer->ScreenSpaceTransform(),
gfx::Rect(layer->bounds())));
}
}
void DebugRectHistory::SaveMainThreadScrollHitTestRects(
LayerTreeImpl* tree_impl) {
for (auto* layer : *tree_impl) {
for (gfx::Rect rect : layer->main_thread_scroll_hit_test_region()) {
debug_rects_.emplace_back(DebugRectType::kMainThreadScrollHitTest,
MathUtil::MapEnclosingClippedRect(
layer->ScreenSpaceTransform(), rect));
}
}
}
void DebugRectHistory::SaveMainThreadScrollRepaintOrRasterInducingScrollRects(
LayerTreeImpl* tree_impl,
DebugRectType type) {
const auto& scroll_tree = tree_impl->property_trees()->scroll_tree();
const auto& transform_tree = tree_impl->property_trees()->transform_tree();
for (auto& node : scroll_tree.nodes()) {
if (type == DebugRectType::kMainThreadScrollRepaint
? scroll_tree.ShouldRealizeScrollsOnMain(node)
: scroll_tree.CanRealizeScrollsOnPendingTree(node)) {
if (const auto* transform_node = transform_tree.Node(node.transform_id);
transform_node && transform_tree.Node(transform_node->parent_id)) {
debug_rects_.emplace_back(
type, MathUtil::MapEnclosingClippedRect(
// Skip the scroll translation node.
transform_tree.ToScreen(transform_node->parent_id),
gfx::Rect(node.container_origin,
scroll_tree.container_bounds(node.id))));
}
}
}
}
} // namespace cc