| Index: cc/trees/property_tree_builder.cc
|
| diff --git a/cc/trees/property_tree_builder.cc b/cc/trees/property_tree_builder.cc
|
| index 8763b91b5f95e2e180d024cc5a999f3d50fb62f5..a770bd6a6bb03fb9172a9c3aef6656ee22cfd036 100644
|
| --- a/cc/trees/property_tree_builder.cc
|
| +++ b/cc/trees/property_tree_builder.cc
|
| @@ -47,6 +47,8 @@ struct DataForRecursion {
|
| bool target_is_clipped;
|
| const gfx::Transform* device_transform;
|
| gfx::Vector2dF scroll_compensation_adjustment;
|
| + gfx::Transform compound_transform_since_render_target;
|
| + bool axis_align_since_render_target;
|
| int sequence_number;
|
| };
|
|
|
| @@ -70,11 +72,11 @@ static ClipNode* GetClipParent(const DataForRecursion<LayerType>& data,
|
| template <typename LayerType>
|
| static bool AppliesClip(LayerType* layer,
|
| const DataForRecursion<LayerType>& data,
|
| + bool created_render_surface,
|
| bool is_clipped) {
|
| - const bool render_surface_applies_clip =
|
| - layer->has_render_surface() && is_clipped;
|
| + const bool render_surface_applies_clip = created_render_surface && is_clipped;
|
| const bool render_surface_may_grow_due_to_clip_children =
|
| - layer->has_render_surface() && layer->num_unclipped_descendants() > 0;
|
| + created_render_surface && layer->num_unclipped_descendants() > 0;
|
|
|
| if (layer->masks_to_bounds() || layer->mask_layer() ||
|
| render_surface_may_grow_due_to_clip_children)
|
| @@ -108,7 +110,7 @@ void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor,
|
| bool layers_are_clipped = false;
|
| bool has_unclipped_surface = false;
|
|
|
| - if (layer->has_render_surface()) {
|
| + if (created_render_surface) {
|
| // Clips can usually be applied to a surface's descendants simply by
|
| // clipping the surface (or applied implicitly by the surface's bounds).
|
| // However, if the surface has unclipped descendants (layers that aren't
|
| @@ -147,7 +149,8 @@ void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor,
|
| parent->data.layers_are_clipped_when_surfaces_disabled;
|
|
|
| bool applies_clip =
|
| - AppliesClip(layer, data_from_ancestor, ancestor_clips_subtree);
|
| + AppliesClip(layer, data_from_ancestor, created_render_surface,
|
| + ancestor_clips_subtree);
|
| bool parent_applies_clip = !parent->data.resets_clip;
|
|
|
| // When we have an unclipped surface, all ancestor clips no longer apply.
|
| @@ -182,7 +185,7 @@ void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor,
|
| // Surfaces reset the rect used for layer clipping. At other nodes, layer
|
| // clipping state from ancestors must continue to get propagated.
|
| node.data.layer_clipping_uses_only_local_clip =
|
| - layer->has_render_surface() || !ancestor_clips_subtree;
|
| + created_render_surface || !ancestor_clips_subtree;
|
| } else {
|
| // Otherwise, we're either unclipped, or exist only in order to apply our
|
| // parent's clips in our space.
|
| @@ -201,7 +204,6 @@ void AddClipNodeIfNeeded(const DataForRecursion<LayerType>& data_from_ancestor,
|
| }
|
|
|
| layer->SetClipTreeIndex(data_for_children->clip_tree_parent);
|
| -
|
| // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the
|
| // clip for all children since we may need to draw. We need to figure out a
|
| // better way, since we will need both the clipped and unclipped versions.
|
| @@ -233,7 +235,7 @@ bool AddTransformNodeIfNeeded(
|
| const bool has_any_transform_animation =
|
| layer->HasAnyAnimationTargetingProperty(Animation::TRANSFORM);
|
|
|
| - const bool has_surface = layer->has_render_surface();
|
| + const bool has_surface = created_render_surface;
|
|
|
| bool requires_node = is_root || is_scrollable || has_significant_transform ||
|
| has_any_transform_animation || has_surface || is_fixed ||
|
| @@ -431,6 +433,122 @@ bool IsAnimatingOpacity(LayerImpl* layer) {
|
| }
|
|
|
| template <typename LayerType>
|
| +static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
|
| + return layer->Is3dSorted() && layer->parent() &&
|
| + layer->parent()->Is3dSorted() &&
|
| + (layer->parent()->sorting_context_id() == layer->sorting_context_id());
|
| +}
|
| +
|
| +template <typename LayerType>
|
| +bool ShouldCreateRenderSurface(LayerType* layer,
|
| + gfx::Transform current_transform,
|
| + bool axis_aligned) {
|
| + const bool preserves_2d_axis_alignment =
|
| + (current_transform * layer->transform()).Preserves2dAxisAlignment() &&
|
| + axis_aligned && layer->AnimationsPreserveAxisAlignment();
|
| + const bool is_root = !layer->parent();
|
| + if (is_root)
|
| + return true;
|
| +
|
| + // If the layer uses a mask and the layer is not a replica layer.
|
| + // TODO(weiliangc): After slimming paint there won't be replica layers.
|
| + if (layer->mask_layer() && layer->parent()->replica_layer() != layer) {
|
| + return true;
|
| + }
|
| +
|
| + // If the layer has a reflection.
|
| + if (layer->replica_layer()) {
|
| + return true;
|
| + }
|
| +
|
| + // If the layer uses a CSS filter.
|
| + if (!layer->filters().IsEmpty() || !layer->background_filters().IsEmpty()) {
|
| + return true;
|
| + }
|
| +
|
| + // If the layer will use a CSS filter. In this case, the animation
|
| + // will start and add a filter to this layer, so it needs a surface.
|
| + if (layer->HasPotentiallyRunningFilterAnimation()) {
|
| + return true;
|
| + }
|
| +
|
| + int num_descendants_that_draw_content =
|
| + layer->NumDescendantsThatDrawContent();
|
| +
|
| + // If the layer flattens its subtree, but it is treated as a 3D object by its
|
| + // parent (i.e. parent participates in a 3D rendering context).
|
| + if (LayerIsInExisting3DRenderingContext(layer) &&
|
| + layer->should_flatten_transform() &&
|
| + num_descendants_that_draw_content > 0) {
|
| + TRACE_EVENT_INSTANT0(
|
| + "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface flattening",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + return true;
|
| + }
|
| +
|
| + // If the layer has blending.
|
| + // TODO(rosca): this is temporary, until blending is implemented for other
|
| + // types of quads than RenderPassDrawQuad. Layers having descendants that draw
|
| + // content will still create a separate rendering surface.
|
| + if (!layer->uses_default_blend_mode()) {
|
| + TRACE_EVENT_INSTANT0(
|
| + "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface blending",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + return true;
|
| + }
|
| + // If the layer clips its descendants but it is not axis-aligned with respect
|
| + // to its parent.
|
| + bool layer_clips_external_content =
|
| + LayerClipsSubtree(layer) || layer->HasDelegatedContent();
|
| + if (layer_clips_external_content && !preserves_2d_axis_alignment &&
|
| + num_descendants_that_draw_content > 0) {
|
| + TRACE_EVENT_INSTANT0(
|
| + "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface clipping",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + return true;
|
| + }
|
| +
|
| + // If the layer has some translucency and does not have a preserves-3d
|
| + // transform style. This condition only needs a render surface if two or more
|
| + // layers in the subtree overlap. But checking layer overlaps is unnecessarily
|
| + // costly so instead we conservatively create a surface whenever at least two
|
| + // layers draw content for this subtree.
|
| + bool at_least_two_layers_in_subtree_draw_content =
|
| + num_descendants_that_draw_content > 0 &&
|
| + (layer->DrawsContent() || num_descendants_that_draw_content > 1);
|
| +
|
| + if (layer->opacity() != 1.f && layer->should_flatten_transform() &&
|
| + at_least_two_layers_in_subtree_draw_content) {
|
| + TRACE_EVENT_INSTANT0(
|
| + "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface opacity",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + DCHECK(!is_root);
|
| + return true;
|
| + }
|
| + // If the layer has isolation.
|
| + // TODO(rosca): to be optimized - create separate rendering surface only when
|
| + // the blending descendants might have access to the content behind this layer
|
| + // (layer has transparent background or descendants overflow).
|
| + // https://code.google.com/p/chromium/issues/detail?id=301738
|
| + if (layer->is_root_for_isolated_group()) {
|
| + TRACE_EVENT_INSTANT0(
|
| + "cc", "PropertyTreeBuilder::ShouldCreateRenderSurface isolation",
|
| + TRACE_EVENT_SCOPE_THREAD);
|
| + return true;
|
| + }
|
| +
|
| + // If we force it.
|
| + if (layer->force_render_surface())
|
| + return true;
|
| +
|
| + // If we'll make a copy of the layer's contents.
|
| + if (layer->HasCopyRequest())
|
| + return true;
|
| +
|
| + return false;
|
| +}
|
| +
|
| +template <typename LayerType>
|
| bool AddEffectNodeIfNeeded(
|
| const DataForRecursion<LayerType>& data_from_ancestor,
|
| LayerType* layer,
|
| @@ -438,15 +556,22 @@ bool AddEffectNodeIfNeeded(
|
| const bool is_root = !layer->parent();
|
| const bool has_transparency = layer->opacity() != 1.f;
|
| const bool has_animated_opacity = IsAnimatingOpacity(layer);
|
| - const bool has_render_surface = layer->has_render_surface();
|
| - bool requires_node =
|
| - is_root || has_transparency || has_animated_opacity || has_render_surface;
|
| + const bool should_create_render_surface = ShouldCreateRenderSurface(
|
| + layer, data_from_ancestor.compound_transform_since_render_target,
|
| + data_from_ancestor.axis_align_since_render_target);
|
| + data_for_children->axis_align_since_render_target &=
|
| + layer->AnimationsPreserveAxisAlignment();
|
| +
|
| + bool requires_node = is_root || has_transparency || has_animated_opacity ||
|
| + should_create_render_surface;
|
|
|
| int parent_id = data_from_ancestor.effect_tree_parent;
|
|
|
| if (!requires_node) {
|
| layer->SetEffectTreeIndex(parent_id);
|
| data_for_children->effect_tree_parent = parent_id;
|
| + data_for_children->compound_transform_since_render_target *=
|
| + layer->transform();
|
| return false;
|
| }
|
|
|
| @@ -454,7 +579,8 @@ bool AddEffectNodeIfNeeded(
|
| node.owner_id = layer->id();
|
| node.data.opacity = layer->opacity();
|
| node.data.screen_space_opacity = layer->opacity();
|
| - node.data.has_render_surface = has_render_surface;
|
| + node.data.has_render_surface = should_create_render_surface;
|
| +
|
| if (!is_root) {
|
| // For every effect node, we create a transform node, so it's safe to use
|
| // the next available id from the transform tree as this effect node's
|
| @@ -477,7 +603,12 @@ bool AddEffectNodeIfNeeded(
|
| data_for_children->effect_tree_parent =
|
| data_for_children->effect_tree->Insert(node, parent_id);
|
| layer->SetEffectTreeIndex(data_for_children->effect_tree_parent);
|
| - return has_render_surface;
|
| + if (should_create_render_surface) {
|
| + data_for_children->compound_transform_since_render_target =
|
| + gfx::Transform();
|
| + data_for_children->axis_align_since_render_target = true;
|
| + }
|
| + return should_create_render_surface;
|
| }
|
|
|
| template <typename LayerType>
|
| @@ -581,6 +712,8 @@ void BuildPropertyTreesTopLevelInternal(
|
| data_for_recursion.transform_tree->clear();
|
| data_for_recursion.clip_tree->clear();
|
| data_for_recursion.effect_tree->clear();
|
| + data_for_recursion.compound_transform_since_render_target = gfx::Transform();
|
| + data_for_recursion.axis_align_since_render_target = true;
|
| data_for_recursion.sequence_number = property_trees->sequence_number;
|
| data_for_recursion.transform_tree->set_device_scale_factor(
|
| device_scale_factor);
|
|
|