blob: 73188d3cc669321b654bb4bf94cbc434bd45da8e [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "cc/test/property_tree_test_utils.h"
#include "cc/layers/picture_layer.h"
#include "cc/layers/picture_layer_impl.h"
#include "cc/trees/clip_node.h"
#include "cc/trees/effect_node.h"
#include "cc/trees/layer_tree_host.h"
#include "cc/trees/layer_tree_impl.h"
#include "cc/trees/property_tree.h"
#include "cc/trees/scroll_node.h"
#include "cc/trees/transform_node.h"
namespace cc {
namespace {
template <typename LayerType>
void SetupRootPropertiesInternal(LayerType* root) {
root->set_property_tree_sequence_number(
GetPropertyTrees(root)->sequence_number);
root->SetElementId(LayerIdToElementIdForTesting(root->id()));
auto& root_transform_node =
CreateTransformNode(root, TransformTree::kRootNodeId);
DCHECK_EQ(root_transform_node.id, TransformTree::kContentsRootNodeId);
auto& root_clip_node = CreateClipNode(root, ClipTree::kRootNodeId);
DCHECK_EQ(root_clip_node.id, ClipTree::kViewportNodeId);
root_clip_node.clip = gfx::RectF(gfx::SizeF(root->bounds()));
// Root clip is in the real root transform space instead of the root layer's
// transform space.
root_clip_node.transform_id = TransformTree::kRootNodeId;
auto& root_effect_node = CreateEffectNode(root, EffectTree::kRootNodeId);
DCHECK_EQ(root_effect_node.id, EffectTree::kContentsRootNodeId);
root_effect_node.render_surface_reason = RenderSurfaceReason::kRoot;
// Root effect is in the real root transform space instead of the root layer's
// transform space.
root_effect_node.transform_id = TransformTree::kRootNodeId;
auto& root_scroll_node = CreateScrollNode(root, ScrollTree::kRootNodeId);
DCHECK_EQ(root_scroll_node.id, ScrollTree::kSecondaryRootNodeId);
}
template <typename LayerType>
void CopyPropertiesInternal(const LayerType* from, LayerType* to) {
to->SetTransformTreeIndex(from->transform_tree_index());
to->SetClipTreeIndex(from->clip_tree_index());
to->SetEffectTreeIndex(from->effect_tree_index());
to->SetScrollTreeIndex(from->scroll_tree_index());
}
// We use a macro instead of a function to avoid |default_id| (which is
// |layer->xxx_tree_index()|) from being evaluated when it's not used because
// |layer| may be null when |id| is valid.
#define ID_OR_DEFAULT(id, default_id) \
((id) == TransformTree::kInvalidNodeId ? (default_id) : (id))
template <typename LayerType>
TransformNode& CreateTransformNodeInternal(LayerType* layer,
PropertyTrees* property_trees,
int parent_id) {
auto& transform_tree = property_trees->transform_tree;
int id = transform_tree.Insert(
TransformNode(), ID_OR_DEFAULT(parent_id, layer->transform_tree_index()));
auto* node = transform_tree.Node(id);
if (layer) {
layer->SetTransformTreeIndex(id);
layer->SetHasTransformNode(true);
node->element_id = layer->element_id();
if (node->element_id) {
property_trees->element_id_to_transform_node_index[node->element_id] =
node->id;
}
}
if (const auto* parent_node = transform_tree.Node(node->parent_id)) {
node->in_subtree_of_page_scale_layer =
parent_node->in_subtree_of_page_scale_layer;
}
transform_tree.set_needs_update(true);
return *node;
}
template <typename LayerType>
ClipNode& CreateClipNodeInternal(
LayerType* layer,
PropertyTrees* property_trees,
int parent_id,
int transform_id = TransformTree::kInvalidNodeId) {
auto& clip_tree = property_trees->clip_tree;
int id = clip_tree.Insert(ClipNode(),
ID_OR_DEFAULT(parent_id, layer->clip_tree_index()));
auto* node = clip_tree.Node(id);
node->clip_type = ClipNode::ClipType::APPLIES_LOCAL_CLIP;
node->transform_id =
ID_OR_DEFAULT(transform_id, layer->transform_tree_index());
if (layer) {
layer->SetClipTreeIndex(id);
node->clip = gfx::RectF(
gfx::PointAtOffsetFromOrigin(layer->offset_to_transform_parent()),
gfx::SizeF(layer->bounds()));
}
clip_tree.set_needs_update(true);
return *node;
}
template <typename LayerType>
EffectNode& CreateEffectNodeInternal(
LayerType* layer,
PropertyTrees* property_trees,
int parent_id,
int transform_id = TransformTree::kInvalidNodeId,
int clip_id = ClipTree::kInvalidNodeId) {
auto& effect_tree = property_trees->effect_tree;
int id = effect_tree.Insert(
EffectNode(), ID_OR_DEFAULT(parent_id, layer->effect_tree_index()));
auto* node = effect_tree.Node(id);
if (layer) {
layer->SetEffectTreeIndex(id);
node->stable_id = layer->id();
if (layer->element_id()) {
property_trees->element_id_to_effect_node_index[layer->element_id()] =
node->id;
}
}
node->transform_id =
ID_OR_DEFAULT(transform_id, layer->transform_tree_index());
node->clip_id = ID_OR_DEFAULT(clip_id, layer->clip_tree_index());
effect_tree.set_needs_update(true);
return *node;
}
template <typename LayerType>
ScrollNode& CreateScrollNodeInternal(LayerType* layer, int parent_id) {
auto* property_trees = GetPropertyTrees(layer);
auto& scroll_tree = property_trees->scroll_tree;
int id = scroll_tree.Insert(
ScrollNode(), ID_OR_DEFAULT(parent_id, layer->scroll_tree_index()));
layer->SetScrollTreeIndex(id);
auto* node = scroll_tree.Node(id);
node->element_id = layer->element_id();
if (node->element_id) {
property_trees->element_id_to_scroll_node_index[node->element_id] =
node->id;
}
node->container_bounds = layer->scroll_container_bounds();
node->bounds = layer->bounds();
node->scrollable = layer->scrollable();
node->user_scrollable_horizontal = true;
node->user_scrollable_vertical = true;
DCHECK(layer->has_transform_node());
node->transform_id = layer->transform_tree_index();
auto* transform_node = GetTransformNode(layer);
transform_node->should_be_snapped = true;
transform_node->scrolls = true;
scroll_tree.SetScrollOffset(layer->element_id(), gfx::ScrollOffset());
scroll_tree.set_needs_update(true);
return *node;
}
template <typename LayerType, typename MaskLayerType>
void SetupMaskPropertiesInternal(LayerType* masked_layer,
MaskLayerType* mask_layer) {
if (!GetEffectNode(masked_layer)->backdrop_filters.IsEmpty())
mask_layer->SetIsBackdropFilterMask(true);
mask_layer->SetBounds(masked_layer->bounds());
auto* masked_effect = GetEffectNode(masked_layer);
masked_effect->render_surface_reason = RenderSurfaceReason::kMask;
masked_effect->has_masking_child = true;
if (!masked_effect->backdrop_filters.IsEmpty()) {
if (!mask_layer->element_id())
mask_layer->SetElementId(LayerIdToElementIdForTesting(mask_layer->id()));
masked_effect->backdrop_mask_element_id = mask_layer->element_id();
}
CopyProperties(masked_layer, mask_layer);
mask_layer->SetOffsetToTransformParent(
masked_layer->offset_to_transform_parent());
CreateEffectNode(mask_layer).blend_mode = SkBlendMode::kDstIn;
}
template <typename LayerType>
void SetScrollOffsetInternal(LayerType* layer,
const gfx::ScrollOffset& scroll_offset) {
DCHECK(layer->has_transform_node());
auto* transform_node = GetTransformNode(layer);
transform_node->scroll_offset = scroll_offset;
SetLocalTransformChanged(layer);
GetPropertyTrees(layer)->scroll_tree.SetScrollOffset(layer->element_id(),
scroll_offset);
}
// TODO(wangxianzhu): Viewport properties can exist without layers, but for now
// it's more convenient to create properties based on layers.
template <typename LayerType>
LayerTreeHost::ViewportPropertyIds SetupViewportProperties(
LayerType* root,
LayerType* inner_viewport_scroll_layer,
LayerType* outer_viewport_scroll_layer) {
LayerTreeHost::ViewportPropertyIds viewport_property_ids;
auto* property_trees = GetPropertyTrees(root);
viewport_property_ids.overscroll_elasticity_transform =
CreateTransformNode(property_trees, root->transform_tree_index()).id;
auto& page_scale_transform = CreateTransformNode(
property_trees, viewport_property_ids.overscroll_elasticity_transform);
page_scale_transform.in_subtree_of_page_scale_layer = true;
viewport_property_ids.page_scale_transform = page_scale_transform.id;
CopyProperties(root, inner_viewport_scroll_layer);
CreateTransformNode(inner_viewport_scroll_layer,
viewport_property_ids.page_scale_transform);
auto& inner_scroll = CreateScrollNode(inner_viewport_scroll_layer);
inner_scroll.scrolls_inner_viewport = true;
inner_scroll.max_scroll_offset_affected_by_page_scale = true;
viewport_property_ids.inner_scroll = inner_scroll.id;
auto& outer_clip = CreateClipNode(property_trees, root->clip_tree_index(),
inner_scroll.transform_id);
outer_clip.clip =
gfx::RectF(gfx::SizeF(inner_viewport_scroll_layer->bounds()));
viewport_property_ids.outer_clip = outer_clip.id;
CopyProperties(inner_viewport_scroll_layer, outer_viewport_scroll_layer);
CreateTransformNode(outer_viewport_scroll_layer);
auto& outer_scroll = CreateScrollNode(outer_viewport_scroll_layer);
outer_scroll.scrolls_outer_viewport = true;
viewport_property_ids.outer_scroll = outer_scroll.id;
return viewport_property_ids;
}
} // anonymous namespace
void SetupRootProperties(Layer* root) {
SetupRootPropertiesInternal(root);
}
void SetupRootProperties(LayerImpl* root) {
SetupRootPropertiesInternal(root);
}
void CopyProperties(const Layer* from, Layer* to) {
DCHECK(from->layer_tree_host()->IsUsingLayerLists());
to->SetLayerTreeHost(from->layer_tree_host());
to->set_property_tree_sequence_number(from->property_tree_sequence_number());
CopyPropertiesInternal(from, to);
}
void CopyProperties(const LayerImpl* from, LayerImpl* to) {
CopyPropertiesInternal(from, to);
}
TransformNode& CreateTransformNode(Layer* layer, int parent_id) {
DCHECK(layer->layer_tree_host()->IsUsingLayerLists());
return CreateTransformNodeInternal(layer, GetPropertyTrees(layer), parent_id);
}
TransformNode& CreateTransformNode(LayerImpl* layer, int parent_id) {
return CreateTransformNodeInternal(layer, GetPropertyTrees(layer), parent_id);
}
TransformNode& CreateTransformNode(PropertyTrees* property_trees,
int parent_id) {
return CreateTransformNodeInternal<Layer>(nullptr, property_trees, parent_id);
}
ClipNode& CreateClipNode(Layer* layer, int parent_id) {
DCHECK(layer->layer_tree_host()->IsUsingLayerLists());
return CreateClipNodeInternal(layer, GetPropertyTrees(layer), parent_id);
}
ClipNode& CreateClipNode(LayerImpl* layer, int parent_id) {
return CreateClipNodeInternal(layer, GetPropertyTrees(layer), parent_id);
}
ClipNode& CreateClipNode(PropertyTrees* property_trees,
int parent_id,
int transform_id) {
return CreateClipNodeInternal<Layer>(nullptr, property_trees, parent_id,
transform_id);
}
EffectNode& CreateEffectNode(Layer* layer, int parent_id) {
DCHECK(layer->layer_tree_host()->IsUsingLayerLists());
return CreateEffectNodeInternal(layer, GetPropertyTrees(layer), parent_id);
}
EffectNode& CreateEffectNode(LayerImpl* layer, int parent_id) {
return CreateEffectNodeInternal(layer, GetPropertyTrees(layer), parent_id);
}
EffectNode& CreateEffectNode(PropertyTrees* property_trees,
int parent_id,
int transform_id,
int clip_id) {
return CreateEffectNodeInternal<Layer>(nullptr, property_trees, parent_id,
transform_id, clip_id);
}
ScrollNode& CreateScrollNode(Layer* layer, int parent_id) {
DCHECK(layer->layer_tree_host()->IsUsingLayerLists());
return CreateScrollNodeInternal(layer, parent_id);
}
ScrollNode& CreateScrollNode(LayerImpl* layer, int parent_id) {
return CreateScrollNodeInternal(layer, parent_id);
}
void SetupMaskProperties(Layer* masked_layer, PictureLayer* mask_layer) {
mask_layer->SetIsDrawable(true);
SetupMaskPropertiesInternal(masked_layer, mask_layer);
}
void SetupMaskProperties(LayerImpl* masked_layer,
PictureLayerImpl* mask_layer) {
mask_layer->SetDrawsContent(true);
SetupMaskPropertiesInternal(masked_layer, mask_layer);
}
void SetScrollOffset(Layer* layer, const gfx::ScrollOffset& scroll_offset) {
layer->SetScrollOffset(scroll_offset);
SetScrollOffsetInternal(layer, scroll_offset);
}
void SetScrollOffset(LayerImpl* layer, const gfx::ScrollOffset& scroll_offset) {
if (layer->IsActive())
layer->SetCurrentScrollOffset(scroll_offset);
SetScrollOffsetInternal(layer, scroll_offset);
}
void SetupViewport(Layer* root,
scoped_refptr<Layer> outer_viewport_scroll_layer,
const gfx::Size& outer_viewport_size) {
DCHECK(root);
DCHECK_EQ(root, root->layer_tree_host()->root_layer());
DCHECK(root->layer_tree_host()->IsUsingLayerLists());
scoped_refptr<Layer> inner_viewport_scroll_layer = Layer::Create();
inner_viewport_scroll_layer->SetBounds(outer_viewport_size);
inner_viewport_scroll_layer->SetScrollable(root->bounds());
inner_viewport_scroll_layer->SetHitTestable(true);
outer_viewport_scroll_layer->SetScrollable(outer_viewport_size);
outer_viewport_scroll_layer->SetHitTestable(true);
root->AddChild(inner_viewport_scroll_layer);
root->AddChild(outer_viewport_scroll_layer);
root->layer_tree_host()->SetElementIdsForTesting();
auto viewport_property_ids =
SetupViewportProperties(root, inner_viewport_scroll_layer.get(),
outer_viewport_scroll_layer.get());
root->layer_tree_host()->RegisterViewportPropertyIds(viewport_property_ids);
}
void SetupViewport(Layer* root,
const gfx::Size& outer_viewport_size,
const gfx::Size& content_size) {
scoped_refptr<Layer> outer_viewport_scroll_layer = Layer::Create();
outer_viewport_scroll_layer->SetBounds(content_size);
outer_viewport_scroll_layer->SetIsDrawable(true);
SetupViewport(root, outer_viewport_scroll_layer, outer_viewport_size);
}
void SetupViewport(LayerImpl* root,
const gfx::Size& outer_viewport_size,
const gfx::Size& content_size) {
DCHECK(root);
LayerTreeImpl* layer_tree_impl = root->layer_tree_impl();
DCHECK(!layer_tree_impl->InnerViewportScrollNode());
DCHECK(layer_tree_impl->settings().use_layer_lists);
DCHECK_EQ(root, layer_tree_impl->root_layer());
std::unique_ptr<LayerImpl> inner_viewport_scroll_layer =
LayerImpl::Create(layer_tree_impl, 10000);
inner_viewport_scroll_layer->SetBounds(outer_viewport_size);
inner_viewport_scroll_layer->SetScrollable(root->bounds());
inner_viewport_scroll_layer->SetHitTestable(true);
inner_viewport_scroll_layer->SetElementId(
LayerIdToElementIdForTesting(inner_viewport_scroll_layer->id()));
std::unique_ptr<LayerImpl> outer_viewport_scroll_layer =
LayerImpl::Create(layer_tree_impl, 10001);
outer_viewport_scroll_layer->SetBounds(content_size);
outer_viewport_scroll_layer->SetDrawsContent(true);
outer_viewport_scroll_layer->SetScrollable(outer_viewport_size);
outer_viewport_scroll_layer->SetHitTestable(true);
outer_viewport_scroll_layer->SetElementId(
LayerIdToElementIdForTesting(outer_viewport_scroll_layer->id()));
auto viewport_property_ids =
SetupViewportProperties(root, inner_viewport_scroll_layer.get(),
outer_viewport_scroll_layer.get());
layer_tree_impl->AddLayer(std::move(inner_viewport_scroll_layer));
layer_tree_impl->AddLayer(std::move(outer_viewport_scroll_layer));
layer_tree_impl->SetViewportPropertyIds(viewport_property_ids);
}
PropertyTrees* GetPropertyTrees(const Layer* layer) {
return layer->layer_tree_host()->property_trees();
}
PropertyTrees* GetPropertyTrees(const LayerImpl* layer) {
return layer->layer_tree_impl()->property_trees();
}
RenderSurfaceImpl* GetRenderSurface(const LayerImpl* layer) {
auto& effect_tree = GetPropertyTrees(layer)->effect_tree;
if (auto* surface = effect_tree.GetRenderSurface(layer->effect_tree_index()))
return surface;
return effect_tree.GetRenderSurface(GetEffectNode(layer)->target_id);
}
} // namespace cc