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 template <typename LayerType
>
24 struct DataForRecursion
{
25 TransformTree
* transform_tree
;
27 OpacityTree
* opacity_tree
;
28 LayerType
* transform_tree_parent
;
29 LayerType
* transform_fixed_parent
;
30 LayerType
* render_target
;
32 int opacity_tree_parent
;
33 const LayerType
* page_scale_layer
;
34 const LayerType
* inner_viewport_scroll_layer
;
35 const LayerType
* outer_viewport_scroll_layer
;
36 float page_scale_factor
;
37 float device_scale_factor
;
38 bool in_subtree_of_page_scale_layer
;
39 bool affected_by_inner_viewport_bounds_delta
;
40 bool affected_by_outer_viewport_bounds_delta
;
42 bool ancestor_clips_subtree
;
43 const gfx::Transform
* device_transform
;
44 gfx::Vector2dF scroll_compensation_adjustment
;
48 template <typename LayerType
>
49 static LayerType
* GetTransformParent(const DataForRecursion
<LayerType
>& data
,
51 return layer
->position_constraint().is_fixed_position()
52 ? data
.transform_fixed_parent
53 : data
.transform_tree_parent
;
56 template <typename LayerType
>
57 static ClipNode
* GetClipParent(const DataForRecursion
<LayerType
>& data
,
59 const bool inherits_clip
= !layer
->parent() || !layer
->clip_parent();
60 const int id
= inherits_clip
? data
.clip_tree_parent
61 : layer
->clip_parent()->clip_tree_index();
62 return data
.clip_tree
->Node(id
);
65 template <typename LayerType
>
66 static bool RequiresClipNode(LayerType
* layer
,
67 const DataForRecursion
<LayerType
>& data
,
68 int parent_transform_id
,
70 const bool render_surface_applies_clip
=
71 layer
->render_surface() && is_clipped
;
72 const bool render_surface_may_grow_due_to_clip_children
=
73 layer
->render_surface() && layer
->num_unclipped_descendants() > 0;
75 if (layer
->masks_to_bounds() || layer
->mask_layer() ||
76 render_surface_may_grow_due_to_clip_children
)
79 if (!render_surface_applies_clip
)
82 return !!layer
->parent();
85 template <typename LayerType
>
86 static bool LayerClipsSubtree(LayerType
* layer
) {
87 return layer
->masks_to_bounds() || layer
->mask_layer();
90 template <typename LayerType
>
91 void AddClipNodeIfNeeded(const DataForRecursion
<LayerType
>& data_from_ancestor
,
93 bool created_transform_node
,
94 DataForRecursion
<LayerType
>* data_for_children
) {
95 ClipNode
* parent
= GetClipParent(data_from_ancestor
, layer
);
96 int parent_id
= parent
->id
;
98 bool ancestor_clips_subtree
=
99 data_from_ancestor
.ancestor_clips_subtree
||
100 (layer
->clip_parent() && layer
->clip_parent()->is_clipped());
102 data_for_children
->ancestor_clips_subtree
= false;
103 bool has_unclipped_surface
= false;
105 if (layer
->has_render_surface()) {
106 if (ancestor_clips_subtree
&& layer
->num_unclipped_descendants() > 0)
107 data_for_children
->ancestor_clips_subtree
= true;
108 else if (!ancestor_clips_subtree
&& !layer
->num_unclipped_descendants())
109 has_unclipped_surface
= true;
111 data_for_children
->ancestor_clips_subtree
= ancestor_clips_subtree
;
114 bool layer_clips_subtree
= LayerClipsSubtree(layer
);
115 if (layer_clips_subtree
)
116 data_for_children
->ancestor_clips_subtree
= true;
118 if (has_unclipped_surface
)
121 if (!RequiresClipNode(layer
, data_from_ancestor
, parent
->data
.transform_id
,
122 ancestor_clips_subtree
)) {
123 // Unclipped surfaces reset the clip rect.
124 data_for_children
->clip_tree_parent
= parent_id
;
126 LayerType
* transform_parent
= data_for_children
->transform_tree_parent
;
127 if (layer
->position_constraint().is_fixed_position() &&
128 !created_transform_node
) {
129 transform_parent
= data_for_children
->transform_fixed_parent
;
132 node
.data
.clip
= gfx::RectF(
133 gfx::PointF() + layer
->offset_to_transform_parent(), layer
->bounds());
134 node
.data
.transform_id
= transform_parent
->transform_tree_index();
135 node
.data
.target_id
=
136 data_for_children
->render_target
->transform_tree_index();
137 node
.owner_id
= layer
->id();
138 node
.data
.inherit_parent_target_space_clip
=
139 !data_for_children
->ancestor_clips_subtree
&&
140 layer
->has_render_surface() && ancestor_clips_subtree
;
141 node
.data
.requires_tight_clip_rect
=
142 ancestor_clips_subtree
&&
143 (!layer
->render_surface() ||
144 (layer
->render_surface() && !layer_clips_subtree
&&
145 layer
->num_unclipped_descendants()));
146 data_for_children
->clip_tree_parent
=
147 data_for_children
->clip_tree
->Insert(node
, parent_id
);
150 layer
->SetClipTreeIndex(
151 has_unclipped_surface
? 0 : data_for_children
->clip_tree_parent
);
153 layer
->set_is_clipped(data_for_children
->ancestor_clips_subtree
);
155 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the
156 // clip for all children since we may need to draw. We need to figure out a
157 // better way, since we will need both the clipped and unclipped versions.
160 template <typename LayerType
>
161 bool AddTransformNodeIfNeeded(
162 const DataForRecursion
<LayerType
>& data_from_ancestor
,
164 DataForRecursion
<LayerType
>* data_for_children
) {
165 const bool is_root
= !layer
->parent();
166 const bool is_page_scale_layer
= layer
== data_from_ancestor
.page_scale_layer
;
167 const bool is_scrollable
= layer
->scrollable();
168 const bool is_fixed
= layer
->position_constraint().is_fixed_position();
170 const bool has_significant_transform
=
171 !layer
->transform().IsIdentityOr2DTranslation();
173 const bool has_potentially_animated_transform
=
174 layer
->HasPotentiallyRunningTransformAnimation();
176 // A transform node is needed even for a finished animation, since differences
177 // in the timing of animation state updates can mean that an animation that's
178 // in the Finished state at tree-building time on the main thread is still in
179 // the Running state right after commit on the compositor thread.
180 const bool has_any_transform_animation
=
181 layer
->HasAnyAnimationTargetingProperty(Animation::TRANSFORM
);
183 const bool has_surface
= !!layer
->render_surface();
185 bool requires_node
= is_root
|| is_scrollable
|| has_significant_transform
||
186 has_any_transform_animation
|| has_surface
|| is_fixed
||
189 LayerType
* transform_parent
= GetTransformParent(data_from_ancestor
, layer
);
190 DCHECK_IMPLIES(!is_root
, transform_parent
);
192 int parent_index
= 0;
193 if (transform_parent
)
194 parent_index
= transform_parent
->transform_tree_index();
196 int source_index
= parent_index
;
198 gfx::Vector2dF source_offset
;
199 if (transform_parent
) {
200 if (layer
->scroll_parent()) {
201 LayerType
* source
= layer
->parent();
202 source_offset
+= source
->offset_to_transform_parent();
203 source_index
= source
->transform_tree_index();
204 } else if (!is_fixed
) {
205 source_offset
= transform_parent
->offset_to_transform_parent();
207 source_offset
= data_from_ancestor
.transform_tree_parent
208 ->offset_to_transform_parent();
210 data_from_ancestor
.transform_tree_parent
->transform_tree_index();
211 source_offset
+= data_from_ancestor
.scroll_compensation_adjustment
;
215 if (layer
->IsContainerForFixedPositionLayers() || is_root
) {
216 data_for_children
->affected_by_inner_viewport_bounds_delta
=
217 layer
== data_from_ancestor
.inner_viewport_scroll_layer
;
218 data_for_children
->affected_by_outer_viewport_bounds_delta
=
219 layer
== data_from_ancestor
.outer_viewport_scroll_layer
;
222 DCHECK(layer
->transform().IsIdentity());
223 data_for_children
->transform_fixed_parent
= layer
->parent();
225 data_for_children
->transform_fixed_parent
= layer
;
228 data_for_children
->transform_tree_parent
= layer
;
230 if (layer
->IsContainerForFixedPositionLayers() || is_fixed
)
231 data_for_children
->scroll_compensation_adjustment
= gfx::Vector2dF();
233 if (!requires_node
) {
234 data_for_children
->should_flatten
|= layer
->should_flatten_transform();
235 gfx::Vector2dF local_offset
= layer
->position().OffsetFromOrigin() +
236 layer
->transform().To2dTranslation();
237 gfx::Vector2dF source_to_parent
;
238 if (source_index
!= parent_index
) {
239 gfx::Transform to_parent
;
240 data_from_ancestor
.transform_tree
->ComputeTransform(
241 source_index
, parent_index
, &to_parent
);
242 source_to_parent
= to_parent
.To2dTranslation();
244 layer
->set_offset_to_transform_parent(source_offset
+ source_to_parent
+
246 layer
->set_should_flatten_transform_from_property_tree(
247 data_from_ancestor
.should_flatten
);
248 layer
->SetTransformTreeIndex(parent_index
);
252 data_for_children
->transform_tree
->Insert(TransformNode(), parent_index
);
254 TransformNode
* node
= data_for_children
->transform_tree
->back();
255 layer
->SetTransformTreeIndex(node
->id
);
257 node
->data
.scrolls
= is_scrollable
;
258 node
->data
.flattens_inherited_transform
= data_for_children
->should_flatten
;
260 // Surfaces inherently flatten transforms.
261 data_for_children
->should_flatten
=
262 layer
->should_flatten_transform() || has_surface
;
263 node
->data
.target_id
=
264 data_from_ancestor
.render_target
->transform_tree_index();
265 node
->data
.content_target_id
=
266 data_for_children
->render_target
->transform_tree_index();
267 DCHECK_NE(node
->data
.target_id
, -1);
268 node
->data
.is_animated
= has_potentially_animated_transform
;
270 float post_local_scale_factor
= 1.0f
;
272 node
->data
.post_local
= *data_from_ancestor
.device_transform
;
273 post_local_scale_factor
= data_from_ancestor
.device_scale_factor
;
276 if (is_page_scale_layer
)
277 post_local_scale_factor
*= data_from_ancestor
.page_scale_factor
;
279 if (has_surface
&& !is_root
) {
280 node
->data
.needs_sublayer_scale
= true;
281 node
->data
.layer_scale_factor
= data_from_ancestor
.device_scale_factor
;
282 if (data_from_ancestor
.in_subtree_of_page_scale_layer
)
283 node
->data
.layer_scale_factor
*= data_from_ancestor
.page_scale_factor
;
286 node
->data
.source_node_id
= source_index
;
288 node
->data
.post_local
.Scale(post_local_scale_factor
,
289 post_local_scale_factor
);
290 node
->data
.post_local
.Translate(layer
->position().x(),
291 layer
->position().y());
293 node
->data
.post_local_scale_factor
= post_local_scale_factor
;
294 node
->data
.source_offset
= source_offset
;
295 node
->data
.update_post_local_transform(layer
->position(),
296 layer
->transform_origin());
299 if (!layer
->scroll_parent())
300 node
->data
.scroll_offset
= layer
->CurrentScrollOffset();
303 if (data_from_ancestor
.affected_by_inner_viewport_bounds_delta
) {
304 node
->data
.affected_by_inner_viewport_bounds_delta_x
=
305 layer
->position_constraint().is_fixed_to_right_edge();
306 node
->data
.affected_by_inner_viewport_bounds_delta_y
=
307 layer
->position_constraint().is_fixed_to_bottom_edge();
308 if (node
->data
.affected_by_inner_viewport_bounds_delta_x
||
309 node
->data
.affected_by_inner_viewport_bounds_delta_y
) {
310 data_for_children
->transform_tree
311 ->AddNodeAffectedByInnerViewportBoundsDelta(node
->id
);
313 } else if (data_from_ancestor
.affected_by_outer_viewport_bounds_delta
) {
314 node
->data
.affected_by_outer_viewport_bounds_delta_x
=
315 layer
->position_constraint().is_fixed_to_right_edge();
316 node
->data
.affected_by_outer_viewport_bounds_delta_y
=
317 layer
->position_constraint().is_fixed_to_bottom_edge();
318 if (node
->data
.affected_by_outer_viewport_bounds_delta_x
||
319 node
->data
.affected_by_outer_viewport_bounds_delta_y
) {
320 data_for_children
->transform_tree
321 ->AddNodeAffectedByOuterViewportBoundsDelta(node
->id
);
326 node
->data
.local
= layer
->transform();
327 node
->data
.update_pre_local_transform(layer
->transform_origin());
329 node
->data
.needs_local_transform_update
= true;
330 data_from_ancestor
.transform_tree
->UpdateTransforms(node
->id
);
332 layer
->set_offset_to_transform_parent(gfx::Vector2dF());
334 // Flattening (if needed) will be handled by |node|.
335 layer
->set_should_flatten_transform_from_property_tree(false);
337 data_for_children
->scroll_compensation_adjustment
+=
338 layer
->ScrollCompensationAdjustment() - node
->data
.scroll_snap
;
340 node
->owner_id
= layer
->id();
345 bool IsAnimatingOpacity(Layer
* layer
) {
346 return layer
->HasPotentiallyRunningOpacityAnimation() ||
347 layer
->OpacityCanAnimateOnImplThread();
350 bool IsAnimatingOpacity(LayerImpl
* layer
) {
351 return layer
->HasPotentiallyRunningOpacityAnimation();
354 template <typename LayerType
>
355 void AddOpacityNodeIfNeeded(
356 const DataForRecursion
<LayerType
>& data_from_ancestor
,
358 DataForRecursion
<LayerType
>* data_for_children
) {
359 const bool is_root
= !layer
->parent();
360 const bool has_transparency
= layer
->opacity() != 1.f
;
361 const bool has_animated_opacity
= IsAnimatingOpacity(layer
);
362 bool requires_node
= is_root
|| has_transparency
|| has_animated_opacity
;
364 int parent_id
= data_from_ancestor
.opacity_tree_parent
;
366 if (!requires_node
) {
367 layer
->SetOpacityTreeIndex(parent_id
);
368 data_for_children
->opacity_tree_parent
= parent_id
;
373 node
.owner_id
= layer
->id();
374 node
.data
.opacity
= layer
->opacity();
375 node
.data
.screen_space_opacity
= layer
->opacity();
377 node
.data
.screen_space_opacity
*=
378 data_from_ancestor
.opacity_tree
->Node(parent_id
)
379 ->data
.screen_space_opacity
;
380 data_for_children
->opacity_tree_parent
=
381 data_for_children
->opacity_tree
->Insert(node
, parent_id
);
382 layer
->SetOpacityTreeIndex(data_for_children
->opacity_tree_parent
);
385 template <typename LayerType
>
386 void BuildPropertyTreesInternal(
388 const DataForRecursion
<LayerType
>& data_from_parent
) {
389 layer
->set_property_tree_sequence_number(data_from_parent
.sequence_number
);
390 DataForRecursion
<LayerType
> data_for_children(data_from_parent
);
391 if (layer
->render_surface())
392 data_for_children
.render_target
= layer
;
394 bool created_transform_node
=
395 AddTransformNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
396 AddClipNodeIfNeeded(data_from_parent
, layer
, created_transform_node
,
399 if (data_from_parent
.opacity_tree
)
400 AddOpacityNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
402 if (layer
== data_from_parent
.page_scale_layer
)
403 data_for_children
.in_subtree_of_page_scale_layer
= true;
405 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
406 if (!layer
->child_at(i
)->scroll_parent()) {
407 BuildPropertyTreesInternal(layer
->child_at(i
), data_for_children
);
409 // The child should be included in its scroll parent's list of scroll
411 DCHECK(layer
->child_at(i
)->scroll_parent()->scroll_children()->count(
412 layer
->child_at(i
)));
416 if (layer
->scroll_children()) {
417 for (LayerType
* scroll_child
: *layer
->scroll_children()) {
418 DCHECK_EQ(scroll_child
->scroll_parent(), layer
);
419 BuildPropertyTreesInternal(scroll_child
, data_for_children
);
423 if (layer
->has_replica())
424 BuildPropertyTreesInternal(layer
->replica_layer(), data_for_children
);
429 template <typename LayerType
>
430 void BuildPropertyTreesTopLevelInternal(
431 LayerType
* root_layer
,
432 const LayerType
* page_scale_layer
,
433 const LayerType
* inner_viewport_scroll_layer
,
434 const LayerType
* outer_viewport_scroll_layer
,
435 float page_scale_factor
,
436 float device_scale_factor
,
437 const gfx::Rect
& viewport
,
438 const gfx::Transform
& device_transform
,
439 PropertyTrees
* property_trees
) {
440 if (!property_trees
->needs_rebuild
)
443 property_trees
->sequence_number
++;
445 DataForRecursion
<LayerType
> data_for_recursion
;
446 data_for_recursion
.transform_tree
= &property_trees
->transform_tree
;
447 data_for_recursion
.clip_tree
= &property_trees
->clip_tree
;
448 data_for_recursion
.opacity_tree
= &property_trees
->opacity_tree
;
449 data_for_recursion
.transform_tree_parent
= nullptr;
450 data_for_recursion
.transform_fixed_parent
= nullptr;
451 data_for_recursion
.render_target
= root_layer
;
452 data_for_recursion
.clip_tree_parent
= 0;
453 data_for_recursion
.opacity_tree_parent
= -1;
454 data_for_recursion
.page_scale_layer
= page_scale_layer
;
455 data_for_recursion
.inner_viewport_scroll_layer
= inner_viewport_scroll_layer
;
456 data_for_recursion
.outer_viewport_scroll_layer
= outer_viewport_scroll_layer
;
457 data_for_recursion
.page_scale_factor
= page_scale_factor
;
458 data_for_recursion
.device_scale_factor
= device_scale_factor
;
459 data_for_recursion
.in_subtree_of_page_scale_layer
= false;
460 data_for_recursion
.affected_by_inner_viewport_bounds_delta
= false;
461 data_for_recursion
.affected_by_outer_viewport_bounds_delta
= false;
462 data_for_recursion
.should_flatten
= false;
463 data_for_recursion
.ancestor_clips_subtree
= true;
464 data_for_recursion
.device_transform
= &device_transform
;
466 data_for_recursion
.transform_tree
->clear();
467 data_for_recursion
.clip_tree
->clear();
468 data_for_recursion
.opacity_tree
->clear();
469 data_for_recursion
.sequence_number
= property_trees
->sequence_number
;
472 root_clip
.data
.clip
= viewport
;
473 root_clip
.data
.transform_id
= 0;
474 data_for_recursion
.clip_tree_parent
=
475 data_for_recursion
.clip_tree
->Insert(root_clip
, 0);
476 BuildPropertyTreesInternal(root_layer
, data_for_recursion
);
477 property_trees
->needs_rebuild
= false;
479 // The transform tree is kept up-to-date as it is built, but the
480 // combined_clips stored in the clip tree aren't computed during tree
482 property_trees
->transform_tree
.set_needs_update(false);
483 property_trees
->clip_tree
.set_needs_update(true);
484 property_trees
->opacity_tree
.set_needs_update(false);
487 void PropertyTreeBuilder::BuildPropertyTrees(
489 const Layer
* page_scale_layer
,
490 const Layer
* inner_viewport_scroll_layer
,
491 const Layer
* outer_viewport_scroll_layer
,
492 float page_scale_factor
,
493 float device_scale_factor
,
494 const gfx::Rect
& viewport
,
495 const gfx::Transform
& device_transform
,
496 PropertyTrees
* property_trees
) {
497 BuildPropertyTreesTopLevelInternal(
498 root_layer
, page_scale_layer
, inner_viewport_scroll_layer
,
499 outer_viewport_scroll_layer
, page_scale_factor
, device_scale_factor
,
500 viewport
, device_transform
, property_trees
);
503 void PropertyTreeBuilder::BuildPropertyTrees(
504 LayerImpl
* root_layer
,
505 const LayerImpl
* page_scale_layer
,
506 const LayerImpl
* inner_viewport_scroll_layer
,
507 const LayerImpl
* outer_viewport_scroll_layer
,
508 float page_scale_factor
,
509 float device_scale_factor
,
510 const gfx::Rect
& viewport
,
511 const gfx::Transform
& device_transform
,
512 PropertyTrees
* property_trees
) {
513 BuildPropertyTreesTopLevelInternal(
514 root_layer
, page_scale_layer
, inner_viewport_scroll_layer
,
515 outer_viewport_scroll_layer
, page_scale_factor
, device_scale_factor
,
516 viewport
, device_transform
, property_trees
);