910e62b5创建于 1月15日历史提交
// 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