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 gfx::Vector2dF offset_to_transform_tree_parent
;
31 gfx::Vector2dF offset_to_transform_fixed_parent
;
32 const Layer
* page_scale_layer
;
33 float page_scale_factor
;
34 float device_scale_factor
;
35 bool in_subtree_of_page_scale_application_layer
;
36 const gfx::Transform
* device_transform
;
39 static Layer
* GetTransformParent(const DataForRecursion
& data
, Layer
* layer
) {
40 return layer
->position_constraint().is_fixed_position()
41 ? data
.transform_fixed_parent
42 : data
.transform_tree_parent
;
45 static ClipNode
* GetClipParent(const DataForRecursion
& data
, Layer
* layer
) {
46 const bool inherits_clip
= !layer
->parent() || !layer
->clip_parent();
47 const int id
= inherits_clip
? data
.clip_tree_parent
48 : layer
->clip_parent()->clip_tree_index();
49 return data
.clip_tree
->Node(id
);
52 static bool RequiresClipNode(Layer
* layer
,
53 bool axis_aligned_with_respect_to_parent
) {
54 const bool render_surface_applies_non_axis_aligned_clip
=
55 layer
->render_surface() && !axis_aligned_with_respect_to_parent
&&
57 const bool render_surface_may_grow_due_to_clip_children
=
58 layer
->render_surface() && layer
->num_unclipped_descendants() > 0;
60 return !layer
->parent() || layer
->masks_to_bounds() || layer
->mask_layer() ||
61 render_surface_applies_non_axis_aligned_clip
||
62 render_surface_may_grow_due_to_clip_children
;
65 void AddClipNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
67 DataForRecursion
* data_for_children
) {
68 ClipNode
* parent
= GetClipParent(data_from_ancestor
, layer
);
69 int parent_id
= parent
->id
;
70 const bool axis_aligned_with_respect_to_parent
=
71 data_from_ancestor
.transform_tree
->Are2DAxisAligned(
72 layer
->transform_tree_index(), parent
->data
.transform_id
);
74 // TODO(vollick): once Andrew refactors the surface determinations out of
75 // CDP, the the layer->render_surface() check will be invalid.
76 const bool has_unclipped_surface
=
77 layer
->render_surface() &&
78 !layer
->render_surface()->is_clipped() &&
79 layer
->num_unclipped_descendants() == 0;
81 if (has_unclipped_surface
)
84 if (!RequiresClipNode(layer
, axis_aligned_with_respect_to_parent
)) {
85 // Unclipped surfaces reset the clip rect.
86 data_for_children
->clip_tree_parent
= parent_id
;
87 } else if (layer
->parent()) {
88 // Note the root clip gets handled elsewhere.
89 Layer
* transform_parent
= GetTransformParent(*data_for_children
, layer
);
91 node
.data
.clip
= gfx::RectF(
92 gfx::PointF() + layer
->offset_to_transform_parent(), layer
->bounds());
93 node
.data
.transform_id
= transform_parent
->transform_tree_index();
95 data_from_ancestor
.render_target
->transform_tree_index();
97 data_for_children
->clip_tree_parent
=
98 data_for_children
->clip_tree
->Insert(node
, parent_id
);
101 layer
->set_clip_tree_index(
102 has_unclipped_surface
? 0 : data_for_children
->clip_tree_parent
);
104 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the
105 // clip for all children since we may need to draw. We need to figure out a
106 // better way, since we will need both the clipped and unclipped versions.
109 void AddTransformNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
111 DataForRecursion
* data_for_children
) {
112 const bool is_root
= !layer
->parent();
113 const bool is_page_scale_application_layer
=
114 layer
->parent() && layer
->parent() == data_from_ancestor
.page_scale_layer
;
115 const bool is_scrollable
= layer
->scrollable();
116 const bool is_fixed
= layer
->position_constraint().is_fixed_position();
118 const bool has_significant_transform
=
119 !layer
->transform().IsIdentityOr2DTranslation();
121 const bool has_animated_transform
=
122 layer
->layer_animation_controller()->IsAnimatingProperty(
123 Animation::TRANSFORM
);
125 const bool has_surface
= !!layer
->render_surface();
127 const bool flattening_change
= layer
->parent() &&
128 layer
->should_flatten_transform() &&
129 !layer
->parent()->should_flatten_transform();
131 bool requires_node
= is_root
|| is_scrollable
|| is_fixed
||
132 has_significant_transform
|| has_animated_transform
||
133 is_page_scale_application_layer
|| flattening_change
||
136 Layer
* transform_parent
= GetTransformParent(data_from_ancestor
, layer
);
138 // May be non-zero if layer is fixed or has a scroll parent.
139 gfx::Vector2dF parent_offset
;
140 if (transform_parent
) {
141 // TODO(vollick): This is to mimic existing bugs (crbug.com/441447).
143 parent_offset
= transform_parent
->offset_to_transform_parent();
145 gfx::Transform to_parent
;
146 Layer
* source
= data_from_ancestor
.transform_tree_parent
;
147 if (layer
->scroll_parent()) {
148 source
= layer
->parent();
149 parent_offset
+= layer
->parent()->offset_to_transform_parent();
151 data_from_ancestor
.transform_tree
->ComputeTransform(
152 source
->transform_tree_index(),
153 transform_parent
->transform_tree_index(), &to_parent
);
155 parent_offset
+= to_parent
.To2dTranslation();
158 if (layer
->IsContainerForFixedPositionLayers() || is_root
)
159 data_for_children
->transform_fixed_parent
= layer
;
160 data_for_children
->transform_tree_parent
= layer
;
162 if (!requires_node
) {
163 gfx::Vector2dF local_offset
= layer
->position().OffsetFromOrigin() +
164 layer
->transform().To2dTranslation();
165 layer
->set_offset_to_transform_parent(parent_offset
+ local_offset
);
166 layer
->set_transform_tree_index(transform_parent
->transform_tree_index());
170 int parent_index
= 0;
171 if (transform_parent
)
172 parent_index
= transform_parent
->transform_tree_index();
174 data_for_children
->transform_tree
->Insert(TransformNode(), parent_index
);
176 TransformNode
* node
= data_for_children
->transform_tree
->back();
177 layer
->set_transform_tree_index(node
->id
);
179 node
->data
.scrolls
= is_scrollable
;
180 node
->data
.flattens
= layer
->should_flatten_transform();
181 node
->data
.target_id
=
182 data_from_ancestor
.render_target
->transform_tree_index();
183 node
->data
.content_target_id
=
184 data_for_children
->render_target
->transform_tree_index();
185 DCHECK_NE(node
->data
.target_id
, -1);
186 node
->data
.is_animated
= layer
->TransformIsAnimating();
188 float scale_factors
= 1.0f
;
190 node
->data
.post_local
= *data_from_ancestor
.device_transform
;
191 scale_factors
= data_from_ancestor
.device_scale_factor
;
194 if (is_page_scale_application_layer
)
195 scale_factors
*= data_from_ancestor
.page_scale_factor
;
197 if (has_surface
&& !is_root
) {
198 node
->data
.needs_sublayer_scale
= true;
199 node
->data
.layer_scale_factor
= data_from_ancestor
.device_scale_factor
;
200 if (data_from_ancestor
.in_subtree_of_page_scale_application_layer
)
201 node
->data
.layer_scale_factor
*= data_from_ancestor
.page_scale_factor
;
204 node
->data
.post_local
.Scale(scale_factors
, scale_factors
);
205 node
->data
.post_local
.Translate3d(
206 layer
->position().x() + parent_offset
.x() + layer
->transform_origin().x(),
207 layer
->position().y() + parent_offset
.y() + layer
->transform_origin().y(),
208 layer
->transform_origin().z());
210 if (!layer
->scroll_parent()) {
211 node
->data
.scroll_offset
=
212 gfx::ScrollOffsetToVector2dF(layer
->CurrentScrollOffset());
215 node
->data
.local
= layer
->transform();
216 node
->data
.pre_local
.Translate3d(-layer
->transform_origin().x(),
217 -layer
->transform_origin().y(),
218 -layer
->transform_origin().z());
220 node
->data
.needs_local_transform_update
= true;
221 data_from_ancestor
.transform_tree
->UpdateTransforms(node
->id
);
223 layer
->set_offset_to_transform_parent(gfx::Vector2dF());
226 void AddOpacityNodeIfNeeded(const DataForRecursion
& data_from_ancestor
,
228 DataForRecursion
* data_for_children
) {
229 const bool is_root
= !layer
->parent();
230 const bool has_transparency
= layer
->opacity() != 1.f
;
231 const bool has_animated_opacity
=
232 layer
->layer_animation_controller()->IsAnimatingProperty(
233 Animation::OPACITY
) ||
234 layer
->OpacityCanAnimateOnImplThread();
235 bool requires_node
= is_root
|| has_transparency
|| has_animated_opacity
;
237 int parent_id
= data_from_ancestor
.opacity_tree_parent
;
239 if (!requires_node
) {
240 layer
->set_opacity_tree_index(parent_id
);
241 data_for_children
->opacity_tree_parent
= parent_id
;
246 node
.data
= layer
->opacity();
247 data_for_children
->opacity_tree_parent
=
248 data_for_children
->opacity_tree
->Insert(node
, parent_id
);
249 layer
->set_opacity_tree_index(data_for_children
->opacity_tree_parent
);
252 void BuildPropertyTreesInternal(Layer
* layer
,
253 const DataForRecursion
& data_from_parent
) {
254 DataForRecursion
data_for_children(data_from_parent
);
255 if (layer
->render_surface())
256 data_for_children
.render_target
= layer
;
258 AddTransformNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
259 AddClipNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
261 if (data_from_parent
.opacity_tree
)
262 AddOpacityNodeIfNeeded(data_from_parent
, layer
, &data_for_children
);
264 if (layer
== data_from_parent
.page_scale_layer
)
265 data_for_children
.in_subtree_of_page_scale_application_layer
= true;
267 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
268 if (!layer
->children()[i
]->scroll_parent())
269 BuildPropertyTreesInternal(layer
->children()[i
].get(), data_for_children
);
272 if (layer
->scroll_children()) {
273 for (Layer
* scroll_child
: *layer
->scroll_children()) {
274 BuildPropertyTreesInternal(scroll_child
, data_for_children
);
278 if (layer
->has_replica())
279 BuildPropertyTreesInternal(layer
->replica_layer(), data_for_children
);
284 void PropertyTreeBuilder::BuildPropertyTrees(
286 const Layer
* page_scale_layer
,
287 float page_scale_factor
,
288 float device_scale_factor
,
289 const gfx::Rect
& viewport
,
290 const gfx::Transform
& device_transform
,
291 TransformTree
* transform_tree
,
293 OpacityTree
* opacity_tree
) {
294 DataForRecursion data_for_recursion
;
295 data_for_recursion
.transform_tree
= transform_tree
;
296 data_for_recursion
.clip_tree
= clip_tree
;
297 data_for_recursion
.opacity_tree
= opacity_tree
;
298 data_for_recursion
.transform_tree_parent
= nullptr;
299 data_for_recursion
.transform_fixed_parent
= nullptr;
300 data_for_recursion
.render_target
= root_layer
;
301 data_for_recursion
.clip_tree_parent
= 0;
302 data_for_recursion
.opacity_tree_parent
= -1;
303 data_for_recursion
.page_scale_layer
= page_scale_layer
;
304 data_for_recursion
.page_scale_factor
= page_scale_factor
;
305 data_for_recursion
.device_scale_factor
= device_scale_factor
;
306 data_for_recursion
.in_subtree_of_page_scale_application_layer
= false;
307 data_for_recursion
.device_transform
= &device_transform
;
310 root_clip
.data
.clip
= viewport
;
311 root_clip
.data
.transform_id
= 0;
312 data_for_recursion
.clip_tree_parent
= clip_tree
->Insert(root_clip
, 0);
313 BuildPropertyTreesInternal(root_layer
, data_for_recursion
);