#include "cc/layers/layer.h"
#include <stddef.h>
#include <stdint.h>
#include <algorithm>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include "base/atomic_sequence_num.h"
#include "base/location.h"
#include "base/memory/raw_ptr.h"
#include "base/metrics/histogram.h"
#include "base/notreached.h"
#include "base/strings/stringprintf.h"
#include "base/task/single_thread_task_runner.h"
#include "base/time/time.h"
#include "base/trace_event/trace_event.h"
#include "cc/base/features.h"
#include "cc/base/simple_enclosed_region.h"
#include "cc/layers/layer_impl.h"
#include "cc/layers/picture_layer.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/draw_property_utils.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/mutator_host.h"
#include "cc/trees/property_tree_builder.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
#include "components/viz/common/frame_sinks/copy_output_request.h"
#include "components/viz/common/frame_sinks/copy_output_result.h"
#include "components/viz/common/view_transition_element_resource_id.h"
#include "third_party/skia/include/core/SkImageFilter.h"
#include "ui/gfx/geometry/rect_conversions.h"
#include "ui/gfx/geometry/vector2d_conversions.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "base/debug/dump_without_crashing.h"
#endif
namespace cc {
struct SameSizeAsLayer : public base::RefCounted<SameSizeAsLayer>,
public ProtectedSequenceSynchronizer {
private:
SameSizeAsLayer();
~SameSizeAsLayer() override;
raw_ptr<void> raw_pointers[2];
std::unique_ptr<void> unique_pointers[2];
struct {
LayerList children;
gfx::Size bounds;
HitTestOpaqueness hit_test_opaqueness;
bool bitfields;
SkColor4f background_color;
TouchActionRegion touch_action_region;
ElementId element_id;
std::unique_ptr<void> rare_inputs;
} inputs;
gfx::Rect update_rect;
int int_fields[7];
gfx::Vector2dF offset;
bool bool_fields[2];
#if DCHECK_IS_ON()
bool allow_remove_for_readd;
#endif
std::unique_ptr<LayerUtils> layer_utils_;
#if BUILDFLAG(ARKWEB_CUSTOM_VIDEO_PLAYER)
bool should_overlay_;
#endif
uint8_t bit_fields[2];
#if BUILDFLAG(IS_CHROMEOS)
bool is_valid_to_destroy_;
#endif
#if BUILDFLAG(IS_ARKWEB) && defined(__arm__)
char dummy[8];
#endif
};
static_assert(sizeof(Layer) == sizeof(SameSizeAsLayer),
"Layer should stay small");
base::AtomicSequenceNumber g_next_layer_id;
constexpr gfx::Transform Layer::kIdentityTransform;
constexpr gfx::RoundedCornersF Layer::kNoRoundedCornersF;
LayerDebugInfo::LayerDebugInfo() = default;
LayerDebugInfo::LayerDebugInfo(const LayerDebugInfo&) = default;
LayerDebugInfo::~LayerDebugInfo() = default;
Layer::RareInputs::RareInputs() = default;
Layer::RareInputs::~RareInputs() = default;
Layer::Inputs::Inputs() = default;
Layer::Inputs::~Inputs() = default;
Layer::LayerTreeInputs::LayerTreeInputs() = default;
Layer::LayerTreeInputs::~LayerTreeInputs() = default;
int Layer::GetNextLayerId() {
return g_next_layer_id.GetNext() + 1;
}
scoped_refptr<Layer> Layer::Create() {
return base::WrapRefCounted(new Layer());
}
Layer::Layer()
: parent_(nullptr),
layer_tree_host_(nullptr),
layer_id_(GetNextLayerId()),
num_descendants_that_draw_content_(0),
transform_tree_index_(kInvalidPropertyNodeId),
effect_tree_index_(kInvalidPropertyNodeId),
clip_tree_index_(kInvalidPropertyNodeId),
scroll_tree_index_(kInvalidPropertyNodeId),
property_tree_sequence_number_(-1),
ignore_set_needs_commit_for_test_(false),
subtree_property_changed_(false),
bitflags_(0u),
changed_properties_(0u) {
layer_utils_ = std::make_unique<LayerUtils>(this);
}
Layer::~Layer() {
DCHECK(!parent());
DCHECK(!layer_tree_host());
RemoveAllChildren();
#if BUILDFLAG(IS_CHROMEOS)
DCHECK(is_valid_to_destroy_);
if (!is_valid_to_destroy_) {
base::debug::DumpWithoutCrashing();
}
#endif
}
Layer::LayerTreeInputs& Layer::EnsureLayerTreeInputs() {
DCHECK(!IsAttached() || !IsUsingLayerLists());
auto& layer_tree_inputs = layer_tree_inputs_.Write(*this);
if (!layer_tree_inputs)
layer_tree_inputs = std::make_unique<LayerTreeInputs>();
return *layer_tree_inputs;
}
#if DCHECK_IS_ON()
const Layer::LayerTreeInputs* Layer::layer_tree_inputs() const {
DCHECK(!IsAttached() || !IsUsingLayerLists());
return layer_tree_inputs_.Read(*this);
}
#endif
void Layer::SetLayerTreeHost(LayerTreeHost* host) {
DCHECK(IsPropertyChangeAllowed());
if (layer_tree_host() == host)
return;
bool property_tree_indices_invalid = false;
auto& inputs = inputs_.Write(*this);
ElementId element_id = inputs.element_id;
if (IsAttached()) {
DCHECK(IsOwnerThread());
layer_tree_host()->WaitForProtectedSequenceCompletion();
layer_tree_host()->UnregisterLayer(this);
if (element_id)
layer_tree_host()->UnregisterElement(element_id, this);
if (!IsUsingLayerLists()) {
layer_tree_host()->property_trees()->set_needs_rebuild(true);
property_tree_indices_invalid = true;
}
}
if (host) {
host->RegisterLayer(this);
if (element_id)
host->RegisterElement(element_id, this);
if (!host->IsUsingLayerLists()) {
host->property_trees()->set_needs_rebuild(true);
property_tree_indices_invalid = true;
}
}
const_cast<raw_ptr<LayerTreeHost>&>(layer_tree_host_) = host;
if (host) {
changed_properties_.Write(*this) |= kChangedAllProperties;
host->AddLayerShouldPushProperties(this);
}
if (property_tree_indices_invalid)
InvalidatePropertyTreesIndices();
for (auto child : inputs.children)
child->SetLayerTreeHost(host);
if (host && !host->IsUsingLayerLists() &&
host->mutator_host()->IsElementAnimating(element_id)) {
host->SetNeedsCommit();
}
}
void Layer::SetNeedsCommit() {
if (!IsAttached())
return;
SetNeedsPushProperties();
if (ignore_set_needs_commit_for_test_.Read(*this))
return;
layer_tree_host()->SetNeedsCommit();
}
void Layer::SetDebugName(std::string name) {
if (!name.empty() || debug_info_.Read(*this)) {
EnsureDebugInfo().name = std::move(name);
}
}
viz::ViewTransitionElementResourceId Layer::ViewTransitionResourceId() const {
return viz::ViewTransitionElementResourceId();
}
bool Layer::IsSolidColorLayerForTesting() const {
return false;
}
void Layer::SetNeedsFullTreeSync() {
if (!IsAttached())
return;
layer_tree_host()->SetNeedsFullTreeSync();
}
void Layer::SetNeedsPushProperties(uint8_t changed_props) {
uint8_t& changed = changed_properties_.Write(*this);
if (!::features::IsCCSlimmingEnabled()) {
changed_props = kChangedAllProperties;
}
if ((changed & changed_props) != changed_props) {
if (!changed && IsAttached()) {
layer_tree_host()->AddLayerShouldPushProperties(this);
}
changed |= changed_props;
}
}
bool Layer::IsPropertyChangeAllowed() const {
if (!IsAttached())
return true;
DCHECK(IsMainThread());
return !layer_tree_host()->in_paint_layer_contents();
}
void Layer::CaptureContent(const gfx::Rect& rect,
std::vector<NodeInfo>* content) const {}
sk_sp<const SkPicture> Layer::GetPicture() const {
return nullptr;
}
void Layer::SetParent(Layer* layer, RemovalReason reason) {
DCHECK(!layer || !layer->HasAncestor(this));
DCHECK(reason == RemovalReason::kNormal || !layer);
raw_ptr<Layer>& parent = parent_.Write(*this);
parent = layer;
if (reason == RemovalReason::kForReadd) {
#if DCHECK_IS_ON()
DCHECK(allow_remove_for_readd_);
#endif
} else {
SetLayerTreeHost(parent ? parent->layer_tree_host() : nullptr);
}
SetPropertyTreesNeedRebuild();
}
void Layer::AddChild(scoped_refptr<Layer> child) {
InsertChild(child, inputs_.Read(*this).children.size());
}
void Layer::InsertChild(scoped_refptr<Layer> child, size_t index) {
DCHECK(IsPropertyChangeAllowed());
AllowRemoveForReadd allow(child.get());
child->RemoveFromParentForReadd();
AddDrawableDescendants(child->NumDescendantsThatDrawContent() +
(child->draws_content() ? 1 : 0));
child->SetParent(this, RemovalReason::kNormal);
child->SetSubtreePropertyChanged();
auto& inputs = inputs_.Write(*this);
index = std::min(index, inputs.children.size());
const auto* layer_tree_inputs = layer_tree_inputs_.Read(*this);
if (layer_tree_inputs && layer_tree_inputs->mask_layer && index &&
index == inputs.children.size()) {
DCHECK_EQ(mask_layer(), inputs.children.back().get());
index--;
}
inputs.children.insert(inputs.children.begin() + index, child);
SetNeedsFullTreeSync();
}
void Layer::RemoveFromParent() {
DCHECK(IsPropertyChangeAllowed());
if (parent_.Read(*this))
parent_.Write(*this)->RemoveChild(this, RemovalReason::kNormal);
}
void Layer::RemoveFromParentForReadd() {
DCHECK(IsPropertyChangeAllowed());
if (parent_.Read(*this))
parent_.Write(*this)->RemoveChild(this, RemovalReason::kForReadd);
}
void Layer::RemoveChild(Layer* child, RemovalReason reason) {
const auto* layer_tree_inputs = layer_tree_inputs_.Read(*this);
if (layer_tree_inputs && child == layer_tree_inputs->mask_layer)
layer_tree_inputs_.Write(*this)->mask_layer = nullptr;
auto& inputs = inputs_.Write(*this);
for (auto iter = inputs.children.begin(); iter != inputs.children.end();
++iter) {
if (iter->get() != child)
continue;
child->SetParent(nullptr, reason);
AddDrawableDescendants(-child->NumDescendantsThatDrawContent() -
(child->draws_content() ? 1 : 0));
inputs.children.erase(iter);
SetNeedsFullTreeSync();
return;
}
}
bool Layer::GetBitFlag(uint8_t mask) const {
return bitflags_.Read(*this) & mask;
}
bool Layer::SetBitFlag(bool new_value,
uint8_t mask,
bool invalidate,
bool needs_push) {
if (GetBitFlag(mask) == new_value)
return false;
if (new_value)
bitflags_.Write(*this) |= mask;
else
bitflags_.Write(*this) &= ~mask;
if (invalidate) {
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
if (needs_push)
SetNeedsPushProperties();
return true;
}
void Layer::ReorderChildren(LayerList* new_children_order) {
auto& inputs = inputs_.Write(*this);
#if DCHECK_IS_ON()
base::flat_set<Layer*> children_set;
for (const auto& child : *new_children_order) {
DCHECK_EQ(child->parent(), this);
children_set.insert(child.get());
}
for (const auto& child : inputs.children)
DCHECK_GT(children_set.count(child.get()), 0u);
#endif
inputs.children = std::move(*new_children_order);
for (const auto& child : inputs.children)
child->subtree_property_changed_.Write(*child) = true;
SetNeedsFullTreeSync();
}
void Layer::ReplaceChild(Layer* reference, scoped_refptr<Layer> new_layer) {
DCHECK(reference);
DCHECK_EQ(reference->parent(), this);
DCHECK(IsPropertyChangeAllowed());
if (reference == new_layer.get())
return;
auto& inputs = inputs_.Write(*this);
auto reference_it =
std::ranges::find(inputs.children, reference, &scoped_refptr<Layer>::get);
CHECK(reference_it != inputs.children.end());
size_t reference_index = reference_it - inputs.children.begin();
reference->RemoveFromParent();
if (new_layer.get()) {
InsertChild(new_layer, reference_index);
}
}
void Layer::SetBounds(const gfx::Size& size) {
DCHECK(IsPropertyChangeAllowed());
if (bounds() == size)
return;
inputs_.Write(*this).bounds = size;
if (!IsAttached())
return;
if (!IsUsingLayerLists()) {
if (subtree_capture_id().is_valid() || masks_to_bounds() || mask_layer() ||
HasMaskFilter()) {
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
}
if (scrollable()) {
auto& scroll_tree =
layer_tree_host()->property_trees()->scroll_tree_mutable();
if (auto* scroll_node = scroll_tree.Node(scroll_tree_index_.Read(*this)))
scroll_node->bounds = inputs_.Read(*this).bounds;
else
SetPropertyTreesNeedRebuild();
}
}
SetNeedsCommit();
}
Layer* Layer::RootLayer() {
Layer* layer = this;
while (layer->parent())
layer = layer->mutable_parent();
return layer;
}
void Layer::RemoveAllChildren() {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = inputs_.Write(*this);
while (inputs.children.size()) {
Layer* layer = inputs.children[0].get();
DCHECK_EQ(this, layer->parent());
layer->RemoveFromParent();
}
}
void Layer::SetChildLayerList(LayerList new_children) {
DCHECK(IsUsingLayerLists());
if (children() == new_children)
return;
{
std::unordered_set<Layer*> children_to_remove;
for (auto& existing_child : children())
children_to_remove.insert(existing_child.get());
for (auto& new_child : new_children)
children_to_remove.erase(new_child.get());
for (auto* child : children_to_remove) {
child->SetParent(nullptr, RemovalReason::kNormal);
AddDrawableDescendants(-child->NumDescendantsThatDrawContent() -
(child->draws_content() ? 1 : 0));
}
}
auto existing_child_it = children().begin();
for (auto& child : new_children) {
if (child->parent() == this) {
existing_child_it = std::find(existing_child_it, children().end(), child);
if (existing_child_it == children().end())
child->SetSubtreePropertyChanged();
}
}
for (auto& child : new_children) {
if (child->parent() != this) {
AllowRemoveForReadd allow(child.get());
child->RemoveFromParentForReadd();
AddDrawableDescendants(child->NumDescendantsThatDrawContent() +
(child->draws_content() ? 1 : 0));
child->SetParent(this, RemovalReason::kNormal);
child->SetSubtreePropertyChanged();
}
}
inputs_.Write(*this).children = std::move(new_children);
layer_tree_host()->SetNeedsFullTreeSync();
}
bool Layer::HasAncestor(const Layer* ancestor) const {
for (const Layer* layer = parent(); layer; layer = layer->parent()) {
if (layer == ancestor)
return true;
}
return false;
}
void Layer::RequestCopyOfOutput(
std::unique_ptr<viz::CopyOutputRequest> request) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (request->has_source()) {
const base::UnguessableToken& source = request->source();
auto it = std::ranges::find_if(
inputs.copy_requests,
[&source](const std::unique_ptr<viz::CopyOutputRequest>& x) {
return x->has_source() && x->source() == source;
});
if (it != inputs.copy_requests.end())
inputs.copy_requests.erase(it);
}
inputs.copy_requests.push_back(std::move(request));
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
if (IsAttached())
layer_tree_host()->SetHasCopyRequest(true);
}
void Layer::SetBackgroundColor(SkColor4f background_color) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = inputs_.Write(*this);
if (inputs.background_color == background_color)
return;
inputs.background_color = background_color;
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
void Layer::SetSafeOpaqueBackgroundColor(SkColor4f background_color) {
DCHECK(IsPropertyChangeAllowed());
SkColor4f opaque_color = background_color.makeOpaque();
auto& inputs = EnsureLayerTreeInputs();
if (inputs.safe_opaque_background_color == opaque_color)
return;
inputs.safe_opaque_background_color = opaque_color;
SetNeedsPushProperties();
}
SkColor4f Layer::SafeOpaqueBackgroundColor() const {
if (contents_opaque()) {
if (!IsUsingLayerLists()) {
DCHECK(layer_tree_inputs());
DCHECK(layer_tree_inputs()->safe_opaque_background_color.isOpaque());
return layer_tree_inputs()->safe_opaque_background_color;
}
return background_color().makeOpaque();
}
if (background_color().isOpaque()) {
return SkColors::kTransparent;
}
return background_color();
}
void Layer::SetMasksToBounds(bool masks_to_bounds) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.masks_to_bounds == masks_to_bounds)
return;
inputs.masks_to_bounds = masks_to_bounds;
SetNeedsCommit();
SetPropertyTreesNeedRebuild();
SetSubtreePropertyChanged();
}
void Layer::SetClipRect(const gfx::Rect& clip_rect) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.clip_rect == clip_rect)
return;
inputs.clip_rect = clip_rect;
const bool force_rebuild = clip_rect.IsEmpty() || !has_clip_node();
SetSubtreePropertyChanged();
if (clip_tree_index() != kInvalidPropertyNodeId && !force_rebuild) {
PropertyTrees* property_trees = layer_tree_host()->property_trees();
gfx::RectF effective_clip_rect = EffectiveClipRect();
if (ClipNode* node =
property_trees->clip_tree_mutable().Node(clip_tree_index())) {
node->clip = effective_clip_rect;
node->clip += offset_to_transform_parent();
property_trees->clip_tree_mutable().set_needs_update(true);
}
if (HasMaskFilter() && effect_tree_index() != kInvalidPropertyNodeId) {
if (EffectNode* node =
property_trees->effect_tree_mutable().Node(effect_tree_index())) {
node->mask_filter_info = gfx::MaskFilterInfo(
effective_clip_rect, corner_radii(), gradient_mask());
node->effect_changed = true;
property_trees->effect_tree_mutable().set_needs_update(true);
}
}
} else {
SetPropertyTreesNeedRebuild();
}
SetNeedsCommit();
}
gfx::RectF Layer::EffectiveClipRect() const {
const gfx::RectF layer_bounds = gfx::RectF(gfx::SizeF(bounds()));
if (clip_rect().IsEmpty())
return layer_bounds;
const gfx::RectF clip_rect_f(clip_rect());
if (masks_to_bounds() || mask_layer() || filters().HasFilterThatMovesPixels())
return gfx::IntersectRects(layer_bounds, clip_rect_f);
return clip_rect_f;
}
void Layer::SetMaskLayer(scoped_refptr<PictureLayer> mask_layer) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.mask_layer.get() == mask_layer)
return;
if (inputs.mask_layer) {
DCHECK_EQ(this, inputs.mask_layer->parent());
inputs.mask_layer->RemoveFromParent();
}
inputs.mask_layer = nullptr;
if (mask_layer) {
DCHECK(mask_layer->children().empty());
mask_layer->EnsureLayerTreeInputs().position = gfx::PointF();
mask_layer->SetIsDrawable(true);
mask_layer->SetBlendMode(SkBlendMode::kDstIn);
mask_layer->SetIsBackdropFilterMask(false);
AddChild(mask_layer);
}
inputs.mask_layer = mask_layer.get();
SetSubtreePropertyChanged();
}
void Layer::SetFilters(const FilterOperations& filters) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.filters == filters)
return;
inputs.filters = filters;
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
void Layer::SetBackdropFilters(const FilterOperations& filters) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.backdrop_filters == filters)
return;
inputs.backdrop_filters = filters;
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
void Layer::SetBackdropFilterBounds(const SkPath& backdrop_filter_bounds) {
EnsureLayerTreeInputs().backdrop_filter_bounds = backdrop_filter_bounds;
}
void Layer::ClearBackdropFilterBounds() {
if (layer_tree_inputs())
layer_tree_inputs_.Write(*this)->backdrop_filter_bounds.reset();
}
void Layer::SetBackdropFilterQuality(const float quality) {
EnsureLayerTreeInputs().backdrop_filter_quality = quality;
}
void Layer::UpdateMaskFilterInfo(const gfx::RoundedCornersF* corner_radii,
const gfx::LinearGradient* gradient_mask) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (corner_radii)
inputs.corner_radii = *corner_radii;
if (gradient_mask)
inputs.gradient_mask = *gradient_mask;
SetSubtreePropertyChanged();
SetNeedsCommit();
PropertyTrees* property_trees =
IsAttached() ? layer_tree_host()->property_trees() : nullptr;
EffectNode* node = nullptr;
if (property_trees && effect_tree_index() != kInvalidPropertyNodeId &&
(node =
property_trees->effect_tree_mutable().Node(effect_tree_index()))) {
gfx::RectF effective_clip_rect = EffectiveClipRect();
effective_clip_rect += offset_to_transform_parent();
node->mask_filter_info = gfx::MaskFilterInfo(
effective_clip_rect, inputs.corner_radii, inputs.gradient_mask);
node->effect_changed = true;
property_trees->effect_tree_mutable().set_needs_update(true);
} else {
SetPropertyTreesNeedRebuild();
}
}
void Layer::SetRoundedCorner(const gfx::RoundedCornersF& corner_radii) {
if (EnsureLayerTreeInputs().corner_radii == corner_radii)
return;
UpdateMaskFilterInfo(&corner_radii, nullptr);
}
void Layer::SetGradientMask(const gfx::LinearGradient& gradient_mask) {
if (EnsureLayerTreeInputs().gradient_mask == gradient_mask)
return;
UpdateMaskFilterInfo(nullptr, &gradient_mask);
}
void Layer::SetIsFastRoundedCorner(bool enable) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.is_fast_rounded_corner == enable)
return;
inputs.is_fast_rounded_corner = enable;
if (!HasRoundedCorner())
return;
SetSubtreePropertyChanged();
SetNeedsCommit();
SetPropertyTreesNeedRebuild();
}
void Layer::SetOpacity(float opacity) {
DCHECK(IsPropertyChangeAllowed());
DCHECK_GE(opacity, 0.f);
DCHECK_LE(opacity, 1.f);
auto& inputs = EnsureLayerTreeInputs();
if (inputs.opacity == opacity)
return;
bool force_rebuild = opacity == 1.f || inputs.opacity == 1.f;
inputs.opacity = opacity;
SetSubtreePropertyChanged();
if (IsAttached()) {
if (!force_rebuild) {
PropertyTrees* property_trees = layer_tree_host()->property_trees();
if (EffectNode* node =
property_trees->effect_tree_mutable().Node(effect_tree_index())) {
node->opacity = opacity;
node->effect_changed = true;
property_trees->effect_tree_mutable().set_needs_update(true);
}
} else {
SetPropertyTreesNeedRebuild();
}
}
SetNeedsCommit();
}
float Layer::EffectiveOpacity() const {
if (!layer_tree_inputs())
return 1.0f;
return layer_tree_inputs()->hide_layer_and_subtree
? 0.f
: layer_tree_inputs()->opacity;
}
bool Layer::OpacityCanAnimateOnImplThread() const {
return false;
}
void Layer::SetBlendMode(SkBlendMode blend_mode) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.blend_mode == blend_mode)
return;
switch (blend_mode) {
case SkBlendMode::kSrcOver:
case SkBlendMode::kDstIn:
case SkBlendMode::kScreen:
case SkBlendMode::kOverlay:
case SkBlendMode::kDarken:
case SkBlendMode::kLighten:
case SkBlendMode::kColorDodge:
case SkBlendMode::kColorBurn:
case SkBlendMode::kHardLight:
case SkBlendMode::kSoftLight:
case SkBlendMode::kDifference:
case SkBlendMode::kExclusion:
case SkBlendMode::kMultiply:
case SkBlendMode::kHue:
case SkBlendMode::kSaturation:
case SkBlendMode::kColor:
case SkBlendMode::kLuminosity:
break;
case SkBlendMode::kClear:
case SkBlendMode::kSrc:
case SkBlendMode::kDst:
case SkBlendMode::kDstOver:
case SkBlendMode::kSrcIn:
case SkBlendMode::kSrcOut:
case SkBlendMode::kDstOut:
case SkBlendMode::kSrcATop:
case SkBlendMode::kDstATop:
case SkBlendMode::kXor:
case SkBlendMode::kPlus:
case SkBlendMode::kModulate:
NOTREACHED();
}
inputs.blend_mode = blend_mode;
SetNeedsCommit();
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
}
void Layer::SetHitTestOpaqueness(HitTestOpaqueness opaqueness) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = inputs_.Write(*this);
if (inputs.hit_test_opaqueness == opaqueness) {
return;
}
inputs.hit_test_opaqueness = opaqueness;
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
void Layer::SetHitTestable(bool hit_testable) {
SetHitTestOpaqueness(hit_testable ? HitTestOpaqueness::kMixed
: HitTestOpaqueness::kTransparent);
}
void Layer::SetContentsOpaque(bool opaque) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.Read(*this).contents_opaque == opaque)
return;
auto& inputs = inputs_.Write(*this);
inputs.contents_opaque = opaque;
inputs.contents_opaque_for_text = opaque;
SetNeedsCommit();
SetSubtreePropertyChanged();
SetPropertyTreesNeedRebuild();
}
void Layer::SetContentsOpaqueForText(bool opaque) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.Read(*this).contents_opaque_for_text == opaque)
return;
DCHECK(!contents_opaque() || opaque);
inputs_.Write(*this).contents_opaque_for_text = opaque;
SetNeedsCommit();
}
void Layer::SetPosition(const gfx::PointF& position) {
DCHECK(!IsAttached() || !IsUsingLayerLists());
if (parent() && parent()->mask_layer() == this) {
DCHECK(this->position().IsOrigin());
return;
}
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.position == position)
return;
inputs.position = position;
if (!IsAttached())
return;
SetSubtreePropertyChanged();
if (has_transform_node()) {
TransformNode* transform_node =
layer_tree_host()->property_trees()->transform_tree_mutable().Node(
transform_tree_index_.Read(*this));
DCHECK(parent());
transform_node->post_translation =
position.OffsetFromOrigin() + parent()->offset_to_transform_parent();
transform_node->needs_local_transform_update = true;
transform_node->SetTransformChanged(DamageReason::kUntracked);
layer_tree_host()
->property_trees()
->transform_tree_mutable()
.set_needs_update(true);
} else {
SetPropertyTreesNeedRebuild();
}
SetNeedsCommit();
}
bool Are2dAxisAligned(const gfx::Transform& a, const gfx::Transform& b) {
if (a.IsScaleOrTranslation() && b.IsScaleOrTranslation()) {
return true;
}
gfx::Transform inverse;
if (b.GetInverse(&inverse)) {
inverse *= a;
return inverse.Preserves2dAxisAlignment();
} else {
return a.Preserves2dAxisAlignment();
}
}
void Layer::SetTransform(const gfx::Transform& transform) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.transform == transform)
return;
SetSubtreePropertyChanged();
if (IsAttached()) {
if (has_transform_node()) {
TransformNode* transform_node =
layer_tree_host()->property_trees()->transform_tree_mutable().Node(
transform_tree_index_.Read(*this));
DCHECK_EQ(transform_tree_index(), transform_node->id);
bool preserves_2d_axis_alignment =
Are2dAxisAligned(inputs.transform, transform);
transform_node->local = transform;
transform_node->needs_local_transform_update = true;
transform_node->SetTransformChanged(DamageReason::kUntracked);
layer_tree_host()
->property_trees()
->transform_tree_mutable()
.set_needs_update(true);
if (!preserves_2d_axis_alignment)
SetPropertyTreesNeedRebuild();
} else {
SetPropertyTreesNeedRebuild();
}
}
inputs.transform = transform;
SetNeedsCommit();
}
void Layer::SetTransformOrigin(const gfx::Point3F& transform_origin) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.transform_origin == transform_origin)
return;
inputs.transform_origin = transform_origin;
if (!IsAttached())
return;
SetSubtreePropertyChanged();
if (has_transform_node()) {
TransformNode* transform_node =
layer_tree_host()->property_trees()->transform_tree_mutable().Node(
transform_tree_index_.Read(*this));
DCHECK_EQ(transform_tree_index(), transform_node->id);
transform_node->origin = transform_origin;
transform_node->needs_local_transform_update = true;
transform_node->SetTransformChanged(DamageReason::kUntracked);
layer_tree_host()
->property_trees()
->transform_tree_mutable()
.set_needs_update(true);
} else {
SetPropertyTreesNeedRebuild();
}
SetNeedsCommit();
}
void Layer::SetScrollOffset(const gfx::PointF& scroll_offset) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.scroll_offset == scroll_offset)
return;
inputs.scroll_offset = scroll_offset;
if (!IsAttached())
return;
UpdatePropertyTreeScrollOffset();
SetNeedsCommit();
}
void Layer::SetScrollOffsetFromImplSide(const gfx::PointF& scroll_offset) {
DCHECK(IsPropertyChangeAllowed());
DCHECK(IsAttached() && layer_tree_host()->CommitRequested());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.scroll_offset == scroll_offset)
return;
inputs.scroll_offset = scroll_offset;
UpdatePropertyTreeScrollOffset();
if (!inputs.did_scroll_callback.is_null())
inputs.did_scroll_callback.Run(scroll_offset, element_id());
}
void Layer::UpdatePropertyTreeScrollOffset() {
DCHECK(scrollable());
DCHECK(!IsUsingLayerLists());
if (scroll_tree_index() == kInvalidPropertyNodeId) {
DCHECK(layer_tree_host()->property_trees()->needs_rebuild());
return;
}
DCHECK(transform_tree_index() != kInvalidPropertyNodeId);
auto& property_trees = *layer_tree_host()->property_trees();
property_trees.scroll_tree_mutable().SetScrollOffset(element_id(),
scroll_offset());
auto* transform_node =
property_trees.transform_tree_mutable().Node(transform_tree_index());
DCHECK_EQ(transform_tree_index(), transform_node->id);
transform_node->SetScrollOffset(scroll_offset(), DamageReason::kUntracked);
transform_node->needs_local_transform_update = true;
property_trees.transform_tree_mutable().set_needs_update(true);
}
void Layer::SetDidScrollCallback(
base::RepeatingCallback<void(const gfx::PointF&, const ElementId&)>
callback) {
EnsureLayerTreeInputs().did_scroll_callback = std::move(callback);
}
void Layer::SetSubtreeCaptureId(viz::SubtreeCaptureId subtree_id) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.subtree_capture_id == subtree_id)
return;
DCHECK(!inputs.subtree_capture_id.is_valid() || !subtree_id.is_valid())
<< "Not allowed to change from a valid ID to another valid ID, as it may "
"already be in use.";
inputs.subtree_capture_id = subtree_id;
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
void Layer::SetScrollable(const gfx::Size& bounds) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.scrollable && inputs.scroll_container_bounds == bounds)
return;
bool was_scrollable = inputs.scrollable;
inputs.scrollable = true;
inputs.scroll_container_bounds = bounds;
if (!IsAttached())
return;
auto& scroll_tree =
layer_tree_host()->property_trees()->scroll_tree_mutable();
auto* scroll_node = scroll_tree.Node(scroll_tree_index_.Read(*this));
if (was_scrollable && scroll_node)
scroll_node->container_bounds = inputs.scroll_container_bounds;
else
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
bool Layer::IsScrollbarLayerForTesting() const {
return false;
}
void Layer::SetMainThreadScrollHitTestRegion(const Region& region) {
DCHECK(IsPropertyChangeAllowed());
const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
if (!rare_inputs && region.IsEmpty())
return;
if (rare_inputs &&
rare_inputs->main_thread_scroll_hit_test_region == region) {
return;
}
EnsureRareInputs().main_thread_scroll_hit_test_region = region;
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
void Layer::SetNonCompositedScrollHitTestRects(
std::vector<ScrollHitTestRect> rects) {
DCHECK(IsPropertyChangeAllowed());
const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
if (!rare_inputs && rects.empty()) {
return;
}
if (rare_inputs &&
rare_inputs->non_composited_scroll_hit_test_rects == rects) {
return;
}
EnsureRareInputs().non_composited_scroll_hit_test_rects = std::move(rects);
SetNeedsCommit();
}
void Layer::SetTouchActionRegion(TouchActionRegion touch_action_region) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.Read(*this).touch_action_region == touch_action_region)
return;
inputs_.Write(*this).touch_action_region = std::move(touch_action_region);
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
}
void Layer::SetCaptureBounds(viz::RegionCaptureBounds bounds) {
DCHECK(IsPropertyChangeAllowed());
const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
if (!rare_inputs && bounds.IsEmpty())
return;
if (rare_inputs && rare_inputs->capture_bounds == bounds)
return;
EnsureRareInputs().capture_bounds = std::move(bounds);
SetPropertyTreesNeedRebuild();
SetNeedsCommit();
SetSubtreePropertyChanged();
}
void Layer::SetWheelEventRegion(Region wheel_event_region) {
DCHECK(IsPropertyChangeAllowed());
const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
if (!rare_inputs && wheel_event_region.IsEmpty())
return;
if (rare_inputs && rare_inputs->wheel_event_region == wheel_event_region)
return;
EnsureRareInputs().wheel_event_region = std::move(wheel_event_region);
SetNeedsCommit();
}
#if BUILDFLAG(IS_ANDROID)
void Layer::SetXrHitTestOrder(std::vector<ElementId> xr_hit_test_order) {
CHECK(IsPropertyChangeAllowed());
const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
if (!rare_inputs && xr_hit_test_order.empty()) {
return;
}
if (rare_inputs && rare_inputs->xr_hit_test_order == xr_hit_test_order) {
return;
}
EnsureRareInputs().xr_hit_test_order = std::move(xr_hit_test_order);
}
#endif
RenderSurfaceReason Layer::GetRenderSurfaceReason() const {
if (!IsAttached())
return RenderSurfaceReason::kNone;
const PropertyTrees* property_trees = layer_tree_host()->property_trees();
DCHECK(!property_trees->needs_rebuild());
const EffectNode* effect_node =
property_trees->effect_tree().Node(this->effect_tree_index());
if (!effect_node ||
(parent_.Read(*this) &&
this->effect_tree_index() == parent_.Read(*this)->effect_tree_index())) {
return RenderSurfaceReason::kNone;
}
return effect_node->render_surface_reason;
}
void Layer::SetTransformTreeIndex(int index) {
DCHECK(IsPropertyChangeAllowed());
if (transform_tree_index_.Read(*this) == index)
return;
SetHasTransformNode(index != kInvalidPropertyNodeId);
transform_tree_index_.Write(*this) = index;
SetNeedsPushProperties(kChangedPropertyTreeIndex);
}
int Layer::transform_tree_index(const PropertyTrees& property_trees) const {
if (property_trees.sequence_number() !=
property_tree_sequence_number_.Read(*this)) {
return kInvalidPropertyNodeId;
}
return transform_tree_index_.Read(*this);
}
bool Layer::transform_tree_index_is_valid(
const PropertyTrees& property_trees) const {
return transform_tree_index_.Read(*this) != kInvalidPropertyNodeId &&
property_trees.sequence_number() ==
property_tree_sequence_number_.Read(*this);
}
int Layer::transform_tree_index() const {
if (!IsAttached())
return kInvalidPropertyNodeId;
return transform_tree_index(*layer_tree_host()->property_trees());
}
void Layer::SetClipTreeIndex(int index) {
DCHECK(IsPropertyChangeAllowed());
if (clip_tree_index_.Read(*this) == index)
return;
clip_tree_index_.Write(*this) = index;
SetNeedsPushProperties(kChangedPropertyTreeIndex);
}
int Layer::clip_tree_index(const PropertyTrees& property_trees) const {
if (property_trees.sequence_number() !=
property_tree_sequence_number_.Read(*this)) {
return kInvalidPropertyNodeId;
}
return clip_tree_index_.Read(*this);
}
bool Layer::clip_tree_index_is_valid(
const PropertyTrees& property_trees) const {
return clip_tree_index_.Read(*this) != kInvalidPropertyNodeId &&
property_trees.sequence_number() ==
property_tree_sequence_number_.Read(*this);
}
int Layer::clip_tree_index() const {
if (!IsAttached())
return kInvalidPropertyNodeId;
return clip_tree_index(*layer_tree_host()->property_trees());
}
void Layer::SetEffectTreeIndex(int index) {
DCHECK(IsPropertyChangeAllowed());
if (effect_tree_index_.Read(*this) == index)
return;
effect_tree_index_.Write(*this) = index;
SetNeedsPushProperties(kChangedPropertyTreeIndex);
}
int Layer::effect_tree_index(const PropertyTrees& property_trees) const {
if (property_trees.sequence_number() !=
property_tree_sequence_number_.Read(*this)) {
return kInvalidPropertyNodeId;
}
return effect_tree_index_.Read(*this);
}
bool Layer::effect_tree_index_is_valid(
const PropertyTrees& property_trees) const {
return effect_tree_index_.Read(*this) != kInvalidPropertyNodeId &&
property_trees.sequence_number() ==
property_tree_sequence_number_.Read(*this);
}
int Layer::effect_tree_index() const {
if (!IsAttached())
return kInvalidPropertyNodeId;
return effect_tree_index(*layer_tree_host()->property_trees());
}
void Layer::SetScrollTreeIndex(int index) {
DCHECK(IsPropertyChangeAllowed());
if (scroll_tree_index_.Read(*this) == index)
return;
scroll_tree_index_.Write(*this) = index;
SetNeedsPushProperties(kChangedPropertyTreeIndex);
}
int Layer::scroll_tree_index(const PropertyTrees& property_trees) const {
if (property_trees.sequence_number() !=
property_tree_sequence_number_.Read(*this)) {
return kInvalidPropertyNodeId;
}
return scroll_tree_index_.Read(*this);
}
bool Layer::scroll_tree_index_is_valid(
const PropertyTrees& property_trees) const {
return scroll_tree_index_.Read(*this) != kInvalidPropertyNodeId &&
property_trees.sequence_number() ==
property_tree_sequence_number_.Read(*this);
}
int Layer::scroll_tree_index() const {
if (!IsAttached())
return kInvalidPropertyNodeId;
return scroll_tree_index(*layer_tree_host()->property_trees());
}
void Layer::SetOffsetToTransformParent(gfx::Vector2dF offset) {
if (offset_to_transform_parent_.Read(*this) == offset)
return;
offset_to_transform_parent_.Write(*this) = offset;
SetNeedsPushProperties();
SetSubtreePropertyChanged();
}
void Layer::InvalidatePropertyTreesIndices() {
SetTransformTreeIndex(kInvalidPropertyNodeId);
SetClipTreeIndex(kInvalidPropertyNodeId);
SetEffectTreeIndex(kInvalidPropertyNodeId);
SetScrollTreeIndex(kInvalidPropertyNodeId);
}
void Layer::SetPropertyTreesNeedRebuild() {
if (IsAttached())
layer_tree_host()->property_trees()->set_needs_rebuild(true);
}
LayerDebugInfo& Layer::EnsureDebugInfo() {
auto& info = debug_info_.Write(*this);
if (!info) {
info = std::make_unique<LayerDebugInfo>();
SetNeedsPushProperties();
}
return *info;
}
void Layer::ClearDebugInfo() {
if (!debug_info_.Read(*this))
return;
debug_info_.Write(*this).reset();
SetNeedsPushProperties();
}
std::string Layer::DebugName() const {
const auto* info = debug_info_.Read(*this);
return info ? info->name : "";
}
std::string Layer::ToString() const {
return base::StringPrintf(
"layer_id: %d\n"
" name: %s\n"
" Bounds: %s\n"
" ElementId: %s\n"
" HitTestOpaqueness: %s\n"
" OffsetToTransformParent: %s\n"
" clip_tree_index: %d\n"
" effect_tree_index: %d\n"
" scroll_tree_index: %d\n"
" transform_tree_index: %d\n",
id(), DebugName().c_str(), bounds().ToString().c_str(),
element_id().ToString().c_str(),
HitTestOpaquenessToString(hit_test_opaqueness()),
offset_to_transform_parent().ToString().c_str(), clip_tree_index(),
effect_tree_index(), scroll_tree_index(), transform_tree_index());
}
void Layer::SetIsDrawable(bool is_drawable) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.Read(*this).is_drawable == is_drawable)
return;
inputs_.Write(*this).is_drawable = is_drawable;
UpdateDrawsContent();
}
void Layer::SetHideLayerAndSubtree(bool hide) {
DCHECK(IsPropertyChangeAllowed());
auto& inputs = EnsureLayerTreeInputs();
if (inputs.hide_layer_and_subtree == hide)
return;
inputs.hide_layer_and_subtree = hide;
SetNeedsCommit();
SetPropertyTreesNeedRebuild();
SetSubtreePropertyChanged();
}
void Layer::SetNeedsDisplayRect(const gfx::Rect& dirty_rect) {
if (dirty_rect.IsEmpty())
return;
SetNeedsPushProperties();
update_rect_.Write(*this).Union(dirty_rect);
if (draws_content() && IsAttached() &&
!ignore_set_needs_commit_for_test_.Read(*this))
layer_tree_host()->SetNeedsUpdateLayers();
}
bool Layer::RequiresSetNeedsDisplayOnHdrHeadroomChange() const {
return false;
}
bool Layer::IsSnappedToPixelGridInTarget() const {
return false;
}
void Layer::PushDirtyPropertiesTo(LayerImpl* layer,
uint8_t dirty_flag,
const CommitState& commit_state,
const ThreadUnsafeCommitState& unsafe_state) {
const PropertyTrees& property_trees = unsafe_state.property_trees;
if (dirty_flag & kChangedPropertyTreeIndex) {
layer->SetTransformTreeIndex(transform_tree_index(property_trees));
layer->SetHasTransformNode(has_transform_node());
layer->SetEffectTreeIndex(effect_tree_index(property_trees));
layer->SetClipTreeIndex(clip_tree_index(property_trees));
layer->SetScrollTreeIndex(scroll_tree_index(property_trees));
}
if (dirty_flag & kChangedGeneralProperty) {
const auto& inputs = inputs_.Read(*this);
layer->SetElementId(inputs.element_id);
layer->SetBackgroundColor(inputs.background_color);
layer->SetSafeOpaqueBackgroundColor(SafeOpaqueBackgroundColor());
layer->SetBounds(inputs.bounds);
layer->SetOffsetToTransformParent(offset_to_transform_parent_.Read(*this));
layer->SetDrawsContent(draws_content());
layer->SetHitTestOpaqueness(inputs.hit_test_opaqueness);
if (subtree_property_changed_.Read(*this)) {
layer->NoteLayerPropertyChanged();
}
#if BUILDFLAG(ARKWEB_SAME_LAYER)
layer_utils_->PushPropertiesToImpl(layer);
#endif
layer->SetTouchActionRegion(inputs.touch_action_region);
layer->SetContentsOpaque(inputs.contents_opaque);
layer->SetContentsOpaqueForText(inputs.contents_opaque_for_text);
layer->SetShouldCheckBackfaceVisibility(should_check_backface_visibility());
DCHECK(layer->layer_tree_impl()->lifecycle().AllowsPropertyTreeAccess());
if (unsafe_state.mutator_host->ScrollOffsetAnimationWasInterrupted(
element_id())) {
PropertyTrees* trees = layer->layer_tree_impl()->property_trees();
trees->scroll_tree_mutable().SetScrollOffsetClobberActiveValue(
layer->element_id());
}
layer->UnionUpdateRect(update_rect_.Read(*this));
layer->UpdateDebugInfo(debug_info_.Write(*this).get());
if (inputs.rare_inputs) {
layer->SetFilterQuality(inputs.rare_inputs->filter_quality);
layer->SetDynamicRangeLimit(inputs.rare_inputs->dynamic_range_limit);
layer->SetMainThreadScrollHitTestRegion(
inputs.rare_inputs->main_thread_scroll_hit_test_region);
layer->SetNonCompositedScrollHitTestRects(
inputs.rare_inputs->non_composited_scroll_hit_test_rects);
layer->SetCaptureBounds(inputs.rare_inputs->capture_bounds);
layer->SetWheelEventHandlerRegion(inputs.rare_inputs->wheel_event_region);
} else {
layer->ResetRareProperties();
}
subtree_property_changed_.Write(*this) = false;
update_rect_.Write(*this) = gfx::Rect();
}
layer->SetNeedsPushProperties(dirty_flag);
}
void Layer::PushPropertiesTo(LayerImpl* layer_impl,
const CommitState& commit_state,
const ThreadUnsafeCommitState& unsafe_state) {
TRACE_EVENT0(TRACE_DISABLED_BY_DEFAULT("cc.debug"),
"Layer::PushPropertiesTo");
DCHECK(IsAttached());
const uint8_t changed_props = changed_properties_.Read(*this);
PushDirtyPropertiesTo(layer_impl, changed_props, commit_state, unsafe_state);
changed_properties_.Write(*this) = 0u;
}
void Layer::TakeCopyRequests(
std::vector<std::unique_ptr<viz::CopyOutputRequest>>* requests) {
if (!layer_tree_inputs())
return;
auto& layer_tree_inputs = layer_tree_inputs_.Write(*this);
for (std::unique_ptr<viz::CopyOutputRequest>& request :
layer_tree_inputs->copy_requests) {
if (!request->has_result_task_runner()) {
request->set_result_task_runner(
layer_tree_host()->GetTaskRunnerProvider()->MainThreadTaskRunner());
}
if (request->has_area()) {
request->set_area(
gfx::IntersectRects(request->area(), gfx::Rect(bounds())));
}
requests->push_back(std::move(request));
}
layer_tree_inputs->copy_requests.clear();
}
std::unique_ptr<LayerImpl> Layer::CreateLayerImpl(
LayerTreeImpl* tree_impl) const {
return LayerImpl::Create(tree_impl, id());
}
bool Layer::HasDrawableContent() const {
return inputs_.Read(*this).is_drawable;
}
void Layer::UpdateDrawsContent() {
bool value = HasDrawableContent();
DCHECK(inputs_.Read(*this).is_drawable || !value);
if (!SetBitFlag(value, kDrawsContentFlagMask, true))
return;
if (parent())
mutable_parent()->AddDrawableDescendants(value ? 1 : -1);
}
int Layer::NumDescendantsThatDrawContent() const {
return num_descendants_that_draw_content_.Read(*this);
}
bool Layer::Update() {
DCHECK(IsAttached());
return false;
}
void Layer::SetSubtreePropertyChanged() {
if (subtree_property_changed_.Read(*this))
return;
subtree_property_changed_.Write(*this) = true;
SetNeedsPushProperties();
}
bool Layer::IsOwnerThread() const {
return !IsAttached() || layer_tree_host_->IsOwnerThread();
}
bool Layer::IsMainThread() const {
return IsAttached() && layer_tree_host_->IsMainThread();
}
bool Layer::InProtectedSequence() const {
return IsAttached() && layer_tree_host_->InProtectedSequence();
}
void Layer::WaitForProtectedSequenceCompletion() const {
if (IsAttached())
layer_tree_host_->WaitForProtectedSequenceCompletion();
}
bool Layer::IsUsingLayerLists() const {
return IsAttached() && layer_tree_host_->IsUsingLayerLists();
}
void Layer::OnFilterAnimated(const FilterOperations& filters) {
EnsureLayerTreeInputs().filters = filters;
}
void Layer::OnBackdropFilterAnimated(const FilterOperations& backdrop_filters) {
EnsureLayerTreeInputs().backdrop_filters = backdrop_filters;
}
void Layer::OnOpacityAnimated(float opacity) {
EnsureLayerTreeInputs().opacity = opacity;
}
void Layer::OnTransformAnimated(const gfx::Transform& transform) {
EnsureLayerTreeInputs().transform = transform;
}
void Layer::SetTrilinearFiltering(bool trilinear_filtering) {
auto& inputs = EnsureLayerTreeInputs();
if (inputs.trilinear_filtering == trilinear_filtering)
return;
inputs.trilinear_filtering = trilinear_filtering;
SetPropertyTreesNeedRebuild();
SetSubtreePropertyChanged();
SetNeedsCommit();
}
void Layer::IncrementMirrorCount() {
SetMirrorCount(mirror_count() + 1);
}
void Layer::DecrementMirrorCount() {
SetMirrorCount(mirror_count() - 1);
}
void Layer::SetMirrorCount(int mirror_count) {
auto& inputs = EnsureLayerTreeInputs();
if (inputs.mirror_count == mirror_count)
return;
DCHECK_LE(0, mirror_count);
bool was_mirrored = inputs.mirror_count > 0;
inputs.mirror_count = mirror_count;
bool is_mirrored = inputs.mirror_count > 0;
if (was_mirrored != is_mirrored)
SetPropertyTreesNeedRebuild();
SetNeedsPushProperties();
}
ElementListType Layer::GetElementTypeForAnimation() const {
return ElementListType::ACTIVE;
}
void Layer::AddDrawableDescendants(int num) {
DCHECK_GE(num_descendants_that_draw_content_.Read(*this), 0);
DCHECK_GE(num_descendants_that_draw_content_.Read(*this) + num, 0);
if (num == 0)
return;
num_descendants_that_draw_content_.Write(*this) += num;
SetNeedsCommit();
if (parent())
mutable_parent()->AddDrawableDescendants(num);
}
void Layer::RunMicroBenchmark(MicroBenchmark* benchmark) {}
void Layer::SetElementId(ElementId id) {
DCHECK(IsPropertyChangeAllowed());
if (inputs_.Read(*this).element_id == id)
return;
TRACE_EVENT1(TRACE_DISABLED_BY_DEFAULT("cc.debug"), "Layer::SetElementId",
"element", id.ToString());
auto& inputs = inputs_.Write(*this);
if (IsAttached() && inputs.element_id)
layer_tree_host()->UnregisterElement(inputs.element_id, this);
inputs.element_id = id;
if (IsAttached() && inputs.element_id)
layer_tree_host()->RegisterElement(inputs.element_id, this);
SetNeedsCommit();
}
gfx::Transform Layer::ScreenSpaceTransform() const {
DCHECK_NE(transform_tree_index_.Read(*this), kInvalidPropertyNodeId);
return draw_property_utils::ScreenSpaceTransform(
this, layer_tree_host()->property_trees()->transform_tree());
}
void Layer::SetFilterQuality(PaintFlags::FilterQuality filter_quality) {
const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
const auto old_filter_quality = rare_inputs ? rare_inputs->filter_quality
: PaintFlags::FilterQuality::kLow;
if (old_filter_quality == filter_quality) {
return;
}
EnsureRareInputs().filter_quality = filter_quality;
SetNeedsCommit();
}
void Layer::SetDynamicRangeLimit(
PaintFlags::DynamicRangeLimitMixture dynamic_range_limit) {
const auto& rare_inputs = inputs_.Read(*this).rare_inputs;
const auto old_dynamic_range_limit =
rare_inputs ? rare_inputs->dynamic_range_limit
: PaintFlags::DynamicRangeLimitMixture(
PaintFlags::DynamicRangeLimit::kHigh);
if (old_dynamic_range_limit == dynamic_range_limit) {
return;
}
EnsureRareInputs().dynamic_range_limit = dynamic_range_limit;
SetNeedsCommit();
}
}