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"
21 struct DataForRecursion
{
22 TransformTree
* transform_tree
;
24 OpacityTree
* opacity_tree
;
25 Layer
* transform_tree_parent
;
26 Layer
* transform_fixed_parent
;
29 int opacity_tree_parent
;
30 const Layer
* page_scale_layer
;
31 float page_scale_factor
;
32 float device_scale_factor
;
33 bool in_subtree_of_page_scale_application_layer
;
35 const gfx::Transform
* device_transform
;
38 static Layer
* GetTransformParent(const DataForRecursion
& data
, Layer
* layer
) {
39 return layer
->position_constraint().is_fixed_position()
40 ? data
.transform_fixed_parent
41 : data
.transform_tree_parent
;
44 static ClipNode
* GetClipParent(const DataForRecursion
& data
, Layer
* layer
) {
45 const bool inherits_clip
= !layer
->parent() || !layer
->clip_parent();
46 const int id
= inherits_clip
? data
.clip_tree_parent
47 : layer
->clip_parent()->clip_tree_index();
48 return data
.clip_tree
->Node(id
);
51 static bool RequiresClipNode(Layer
* layer
,
52 bool axis_aligned_with_respect_to_parent
) {
53 const bool render_surface_applies_non_axis_aligned_clip
=
54 layer
->render_surface() && !axis_aligned_with_respect_to_parent
&&
56 const bool render_surface_may_grow_due_to_clip_children
=
57 layer
->render_surface() && layer
->num_unclipped_descendants() > 0;
59 return !layer
->parent() || layer
->masks_to_bounds() || layer
->mask_layer() ||
60 render_surface_applies_non_axis_aligned_clip
||
61 render_surface_may_grow_due_to_clip_children
;
64 void AddClipNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
66 DataForRecursion
* data_for_children
) {
67 ClipNode
* parent
= GetClipParent(data_from_ancestor
, layer
);
68 int parent_id
= parent
->id
;
69 const bool axis_aligned_with_respect_to_parent
=
70 data_from_ancestor
.transform_tree
->Are2DAxisAligned(
71 layer
->transform_tree_index(), parent
->data
.transform_id
);
73 // TODO(vollick): once Andrew refactors the surface determinations out of
74 // CDP, the the layer->render_surface() check will be invalid.
75 const bool has_unclipped_surface
=
76 layer
->render_surface() &&
77 !layer
->render_surface()->is_clipped() &&
78 layer
->num_unclipped_descendants() == 0;
80 if (has_unclipped_surface
)
83 if (!RequiresClipNode(layer
, axis_aligned_with_respect_to_parent
)) {
84 // Unclipped surfaces reset the clip rect.
85 data_for_children
->clip_tree_parent
= parent_id
;
86 } else if (layer
->parent()) {
87 // Note the root clip gets handled elsewhere.
88 Layer
* transform_parent
= GetTransformParent(*data_for_children
, layer
);
90 node
.data
.clip
= gfx::RectF(
91 gfx::PointF() + layer
->offset_to_transform_parent(), layer
->bounds());
92 node
.data
.transform_id
= transform_parent
->transform_tree_index();
94 data_from_ancestor
.render_target
->transform_tree_index();
96 data_for_children
->clip_tree_parent
=
97 data_for_children
->clip_tree
->Insert(node
, parent_id
);
100 layer
->set_clip_tree_index(
101 has_unclipped_surface
? 0 : data_for_children
->clip_tree_parent
);
103 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the
104 // clip for all children since we may need to draw. We need to figure out a
105 // better way, since we will need both the clipped and unclipped versions.
108 void AddTransformNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
110 DataForRecursion
* data_for_children
) {
111 const bool is_root
= !layer
->parent();
112 const bool is_page_scale_application_layer
=
113 layer
->parent() && layer
->parent() == data_from_ancestor
.page_scale_layer
;
114 const bool is_scrollable
= layer
->scrollable();
115 const bool is_fixed
= layer
->position_constraint().is_fixed_position();
117 const bool has_significant_transform
=
118 !layer
->transform().IsIdentityOr2DTranslation();
120 const bool has_animated_transform
=
121 layer
->layer_animation_controller()->IsAnimatingProperty(
122 Animation::TRANSFORM
);
124 const bool has_surface
= !!layer
->render_surface();
126 bool requires_node
= is_root
|| is_scrollable
|| has_significant_transform
||
127 has_animated_transform
|| has_surface
||
128 is_page_scale_application_layer
;
130 Layer
* transform_parent
= GetTransformParent(data_from_ancestor
, layer
);
132 gfx::Vector2dF parent_offset
;
133 if (transform_parent
) {
134 if (layer
->scroll_parent()) {
135 gfx::Transform to_parent
;
136 Layer
* source
= layer
->parent();
137 parent_offset
+= source
->offset_to_transform_parent();
138 data_from_ancestor
.transform_tree
->ComputeTransform(
139 source
->transform_tree_index(),
140 transform_parent
->transform_tree_index(), &to_parent
);
141 parent_offset
+= to_parent
.To2dTranslation();
142 } else if (!is_fixed
) {
143 parent_offset
= transform_parent
->offset_to_transform_parent();
144 } else if (data_from_ancestor
.transform_tree_parent
!=
145 data_from_ancestor
.transform_fixed_parent
) {
146 gfx::Vector2dF fixed_offset
= data_from_ancestor
.transform_tree_parent
147 ->offset_to_transform_parent();
148 gfx::Transform parent_to_parent
;
149 data_from_ancestor
.transform_tree
->ComputeTransform(
150 data_from_ancestor
.transform_tree_parent
->transform_tree_index(),
151 data_from_ancestor
.transform_fixed_parent
->transform_tree_index(),
154 fixed_offset
+= parent_to_parent
.To2dTranslation();
155 parent_offset
+= fixed_offset
;
159 if (layer
->IsContainerForFixedPositionLayers() || is_root
)
160 data_for_children
->transform_fixed_parent
= layer
;
161 data_for_children
->transform_tree_parent
= layer
;
163 if (!requires_node
) {
164 data_for_children
->should_flatten
|= layer
->should_flatten_transform();
165 gfx::Vector2dF local_offset
= layer
->position().OffsetFromOrigin() +
166 layer
->transform().To2dTranslation();
167 layer
->set_offset_to_transform_parent(parent_offset
+ local_offset
);
168 layer
->set_should_flatten_transform_from_property_tree(
169 data_from_ancestor
.should_flatten
);
170 layer
->set_transform_tree_index(transform_parent
->transform_tree_index());
174 int parent_index
= 0;
175 if (transform_parent
)
176 parent_index
= transform_parent
->transform_tree_index();
178 data_for_children
->transform_tree
->Insert(TransformNode(), parent_index
);
180 TransformNode
* node
= data_for_children
->transform_tree
->back();
181 layer
->set_transform_tree_index(node
->id
);
183 node
->data
.scrolls
= is_scrollable
;
184 node
->data
.flattens_inherited_transform
= data_for_children
->should_flatten
;
186 // Surfaces inherently flatten transforms.
187 data_for_children
->should_flatten
=
188 layer
->should_flatten_transform() || has_surface
;
189 node
->data
.target_id
=
190 data_from_ancestor
.render_target
->transform_tree_index();
191 node
->data
.content_target_id
=
192 data_for_children
->render_target
->transform_tree_index();
193 DCHECK_NE(node
->data
.target_id
, -1);
194 node
->data
.is_animated
= layer
->TransformIsAnimating();
196 float scale_factors
= 1.0f
;
198 node
->data
.post_local
= *data_from_ancestor
.device_transform
;
199 scale_factors
= data_from_ancestor
.device_scale_factor
;
202 if (is_page_scale_application_layer
)
203 scale_factors
*= data_from_ancestor
.page_scale_factor
;
205 if (has_surface
&& !is_root
) {
206 node
->data
.needs_sublayer_scale
= true;
207 node
->data
.layer_scale_factor
= data_from_ancestor
.device_scale_factor
;
208 if (data_from_ancestor
.in_subtree_of_page_scale_application_layer
)
209 node
->data
.layer_scale_factor
*= data_from_ancestor
.page_scale_factor
;
212 node
->data
.post_local
.Scale(scale_factors
, scale_factors
);
213 node
->data
.post_local
.Translate3d(
214 layer
->position().x() + parent_offset
.x() + layer
->transform_origin().x(),
215 layer
->position().y() + parent_offset
.y() + layer
->transform_origin().y(),
216 layer
->transform_origin().z());
218 if (!layer
->scroll_parent()) {
219 node
->data
.scroll_offset
=
220 gfx::ScrollOffsetToVector2dF(layer
->CurrentScrollOffset());
223 node
->data
.local
= layer
->transform();
224 node
->data
.pre_local
.Translate3d(-layer
->transform_origin().x(),
225 -layer
->transform_origin().y(),
226 -layer
->transform_origin().z());
228 node
->data
.needs_local_transform_update
= true;
229 data_from_ancestor
.transform_tree
->UpdateTransforms(node
->id
);
231 layer
->set_offset_to_transform_parent(gfx::Vector2dF());
233 // Flattening (if needed) will be handled by |node|.
234 layer
->set_should_flatten_transform_from_property_tree(false);
237 void AddOpacityNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
239 DataForRecursion
* data_for_children
) {
240 const bool is_root
= !layer
->parent();
241 const bool has_transparency
= layer
->opacity() != 1.f
;
242 const bool has_animated_opacity
=
243 layer
->layer_animation_controller()->IsAnimatingProperty(
244 Animation::OPACITY
) ||
245 layer
->OpacityCanAnimateOnImplThread();
246 bool requires_node
= is_root
|| has_transparency
|| has_animated_opacity
;
248 int parent_id
= data_from_ancestor
.opacity_tree_parent
;
250 if (!requires_node
) {
251 layer
->set_opacity_tree_index(parent_id
);
252 data_for_children
->opacity_tree_parent
= parent_id
;
257 node
.data
= layer
->opacity();
258 data_for_children
->opacity_tree_parent
=
259 data_for_children
->opacity_tree
->Insert(node
, parent_id
);
260 layer
->set_opacity_tree_index(data_for_children
->opacity_tree_parent
);
263 void BuildPropertyTreesInternal(Layer
* layer
,
264 const DataForRecursion
& data_from_parent
) {
265 DataForRecursion
data_for_children(data_from_parent
);
266 if (layer
->render_surface())
267 data_for_children
.render_target
= layer
;
269 AddTransformNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
270 AddClipNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
272 if (data_from_parent
.opacity_tree
)
273 AddOpacityNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
275 if (layer
== data_from_parent
.page_scale_layer
)
276 data_for_children
.in_subtree_of_page_scale_application_layer
= true;
278 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
279 if (!layer
->children()[i
]->scroll_parent())
280 BuildPropertyTreesInternal(layer
->children()[i
].get(), data_for_children
);
283 if (layer
->scroll_children()) {
284 for (Layer
* scroll_child
: *layer
->scroll_children()) {
285 BuildPropertyTreesInternal(scroll_child
, data_for_children
);
289 if (layer
->has_replica())
290 BuildPropertyTreesInternal(layer
->replica_layer(), data_for_children
);
295 void PropertyTreeBuilder::BuildPropertyTrees(
297 const Layer
* page_scale_layer
,
298 float page_scale_factor
,
299 float device_scale_factor
,
300 const gfx::Rect
& viewport
,
301 const gfx::Transform
& device_transform
,
302 TransformTree
* transform_tree
,
304 OpacityTree
* opacity_tree
) {
305 DataForRecursion data_for_recursion
;
306 data_for_recursion
.transform_tree
= transform_tree
;
307 data_for_recursion
.clip_tree
= clip_tree
;
308 data_for_recursion
.opacity_tree
= opacity_tree
;
309 data_for_recursion
.transform_tree_parent
= nullptr;
310 data_for_recursion
.transform_fixed_parent
= nullptr;
311 data_for_recursion
.render_target
= root_layer
;
312 data_for_recursion
.clip_tree_parent
= 0;
313 data_for_recursion
.opacity_tree_parent
= -1;
314 data_for_recursion
.page_scale_layer
= page_scale_layer
;
315 data_for_recursion
.page_scale_factor
= page_scale_factor
;
316 data_for_recursion
.device_scale_factor
= device_scale_factor
;
317 data_for_recursion
.in_subtree_of_page_scale_application_layer
= false;
318 data_for_recursion
.should_flatten
= false;
319 data_for_recursion
.device_transform
= &device_transform
;
322 root_clip
.data
.clip
= viewport
;
323 root_clip
.data
.transform_id
= 0;
324 data_for_recursion
.clip_tree_parent
= clip_tree
->Insert(root_clip
, 0);
325 BuildPropertyTreesInternal(root_layer
, data_for_recursion
);