Add ICU message format support
[chromium-blink-merge.git] / cc / trees / draw_property_utils.cc
blob876645e1eed0e19221621dc02c8ef96682953546
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);
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 continue;
71 clip_rect_in_target_space =
72 gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
73 clip_to_target, clip_node->data.combined_clip));
74 } else {
75 // Computing a transform to an ancestor should always succeed.
76 DCHECK(success);
77 clip_rect_in_target_space =
78 gfx::ToEnclosingRect(MathUtil::MapClippedRect(
79 clip_to_target, clip_node->data.combined_clip));
82 gfx::Rect layer_content_rect = gfx::Rect(layer_bounds);
83 gfx::Rect layer_content_bounds_in_target_space =
84 MathUtil::MapEnclosingClippedRect(content_to_target,
85 layer_content_rect);
86 clip_rect_in_target_space.Intersect(layer_content_bounds_in_target_space);
87 if (clip_rect_in_target_space.IsEmpty()) {
88 layer->set_visible_rect_from_property_trees(gfx::Rect());
89 continue;
92 // If the layer is fully contained within the clip, treat it as fully
93 // visible. Since clip_rect_in_target_space has already been intersected
94 // with layer_content_bounds_in_target_space, the layer is fully contained
95 // within the clip iff these rects are equal.
96 if (clip_rect_in_target_space == layer_content_bounds_in_target_space) {
97 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
98 continue;
101 gfx::Transform target_to_content;
102 gfx::Transform target_to_layer;
104 if (transform_node->data.ancestors_are_invertible) {
105 target_to_layer = transform_node->data.from_target;
106 success = true;
107 } else {
108 success = transform_tree.ComputeTransformWithSourceSublayerScale(
109 target_node->id, transform_node->id, &target_to_layer);
112 if (!success) {
113 // An animated singular transform may become non-singular during the
114 // animation, so we still need to compute a visible rect. In this
115 // situation, we treat the entire layer as visible.
116 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
117 continue;
120 target_to_content.Translate(-layer->offset_to_transform_parent().x(),
121 -layer->offset_to_transform_parent().y());
122 target_to_content.PreconcatTransform(target_to_layer);
124 gfx::Rect visible_rect = MathUtil::ProjectEnclosingClippedRect(
125 target_to_content, clip_rect_in_target_space);
127 visible_rect.Intersect(gfx::Rect(layer_bounds));
129 layer->set_visible_rect_from_property_trees(visible_rect);
130 } else {
131 layer->set_visible_rect_from_property_trees(gfx::Rect(layer_bounds));
136 template <typename LayerType>
137 static bool IsRootLayerOfNewRenderingContext(LayerType* layer) {
138 if (layer->parent())
139 return !layer->parent()->Is3dSorted() && layer->Is3dSorted();
140 return layer->Is3dSorted();
143 template <typename LayerType>
144 static inline bool LayerIsInExisting3DRenderingContext(LayerType* layer) {
145 return layer->Is3dSorted() && layer->parent() &&
146 layer->parent()->Is3dSorted() &&
147 layer->parent()->sorting_context_id() == layer->sorting_context_id();
150 template <typename LayerType>
151 static bool TransformToScreenIsKnown(LayerType* layer,
152 const TransformTree& tree) {
153 const TransformNode* node = tree.Node(layer->transform_tree_index());
154 return !node->data.to_screen_is_animated;
157 template <typename LayerType>
158 static bool HasSingularTransform(LayerType* layer, const TransformTree& tree) {
159 const TransformNode* node = tree.Node(layer->transform_tree_index());
160 return !node->data.is_invertible || !node->data.ancestors_are_invertible;
163 template <typename LayerType>
164 static bool IsLayerBackFaceVisible(LayerType* layer,
165 const TransformTree& tree) {
166 // The current W3C spec on CSS transforms says that backface visibility should
167 // be determined differently depending on whether the layer is in a "3d
168 // rendering context" or not. For Chromium code, we can determine whether we
169 // are in a 3d rendering context by checking if the parent preserves 3d.
171 if (LayerIsInExisting3DRenderingContext(layer))
172 return DrawTransformFromPropertyTrees(layer, tree).IsBackFaceVisible();
174 // In this case, either the layer establishes a new 3d rendering context, or
175 // is not in a 3d rendering context at all.
176 return layer->transform().IsBackFaceVisible();
179 template <typename LayerType>
180 static bool IsSurfaceBackFaceVisible(LayerType* layer,
181 const TransformTree& tree) {
182 if (LayerIsInExisting3DRenderingContext(layer)) {
183 const TransformNode* node = tree.Node(layer->transform_tree_index());
184 // Draw transform as a contributing render surface.
185 // TODO(enne): we shouldn't walk the tree during a tree walk.
186 gfx::Transform surface_draw_transform;
187 tree.ComputeTransform(node->id, node->data.target_id,
188 &surface_draw_transform);
189 return surface_draw_transform.IsBackFaceVisible();
192 if (IsRootLayerOfNewRenderingContext(layer))
193 return layer->transform().IsBackFaceVisible();
195 // If the render_surface is not part of a new or existing rendering context,
196 // then the layers that contribute to this surface will decide back-face
197 // visibility for themselves.
198 return false;
201 template <typename LayerType>
202 static bool IsAnimatingTransformToScreen(LayerType* layer,
203 const TransformTree& tree) {
204 const TransformNode* node = tree.Node(layer->transform_tree_index());
205 return node->data.to_screen_is_animated;
208 static inline bool TransformToScreenIsKnown(Layer* layer,
209 const TransformTree& tree) {
210 return !IsAnimatingTransformToScreen(layer, tree);
213 static inline bool TransformToScreenIsKnown(LayerImpl* layer,
214 const TransformTree& tree) {
215 return true;
218 template <typename LayerType>
219 static bool HasInvertibleOrAnimatedTransform(LayerType* layer) {
220 return layer->transform_is_invertible() ||
221 layer->HasPotentiallyRunningTransformAnimation();
224 static inline bool SubtreeShouldBeSkipped(LayerImpl* layer,
225 bool layer_is_drawn,
226 const TransformTree& tree) {
227 // If the layer transform is not invertible, it should not be drawn.
228 // TODO(ajuma): Correctly process subtrees with singular transform for the
229 // case where we may animate to a non-singular transform and wish to
230 // pre-raster.
231 if (!HasInvertibleOrAnimatedTransform(layer))
232 return true;
234 // When we need to do a readback/copy of a layer's output, we can not skip
235 // it or any of its ancestors.
236 if (layer->draw_properties().layer_or_descendant_has_copy_request)
237 return false;
239 // We cannot skip the the subtree if a descendant has a wheel or touch handler
240 // or the hit testing code will break (it requires fresh transforms, etc).
241 if (layer->draw_properties().layer_or_descendant_has_input_handler)
242 return false;
244 // If the layer is not drawn, then skip it and its subtree.
245 if (!layer_is_drawn)
246 return true;
248 if (layer->render_surface() && !layer->double_sided() &&
249 IsSurfaceBackFaceVisible(layer, tree))
250 return true;
252 // If layer is on the pending tree and opacity is being animated then
253 // this subtree can't be skipped as we need to create, prioritize and
254 // include tiles for this layer when deciding if tree can be activated.
255 if (layer->layer_tree_impl()->IsPendingTree() &&
256 layer->HasPotentiallyRunningOpacityAnimation())
257 return false;
259 // The opacity of a layer always applies to its children (either implicitly
260 // via a render surface or explicitly if the parent preserves 3D), so the
261 // entire subtree can be skipped if this layer is fully transparent.
262 return !layer->opacity();
265 static inline bool SubtreeShouldBeSkipped(Layer* layer,
266 bool layer_is_drawn,
267 const TransformTree& tree) {
268 // If the layer transform is not invertible, it should not be drawn.
269 if (!layer->transform_is_invertible() &&
270 !layer->HasPotentiallyRunningTransformAnimation())
271 return true;
273 // When we need to do a readback/copy of a layer's output, we can not skip
274 // it or any of its ancestors.
275 if (layer->draw_properties().layer_or_descendant_has_copy_request)
276 return false;
278 // We cannot skip the the subtree if a descendant has a wheel or touch handler
279 // or the hit testing code will break (it requires fresh transforms, etc).
280 if (layer->draw_properties().layer_or_descendant_has_input_handler)
281 return false;
283 // If the layer is not drawn, then skip it and its subtree.
284 if (!layer_is_drawn)
285 return true;
287 if (layer->render_surface() && !layer->double_sided() &&
288 !layer->HasPotentiallyRunningTransformAnimation() &&
289 IsSurfaceBackFaceVisible(layer, tree))
290 return true;
292 // If the opacity is being animated then the opacity on the main thread is
293 // unreliable (since the impl thread may be using a different opacity), so it
294 // should not be trusted.
295 // In particular, it should not cause the subtree to be skipped.
296 // Similarly, for layers that might animate opacity using an impl-only
297 // animation, their subtree should also not be skipped.
298 return !layer->opacity() && !layer->HasPotentiallyRunningOpacityAnimation() &&
299 !layer->OpacityCanAnimateOnImplThread();
302 template <typename LayerType>
303 static bool LayerShouldBeSkipped(LayerType* layer,
304 bool layer_is_drawn,
305 const TransformTree& tree) {
306 // Layers can be skipped if any of these conditions are met.
307 // - is not drawn due to it or one of its ancestors being hidden (or having
308 // no copy requests).
309 // - does not draw content.
310 // - is transparent.
311 // - has empty bounds
312 // - the layer is not double-sided, but its back face is visible.
314 // Some additional conditions need to be computed at a later point after the
315 // recursion is finished.
316 // - the intersection of render_surface content and layer clip_rect is empty
317 // - the visible_layer_rect is empty
319 // Note, if the layer should not have been drawn due to being fully
320 // transparent, we would have skipped the entire subtree and never made it
321 // into this function, so it is safe to omit this check here.
322 if (!layer_is_drawn)
323 return true;
325 if (!layer->DrawsContent() || layer->bounds().IsEmpty())
326 return true;
328 LayerType* backface_test_layer = layer;
329 if (layer->use_parent_backface_visibility()) {
330 DCHECK(layer->parent());
331 DCHECK(!layer->parent()->use_parent_backface_visibility());
332 backface_test_layer = layer->parent();
335 // The layer should not be drawn if (1) it is not double-sided and (2) the
336 // back of the layer is known to be facing the screen.
337 if (!backface_test_layer->double_sided() &&
338 TransformToScreenIsKnown(backface_test_layer, tree) &&
339 IsLayerBackFaceVisible(backface_test_layer, tree))
340 return true;
342 return false;
345 template <typename LayerType>
346 void FindLayersThatNeedUpdates(
347 LayerType* layer,
348 const TransformTree& tree,
349 bool subtree_is_visible_from_ancestor,
350 typename LayerType::LayerListType* update_layer_list,
351 std::vector<LayerType*>* visible_layer_list) {
352 bool layer_is_drawn =
353 layer->HasCopyRequest() ||
354 (subtree_is_visible_from_ancestor && !layer->hide_layer_and_subtree());
356 if (layer->parent() && SubtreeShouldBeSkipped(layer, layer_is_drawn, tree))
357 return;
359 if (!LayerShouldBeSkipped(layer, layer_is_drawn, tree)) {
360 visible_layer_list->push_back(layer);
361 update_layer_list->push_back(layer);
364 // Append mask layers to the update layer list. They don't have valid visible
365 // rects, so need to get added after the above calculation. Replica layers
366 // don't need to be updated.
367 if (LayerType* mask_layer = layer->mask_layer())
368 update_layer_list->push_back(mask_layer);
369 if (LayerType* replica_layer = layer->replica_layer()) {
370 if (LayerType* mask_layer = replica_layer->mask_layer())
371 update_layer_list->push_back(mask_layer);
374 for (size_t i = 0; i < layer->children().size(); ++i) {
375 FindLayersThatNeedUpdates(layer->child_at(i), tree, layer_is_drawn,
376 update_layer_list, visible_layer_list);
380 } // namespace
382 void ComputeClips(ClipTree* clip_tree, const TransformTree& transform_tree) {
383 if (!clip_tree->needs_update())
384 return;
385 for (int i = 0; i < static_cast<int>(clip_tree->size()); ++i) {
386 ClipNode* clip_node = clip_tree->Node(i);
388 // Only descendants of a real clipping layer (i.e., not 0) may have their
389 // clip adjusted due to intersecting with an ancestor clip.
390 const bool is_clipped = clip_node->parent_id > 0;
391 if (!is_clipped) {
392 DCHECK(!clip_node->data.inherit_parent_target_space_clip);
393 clip_node->data.combined_clip = clip_node->data.clip;
394 continue;
397 ClipNode* parent_clip_node = clip_tree->parent(clip_node);
398 const TransformNode* parent_transform_node =
399 transform_tree.Node(parent_clip_node->data.transform_id);
400 const TransformNode* transform_node =
401 transform_tree.Node(clip_node->data.transform_id);
403 // Clips must be combined in target space. We cannot, for example, combine
404 // clips in the space of the child clip. The reason is non-affine
405 // transforms. Say we have the following tree T->A->B->C, and B clips C, but
406 // draw into target T. It may be the case that A applies a perspective
407 // transform, and B and C are at different z positions. When projected into
408 // target space, the relative sizes and positions of B and C can shift.
409 // Since it's the relationship in target space that matters, that's where we
410 // must combine clips.
411 gfx::Transform parent_to_target;
412 gfx::Transform clip_to_target;
413 gfx::Transform target_to_clip;
414 gfx::Transform parent_to_transform_target;
415 gfx::Transform transform_target_to_target;
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 // When render surface applies clip, we need the clip from the target's
425 // target space. But, as the combined clip is in parent clip's target
426 // space, we need to first transform it from parent's target space to
427 // target's target space.
428 if (clip_node->data.inherit_parent_target_space_clip) {
429 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
430 parent_transform_node->id, transform_node->data.target_id,
431 &parent_to_transform_target);
432 success &= transform_tree.ComputeTransformWithSourceSublayerScale(
433 transform_node->data.target_id, target_id,
434 &transform_target_to_target);
435 transform_target_to_target.matrix().postScale(
436 transform_node->data.sublayer_scale.x(),
437 transform_node->data.sublayer_scale.y(), 1.0);
438 } else if (parent_transform_node->data.content_target_id ==
439 clip_node->data.target_id) {
440 parent_to_target = parent_transform_node->data.to_target;
441 } else {
442 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
443 parent_transform_node->id, target_id, &parent_to_target);
446 if (transform_node->data.content_target_id == clip_node->data.target_id) {
447 clip_to_target = transform_node->data.to_target;
448 } else {
449 success &= transform_tree.ComputeTransformWithDestinationSublayerScale(
450 transform_node->id, target_id, &clip_to_target);
453 if (transform_node->data.content_target_id == clip_node->data.target_id &&
454 transform_node->data.ancestors_are_invertible) {
455 target_to_clip = transform_node->data.from_target;
456 } else {
457 success &= clip_to_target.GetInverse(&target_to_clip);
460 // If we can't compute a transform, it's because we had to use the inverse
461 // of a singular transform. We won't draw in this case, so there's no need
462 // to compute clips.
463 if (!success) {
464 continue;
467 // In order to intersect with as small a rect as possible, we do a
468 // preliminary clip in target space so that when we project back, there's
469 // less likelihood of intersecting the view plane.
470 gfx::RectF inherited_clip_in_target_space;
471 if (clip_node->data.inherit_parent_target_space_clip) {
472 gfx::RectF combined_clip_in_transform_target_space;
473 if (parent_transform_node->id > transform_node->data.target_id)
474 combined_clip_in_transform_target_space = MathUtil::MapClippedRect(
475 parent_to_transform_target, parent_clip_node->data.combined_clip);
476 else
477 combined_clip_in_transform_target_space = MathUtil::ProjectClippedRect(
478 parent_to_transform_target, parent_clip_node->data.combined_clip);
479 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
480 transform_target_to_target, combined_clip_in_transform_target_space);
481 } else if (parent_transform_node->id > target_id) {
482 inherited_clip_in_target_space = MathUtil::MapClippedRect(
483 parent_to_target, parent_clip_node->data.combined_clip);
484 } else {
485 inherited_clip_in_target_space = MathUtil::ProjectClippedRect(
486 parent_to_target, parent_clip_node->data.combined_clip);
489 // When render surface inherits its parent target space clip, the layer
490 // that created the clip node doesn't apply any clip. So, we shouldn't clip
491 // using the clip value stored in the clip node.
492 gfx::RectF intersected_in_target_space;
493 if (!clip_node->data.inherit_parent_target_space_clip) {
494 gfx::RectF clip_in_target_space =
495 MathUtil::MapClippedRect(clip_to_target, clip_node->data.clip);
497 intersected_in_target_space = gfx::IntersectRects(
498 inherited_clip_in_target_space, clip_in_target_space);
499 } else {
500 intersected_in_target_space = inherited_clip_in_target_space;
503 clip_node->data.combined_clip = MathUtil::ProjectClippedRect(
504 target_to_clip, intersected_in_target_space);
506 if (!clip_node->data.inherit_parent_target_space_clip)
507 clip_node->data.combined_clip.Intersect(clip_node->data.clip);
509 clip_tree->set_needs_update(false);
512 void ComputeTransforms(TransformTree* transform_tree) {
513 if (!transform_tree->needs_update())
514 return;
515 for (int i = 1; i < static_cast<int>(transform_tree->size()); ++i)
516 transform_tree->UpdateTransforms(i);
517 transform_tree->set_needs_update(false);
520 void ComputeOpacities(OpacityTree* opacity_tree) {
521 if (!opacity_tree->needs_update())
522 return;
523 for (int i = 1; i < static_cast<int>(opacity_tree->size()); ++i)
524 opacity_tree->UpdateOpacities(i);
525 opacity_tree->set_needs_update(false);
528 template <typename LayerType>
529 void ComputeVisibleRectsUsingPropertyTreesInternal(
530 LayerType* root_layer,
531 PropertyTrees* property_trees,
532 typename LayerType::LayerListType* update_layer_list) {
533 if (property_trees->transform_tree.needs_update())
534 property_trees->clip_tree.set_needs_update(true);
535 ComputeTransforms(&property_trees->transform_tree);
536 ComputeClips(&property_trees->clip_tree, property_trees->transform_tree);
537 ComputeOpacities(&property_trees->opacity_tree);
539 const bool subtree_is_visible_from_ancestor = true;
540 std::vector<LayerType*> visible_layer_list;
541 FindLayersThatNeedUpdates(root_layer, property_trees->transform_tree,
542 subtree_is_visible_from_ancestor, update_layer_list,
543 &visible_layer_list);
544 CalculateVisibleRects<LayerType>(visible_layer_list,
545 property_trees->clip_tree,
546 property_trees->transform_tree);
549 void BuildPropertyTreesAndComputeVisibleRects(
550 Layer* root_layer,
551 const Layer* page_scale_layer,
552 const Layer* inner_viewport_scroll_layer,
553 const Layer* outer_viewport_scroll_layer,
554 float page_scale_factor,
555 float device_scale_factor,
556 const gfx::Rect& viewport,
557 const gfx::Transform& device_transform,
558 PropertyTrees* property_trees,
559 LayerList* update_layer_list) {
560 PropertyTreeBuilder::BuildPropertyTrees(
561 root_layer, page_scale_layer, inner_viewport_scroll_layer,
562 outer_viewport_scroll_layer, page_scale_factor, device_scale_factor,
563 viewport, device_transform, property_trees);
564 ComputeVisibleRectsUsingPropertyTrees(root_layer, property_trees,
565 update_layer_list);
568 void BuildPropertyTreesAndComputeVisibleRects(
569 LayerImpl* root_layer,
570 const LayerImpl* page_scale_layer,
571 const LayerImpl* inner_viewport_scroll_layer,
572 const LayerImpl* 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 LayerImplList* 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 ComputeVisibleRectsUsingPropertyTrees(Layer* root_layer,
588 PropertyTrees* property_trees,
589 LayerList* update_layer_list) {
590 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
591 update_layer_list);
594 void ComputeVisibleRectsUsingPropertyTrees(LayerImpl* root_layer,
595 PropertyTrees* property_trees,
596 LayerImplList* update_layer_list) {
597 ComputeVisibleRectsUsingPropertyTreesInternal(root_layer, property_trees,
598 update_layer_list);
601 template <typename LayerType>
602 gfx::Transform DrawTransformFromPropertyTreesInternal(
603 const LayerType* layer,
604 const TransformTree& tree) {
605 const TransformNode* node = tree.Node(layer->transform_tree_index());
607 gfx::Transform xform;
608 const bool owns_non_root_surface = layer->parent() && layer->render_surface();
609 if (!owns_non_root_surface) {
610 // If you're not the root, or you don't own a surface, you need to apply
611 // your local offset.
612 xform = node->data.to_target;
613 if (layer->should_flatten_transform_from_property_tree())
614 xform.FlattenTo2d();
615 xform.Translate(layer->offset_to_transform_parent().x(),
616 layer->offset_to_transform_parent().y());
617 } else {
618 // Surfaces need to apply their sublayer scale.
619 xform.Scale(node->data.sublayer_scale.x(), node->data.sublayer_scale.y());
621 return xform;
624 gfx::Transform DrawTransformFromPropertyTrees(const Layer* layer,
625 const TransformTree& tree) {
626 return DrawTransformFromPropertyTreesInternal(layer, tree);
629 gfx::Transform DrawTransformFromPropertyTrees(const LayerImpl* layer,
630 const TransformTree& tree) {
631 return DrawTransformFromPropertyTreesInternal(layer, tree);
634 gfx::Transform DrawTransformOfRenderSurfaceFromPropertyTrees(
635 const RenderSurfaceImpl* render_surface,
636 const TransformTree& tree) {
637 const TransformNode* node = tree.Node(render_surface->TransformTreeIndex());
638 gfx::Transform render_surface_transform;
639 // The draw transform of root render surface is identity tranform.
640 if (node->id == 1)
641 return render_surface_transform;
642 const TransformNode* target_node = tree.Node(node->data.target_id);
643 if (target_node->id == 1)
644 target_node = tree.Node(0);
645 tree.ComputeTransformWithDestinationSublayerScale(node->id, target_node->id,
646 &render_surface_transform);
647 render_surface_transform.Scale(1.0 / node->data.sublayer_scale.x(),
648 1.0 / node->data.sublayer_scale.y());
649 return render_surface_transform;
652 template <typename LayerType>
653 gfx::Transform ScreenSpaceTransformFromPropertyTreesInternal(
654 LayerType* layer,
655 const TransformTree& tree) {
656 gfx::Transform xform(1, 0, 0, 1, layer->offset_to_transform_parent().x(),
657 layer->offset_to_transform_parent().y());
658 if (layer->transform_tree_index() >= 0) {
659 gfx::Transform ssxform =
660 tree.Node(layer->transform_tree_index())->data.to_screen;
661 xform.ConcatTransform(ssxform);
662 if (layer->should_flatten_transform_from_property_tree())
663 xform.FlattenTo2d();
665 return xform;
668 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
669 const Layer* layer,
670 const TransformTree& tree) {
671 return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
674 gfx::Transform ScreenSpaceTransformFromPropertyTrees(
675 const LayerImpl* layer,
676 const TransformTree& tree) {
677 return ScreenSpaceTransformFromPropertyTreesInternal(layer, tree);
680 template <typename LayerType>
681 bool ScreenSpaceTransformIsAnimatingFromPropertyTreesInternal(
682 LayerType* layer,
683 const TransformTree& tree) {
684 return tree.Node(layer->transform_tree_index())->data.to_screen_is_animated;
687 bool ScreenSpaceTransformIsAnimatingFromPropertyTrees(
688 const Layer* layer,
689 const TransformTree& tree) {
690 return ScreenSpaceTransformIsAnimatingFromPropertyTreesInternal(layer, tree);
693 bool ScreenSpaceTransformIsAnimatingFromPropertyTrees(
694 const LayerImpl* layer,
695 const TransformTree& tree) {
696 return ScreenSpaceTransformIsAnimatingFromPropertyTreesInternal(layer, tree);
699 template <typename LayerType>
700 float DrawOpacityFromPropertyTreesInternal(LayerType layer,
701 const OpacityTree& tree) {
702 if (!layer->render_target())
703 return 0.f;
705 const OpacityNode* target_node =
706 tree.Node(layer->render_target()->opacity_tree_index());
707 const OpacityNode* node = tree.Node(layer->opacity_tree_index());
708 if (node == target_node)
709 return 1.f;
711 float draw_opacity = 1.f;
712 while (node != target_node) {
713 draw_opacity *= node->data.opacity;
714 node = tree.parent(node);
716 return draw_opacity;
719 float DrawOpacityFromPropertyTrees(const Layer* layer,
720 const OpacityTree& tree) {
721 return DrawOpacityFromPropertyTreesInternal(layer, tree);
724 float DrawOpacityFromPropertyTrees(const LayerImpl* layer,
725 const OpacityTree& tree) {
726 return DrawOpacityFromPropertyTreesInternal(layer, tree);
729 bool CanUseLcdTextFromPropertyTrees(const LayerImpl* layer,
730 bool layers_always_allowed_lcd_text,
731 bool can_use_lcd_text,
732 PropertyTrees* property_trees) {
733 if (layers_always_allowed_lcd_text)
734 return true;
735 if (!can_use_lcd_text)
736 return false;
737 if (!layer->contents_opaque())
738 return false;
739 DCHECK(!property_trees->transform_tree.needs_update());
740 DCHECK(!property_trees->opacity_tree.needs_update());
742 const OpacityNode* opacity_node =
743 property_trees->opacity_tree.Node(layer->opacity_tree_index());
744 if (opacity_node->data.screen_space_opacity != 1.f)
745 return false;
746 const TransformNode* transform_node =
747 property_trees->transform_tree.Node(layer->transform_tree_index());
748 if (!transform_node->data.node_and_ancestors_have_only_integer_translation)
749 return false;
750 if (static_cast<int>(layer->offset_to_transform_parent().x()) !=
751 layer->offset_to_transform_parent().x())
752 return false;
753 if (static_cast<int>(layer->offset_to_transform_parent().y()) !=
754 layer->offset_to_transform_parent().y())
755 return false;
756 return true;
759 } // namespace cc