| // 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/layers/layer.h" |
| #include "cc/paint/filter_operation.h" |
| #include "cc/paint/filter_operations.h" |
| #include "cc/slim/features.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() { |
| scoped_refptr<cc::Layer> cc_layer; |
| if (!features::IsSlimCompositorEnabled()) { |
| cc_layer = cc::Layer::Create(); |
| } |
| return base::AdoptRef(new Layer(std::move(cc_layer))); |
| } |
| |
| Layer::Layer(scoped_refptr<cc::Layer> cc_layer) |
| : cc_layer_(std::move(cc_layer)), |
| id_(g_next_id.GetNext() + 1), |
| is_drawable_(false), |
| contents_opaque_(false), |
| draws_content_(false), |
| hide_layer_and_subtree_(false), |
| masks_to_bounds_(false) {} |
| |
| Layer::~Layer() { |
| RemoveAllChildren(); |
| } |
| |
| 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) { |
| if (cc_layer()) { |
| cc_layer()->AddChild(child->cc_layer()); |
| } |
| InsertChildSlim(std::move(child), children_.size()); |
| } |
| |
| void Layer::InsertChild(scoped_refptr<Layer> child, size_t position) { |
| if (cc_layer()) { |
| cc_layer()->InsertChild(child->cc_layer(), position); |
| } |
| InsertChildSlim(std::move(child), position); |
| } |
| |
| void Layer::InsertChildSlim(scoped_refptr<Layer> child, size_t position) { |
| WillAddChildSlim(child.get()); |
| const size_t index = std::min(position, children_.size()); |
| children_.insert(children_.begin() + index, std::move(child)); |
| NotifyTreeChanged(); |
| } |
| |
| void Layer::WillAddChildSlim(Layer* child) { |
| child->RemoveFromParentSlim(); |
| child->parent_ = this; |
| child->SetLayerTree(layer_tree()); |
| } |
| |
| void Layer::ReplaceChild(Layer* old_child, scoped_refptr<Layer> new_child) { |
| if (cc_layer()) { |
| cc_layer()->ReplaceChild(old_child->cc_layer(), |
| new_child ? new_child->cc_layer() : nullptr); |
| } |
| 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->parent_ = nullptr; |
| old_child->SetLayerTree(nullptr); |
| |
| if (new_child) { |
| WillAddChildSlim(new_child.get()); |
| *it = std::move(new_child); |
| } else { |
| children_.erase(it); |
| } |
| NotifyTreeChanged(); |
| } |
| |
| void Layer::RemoveFromParent() { |
| if (cc_layer()) { |
| cc_layer()->RemoveFromParent(); |
| } |
| RemoveFromParentSlim(); |
| } |
| |
| void Layer::RemoveFromParentSlim() { |
| if (!parent_) { |
| return; |
| } |
| |
| SetLayerTree(nullptr); |
| base::EraseIf(parent_->children_, |
| [&](auto& ptr) { return ptr.get() == this; }); |
| parent_->NotifyTreeChanged(); |
| parent_ = nullptr; |
| } |
| |
| void Layer::RemoveAllChildren() { |
| if (cc_layer()) { |
| cc_layer()->RemoveAllChildren(); |
| } |
| |
| if (children_.empty()) { |
| return; |
| } |
| |
| for (auto& child : children_) { |
| child->SetLayerTree(nullptr); |
| child->parent_ = nullptr; |
| } |
| children_.clear(); |
| NotifyTreeChanged(); |
| } |
| |
| bool Layer::HasAncestor(Layer* layer) const { |
| for (Layer* ancestor = parent_; ancestor; ancestor = ancestor->parent_) { |
| if (ancestor == layer) { |
| DCHECK(!cc_layer() || cc_layer()->HasAncestor(layer->cc_layer())); |
| return true; |
| } |
| } |
| DCHECK(!cc_layer() || !cc_layer()->HasAncestor(layer->cc_layer())); |
| return false; |
| } |
| |
| void Layer::SetPosition(const gfx::PointF& position) { |
| if (cc_layer()) { |
| cc_layer()->SetPosition(position); |
| return; |
| } |
| if (position_ == position) { |
| return; |
| } |
| position_ = position; |
| NotifyPropertyChanged(); |
| } |
| |
| const gfx::PointF Layer::position() const { |
| return cc_layer() ? cc_layer()->position() : position_; |
| } |
| |
| void Layer::SetBounds(const gfx::Size& bounds) { |
| if (cc_layer()) { |
| cc_layer()->SetBounds(bounds); |
| return; |
| } |
| if (bounds_ == bounds) { |
| return; |
| } |
| bounds_ = bounds; |
| NotifyPropertyChanged(); |
| } |
| |
| const gfx::Size& Layer::bounds() const { |
| return cc_layer() ? cc_layer()->bounds() : bounds_; |
| } |
| |
| void Layer::SetTransform(const gfx::Transform& transform) { |
| if (cc_layer()) { |
| cc_layer()->SetTransform(transform); |
| return; |
| } |
| if (transform_ == transform) { |
| return; |
| } |
| transform_ = transform; |
| NotifyPropertyChanged(); |
| } |
| |
| const gfx::Transform& Layer::transform() const { |
| return cc_layer() ? cc_layer()->transform() : transform_; |
| } |
| |
| void Layer::SetTransformOrigin(const gfx::Point3F& origin) { |
| if (cc_layer()) { |
| cc_layer()->SetTransformOrigin(origin); |
| return; |
| } |
| if (transform_origin_ == origin) { |
| return; |
| } |
| transform_origin_ = origin; |
| NotifyPropertyChanged(); |
| } |
| |
| gfx::Point3F Layer::transform_origin() const { |
| return cc_layer() ? cc_layer()->transform_origin() : transform_origin_; |
| } |
| |
| void Layer::SetIsDrawable(bool drawable) { |
| if (cc_layer()) { |
| cc_layer()->SetIsDrawable(drawable); |
| return; |
| } |
| if (is_drawable_ == drawable) { |
| return; |
| } |
| is_drawable_ = drawable; |
| SetDrawsContent(HasDrawableContent()); |
| } |
| |
| void Layer::SetBackgroundColor(SkColor4f color) { |
| if (cc_layer()) { |
| cc_layer()->SetBackgroundColor(color); |
| return; |
| } |
| if (background_color_ == color) { |
| return; |
| } |
| background_color_ = color; |
| NotifyPropertyChanged(); |
| } |
| |
| SkColor4f Layer::background_color() const { |
| return cc_layer() ? cc_layer()->background_color() : background_color_; |
| } |
| |
| void Layer::SetContentsOpaque(bool opaque) { |
| if (cc_layer()) { |
| cc_layer()->SetContentsOpaque(opaque); |
| return; |
| } |
| if (contents_opaque_ == opaque) { |
| return; |
| } |
| contents_opaque_ = opaque; |
| NotifyPropertyChanged(); |
| } |
| |
| bool Layer::contents_opaque() const { |
| return cc_layer() ? cc_layer()->contents_opaque() : contents_opaque_; |
| } |
| |
| void Layer::SetOpacity(float opacity) { |
| if (cc_layer()) { |
| cc_layer()->SetOpacity(opacity); |
| return; |
| } |
| if (opacity_ == opacity) { |
| return; |
| } |
| opacity_ = opacity; |
| NotifyPropertyChanged(); |
| } |
| |
| float Layer::opacity() const { |
| return cc_layer() ? cc_layer()->opacity() : opacity_; |
| } |
| |
| bool Layer::draws_content() const { |
| return cc_layer() ? cc_layer()->draws_content() : draws_content_; |
| } |
| |
| void Layer::SetDrawsContent(bool value) { |
| if (cc_layer()) { |
| cc_layer()->SetDrawsContent(value); |
| return; |
| } |
| if (draws_content_ == value) { |
| return; |
| } |
| draws_content_ = value; |
| NotifyPropertyChanged(); |
| } |
| |
| void Layer::SetHideLayerAndSubtree(bool hide) { |
| if (cc_layer()) { |
| cc_layer()->SetHideLayerAndSubtree(hide); |
| return; |
| } |
| if (hide_layer_and_subtree_ == hide) { |
| return; |
| } |
| hide_layer_and_subtree_ = hide; |
| NotifyPropertyChanged(); |
| } |
| |
| bool Layer::hide_layer_and_subtree() const { |
| return cc_layer() ? cc_layer()->hide_layer_and_subtree() |
| : hide_layer_and_subtree_; |
| } |
| |
| void Layer::SetMasksToBounds(bool masks_to_bounds) { |
| if (cc_layer()) { |
| cc_layer()->SetMasksToBounds(masks_to_bounds); |
| return; |
| } |
| if (masks_to_bounds_ == masks_to_bounds) { |
| return; |
| } |
| masks_to_bounds_ = masks_to_bounds; |
| NotifyPropertyChanged(); |
| } |
| |
| bool Layer::masks_to_bounds() const { |
| return cc_layer() ? cc_layer()->masks_to_bounds() : masks_to_bounds_; |
| } |
| |
| void Layer::SetFilters(std::vector<Filter> filters) { |
| if (cc_layer()) { |
| cc_layer()->SetFilters(ToCcFilters(std::move(filters))); |
| return; |
| } |
| if (filters_ == filters) { |
| return; |
| } |
| filters_ = std::move(filters); |
| NotifyPropertyChanged(); |
| } |
| |
| bool Layer::HasDrawableContent() const { |
| return is_drawable_; |
| } |
| |
| gfx::Transform Layer::ComputeTransformToParent() { |
| // 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; |
| } |
| |
| void Layer::AppendQuads(viz::CompositorRenderPass& render_pass, |
| const gfx::Transform& transform, |
| const gfx::Rect* clip) {} |
| |
| void Layer::NotifyTreeChanged() { |
| if (cc_layer()) { |
| return; |
| } |
| if (layer_tree_) { |
| static_cast<LayerTreeImpl*>(layer_tree_)->NotifyTreeChanged(); |
| } |
| } |
| |
| void Layer::NotifyPropertyChanged() { |
| DCHECK(!cc_layer()); |
| if (layer_tree_) { |
| static_cast<LayerTreeImpl*>(layer_tree_)->NotifyPropertyChanged(); |
| } |
| } |
| |
| viz::SharedQuadState* Layer::CreateAndAppendSharedQuadState( |
| viz::CompositorRenderPass& render_pass, |
| const gfx::Transform& transform, |
| const gfx::Rect* clip) { |
| viz::SharedQuadState* quad_state = |
| render_pass.CreateAndAppendSharedQuadState(); |
| const gfx::Rect rect{bounds()}; |
| absl::optional<gfx::Rect> clip_opt; |
| if (clip) { |
| clip_opt = *clip; |
| } |
| // TODO(crbug.com/1408128): Set visible_layer_rect properly. |
| quad_state->SetAll(transform, /*layer_rect=*/rect, |
| /*visible_layer_rect=*/rect, gfx::MaskFilterInfo(), |
| std::move(clip_opt), contents_opaque(), opacity(), |
| SkBlendMode::kSrcOver, 0); |
| return quad_state; |
| } |
| |
| } // namespace cc::slim |