1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "cc/trees/property_tree_builder.h"
10 #include "cc/base/math_util.h"
11 #include "cc/layers/layer.h"
12 #include "cc/layers/layer_impl.h"
13 #include "cc/trees/layer_tree_host.h"
14 #include "ui/gfx/geometry/point_f.h"
15 #include "ui/gfx/geometry/vector2d_conversions.h"
23 static const int kInvalidPropertyTreeNodeId
= -1;
24 static const int kRootPropertyTreeNodeId
= 0;
25 static const int kUnclippedRootClipTreeNodeId
= 0;
27 template <typename LayerType
>
28 struct DataForRecursion
{
29 TransformTree
* transform_tree
;
31 EffectTree
* effect_tree
;
32 LayerType
* transform_tree_parent
;
33 LayerType
* transform_fixed_parent
;
36 int effect_tree_parent
;
37 const LayerType
* page_scale_layer
;
38 const LayerType
* inner_viewport_scroll_layer
;
39 const LayerType
* outer_viewport_scroll_layer
;
40 float page_scale_factor
;
41 float device_scale_factor
;
42 bool in_subtree_of_page_scale_layer
;
43 bool affected_by_inner_viewport_bounds_delta
;
44 bool affected_by_outer_viewport_bounds_delta
;
46 bool ancestor_clips_subtree
;
47 const gfx::Transform
* device_transform
;
48 gfx::Vector2dF scroll_compensation_adjustment
;
52 template <typename LayerType
>
53 static LayerType
* GetTransformParent(const DataForRecursion
<LayerType
>& data
,
55 return layer
->position_constraint().is_fixed_position()
56 ? data
.transform_fixed_parent
57 : data
.transform_tree_parent
;
60 template <typename LayerType
>
61 static ClipNode
* GetClipParent(const DataForRecursion
<LayerType
>& data
,
63 const bool inherits_clip
= !layer
->parent() || !layer
->clip_parent();
64 const int id
= inherits_clip
? data
.clip_tree_parent
65 : layer
->clip_parent()->clip_tree_index();
66 return data
.clip_tree
->Node(id
);
69 template <typename LayerType
>
70 static bool RequiresClipNode(LayerType
* layer
,
71 const DataForRecursion
<LayerType
>& data
,
72 int parent_transform_id
,
74 const bool render_surface_applies_clip
=
75 layer
->has_render_surface() && is_clipped
;
76 const bool render_surface_may_grow_due_to_clip_children
=
77 layer
->has_render_surface() && layer
->num_unclipped_descendants() > 0;
79 if (layer
->masks_to_bounds() || layer
->mask_layer() ||
80 render_surface_may_grow_due_to_clip_children
)
83 if (!render_surface_applies_clip
)
89 template <typename LayerType
>
90 static bool LayerClipsSubtree(LayerType
* layer
) {
91 return layer
->masks_to_bounds() || layer
->mask_layer();
94 template <typename LayerType
>
95 void AddClipNodeIfNeeded(const DataForRecursion
<LayerType
>& data_from_ancestor
,
97 bool created_render_surface
,
98 bool created_transform_node
,
99 DataForRecursion
<LayerType
>* data_for_children
) {
100 ClipNode
* parent
= GetClipParent(data_from_ancestor
, layer
);
101 int parent_id
= parent
->id
;
103 bool ancestor_clips_subtree
=
104 data_from_ancestor
.ancestor_clips_subtree
||
105 (layer
->clip_parent() && layer
->clip_parent()->is_clipped());
107 data_for_children
->ancestor_clips_subtree
= false;
108 bool has_unclipped_surface
= false;
110 if (layer
->has_render_surface()) {
111 if (ancestor_clips_subtree
&& layer
->num_unclipped_descendants() > 0)
112 data_for_children
->ancestor_clips_subtree
= true;
113 else if (!ancestor_clips_subtree
)
114 has_unclipped_surface
= true;
116 data_for_children
->ancestor_clips_subtree
= ancestor_clips_subtree
;
119 bool layer_clips_subtree
= LayerClipsSubtree(layer
);
120 if (layer_clips_subtree
)
121 data_for_children
->ancestor_clips_subtree
= true;
123 if (has_unclipped_surface
) {
124 parent_id
= kUnclippedRootClipTreeNodeId
;
125 data_for_children
->effect_tree
->Node(data_for_children
->render_target
)
126 ->data
.clip_id
= kUnclippedRootClipTreeNodeId
;
128 if (!RequiresClipNode(layer
, data_from_ancestor
, parent
->data
.transform_id
,
129 ancestor_clips_subtree
)) {
130 // Unclipped surfaces reset the clip rect.
131 data_for_children
->clip_tree_parent
= parent_id
;
133 LayerType
* transform_parent
= data_for_children
->transform_tree_parent
;
134 if (layer
->position_constraint().is_fixed_position() &&
135 !created_transform_node
) {
136 transform_parent
= data_for_children
->transform_fixed_parent
;
139 node
.data
.clip
= gfx::RectF(
140 gfx::PointF() + layer
->offset_to_transform_parent(), layer
->bounds());
141 node
.data
.transform_id
= transform_parent
->transform_tree_index();
142 node
.data
.target_id
=
143 data_for_children
->effect_tree
->Node(data_for_children
->render_target
)
145 node
.owner_id
= layer
->id();
146 node
.data
.inherit_parent_target_space_clip
= !layer_clips_subtree
&&
147 layer
->has_render_surface() &&
148 ancestor_clips_subtree
;
149 node
.data
.requires_tight_clip_rect
=
150 ancestor_clips_subtree
&&
151 (!layer
->has_render_surface() ||
152 (!layer_clips_subtree
&& layer
->num_unclipped_descendants()));
154 node
.data
.render_surface_is_clipped
= layer
->has_render_surface() &&
155 ancestor_clips_subtree
&&
156 !layer
->num_unclipped_descendants();
158 data_for_children
->clip_tree_parent
=
159 data_for_children
->clip_tree
->Insert(node
, parent_id
);
162 layer
->SetClipTreeIndex(data_for_children
->clip_tree_parent
);
164 layer
->set_is_clipped(data_for_children
->ancestor_clips_subtree
);
166 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the
167 // clip for all children since we may need to draw. We need to figure out a
168 // better way, since we will need both the clipped and unclipped versions.
171 template <typename LayerType
>
172 bool AddTransformNodeIfNeeded(
173 const DataForRecursion
<LayerType
>& data_from_ancestor
,
175 bool created_render_surface
,
176 DataForRecursion
<LayerType
>* data_for_children
) {
177 const bool is_root
= !layer
->parent();
178 const bool is_page_scale_layer
= layer
== data_from_ancestor
.page_scale_layer
;
179 const bool is_scrollable
= layer
->scrollable();
180 const bool is_fixed
= layer
->position_constraint().is_fixed_position();
182 const bool has_significant_transform
=
183 !layer
->transform().IsIdentityOr2DTranslation();
185 const bool has_potentially_animated_transform
=
186 layer
->HasPotentiallyRunningTransformAnimation();
188 // A transform node is needed even for a finished animation, since differences
189 // in the timing of animation state updates can mean that an animation that's
190 // in the Finished state at tree-building time on the main thread is still in
191 // the Running state right after commit on the compositor thread.
192 const bool has_any_transform_animation
=
193 layer
->HasAnyAnimationTargetingProperty(Animation::TRANSFORM
);
195 const bool has_surface
= layer
->has_render_surface();
197 bool requires_node
= is_root
|| is_scrollable
|| has_significant_transform
||
198 has_any_transform_animation
|| has_surface
|| is_fixed
||
201 LayerType
* transform_parent
= GetTransformParent(data_from_ancestor
, layer
);
202 DCHECK_IMPLIES(!is_root
, transform_parent
);
204 int parent_index
= kRootPropertyTreeNodeId
;
205 if (transform_parent
)
206 parent_index
= transform_parent
->transform_tree_index();
208 int source_index
= parent_index
;
210 gfx::Vector2dF source_offset
;
211 if (transform_parent
) {
212 if (layer
->scroll_parent()) {
213 LayerType
* source
= layer
->parent();
214 source_offset
+= source
->offset_to_transform_parent();
215 source_index
= source
->transform_tree_index();
216 } else if (!is_fixed
) {
217 source_offset
= transform_parent
->offset_to_transform_parent();
219 source_offset
= data_from_ancestor
.transform_tree_parent
220 ->offset_to_transform_parent();
222 data_from_ancestor
.transform_tree_parent
->transform_tree_index();
223 source_offset
+= data_from_ancestor
.scroll_compensation_adjustment
;
227 if (layer
->IsContainerForFixedPositionLayers() || is_root
) {
228 data_for_children
->affected_by_inner_viewport_bounds_delta
=
229 layer
== data_from_ancestor
.inner_viewport_scroll_layer
;
230 data_for_children
->affected_by_outer_viewport_bounds_delta
=
231 layer
== data_from_ancestor
.outer_viewport_scroll_layer
;
234 DCHECK(layer
->transform().IsIdentity());
235 data_for_children
->transform_fixed_parent
= layer
->parent();
237 data_for_children
->transform_fixed_parent
= layer
;
240 data_for_children
->transform_tree_parent
= layer
;
242 if (layer
->IsContainerForFixedPositionLayers() || is_fixed
)
243 data_for_children
->scroll_compensation_adjustment
= gfx::Vector2dF();
245 if (!requires_node
) {
246 data_for_children
->should_flatten
|= layer
->should_flatten_transform();
247 gfx::Vector2dF local_offset
= layer
->position().OffsetFromOrigin() +
248 layer
->transform().To2dTranslation();
249 gfx::Vector2dF source_to_parent
;
250 if (source_index
!= parent_index
) {
251 gfx::Transform to_parent
;
252 data_from_ancestor
.transform_tree
->ComputeTransform(
253 source_index
, parent_index
, &to_parent
);
254 source_to_parent
= to_parent
.To2dTranslation();
256 layer
->set_offset_to_transform_parent(source_offset
+ source_to_parent
+
258 layer
->set_should_flatten_transform_from_property_tree(
259 data_from_ancestor
.should_flatten
);
260 layer
->SetTransformTreeIndex(parent_index
);
264 data_for_children
->transform_tree
->Insert(TransformNode(), parent_index
);
266 TransformNode
* node
= data_for_children
->transform_tree
->back();
267 layer
->SetTransformTreeIndex(node
->id
);
269 node
->data
.scrolls
= is_scrollable
;
270 node
->data
.flattens_inherited_transform
= data_for_children
->should_flatten
;
272 // Surfaces inherently flatten transforms.
273 data_for_children
->should_flatten
=
274 layer
->should_flatten_transform() || has_surface
;
275 DCHECK_GT(data_from_ancestor
.effect_tree
->size(), 0u);
277 node
->data
.target_id
=
278 data_for_children
->effect_tree
->Node(data_from_ancestor
.render_target
)
280 node
->data
.content_target_id
=
281 data_for_children
->effect_tree
->Node(data_for_children
->render_target
)
283 DCHECK_NE(node
->data
.target_id
, kInvalidPropertyTreeNodeId
);
285 node
->data
.is_animated
= has_potentially_animated_transform
;
286 if (has_potentially_animated_transform
) {
287 float maximum_animation_target_scale
= 0.f
;
288 if (layer
->MaximumTargetScale(&maximum_animation_target_scale
)) {
289 node
->data
.local_maximum_animation_target_scale
=
290 maximum_animation_target_scale
;
293 float starting_animation_scale
= 0.f
;
294 if (layer
->AnimationStartScale(&starting_animation_scale
)) {
295 node
->data
.local_starting_animation_scale
= starting_animation_scale
;
298 node
->data
.has_only_translation_animations
=
299 layer
->HasOnlyTranslationTransforms();
302 float post_local_scale_factor
= 1.0f
;
304 node
->data
.post_local
= *data_from_ancestor
.device_transform
;
305 post_local_scale_factor
= data_from_ancestor
.device_scale_factor
;
308 if (is_page_scale_layer
)
309 post_local_scale_factor
*= data_from_ancestor
.page_scale_factor
;
311 if (has_surface
&& !is_root
) {
312 node
->data
.needs_sublayer_scale
= true;
313 node
->data
.layer_scale_factor
= data_from_ancestor
.device_scale_factor
;
314 if (data_from_ancestor
.in_subtree_of_page_scale_layer
)
315 node
->data
.layer_scale_factor
*= data_from_ancestor
.page_scale_factor
;
318 node
->data
.source_node_id
= source_index
;
320 node
->data
.post_local
.Scale(post_local_scale_factor
,
321 post_local_scale_factor
);
322 node
->data
.post_local
.Translate(layer
->position().x(),
323 layer
->position().y());
325 node
->data
.post_local_scale_factor
= post_local_scale_factor
;
326 node
->data
.source_offset
= source_offset
;
327 node
->data
.update_post_local_transform(layer
->position(),
328 layer
->transform_origin());
331 if (!layer
->scroll_parent())
332 node
->data
.scroll_offset
= layer
->CurrentScrollOffset();
335 if (data_from_ancestor
.affected_by_inner_viewport_bounds_delta
) {
336 node
->data
.affected_by_inner_viewport_bounds_delta_x
=
337 layer
->position_constraint().is_fixed_to_right_edge();
338 node
->data
.affected_by_inner_viewport_bounds_delta_y
=
339 layer
->position_constraint().is_fixed_to_bottom_edge();
340 if (node
->data
.affected_by_inner_viewport_bounds_delta_x
||
341 node
->data
.affected_by_inner_viewport_bounds_delta_y
) {
342 data_for_children
->transform_tree
343 ->AddNodeAffectedByInnerViewportBoundsDelta(node
->id
);
345 } else if (data_from_ancestor
.affected_by_outer_viewport_bounds_delta
) {
346 node
->data
.affected_by_outer_viewport_bounds_delta_x
=
347 layer
->position_constraint().is_fixed_to_right_edge();
348 node
->data
.affected_by_outer_viewport_bounds_delta_y
=
349 layer
->position_constraint().is_fixed_to_bottom_edge();
350 if (node
->data
.affected_by_outer_viewport_bounds_delta_x
||
351 node
->data
.affected_by_outer_viewport_bounds_delta_y
) {
352 data_for_children
->transform_tree
353 ->AddNodeAffectedByOuterViewportBoundsDelta(node
->id
);
358 node
->data
.local
= layer
->transform();
359 node
->data
.update_pre_local_transform(layer
->transform_origin());
361 node
->data
.needs_local_transform_update
= true;
362 data_from_ancestor
.transform_tree
->UpdateTransforms(node
->id
);
364 layer
->set_offset_to_transform_parent(gfx::Vector2dF());
366 // Flattening (if needed) will be handled by |node|.
367 layer
->set_should_flatten_transform_from_property_tree(false);
369 data_for_children
->scroll_compensation_adjustment
+=
370 layer
->ScrollCompensationAdjustment() - node
->data
.scroll_snap
;
372 node
->owner_id
= layer
->id();
377 bool IsAnimatingOpacity(Layer
* layer
) {
378 return layer
->HasPotentiallyRunningOpacityAnimation() ||
379 layer
->OpacityCanAnimateOnImplThread();
382 bool IsAnimatingOpacity(LayerImpl
* layer
) {
383 return layer
->HasPotentiallyRunningOpacityAnimation();
386 template <typename LayerType
>
387 bool AddEffectNodeIfNeeded(
388 const DataForRecursion
<LayerType
>& data_from_ancestor
,
390 DataForRecursion
<LayerType
>* data_for_children
) {
391 const bool is_root
= !layer
->parent();
392 const bool has_transparency
= layer
->opacity() != 1.f
;
393 const bool has_animated_opacity
= IsAnimatingOpacity(layer
);
394 const bool has_render_surface
= layer
->has_render_surface();
396 is_root
|| has_transparency
|| has_animated_opacity
|| has_render_surface
;
398 int parent_id
= data_from_ancestor
.effect_tree_parent
;
400 if (!requires_node
) {
401 layer
->SetEffectTreeIndex(parent_id
);
402 data_for_children
->effect_tree_parent
= parent_id
;
407 node
.owner_id
= layer
->id();
408 node
.data
.opacity
= layer
->opacity();
409 node
.data
.screen_space_opacity
= layer
->opacity();
410 node
.data
.has_render_surface
= has_render_surface
;
412 // For every effect node, we create a transform node, so it's safe to use
413 // the next available id from the transform tree as this effect node's
415 node
.data
.transform_id
=
416 data_from_ancestor
.transform_tree
->next_available_id();
417 node
.data
.clip_id
= data_from_ancestor
.clip_tree_parent
;
419 node
.data
.screen_space_opacity
*=
420 data_from_ancestor
.effect_tree
->Node(parent_id
)
421 ->data
.screen_space_opacity
;
423 // Root render surface acts the unbounded and untransformed to draw content
424 // into. Transform node created from root layer (includes device scale
425 // factor) and clip node created from root layer (include viewports) applies
426 // to root render surface's content, but not root render surface itself.
427 node
.data
.transform_id
= kRootPropertyTreeNodeId
;
428 node
.data
.clip_id
= kUnclippedRootClipTreeNodeId
;
430 data_for_children
->effect_tree_parent
=
431 data_for_children
->effect_tree
->Insert(node
, parent_id
);
432 layer
->SetEffectTreeIndex(data_for_children
->effect_tree_parent
);
433 return has_render_surface
;
436 template <typename LayerType
>
437 void BuildPropertyTreesInternal(
439 const DataForRecursion
<LayerType
>& data_from_parent
) {
440 layer
->set_property_tree_sequence_number(data_from_parent
.sequence_number
);
441 DataForRecursion
<LayerType
> data_for_children(data_from_parent
);
443 bool created_render_surface
=
444 AddEffectNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
446 if (created_render_surface
) {
447 data_for_children
.render_target
= data_for_children
.effect_tree_parent
;
448 layer
->set_draw_blend_mode(SkXfermode::kSrcOver_Mode
);
450 layer
->set_draw_blend_mode(layer
->blend_mode());
453 bool created_transform_node
= AddTransformNodeIfNeeded(
454 data_from_parent
, layer
, created_render_surface
, &data_for_children
);
455 AddClipNodeIfNeeded(data_from_parent
, layer
, created_render_surface
,
456 created_transform_node
, &data_for_children
);
458 if (layer
== data_from_parent
.page_scale_layer
)
459 data_for_children
.in_subtree_of_page_scale_layer
= true;
461 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
462 if (!layer
->child_at(i
)->scroll_parent()) {
463 BuildPropertyTreesInternal(layer
->child_at(i
), data_for_children
);
465 // The child should be included in its scroll parent's list of scroll
467 DCHECK(layer
->child_at(i
)->scroll_parent()->scroll_children()->count(
468 layer
->child_at(i
)));
472 if (layer
->scroll_children()) {
473 for (LayerType
* scroll_child
: *layer
->scroll_children()) {
474 DCHECK_EQ(scroll_child
->scroll_parent(), layer
);
475 BuildPropertyTreesInternal(scroll_child
, data_for_children
);
479 if (layer
->has_replica())
480 BuildPropertyTreesInternal(layer
->replica_layer(), data_for_children
);
485 template <typename LayerType
>
486 void BuildPropertyTreesTopLevelInternal(
487 LayerType
* root_layer
,
488 const LayerType
* page_scale_layer
,
489 const LayerType
* inner_viewport_scroll_layer
,
490 const LayerType
* outer_viewport_scroll_layer
,
491 float page_scale_factor
,
492 float device_scale_factor
,
493 const gfx::Rect
& viewport
,
494 const gfx::Transform
& device_transform
,
495 PropertyTrees
* property_trees
) {
496 if (!property_trees
->needs_rebuild
)
499 property_trees
->sequence_number
++;
501 DataForRecursion
<LayerType
> data_for_recursion
;
502 data_for_recursion
.transform_tree
= &property_trees
->transform_tree
;
503 data_for_recursion
.clip_tree
= &property_trees
->clip_tree
;
504 data_for_recursion
.effect_tree
= &property_trees
->effect_tree
;
505 data_for_recursion
.transform_tree_parent
= nullptr;
506 data_for_recursion
.transform_fixed_parent
= nullptr;
507 data_for_recursion
.render_target
= kRootPropertyTreeNodeId
;
508 data_for_recursion
.clip_tree_parent
= kUnclippedRootClipTreeNodeId
;
509 data_for_recursion
.effect_tree_parent
= kInvalidPropertyTreeNodeId
;
510 data_for_recursion
.page_scale_layer
= page_scale_layer
;
511 data_for_recursion
.inner_viewport_scroll_layer
= inner_viewport_scroll_layer
;
512 data_for_recursion
.outer_viewport_scroll_layer
= outer_viewport_scroll_layer
;
513 data_for_recursion
.page_scale_factor
= page_scale_factor
;
514 data_for_recursion
.device_scale_factor
= device_scale_factor
;
515 data_for_recursion
.in_subtree_of_page_scale_layer
= false;
516 data_for_recursion
.affected_by_inner_viewport_bounds_delta
= false;
517 data_for_recursion
.affected_by_outer_viewport_bounds_delta
= false;
518 data_for_recursion
.should_flatten
= false;
519 data_for_recursion
.ancestor_clips_subtree
= true;
520 data_for_recursion
.device_transform
= &device_transform
;
522 data_for_recursion
.transform_tree
->clear();
523 data_for_recursion
.clip_tree
->clear();
524 data_for_recursion
.effect_tree
->clear();
525 data_for_recursion
.sequence_number
= property_trees
->sequence_number
;
528 root_clip
.data
.clip
= gfx::RectF(viewport
);
529 root_clip
.data
.transform_id
= kRootPropertyTreeNodeId
;
530 data_for_recursion
.clip_tree_parent
= data_for_recursion
.clip_tree
->Insert(
531 root_clip
, kUnclippedRootClipTreeNodeId
);
532 BuildPropertyTreesInternal(root_layer
, data_for_recursion
);
533 property_trees
->needs_rebuild
= false;
535 // The transform tree is kept up-to-date as it is built, but the
536 // combined_clips stored in the clip tree aren't computed during tree
538 property_trees
->transform_tree
.set_needs_update(false);
539 property_trees
->clip_tree
.set_needs_update(true);
540 property_trees
->effect_tree
.set_needs_update(false);
543 void PropertyTreeBuilder::BuildPropertyTrees(
545 const Layer
* page_scale_layer
,
546 const Layer
* inner_viewport_scroll_layer
,
547 const Layer
* outer_viewport_scroll_layer
,
548 float page_scale_factor
,
549 float device_scale_factor
,
550 const gfx::Rect
& viewport
,
551 const gfx::Transform
& device_transform
,
552 PropertyTrees
* property_trees
) {
553 BuildPropertyTreesTopLevelInternal(
554 root_layer
, page_scale_layer
, inner_viewport_scroll_layer
,
555 outer_viewport_scroll_layer
, page_scale_factor
, device_scale_factor
,
556 viewport
, device_transform
, property_trees
);
559 void PropertyTreeBuilder::BuildPropertyTrees(
560 LayerImpl
* root_layer
,
561 const LayerImpl
* page_scale_layer
,
562 const LayerImpl
* inner_viewport_scroll_layer
,
563 const LayerImpl
* outer_viewport_scroll_layer
,
564 float page_scale_factor
,
565 float device_scale_factor
,
566 const gfx::Rect
& viewport
,
567 const gfx::Transform
& device_transform
,
568 PropertyTrees
* property_trees
) {
569 BuildPropertyTreesTopLevelInternal(
570 root_layer
, page_scale_layer
, inner_viewport_scroll_layer
,
571 outer_viewport_scroll_layer
, page_scale_factor
, device_scale_factor
,
572 viewport
, device_transform
, property_trees
);