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/trees/layer_tree_host.h"
13 #include "ui/gfx/geometry/point_f.h"
14 #include "ui/gfx/geometry/vector2d_conversions.h"
22 struct DataForRecursion
{
23 TransformTree
* transform_tree
;
25 OpacityTree
* opacity_tree
;
26 Layer
* transform_tree_parent
;
27 Layer
* transform_fixed_parent
;
30 int opacity_tree_parent
;
31 const Layer
* page_scale_layer
;
32 float page_scale_factor
;
33 float device_scale_factor
;
34 bool in_subtree_of_page_scale_application_layer
;
36 const gfx::Transform
* device_transform
;
37 gfx::Vector2dF scroll_compensation_adjustment
;
40 static Layer
* GetTransformParent(const DataForRecursion
& data
, Layer
* layer
) {
41 return layer
->position_constraint().is_fixed_position()
42 ? data
.transform_fixed_parent
43 : data
.transform_tree_parent
;
46 static ClipNode
* GetClipParent(const DataForRecursion
& data
, Layer
* layer
) {
47 const bool inherits_clip
= !layer
->parent() || !layer
->clip_parent();
48 const int id
= inherits_clip
? data
.clip_tree_parent
49 : layer
->clip_parent()->clip_tree_index();
50 return data
.clip_tree
->Node(id
);
53 static bool RequiresClipNode(Layer
* layer
,
54 bool axis_aligned_with_respect_to_parent
) {
55 const bool render_surface_applies_non_axis_aligned_clip
=
56 layer
->render_surface() && !axis_aligned_with_respect_to_parent
&&
58 const bool render_surface_may_grow_due_to_clip_children
=
59 layer
->render_surface() && layer
->num_unclipped_descendants() > 0;
61 return !layer
->parent() || layer
->masks_to_bounds() || layer
->mask_layer() ||
62 render_surface_applies_non_axis_aligned_clip
||
63 render_surface_may_grow_due_to_clip_children
;
66 void AddClipNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
68 bool created_transform_node
,
69 DataForRecursion
* data_for_children
) {
70 ClipNode
* parent
= GetClipParent(data_from_ancestor
, layer
);
71 int parent_id
= parent
->id
;
72 const bool axis_aligned_with_respect_to_parent
=
73 data_from_ancestor
.transform_tree
->Are2DAxisAligned(
74 layer
->transform_tree_index(), parent
->data
.transform_id
);
76 // TODO(vollick): once Andrew refactors the surface determinations out of
77 // CDP, the the layer->render_surface() check will be invalid.
78 const bool has_unclipped_surface
=
79 layer
->render_surface() &&
80 !layer
->render_surface()->is_clipped() &&
81 layer
->num_unclipped_descendants() == 0;
83 if (has_unclipped_surface
)
86 if (!RequiresClipNode(layer
, axis_aligned_with_respect_to_parent
)) {
87 // Unclipped surfaces reset the clip rect.
88 data_for_children
->clip_tree_parent
= parent_id
;
89 } else if (layer
->parent()) {
90 // Note the root clip gets handled elsewhere.
91 Layer
* transform_parent
= data_for_children
->transform_tree_parent
;
92 if (layer
->position_constraint().is_fixed_position() &&
93 !created_transform_node
) {
94 transform_parent
= data_for_children
->transform_fixed_parent
;
97 node
.data
.clip
= gfx::RectF(
98 gfx::PointF() + layer
->offset_to_transform_parent(), layer
->bounds());
99 node
.data
.transform_id
= transform_parent
->transform_tree_index();
100 node
.data
.target_id
=
101 data_for_children
->render_target
->transform_tree_index();
103 data_for_children
->clip_tree_parent
=
104 data_for_children
->clip_tree
->Insert(node
, parent_id
);
107 layer
->set_clip_tree_index(
108 has_unclipped_surface
? 0 : data_for_children
->clip_tree_parent
);
110 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the
111 // clip for all children since we may need to draw. We need to figure out a
112 // better way, since we will need both the clipped and unclipped versions.
115 bool AddTransformNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
117 DataForRecursion
* data_for_children
) {
118 const bool is_root
= !layer
->parent();
119 const bool is_page_scale_application_layer
=
120 layer
->parent() && layer
->parent() == data_from_ancestor
.page_scale_layer
;
121 const bool is_scrollable
= layer
->scrollable();
122 const bool is_fixed
= layer
->position_constraint().is_fixed_position();
124 const bool has_significant_transform
=
125 !layer
->transform().IsIdentityOr2DTranslation();
127 const bool has_animated_transform
=
128 layer
->layer_animation_controller()->IsAnimatingProperty(
129 Animation::TRANSFORM
);
131 const bool has_surface
= !!layer
->render_surface();
133 bool requires_node
= is_root
|| is_scrollable
|| has_significant_transform
||
134 has_animated_transform
|| has_surface
||
135 is_page_scale_application_layer
;
137 Layer
* transform_parent
= GetTransformParent(data_from_ancestor
, layer
);
139 gfx::Vector2dF parent_offset
;
140 if (transform_parent
) {
141 if (layer
->scroll_parent()) {
142 gfx::Transform to_parent
;
143 Layer
* source
= layer
->parent();
144 parent_offset
+= source
->offset_to_transform_parent();
145 data_from_ancestor
.transform_tree
->ComputeTransform(
146 source
->transform_tree_index(),
147 transform_parent
->transform_tree_index(), &to_parent
);
148 parent_offset
+= to_parent
.To2dTranslation();
149 } else if (!is_fixed
) {
150 parent_offset
= transform_parent
->offset_to_transform_parent();
152 if (data_from_ancestor
.transform_tree_parent
!=
153 data_from_ancestor
.transform_fixed_parent
) {
154 gfx::Vector2dF fixed_offset
= data_from_ancestor
.transform_tree_parent
155 ->offset_to_transform_parent();
156 gfx::Transform parent_to_parent
;
157 data_from_ancestor
.transform_tree
->ComputeTransform(
158 data_from_ancestor
.transform_tree_parent
->transform_tree_index(),
159 data_from_ancestor
.transform_fixed_parent
->transform_tree_index(),
162 fixed_offset
+= parent_to_parent
.To2dTranslation();
163 parent_offset
+= fixed_offset
;
165 parent_offset
+= data_from_ancestor
.scroll_compensation_adjustment
;
169 if (layer
->IsContainerForFixedPositionLayers() || is_root
)
170 data_for_children
->transform_fixed_parent
= layer
;
171 data_for_children
->transform_tree_parent
= layer
;
173 if (layer
->IsContainerForFixedPositionLayers() || is_fixed
)
174 data_for_children
->scroll_compensation_adjustment
= gfx::Vector2dF();
176 if (!requires_node
) {
177 data_for_children
->should_flatten
|= layer
->should_flatten_transform();
178 gfx::Vector2dF local_offset
= layer
->position().OffsetFromOrigin() +
179 layer
->transform().To2dTranslation();
180 layer
->set_offset_to_transform_parent(parent_offset
+ local_offset
);
181 layer
->set_should_flatten_transform_from_property_tree(
182 data_from_ancestor
.should_flatten
);
183 layer
->set_transform_tree_index(transform_parent
->transform_tree_index());
187 int parent_index
= 0;
188 if (transform_parent
)
189 parent_index
= transform_parent
->transform_tree_index();
191 data_for_children
->transform_tree
->Insert(TransformNode(), parent_index
);
193 TransformNode
* node
= data_for_children
->transform_tree
->back();
194 layer
->set_transform_tree_index(node
->id
);
196 node
->data
.scrolls
= is_scrollable
;
197 node
->data
.flattens_inherited_transform
= data_for_children
->should_flatten
;
199 // Surfaces inherently flatten transforms.
200 data_for_children
->should_flatten
=
201 layer
->should_flatten_transform() || has_surface
;
202 node
->data
.target_id
=
203 data_from_ancestor
.render_target
->transform_tree_index();
204 node
->data
.content_target_id
=
205 data_for_children
->render_target
->transform_tree_index();
206 DCHECK_NE(node
->data
.target_id
, -1);
207 node
->data
.is_animated
= layer
->TransformIsAnimating();
209 float scale_factors
= 1.0f
;
211 node
->data
.post_local
= *data_from_ancestor
.device_transform
;
212 scale_factors
= data_from_ancestor
.device_scale_factor
;
215 if (is_page_scale_application_layer
)
216 scale_factors
*= data_from_ancestor
.page_scale_factor
;
218 if (has_surface
&& !is_root
) {
219 node
->data
.needs_sublayer_scale
= true;
220 node
->data
.layer_scale_factor
= data_from_ancestor
.device_scale_factor
;
221 if (data_from_ancestor
.in_subtree_of_page_scale_application_layer
)
222 node
->data
.layer_scale_factor
*= data_from_ancestor
.page_scale_factor
;
225 node
->data
.post_local
.Scale(scale_factors
, scale_factors
);
226 node
->data
.post_local
.Translate3d(
227 layer
->position().x() + parent_offset
.x() + layer
->transform_origin().x(),
228 layer
->position().y() + parent_offset
.y() + layer
->transform_origin().y(),
229 layer
->transform_origin().z());
231 if (!layer
->scroll_parent()) {
232 node
->data
.scroll_offset
=
233 gfx::ScrollOffsetToVector2dF(layer
->CurrentScrollOffset());
236 node
->data
.local
= layer
->transform();
237 node
->data
.pre_local
.Translate3d(-layer
->transform_origin().x(),
238 -layer
->transform_origin().y(),
239 -layer
->transform_origin().z());
241 node
->data
.needs_local_transform_update
= true;
242 data_from_ancestor
.transform_tree
->UpdateTransforms(node
->id
);
244 layer
->set_offset_to_transform_parent(gfx::Vector2dF());
246 // Flattening (if needed) will be handled by |node|.
247 layer
->set_should_flatten_transform_from_property_tree(false);
249 data_for_children
->scroll_compensation_adjustment
+=
250 layer
->ScrollCompensationAdjustment() - node
->data
.scroll_snap
;
254 void AddOpacityNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
256 DataForRecursion
* data_for_children
) {
257 const bool is_root
= !layer
->parent();
258 const bool has_transparency
= layer
->opacity() != 1.f
;
259 const bool has_animated_opacity
=
260 layer
->layer_animation_controller()->IsAnimatingProperty(
261 Animation::OPACITY
) ||
262 layer
->OpacityCanAnimateOnImplThread();
263 bool requires_node
= is_root
|| has_transparency
|| has_animated_opacity
;
265 int parent_id
= data_from_ancestor
.opacity_tree_parent
;
267 if (!requires_node
) {
268 layer
->set_opacity_tree_index(parent_id
);
269 data_for_children
->opacity_tree_parent
= parent_id
;
274 node
.data
= layer
->opacity();
275 data_for_children
->opacity_tree_parent
=
276 data_for_children
->opacity_tree
->Insert(node
, parent_id
);
277 layer
->set_opacity_tree_index(data_for_children
->opacity_tree_parent
);
280 void BuildPropertyTreesInternal(Layer
* layer
,
281 const DataForRecursion
& data_from_parent
) {
282 DataForRecursion
data_for_children(data_from_parent
);
283 if (layer
->render_surface())
284 data_for_children
.render_target
= layer
;
286 bool created_transform_node
=
287 AddTransformNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
288 AddClipNodeIfNeeded(data_from_parent
, layer
, created_transform_node
,
291 if (data_from_parent
.opacity_tree
)
292 AddOpacityNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
294 if (layer
== data_from_parent
.page_scale_layer
)
295 data_for_children
.in_subtree_of_page_scale_application_layer
= true;
297 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
298 if (!layer
->children()[i
]->scroll_parent())
299 BuildPropertyTreesInternal(layer
->children()[i
].get(), data_for_children
);
302 if (layer
->scroll_children()) {
303 for (Layer
* scroll_child
: *layer
->scroll_children()) {
304 BuildPropertyTreesInternal(scroll_child
, data_for_children
);
308 if (layer
->has_replica())
309 BuildPropertyTreesInternal(layer
->replica_layer(), data_for_children
);
314 void PropertyTreeBuilder::BuildPropertyTrees(
316 const Layer
* page_scale_layer
,
317 float page_scale_factor
,
318 float device_scale_factor
,
319 const gfx::Rect
& viewport
,
320 const gfx::Transform
& device_transform
,
321 TransformTree
* transform_tree
,
323 OpacityTree
* opacity_tree
) {
324 DataForRecursion data_for_recursion
;
325 data_for_recursion
.transform_tree
= transform_tree
;
326 data_for_recursion
.clip_tree
= clip_tree
;
327 data_for_recursion
.opacity_tree
= opacity_tree
;
328 data_for_recursion
.transform_tree_parent
= nullptr;
329 data_for_recursion
.transform_fixed_parent
= nullptr;
330 data_for_recursion
.render_target
= root_layer
;
331 data_for_recursion
.clip_tree_parent
= 0;
332 data_for_recursion
.opacity_tree_parent
= -1;
333 data_for_recursion
.page_scale_layer
= page_scale_layer
;
334 data_for_recursion
.page_scale_factor
= page_scale_factor
;
335 data_for_recursion
.device_scale_factor
= device_scale_factor
;
336 data_for_recursion
.in_subtree_of_page_scale_application_layer
= false;
337 data_for_recursion
.should_flatten
= false;
338 data_for_recursion
.device_transform
= &device_transform
;
341 root_clip
.data
.clip
= viewport
;
342 root_clip
.data
.transform_id
= 0;
343 data_for_recursion
.clip_tree_parent
= clip_tree
->Insert(root_clip
, 0);
344 BuildPropertyTreesInternal(root_layer
, data_for_recursion
);