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 float page_scale_factor
;
35 float device_scale_factor
;
36 bool in_subtree_of_page_scale_layer
;
38 bool ancestor_clips_subtree
;
39 const gfx::Transform
* device_transform
;
40 gfx::Vector2dF scroll_compensation_adjustment
;
44 template <typename LayerType
>
45 static LayerType
* GetTransformParent(const DataForRecursion
<LayerType
>& data
,
47 return layer
->position_constraint().is_fixed_position()
48 ? data
.transform_fixed_parent
49 : data
.transform_tree_parent
;
52 template <typename LayerType
>
53 static ClipNode
* GetClipParent(const DataForRecursion
<LayerType
>& data
,
55 const bool inherits_clip
= !layer
->parent() || !layer
->clip_parent();
56 const int id
= inherits_clip
? data
.clip_tree_parent
57 : layer
->clip_parent()->clip_tree_index();
58 return data
.clip_tree
->Node(id
);
61 template <typename LayerType
>
62 static bool HasPotentiallyRunningAnimation(LayerType
* layer
,
63 Animation::TargetProperty property
) {
64 if (Animation
* animation
=
65 layer
->layer_animation_controller()->GetAnimation(property
)) {
66 return !animation
->is_finished();
71 template <typename LayerType
>
72 static bool RequiresClipNode(LayerType
* layer
,
73 const DataForRecursion
<LayerType
>& data
,
74 int parent_transform_id
,
76 const bool render_surface_applies_clip
=
77 layer
->render_surface() && is_clipped
;
78 const bool render_surface_may_grow_due_to_clip_children
=
79 layer
->render_surface() && layer
->num_unclipped_descendants() > 0;
81 if (!layer
->parent() || layer
->masks_to_bounds() || layer
->mask_layer() ||
82 render_surface_may_grow_due_to_clip_children
)
85 if (!render_surface_applies_clip
)
88 bool axis_aligned_with_respect_to_parent
=
89 data
.transform_tree
->Are2DAxisAligned(layer
->transform_tree_index(),
92 return !axis_aligned_with_respect_to_parent
;
95 template <typename LayerType
>
96 static bool LayerClipsSubtree(LayerType
* layer
) {
97 return layer
->masks_to_bounds() || layer
->mask_layer();
100 template <typename LayerType
>
101 void AddClipNodeIfNeeded(const DataForRecursion
<LayerType
>& data_from_ancestor
,
103 bool created_transform_node
,
104 DataForRecursion
<LayerType
>* data_for_children
) {
105 ClipNode
* parent
= GetClipParent(data_from_ancestor
, layer
);
106 int parent_id
= parent
->id
;
108 bool ancestor_clips_subtree
=
109 data_from_ancestor
.ancestor_clips_subtree
|| layer
->clip_parent();
111 data_for_children
->ancestor_clips_subtree
= false;
112 bool has_unclipped_surface
= false;
114 if (layer
->has_render_surface()) {
115 if (ancestor_clips_subtree
&& layer
->num_unclipped_descendants() > 0)
116 data_for_children
->ancestor_clips_subtree
= true;
117 else if (!ancestor_clips_subtree
&& !layer
->num_unclipped_descendants())
118 has_unclipped_surface
= true;
120 data_for_children
->ancestor_clips_subtree
= ancestor_clips_subtree
;
123 if (LayerClipsSubtree(layer
))
124 data_for_children
->ancestor_clips_subtree
= true;
126 if (has_unclipped_surface
)
129 if (!RequiresClipNode(layer
, data_from_ancestor
, parent
->data
.transform_id
,
130 data_for_children
->ancestor_clips_subtree
)) {
131 // Unclipped surfaces reset the clip rect.
132 data_for_children
->clip_tree_parent
= parent_id
;
133 } else if (layer
->parent()) {
134 // Note the root clip gets handled elsewhere.
135 LayerType
* transform_parent
= data_for_children
->transform_tree_parent
;
136 if (layer
->position_constraint().is_fixed_position() &&
137 !created_transform_node
) {
138 transform_parent
= data_for_children
->transform_fixed_parent
;
141 node
.data
.clip
= gfx::RectF(
142 gfx::PointF() + layer
->offset_to_transform_parent(), layer
->bounds());
143 node
.data
.transform_id
= transform_parent
->transform_tree_index();
144 node
.data
.target_id
=
145 data_for_children
->render_target
->transform_tree_index();
146 node
.owner_id
= layer
->id();
148 data_for_children
->clip_tree_parent
=
149 data_for_children
->clip_tree
->Insert(node
, parent_id
);
152 layer
->SetClipTreeIndex(
153 has_unclipped_surface
? 0 : data_for_children
->clip_tree_parent
);
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 HasPotentiallyRunningAnimation(layer
, Animation::TRANSFORM
);
176 const bool has_animated_transform
=
177 layer
->layer_animation_controller()->IsAnimatingProperty(
178 Animation::TRANSFORM
);
180 const bool has_surface
= !!layer
->render_surface();
182 bool requires_node
= is_root
|| is_scrollable
|| has_significant_transform
||
183 has_potentially_animated_transform
|| has_surface
||
184 is_fixed
|| is_page_scale_layer
;
186 LayerType
* transform_parent
= GetTransformParent(data_from_ancestor
, layer
);
188 int parent_index
= 0;
189 if (transform_parent
)
190 parent_index
= transform_parent
->transform_tree_index();
192 int source_index
= parent_index
;
194 gfx::Vector2dF source_offset
;
195 if (transform_parent
) {
196 if (layer
->scroll_parent()) {
197 LayerType
* source
= layer
->parent();
198 source_offset
+= source
->offset_to_transform_parent();
199 source_index
= source
->transform_tree_index();
200 } else if (!is_fixed
) {
201 source_offset
= transform_parent
->offset_to_transform_parent();
203 if (data_from_ancestor
.transform_tree_parent
!=
204 data_from_ancestor
.transform_fixed_parent
) {
205 source_offset
= data_from_ancestor
.transform_tree_parent
206 ->offset_to_transform_parent();
208 data_from_ancestor
.transform_tree_parent
->transform_tree_index();
210 source_offset
+= data_from_ancestor
.scroll_compensation_adjustment
;
214 if (layer
->IsContainerForFixedPositionLayers() || is_root
) {
217 DCHECK(layer
->transform().IsIdentity());
218 data_for_children
->transform_fixed_parent
= layer
->parent();
220 data_for_children
->transform_fixed_parent
= layer
;
223 data_for_children
->transform_tree_parent
= layer
;
225 if (layer
->IsContainerForFixedPositionLayers() || is_fixed
)
226 data_for_children
->scroll_compensation_adjustment
= gfx::Vector2dF();
228 if (!requires_node
) {
229 data_for_children
->should_flatten
|= layer
->should_flatten_transform();
230 gfx::Vector2dF local_offset
= layer
->position().OffsetFromOrigin() +
231 layer
->transform().To2dTranslation();
232 gfx::Vector2dF source_to_parent
;
233 if (source_index
!= parent_index
) {
234 gfx::Transform to_parent
;
235 data_from_ancestor
.transform_tree
->ComputeTransform(
236 source_index
, parent_index
, &to_parent
);
237 source_to_parent
= to_parent
.To2dTranslation();
239 layer
->set_offset_to_transform_parent(source_offset
+ source_to_parent
+
241 layer
->set_should_flatten_transform_from_property_tree(
242 data_from_ancestor
.should_flatten
);
243 layer
->SetTransformTreeIndex(parent_index
);
247 data_for_children
->transform_tree
->Insert(TransformNode(), parent_index
);
249 TransformNode
* node
= data_for_children
->transform_tree
->back();
250 layer
->SetTransformTreeIndex(node
->id
);
252 node
->data
.scrolls
= is_scrollable
;
253 node
->data
.flattens_inherited_transform
= data_for_children
->should_flatten
;
255 // Surfaces inherently flatten transforms.
256 data_for_children
->should_flatten
=
257 layer
->should_flatten_transform() || has_surface
;
258 node
->data
.target_id
=
259 data_from_ancestor
.render_target
->transform_tree_index();
260 node
->data
.content_target_id
=
261 data_for_children
->render_target
->transform_tree_index();
262 DCHECK_NE(node
->data
.target_id
, -1);
263 node
->data
.is_animated
= has_animated_transform
;
265 float post_local_scale_factor
= 1.0f
;
267 node
->data
.post_local
= *data_from_ancestor
.device_transform
;
268 post_local_scale_factor
= data_from_ancestor
.device_scale_factor
;
271 if (is_page_scale_layer
)
272 post_local_scale_factor
*= data_from_ancestor
.page_scale_factor
;
274 if (has_surface
&& !is_root
) {
275 node
->data
.needs_sublayer_scale
= true;
276 node
->data
.layer_scale_factor
= data_from_ancestor
.device_scale_factor
;
277 if (data_from_ancestor
.in_subtree_of_page_scale_layer
)
278 node
->data
.layer_scale_factor
*= data_from_ancestor
.page_scale_factor
;
281 node
->data
.source_node_id
= source_index
;
283 node
->data
.post_local
.Scale(post_local_scale_factor
,
284 post_local_scale_factor
);
285 node
->data
.post_local
.Translate(layer
->position().x(),
286 layer
->position().y());
288 node
->data
.post_local_scale_factor
= post_local_scale_factor
;
289 node
->data
.source_offset
= source_offset
;
290 node
->data
.update_post_local_transform(layer
->position(),
291 layer
->transform_origin());
294 if (!layer
->scroll_parent())
295 node
->data
.scroll_offset
= layer
->CurrentScrollOffset();
297 node
->data
.local
= layer
->transform();
298 node
->data
.update_pre_local_transform(layer
->transform_origin());
300 node
->data
.needs_local_transform_update
= true;
301 data_from_ancestor
.transform_tree
->UpdateTransforms(node
->id
);
303 layer
->set_offset_to_transform_parent(gfx::Vector2dF());
305 // Flattening (if needed) will be handled by |node|.
306 layer
->set_should_flatten_transform_from_property_tree(false);
308 data_for_children
->scroll_compensation_adjustment
+=
309 layer
->ScrollCompensationAdjustment() - node
->data
.scroll_snap
;
311 node
->owner_id
= layer
->id();
316 bool IsAnimatingOpacity(Layer
* layer
) {
317 return HasPotentiallyRunningAnimation(layer
, Animation::OPACITY
) ||
318 layer
->OpacityCanAnimateOnImplThread();
321 bool IsAnimatingOpacity(LayerImpl
* layer
) {
322 return HasPotentiallyRunningAnimation(layer
, Animation::OPACITY
);
325 template <typename LayerType
>
326 void AddOpacityNodeIfNeeded(
327 const DataForRecursion
<LayerType
>& data_from_ancestor
,
329 DataForRecursion
<LayerType
>* data_for_children
) {
330 const bool is_root
= !layer
->parent();
331 const bool has_transparency
= layer
->opacity() != 1.f
;
332 const bool has_animated_opacity
= IsAnimatingOpacity(layer
);
333 bool requires_node
= is_root
|| has_transparency
|| has_animated_opacity
;
335 int parent_id
= data_from_ancestor
.opacity_tree_parent
;
337 if (!requires_node
) {
338 layer
->SetOpacityTreeIndex(parent_id
);
339 data_for_children
->opacity_tree_parent
= parent_id
;
344 node
.owner_id
= layer
->id();
345 node
.data
= layer
->opacity();
346 data_for_children
->opacity_tree_parent
=
347 data_for_children
->opacity_tree
->Insert(node
, parent_id
);
348 layer
->SetOpacityTreeIndex(data_for_children
->opacity_tree_parent
);
351 template <typename LayerType
>
352 void BuildPropertyTreesInternal(
354 const DataForRecursion
<LayerType
>& data_from_parent
) {
355 layer
->set_property_tree_sequence_number(data_from_parent
.sequence_number
);
356 DataForRecursion
<LayerType
> data_for_children(data_from_parent
);
357 if (layer
->render_surface())
358 data_for_children
.render_target
= layer
;
360 bool created_transform_node
=
361 AddTransformNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
362 AddClipNodeIfNeeded(data_from_parent
, layer
, created_transform_node
,
365 if (data_from_parent
.opacity_tree
)
366 AddOpacityNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
368 if (layer
== data_from_parent
.page_scale_layer
)
369 data_for_children
.in_subtree_of_page_scale_layer
= true;
371 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
372 if (!layer
->child_at(i
)->scroll_parent())
373 BuildPropertyTreesInternal(layer
->child_at(i
), data_for_children
);
376 if (layer
->scroll_children()) {
377 for (LayerType
* scroll_child
: *layer
->scroll_children()) {
378 BuildPropertyTreesInternal(scroll_child
, data_for_children
);
382 if (layer
->has_replica())
383 BuildPropertyTreesInternal(layer
->replica_layer(), data_for_children
);
388 template <typename LayerType
>
389 void BuildPropertyTreesTopLevelInternal(LayerType
* root_layer
,
390 const LayerType
* page_scale_layer
,
391 float page_scale_factor
,
392 float device_scale_factor
,
393 const gfx::Rect
& viewport
,
394 const gfx::Transform
& device_transform
,
395 PropertyTrees
* property_trees
) {
396 if (!property_trees
->needs_rebuild
)
399 property_trees
->sequence_number
++;
401 DataForRecursion
<LayerType
> data_for_recursion
;
402 data_for_recursion
.transform_tree
= &property_trees
->transform_tree
;
403 data_for_recursion
.clip_tree
= &property_trees
->clip_tree
;
404 data_for_recursion
.opacity_tree
= &property_trees
->opacity_tree
;
405 data_for_recursion
.transform_tree_parent
= nullptr;
406 data_for_recursion
.transform_fixed_parent
= nullptr;
407 data_for_recursion
.render_target
= root_layer
;
408 data_for_recursion
.clip_tree_parent
= 0;
409 data_for_recursion
.opacity_tree_parent
= -1;
410 data_for_recursion
.page_scale_layer
= page_scale_layer
;
411 data_for_recursion
.page_scale_factor
= page_scale_factor
;
412 data_for_recursion
.device_scale_factor
= device_scale_factor
;
413 data_for_recursion
.in_subtree_of_page_scale_layer
= false;
414 data_for_recursion
.should_flatten
= false;
415 data_for_recursion
.ancestor_clips_subtree
= true;
416 data_for_recursion
.device_transform
= &device_transform
;
418 data_for_recursion
.transform_tree
->clear();
419 data_for_recursion
.clip_tree
->clear();
420 data_for_recursion
.opacity_tree
->clear();
421 data_for_recursion
.sequence_number
= property_trees
->sequence_number
;
424 root_clip
.data
.clip
= viewport
;
425 root_clip
.data
.transform_id
= 0;
426 data_for_recursion
.clip_tree_parent
=
427 data_for_recursion
.clip_tree
->Insert(root_clip
, 0);
428 BuildPropertyTreesInternal(root_layer
, data_for_recursion
);
429 property_trees
->needs_rebuild
= false;
431 // The transform tree is kept up-to-date as it is built, but the
432 // combined_clips stored in the clip tree aren't computed during tree
434 property_trees
->transform_tree
.set_needs_update(false);
435 property_trees
->clip_tree
.set_needs_update(true);
438 void PropertyTreeBuilder::BuildPropertyTrees(
440 const Layer
* page_scale_layer
,
441 float page_scale_factor
,
442 float device_scale_factor
,
443 const gfx::Rect
& viewport
,
444 const gfx::Transform
& device_transform
,
445 PropertyTrees
* property_trees
) {
446 BuildPropertyTreesTopLevelInternal(
447 root_layer
, page_scale_layer
, page_scale_factor
, device_scale_factor
,
448 viewport
, device_transform
, property_trees
);
451 void PropertyTreeBuilder::BuildPropertyTrees(
452 LayerImpl
* root_layer
,
453 const LayerImpl
* page_scale_layer
,
454 float page_scale_factor
,
455 float device_scale_factor
,
456 const gfx::Rect
& viewport
,
457 const gfx::Transform
& device_transform
,
458 PropertyTrees
* property_trees
) {
459 BuildPropertyTreesTopLevelInternal(
460 root_layer
, page_scale_layer
, page_scale_factor
, device_scale_factor
,
461 viewport
, device_transform
, property_trees
);