Roll src/third_party/skia 4cd6713:0edd965
[chromium-blink-merge.git] / cc / trees / property_tree_builder.cc
blobb47831318b0a0f38cdec916df6c8d56ccc8991a6
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/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"
17 namespace cc {
19 class LayerTreeHost;
21 namespace {
23 template <typename LayerType>
24 struct DataForRecursion {
25 TransformTree* transform_tree;
26 ClipTree* clip_tree;
27 OpacityTree* opacity_tree;
28 LayerType* transform_tree_parent;
29 LayerType* transform_fixed_parent;
30 LayerType* render_target;
31 int clip_tree_parent;
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;
37 bool should_flatten;
38 bool ancestor_clips_subtree;
39 const gfx::Transform* device_transform;
40 gfx::Vector2dF scroll_compensation_adjustment;
41 int sequence_number;
44 template <typename LayerType>
45 static LayerType* GetTransformParent(const DataForRecursion<LayerType>& data,
46 LayerType* layer) {
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,
54 LayerType* layer) {
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();
68 return false;
71 template <typename LayerType>
72 static bool RequiresClipNode(LayerType* layer,
73 const DataForRecursion<LayerType>& data,
74 int parent_transform_id,
75 bool is_clipped) {
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)
83 return true;
85 if (!render_surface_applies_clip)
86 return false;
88 bool axis_aligned_with_respect_to_parent =
89 data.transform_tree->Are2DAxisAligned(layer->transform_tree_index(),
90 parent_transform_id);
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,
102 LayerType* layer,
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;
119 } else {
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)
127 parent_id = 0;
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;
140 ClipNode node;
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,
163 LayerType* layer,
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();
202 } else {
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();
207 source_index =
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) {
215 if (is_scrollable) {
216 DCHECK(!is_root);
217 DCHECK(layer->transform().IsIdentity());
218 data_for_children->transform_fixed_parent = layer->parent();
219 } else {
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 +
240 local_offset);
241 layer->set_should_flatten_transform_from_property_tree(
242 data_from_ancestor.should_flatten);
243 layer->SetTransformTreeIndex(parent_index);
244 return false;
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;
266 if (is_root) {
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;
282 if (is_root) {
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());
287 } else {
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();
313 return true;
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,
328 LayerType* layer,
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;
340 return;
343 OpacityNode node;
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(
353 LayerType* layer,
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,
363 &data_for_children);
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);
386 } // namespace
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)
397 return;
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;
423 ClipNode root_clip;
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
433 // building.
434 property_trees->transform_tree.set_needs_update(false);
435 property_trees->clip_tree.set_needs_update(true);
438 void PropertyTreeBuilder::BuildPropertyTrees(
439 Layer* root_layer,
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);
464 } // namespace cc