Mark NavigateTest@testNavigateMany() as flaky
[chromium-blink-merge.git] / cc / trees / draw_property_utils.cc
blob5a8517b2878a9da09a2ff33244b3ed276dfe6a16
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 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);
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 continue;
72 clip_rect_in_target_space =
73 gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
74 clip_to_target, clip_node->data.combined_clip));
75 } else {
76 // Computing a transform to an ancestor should always succeed.
77 DCHECK(success);
78 clip_rect_in_target_space =
79 gfx::ToEnclosingRect(MathUtil::MapClippedRect(
80 clip_to_target, clip_node->data.combined_clip));
83 gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
84 gfx::Rect layer_content_bounds_in_target_space =
85 MathUtil::MapEnclosingClippedRect(content_to_target,
86 layer_content_rect);
87 clip_rect_in_target_space.Intersect(layer_content_bounds_in_target_space);
88 if (clip_rect_in_target_space.IsEmpty()) {
89 layer->set_visible_rect_from_property_trees(gfx::Rect());
90 continue;
93 // If the layer is fully contained within the clip, treat it as fully
94 // visible. Since clip_rect_in_target_space has already been intersected
95 // with layer_content_bounds_in_target_space, the layer is fully contained
96 // within the clip iff these rects are equal.
97 if (clip_rect_in_target_space == layer_content_bounds_in_target_space) {
98 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
99 continue;
102 gfx::Transform target_to_content;
103 gfx::Transform target_to_layer;
105 if (transform_node->data.ancestors_are_invertible) {
106 target_to_layer = transform_node->data.from_target;
107 success = true;
108 } else {
109 success = transform_tree.ComputeTransformWithSourceSublayerScale(
110 target_node->id, transform_node->id, &target_to_layer);
113 if (!success) {
114 DCHECK(transform_node->data.to_screen_is_animated);
116 // An animated singular transform may become non-singular during the
117 // animation, so we still need to compute a visible rect. In this
118 // situation, we treat the entire layer as visible.
119 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
120 continue;
123 target_to_content.Translate(-layer->offset_to_transform_parent().x(),
124 -layer->offset_to_transform_parent().y());
125 target_to_content.PreconcatTransform(target_to_layer);
127 gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
128 target_to_content, clip_rect_in_target_space);
130 visible_rect.Intersect(gfx::Rect(layer_bounds));
132 layer->set_visible_rect_from_property_trees(visible_rect);
133 } else {
134 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
139 template <typename LayerType>
140 static bool IsRootLayerOfNewRenderingContext(LayerType* layer) {
141 if (layer->parent())
142 return !layer->parent()->Is3dSorted() && layer->Is3dSorted();
143 return layer->Is3dSorted();
146 template <typename LayerType>
147 static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
148 return layer->Is3dSorted() && layer->parent() &&
149 layer->parent()->Is3dSorted() &&
150 layer->parent()->sorting_context_id() == layer->sorting_context_id();
153 template <typename LayerType>
154 static bool TransformToScreenIsKnown(LayerType* layer,
155 const TransformTree& tree) {
156 const TransformNode* node = tree.Node(layer->transform_tree_index());
157 return !node->data.to_screen_is_animated;
160 template <typename LayerType>
161 static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
162 const TransformNode* node = tree.Node(layer->transform_tree_index());
163 return !node->data.is_invertible || !node->data.ancestors_are_invertible;
166 template <typename LayerType>
167 static bool IsLayerBackFaceVisible(LayerType* layer,
168 const TransformTree& tree) {
169 // The current W3C spec on CSS transforms says that backface visibility should
170 // be determined differently depending on whether the layer is in a "3d
171 // rendering context" or not. For Chromium code, we can determine whether we
172 // are in a 3d rendering context by checking if the parent preserves 3d.
174 if (LayerIsInExisting3DRenderingContext(layer))
175 return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
177 // In this case, either the layer establishes a new 3d rendering context, or
178 // is not in a 3d rendering context at all.
179 return layer->transform().IsBackFaceVisible();
182 template <typename LayerType>
183 static bool IsSurfaceBackFaceVisible(LayerType* layer,
184 const TransformTree& tree) {
185 if (LayerIsInExisting3DRenderingContext(layer)) {
186 const TransformNode* node = tree.Node(layer->transform_tree_index());
187 // Draw transform as a contributing render surface.
188 // TODO(enne): we shouldn't walk the tree during a tree walk.
189 gfx::Transform surface_draw_transform;
190 tree.ComputeTransform(node->id, node->data.target_id,
191 &surface_draw_transform);
192 return surface_draw_transform.IsBackFaceVisible();
195 if (IsRootLayerOfNewRenderingContext(layer))
196 return layer->transform().IsBackFaceVisible();
198 // If the render_surface is not part of a new or existing rendering context,
199 // then the layers that contribute to this surface will decide back-face
200 // visibility for themselves.
201 return false;
204 template <typename LayerType>
205 static bool IsAnimatingTransformToScreen(LayerType* layer,
206 const TransformTree& tree) {
207 const TransformNode* node = tree.Node(layer->transform_tree_index());
208 return node->data.to_screen_is_animated;
211 static inline bool TransformToScreenIsKnown(Layer* layer,
212 const TransformTree& tree) {
213 return !IsAnimatingTransformToScreen(layer, tree);
216 static inline bool TransformToScreenIsKnown(LayerImpl* layer,
217 const TransformTree& tree) {
218 return true;
221 template <typename LayerType>
222 static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
223 return layer->transform_is_invertible() ||
224 layer->HasPotentiallyRunningTransformAnimation();
227 static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
228 bool layer_is_drawn,
229 const TransformTree& tree) {
230 // If the layer transform is not invertible, it should not be drawn.
231 // TODO(ajuma): Correctly process subtrees with singular transform for the
232 // case where we may animate to a non-singular transform and wish to
233 // pre-raster.
234 if (!HasInvertibleOrAnimatedTransform(layer))
235 return true;
237 // When we need to do a readback/copy of a layer's output, we can not skip
238 // it or any of its ancestors.
239 if (layer->draw_properties().layer_or_descendant_has_copy_request)
240 return false;
242 // We cannot skip the the subtree if a descendant has a wheel or touch handler
243 // or the hit testing code will break (it requires fresh transforms, etc).
244 if (layer->draw_properties().layer_or_descendant_has_input_handler)
245 return false;
247 // If the layer is not drawn, then skip it and its subtree.
248 if (!layer_is_drawn)
249 return true;
251 if (layer->render_surface() && !layer->double_sided() &&
252 IsSurfaceBackFaceVisible(layer, tree))
253 return true;
255 // If layer is on the pending tree and opacity is being animated then
256 // this subtree can't be skipped as we need to create, prioritize and
257 // include tiles for this layer when deciding if tree can be activated.
258 if (layer->layer_tree_impl()->IsPendingTree() &&
259 layer->HasPotentiallyRunningOpacityAnimation())
260 return false;
262 // The opacity of a layer always applies to its children (either implicitly
263 // via a render surface or explicitly if the parent preserves 3D), so the
264 // entire subtree can be skipped if this layer is fully transparent.
265 return !layer->opacity();
268 static inline bool SubtreeShouldBeSkipped(Layer* layer,
269 bool layer_is_drawn,
270 const TransformTree& tree) {
271 // If the layer transform is not invertible, it should not be drawn.
272 if (!layer->transform_is_invertible() &&
273 !layer->HasPotentiallyRunningTransformAnimation())
274 return true;
276 // When we need to do a readback/copy of a layer's output, we can not skip
277 // it or any of its ancestors.
278 if (layer->draw_properties().layer_or_descendant_has_copy_request)
279 return false;
281 // We cannot skip the the subtree if a descendant has a wheel or touch handler
282 // or the hit testing code will break (it requires fresh transforms, etc).
283 if (layer->draw_properties().layer_or_descendant_has_input_handler)
284 return false;
286 // If the layer is not drawn, then skip it and its subtree.
287 if (!layer_is_drawn)
288 return true;
290 if (layer->render_surface() && !layer->double_sided() &&
291 !layer->HasPotentiallyRunningTransformAnimation() &&
292 IsSurfaceBackFaceVisible(layer, tree))
293 return true;
295 // If the opacity is being animated then the opacity on the main thread is
296 // unreliable (since the impl thread may be using a different opacity), so it
297 // should not be trusted.
298 // In particular, it should not cause the subtree to be skipped.
299 // Similarly, for layers that might animate opacity using an impl-only
300 // animation, their subtree should also not be skipped.
301 return !layer->opacity() && !layer->HasPotentiallyRunningOpacityAnimation() &&
302 !layer->OpacityCanAnimateOnImplThread();
305 template <typename LayerType>
306 static bool LayerShouldBeSkipped(LayerType* layer,
307 bool layer_is_drawn,
308 const TransformTree& tree) {
309 // Layers can be skipped if any of these conditions are met.
310 // - is not drawn due to it or one of its ancestors being hidden (or having
311 // no copy requests).
312 // - does not draw content.
313 // - is transparent.
314 // - has empty bounds
315 // - the layer is not double-sided, but its back face is visible.
317 // Some additional conditions need to be computed at a later point after the
318 // recursion is finished.
319 // - the intersection of render_surface content and layer clip_rect is empty
320 // - the visible_layer_rect is empty
322 // Note, if the layer should not have been drawn due to being fully
323 // transparent, we would have skipped the entire subtree and never made it
324 // into this function, so it is safe to omit this check here.
325 if (!layer_is_drawn)
326 return true;
328 if (!layer->DrawsContent() || layer->bounds().IsEmpty())
329 return true;
331 LayerType* backface_test_layer = layer;
332 if (layer->use_parent_backface_visibility()) {
333 DCHECK(layer->parent());
334 DCHECK(!layer->parent()->use_parent_backface_visibility());
335 backface_test_layer = layer->parent();
338 // The layer should not be drawn if (1) it is not double-sided and (2) the
339 // back of the layer is known to be facing the screen.
340 if (!backface_test_layer->double_sided() &&
341 TransformToScreenIsKnown(backface_test_layer, tree) &&
342 IsLayerBackFaceVisible(backface_test_layer, tree))
343 return true;
345 return false;
348 template <typename LayerType>
349 void FindLayersThatNeedUpdates(
350 LayerType* layer,
351 const TransformTree& tree,
352 bool subtree_is_visible_from_ancestor,
353 typename LayerType::LayerListType* update_layer_list,
354 std::vector<LayerType*>* visible_layer_list) {
355 bool layer_is_drawn =
356 layer->HasCopyRequest() ||
357 (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree());
359 if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn, tree))
360 return;
362 if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) {
363 visible_layer_list->push_back(layer);
364 update_layer_list->push_back(layer);
367 // Append mask layers to the update layer list. They don't have valid visible
368 // rects, so need to get added after the above calculation. Replica layers
369 // don't need to be updated.
370 if (LayerType* mask_layer = layer->mask_layer())
371 update_layer_list->push_back(mask_layer);
372 if (LayerType* replica_layer = layer->replica_layer()) {
373 if (LayerType* mask_layer = replica_layer->mask_layer())
374 update_layer_list->push_back(mask_layer);
377 for (size_t i = 0; i < layer->children().size(); ++i) {
378 FindLayersThatNeedUpdates(layer->child_at(i), tree, layer_is_drawn,
379 update_layer_list, visible_layer_list);
383 } // namespace
385 void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) {
386 if (!clip_tree->needs_update())
387 return;
388 for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) {
389 ClipNode* clip_node = clip_tree->Node(i);
391 // Only descendants of a real clipping layer (i.e., not 0) may have their
392 // clip adjusted due to intersecting with an ancestor clip.
393 const bool is_clipped = clip_node->parent_id > 0;
394 if (!is_clipped) {
395 clip_node->data.combined_clip = clip_node->data.clip;
396 continue;
399 ClipNode* parent_clip_node = clip_tree->parent(clip_node);
400 const TransformNode* parent_transform_node =
401 transform_tree.Node(parent_clip_node->data.transform_id);
402 const TransformNode* transform_node =
403 transform_tree.Node(clip_node->data.transform_id);
405 // Clips must be combined in target space. We cannot, for example, combine
406 // clips in the space of the child clip. The reason is non-affine
407 // transforms. Say we have the following tree T->A->B->C, and B clips C, but
408 // draw into target T. It may be the case that A applies a perspective
409 // transform, and B and C are at different z positions. When projected into
410 // target space, the relative sizes and positions of B and C can shift.
411 // Since it's the relationship in target space that matters, that's where we
412 // must combine clips.
413 gfx::Transform parent_to_target;
414 gfx::Transform clip_to_target;
415 gfx::Transform target_to_clip;
417 const bool target_is_root_surface = clip_node->data.target_id == 1;
418 // When the target is the root surface, we need to include the root
419 // transform by walking up to the root of the transform tree.
420 const int target_id =
421 target_is_root_surface ? 0 : clip_node->data.target_id;
423 bool success = true;
424 if (parent_transform_node->data.content_target_id ==
425 clip_node->data.target_id) {
426 parent_to_target = parent_transform_node->data.to_target;
427 } else {
428 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
429 parent_transform_node->id, target_id, &parent_to_target);
432 if (transform_node->data.content_target_id == clip_node->data.target_id) {
433 clip_to_target = transform_node->data.to_target;
434 } else {
435 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
436 transform_node->id, target_id, &clip_to_target);
439 if (transform_node->data.content_target_id == clip_node->data.target_id &&
440 transform_node->data.ancestors_are_invertible) {
441 target_to_clip = transform_node->data.from_target;
442 } else {
443 success &= clip_to_target.GetInverse(&target_to_clip);
446 // If we can't compute a transform, it's because we had to use the inverse
447 // of a singular transform. We won't draw in this case, so there's no need
448 // to compute clips.
449 if (!success)
450 continue;
452 // In order to intersect with as small a rect as possible, we do a
453 // preliminary clip in target space so that when we project back, there's
454 // less likelihood of intersecting the view plane.
455 gfx::RectF inherited_clip_in_target_space = MathUtil::MapClippedRect(
456 parent_to_target, parent_clip_node->data.combined_clip);
458 gfx::RectF clip_in_target_space =
459 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip);
461 gfx::RectF intersected_in_target_space = gfx::IntersectRects(
462 inherited_clip_in_target_space, clip_in_target_space);
464 clip_node->data.combined_clip = MathUtil::ProjectClippedRect(
465 target_to_clip, intersected_in_target_space);
467 clip_node->data.combined_clip.Intersect(clip_node->data.clip);
469 clip_tree->set_needs_update(false);
472 void ComputeTransforms(TransformTree* transform_tree) {
473 if (!transform_tree->needs_update())
474 return;
475 for (int i = 1; i < static_cast<int>(transform_tree->size()); ++i)
476 transform_tree->UpdateTransforms(i);
477 transform_tree->set_needs_update(false);
480 void ComputeOpacities(OpacityTree* opacity_tree) {
481 if (!opacity_tree->needs_update())
482 return;
483 for (int i = 1; i < static_cast<int>(opacity_tree->size()); ++i)
484 opacity_tree->UpdateOpacities(i);
485 opacity_tree->set_needs_update(false);
488 template <typename LayerType>
489 void ComputeVisibleRectsUsingPropertyTreesInternal(
490 LayerType* root_layer,
491 PropertyTrees* property_trees,
492 typename LayerType::LayerListType* update_layer_list) {
493 if (property_trees->transform_tree.needs_update())
494 property_trees->clip_tree.set_needs_update(true);
495 ComputeTransforms(&property_trees->transform_tree);
496 ComputeClips(&property_trees->clip_tree, property_trees->transform_tree);
497 ComputeOpacities(&property_trees->opacity_tree);
499 const bool subtree_is_visible_from_ancestor = true;
500 std::vector<LayerType*> visible_layer_list;
501 FindLayersThatNeedUpdates(root_layer, property_trees->transform_tree,
502 subtree_is_visible_from_ancestor, update_layer_list,
503 &visible_layer_list);
504 CalculateVisibleRects<LayerType>(visible_layer_list,
505 property_trees->clip_tree,
506 property_trees->transform_tree);
509 void BuildPropertyTreesAndComputeVisibleRects(
510 Layer* root_layer,
511 const Layer* page_scale_layer,
512 const Layer* inner_viewport_scroll_layer,
513 const Layer* outer_viewport_scroll_layer,
514 float page_scale_factor,
515 float device_scale_factor,
516 const gfx::Rect& viewport,
517 const gfx::Transform& device_transform,
518 PropertyTrees* property_trees,
519 LayerList* update_layer_list) {
520 PropertyTreeBuilder::BuildPropertyTrees(
521 root_layer, page_scale_layer, inner_viewport_scroll_layer,
522 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
523 viewport, device_transform, property_trees);
524 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
525 update_layer_list);
528 void BuildPropertyTreesAndComputeVisibleRects(
529 LayerImpl* root_layer,
530 const LayerImpl* page_scale_layer,
531 const LayerImpl* inner_viewport_scroll_layer,
532 const LayerImpl* outer_viewport_scroll_layer,
533 float page_scale_factor,
534 float device_scale_factor,
535 const gfx::Rect& viewport,
536 const gfx::Transform& device_transform,
537 PropertyTrees* property_trees,
538 LayerImplList* update_layer_list) {
539 PropertyTreeBuilder::BuildPropertyTrees(
540 root_layer, page_scale_layer, inner_viewport_scroll_layer,
541 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
542 viewport, device_transform, property_trees);
543 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
544 update_layer_list);
547 void ComputeVisibleRectsUsingPropertyTrees(Layer* root_layer,
548 PropertyTrees* property_trees,
549 LayerList* update_layer_list) {
550 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
551 update_layer_list);
554 void ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer,
555 PropertyTrees* property_trees,
556 LayerImplList* update_layer_list) {
557 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
558 update_layer_list);
561 template <typename LayerType>
562 gfx::Transform DrawTransformFromPropertyTreesInternal(
563 const LayerType* layer,
564 const TransformTree& tree) {
565 const TransformNode* node = tree.Node(layer->transform_tree_index());
567 gfx::Transform xform;
568 const bool owns_non_root_surface = layer->parent() && layer->render_surface();
569 if (!owns_non_root_surface) {
570 // If you're not the root, or you don't own a surface, you need to apply
571 // your local offset.
572 xform = node->data.to_target;
573 if (layer->should_flatten_transform_from_property_tree())
574 xform.FlattenTo2d();
575 xform.Translate(layer->offset_to_transform_parent().x(),
576 layer->offset_to_transform_parent().y());
577 } else {
578 // Surfaces need to apply their sublayer scale.
579 xform.Scale(node->data.sublayer_scale.x(), node->data.sublayer_scale.y());
581 return xform;
584 gfx::Transform DrawTransformFromPropertyTrees(const Layer* layer,
585 const TransformTree& tree) {
586 return DrawTransformFromPropertyTreesInternal(layer, tree);
589 gfx::Transform DrawTransformFromPropertyTrees(const LayerImpl* layer,
590 const TransformTree& tree) {
591 return DrawTransformFromPropertyTreesInternal(layer, tree);
594 gfx::Transform DrawTransformOfRenderSurfaceFromPropertyTrees(
595 const RenderSurfaceImpl* render_surface,
596 const TransformTree& tree) {
597 const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
598 gfx::Transform render_surface_transform;
599 // The draw transform of root render surface is identity tranform.
600 if (node->id == 1)
601 return render_surface_transform;
602 const TransformNode* target_node = tree.Node(node->data.target_id);
603 if (target_node->id == 1)
604 target_node = tree.Node(0);
605 tree.ComputeTransformWithDestinationSublayerScale(node->id, target_node->id,
606 &render_surface_transform);
607 render_surface_transform.Scale(1.0 / node->data.sublayer_scale.x(),
608 1.0 / node->data.sublayer_scale.y());
609 return render_surface_transform;
612 template <typename LayerType>
613 gfx::Transform ScreenSpaceTransformFromPropertyTreesInternal(
614 LayerType* layer,
615 const TransformTree& tree) {
616 gfx::Transform xform(1, 0, 0, 1, layer->offset_to_transform_parent().x(),
617 layer->offset_to_transform_parent().y());
618 if (layer->transform_tree_index() >= 0) {
619 gfx::Transform ssxform =
620 tree.Node(layer->transform_tree_index())->data.to_screen;
621 xform.ConcatTransform(ssxform);
622 if (layer->should_flatten_transform_from_property_tree())
623 xform.FlattenTo2d();
625 return xform;
628 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
629 const Layer* layer,
630 const TransformTree& tree) {
631 return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
634 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
635 const LayerImpl* layer,
636 const TransformTree& tree) {
637 return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
640 template <typename LayerType>
641 float DrawOpacityFromPropertyTreesInternal(LayerType layer,
642 const OpacityTree& tree) {
643 if (!layer->render_target())
644 return 0.f;
646 const OpacityNode* target_node =
647 tree.Node(layer->render_target()->opacity_tree_index());
648 const OpacityNode* node = tree.Node(layer->opacity_tree_index());
649 if (node == target_node)
650 return 1.f;
652 float draw_opacity = 1.f;
653 while (node != target_node) {
654 draw_opacity *= node->data.opacity;
655 node = tree.parent(node);
657 return draw_opacity;
660 float DrawOpacityFromPropertyTrees(const Layer* layer,
661 const OpacityTree& tree) {
662 return DrawOpacityFromPropertyTreesInternal(layer, tree);
665 float DrawOpacityFromPropertyTrees(const LayerImpl* layer,
666 const OpacityTree& tree) {
667 return DrawOpacityFromPropertyTreesInternal(layer, tree);
670 bool CanUseLcdTextFromPropertyTrees(const LayerImpl* layer,
671 bool layers_always_allowed_lcd_text,
672 bool can_use_lcd_text,
673 PropertyTrees* property_trees) {
674 if (layers_always_allowed_lcd_text)
675 return true;
676 if (!can_use_lcd_text)
677 return false;
678 if (!layer->contents_opaque())
679 return false;
680 DCHECK(!property_trees->transform_tree.needs_update());
681 DCHECK(!property_trees->opacity_tree.needs_update());
683 const OpacityNode* opacity_node =
684 property_trees->opacity_tree.Node(layer->opacity_tree_index());
685 if (opacity_node->data.screen_space_opacity != 1.f)
686 return false;
687 const TransformNode* transform_node =
688 property_trees->transform_tree.Node(layer->transform_tree_index());
689 if (!transform_node->data.node_and_ancestors_have_only_integer_translation)
690 return false;
691 if (static_cast<int>(layer->offset_to_transform_parent().x()) !=
692 layer->offset_to_transform_parent().x())
693 return false;
694 if (static_cast<int>(layer->offset_to_transform_parent().y()) !=
695 layer->offset_to_transform_parent().y())
696 return false;
697 return true;
700 } // namespace cc