Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / cc / trees / draw_property_utils.cc
bloba3fa4b5b0e8ef3a87199dc75e4db29d28449cb37
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/draw_property_utils.h"
7 #include <vector>
9 #include "cc/base/math_util.h"
10 #include "cc/layers/draw_properties.h"
11 #include "cc/layers/layer.h"
12 #include "cc/layers/layer_impl.h"
13 #include "cc/layers/render_surface_draw_properties.h"
14 #include "cc/trees/layer_tree_impl.h"
15 #include "cc/trees/property_tree.h"
16 #include "cc/trees/property_tree_builder.h"
17 #include "ui/gfx/geometry/rect_conversions.h"
19 namespace cc {
21 namespace {
23 template <typename LayerType>
24 void CalculateVisibleRects(const std::vector<LayerType*>& visible_layer_list,
25 const ClipTree& clip_tree,
26 const TransformTree& transform_tree) {
27 for (auto& layer : visible_layer_list) {
28 // TODO(ajuma): Compute content_scale rather than using it. Note that for
29 // PictureLayer and PictureImageLayers, content_bounds == bounds and
30 // content_scale_x == content_scale_y == 1.0, so once impl painting is on
31 // everywhere, this code will be unnecessary.
32 gfx::Size layer_bounds = layer->bounds();
33 const bool has_clip = layer->clip_tree_index() > 0;
34 const TransformNode* transform_node =
35 transform_tree.Node(layer->transform_tree_index());
36 if (has_clip) {
37 const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
38 const TransformNode* clip_transform_node =
39 transform_tree.Node(clip_node->data.transform_id);
40 const bool target_is_root_surface =
41 transform_node->data.content_target_id == 1;
42 // When the target is the root surface, we need to include the root
43 // transform by walking up to the root of the transform tree.
44 const int target_id =
45 target_is_root_surface ? 0 : transform_node->data.content_target_id;
46 const TransformNode* target_node = transform_tree.Node(target_id);
48 gfx::Transform content_to_target = transform_node->data.to_target;
50 content_to_target.Translate(layer->offset_to_transform_parent().x(),
51 layer->offset_to_transform_parent().y());
53 gfx::Rect combined_clip_rect_in_target_space;
54 gfx::Rect clip_rect_in_target_space;
55 gfx::Transform clip_to_target;
56 bool success = true;
57 if (clip_transform_node->data.target_id == target_node->id) {
58 clip_to_target = clip_transform_node->data.to_target;
59 } else {
60 success = transform_tree.ComputeTransformWithDestinationSublayerScale(
61 clip_transform_node->id, target_node->id, &clip_to_target);
63 if (target_node->id > clip_node->data.transform_id) {
64 if (!success) {
65 DCHECK(target_node->data.to_screen_is_animated);
67 // An animated singular transform may become non-singular during the
68 // animation, so we still need to compute a visible rect. In this
69 // situation, we treat the entire layer as visible.
70 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
71 layer->set_clip_rect_in_target_space_from_property_trees(
72 gfx::ToEnclosingRect(clip_node->data.combined_clip));
73 continue;
76 combined_clip_rect_in_target_space =
77 gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
78 clip_to_target, clip_node->data.combined_clip));
79 clip_rect_in_target_space = gfx::ToEnclosingRect(
80 MathUtil::ProjectClippedRect(clip_to_target, clip_node->data.clip));
81 } else {
82 // Computing a transform to an ancestor should always succeed.
83 DCHECK(success);
84 combined_clip_rect_in_target_space =
85 gfx::ToEnclosingRect(MathUtil::MapClippedRect(
86 clip_to_target, clip_node->data.combined_clip));
87 clip_rect_in_target_space = gfx::ToEnclosingRect(
88 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip));
91 if (clip_node->data.requires_tight_clip_rect)
92 layer->set_clip_rect_in_target_space_from_property_trees(
93 combined_clip_rect_in_target_space);
94 else
95 layer->set_clip_rect_in_target_space_from_property_trees(
96 clip_rect_in_target_space);
98 gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
99 gfx::Rect layer_content_bounds_in_target_space =
100 MathUtil::MapEnclosingClippedRect(content_to_target,
101 layer_content_rect);
102 combined_clip_rect_in_target_space.Intersect(
103 layer_content_bounds_in_target_space);
104 clip_rect_in_target_space.Intersect(layer_content_bounds_in_target_space);
105 if (combined_clip_rect_in_target_space.IsEmpty()) {
106 layer->set_visible_rect_from_property_trees(gfx::Rect());
107 continue;
110 // If the layer is fully contained within the clip, treat it as fully
111 // visible. Since clip_rect_in_target_space has already been intersected
112 // with layer_content_bounds_in_target_space, the layer is fully contained
113 // within the clip iff these rects are equal.
114 if (combined_clip_rect_in_target_space ==
115 layer_content_bounds_in_target_space) {
116 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
117 continue;
120 gfx::Transform target_to_content;
121 gfx::Transform target_to_layer;
123 if (transform_node->data.ancestors_are_invertible) {
124 target_to_layer = transform_node->data.from_target;
125 success = true;
126 } else {
127 success = transform_tree.ComputeTransformWithSourceSublayerScale(
128 target_node->id, transform_node->id, &target_to_layer);
131 if (!success) {
132 // An animated singular transform may become non-singular during the
133 // animation, so we still need to compute a visible rect. In this
134 // situation, we treat the entire layer as visible.
135 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
136 continue;
139 target_to_content.Translate(-layer->offset_to_transform_parent().x(),
140 -layer->offset_to_transform_parent().y());
141 target_to_content.PreconcatTransform(target_to_layer);
143 gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
144 target_to_content, combined_clip_rect_in_target_space);
146 visible_rect.Intersect(gfx::Rect(layer_bounds));
148 layer->set_visible_rect_from_property_trees(visible_rect);
149 } else {
150 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
151 layer->set_clip_rect_in_target_space_from_property_trees(
152 gfx::Rect(layer_bounds));
157 template <typename LayerType>
158 static bool IsRootLayerOfNewRenderingContext(LayerType* layer) {
159 if (layer->parent())
160 return !layer->parent()->Is3dSorted() && layer->Is3dSorted();
161 return layer->Is3dSorted();
164 template <typename LayerType>
165 static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
166 return layer->Is3dSorted() && layer->parent() &&
167 layer->parent()->Is3dSorted() &&
168 layer->parent()->sorting_context_id() == layer->sorting_context_id();
171 template <typename LayerType>
172 static bool TransformToScreenIsKnown(LayerType* layer,
173 const TransformTree& tree) {
174 const TransformNode* node = tree.Node(layer->transform_tree_index());
175 return !node->data.to_screen_is_animated;
178 template <typename LayerType>
179 static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
180 const TransformNode* node = tree.Node(layer->transform_tree_index());
181 return !node->data.is_invertible || !node->data.ancestors_are_invertible;
184 template <typename LayerType>
185 static bool IsLayerBackFaceVisible(LayerType* layer,
186 const TransformTree& tree) {
187 // The current W3C spec on CSS transforms says that backface visibility should
188 // be determined differently depending on whether the layer is in a "3d
189 // rendering context" or not. For Chromium code, we can determine whether we
190 // are in a 3d rendering context by checking if the parent preserves 3d.
192 if (LayerIsInExisting3DRenderingContext(layer))
193 return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
195 // In this case, either the layer establishes a new 3d rendering context, or
196 // is not in a 3d rendering context at all.
197 return layer->transform().IsBackFaceVisible();
200 template <typename LayerType>
201 static bool IsSurfaceBackFaceVisible(LayerType* layer,
202 const TransformTree& tree) {
203 if (LayerIsInExisting3DRenderingContext(layer)) {
204 const TransformNode* node = tree.Node(layer->transform_tree_index());
205 // Draw transform as a contributing render surface.
206 // TODO(enne): we shouldn't walk the tree during a tree walk.
207 gfx::Transform surface_draw_transform;
208 tree.ComputeTransform(node->id, node->data.target_id,
209 &surface_draw_transform);
210 return surface_draw_transform.IsBackFaceVisible();
213 if (IsRootLayerOfNewRenderingContext(layer))
214 return layer->transform().IsBackFaceVisible();
216 // If the render_surface is not part of a new or existing rendering context,
217 // then the layers that contribute to this surface will decide back-face
218 // visibility for themselves.
219 return false;
222 template <typename LayerType>
223 static bool IsAnimatingTransformToScreen(LayerType* layer,
224 const TransformTree& tree) {
225 const TransformNode* node = tree.Node(layer->transform_tree_index());
226 return node->data.to_screen_is_animated;
229 static inline bool TransformToScreenIsKnown(Layer* layer,
230 const TransformTree& tree) {
231 return !IsAnimatingTransformToScreen(layer, tree);
234 static inline bool TransformToScreenIsKnown(LayerImpl* layer,
235 const TransformTree& tree) {
236 return true;
239 template <typename LayerType>
240 static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
241 return layer->transform_is_invertible() ||
242 layer->HasPotentiallyRunningTransformAnimation();
245 static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
246 bool layer_is_drawn,
247 const TransformTree& tree) {
248 // If the layer transform is not invertible, it should not be drawn.
249 // TODO(ajuma): Correctly process subtrees with singular transform for the
250 // case where we may animate to a non-singular transform and wish to
251 // pre-raster.
252 if (!HasInvertibleOrAnimatedTransform(layer))
253 return true;
255 // When we need to do a readback/copy of a layer's output, we can not skip
256 // it or any of its ancestors.
257 if (layer->draw_properties().layer_or_descendant_has_copy_request)
258 return false;
260 // If the layer is not drawn, then skip it and its subtree.
261 if (!layer_is_drawn)
262 return true;
264 if (layer->render_surface() && !layer->double_sided() &&
265 IsSurfaceBackFaceVisible(layer, tree))
266 return true;
268 // If layer is on the pending tree and opacity is being animated then
269 // this subtree can't be skipped as we need to create, prioritize and
270 // include tiles for this layer when deciding if tree can be activated.
271 if (layer->layer_tree_impl()->IsPendingTree() &&
272 layer->HasPotentiallyRunningOpacityAnimation())
273 return false;
275 // If layer has a background filter, don't skip the layer, even it the
276 // opacity is 0.
277 if (!layer->background_filters().IsEmpty())
278 return false;
280 // The opacity of a layer always applies to its children (either implicitly
281 // via a render surface or explicitly if the parent preserves 3D), so the
282 // entire subtree can be skipped if this layer is fully transparent.
283 return !layer->opacity();
286 static inline bool SubtreeShouldBeSkipped(Layer* layer,
287 bool layer_is_drawn,
288 const TransformTree& tree) {
289 // If the layer transform is not invertible, it should not be drawn.
290 if (!layer->transform_is_invertible() &&
291 !layer->HasPotentiallyRunningTransformAnimation())
292 return true;
294 // When we need to do a readback/copy of a layer's output, we can not skip
295 // it or any of its ancestors.
296 if (layer->num_layer_or_descendants_with_copy_request() > 0)
297 return false;
299 // If the layer is not drawn, then skip it and its subtree.
300 if (!layer_is_drawn)
301 return true;
303 if (layer->has_render_surface() && !layer->double_sided() &&
304 !layer->HasPotentiallyRunningTransformAnimation() &&
305 IsSurfaceBackFaceVisible(layer, tree))
306 return true;
308 // If layer has a background filter, don't skip the layer, even it the
309 // opacity is 0.
310 if (!layer->background_filters().IsEmpty())
311 return false;
313 // If the opacity is being animated then the opacity on the main thread is
314 // unreliable (since the impl thread may be using a different opacity), so it
315 // should not be trusted.
316 // In particular, it should not cause the subtree to be skipped.
317 // Similarly, for layers that might animate opacity using an impl-only
318 // animation, their subtree should also not be skipped.
319 return !layer->opacity() && !layer->HasPotentiallyRunningOpacityAnimation() &&
320 !layer->OpacityCanAnimateOnImplThread();
323 template <typename LayerType>
324 static bool LayerShouldBeSkipped(LayerType* layer,
325 bool layer_is_drawn,
326 const TransformTree& tree) {
327 // Layers can be skipped if any of these conditions are met.
328 // - is not drawn due to it or one of its ancestors being hidden (or having
329 // no copy requests).
330 // - does not draw content.
331 // - is transparent.
332 // - has empty bounds
333 // - the layer is not double-sided, but its back face is visible.
335 // Some additional conditions need to be computed at a later point after the
336 // recursion is finished.
337 // - the intersection of render_surface content and layer clip_rect is empty
338 // - the visible_layer_rect is empty
340 // Note, if the layer should not have been drawn due to being fully
341 // transparent, we would have skipped the entire subtree and never made it
342 // into this function, so it is safe to omit this check here.
343 if (!layer_is_drawn)
344 return true;
346 if (!layer->DrawsContent() || layer->bounds().IsEmpty())
347 return true;
349 LayerType* backface_test_layer = layer;
350 if (layer->use_parent_backface_visibility()) {
351 DCHECK(layer->parent());
352 DCHECK(!layer->parent()->use_parent_backface_visibility());
353 backface_test_layer = layer->parent();
356 // The layer should not be drawn if (1) it is not double-sided and (2) the
357 // back of the layer is known to be facing the screen.
358 if (!backface_test_layer->double_sided() &&
359 TransformToScreenIsKnown(backface_test_layer, tree) &&
360 IsLayerBackFaceVisible(backface_test_layer, tree))
361 return true;
363 return false;
366 template <typename LayerType>
367 void FindLayersThatNeedUpdates(
368 LayerType* layer,
369 const TransformTree& tree,
370 bool subtree_is_visible_from_ancestor,
371 typename LayerType::LayerListType* update_layer_list,
372 std::vector<LayerType*>* visible_layer_list) {
373 bool layer_is_drawn =
374 layer->HasCopyRequest() ||
375 (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree());
377 if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn, tree))
378 return;
380 if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) {
381 visible_layer_list->push_back(layer);
382 update_layer_list->push_back(layer);
385 // Append mask layers to the update layer list. They don't have valid visible
386 // rects, so need to get added after the above calculation. Replica layers
387 // don't need to be updated.
388 if (LayerType* mask_layer = layer->mask_layer())
389 update_layer_list->push_back(mask_layer);
390 if (LayerType* replica_layer = layer->replica_layer()) {
391 if (LayerType* mask_layer = replica_layer->mask_layer())
392 update_layer_list->push_back(mask_layer);
395 for (size_t i = 0; i < layer->children().size(); ++i) {
396 FindLayersThatNeedUpdates(layer->child_at(i), tree, layer_is_drawn,
397 update_layer_list, visible_layer_list);
401 } // namespace
403 void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) {
404 if (!clip_tree->needs_update())
405 return;
406 for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) {
407 ClipNode* clip_node = clip_tree->Node(i);
408 const TransformNode* transform_node =
409 transform_tree.Node(clip_node->data.transform_id);
411 // Only descendants of a real clipping layer (i.e., not 0) may have their
412 // clip adjusted due to intersecting with an ancestor clip.
413 const bool is_clipped = clip_node->parent_id > 0;
414 if (!is_clipped) {
415 DCHECK(!clip_node->data.inherit_parent_target_space_clip);
416 clip_node->data.combined_clip = clip_node->data.clip;
417 if (clip_node->id > 0) {
418 gfx::Transform to_target = transform_node->data.to_target;
419 clip_node->data.clip_in_target_space =
420 MathUtil::MapClippedRect(to_target, clip_node->data.combined_clip);
422 continue;
425 ClipNode* parent_clip_node = clip_tree->parent(clip_node);
426 const TransformNode* parent_transform_node =
427 transform_tree.Node(parent_clip_node->data.transform_id);
429 // Clips must be combined in target space. We cannot, for example, combine
430 // clips in the space of the child clip. The reason is non-affine
431 // transforms. Say we have the following tree T->A->B->C, and B clips C, but
432 // draw into target T. It may be the case that A applies a perspective
433 // transform, and B and C are at different z positions. When projected into
434 // target space, the relative sizes and positions of B and C can shift.
435 // Since it's the relationship in target space that matters, that's where we
436 // must combine clips.
437 gfx::Transform parent_to_target;
438 gfx::Transform clip_to_target;
440 gfx::Transform target_to_clip;
441 gfx::Transform parent_to_transform_target;
442 gfx::Transform transform_target_to_target;
444 const bool target_is_root_surface = clip_node->data.target_id == 1;
445 // When the target is the root surface, we need to include the root
446 // transform by walking up to the root of the transform tree.
447 const int target_id =
448 target_is_root_surface ? 0 : clip_node->data.target_id;
450 bool success = true;
451 // When render surface applies clip, we need the clip from the target's
452 // target space. But, as the combined clip is in parent clip's target
453 // space, we need to first transform it from parent's target space to
454 // target's target space.
455 if (clip_node->data.inherit_parent_target_space_clip) {
456 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
457 parent_transform_node->id, transform_node->data.target_id,
458 &parent_to_transform_target);
459 success &= transform_tree.ComputeTransformWithSourceSublayerScale(
460 transform_node->data.target_id, target_id,
461 &transform_target_to_target);
462 transform_target_to_target.matrix().postScale(
463 transform_node->data.sublayer_scale.x(),
464 transform_node->data.sublayer_scale.y(), 1.0);
465 } else if (parent_transform_node->data.content_target_id ==
466 clip_node->data.target_id) {
467 parent_to_target = parent_transform_node->data.to_target;
468 } else {
469 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
470 parent_transform_node->id, target_id, &parent_to_target);
473 if (transform_node->data.content_target_id == clip_node->data.target_id) {
474 clip_to_target = transform_node->data.to_target;
475 } else {
476 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
477 transform_node->id, target_id, &clip_to_target);
480 if (transform_node->data.content_target_id == clip_node->data.target_id &&
481 transform_node->data.ancestors_are_invertible) {
482 target_to_clip = transform_node->data.from_target;
483 } else {
484 success &= clip_to_target.GetInverse(&target_to_clip);
487 // If we can't compute a transform, it's because we had to use the inverse
488 // of a singular transform. We won't draw in this case, so there's no need
489 // to compute clips.
490 if (!success) {
491 continue;
494 // In order to intersect with as small a rect as possible, we do a
495 // preliminary clip in target space so that when we project back, there's
496 // less likelihood of intersecting the view plane.
497 gfx::RectF inherited_clip_in_target_space;
498 if (clip_node->data.inherit_parent_target_space_clip) {
499 gfx::RectF combined_clip_in_transform_target_space;
500 if (parent_transform_node->id > transform_node->data.target_id)
501 combined_clip_in_transform_target_space = MathUtil::MapClippedRect(
502 parent_to_transform_target, parent_clip_node->data.combined_clip);
503 else
504 combined_clip_in_transform_target_space = MathUtil::ProjectClippedRect(
505 parent_to_transform_target, parent_clip_node->data.combined_clip);
506 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
507 transform_target_to_target, combined_clip_in_transform_target_space);
508 } else if (parent_transform_node->id > target_id) {
509 inherited_clip_in_target_space = MathUtil::MapClippedRect(
510 parent_to_target, parent_clip_node->data.combined_clip);
511 } else {
512 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
513 parent_to_target, parent_clip_node->data.combined_clip);
516 // When render surface inherits its parent target space clip, the layer
517 // that created the clip node doesn't apply any clip. So, we shouldn't clip
518 // using the clip value stored in the clip node.
519 gfx::RectF intersected_in_target_space;
520 if (!clip_node->data.inherit_parent_target_space_clip) {
521 gfx::RectF clip_in_target_space =
522 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip);
523 intersected_in_target_space = gfx::IntersectRects(
524 inherited_clip_in_target_space, clip_in_target_space);
525 if (!clip_node->data.requires_tight_clip_rect)
526 clip_node->data.clip_in_target_space = clip_in_target_space;
527 else
528 clip_node->data.clip_in_target_space = intersected_in_target_space;
529 } else {
530 intersected_in_target_space = inherited_clip_in_target_space;
531 clip_node->data.clip_in_target_space = intersected_in_target_space;
534 clip_node->data.combined_clip = MathUtil::ProjectClippedRect(
535 target_to_clip, intersected_in_target_space);
537 if (!clip_node->data.inherit_parent_target_space_clip)
538 clip_node->data.combined_clip.Intersect(clip_node->data.clip);
540 clip_tree->set_needs_update(false);
543 void ComputeTransforms(TransformTree* transform_tree) {
544 if (!transform_tree->needs_update())
545 return;
546 for (int i = 1; i < static_cast<int>(transform_tree->size()); ++i)
547 transform_tree->UpdateTransforms(i);
548 transform_tree->set_needs_update(false);
551 void ComputeOpacities(EffectTree* effect_tree) {
552 if (!effect_tree->needs_update())
553 return;
554 for (int i = 1; i < static_cast<int>(effect_tree->size()); ++i)
555 effect_tree->UpdateOpacities(i);
556 effect_tree->set_needs_update(false);
559 template <typename LayerType>
560 void ComputeVisibleRectsUsingPropertyTreesInternal(
561 LayerType* root_layer,
562 PropertyTrees* property_trees,
563 typename LayerType::LayerListType* update_layer_list) {
564 if (property_trees->transform_tree.needs_update())
565 property_trees->clip_tree.set_needs_update(true);
566 ComputeTransforms(&property_trees->transform_tree);
567 ComputeClips(&property_trees->clip_tree, property_trees->transform_tree);
568 ComputeOpacities(&property_trees->effect_tree);
570 const bool subtree_is_visible_from_ancestor = true;
571 std::vector<LayerType*> visible_layer_list;
572 FindLayersThatNeedUpdates(root_layer, property_trees->transform_tree,
573 subtree_is_visible_from_ancestor, update_layer_list,
574 &visible_layer_list);
575 CalculateVisibleRects<LayerType>(visible_layer_list,
576 property_trees->clip_tree,
577 property_trees->transform_tree);
580 void BuildPropertyTreesAndComputeVisibleRects(
581 Layer* root_layer,
582 const Layer* page_scale_layer,
583 const Layer* inner_viewport_scroll_layer,
584 const Layer* outer_viewport_scroll_layer,
585 float page_scale_factor,
586 float device_scale_factor,
587 const gfx::Rect& viewport,
588 const gfx::Transform& device_transform,
589 PropertyTrees* property_trees,
590 LayerList* update_layer_list) {
591 PropertyTreeBuilder::BuildPropertyTrees(
592 root_layer, page_scale_layer, inner_viewport_scroll_layer,
593 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
594 viewport, device_transform, property_trees);
595 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
596 update_layer_list);
599 void BuildPropertyTreesAndComputeVisibleRects(
600 LayerImpl* root_layer,
601 const LayerImpl* page_scale_layer,
602 const LayerImpl* inner_viewport_scroll_layer,
603 const LayerImpl* outer_viewport_scroll_layer,
604 float page_scale_factor,
605 float device_scale_factor,
606 const gfx::Rect& viewport,
607 const gfx::Transform& device_transform,
608 PropertyTrees* property_trees,
609 LayerImplList* update_layer_list) {
610 PropertyTreeBuilder::BuildPropertyTrees(
611 root_layer, page_scale_layer, inner_viewport_scroll_layer,
612 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
613 viewport, device_transform, property_trees);
614 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
615 update_layer_list);
618 void ComputeVisibleRectsUsingPropertyTrees(Layer* root_layer,
619 PropertyTrees* property_trees,
620 LayerList* update_layer_list) {
621 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
622 update_layer_list);
625 void ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer,
626 PropertyTrees* property_trees,
627 LayerImplList* update_layer_list) {
628 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
629 update_layer_list);
632 template <typename LayerType>
633 gfx::Transform DrawTransformFromPropertyTreesInternal(
634 const LayerType* layer,
635 const TransformNode* node) {
636 gfx::Transform xform;
637 const bool owns_non_root_surface =
638 layer->parent() && layer->has_render_surface();
639 if (!owns_non_root_surface) {
640 // If you're not the root, or you don't own a surface, you need to apply
641 // your local offset.
642 xform = node->data.to_target;
643 if (layer->should_flatten_transform_from_property_tree())
644 xform.FlattenTo2d();
645 xform.Translate(layer->offset_to_transform_parent().x(),
646 layer->offset_to_transform_parent().y());
647 } else {
648 // Surfaces need to apply their sublayer scale.
649 xform.Scale(node->data.sublayer_scale.x(), node->data.sublayer_scale.y());
651 return xform;
654 gfx::Transform DrawTransformFromPropertyTrees(const Layer* layer,
655 const TransformTree& tree) {
656 return DrawTransformFromPropertyTreesInternal(
657 layer, tree.Node(layer->transform_tree_index()));
660 gfx::Transform DrawTransformFromPropertyTrees(const LayerImpl* layer,
661 const TransformTree& tree) {
662 return DrawTransformFromPropertyTreesInternal(
663 layer, tree.Node(layer->transform_tree_index()));
666 gfx::Transform SurfaceDrawTransform(const RenderSurfaceImpl* render_surface,
667 const TransformTree& tree) {
668 const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
669 gfx::Transform render_surface_transform;
670 // The draw transform of root render surface is identity tranform.
671 if (node->id == 1)
672 return render_surface_transform;
673 const TransformNode* target_node = tree.Node(node->data.target_id);
674 if (target_node->id == 1)
675 target_node = tree.Node(0);
676 tree.ComputeTransformWithDestinationSublayerScale(node->id, target_node->id,
677 &render_surface_transform);
678 if (node->data.sublayer_scale.x() != 0.0 &&
679 node->data.sublayer_scale.y() != 0.0)
680 render_surface_transform.Scale(1.0 / node->data.sublayer_scale.x(),
681 1.0 / node->data.sublayer_scale.y());
682 return render_surface_transform;
685 bool SurfaceIsClipped(const RenderSurfaceImpl* render_surface,
686 const ClipNode* clip_node) {
687 // If the render surface's owning layer doesn't form a clip node, it is not
688 // clipped.
689 if (render_surface->OwningLayerId() != clip_node->owner_id)
690 return false;
691 return clip_node->data.render_surface_is_clipped;
694 gfx::Rect SurfaceClipRect(const RenderSurfaceImpl* render_surface,
695 const ClipNode* parent_clip_node,
696 bool is_clipped) {
697 if (!is_clipped)
698 return gfx::Rect();
699 return gfx::ToEnclosingRect(parent_clip_node->data.clip_in_target_space);
702 gfx::Transform SurfaceScreenSpaceTransform(
703 const RenderSurfaceImpl* render_surface,
704 const TransformTree& tree) {
705 const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
706 gfx::Transform screen_space_transform;
707 // The screen space transform of root render surface is identity tranform.
708 if (node->id == 1)
709 return screen_space_transform;
710 screen_space_transform = node->data.to_screen;
711 if (node->data.sublayer_scale.x() != 0.0 &&
712 node->data.sublayer_scale.y() != 0.0)
713 screen_space_transform.Scale(1.0 / node->data.sublayer_scale.x(),
714 1.0 / node->data.sublayer_scale.y());
715 return screen_space_transform;
718 template <typename LayerType>
719 gfx::Transform ScreenSpaceTransformFromPropertyTreesInternal(
720 LayerType* layer,
721 const TransformNode* node) {
722 gfx::Transform xform(1, 0, 0, 1, layer->offset_to_transform_parent().x(),
723 layer->offset_to_transform_parent().y());
724 gfx::Transform ssxform = node->data.to_screen;
725 xform.ConcatTransform(ssxform);
726 if (layer->should_flatten_transform_from_property_tree())
727 xform.FlattenTo2d();
728 return xform;
731 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
732 const Layer* layer,
733 const TransformTree& tree) {
734 return ScreenSpaceTransformFromPropertyTreesInternal(
735 layer, tree.Node(layer->transform_tree_index()));
738 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
739 const LayerImpl* layer,
740 const TransformTree& tree) {
741 return ScreenSpaceTransformFromPropertyTreesInternal(
742 layer, tree.Node(layer->transform_tree_index()));
745 float LayerDrawOpacity(const LayerImpl* layer, const EffectTree& tree) {
746 if (!layer->render_target())
747 return 0.f;
749 const EffectNode* target_node =
750 tree.Node(layer->render_target()->effect_tree_index());
751 const EffectNode* node = tree.Node(layer->effect_tree_index());
752 if (node == target_node)
753 return 1.f;
755 float draw_opacity = 1.f;
756 while (node != target_node) {
757 draw_opacity *= node->data.opacity;
758 node = tree.parent(node);
760 return draw_opacity;
763 float SurfaceDrawOpacity(RenderSurfaceImpl* render_surface,
764 const EffectTree& tree) {
765 const EffectNode* node = tree.Node(render_surface->EffectTreeIndex());
766 float target_opacity_tree_index = render_surface->TargetEffectTreeIndex();
767 if (target_opacity_tree_index < 0)
768 return node->data.screen_space_opacity;
769 const EffectNode* target_node = tree.Node(target_opacity_tree_index);
770 float draw_opacity = 1.f;
771 while (node != target_node) {
772 draw_opacity *= node->data.opacity;
773 node = tree.parent(node);
775 return draw_opacity;
778 bool LayerCanUseLcdText(const LayerImpl* layer,
779 bool layers_always_allowed_lcd_text,
780 bool can_use_lcd_text,
781 const TransformNode* transform_node,
782 const EffectNode* effect_node) {
783 if (layers_always_allowed_lcd_text)
784 return true;
785 if (!can_use_lcd_text)
786 return false;
787 if (!layer->contents_opaque())
788 return false;
790 if (effect_node->data.screen_space_opacity != 1.f)
791 return false;
792 if (!transform_node->data.node_and_ancestors_have_only_integer_translation)
793 return false;
794 if (static_cast<int>(layer->offset_to_transform_parent().x()) !=
795 layer->offset_to_transform_parent().x())
796 return false;
797 if (static_cast<int>(layer->offset_to_transform_parent().y()) !=
798 layer->offset_to_transform_parent().y())
799 return false;
800 return true;
803 gfx::Rect LayerDrawableContentRect(
804 const LayerImpl* layer,
805 const gfx::Rect& layer_bounds_in_target_space,
806 const gfx::Rect& clip_rect) {
807 if (layer->is_clipped())
808 return IntersectRects(layer_bounds_in_target_space, clip_rect);
810 return layer_bounds_in_target_space;
813 gfx::Transform ReplicaToSurfaceTransform(
814 const RenderSurfaceImpl* render_surface,
815 const TransformTree& tree) {
816 gfx::Transform replica_to_surface;
817 if (!render_surface->HasReplica())
818 return replica_to_surface;
819 const LayerImpl* replica_layer = render_surface->ReplicaLayer();
820 const TransformNode* surface_transform_node =
821 tree.Node(render_surface->TransformTreeIndex());
822 replica_to_surface.Scale(surface_transform_node->data.sublayer_scale.x(),
823 surface_transform_node->data.sublayer_scale.y());
824 replica_to_surface.Translate(replica_layer->offset_to_transform_parent().x(),
825 replica_layer->offset_to_transform_parent().y());
826 gfx::Transform replica_transform_node_to_surface;
827 tree.ComputeTransform(replica_layer->transform_tree_index(),
828 render_surface->TransformTreeIndex(),
829 &replica_transform_node_to_surface);
830 replica_to_surface.PreconcatTransform(replica_transform_node_to_surface);
831 if (surface_transform_node->data.sublayer_scale.x() != 0 &&
832 surface_transform_node->data.sublayer_scale.y() != 0) {
833 replica_to_surface.Scale(
834 1.0 / surface_transform_node->data.sublayer_scale.x(),
835 1.0 / surface_transform_node->data.sublayer_scale.y());
837 return replica_to_surface;
840 gfx::Rect LayerClipRect(const LayerImpl* layer,
841 const gfx::Rect& layer_bounds_in_target_space) {
842 if (layer->is_clipped())
843 return layer->clip_rect_in_target_space_from_property_trees();
845 return layer_bounds_in_target_space;
848 void ComputeLayerDrawPropertiesUsingPropertyTrees(
849 const LayerImpl* layer,
850 const PropertyTrees* property_trees,
851 bool layers_always_allowed_lcd_text,
852 bool can_use_lcd_text,
853 DrawProperties* draw_properties) {
854 draw_properties->visible_layer_rect =
855 layer->visible_rect_from_property_trees();
857 const TransformNode* transform_node =
858 property_trees->transform_tree.Node(layer->transform_tree_index());
859 const EffectNode* effect_node =
860 property_trees->effect_tree.Node(layer->effect_tree_index());
862 draw_properties->target_space_transform =
863 DrawTransformFromPropertyTreesInternal(layer, transform_node);
864 draw_properties->screen_space_transform =
865 ScreenSpaceTransformFromPropertyTreesInternal(layer, transform_node);
866 draw_properties->screen_space_transform_is_animating =
867 transform_node->data.to_screen_is_animated;
868 if (layer->layer_tree_impl()
869 ->settings()
870 .layer_transforms_should_scale_layer_contents) {
871 draw_properties->maximum_animation_contents_scale =
872 transform_node->data.combined_maximum_animation_target_scale;
873 draw_properties->starting_animation_contents_scale =
874 transform_node->data.combined_starting_animation_scale;
875 } else {
876 draw_properties->maximum_animation_contents_scale = 0.f;
877 draw_properties->starting_animation_contents_scale = 0.f;
880 draw_properties->opacity =
881 LayerDrawOpacity(layer, property_trees->effect_tree);
882 draw_properties->can_use_lcd_text =
883 LayerCanUseLcdText(layer, layers_always_allowed_lcd_text,
884 can_use_lcd_text, transform_node, effect_node);
886 gfx::Rect bounds_in_target_space = MathUtil::MapEnclosingClippedRect(
887 draw_properties->target_space_transform, gfx::Rect(layer->bounds()));
888 draw_properties->clip_rect = LayerClipRect(layer, bounds_in_target_space);
889 draw_properties->drawable_content_rect = LayerDrawableContentRect(
890 layer, bounds_in_target_space, draw_properties->clip_rect);
893 void ComputeSurfaceDrawPropertiesUsingPropertyTrees(
894 RenderSurfaceImpl* render_surface,
895 const PropertyTrees* property_trees,
896 RenderSurfaceDrawProperties* draw_properties) {
897 const ClipNode* clip_node =
898 property_trees->clip_tree.Node(render_surface->ClipTreeIndex());
900 draw_properties->is_clipped = SurfaceIsClipped(render_surface, clip_node);
901 draw_properties->draw_opacity =
902 SurfaceDrawOpacity(render_surface, property_trees->effect_tree);
903 draw_properties->draw_transform =
904 SurfaceDrawTransform(render_surface, property_trees->transform_tree);
905 draw_properties->screen_space_transform = SurfaceScreenSpaceTransform(
906 render_surface, property_trees->transform_tree);
908 if (render_surface->HasReplica()) {
909 gfx::Transform replica_to_surface = ReplicaToSurfaceTransform(
910 render_surface, property_trees->transform_tree);
911 draw_properties->replica_draw_transform =
912 draw_properties->draw_transform * replica_to_surface;
913 draw_properties->replica_screen_space_transform =
914 draw_properties->screen_space_transform * replica_to_surface;
915 } else {
916 draw_properties->replica_draw_transform.MakeIdentity();
917 draw_properties->replica_screen_space_transform.MakeIdentity();
920 draw_properties->clip_rect = SurfaceClipRect(
921 render_surface, property_trees->clip_tree.parent(clip_node),
922 draw_properties->is_clipped);
925 } // namespace cc