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"
9 #include "cc/base/math_util.h"
10 #include "cc/layers/layer.h"
11 #include "cc/trees/property_tree.h"
12 #include "cc/trees/property_tree_builder.h"
13 #include "ui/gfx/geometry/rect_conversions.h"
19 void CalculateVisibleRects(
20 const std::vector
<Layer
*>& layers_that_need_visible_rects
,
21 const ClipTree
& clip_tree
,
22 const TransformTree
& transform_tree
) {
23 for (size_t i
= 0; i
< layers_that_need_visible_rects
.size(); ++i
) {
24 Layer
* layer
= layers_that_need_visible_rects
[i
];
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_content_bounds
= layer
->content_bounds();
31 float contents_scale_x
= layer
->contents_scale_x();
32 float contents_scale_y
= layer
->contents_scale_y();
33 const bool has_clip
= layer
->clip_tree_index() > 0;
34 const TransformNode
* transform_node
=
35 transform_tree
.Node(layer
->transform_tree_index());
37 const ClipNode
* clip_node
= clip_tree
.Node(layer
->clip_tree_index());
38 const TransformNode
* clip_transform_node
=
39 transform_tree
.Node(clip_node
->data
.transform_id
);
40 const bool target_is_root_surface
=
41 transform_node
->data
.content_target_id
== 1;
42 // When the target is the root surface, we need to include the root
43 // transform by walking up to the root of the transform tree.
45 target_is_root_surface
? 0 : transform_node
->data
.content_target_id
;
46 const TransformNode
* target_node
= transform_tree
.Node(target_id
);
48 gfx::Transform content_to_target
= transform_node
->data
.to_target
;
50 content_to_target
.Translate(layer
->offset_to_transform_parent().x(),
51 layer
->offset_to_transform_parent().y());
52 content_to_target
.Scale(1.0 / contents_scale_x
, 1.0 / contents_scale_y
);
54 gfx::Rect clip_rect_in_target_space
;
55 gfx::Transform clip_to_target
;
57 if (clip_transform_node
->data
.target_id
== target_node
->id
) {
58 clip_to_target
= clip_transform_node
->data
.to_target
;
60 success
= transform_tree
.ComputeTransform(
61 clip_transform_node
->id
, target_node
->id
, &clip_to_target
);
62 if (target_node
->data
.needs_sublayer_scale
) {
63 clip_to_target
.Scale(target_node
->data
.sublayer_scale
.x(),
64 target_node
->data
.sublayer_scale
.y());
68 if (target_node
->id
> clip_node
->data
.transform_id
) {
70 DCHECK(target_node
->data
.to_screen_is_animated
);
72 // An animated singular transform may become non-singular during the
73 // animation, so we still need to compute a visible rect. In this
74 // situation, we treat the entire layer as visible.
75 layer
->set_visible_rect_from_property_trees(
76 gfx::Rect(layer_content_bounds
));
80 clip_rect_in_target_space
=
81 gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
82 clip_to_target
, clip_node
->data
.combined_clip
));
84 // Computing a transform to an ancestor should always succeed.
86 clip_rect_in_target_space
=
87 gfx::ToEnclosingRect(MathUtil::MapClippedRect(
88 clip_to_target
, clip_node
->data
.combined_clip
));
91 gfx::Rect layer_content_rect
= gfx::Rect(layer_content_bounds
);
92 gfx::Rect layer_content_bounds_in_target_space
=
93 MathUtil::MapEnclosingClippedRect(content_to_target
,
95 clip_rect_in_target_space
.Intersect(layer_content_bounds_in_target_space
);
96 if (clip_rect_in_target_space
.IsEmpty()) {
97 layer
->set_visible_rect_from_property_trees(gfx::Rect());
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
;
108 success
= transform_tree
.ComputeTransform(
109 target_node
->id
, transform_node
->id
, &target_to_layer
);
110 if (target_node
->data
.needs_sublayer_scale
) {
111 target_to_layer
.matrix().postScale(
112 1.f
/ target_node
->data
.sublayer_scale
.x(),
113 1.f
/ target_node
->data
.sublayer_scale
.y(), 1.f
);
118 DCHECK(transform_node
->data
.to_screen_is_animated
);
120 // An animated singular transform may become non-singular during the
121 // animation, so we still need to compute a visible rect. In this
122 // situation, we treat the entire layer as visible.
123 layer
->set_visible_rect_from_property_trees(
124 gfx::Rect(layer_content_bounds
));
128 target_to_content
.Scale(contents_scale_x
, contents_scale_y
);
129 target_to_content
.Translate(-layer
->offset_to_transform_parent().x(),
130 -layer
->offset_to_transform_parent().y());
131 target_to_content
.PreconcatTransform(target_to_layer
);
133 gfx::Rect visible_rect
= MathUtil::ProjectEnclosingClippedRect(
134 target_to_content
, clip_rect_in_target_space
);
136 visible_rect
.Intersect(gfx::Rect(layer_content_bounds
));
138 layer
->set_visible_rect_from_property_trees(visible_rect
);
140 layer
->set_visible_rect_from_property_trees(
141 gfx::Rect(layer_content_bounds
));
146 static bool IsRootLayerOfNewRenderingContext(Layer
* layer
) {
148 return !layer
->parent()->Is3dSorted() && layer
->Is3dSorted();
149 return layer
->Is3dSorted();
152 static inline bool LayerIsInExisting3DRenderingContext(Layer
* layer
) {
153 return layer
->Is3dSorted() && layer
->parent() &&
154 layer
->parent()->Is3dSorted();
157 static bool TransformToScreenIsKnown(Layer
* layer
, const TransformTree
& tree
) {
158 const TransformNode
* node
= tree
.Node(layer
->transform_tree_index());
159 return !node
->data
.to_screen_is_animated
;
162 static bool IsLayerBackFaceExposed(Layer
* layer
, const TransformTree
& tree
) {
163 if (!TransformToScreenIsKnown(layer
, tree
))
165 if (LayerIsInExisting3DRenderingContext(layer
))
166 return layer
->draw_transform_from_property_trees(tree
).IsBackFaceVisible();
167 return layer
->transform().IsBackFaceVisible();
170 static bool IsSurfaceBackFaceExposed(Layer
* layer
,
171 const TransformTree
& tree
) {
172 if (!TransformToScreenIsKnown(layer
, tree
))
174 if (LayerIsInExisting3DRenderingContext(layer
))
175 return layer
->draw_transform_from_property_trees(tree
).IsBackFaceVisible();
177 if (IsRootLayerOfNewRenderingContext(layer
))
178 return layer
->transform().IsBackFaceVisible();
180 // If the render_surface is not part of a new or existing rendering context,
181 // then the layers that contribute to this surface will decide back-face
182 // visibility for themselves.
186 static bool HasSingularTransform(Layer
* layer
, const TransformTree
& tree
) {
187 const TransformNode
* node
= tree
.Node(layer
->transform_tree_index());
188 return !node
->data
.is_invertible
|| !node
->data
.ancestors_are_invertible
;
191 static bool IsBackFaceInvisible(Layer
* layer
, const TransformTree
& tree
) {
192 Layer
* backface_test_layer
= layer
;
193 if (layer
->use_parent_backface_visibility()) {
194 DCHECK(layer
->parent());
195 DCHECK(!layer
->parent()->use_parent_backface_visibility());
196 backface_test_layer
= layer
->parent();
198 return !backface_test_layer
->double_sided() &&
199 IsLayerBackFaceExposed(backface_test_layer
, tree
);
202 static bool IsAnimatingTransformToScreen(Layer
* 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 bool IsInvisibleDueToTransform(Layer
* layer
, const TransformTree
& tree
) {
209 if (IsAnimatingTransformToScreen(layer
, tree
))
211 return HasSingularTransform(layer
, tree
) || IsBackFaceInvisible(layer
, tree
);
214 void FindLayersThatNeedVisibleRects(Layer
* layer
,
215 const TransformTree
& tree
,
216 bool subtree_is_visible_from_ancestor
,
217 std::vector
<Layer
*>* layers_to_update
) {
218 const bool layer_is_invisible
=
219 (!layer
->opacity() && !layer
->OpacityIsAnimating() &&
220 !layer
->OpacityCanAnimateOnImplThread());
221 const bool layer_is_backfacing
=
222 (layer
->has_render_surface() && !layer
->double_sided() &&
223 IsSurfaceBackFaceExposed(layer
, tree
));
225 const bool subtree_is_invisble
= layer_is_invisible
|| layer_is_backfacing
;
226 if (subtree_is_invisble
)
229 bool layer_is_drawn
=
230 layer
->HasCopyRequest() ||
231 (subtree_is_visible_from_ancestor
&& !layer
->hide_layer_and_subtree());
233 if (layer_is_drawn
&& layer
->DrawsContent()) {
234 const bool visible
= !IsInvisibleDueToTransform(layer
, tree
);
236 layers_to_update
->push_back(layer
);
239 for (size_t i
= 0; i
< layer
->children().size(); ++i
) {
240 FindLayersThatNeedVisibleRects(layer
->children()[i
].get(),
249 void ComputeClips(ClipTree
* clip_tree
, const TransformTree
& transform_tree
) {
250 for (int i
= 0; i
< static_cast<int>(clip_tree
->size()); ++i
) {
251 ClipNode
* clip_node
= clip_tree
->Node(i
);
253 // Only descendants of a real clipping layer (i.e., not 0) may have their
254 // clip adjusted due to intersecting with an ancestor clip.
255 const bool is_clipped
= clip_node
->parent_id
> 0;
257 clip_node
->data
.combined_clip
= clip_node
->data
.clip
;
261 ClipNode
* parent_clip_node
= clip_tree
->parent(clip_node
);
262 const TransformNode
* parent_transform_node
=
263 transform_tree
.Node(parent_clip_node
->data
.transform_id
);
264 const TransformNode
* transform_node
=
265 transform_tree
.Node(clip_node
->data
.transform_id
);
267 // Clips must be combined in target space. We cannot, for example, combine
268 // clips in the space of the child clip. The reason is non-affine
269 // transforms. Say we have the following tree T->A->B->C, and B clips C, but
270 // draw into target T. It may be the case that A applies a perspective
271 // transform, and B and C are at different z positions. When projected into
272 // target space, the relative sizes and positions of B and C can shift.
273 // Since it's the relationship in target space that matters, that's where we
274 // must combine clips.
275 gfx::Transform parent_to_target
;
276 gfx::Transform clip_to_target
;
277 gfx::Transform target_to_clip
;
280 transform_tree
.ComputeTransform(parent_transform_node
->id
,
281 clip_node
->data
.target_id
,
282 &parent_to_target
) &&
283 transform_tree
.ComputeTransform(
284 transform_node
->id
, clip_node
->data
.target_id
, &clip_to_target
) &&
285 transform_tree
.ComputeTransform(clip_node
->data
.target_id
,
286 transform_node
->id
, &target_to_clip
);
288 // If we can't compute a transform, it's because we had to use the inverse
289 // of a singular transform. We won't draw in this case, so there's no need
294 // In order to intersect with as small a rect as possible, we do a
295 // preliminary clip in target space so that when we project back, there's
296 // less likelihood of intersecting the view plane.
297 gfx::RectF inherited_clip_in_target_space
= MathUtil::MapClippedRect(
298 parent_to_target
, parent_clip_node
->data
.combined_clip
);
300 gfx::RectF clip_in_target_space
=
301 MathUtil::MapClippedRect(clip_to_target
, clip_node
->data
.clip
);
303 gfx::RectF intersected_in_target_space
= gfx::IntersectRects(
304 inherited_clip_in_target_space
, clip_in_target_space
);
306 clip_node
->data
.combined_clip
= MathUtil::ProjectClippedRect(
307 target_to_clip
, intersected_in_target_space
);
309 clip_node
->data
.combined_clip
.Intersect(clip_node
->data
.clip
);
313 void ComputeTransforms(TransformTree
* transform_tree
) {
314 for (int i
= 1; i
< static_cast<int>(transform_tree
->size()); ++i
)
315 transform_tree
->UpdateTransforms(i
);
318 void ComputeVisibleRectsUsingPropertyTrees(
320 const Layer
* page_scale_layer
,
321 float page_scale_factor
,
322 float device_scale_factor
,
323 const gfx::Rect
& viewport
,
324 const gfx::Transform
& device_transform
,
325 TransformTree
* transform_tree
,
327 OpacityTree
* opacity_tree
) {
328 PropertyTreeBuilder::BuildPropertyTrees(
329 root_layer
, page_scale_layer
, page_scale_factor
, device_scale_factor
,
330 viewport
, device_transform
, transform_tree
, clip_tree
, opacity_tree
);
331 ComputeTransforms(transform_tree
);
332 ComputeClips(clip_tree
, *transform_tree
);
334 std::vector
<Layer
*> layers_to_update
;
335 const bool subtree_is_visible_from_ancestor
= true;
336 FindLayersThatNeedVisibleRects(root_layer
, *transform_tree
,
337 subtree_is_visible_from_ancestor
,
339 CalculateVisibleRects(layers_to_update
, *clip_tree
, *transform_tree
);