OLD | NEW |
---|---|
(Empty) | |
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. | |
4 | |
5 #include "cc/trees/property_tree_builder.h" | |
6 | |
7 #include <map> | |
8 #include <set> | |
9 | |
10 #include "cc/base/math_util.h" | |
11 #include "cc/layers/layer.h" | |
12 #include "cc/trees/layer_tree_host.h" | |
13 #include "ui/gfx/point_f.h" | |
14 | |
15 namespace cc { | |
16 | |
17 class LayerTreeHost; | |
18 | |
19 namespace { | |
20 | |
21 struct DataForRecursion { | |
22 TransformTree* transform_tree; | |
23 ClipTree* clip_tree; | |
24 Layer* transform_tree_parent; | |
25 Layer* transform_fixed_parent; | |
26 Layer* render_target; | |
27 int clip_tree_parent; | |
28 gfx::Vector2dF offset_to_transform_tree_parent; | |
29 gfx::Vector2dF offset_to_transform_fixed_parent; | |
30 const Layer* page_scale_layer; | |
31 float page_scale_factor; | |
32 float device_scale_factor; | |
33 }; | |
34 | |
35 static Layer* GetTransformParent(const DataForRecursion& data, Layer* layer) { | |
36 return layer->position_constraint().is_fixed_position() | |
37 ? data.transform_fixed_parent | |
38 : data.transform_tree_parent; | |
39 } | |
40 | |
41 static ClipNode* GetClipParent(const DataForRecursion& data, Layer* layer) { | |
42 const bool inherits_clip = !layer->parent() || !layer->clip_parent(); | |
43 const int id = inherits_clip ? data.clip_tree_parent | |
44 : layer->clip_parent()->clip_tree_index(); | |
45 return data.clip_tree->Node(id); | |
46 } | |
47 | |
48 static bool RequiresClipNode(Layer* layer, | |
49 bool axis_aligned_with_respect_to_parent) { | |
50 const bool render_surface_applies_non_axis_aligned_clip = | |
51 layer->render_surface() && !axis_aligned_with_respect_to_parent && | |
52 layer->is_clipped(); | |
53 const bool render_surface_may_grow_due_to_clip_children = | |
54 layer->render_surface() && layer->num_unclipped_descendants() > 0; | |
55 | |
56 return !layer->parent() || layer->masks_to_bounds() || layer->mask_layer() || | |
57 render_surface_applies_non_axis_aligned_clip || | |
58 render_surface_may_grow_due_to_clip_children; | |
59 } | |
60 | |
61 void AddClipNodeIfNeeded(const DataForRecursion& data_from_ancestor, | |
62 Layer* layer, | |
63 DataForRecursion* data_for_children) { | |
64 ClipNode* parent = GetClipParent(data_from_ancestor, layer); | |
65 int parent_id = parent->id; | |
66 | |
67 const bool axis_aligned_with_respect_to_parent = Are2DAxisAligned( | |
68 *data_from_ancestor.transform_tree, layer->transform_tree_index(), | |
69 parent->data.transform_id); | |
70 | |
71 // TODO(vollick): once Andrew refactors the surface determinations out of | |
enne (OOO)
2014/12/10 23:45:59
What's the status on this work?
Ian Vollick
2014/12/12 03:01:47
Andrew's got a patch up for review. Ball's in Dana
| |
72 // CDP, the the layer->render_surface() check will be invalid. | |
73 const bool has_unclipped_surface = | |
74 layer->render_surface() && | |
75 layer->render_surface()->clip_rect().IsEmpty() && | |
76 layer->num_unclipped_descendants() == 0; | |
77 | |
78 if (has_unclipped_surface) | |
79 parent_id = 0; | |
80 | |
81 if (!RequiresClipNode(layer, axis_aligned_with_respect_to_parent)) { | |
82 // Unclipped surfaces reset the clip rect. | |
83 data_for_children->clip_tree_parent = parent_id; | |
84 } else if (layer->parent()) { | |
85 // Note the root clip gets handled elsewhere. | |
86 Layer* transform_parent = GetTransformParent(*data_for_children, layer); | |
87 ClipNode node; | |
88 node.data.clip = gfx::RectF( | |
89 gfx::PointF() + layer->offset_to_transform_parent(), layer->bounds()); | |
90 node.data.transform_id = transform_parent->transform_tree_index(); | |
91 node.data.target_id = | |
92 data_from_ancestor.render_target->transform_tree_index(); | |
93 | |
94 data_for_children->clip_tree_parent = | |
95 data_for_children->clip_tree->Insert(node, parent_id); | |
96 } | |
97 | |
98 layer->set_clip_tree_index( | |
99 has_unclipped_surface ? 0 : data_for_children->clip_tree_parent); | |
100 | |
101 // TODO(awoloszyn): Right now when we hit a node with a replica, we reset the | |
102 // clip for all children since we may need to draw. We need to figure out a | |
103 // better way, since we will need both the clipped and unclipped versions. | |
104 } | |
105 | |
106 void AddTransformNodeIfNeeded(const DataForRecursion& data_from_ancestor, | |
107 Layer* layer, | |
108 DataForRecursion* data_for_children) { | |
109 const bool is_root = !layer->parent(); | |
110 const bool is_page_scale_application_layer = | |
111 layer->parent() && layer->parent() == data_from_ancestor.page_scale_layer; | |
112 const bool is_scrollable = layer->scrollable(); | |
113 const bool is_fixed = layer->position_constraint().is_fixed_position(); | |
114 | |
115 const bool has_significant_transform = | |
116 !layer->transform().IsIdentityOr2DTranslation(); | |
117 | |
118 const bool has_animated_transform = | |
119 layer->layer_animation_controller()->IsAnimatingProperty( | |
120 Animation::Transform); | |
121 | |
122 const bool has_transform_origin = layer->transform_origin() != gfx::Point3F(); | |
123 | |
124 const bool has_surface = layer->render_surface(); | |
125 | |
126 const bool flattening_change = layer->parent() && | |
127 layer->should_flatten_transform() && | |
128 !layer->parent()->should_flatten_transform(); | |
129 | |
130 bool requires_node = is_root || is_scrollable || is_fixed || | |
131 has_significant_transform || has_animated_transform || | |
132 is_page_scale_application_layer || flattening_change || | |
133 has_transform_origin || has_surface; | |
134 | |
135 Layer* transform_parent = GetTransformParent(data_from_ancestor, layer); | |
136 | |
137 // May be non-zero if layer is fixed or has a scroll parent. | |
138 gfx::Vector2dF parent_offset; | |
139 if (transform_parent) { | |
140 // TODO(vollick): This is to mimic bugs in current CDP. Need to log a bug | |
enne (OOO)
2014/12/10 23:45:59
!!!
Ian Vollick
2014/12/12 03:01:47
Yeah :( I've logged the bug and referenced it in t
| |
141 // about this and reference it here. | |
142 if (!is_fixed) | |
143 parent_offset = transform_parent->offset_to_transform_parent(); | |
144 | |
145 gfx::Transform to_parent; | |
146 Layer* source = data_from_ancestor.transform_tree_parent; | |
147 if (layer->scroll_parent()) { | |
148 source = layer->parent(); | |
149 parent_offset += layer->parent()->offset_to_transform_parent(); | |
150 } | |
151 | |
152 ComputeTransform(*data_from_ancestor.transform_tree, | |
153 source->transform_tree_index(), | |
154 transform_parent->transform_tree_index(), &to_parent); | |
155 | |
156 parent_offset += to_parent.To2dTranslation(); | |
157 } | |
158 | |
159 if (layer->IsContainerForFixedPositionLayers() || is_root) | |
160 data_for_children->transform_fixed_parent = layer; | |
161 data_for_children->transform_tree_parent = layer; | |
162 | |
163 if (!requires_node) { | |
164 gfx::Vector2dF local_offset = layer->position().OffsetFromOrigin() + | |
165 layer->transform().To2dTranslation(); | |
166 layer->set_offset_to_transform_parent(parent_offset + local_offset); | |
167 layer->set_transform_tree_index(transform_parent->transform_tree_index()); | |
168 return; | |
169 } | |
170 | |
171 if (!is_root) { | |
172 data_for_children->transform_tree->Insert( | |
173 TransformNode(), transform_parent->transform_tree_index()); | |
174 } | |
175 | |
176 TransformNode* node = data_for_children->transform_tree->back(); | |
177 | |
178 node->data.flattens = layer->should_flatten_transform(); | |
179 node->data.target_id = | |
180 data_from_ancestor.render_target->transform_tree_index(); | |
181 | |
182 gfx::Transform transform; | |
183 float device_and_page_scale_factors = 1.0f; | |
184 if (is_root) | |
185 device_and_page_scale_factors = data_from_ancestor.device_scale_factor; | |
186 if (is_page_scale_application_layer) | |
187 device_and_page_scale_factors *= data_from_ancestor.page_scale_factor; | |
188 | |
189 transform.Scale(device_and_page_scale_factors, device_and_page_scale_factors); | |
190 | |
191 // NB: We've accounted for the scroll offset here but we haven't taken into | |
192 // account snapping to screen space pixels (since we haven't computed any | |
193 // screen space transforms). For the purposes of computing rects we need to | |
194 // record, this should be fine (the visible rects we compute may be slightly | |
195 // different than what we'd compute with snapping, but since we significantly | |
196 // expand the visible rect when determining what to record, the slight | |
197 // difference should be inconsequential). | |
198 gfx::Vector2dF position = layer->position().OffsetFromOrigin(); | |
199 if (!layer->scroll_parent()) { | |
200 position -= gfx::Vector2dF(layer->TotalScrollOffset().x(), | |
201 layer->TotalScrollOffset().y()); | |
202 } | |
203 | |
204 position += parent_offset; | |
205 | |
206 transform.Translate3d(position.x() + layer->transform_origin().x(), | |
207 position.y() + layer->transform_origin().y(), | |
208 layer->transform_origin().z()); | |
209 transform.PreconcatTransform(layer->transform()); | |
210 transform.Translate3d(-layer->transform_origin().x(), | |
211 -layer->transform_origin().y(), | |
212 -layer->transform_origin().z()); | |
213 | |
214 node->data.to_parent = transform; | |
215 node->data.is_invertible = transform.GetInverse(&node->data.from_parent); | |
216 | |
217 UpdateScreenSpaceTransform(data_from_ancestor.transform_tree, node->id); | |
218 | |
219 layer->set_offset_to_transform_parent(gfx::Vector2dF()); | |
220 layer->set_transform_tree_index(node->id); | |
221 } | |
222 | |
223 void BuildPropertyTreesInternal(Layer* layer, | |
224 const DataForRecursion& data_from_parent) { | |
225 DataForRecursion data_for_children(data_from_parent); | |
226 if (layer->render_surface()) | |
227 data_for_children.render_target = layer; | |
228 | |
229 AddTransformNodeIfNeeded(data_from_parent, layer, &data_for_children); | |
230 AddClipNodeIfNeeded(data_from_parent, layer, &data_for_children); | |
231 | |
232 for (size_t i = 0; i < layer->children().size(); ++i) { | |
233 if (!layer->children()[i]->scroll_parent()) | |
234 BuildPropertyTreesInternal(layer->children()[i].get(), data_for_children); | |
235 } | |
236 | |
237 if (layer->scroll_children()) { | |
238 for (Layer* scroll_child : *layer->scroll_children()) { | |
239 BuildPropertyTreesInternal(scroll_child, data_for_children); | |
240 } | |
241 } | |
242 | |
243 if (layer->has_replica()) | |
244 BuildPropertyTreesInternal(layer->replica_layer(), data_for_children); | |
245 } | |
246 | |
247 } // namespace | |
248 | |
249 void PropertyTreeBuilder::BuildPropertyTrees( | |
250 Layer* root_layer, | |
251 const Layer* page_scale_layer, | |
252 float page_scale_factor, | |
253 float device_scale_factor, | |
254 const gfx::Rect& viewport, | |
255 const gfx::Transform& device_transform, | |
256 TransformTree* transform_tree, | |
257 ClipTree* clip_tree) { | |
258 DataForRecursion data_for_recursion; | |
259 data_for_recursion.transform_tree = transform_tree; | |
260 data_for_recursion.clip_tree = clip_tree; | |
261 data_for_recursion.transform_tree_parent = nullptr; | |
262 data_for_recursion.transform_fixed_parent = nullptr; | |
263 data_for_recursion.render_target = root_layer; | |
264 data_for_recursion.clip_tree_parent = 0; | |
265 data_for_recursion.page_scale_layer = page_scale_layer; | |
266 data_for_recursion.page_scale_factor = page_scale_factor; | |
267 data_for_recursion.device_scale_factor = device_scale_factor; | |
268 | |
269 int transform_root_id = 0; | |
270 int clip_root_id = 0; | |
271 | |
272 // We only need to clip the root if we have a non-empty viewport. The root of | |
enne (OOO)
2014/12/10 23:46:00
When is the viewport empty?
Ian Vollick
2014/12/12 03:01:47
This happens in unit tests and the assumption ther
enne (OOO)
2014/12/12 19:05:49
Can you leave a comment saying that empty viewport
Ian Vollick
2014/12/15 21:45:17
This is now unnecessary due to hush's patch. Remov
| |
273 // the clip tree does not clip, so we need to add another node in this case. | |
274 if (!viewport.IsEmpty()) { | |
275 data_for_recursion.clip_tree_parent = clip_tree->Insert(ClipNode(), 0); | |
276 clip_root_id = data_for_recursion.clip_tree_parent; | |
277 } | |
278 | |
279 BuildPropertyTreesInternal(root_layer, data_for_recursion); | |
280 | |
281 TransformNode* transform_root = transform_tree->Node(transform_root_id); | |
282 ClipNode* clip_root = clip_tree->Node(clip_root_id); | |
283 | |
284 gfx::Transform combined_transform = | |
285 device_transform * transform_root->data.to_parent; | |
enne (OOO)
2014/12/10 23:45:59
Is this ever not identity? Doesn't the transform r
Ian Vollick
2014/12/12 03:01:47
The dsf (and device transform) are applied to the
Ian Vollick
2014/12/15 21:45:17
I've added an extra "super root" to the transform
| |
286 | |
287 transform_root->data.set_to_parent(combined_transform); | |
288 gfx::RectF transformed_viewport = viewport; | |
289 | |
290 if (!combined_transform.IsIdentity()) { | |
291 gfx::Transform inverse_transform; | |
292 if (!combined_transform.GetInverse(&inverse_transform)) { | |
293 // If we have an univertible transform, then we clip off the entire | |
294 // subtree. | |
295 transformed_viewport = gfx::RectF(); | |
296 } else { | |
297 transformed_viewport = | |
298 MathUtil::ProjectClippedRect(inverse_transform, viewport); | |
299 } | |
300 } | |
301 | |
302 clip_root->data.clip = transformed_viewport; | |
enne (OOO)
2014/12/10 23:46:00
Why do you need to inverse transform the viewport
Ian Vollick
2014/12/12 03:01:47
To get to screen space (where this clip is applied
enne (OOO)
2014/12/12 19:05:49
Hmm. Maybe I just figured that this function woul
Ian Vollick
2014/12/15 21:45:17
Now that we have the super root, we don't need to
| |
303 clip_root->data.transform_id = transform_root->id; | |
304 } | |
305 | |
306 } // namespace cc | |
OLD | NEW |