| // 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_surface.h" |
| |
| #include <algorithm> |
| #include <utility> |
| |
| #include "base/notreached.h" |
| #include "cc/layers/surface_layer.h" |
| #include "components/viz/common/surfaces/surface_id.h" |
| #include "ui/compositor/layer_mirror.h" |
| |
| namespace ui { |
| |
| LayerSurface::LayerSurface() : Layer(LAYER_SURFACE) { |
| surface_layer_ = cc::SurfaceLayer::Create(); |
| cc_layer_ = surface_layer_.get(); |
| |
| InitializeCcLayer(); |
| surface_layer_->SetSurfaceHitTestable(true); |
| } |
| |
| LayerSurface::~LayerSurface() { |
| Destroy(); |
| } |
| |
| bool LayerSurface::ShouldSchedulePaint() const { |
| return false; |
| } |
| |
| void LayerSurface::SetFallbackBackgroundColor(SkColor4f color) { |
| surface_layer_->SetBackgroundColor(color); |
| surface_layer_->SetSafeOpaqueBackgroundColor(color); |
| |
| for (const auto& mirror : mirrors_) { |
| mirror->dest()->AsSurface()->SetFallbackBackgroundColor(color); |
| } |
| } |
| |
| SkColor4f LayerSurface::GetFallbackBackgroundColor() const { |
| return surface_layer_->background_color(); |
| } |
| |
| std::unique_ptr<Layer> LayerSurface::Clone() const { |
| auto clone = Layer::Clone(); |
| auto* cloned_surface = clone->AsSurface(); |
| |
| cloned_surface->SetFallbackBackgroundColor( |
| surface_layer_->background_color()); |
| cloned_surface->SetShowSurface( |
| surface_layer_->surface_id(), frame_size_in_dip_, |
| surface_layer_->deadline_in_frames() |
| ? cc::DeadlinePolicy::UseSpecifiedDeadline( |
| *surface_layer_->deadline_in_frames()) |
| : cc::DeadlinePolicy::UseDefaultDeadline(), |
| surface_layer_->stretch_content_to_fill_bounds()); |
| if (surface_layer_->oldest_acceptable_fallback()) { |
| cloned_surface->SetOldestAcceptableFallback( |
| *surface_layer_->oldest_acceptable_fallback()); |
| } |
| |
| return clone; |
| } |
| |
| void LayerSurface::SetShowSurface(const viz::SurfaceId& surface_id, |
| const gfx::Size& frame_size_in_dip, |
| const cc::DeadlinePolicy& deadline_policy, |
| bool stretch_content_to_fill_bounds) { |
| surface_layer_->SetSurfaceId(surface_id, deadline_policy); |
| surface_layer_->SetStretchContentToFillBounds(stretch_content_to_fill_bounds); |
| |
| frame_size_in_dip_ = frame_size_in_dip; |
| RecomputeDrawsContentAndUVRect(); |
| |
| for (const auto& mirror : mirrors_) { |
| mirror->dest()->AsSurface()->SetShowSurface(surface_id, frame_size_in_dip, |
| deadline_policy, |
| stretch_content_to_fill_bounds); |
| } |
| } |
| |
| void LayerSurface::SetShowSurface(const viz::SurfaceId& surface_id, |
| const cc::DeadlinePolicy& deadline_policy, |
| bool stretch_content_to_fill_bounds) { |
| // Assumes `frame_size_in_dip_` is already set. |
| // TODO(crbug.com/40285157): with surface sync, it should use on `bounds_`. |
| surface_layer_->SetSurfaceId(surface_id, deadline_policy); |
| surface_layer_->SetStretchContentToFillBounds(stretch_content_to_fill_bounds); |
| |
| for (const auto& mirror : mirrors_) { |
| mirror->dest()->AsSurface()->SetShowSurface(surface_id, deadline_policy, |
| stretch_content_to_fill_bounds); |
| } |
| } |
| |
| void LayerSurface::SetShowReflectedSurface( |
| const viz::SurfaceId& surface_id, |
| const gfx::Size& frame_size_in_pixels) { |
| surface_layer_->SetSurfaceId(surface_id, |
| cc::DeadlinePolicy::UseInfiniteDeadline()); |
| // Set the fallback color (also used for gutters) as kBlack. |
| surface_layer_->SetBackgroundColor(SkColors::kBlack); |
| surface_layer_->SetSafeOpaqueBackgroundColor(SkColors::kBlack); |
| surface_layer_->SetStretchContentToFillBounds(true); |
| surface_layer_->SetIsReflection(true); |
| |
| // The reflecting surface uses the native size of the reflected display. |
| frame_size_in_dip_ = frame_size_in_pixels; |
| RecomputeDrawsContentAndUVRect(); |
| } |
| |
| void LayerSurface::SetOldestAcceptableFallback( |
| const viz::SurfaceId& surface_id) { |
| surface_layer_->SetOldestAcceptableFallback(surface_id); |
| |
| for (const auto& mirror : mirrors_) { |
| mirror->dest()->AsSurface()->SetOldestAcceptableFallback(surface_id); |
| } |
| } |
| |
| const viz::SurfaceId* LayerSurface::GetOldestAcceptableFallback() const { |
| if (surface_layer_->oldest_acceptable_fallback()) { |
| return &surface_layer_->oldest_acceptable_fallback().value(); |
| } |
| |
| return nullptr; |
| } |
| |
| bool LayerSurface::StretchContentToFillBounds() const { |
| return surface_layer_->stretch_content_to_fill_bounds(); |
| } |
| |
| void LayerSurface::SetSurfaceSize(gfx::Size surface_size_in_dip) { |
| if (frame_size_in_dip_ == surface_size_in_dip) { |
| return; |
| } |
| |
| frame_size_in_dip_ = surface_size_in_dip; |
| RecomputeDrawsContentAndUVRect(); |
| } |
| |
| const viz::SurfaceId* LayerSurface::GetSurfaceId() const { |
| if (surface_layer_->surface_id().is_valid()) { |
| return &surface_layer_->surface_id(); |
| } |
| |
| return nullptr; |
| } |
| |
| void LayerSurface::RecomputeDrawsContentAndUVRect() { |
| gfx::Size size(bounds_.size()); |
| // TODO(crbug.com/40285157): with surface sync, size shouldn't rely on |
| // `frame_size_in_dip_` anymore. |
| size.SetToMin(frame_size_in_dip_); |
| cc_layer_->SetBounds(size); |
| } |
| |
| void LayerSurface::Reset() { |
| surface_layer_ = nullptr; |
| } |
| |
| void LayerSurface::OnPaintScheduled() { |
| NOTREACHED(); |
| } |
| |
| } // namespace ui |