#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/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;
}
}
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),
property_changed_(false),
subtree_property_changed_(false) {}
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) {
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) {
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 (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->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() {
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_->NotifyPropertyChanged();
SetParentSlim(nullptr);
}
void Layer::RemoveAllChildren() {
if (cc_layer()) {
cc_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) {
DCHECK(!cc_layer() || cc_layer()->HasAncestor(layer->cc_layer()));
return true;
}
}
DCHECK(!cc_layer() || !cc_layer()->HasAncestor(layer->cc_layer()));
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 (cc_layer()) {
cc_layer()->SetPosition(position);
return;
}
if (position_ == position) {
return;
}
position_ = position;
NotifySubtreeChanged();
}
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;
if (masks_to_bounds_) {
NotifySubtreeChanged();
} else {
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;
}
CHECK(transform.Is2dTransform());
if (transform_ == transform) {
return;
}
transform_ = transform;
NotifySubtreeChanged();
}
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;
NotifySubtreeChanged();
}
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;
UpdateDrawsContent();
}
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;
NotifySubtreeChanged();
}
bool Layer::contents_opaque() const {
return cc_layer() ? cc_layer()->contents_opaque() : contents_opaque_;
}
void Layer::SetOpacity(float opacity) {
DCHECK_GE(opacity, 0.f);
DCHECK_LE(opacity, 1.f);
if (cc_layer()) {
cc_layer()->SetOpacity(opacity);
return;
}
if (opacity_ == opacity) {
return;
}
opacity_ = opacity;
NotifySubtreeChanged();
}
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_;
}
int Layer::NumDescendantsThatDrawContent() const {
if (cc_layer()) {
return cc_layer()->NumDescendantsThatDrawContent();
}
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 (cc_layer()) {
cc_layer()->SetHideLayerAndSubtree(hide);
return;
}
if (hide_layer_and_subtree_ == hide) {
return;
}
hide_layer_and_subtree_ = hide;
NotifySubtreeChanged();
}
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;
NotifySubtreeChanged();
}
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);
NotifySubtreeChanged();
}
bool Layer::HasDrawableContent() const {
return is_drawable_;
}
gfx::Transform Layer::ComputeTransformToParent() const {
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;
}
absl::optional<gfx::Transform> Layer::ComputeTransformFromParent() const {
gfx::Transform inverse_transform;
if (!transform_.GetInverse(&inverse_transform)) {
return absl::nullopt;
}
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,
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));
absl::optional<gfx::Rect> clip_opt;
if (clip_in_target) {
clip_opt = *clip_in_target;
}
quad_state->SetAll(transform_to_target, layer_rect, visible_rect,
gfx::MaskFilterInfo(), clip_opt, contents_opaque(),
opacity, SkBlendMode::kSrcOver, 0);
return quad_state;
}
void Layer::NotifySubtreeChanged() {
if (cc_layer()) {
return;
}
subtree_property_changed_ = true;
if (layer_tree_) {
static_cast<LayerTreeImpl*>(layer_tree_)->NotifyTreeChanged();
}
}
void Layer::NotifyPropertyChanged() {
if (cc_layer()) {
return;
}
property_changed_ = true;
if (layer_tree_) {
static_cast<LayerTreeImpl*>(layer_tree_)->NotifyTreeChanged();
}
}
}