blob: 55d510aa6882c2bd54c0ba677a45d15aa65d0824 [file]
// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ui/compositor/layer_textured.h"
#include <cstdint>
#include "base/check_op.h"
#include "base/memory/scoped_refptr.h"
#include "base/trace_event/trace_event.h"
#include "cc/layers/picture_layer.h"
#include "cc/paint/display_item_list.h"
#include "ui/compositor/compositor.h"
#include "ui/compositor/layer_delegate.h"
#include "ui/compositor/layer_mirror.h"
#include "ui/compositor/paint_context.h"
#include "ui/gfx/geometry/rect.h"
namespace ui {
LayerTextured::LayerTextured() : Layer(LAYER_TEXTURED) {
content_layer_ = cc::PictureLayer::Create(this);
cc_layer_ = content_layer_.get();
InitializeCcLayer();
}
LayerTextured::~LayerTextured() {
Destroy();
}
void LayerTextured::AddDeferredPaintRequest() {
++deferred_paint_requests_;
TRACE_COUNTER("ui",
perfetto::CounterTrack("DeferredPaintRequests",
reinterpret_cast<uintptr_t>(this)),
deferred_paint_requests_);
}
void LayerTextured::RemoveDeferredPaintRequest() {
DCHECK_GT(deferred_paint_requests_, 0u);
--deferred_paint_requests_;
TRACE_COUNTER("ui",
perfetto::CounterTrack("DeferredPaintRequests",
reinterpret_cast<uintptr_t>(this)),
deferred_paint_requests_);
if (!deferred_paint_requests_ && !damaged_region_.IsEmpty()) {
ScheduleDraw();
}
}
bool LayerTextured::IsPaintDeferred() const {
return deferred_paint_requests_ > 0;
}
std::unique_ptr<Layer> LayerTextured::Clone() const {
auto clone = Layer::Clone();
clone->AsTextured()->SetFillsBoundsCompletely(FillsBoundsCompletely());
return clone;
}
bool LayerTextured::ShouldSchedulePaint() const {
// LayerTextured only needs to schedule paint if it has a delegate to paint
// its contents.
return delegate_ != nullptr;
}
scoped_refptr<cc::DisplayItemList> LayerTextured::PaintContentsToDisplayList() {
TRACE_EVENT1("ui", "LayerTextured::PaintContentsToDisplayList", "name",
name_);
gfx::Rect local_bounds(bounds().size());
gfx::Rect invalidation(
gfx::IntersectRects(paint_region_.bounds(), local_bounds));
paint_region_.Clear();
auto display_list = base::MakeRefCounted<cc::DisplayItemList>();
if (delegate_) {
delegate_->OnPaintLayer(PaintContext(display_list.get(),
device_scale_factor_, invalidation,
GetCompositor()->is_pixel_canvas()));
}
display_list->Finalize();
// TODO(domlaskowski): Move mirror invalidation to Layer::SchedulePaint.
for (const auto& mirror : mirrors_) {
mirror->dest()->SchedulePaint(invalidation);
}
return display_list;
}
bool LayerTextured::FillsBoundsCompletely() const {
return fills_bounds_completely_;
}
void LayerTextured::SetFillsBoundsCompletely(bool fills_bounds_completely) {
fills_bounds_completely_ = fills_bounds_completely;
}
void LayerTextured::OnPaintScheduled() {
if (IsPaintDeferred()) {
return;
}
ScheduleDraw();
}
void LayerTextured::CommitDamage() {
// If painting is deferred, or if there is no delegate to paint our contents,
// do not commit the accumulated damage yet.
if (deferred_paint_requests_ || !delegate_) {
return;
}
// Record the accumulated damage in `paint_region_` to be used when the
// compositor is ready to paint the content in PaintContentsToDisplayList().
paint_region_.Union(damaged_region_);
Layer::CommitDamage();
}
void LayerTextured::Reset() {
if (content_layer_) {
content_layer_->ClearClient();
}
content_layer_ = nullptr;
}
} // namespace ui