Roll src/third_party/WebKit e0eac24:489c548 (svn 193311:193320)
[chromium-blink-merge.git] / cc / trees / draw_property_utils.cc
blobdf4c39ad9004aa579091eb3af23a02951b839eb3
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/trees/property_tree.h"
12 #include "cc/trees/property_tree_builder.h"
13 #include "ui/gfx/geometry/rect_conversions.h"
15 namespace cc {
17 namespace {
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());
36 if (has_clip) {
37 const ClipNode* clip_node = clip_tree.Node(layer->clip_tree_index());
38 const TransformNode* clip_transform_node =
39 transform_tree.Node(clip_node->data.transform_id);
40 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.
44 const int target_id =
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;
56 bool success = true;
57 if (clip_transform_node->data.target_id == target_node->id) {
58 clip_to_target = clip_transform_node->data.to_target;
59 } else {
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) {
69 if (!success) {
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));
77 continue;
80 clip_rect_in_target_space =
81 gfx::ToEnclosingRect(MathUtil::ProjectClippedRect(
82 clip_to_target, clip_node->data.combined_clip));
83 } else {
84 // Computing a transform to an ancestor should always succeed.
85 DCHECK(success);
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,
94 layer_content_rect);
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());
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.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);
117 if (!success) {
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));
125 continue;
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);
139 } else {
140 layer->set_visible_rect_from_property_trees(
141 gfx::Rect(layer_content_bounds));
146 static bool IsRootLayerOfNewRenderingContext(Layer* layer) {
147 if (layer->parent())
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))
164 return false;
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))
173 return false;
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.
183 return false;
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))
210 return false;
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)
227 return;
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);
235 if (visible)
236 layers_to_update->push_back(layer);
239 for (size_t i = 0; i < layer->children().size(); ++i) {
240 FindLayersThatNeedVisibleRects(layer->children()[i].get(),
241 tree,
242 layer_is_drawn,
243 layers_to_update);
247 } // namespace
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;
256 if (!is_clipped) {
257 clip_node->data.combined_clip = clip_node->data.clip;
258 continue;
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;
279 bool success =
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
290 // to compute clips.
291 if (!success)
292 continue;
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(
319 Layer* root_layer,
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,
326 ClipTree* clip_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,
338 &layers_to_update);
339 CalculateVisibleRects(layers_to_update, *clip_tree, *transform_tree);
342 } // namespace cc