Update V8 to version 4.6.65.
[chromium-blink-merge.git] / cc / trees / draw_property_utils.cc
blob38a8104817b45e067fc964e420092e0bc9f51ccc
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/layer.h"
11 #include "cc/layers/layer_impl.h"
12 #include "cc/trees/layer_tree_impl.h"
13 #include "cc/trees/property_tree.h"
14 #include "cc/trees/property_tree_builder.h"
15 #include "ui/gfx/geometry/rect_conversions.h"
17 namespace cc {
19 namespace {
21 template <typename LayerType>
22 void CalculateVisibleRects(const std::vector<LayerType*>& visible_layer_list,
23 const ClipTree& clip_tree,
24 const TransformTree& transform_tree) {
25 for (auto& layer : visible_layer_list) {
26 // TODO(ajuma): Compute content_scale rather than using it. Note that for
27 // PictureLayer and PictureImageLayers, content_bounds == bounds and
28 // content_scale_x == content_scale_y == 1.0, so once impl painting is on
29 // everywhere, this code will be unnecessary.
30 gfx::Size layer_bounds = layer->bounds();
31 const bool has_clip = layer->clip_tree_index() > 0;
32 const TransformNode* transform_node =
33 transform_tree.Node(layer->transform_tree_index());
34 if (has_clip) {
35 const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
36 const TransformNode* clip_transform_node =
37 transform_tree.Node(clip_node->data.transform_id);
38 const bool target_is_root_surface =
39 transform_node->data.content_target_id == 1;
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 =
43 target_is_root_surface ? 0 : transform_node->data.content_target_id;
44 const TransformNode* target_node = transform_tree.Node(target_id);
46 gfx::Transform content_to_target = transform_node->data.to_target;
48 content_to_target.Translate(layer->offset_to_transform_parent().x(),
49 layer->offset_to_transform_parent().y());
51 gfx::Rect combined_clip_rect_in_target_space;
52 gfx::Rect clip_rect_in_target_space;
53 gfx::Transform clip_to_target;
54 bool success = true;
55 if (clip_transform_node->data.target_id == target_node->id) {
56 clip_to_target = clip_transform_node->data.to_target;
57 } else {
58 success = transform_tree.ComputeTransformWithDestinationSublayerScale(
59 clip_transform_node->id, target_node->id, &clip_to_target);
61 if (target_node->id > clip_node->data.transform_id) {
62 if (!success) {
63 DCHECK(target_node->data.to_screen_is_animated);
65 // An animated singular transform may become non-singular during the
66 // animation, so we still need to compute a visible rect. In this
67 // situation, we treat the entire layer as visible.
68 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
69 layer->set_clip_rect_in_target_space_from_property_trees(
70 gfx::ToEnclosingRect(clip_node->data.combined_clip));
71 continue;
74 combined_clip_rect_in_target_space =
75 gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
76 clip_to_target, clip_node->data.combined_clip));
77 clip_rect_in_target_space = gfx::ToEnclosingRect(
78 MathUtil::ProjectClippedRect(clip_to_target, clip_node->data.clip));
79 } else {
80 // Computing a transform to an ancestor should always succeed.
81 DCHECK(success);
82 combined_clip_rect_in_target_space =
83 gfx::ToEnclosingRect(MathUtil::MapClippedRect(
84 clip_to_target, clip_node->data.combined_clip));
85 clip_rect_in_target_space = gfx::ToEnclosingRect(
86 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip));
89 gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
90 gfx::Rect layer_content_bounds_in_target_space =
91 MathUtil::MapEnclosingClippedRect(content_to_target,
92 layer_content_rect);
93 combined_clip_rect_in_target_space.Intersect(
94 layer_content_bounds_in_target_space);
95 clip_rect_in_target_space.Intersect(layer_content_bounds_in_target_space);
96 if (clip_node->data.requires_tight_clip_rect) {
97 layer->set_clip_rect_in_target_space_from_property_trees(
98 combined_clip_rect_in_target_space);
99 } else {
100 layer->set_clip_rect_in_target_space_from_property_trees(
101 clip_rect_in_target_space);
103 if (combined_clip_rect_in_target_space.IsEmpty()) {
104 layer->set_visible_rect_from_property_trees(gfx::Rect());
105 continue;
108 // If the layer is fully contained within the clip, treat it as fully
109 // visible. Since clip_rect_in_target_space has already been intersected
110 // with layer_content_bounds_in_target_space, the layer is fully contained
111 // within the clip iff these rects are equal.
112 if (combined_clip_rect_in_target_space ==
113 layer_content_bounds_in_target_space) {
114 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
115 continue;
118 gfx::Transform target_to_content;
119 gfx::Transform target_to_layer;
121 if (transform_node->data.ancestors_are_invertible) {
122 target_to_layer = transform_node->data.from_target;
123 success = true;
124 } else {
125 success = transform_tree.ComputeTransformWithSourceSublayerScale(
126 target_node->id, transform_node->id, &target_to_layer);
129 if (!success) {
130 // An animated singular transform may become non-singular during the
131 // animation, so we still need to compute a visible rect. In this
132 // situation, we treat the entire layer as visible.
133 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
134 continue;
137 target_to_content.Translate(-layer->offset_to_transform_parent().x(),
138 -layer->offset_to_transform_parent().y());
139 target_to_content.PreconcatTransform(target_to_layer);
141 gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
142 target_to_content, combined_clip_rect_in_target_space);
144 visible_rect.Intersect(gfx::Rect(layer_bounds));
146 layer->set_visible_rect_from_property_trees(visible_rect);
147 } else {
148 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
149 layer->set_clip_rect_in_target_space_from_property_trees(
150 gfx::Rect(layer_bounds));
155 template <typename LayerType>
156 static bool IsRootLayerOfNewRenderingContext(LayerType* layer) {
157 if (layer->parent())
158 return !layer->parent()->Is3dSorted() && layer->Is3dSorted();
159 return layer->Is3dSorted();
162 template <typename LayerType>
163 static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
164 return layer->Is3dSorted() && layer->parent() &&
165 layer->parent()->Is3dSorted() &&
166 layer->parent()->sorting_context_id() == layer->sorting_context_id();
169 template <typename LayerType>
170 static bool TransformToScreenIsKnown(LayerType* layer,
171 const TransformTree& tree) {
172 const TransformNode* node = tree.Node(layer->transform_tree_index());
173 return !node->data.to_screen_is_animated;
176 template <typename LayerType>
177 static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
178 const TransformNode* node = tree.Node(layer->transform_tree_index());
179 return !node->data.is_invertible || !node->data.ancestors_are_invertible;
182 template <typename LayerType>
183 static bool IsLayerBackFaceVisible(LayerType* layer,
184 const TransformTree& tree) {
185 // The current W3C spec on CSS transforms says that backface visibility should
186 // be determined differently depending on whether the layer is in a "3d
187 // rendering context" or not. For Chromium code, we can determine whether we
188 // are in a 3d rendering context by checking if the parent preserves 3d.
190 if (LayerIsInExisting3DRenderingContext(layer))
191 return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
193 // In this case, either the layer establishes a new 3d rendering context, or
194 // is not in a 3d rendering context at all.
195 return layer->transform().IsBackFaceVisible();
198 template <typename LayerType>
199 static bool IsSurfaceBackFaceVisible(LayerType* layer,
200 const TransformTree& tree) {
201 if (LayerIsInExisting3DRenderingContext(layer)) {
202 const TransformNode* node = tree.Node(layer->transform_tree_index());
203 // Draw transform as a contributing render surface.
204 // TODO(enne): we shouldn't walk the tree during a tree walk.
205 gfx::Transform surface_draw_transform;
206 tree.ComputeTransform(node->id, node->data.target_id,
207 &surface_draw_transform);
208 return surface_draw_transform.IsBackFaceVisible();
211 if (IsRootLayerOfNewRenderingContext(layer))
212 return layer->transform().IsBackFaceVisible();
214 // If the render_surface is not part of a new or existing rendering context,
215 // then the layers that contribute to this surface will decide back-face
216 // visibility for themselves.
217 return false;
220 template <typename LayerType>
221 static bool IsAnimatingTransformToScreen(LayerType* layer,
222 const TransformTree& tree) {
223 const TransformNode* node = tree.Node(layer->transform_tree_index());
224 return node->data.to_screen_is_animated;
227 static inline bool TransformToScreenIsKnown(Layer* layer,
228 const TransformTree& tree) {
229 return !IsAnimatingTransformToScreen(layer, tree);
232 static inline bool TransformToScreenIsKnown(LayerImpl* layer,
233 const TransformTree& tree) {
234 return true;
237 template <typename LayerType>
238 static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
239 return layer->transform_is_invertible() ||
240 layer->HasPotentiallyRunningTransformAnimation();
243 static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
244 bool layer_is_drawn,
245 const TransformTree& tree) {
246 // If the layer transform is not invertible, it should not be drawn.
247 // TODO(ajuma): Correctly process subtrees with singular transform for the
248 // case where we may animate to a non-singular transform and wish to
249 // pre-raster.
250 if (!HasInvertibleOrAnimatedTransform(layer))
251 return true;
253 // When we need to do a readback/copy of a layer's output, we can not skip
254 // it or any of its ancestors.
255 if (layer->draw_properties().layer_or_descendant_has_copy_request)
256 return false;
258 // We cannot skip the the subtree if a descendant has a wheel or touch handler
259 // or the hit testing code will break (it requires fresh transforms, etc).
260 if (layer->draw_properties().layer_or_descendant_has_input_handler)
261 return false;
263 // If the layer is not drawn, then skip it and its subtree.
264 if (!layer_is_drawn)
265 return true;
267 if (layer->render_surface() && !layer->double_sided() &&
268 IsSurfaceBackFaceVisible(layer, tree))
269 return true;
271 // If layer is on the pending tree and opacity is being animated then
272 // this subtree can't be skipped as we need to create, prioritize and
273 // include tiles for this layer when deciding if tree can be activated.
274 if (layer->layer_tree_impl()->IsPendingTree() &&
275 layer->HasPotentiallyRunningOpacityAnimation())
276 return false;
278 // The opacity of a layer always applies to its children (either implicitly
279 // via a render surface or explicitly if the parent preserves 3D), so the
280 // entire subtree can be skipped if this layer is fully transparent.
281 return !layer->opacity();
284 static inline bool SubtreeShouldBeSkipped(Layer* layer,
285 bool layer_is_drawn,
286 const TransformTree& tree) {
287 // If the layer transform is not invertible, it should not be drawn.
288 if (!layer->transform_is_invertible() &&
289 !layer->HasPotentiallyRunningTransformAnimation())
290 return true;
292 // When we need to do a readback/copy of a layer's output, we can not skip
293 // it or any of its ancestors.
294 if (layer->draw_properties().layer_or_descendant_has_copy_request)
295 return false;
297 // We cannot skip the the subtree if a descendant has a wheel or touch handler
298 // or the hit testing code will break (it requires fresh transforms, etc).
299 if (layer->draw_properties().layer_or_descendant_has_input_handler)
300 return false;
302 // If the layer is not drawn, then skip it and its subtree.
303 if (!layer_is_drawn)
304 return true;
306 if (layer->render_surface() && !layer->double_sided() &&
307 !layer->HasPotentiallyRunningTransformAnimation() &&
308 IsSurfaceBackFaceVisible(layer, tree))
309 return true;
311 // If the opacity is being animated then the opacity on the main thread is
312 // unreliable (since the impl thread may be using a different opacity), so it
313 // should not be trusted.
314 // In particular, it should not cause the subtree to be skipped.
315 // Similarly, for layers that might animate opacity using an impl-only
316 // animation, their subtree should also not be skipped.
317 return !layer->opacity() && !layer->HasPotentiallyRunningOpacityAnimation() &&
318 !layer->OpacityCanAnimateOnImplThread();
321 template <typename LayerType>
322 static bool LayerShouldBeSkipped(LayerType* layer,
323 bool layer_is_drawn,
324 const TransformTree& tree) {
325 // Layers can be skipped if any of these conditions are met.
326 // - is not drawn due to it or one of its ancestors being hidden (or having
327 // no copy requests).
328 // - does not draw content.
329 // - is transparent.
330 // - has empty bounds
331 // - the layer is not double-sided, but its back face is visible.
333 // Some additional conditions need to be computed at a later point after the
334 // recursion is finished.
335 // - the intersection of render_surface content and layer clip_rect is empty
336 // - the visible_layer_rect is empty
338 // Note, if the layer should not have been drawn due to being fully
339 // transparent, we would have skipped the entire subtree and never made it
340 // into this function, so it is safe to omit this check here.
341 if (!layer_is_drawn)
342 return true;
344 if (!layer->DrawsContent() || layer->bounds().IsEmpty())
345 return true;
347 LayerType* backface_test_layer = layer;
348 if (layer->use_parent_backface_visibility()) {
349 DCHECK(layer->parent());
350 DCHECK(!layer->parent()->use_parent_backface_visibility());
351 backface_test_layer = layer->parent();
354 // The layer should not be drawn if (1) it is not double-sided and (2) the
355 // back of the layer is known to be facing the screen.
356 if (!backface_test_layer->double_sided() &&
357 TransformToScreenIsKnown(backface_test_layer, tree) &&
358 IsLayerBackFaceVisible(backface_test_layer, tree))
359 return true;
361 return false;
364 template <typename LayerType>
365 void FindLayersThatNeedUpdates(
366 LayerType* layer,
367 const TransformTree& tree,
368 bool subtree_is_visible_from_ancestor,
369 typename LayerType::LayerListType* update_layer_list,
370 std::vector<LayerType*>* visible_layer_list) {
371 bool layer_is_drawn =
372 layer->HasCopyRequest() ||
373 (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree());
375 if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn, tree))
376 return;
378 if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) {
379 visible_layer_list->push_back(layer);
380 update_layer_list->push_back(layer);
383 // Append mask layers to the update layer list. They don't have valid visible
384 // rects, so need to get added after the above calculation. Replica layers
385 // don't need to be updated.
386 if (LayerType* mask_layer = layer->mask_layer())
387 update_layer_list->push_back(mask_layer);
388 if (LayerType* replica_layer = layer->replica_layer()) {
389 if (LayerType* mask_layer = replica_layer->mask_layer())
390 update_layer_list->push_back(mask_layer);
393 for (size_t i = 0; i < layer->children().size(); ++i) {
394 FindLayersThatNeedUpdates(layer->child_at(i), tree, layer_is_drawn,
395 update_layer_list, visible_layer_list);
399 } // namespace
401 void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) {
402 if (!clip_tree->needs_update())
403 return;
404 for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) {
405 ClipNode* clip_node = clip_tree->Node(i);
407 // Only descendants of a real clipping layer (i.e., not 0) may have their
408 // clip adjusted due to intersecting with an ancestor clip.
409 const bool is_clipped = clip_node->parent_id > 0;
410 if (!is_clipped) {
411 DCHECK(!clip_node->data.inherit_parent_target_space_clip);
412 clip_node->data.combined_clip = clip_node->data.clip;
413 continue;
416 ClipNode* parent_clip_node = clip_tree->parent(clip_node);
417 const TransformNode* parent_transform_node =
418 transform_tree.Node(parent_clip_node->data.transform_id);
419 const TransformNode* transform_node =
420 transform_tree.Node(clip_node->data.transform_id);
422 // Clips must be combined in target space. We cannot, for example, combine
423 // clips in the space of the child clip. The reason is non-affine
424 // transforms. Say we have the following tree T->A->B->C, and B clips C, but
425 // draw into target T. It may be the case that A applies a perspective
426 // transform, and B and C are at different z positions. When projected into
427 // target space, the relative sizes and positions of B and C can shift.
428 // Since it's the relationship in target space that matters, that's where we
429 // must combine clips.
430 gfx::Transform parent_to_target;
431 gfx::Transform clip_to_target;
432 gfx::Transform target_to_clip;
433 gfx::Transform parent_to_transform_target;
434 gfx::Transform transform_target_to_target;
436 const bool target_is_root_surface = clip_node->data.target_id == 1;
437 // When the target is the root surface, we need to include the root
438 // transform by walking up to the root of the transform tree.
439 const int target_id =
440 target_is_root_surface ? 0 : clip_node->data.target_id;
442 bool success = true;
443 // When render surface applies clip, we need the clip from the target's
444 // target space. But, as the combined clip is in parent clip's target
445 // space, we need to first transform it from parent's target space to
446 // target's target space.
447 if (clip_node->data.inherit_parent_target_space_clip) {
448 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
449 parent_transform_node->id, transform_node->data.target_id,
450 &parent_to_transform_target);
451 success &= transform_tree.ComputeTransformWithSourceSublayerScale(
452 transform_node->data.target_id, target_id,
453 &transform_target_to_target);
454 transform_target_to_target.matrix().postScale(
455 transform_node->data.sublayer_scale.x(),
456 transform_node->data.sublayer_scale.y(), 1.0);
457 } else if (parent_transform_node->data.content_target_id ==
458 clip_node->data.target_id) {
459 parent_to_target = parent_transform_node->data.to_target;
460 } else {
461 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
462 parent_transform_node->id, target_id, &parent_to_target);
465 if (transform_node->data.content_target_id == clip_node->data.target_id) {
466 clip_to_target = transform_node->data.to_target;
467 } else {
468 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
469 transform_node->id, target_id, &clip_to_target);
472 if (transform_node->data.content_target_id == clip_node->data.target_id &&
473 transform_node->data.ancestors_are_invertible) {
474 target_to_clip = transform_node->data.from_target;
475 } else {
476 success &= clip_to_target.GetInverse(&target_to_clip);
479 // If we can't compute a transform, it's because we had to use the inverse
480 // of a singular transform. We won't draw in this case, so there's no need
481 // to compute clips.
482 if (!success) {
483 continue;
486 // In order to intersect with as small a rect as possible, we do a
487 // preliminary clip in target space so that when we project back, there's
488 // less likelihood of intersecting the view plane.
489 gfx::RectF inherited_clip_in_target_space;
490 if (clip_node->data.inherit_parent_target_space_clip) {
491 gfx::RectF combined_clip_in_transform_target_space;
492 if (parent_transform_node->id > transform_node->data.target_id)
493 combined_clip_in_transform_target_space = MathUtil::MapClippedRect(
494 parent_to_transform_target, parent_clip_node->data.combined_clip);
495 else
496 combined_clip_in_transform_target_space = MathUtil::ProjectClippedRect(
497 parent_to_transform_target, parent_clip_node->data.combined_clip);
498 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
499 transform_target_to_target, combined_clip_in_transform_target_space);
500 } else if (parent_transform_node->id > target_id) {
501 inherited_clip_in_target_space = MathUtil::MapClippedRect(
502 parent_to_target, parent_clip_node->data.combined_clip);
503 } else {
504 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
505 parent_to_target, parent_clip_node->data.combined_clip);
508 // When render surface inherits its parent target space clip, the layer
509 // that created the clip node doesn't apply any clip. So, we shouldn't clip
510 // using the clip value stored in the clip node.
511 gfx::RectF intersected_in_target_space;
512 if (!clip_node->data.inherit_parent_target_space_clip) {
513 gfx::RectF clip_in_target_space =
514 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip);
516 intersected_in_target_space = gfx::IntersectRects(
517 inherited_clip_in_target_space, clip_in_target_space);
518 } else {
519 intersected_in_target_space = inherited_clip_in_target_space;
522 clip_node->data.combined_clip = MathUtil::ProjectClippedRect(
523 target_to_clip, intersected_in_target_space);
525 if (!clip_node->data.inherit_parent_target_space_clip)
526 clip_node->data.combined_clip.Intersect(clip_node->data.clip);
528 clip_tree->set_needs_update(false);
531 void ComputeTransforms(TransformTree* transform_tree) {
532 if (!transform_tree->needs_update())
533 return;
534 for (int i = 1; i < static_cast<int>(transform_tree->size()); ++i)
535 transform_tree->UpdateTransforms(i);
536 transform_tree->set_needs_update(false);
539 void ComputeOpacities(OpacityTree* opacity_tree) {
540 if (!opacity_tree->needs_update())
541 return;
542 for (int i = 1; i < static_cast<int>(opacity_tree->size()); ++i)
543 opacity_tree->UpdateOpacities(i);
544 opacity_tree->set_needs_update(false);
547 template <typename LayerType>
548 void ComputeVisibleRectsUsingPropertyTreesInternal(
549 LayerType* root_layer,
550 PropertyTrees* property_trees,
551 typename LayerType::LayerListType* update_layer_list) {
552 if (property_trees->transform_tree.needs_update())
553 property_trees->clip_tree.set_needs_update(true);
554 ComputeTransforms(&property_trees->transform_tree);
555 ComputeClips(&property_trees->clip_tree, property_trees->transform_tree);
556 ComputeOpacities(&property_trees->opacity_tree);
558 const bool subtree_is_visible_from_ancestor = true;
559 std::vector<LayerType*> visible_layer_list;
560 FindLayersThatNeedUpdates(root_layer, property_trees->transform_tree,
561 subtree_is_visible_from_ancestor, update_layer_list,
562 &visible_layer_list);
563 CalculateVisibleRects<LayerType>(visible_layer_list,
564 property_trees->clip_tree,
565 property_trees->transform_tree);
568 void BuildPropertyTreesAndComputeVisibleRects(
569 Layer* root_layer,
570 const Layer* page_scale_layer,
571 const Layer* inner_viewport_scroll_layer,
572 const Layer* outer_viewport_scroll_layer,
573 float page_scale_factor,
574 float device_scale_factor,
575 const gfx::Rect& viewport,
576 const gfx::Transform& device_transform,
577 PropertyTrees* property_trees,
578 LayerList* update_layer_list) {
579 PropertyTreeBuilder::BuildPropertyTrees(
580 root_layer, page_scale_layer, inner_viewport_scroll_layer,
581 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
582 viewport, device_transform, property_trees);
583 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
584 update_layer_list);
587 void BuildPropertyTreesAndComputeVisibleRects(
588 LayerImpl* root_layer,
589 const LayerImpl* page_scale_layer,
590 const LayerImpl* inner_viewport_scroll_layer,
591 const LayerImpl* outer_viewport_scroll_layer,
592 float page_scale_factor,
593 float device_scale_factor,
594 const gfx::Rect& viewport,
595 const gfx::Transform& device_transform,
596 PropertyTrees* property_trees,
597 LayerImplList* update_layer_list) {
598 PropertyTreeBuilder::BuildPropertyTrees(
599 root_layer, page_scale_layer, inner_viewport_scroll_layer,
600 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
601 viewport, device_transform, property_trees);
602 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
603 update_layer_list);
606 void ComputeVisibleRectsUsingPropertyTrees(Layer* root_layer,
607 PropertyTrees* property_trees,
608 LayerList* update_layer_list) {
609 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
610 update_layer_list);
613 void ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer,
614 PropertyTrees* property_trees,
615 LayerImplList* update_layer_list) {
616 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
617 update_layer_list);
620 template <typename LayerType>
621 gfx::Transform DrawTransformFromPropertyTreesInternal(
622 const LayerType* layer,
623 const TransformTree& tree) {
624 const TransformNode* node = tree.Node(layer->transform_tree_index());
626 gfx::Transform xform;
627 const bool owns_non_root_surface = layer->parent() && layer->render_surface();
628 if (!owns_non_root_surface) {
629 // If you're not the root, or you don't own a surface, you need to apply
630 // your local offset.
631 xform = node->data.to_target;
632 if (layer->should_flatten_transform_from_property_tree())
633 xform.FlattenTo2d();
634 xform.Translate(layer->offset_to_transform_parent().x(),
635 layer->offset_to_transform_parent().y());
636 } else {
637 // Surfaces need to apply their sublayer scale.
638 xform.Scale(node->data.sublayer_scale.x(), node->data.sublayer_scale.y());
640 return xform;
643 gfx::Transform DrawTransformFromPropertyTrees(const Layer* layer,
644 const TransformTree& tree) {
645 return DrawTransformFromPropertyTreesInternal(layer, tree);
648 gfx::Transform DrawTransformFromPropertyTrees(const LayerImpl* layer,
649 const TransformTree& tree) {
650 return DrawTransformFromPropertyTreesInternal(layer, tree);
653 gfx::Transform DrawTransformOfRenderSurfaceFromPropertyTrees(
654 const RenderSurfaceImpl* render_surface,
655 const TransformTree& tree) {
656 const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
657 gfx::Transform render_surface_transform;
658 // The draw transform of root render surface is identity tranform.
659 if (node->id == 1)
660 return render_surface_transform;
661 const TransformNode* target_node = tree.Node(node->data.target_id);
662 if (target_node->id == 1)
663 target_node = tree.Node(0);
664 tree.ComputeTransformWithDestinationSublayerScale(node->id, target_node->id,
665 &render_surface_transform);
666 render_surface_transform.Scale(1.0 / node->data.sublayer_scale.x(),
667 1.0 / node->data.sublayer_scale.y());
668 return render_surface_transform;
671 template <typename LayerType>
672 gfx::Transform ScreenSpaceTransformFromPropertyTreesInternal(
673 LayerType* layer,
674 const TransformTree& tree) {
675 gfx::Transform xform(1, 0, 0, 1, layer->offset_to_transform_parent().x(),
676 layer->offset_to_transform_parent().y());
677 if (layer->transform_tree_index() >= 0) {
678 gfx::Transform ssxform =
679 tree.Node(layer->transform_tree_index())->data.to_screen;
680 xform.ConcatTransform(ssxform);
681 if (layer->should_flatten_transform_from_property_tree())
682 xform.FlattenTo2d();
684 return xform;
687 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
688 const Layer* layer,
689 const TransformTree& tree) {
690 return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
693 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
694 const LayerImpl* layer,
695 const TransformTree& tree) {
696 return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
699 template <typename LayerType>
700 bool ScreenSpaceTransformIsAnimatingFromPropertyTreesInternal(
701 LayerType* layer,
702 const TransformTree& tree) {
703 return tree.Node(layer->transform_tree_index())->data.to_screen_is_animated;
706 bool ScreenSpaceTransformIsAnimatingFromPropertyTrees(
707 const Layer* layer,
708 const TransformTree& tree) {
709 return ScreenSpaceTransformIsAnimatingFromPropertyTreesInternal(layer, tree);
712 bool ScreenSpaceTransformIsAnimatingFromPropertyTrees(
713 const LayerImpl* layer,
714 const TransformTree& tree) {
715 return ScreenSpaceTransformIsAnimatingFromPropertyTreesInternal(layer, tree);
718 template <typename LayerType>
719 float DrawOpacityFromPropertyTreesInternal(LayerType layer,
720 const OpacityTree& tree) {
721 if (!layer->render_target())
722 return 0.f;
724 const OpacityNode* target_node =
725 tree.Node(layer->render_target()->opacity_tree_index());
726 const OpacityNode* node = tree.Node(layer->opacity_tree_index());
727 if (node == target_node)
728 return 1.f;
730 float draw_opacity = 1.f;
731 while (node != target_node) {
732 draw_opacity *= node->data.opacity;
733 node = tree.parent(node);
735 return draw_opacity;
738 float DrawOpacityFromPropertyTrees(const Layer* layer,
739 const OpacityTree& tree) {
740 return DrawOpacityFromPropertyTreesInternal(layer, tree);
743 float DrawOpacityFromPropertyTrees(const LayerImpl* layer,
744 const OpacityTree& tree) {
745 return DrawOpacityFromPropertyTreesInternal(layer, tree);
748 bool CanUseLcdTextFromPropertyTrees(const LayerImpl* layer,
749 bool layers_always_allowed_lcd_text,
750 bool can_use_lcd_text,
751 PropertyTrees* property_trees) {
752 if (layers_always_allowed_lcd_text)
753 return true;
754 if (!can_use_lcd_text)
755 return false;
756 if (!layer->contents_opaque())
757 return false;
758 DCHECK(!property_trees->transform_tree.needs_update());
759 DCHECK(!property_trees->opacity_tree.needs_update());
761 const OpacityNode* opacity_node =
762 property_trees->opacity_tree.Node(layer->opacity_tree_index());
763 if (opacity_node->data.screen_space_opacity != 1.f)
764 return false;
765 const TransformNode* transform_node =
766 property_trees->transform_tree.Node(layer->transform_tree_index());
767 if (!transform_node->data.node_and_ancestors_have_only_integer_translation)
768 return false;
769 if (static_cast<int>(layer->offset_to_transform_parent().x()) !=
770 layer->offset_to_transform_parent().x())
771 return false;
772 if (static_cast<int>(layer->offset_to_transform_parent().y()) !=
773 layer->offset_to_transform_parent().y())
774 return false;
775 return true;
778 gfx::Rect DrawableContentRectFromPropertyTrees(
779 const LayerImpl* layer,
780 const TransformTree& transform_tree) {
781 gfx::Rect drawable_content_rect = MathUtil::MapEnclosingClippedRect(
782 DrawTransformFromPropertyTrees(layer, transform_tree),
783 gfx::Rect(layer->bounds()));
784 if (layer->is_clipped() && layer->clip_tree_index() > 0) {
785 drawable_content_rect.Intersect(
786 layer->clip_rect_in_target_space_from_property_trees());
788 return drawable_content_rect;
791 } // namespace cc