blob: 0cca2335b6de09e2af80103dd472b4790e21a163 [file] [log] [blame]
// Copyright 2023 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/slim/layer.h"
#include <algorithm>
#include <atomic>
#include <utility>
#include "base/atomic_sequence_num.h"
#include "base/check.h"
#include "base/containers/cxx20_erase_vector.h"
#include "base/ranges/algorithm.h"
#include "cc/paint/filter_operation.h"
#include "cc/slim/layer_tree.h"
#include "cc/slim/layer_tree_impl.h"
#include "components/viz/common/quads/shared_quad_state.h"
namespace cc::slim {
namespace {
base::AtomicSequenceNumber g_next_id;
cc::FilterOperations ToCcFilters(std::vector<cc::slim::Filter> filters) {
cc::FilterOperations cc_filters;
for (const auto& slim_filter : filters) {
switch (slim_filter.type()) {
case cc::slim::Filter::kBrightness:
cc_filters.Append(
cc::FilterOperation::CreateBrightnessFilter(slim_filter.amount()));
break;
case cc::slim::Filter::kSaturation:
cc_filters.Append(
cc::FilterOperation::CreateSaturateFilter(slim_filter.amount()));
break;
}
}
return cc_filters;
}
} // namespace
// static
scoped_refptr<Layer> Layer::Create() {
return base::AdoptRef(new Layer());
}
Layer::Layer() : id_(g_next_id.GetNext() + 1) {}
Layer::~Layer() {
RemoveAllChildren();
DCHECK_EQ(num_descendants_that_draw_content_, 0);
}
void Layer::SetLayerTree(LayerTree* layer_tree) {
if (layer_tree_ == layer_tree) {
return;
}
layer_tree_ = layer_tree;
for (auto& child : children_) {
child->SetLayerTree(layer_tree);
}
}
Layer* Layer::RootLayer() {
Layer* layer = this;
while (layer->parent_) {
layer = layer->parent_;
}
return layer;
}
void Layer::AddChild(scoped_refptr<Layer> child) {
InsertChildSlim(std::move(child), children_.size());
}
void Layer::InsertChild(scoped_refptr<Layer> child, size_t position) {
InsertChildSlim(std::move(child), position);
}
void Layer::InsertChildSlim(scoped_refptr<Layer> child, size_t position) {
if (position < children_.size() && children_.at(position) == child) {
return;
}
WillAddChildSlim(child.get());
const size_t index = std::min(position, children_.size());
children_.insert(children_.begin() + index, std::move(child));
}
void Layer::WillAddChildSlim(Layer* child) {
child->RemoveFromParentSlim();
child->SetParentSlim(this);
child->SetLayerTree(layer_tree());
child->NotifySubtreeChanged();
}
void Layer::ReplaceChild(Layer* old_child, scoped_refptr<Layer> new_child) {
if (old_child->parent_ != this || old_child == new_child.get()) {
return;
}
auto it = base::ranges::find_if(
children_, [&](auto& ptr) { return ptr.get() == old_child; });
DCHECK(it != children_.end());
old_child->SetParentSlim(nullptr);
old_child->SetLayerTree(nullptr);
if (new_child) {
WillAddChildSlim(new_child.get());
*it = std::move(new_child);
} else {
children_.erase(it);
NotifyPropertyChanged();
}
}
void Layer::RemoveFromParent() {
RemoveFromParentSlim();
}
void Layer::RemoveFromParentSlim() {
if (!parent_) {
return;
}
SetLayerTree(nullptr);
base::EraseIf(parent_->children_,
[&](auto& ptr) { return ptr.get() == this; });
parent_->NotifyPropertyChanged();
SetParentSlim(nullptr);
}
void Layer::RemoveAllChildren() {
if (children_.empty()) {
return;
}
for (auto& child : children_) {
child->SetLayerTree(nullptr);
child->SetParentSlim(nullptr);
}
children_.clear();
NotifySubtreeChanged();
}
bool Layer::HasAncestor(Layer* layer) const {
for (Layer* ancestor = parent_; ancestor; ancestor = ancestor->parent_) {
if (ancestor == layer) {
return true;
}
}
return false;
}
void Layer::SetParentSlim(Layer* parent) {
if (parent_ == parent) {
return;
}
int drawing_layers_in_subtree = GetNumDrawingLayersInSubtree();
if (parent_) {
parent_->ChangeDrawableDescendantsBySlim(0 - drawing_layers_in_subtree);
}
parent_ = parent;
if (parent_) {
parent_->ChangeDrawableDescendantsBySlim(drawing_layers_in_subtree);
}
}
void Layer::ChangeDrawableDescendantsBySlim(int num) {
DCHECK_GE(num_descendants_that_draw_content_ + num, 0);
if (!num) {
return;
}
num_descendants_that_draw_content_ += num;
if (parent_) {
parent_->ChangeDrawableDescendantsBySlim(num);
}
}
void Layer::SetPosition(const gfx::PointF& position) {
if (position_ == position) {
return;
}
position_ = position;
NotifySubtreeChanged();
}
void Layer::SetBounds(const gfx::Size& bounds) {
if (bounds_ == bounds) {
return;
}
bounds_ = bounds;
if (masks_to_bounds_) {
NotifySubtreeChanged();
} else {
NotifyPropertyChanged();
}
}
void Layer::SetTransform(const gfx::Transform& transform) {
CHECK(transform.Is2dTransform());
if (transform_ == transform) {
return;
}
transform_ = transform;
NotifySubtreeChanged();
}
void Layer::SetTransformOrigin(const gfx::Point3F& origin) {
if (transform_origin_ == origin) {
return;
}
transform_origin_ = origin;
NotifySubtreeChanged();
}
void Layer::SetIsDrawable(bool drawable) {
if (is_drawable_ == drawable) {
return;
}
is_drawable_ = drawable;
UpdateDrawsContent();
}
void Layer::SetBackgroundColor(SkColor4f color) {
if (background_color_ == color) {
return;
}
background_color_ = color;
NotifyPropertyChanged();
}
void Layer::SetContentsOpaque(bool opaque) {
if (contents_opaque_ == opaque) {
return;
}
contents_opaque_ = opaque;
NotifySubtreeChanged();
}
void Layer::SetOpacity(float opacity) {
DCHECK_GE(opacity, 0.f);
DCHECK_LE(opacity, 1.f);
if (opacity_ == opacity) {
return;
}
opacity_ = opacity;
NotifySubtreeChanged();
}
int Layer::NumDescendantsThatDrawContent() const {
return num_descendants_that_draw_content_;
}
void Layer::UpdateDrawsContent() {
bool value = HasDrawableContent();
if (draws_content_ == value) {
return;
}
draws_content_ = value;
if (parent_) {
parent_->ChangeDrawableDescendantsBySlim(value ? 1 : -1);
}
NotifyPropertyChanged();
}
void Layer::SetHideLayerAndSubtree(bool hide) {
if (hide_layer_and_subtree_ == hide) {
return;
}
hide_layer_and_subtree_ = hide;
NotifySubtreeChanged();
}
void Layer::SetMasksToBounds(bool masks_to_bounds) {
if (masks_to_bounds_ == masks_to_bounds) {
return;
}
masks_to_bounds_ = masks_to_bounds;
NotifySubtreeChanged();
}
void Layer::SetRoundedCorner(const gfx::RoundedCornersF& corner_radii) {
if (rounded_corners_ == corner_radii) {
return;
}
rounded_corners_ = corner_radii;
NotifySubtreeChanged();
}
void Layer::SetGradientMask(const gfx::LinearGradient& gradient_mask) {
if (gradient_mask_ == gradient_mask) {
return;
}
gradient_mask_ = gradient_mask;
NotifySubtreeChanged();
}
bool Layer::HasNonTrivialMaskFilterInfo() const {
return !rounded_corners_.IsEmpty() || !gradient_mask_.IsEmpty();
}
void Layer::SetFilters(std::vector<Filter> filters) {
if (filters_ == filters) {
return;
}
filters_ = std::move(filters);
NotifySubtreeChanged();
}
bool Layer::HasDrawableContent() const {
return is_drawable_;
}
gfx::Transform Layer::ComputeTransformToParent() const {
// Layer transform is:
// position x transform_origin x transform x -transform_origin
gfx::Transform transform =
gfx::Transform::MakeTranslation(position_.x(), position_.y());
transform.Translate3d(transform_origin_.x(), transform_origin_.y(),
transform_origin_.z());
transform.PreConcat(transform_);
transform.Translate3d(-transform_origin_.x(), -transform_origin_.y(),
-transform_origin_.z());
return transform;
}
std::optional<gfx::Transform> Layer::ComputeTransformFromParent() const {
// TODO(crbug.com/1408128): Consider caching this result since GetInverse
// may be expensive.
gfx::Transform inverse_transform;
if (!transform_.GetInverse(&inverse_transform)) {
return std::nullopt;
}
// TransformFromParent is:
// transform_origin x inverse_transform x -transform_origin x -position
gfx::Transform from_parent;
from_parent.Translate3d(transform_origin_.x(), transform_origin_.y(),
transform_origin_.z());
from_parent.PreConcat(inverse_transform);
from_parent.Translate3d(-transform_origin_.x(), -transform_origin_.y(),
-transform_origin_.z());
from_parent.Translate(-position_.x(), -position_.y());
return from_parent;
}
bool Layer::HasFilters() const {
return !filters_.empty();
}
cc::FilterOperations Layer::GetFilters() const {
return ToCcFilters(filters_);
}
int Layer::GetNumDrawingLayersInSubtree() const {
return num_descendants_that_draw_content_ + (draws_content_ ? 1 : 0);
}
bool Layer::GetAndResetPropertyChanged() {
bool changed = property_changed_;
property_changed_ = false;
return changed;
}
bool Layer::GetAndResetSubtreePropertyChanged() {
bool changed = subtree_property_changed_;
subtree_property_changed_ = false;
return changed;
}
void Layer::AppendQuads(viz::CompositorRenderPass& render_pass,
FrameData& data,
const gfx::Transform& transform_to_root,
const gfx::Transform& transform_to_target,
const gfx::Rect* clip_in_target,
const gfx::Rect& visible_rect,
float opacity) {}
viz::SharedQuadState* Layer::CreateAndAppendSharedQuadState(
viz::CompositorRenderPass& render_pass,
FrameData& data,
const gfx::Transform& transform_to_target,
const gfx::Rect* clip_in_target,
const gfx::Rect& visible_rect,
float opacity) {
viz::SharedQuadState* quad_state =
render_pass.CreateAndAppendSharedQuadState();
const gfx::Rect layer_rect{bounds()};
DCHECK(layer_rect.Contains(visible_rect));
std::optional<gfx::Rect> clip_opt;
if (clip_in_target) {
clip_opt = *clip_in_target;
}
quad_state->SetAll(transform_to_target, layer_rect, visible_rect,
data.mask_filter_info_in_target, clip_opt,
contents_opaque(), opacity, SkBlendMode::kSrcOver,
/*sorting_context=*/0,
/*layer_id=*/0u, /*fast_rounded_corner=*/false);
quad_state->is_fast_rounded_corner = true;
return quad_state;
}
void Layer::NotifySubtreeChanged() {
subtree_property_changed_ = true;
if (layer_tree_) {
static_cast<LayerTreeImpl*>(layer_tree_)->NotifyTreeChanged();
}
}
void Layer::NotifyPropertyChanged() {
property_changed_ = true;
if (layer_tree_) {
static_cast<LayerTreeImpl*>(layer_tree_)->NotifyTreeChanged();
}
}
} // namespace cc::slim