This sets up API to release OutputSurface from LTHClient.
[chromium-blink-merge.git] / cc / trees / draw_property_utils.cc
blob709d225b98939e8efa846b7c2c3b9fb3bab8863f
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 // When the target is the root surface, we need to include the root
41 // transform by walking up to the root of the transform tree.
42 const int target_id = transform_node->data.content_target_id;
43 const TransformNode* target_node = transform_tree.Node(target_id);
45 gfx::Transform content_to_target = transform_node->data.to_target;
47 content_to_target.Translate(layer->offset_to_transform_parent().x(),
48 layer->offset_to_transform_parent().y());
50 gfx::Rect combined_clip_rect_in_target_space;
51 gfx::Rect clip_rect_in_target_space;
52 gfx::Transform clip_to_target;
53 bool success = true;
54 if (clip_transform_node->data.target_id == target_node->id) {
55 clip_to_target = clip_transform_node->data.to_target;
56 } else {
57 success = transform_tree.ComputeTransformWithDestinationSublayerScale(
58 clip_transform_node->id, target_node->id, &clip_to_target);
60 if (target_node->id > clip_node->data.transform_id) {
61 if (!success) {
62 DCHECK(target_node->data.to_screen_is_animated);
64 // An animated singular transform may become non-singular during the
65 // animation, so we still need to compute a visible rect. In this
66 // situation, we treat the entire layer as visible.
67 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
68 layer->set_clip_rect_in_target_space_from_property_trees(
69 gfx::ToEnclosingRect(clip_node->data.combined_clip));
70 continue;
73 combined_clip_rect_in_target_space =
74 gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
75 clip_to_target, clip_node->data.combined_clip));
76 clip_rect_in_target_space = gfx::ToEnclosingRect(
77 MathUtil::ProjectClippedRect(clip_to_target, clip_node->data.clip));
78 } else {
79 // Computing a transform to an ancestor should always succeed.
80 DCHECK(success);
81 combined_clip_rect_in_target_space =
82 gfx::ToEnclosingRect(MathUtil::MapClippedRect(
83 clip_to_target, clip_node->data.combined_clip));
84 clip_rect_in_target_space = gfx::ToEnclosingRect(
85 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip));
88 if (clip_node->data.requires_tight_clip_rect) {
89 if (!combined_clip_rect_in_target_space.IsEmpty()) {
90 layer->set_clip_rect_in_target_space_from_property_trees(
91 combined_clip_rect_in_target_space);
92 } else {
93 layer->set_clip_rect_in_target_space_from_property_trees(gfx::Rect());
95 } else {
96 if (!clip_rect_in_target_space.IsEmpty()) {
97 layer->set_clip_rect_in_target_space_from_property_trees(
98 clip_rect_in_target_space);
99 } else {
100 layer->set_clip_rect_in_target_space_from_property_trees(gfx::Rect());
104 gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
105 gfx::Rect layer_content_bounds_in_target_space =
106 MathUtil::MapEnclosingClippedRect(content_to_target,
107 layer_content_rect);
108 combined_clip_rect_in_target_space.Intersect(
109 layer_content_bounds_in_target_space);
110 if (combined_clip_rect_in_target_space.IsEmpty()) {
111 layer->set_visible_rect_from_property_trees(gfx::Rect());
112 continue;
115 // If the layer is fully contained within the clip, treat it as fully
116 // visible. Since clip_rect_in_target_space has already been intersected
117 // with layer_content_bounds_in_target_space, the layer is fully contained
118 // within the clip iff these rects are equal.
119 if (combined_clip_rect_in_target_space ==
120 layer_content_bounds_in_target_space) {
121 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
122 continue;
125 gfx::Transform target_to_content;
126 gfx::Transform target_to_layer;
128 if (transform_node->data.ancestors_are_invertible) {
129 target_to_layer = transform_node->data.from_target;
130 success = true;
131 } else {
132 success = transform_tree.ComputeTransformWithSourceSublayerScale(
133 target_node->id, transform_node->id, &target_to_layer);
136 if (!success) {
137 // An animated singular transform may become non-singular during the
138 // animation, so we still need to compute a visible rect. In this
139 // situation, we treat the entire layer as visible.
140 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
141 continue;
144 target_to_content.Translate(-layer->offset_to_transform_parent().x(),
145 -layer->offset_to_transform_parent().y());
146 target_to_content.PreconcatTransform(target_to_layer);
148 gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
149 target_to_content, combined_clip_rect_in_target_space);
151 visible_rect.Intersect(gfx::Rect(layer_bounds));
153 layer->set_visible_rect_from_property_trees(visible_rect);
154 } else {
155 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
156 layer->set_clip_rect_in_target_space_from_property_trees(
157 gfx::Rect(layer_bounds));
162 template <typename LayerType>
163 static bool IsRootLayerOfNewRenderingContext(LayerType* layer) {
164 if (layer->parent())
165 return !layer->parent()->Is3dSorted() && layer->Is3dSorted();
166 return layer->Is3dSorted();
169 template <typename LayerType>
170 static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
171 return layer->Is3dSorted() && layer->parent() &&
172 layer->parent()->Is3dSorted() &&
173 layer->parent()->sorting_context_id() == layer->sorting_context_id();
176 template <typename LayerType>
177 static bool TransformToScreenIsKnown(LayerType* layer,
178 const TransformTree& tree) {
179 const TransformNode* node = tree.Node(layer->transform_tree_index());
180 return !node->data.to_screen_is_animated;
183 template <typename LayerType>
184 static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
185 const TransformNode* node = tree.Node(layer->transform_tree_index());
186 return !node->data.is_invertible || !node->data.ancestors_are_invertible;
189 template <typename LayerType>
190 static bool IsLayerBackFaceVisible(LayerType* layer,
191 const TransformTree& tree) {
192 // The current W3C spec on CSS transforms says that backface visibility should
193 // be determined differently depending on whether the layer is in a "3d
194 // rendering context" or not. For Chromium code, we can determine whether we
195 // are in a 3d rendering context by checking if the parent preserves 3d.
197 if (LayerIsInExisting3DRenderingContext(layer))
198 return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
200 // In this case, either the layer establishes a new 3d rendering context, or
201 // is not in a 3d rendering context at all.
202 return layer->transform().IsBackFaceVisible();
205 template <typename LayerType>
206 static bool IsSurfaceBackFaceVisible(LayerType* layer,
207 const TransformTree& tree) {
208 if (LayerIsInExisting3DRenderingContext(layer)) {
209 const TransformNode* node = tree.Node(layer->transform_tree_index());
210 // Draw transform as a contributing render surface.
211 // TODO(enne): we shouldn't walk the tree during a tree walk.
212 gfx::Transform surface_draw_transform;
213 tree.ComputeTransform(node->id, node->data.target_id,
214 &surface_draw_transform);
215 return surface_draw_transform.IsBackFaceVisible();
218 if (IsRootLayerOfNewRenderingContext(layer))
219 return layer->transform().IsBackFaceVisible();
221 // If the render_surface is not part of a new or existing rendering context,
222 // then the layers that contribute to this surface will decide back-face
223 // visibility for themselves.
224 return false;
227 template <typename LayerType>
228 static bool IsAnimatingTransformToScreen(LayerType* layer,
229 const TransformTree& tree) {
230 const TransformNode* node = tree.Node(layer->transform_tree_index());
231 return node->data.to_screen_is_animated;
234 static inline bool TransformToScreenIsKnown(Layer* layer,
235 const TransformTree& tree) {
236 return !IsAnimatingTransformToScreen(layer, tree);
239 static inline bool TransformToScreenIsKnown(LayerImpl* layer,
240 const TransformTree& tree) {
241 return true;
244 template <typename LayerType>
245 static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
246 return layer->transform_is_invertible() ||
247 layer->HasPotentiallyRunningTransformAnimation();
250 static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
251 bool layer_is_drawn,
252 const TransformTree& tree) {
253 // If the layer transform is not invertible, it should not be drawn.
254 // TODO(ajuma): Correctly process subtrees with singular transform for the
255 // case where we may animate to a non-singular transform and wish to
256 // pre-raster.
257 if (!HasInvertibleOrAnimatedTransform(layer))
258 return true;
260 // When we need to do a readback/copy of a layer's output, we can not skip
261 // it or any of its ancestors.
262 if (layer->draw_properties().layer_or_descendant_has_copy_request)
263 return false;
265 // If the layer is not drawn, then skip it and its subtree.
266 if (!layer_is_drawn)
267 return true;
269 if (layer->render_surface() && !layer->double_sided() &&
270 IsSurfaceBackFaceVisible(layer, tree))
271 return true;
273 // If layer is on the pending tree and opacity is being animated then
274 // this subtree can't be skipped as we need to create, prioritize and
275 // include tiles for this layer when deciding if tree can be activated.
276 if (layer->layer_tree_impl()->IsPendingTree() &&
277 layer->HasPotentiallyRunningOpacityAnimation())
278 return false;
280 // If layer has a background filter, don't skip the layer, even it the
281 // opacity is 0.
282 if (!layer->background_filters().IsEmpty())
283 return false;
285 // The opacity of a layer always applies to its children (either implicitly
286 // via a render surface or explicitly if the parent preserves 3D), so the
287 // entire subtree can be skipped if this layer is fully transparent.
288 return !layer->opacity();
291 static inline bool SubtreeShouldBeSkipped(Layer* layer,
292 bool layer_is_drawn,
293 const TransformTree& tree) {
294 // If the layer transform is not invertible, it should not be drawn.
295 if (!layer->transform_is_invertible() &&
296 !layer->HasPotentiallyRunningTransformAnimation())
297 return true;
299 // When we need to do a readback/copy of a layer's output, we can not skip
300 // it or any of its ancestors.
301 if (layer->num_layer_or_descendants_with_copy_request() > 0)
302 return false;
304 // If the layer is not drawn, then skip it and its subtree.
305 if (!layer_is_drawn)
306 return true;
308 if (layer->has_render_surface() && !layer->double_sided() &&
309 !layer->HasPotentiallyRunningTransformAnimation() &&
310 IsSurfaceBackFaceVisible(layer, tree))
311 return true;
313 // If layer has a background filter, don't skip the layer, even it the
314 // opacity is 0.
315 if (!layer->background_filters().IsEmpty())
316 return false;
318 // If the opacity is being animated then the opacity on the main thread is
319 // unreliable (since the impl thread may be using a different opacity), so it
320 // should not be trusted.
321 // In particular, it should not cause the subtree to be skipped.
322 // Similarly, for layers that might animate opacity using an impl-only
323 // animation, their subtree should also not be skipped.
324 return !layer->opacity() && !layer->HasPotentiallyRunningOpacityAnimation() &&
325 !layer->OpacityCanAnimateOnImplThread();
328 template <typename LayerType>
329 static bool LayerShouldBeSkipped(LayerType* layer,
330 bool layer_is_drawn,
331 const TransformTree& tree) {
332 // Layers can be skipped if any of these conditions are met.
333 // - is not drawn due to it or one of its ancestors being hidden (or having
334 // no copy requests).
335 // - does not draw content.
336 // - is transparent.
337 // - has empty bounds
338 // - the layer is not double-sided, but its back face is visible.
340 // Some additional conditions need to be computed at a later point after the
341 // recursion is finished.
342 // - the intersection of render_surface content and layer clip_rect is empty
343 // - the visible_layer_rect is empty
345 // Note, if the layer should not have been drawn due to being fully
346 // transparent, we would have skipped the entire subtree and never made it
347 // into this function, so it is safe to omit this check here.
348 if (!layer_is_drawn)
349 return true;
351 if (!layer->DrawsContent() || layer->bounds().IsEmpty())
352 return true;
354 LayerType* backface_test_layer = layer;
355 if (layer->use_parent_backface_visibility()) {
356 DCHECK(layer->parent());
357 DCHECK(!layer->parent()->use_parent_backface_visibility());
358 backface_test_layer = layer->parent();
361 // The layer should not be drawn if (1) it is not double-sided and (2) the
362 // back of the layer is known to be facing the screen.
363 if (!backface_test_layer->double_sided() &&
364 TransformToScreenIsKnown(backface_test_layer, tree) &&
365 IsLayerBackFaceVisible(backface_test_layer, tree))
366 return true;
368 return false;
371 template <typename LayerType>
372 void FindLayersThatNeedUpdates(
373 LayerType* layer,
374 const TransformTree& tree,
375 bool subtree_is_visible_from_ancestor,
376 typename LayerType::LayerListType* update_layer_list,
377 std::vector<LayerType*>* visible_layer_list) {
378 bool layer_is_drawn =
379 layer->HasCopyRequest() ||
380 (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree());
382 if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn, tree))
383 return;
385 if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) {
386 visible_layer_list->push_back(layer);
387 update_layer_list->push_back(layer);
390 // Append mask layers to the update layer list. They don't have valid visible
391 // rects, so need to get added after the above calculation. Replica layers
392 // don't need to be updated.
393 if (LayerType* mask_layer = layer->mask_layer())
394 update_layer_list->push_back(mask_layer);
395 if (LayerType* replica_layer = layer->replica_layer()) {
396 if (LayerType* mask_layer = replica_layer->mask_layer())
397 update_layer_list->push_back(mask_layer);
400 for (size_t i = 0; i < layer->children().size(); ++i) {
401 FindLayersThatNeedUpdates(layer->child_at(i), tree, layer_is_drawn,
402 update_layer_list, visible_layer_list);
406 } // namespace
408 void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) {
409 if (!clip_tree->needs_update())
410 return;
411 for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) {
412 ClipNode* clip_node = clip_tree->Node(i);
413 const TransformNode* transform_node =
414 transform_tree.Node(clip_node->data.transform_id);
416 // Only descendants of a real clipping layer (i.e., not 0) may have their
417 // clip adjusted due to intersecting with an ancestor clip.
418 const bool is_clipped = clip_node->parent_id > 0;
419 if (!is_clipped) {
420 DCHECK(!clip_node->data.inherit_parent_target_space_clip);
421 clip_node->data.combined_clip = clip_node->data.clip;
422 if (clip_node->id > 0) {
423 gfx::Transform to_target = transform_node->data.to_target;
424 clip_node->data.clip_in_target_space =
425 MathUtil::MapClippedRect(to_target, clip_node->data.combined_clip);
427 continue;
430 ClipNode* parent_clip_node = clip_tree->parent(clip_node);
431 const TransformNode* parent_transform_node =
432 transform_tree.Node(parent_clip_node->data.transform_id);
434 // Clips must be combined in target space. We cannot, for example, combine
435 // clips in the space of the child clip. The reason is non-affine
436 // transforms. Say we have the following tree T->A->B->C, and B clips C, but
437 // draw into target T. It may be the case that A applies a perspective
438 // transform, and B and C are at different z positions. When projected into
439 // target space, the relative sizes and positions of B and C can shift.
440 // Since it's the relationship in target space that matters, that's where we
441 // must combine clips.
442 gfx::Transform parent_to_target;
443 gfx::Transform clip_to_target;
445 gfx::Transform target_to_clip;
446 gfx::Transform parent_to_transform_target;
447 gfx::Transform transform_target_to_target;
449 // When the target is the root surface, we need to include the root
450 // transform by walking up to the root of the transform tree.
451 const int target_id = clip_node->data.target_id;
453 bool success = true;
454 // When render surface applies clip, we need the clip from the target's
455 // target space. But, as the combined clip is in parent clip's target
456 // space, we need to first transform it from parent's target space to
457 // target's target space.
458 if (clip_node->data.inherit_parent_target_space_clip) {
459 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
460 parent_transform_node->id, transform_node->data.target_id,
461 &parent_to_transform_target);
462 success &= transform_tree.ComputeTransformWithSourceSublayerScale(
463 transform_node->data.target_id, target_id,
464 &transform_target_to_target);
465 transform_target_to_target.matrix().postScale(
466 transform_node->data.sublayer_scale.x(),
467 transform_node->data.sublayer_scale.y(), 1.0);
468 } else if (parent_transform_node->data.content_target_id ==
469 clip_node->data.target_id) {
470 parent_to_target = parent_transform_node->data.to_target;
471 } else {
472 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
473 parent_transform_node->id, target_id, &parent_to_target);
476 if (transform_node->data.content_target_id == clip_node->data.target_id) {
477 clip_to_target = transform_node->data.to_target;
478 } else {
479 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
480 transform_node->id, target_id, &clip_to_target);
483 if (transform_node->data.content_target_id == clip_node->data.target_id &&
484 transform_node->data.ancestors_are_invertible) {
485 target_to_clip = transform_node->data.from_target;
486 } else {
487 success &= clip_to_target.GetInverse(&target_to_clip);
490 // If we can't compute a transform, it's because we had to use the inverse
491 // of a singular transform. We won't draw in this case, so there's no need
492 // to compute clips.
493 if (!success) {
494 continue;
497 // In order to intersect with as small a rect as possible, we do a
498 // preliminary clip in target space so that when we project back, there's
499 // less likelihood of intersecting the view plane.
500 gfx::RectF inherited_clip_in_target_space;
501 if (clip_node->data.inherit_parent_target_space_clip) {
502 gfx::RectF combined_clip_in_transform_target_space;
503 if (parent_transform_node->id > transform_node->data.target_id)
504 combined_clip_in_transform_target_space = MathUtil::MapClippedRect(
505 parent_to_transform_target, parent_clip_node->data.combined_clip);
506 else
507 combined_clip_in_transform_target_space = MathUtil::ProjectClippedRect(
508 parent_to_transform_target, parent_clip_node->data.combined_clip);
509 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
510 transform_target_to_target, combined_clip_in_transform_target_space);
511 } else if (parent_transform_node->id > target_id) {
512 inherited_clip_in_target_space = MathUtil::MapClippedRect(
513 parent_to_target, parent_clip_node->data.combined_clip);
514 } else {
515 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
516 parent_to_target, parent_clip_node->data.combined_clip);
519 // When render surface inherits its parent target space clip, the layer
520 // that created the clip node doesn't apply any clip. So, we shouldn't clip
521 // using the clip value stored in the clip node.
522 gfx::RectF intersected_in_target_space;
523 if (!clip_node->data.inherit_parent_target_space_clip) {
524 gfx::RectF clip_in_target_space =
525 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip);
526 intersected_in_target_space = gfx::IntersectRects(
527 inherited_clip_in_target_space, clip_in_target_space);
528 if (!clip_node->data.requires_tight_clip_rect)
529 clip_node->data.clip_in_target_space = clip_in_target_space;
530 else
531 clip_node->data.clip_in_target_space = intersected_in_target_space;
532 } else {
533 intersected_in_target_space = inherited_clip_in_target_space;
534 clip_node->data.clip_in_target_space = intersected_in_target_space;
537 clip_node->data.combined_clip = MathUtil::ProjectClippedRect(
538 target_to_clip, intersected_in_target_space);
540 if (!clip_node->data.inherit_parent_target_space_clip)
541 clip_node->data.combined_clip.Intersect(clip_node->data.clip);
543 clip_tree->set_needs_update(false);
546 void ComputeTransforms(TransformTree* transform_tree) {
547 if (!transform_tree->needs_update())
548 return;
549 for (int i = 1; i < static_cast<int>(transform_tree->size()); ++i)
550 transform_tree->UpdateTransforms(i);
551 transform_tree->set_needs_update(false);
554 void ComputeOpacities(EffectTree* effect_tree) {
555 if (!effect_tree->needs_update())
556 return;
557 for (int i = 1; i < static_cast<int>(effect_tree->size()); ++i)
558 effect_tree->UpdateOpacities(i);
559 effect_tree->set_needs_update(false);
562 template <typename LayerType>
563 void ComputeVisibleRectsUsingPropertyTreesInternal(
564 LayerType* root_layer,
565 PropertyTrees* property_trees,
566 typename LayerType::LayerListType* update_layer_list) {
567 if (property_trees->transform_tree.needs_update())
568 property_trees->clip_tree.set_needs_update(true);
569 ComputeTransforms(&property_trees->transform_tree);
570 ComputeClips(&property_trees->clip_tree, property_trees->transform_tree);
571 ComputeOpacities(&property_trees->effect_tree);
573 const bool subtree_is_visible_from_ancestor = true;
574 std::vector<LayerType*> visible_layer_list;
575 FindLayersThatNeedUpdates(root_layer, property_trees->transform_tree,
576 subtree_is_visible_from_ancestor, update_layer_list,
577 &visible_layer_list);
578 CalculateVisibleRects<LayerType>(visible_layer_list,
579 property_trees->clip_tree,
580 property_trees->transform_tree);
583 void BuildPropertyTreesAndComputeVisibleRects(
584 Layer* root_layer,
585 const Layer* page_scale_layer,
586 const Layer* inner_viewport_scroll_layer,
587 const Layer* outer_viewport_scroll_layer,
588 float page_scale_factor,
589 float device_scale_factor,
590 const gfx::Rect& viewport,
591 const gfx::Transform& device_transform,
592 PropertyTrees* property_trees,
593 LayerList* update_layer_list) {
594 PropertyTreeBuilder::BuildPropertyTrees(
595 root_layer, page_scale_layer, inner_viewport_scroll_layer,
596 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
597 viewport, device_transform, property_trees);
598 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
599 update_layer_list);
602 void BuildPropertyTreesAndComputeVisibleRects(
603 LayerImpl* root_layer,
604 const LayerImpl* page_scale_layer,
605 const LayerImpl* inner_viewport_scroll_layer,
606 const LayerImpl* outer_viewport_scroll_layer,
607 float page_scale_factor,
608 float device_scale_factor,
609 const gfx::Rect& viewport,
610 const gfx::Transform& device_transform,
611 PropertyTrees* property_trees,
612 LayerImplList* update_layer_list) {
613 PropertyTreeBuilder::BuildPropertyTrees(
614 root_layer, page_scale_layer, inner_viewport_scroll_layer,
615 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
616 viewport, device_transform, property_trees);
617 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
618 update_layer_list);
621 void ComputeVisibleRectsUsingPropertyTrees(Layer* root_layer,
622 PropertyTrees* property_trees,
623 LayerList* update_layer_list) {
624 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
625 update_layer_list);
628 void ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer,
629 PropertyTrees* property_trees,
630 LayerImplList* update_layer_list) {
631 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
632 update_layer_list);
635 template <typename LayerType>
636 gfx::Transform DrawTransformFromPropertyTreesInternal(
637 const LayerType* layer,
638 const TransformNode* node) {
639 gfx::Transform xform;
640 const bool owns_non_root_surface =
641 layer->parent() && layer->has_render_surface();
642 if (!owns_non_root_surface) {
643 // If you're not the root, or you don't own a surface, you need to apply
644 // your local offset.
645 xform = node->data.to_target;
646 if (layer->should_flatten_transform_from_property_tree())
647 xform.FlattenTo2d();
648 xform.Translate(layer->offset_to_transform_parent().x(),
649 layer->offset_to_transform_parent().y());
650 } else {
651 // Surfaces need to apply their sublayer scale.
652 xform.Scale(node->data.sublayer_scale.x(), node->data.sublayer_scale.y());
654 return xform;
657 gfx::Transform DrawTransformFromPropertyTrees(const Layer* layer,
658 const TransformTree& tree) {
659 return DrawTransformFromPropertyTreesInternal(
660 layer, tree.Node(layer->transform_tree_index()));
663 gfx::Transform DrawTransformFromPropertyTrees(const LayerImpl* layer,
664 const TransformTree& tree) {
665 return DrawTransformFromPropertyTreesInternal(
666 layer, tree.Node(layer->transform_tree_index()));
669 gfx::Transform SurfaceDrawTransform(const RenderSurfaceImpl* render_surface,
670 const TransformTree& tree) {
671 const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
672 gfx::Transform render_surface_transform;
673 // The draw transform of root render surface is identity tranform.
674 if (node->id == 1)
675 return render_surface_transform;
676 const TransformNode* target_node = tree.Node(node->data.target_id);
677 tree.ComputeTransformWithDestinationSublayerScale(node->id, target_node->id,
678 &render_surface_transform);
679 if (node->data.sublayer_scale.x() != 0.0 &&
680 node->data.sublayer_scale.y() != 0.0)
681 render_surface_transform.Scale(1.0 / node->data.sublayer_scale.x(),
682 1.0 / node->data.sublayer_scale.y());
683 return render_surface_transform;
686 bool SurfaceIsClipped(const RenderSurfaceImpl* render_surface,
687 const ClipNode* clip_node) {
688 // If the render surface's owning layer doesn't form a clip node, it is not
689 // clipped.
690 if (render_surface->OwningLayerId() != clip_node->owner_id)
691 return false;
692 return clip_node->data.render_surface_is_clipped;
695 gfx::Rect SurfaceClipRect(const RenderSurfaceImpl* render_surface,
696 const ClipNode* parent_clip_node,
697 bool is_clipped) {
698 if (!is_clipped)
699 return gfx::Rect();
700 return gfx::ToEnclosingRect(parent_clip_node->data.clip_in_target_space);
703 gfx::Transform SurfaceScreenSpaceTransform(
704 const RenderSurfaceImpl* render_surface,
705 const TransformTree& tree) {
706 const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
707 gfx::Transform screen_space_transform;
708 // The screen space transform of root render surface is identity tranform.
709 if (node->id == 1)
710 return screen_space_transform;
711 screen_space_transform = node->data.to_screen;
712 if (node->data.sublayer_scale.x() != 0.0 &&
713 node->data.sublayer_scale.y() != 0.0)
714 screen_space_transform.Scale(1.0 / node->data.sublayer_scale.x(),
715 1.0 / node->data.sublayer_scale.y());
716 return screen_space_transform;
719 template <typename LayerType>
720 gfx::Transform ScreenSpaceTransformFromPropertyTreesInternal(
721 LayerType* layer,
722 const TransformNode* node) {
723 gfx::Transform xform(1, 0, 0, 1, layer->offset_to_transform_parent().x(),
724 layer->offset_to_transform_parent().y());
725 gfx::Transform ssxform = node->data.to_screen;
726 xform.ConcatTransform(ssxform);
727 if (layer->should_flatten_transform_from_property_tree())
728 xform.FlattenTo2d();
729 return xform;
732 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
733 const Layer* layer,
734 const TransformTree& tree) {
735 return ScreenSpaceTransformFromPropertyTreesInternal(
736 layer, tree.Node(layer->transform_tree_index()));
739 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
740 const LayerImpl* layer,
741 const TransformTree& tree) {
742 return ScreenSpaceTransformFromPropertyTreesInternal(
743 layer, tree.Node(layer->transform_tree_index()));
746 float LayerDrawOpacity(const LayerImpl* layer, const EffectTree& tree) {
747 if (!layer->render_target())
748 return 0.f;
750 const EffectNode* target_node =
751 tree.Node(layer->render_target()->effect_tree_index());
752 const EffectNode* node = tree.Node(layer->effect_tree_index());
753 if (node == target_node)
754 return 1.f;
756 float draw_opacity = 1.f;
757 while (node != target_node) {
758 draw_opacity *= node->data.opacity;
759 node = tree.parent(node);
761 return draw_opacity;
764 float SurfaceDrawOpacity(RenderSurfaceImpl* render_surface,
765 const EffectTree& tree) {
766 const EffectNode* node = tree.Node(render_surface->EffectTreeIndex());
767 float target_opacity_tree_index = render_surface->TargetEffectTreeIndex();
768 if (target_opacity_tree_index < 0)
769 return node->data.screen_space_opacity;
770 const EffectNode* target_node = tree.Node(target_opacity_tree_index);
771 float draw_opacity = 1.f;
772 while (node != target_node) {
773 draw_opacity *= node->data.opacity;
774 node = tree.parent(node);
776 return draw_opacity;
779 bool LayerCanUseLcdText(const LayerImpl* layer,
780 bool layers_always_allowed_lcd_text,
781 bool can_use_lcd_text,
782 const TransformNode* transform_node,
783 const EffectNode* effect_node) {
784 if (layers_always_allowed_lcd_text)
785 return true;
786 if (!can_use_lcd_text)
787 return false;
788 if (!layer->contents_opaque())
789 return false;
791 if (effect_node->data.screen_space_opacity != 1.f)
792 return false;
793 if (!transform_node->data.node_and_ancestors_have_only_integer_translation)
794 return false;
795 if (static_cast<int>(layer->offset_to_transform_parent().x()) !=
796 layer->offset_to_transform_parent().x())
797 return false;
798 if (static_cast<int>(layer->offset_to_transform_parent().y()) !=
799 layer->offset_to_transform_parent().y())
800 return false;
801 return true;
804 gfx::Rect LayerDrawableContentRect(
805 const LayerImpl* layer,
806 const gfx::Rect& layer_bounds_in_target_space,
807 const gfx::Rect& clip_rect) {
808 if (layer->is_clipped())
809 return IntersectRects(layer_bounds_in_target_space, clip_rect);
811 return layer_bounds_in_target_space;
814 gfx::Transform ReplicaToSurfaceTransform(
815 const RenderSurfaceImpl* render_surface,
816 const TransformTree& tree) {
817 gfx::Transform replica_to_surface;
818 if (!render_surface->HasReplica())
819 return replica_to_surface;
820 const LayerImpl* replica_layer = render_surface->ReplicaLayer();
821 const TransformNode* surface_transform_node =
822 tree.Node(render_surface->TransformTreeIndex());
823 replica_to_surface.Scale(surface_transform_node->data.sublayer_scale.x(),
824 surface_transform_node->data.sublayer_scale.y());
825 replica_to_surface.Translate(replica_layer->offset_to_transform_parent().x(),
826 replica_layer->offset_to_transform_parent().y());
827 gfx::Transform replica_transform_node_to_surface;
828 tree.ComputeTransform(replica_layer->transform_tree_index(),
829 render_surface->TransformTreeIndex(),
830 &replica_transform_node_to_surface);
831 replica_to_surface.PreconcatTransform(replica_transform_node_to_surface);
832 if (surface_transform_node->data.sublayer_scale.x() != 0 &&
833 surface_transform_node->data.sublayer_scale.y() != 0) {
834 replica_to_surface.Scale(
835 1.0 / surface_transform_node->data.sublayer_scale.x(),
836 1.0 / surface_transform_node->data.sublayer_scale.y());
838 return replica_to_surface;
841 gfx::Rect LayerClipRect(const LayerImpl* layer,
842 const gfx::Rect& layer_bounds_in_target_space) {
843 if (layer->is_clipped())
844 return layer->clip_rect_in_target_space_from_property_trees();
846 return layer_bounds_in_target_space;
849 void ComputeLayerDrawPropertiesUsingPropertyTrees(
850 const LayerImpl* layer,
851 const PropertyTrees* property_trees,
852 bool layers_always_allowed_lcd_text,
853 bool can_use_lcd_text,
854 DrawProperties* draw_properties) {
855 draw_properties->visible_layer_rect =
856 layer->visible_rect_from_property_trees();
858 const TransformNode* transform_node =
859 property_trees->transform_tree.Node(layer->transform_tree_index());
860 const EffectNode* effect_node =
861 property_trees->effect_tree.Node(layer->effect_tree_index());
863 draw_properties->target_space_transform =
864 DrawTransformFromPropertyTreesInternal(layer, transform_node);
865 draw_properties->screen_space_transform =
866 ScreenSpaceTransformFromPropertyTreesInternal(layer, transform_node);
867 draw_properties->screen_space_transform_is_animating =
868 transform_node->data.to_screen_is_animated;
869 if (layer->layer_tree_impl()
870 ->settings()
871 .layer_transforms_should_scale_layer_contents) {
872 draw_properties->maximum_animation_contents_scale =
873 transform_node->data.combined_maximum_animation_target_scale;
874 draw_properties->starting_animation_contents_scale =
875 transform_node->data.combined_starting_animation_scale;
876 } else {
877 draw_properties->maximum_animation_contents_scale = 0.f;
878 draw_properties->starting_animation_contents_scale = 0.f;
881 draw_properties->opacity =
882 LayerDrawOpacity(layer, property_trees->effect_tree);
883 draw_properties->can_use_lcd_text =
884 LayerCanUseLcdText(layer, layers_always_allowed_lcd_text,
885 can_use_lcd_text, transform_node, effect_node);
887 gfx::Rect bounds_in_target_space = MathUtil::MapEnclosingClippedRect(
888 draw_properties->target_space_transform, gfx::Rect(layer->bounds()));
889 draw_properties->clip_rect = LayerClipRect(layer, bounds_in_target_space);
890 draw_properties->drawable_content_rect = LayerDrawableContentRect(
891 layer, bounds_in_target_space, draw_properties->clip_rect);
894 void ComputeSurfaceDrawPropertiesUsingPropertyTrees(
895 RenderSurfaceImpl* render_surface,
896 const PropertyTrees* property_trees,
897 RenderSurfaceDrawProperties* draw_properties) {
898 const ClipNode* clip_node =
899 property_trees->clip_tree.Node(render_surface->ClipTreeIndex());
901 draw_properties->is_clipped = SurfaceIsClipped(render_surface, clip_node);
902 draw_properties->draw_opacity =
903 SurfaceDrawOpacity(render_surface, property_trees->effect_tree);
904 draw_properties->draw_transform =
905 SurfaceDrawTransform(render_surface, property_trees->transform_tree);
906 draw_properties->screen_space_transform = SurfaceScreenSpaceTransform(
907 render_surface, property_trees->transform_tree);
909 if (render_surface->HasReplica()) {
910 gfx::Transform replica_to_surface = ReplicaToSurfaceTransform(
911 render_surface, property_trees->transform_tree);
912 draw_properties->replica_draw_transform =
913 draw_properties->draw_transform * replica_to_surface;
914 draw_properties->replica_screen_space_transform =
915 draw_properties->screen_space_transform * replica_to_surface;
916 } else {
917 draw_properties->replica_draw_transform.MakeIdentity();
918 draw_properties->replica_screen_space_transform.MakeIdentity();
921 draw_properties->clip_rect = SurfaceClipRect(
922 render_surface, property_trees->clip_tree.parent(clip_node),
923 draw_properties->is_clipped);
926 } // namespace cc