blob: 22747be2f8c7c7bd78f235ffacdac3c809ed9042 [file] [log] [blame]
// Copyright 2015 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 "third_party/blink/renderer/platform/graphics/paint/paint_artifact.h"
#include "cc/paint/display_item_list.h"
#include "third_party/blink/renderer/platform/geometry/int_rect.h"
#include "third_party/blink/renderer/platform/graphics/compositing/paint_chunks_to_cc_layer.h"
#include "third_party/blink/renderer/platform/graphics/graphics_layer.h"
#include "third_party/blink/renderer/platform/graphics/paint/drawing_display_item.h"
#include "third_party/blink/renderer/platform/graphics/paint/geometry_mapper.h"
#include "third_party/blink/renderer/platform/graphics/paint/hit_test_display_item.h"
#include "third_party/blink/renderer/platform/instrumentation/tracing/trace_event.h"
#include "third_party/skia/include/core/SkRegion.h"
namespace blink {
namespace {
void ComputeChunkDerivedData(const DisplayItemList& display_items,
PaintChunk& chunk) {
// This happens in tests testing paint chunks without display items.
if (!chunk.size())
return;
SkRegion known_to_be_opaque_region;
for (const DisplayItem& item : display_items.ItemsInPaintChunk(chunk)) {
chunk.bounds.Unite(item.VisualRect());
chunk.outset_for_raster_effects = std::max(chunk.outset_for_raster_effects,
item.OutsetForRasterEffects());
if (RuntimeEnabledFeatures::CompositeAfterPaintEnabled() &&
item.IsDrawing()) {
const auto& drawing = static_cast<const DrawingDisplayItem&>(item);
if (drawing.GetPaintRecord() && drawing.KnownToBeOpaque()) {
known_to_be_opaque_region.op(
SkIRect(EnclosedIntRect(drawing.VisualRect())),
SkRegion::kUnion_Op);
}
}
if (RuntimeEnabledFeatures::PaintTouchActionRectsEnabled() &&
item.IsHitTest()) {
const auto& hit_test = static_cast<const HitTestDisplayItem&>(item);
if (!chunk.hit_test_data)
chunk.hit_test_data = std::make_unique<HitTestData>();
chunk.hit_test_data->Append(hit_test.GetHitTestRect());
}
}
if (known_to_be_opaque_region.contains(EnclosingIntRect(chunk.bounds)))
chunk.known_to_be_opaque = true;
}
// For PaintArtifact::AppendDebugDrawing().
class DebugDrawingClient final : public DisplayItemClient {
public:
DebugDrawingClient() { Invalidate(PaintInvalidationReason::kUncacheable); }
String DebugName() const final { return "DebugDrawing"; }
LayoutRect VisualRect() const final {
return LayoutRect(LayoutRect::InfiniteIntRect());
}
};
} // namespace
PaintArtifact::PaintArtifact() : display_item_list_(0) {}
PaintArtifact::PaintArtifact(DisplayItemList display_items,
Vector<PaintChunk> chunks)
: display_item_list_(std::move(display_items)), chunks_(std::move(chunks)) {
for (auto& chunk : chunks_)
ComputeChunkDerivedData(display_item_list_, chunk);
}
PaintArtifact::~PaintArtifact() = default;
scoped_refptr<PaintArtifact> PaintArtifact::Create(
DisplayItemList display_items,
Vector<PaintChunk> chunks) {
return base::AdoptRef(
new PaintArtifact(std::move(display_items), std::move(chunks)));
}
scoped_refptr<PaintArtifact> PaintArtifact::Empty() {
DEFINE_STATIC_REF(PaintArtifact, empty, base::AdoptRef(new PaintArtifact()));
return empty;
}
size_t PaintArtifact::ApproximateUnsharedMemoryUsage() const {
size_t total_size = sizeof(*this) + display_item_list_.MemoryUsageInBytes() +
chunks_.capacity() * sizeof(chunks_[0]);
for (const auto& chunk : chunks_)
total_size += chunk.MemoryUsageInBytes();
return total_size;
}
void PaintArtifact::AppendDebugDrawing(
sk_sp<const PaintRecord> record,
const PropertyTreeState& property_tree_state) {
DEFINE_STATIC_LOCAL(DebugDrawingClient, debug_drawing_client, ());
DCHECK(!RuntimeEnabledFeatures::CompositeAfterPaintEnabled());
auto& display_item =
display_item_list_.AllocateAndConstruct<DrawingDisplayItem>(
debug_drawing_client, DisplayItem::kDebugDrawing, std::move(record));
// Create a PaintChunk for the debug drawing.
chunks_.emplace_back(display_item_list_.size() - 1, display_item_list_.size(),
display_item.GetId(), property_tree_state);
ComputeChunkDerivedData(display_item_list_, chunks_.back());
}
void PaintArtifact::Replay(GraphicsContext& graphics_context,
const PropertyTreeState& replay_state,
const IntPoint& offset) const {
Replay(*graphics_context.Canvas(), replay_state, offset);
}
void PaintArtifact::Replay(cc::PaintCanvas& canvas,
const PropertyTreeState& replay_state,
const IntPoint& offset) const {
TRACE_EVENT0("blink,benchmark", "PaintArtifact::replay");
scoped_refptr<cc::DisplayItemList> display_item_list =
PaintChunksToCcLayer::Convert(
PaintChunks(), replay_state, gfx::Vector2dF(offset.X(), offset.Y()),
GetDisplayItemList(),
cc::DisplayItemList::kToBeReleasedAsPaintOpBuffer);
canvas.drawPicture(display_item_list->ReleaseAsRecord());
}
DISABLE_CFI_PERF
void PaintArtifact::AppendToDisplayItemList(const FloatSize& visual_rect_offset,
cc::DisplayItemList& list) const {
TRACE_EVENT0("blink,benchmark", "PaintArtifact::AppendToDisplayItemList");
for (const DisplayItem& item : display_item_list_)
item.AppendToDisplayItemList(visual_rect_offset, list);
}
void PaintArtifact::FinishCycle() {
// BlinkGenPropertyTrees uses PaintController::ClearPropertyTreeChangedStateTo
// for clearing the property tree changed state at the end of paint instead of
// in FinishCycle. See: LocalFrameView::RunPaintLifecyclePhase.
bool clear_property_tree_changed =
!RuntimeEnabledFeatures::BlinkGenPropertyTreesEnabled() ||
RuntimeEnabledFeatures::CompositeAfterPaintEnabled();
for (auto& chunk : chunks_) {
chunk.client_is_just_created = false;
if (clear_property_tree_changed)
chunk.properties.ClearChangedToRoot();
}
}
} // namespace blink