Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320)
[chromium-blink-merge.git] / cc / trees / property_tree_builder.cc
blob9009bc9a3a63c926f569041be7dbc7d09a5ee6b1
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"
7 #include <map>
8 #include <set>
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"
16 namespace cc {
18 class LayerTreeHost;
20 namespace {
22 struct DataForRecursion {
23 TransformTree* transform_tree;
24 ClipTree* clip_tree;
25 OpacityTree* opacity_tree;
26 Layer* transform_tree_parent;
27 Layer* transform_fixed_parent;
28 Layer* render_target;
29 int clip_tree_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;
35 bool should_flatten;
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 &&
57 layer->is_clipped();
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,
67 Layer* layer,
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)
84 parent_id = 0;
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;
96 ClipNode node;
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,
116 Layer* layer,
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();
151 } else {
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(),
160 &parent_to_parent);
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());
184 return false;
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;
210 if (is_root) {
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;
251 return true;
254 void AddOpacityNodeIfNeeded(const DataForRecursion& data_from_ancestor,
255 Layer* layer,
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;
270 return;
273 OpacityNode node;
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,
289 &data_for_children);
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);
312 } // namespace
314 void PropertyTreeBuilder::BuildPropertyTrees(
315 Layer* root_layer,
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,
322 ClipTree* clip_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;
340 ClipNode root_clip;
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);
347 } // namespace cc