OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include <set> | 5 #include <set> |
| 6 #include <vector> |
6 | 7 |
7 #include "base/logging.h" | 8 #include "base/logging.h" |
8 #include "cc/base/math_util.h" | 9 #include "cc/base/math_util.h" |
9 #include "cc/trees/property_tree.h" | 10 #include "cc/trees/property_tree.h" |
10 | 11 |
11 namespace cc { | 12 namespace cc { |
12 | 13 |
13 template <typename T> | 14 template <typename T> |
14 PropertyTree<T>::PropertyTree() { | 15 PropertyTree<T>::PropertyTree() { |
15 nodes_.push_back(T()); | 16 nodes_.push_back(T()); |
(...skipping 21 matching lines...) Expand all Loading... |
37 | 38 |
38 TransformNodeData::TransformNodeData() | 39 TransformNodeData::TransformNodeData() |
39 : target_id(-1), | 40 : target_id(-1), |
40 content_target_id(-1), | 41 content_target_id(-1), |
41 needs_local_transform_update(true), | 42 needs_local_transform_update(true), |
42 is_invertible(true), | 43 is_invertible(true), |
43 ancestors_are_invertible(true), | 44 ancestors_are_invertible(true), |
44 is_animated(false), | 45 is_animated(false), |
45 to_screen_is_animated(false), | 46 to_screen_is_animated(false), |
46 flattens_inherited_transform(false), | 47 flattens_inherited_transform(false), |
47 flattens_local_transform(false), | 48 node_and_ancestors_are_flat(true), |
48 scrolls(false), | 49 scrolls(false), |
49 needs_sublayer_scale(false), | 50 needs_sublayer_scale(false), |
50 layer_scale_factor(1.0f) { | 51 layer_scale_factor(1.0f) { |
51 } | 52 } |
52 | 53 |
53 TransformNodeData::~TransformNodeData() { | 54 TransformNodeData::~TransformNodeData() { |
54 } | 55 } |
55 | 56 |
56 ClipNodeData::ClipNodeData() : transform_id(-1), target_id(-1) { | 57 ClipNodeData::ClipNodeData() : transform_id(-1), target_id(-1) { |
57 } | 58 } |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
128 } | 129 } |
129 NOTREACHED(); | 130 NOTREACHED(); |
130 return 0; | 131 return 0; |
131 } | 132 } |
132 | 133 |
133 bool TransformTree::CombineTransformsBetween(int source_id, | 134 bool TransformTree::CombineTransformsBetween(int source_id, |
134 int dest_id, | 135 int dest_id, |
135 gfx::Transform* transform) const { | 136 gfx::Transform* transform) const { |
136 const TransformNode* current = Node(source_id); | 137 const TransformNode* current = Node(source_id); |
137 const TransformNode* dest = Node(dest_id); | 138 const TransformNode* dest = Node(dest_id); |
138 if (!dest || dest->data.ancestors_are_invertible) { | 139 // Combine transforms to and from the screen when possible. Since flattening |
| 140 // is a non-linear operation, we cannot use this approach when there is |
| 141 // non-trivial flattening between the source and destination nodes. For |
| 142 // example, consider the tree R->A->B->C, where B flattens its inherited |
| 143 // transform, and A has a non-flat transform. Suppose C is the source and A is |
| 144 // the destination. The expected result is C * B. But C's to_screen |
| 145 // transform is C * B * flattened(A * R), and A's from_screen transform is |
| 146 // R^{-1} * A^{-1}. If at least one of A and R isn't flat, the inverse of |
| 147 // flattened(A * R) won't be R^{-1} * A{-1}, so multiplying C's to_screen and |
| 148 // A's from_screen will not produce the correct result. |
| 149 if (!dest || (dest->data.ancestors_are_invertible && |
| 150 current->data.node_and_ancestors_are_flat)) { |
139 transform->ConcatTransform(current->data.to_screen); | 151 transform->ConcatTransform(current->data.to_screen); |
140 if (dest) | 152 if (dest) |
141 transform->ConcatTransform(dest->data.from_screen); | 153 transform->ConcatTransform(dest->data.from_screen); |
142 return true; | 154 return true; |
143 } | 155 } |
144 | 156 |
145 bool all_are_invertible = true; | 157 bool all_are_invertible = true; |
| 158 |
| 159 // Flattening is defined in a way that requires it to be applied while |
| 160 // traversing downward in the tree. We first identify nodes that are on the |
| 161 // path from the source to the destination (this is traversing upward), and |
| 162 // then we visit these nodes in reverse order, flattening as needed. We |
| 163 // early-out if we get to a node whose target node is the destination, since |
| 164 // we can then re-use the target space transform stored at that node. |
| 165 std::vector<int> source_to_destination; |
| 166 source_to_destination.push_back(current->id); |
| 167 current = parent(current); |
146 for (; current && current->id > dest_id; current = parent(current)) { | 168 for (; current && current->id > dest_id; current = parent(current)) { |
147 transform->ConcatTransform(current->data.to_parent); | 169 if (current->data.target_id == dest_id && |
148 if (!current->data.is_invertible) | 170 current->data.content_target_id == dest_id) |
| 171 break; |
| 172 source_to_destination.push_back(current->id); |
| 173 } |
| 174 |
| 175 gfx::Transform combined_transform; |
| 176 if (current->id > dest_id) { |
| 177 combined_transform = current->data.to_target; |
| 178 // The stored target space transform has sublayer scale baked in, but we |
| 179 // need the unscaled transform. |
| 180 combined_transform.Scale(1.0f / dest->data.sublayer_scale.x(), |
| 181 1.0f / dest->data.sublayer_scale.y()); |
| 182 } |
| 183 |
| 184 for (int i = source_to_destination.size() - 1; i >= 0; i--) { |
| 185 const TransformNode* node = Node(source_to_destination[i]); |
| 186 if (node->data.flattens_inherited_transform) |
| 187 combined_transform.FlattenTo2d(); |
| 188 combined_transform.PreconcatTransform(node->data.to_parent); |
| 189 |
| 190 if (!node->data.is_invertible) |
149 all_are_invertible = false; | 191 all_are_invertible = false; |
150 } | 192 } |
151 | 193 |
| 194 transform->ConcatTransform(combined_transform); |
152 return all_are_invertible; | 195 return all_are_invertible; |
153 } | 196 } |
154 | 197 |
155 bool TransformTree::CombineInversesBetween(int source_id, | 198 bool TransformTree::CombineInversesBetween(int source_id, |
156 int dest_id, | 199 int dest_id, |
157 gfx::Transform* transform) const { | 200 gfx::Transform* transform) const { |
158 const TransformNode* current = Node(dest_id); | 201 const TransformNode* current = Node(dest_id); |
159 const TransformNode* dest = Node(source_id); | 202 const TransformNode* dest = Node(source_id); |
160 if (current->data.ancestors_are_invertible) { | 203 // Just as in CombineTransformsBetween, we can use screen space transforms in |
| 204 // this computation only when there isn't any non-trivial flattening |
| 205 // involved. |
| 206 if (current->data.ancestors_are_invertible && |
| 207 current->data.node_and_ancestors_are_flat) { |
161 transform->PreconcatTransform(current->data.from_screen); | 208 transform->PreconcatTransform(current->data.from_screen); |
162 if (dest) | 209 if (dest) |
163 transform->PreconcatTransform(dest->data.to_screen); | 210 transform->PreconcatTransform(dest->data.to_screen); |
164 return true; | 211 return true; |
165 } | 212 } |
166 | 213 |
167 bool all_are_invertible = true; | 214 // Inverting a flattening is not equivalent to flattening an inverse. This |
168 for (; current && current->id > source_id; current = parent(current)) { | 215 // means we cannot, for example, use the inverse of each node's to_parent |
169 transform->PreconcatTransform(current->data.from_parent); | 216 // transform, flattening where needed. Instead, we must compute the transform |
170 if (!current->data.is_invertible) | 217 // from the destination to the source, with flattening, and then invert the |
171 all_are_invertible = false; | 218 // result. |
172 } | 219 gfx::Transform dest_to_source; |
173 | 220 CombineTransformsBetween(dest_id, source_id, &dest_to_source); |
| 221 gfx::Transform source_to_dest; |
| 222 bool all_are_invertible = dest_to_source.GetInverse(&source_to_dest); |
| 223 transform->PreconcatTransform(source_to_dest); |
174 return all_are_invertible; | 224 return all_are_invertible; |
175 } | 225 } |
176 | 226 |
177 void TransformTree::UpdateLocalTransform(TransformNode* node) { | 227 void TransformTree::UpdateLocalTransform(TransformNode* node) { |
178 gfx::Transform transform = node->data.post_local; | 228 gfx::Transform transform = node->data.post_local; |
179 transform.Translate(-node->data.scroll_offset.x(), | 229 transform.Translate(-node->data.scroll_offset.x(), |
180 -node->data.scroll_offset.y()); | 230 -node->data.scroll_offset.y()); |
181 transform.PreconcatTransform(node->data.local); | 231 transform.PreconcatTransform(node->data.local); |
182 transform.PreconcatTransform(node->data.pre_local); | 232 transform.PreconcatTransform(node->data.pre_local); |
183 node->data.set_to_parent(transform); | 233 node->data.set_to_parent(transform); |
184 node->data.needs_local_transform_update = false; | 234 node->data.needs_local_transform_update = false; |
185 } | 235 } |
186 | 236 |
187 void TransformTree::UpdateScreenSpaceTransform(TransformNode* node, | 237 void TransformTree::UpdateScreenSpaceTransform(TransformNode* node, |
188 TransformNode* parent_node, | 238 TransformNode* parent_node, |
189 TransformNode* target_node) { | 239 TransformNode* target_node) { |
190 if (!parent_node) { | 240 if (!parent_node) { |
191 node->data.to_screen = node->data.to_parent; | 241 node->data.to_screen = node->data.to_parent; |
192 node->data.ancestors_are_invertible = true; | 242 node->data.ancestors_are_invertible = true; |
193 node->data.to_screen_is_animated = false; | 243 node->data.to_screen_is_animated = false; |
194 } else if (parent_node->data.flattens_local_transform || | 244 node->data.node_and_ancestors_are_flat = node->data.to_parent.IsFlat(); |
195 node->data.flattens_inherited_transform) { | 245 } else { |
196 // Flattening is tricky. Once a layer is drawn into its render target, it | 246 node->data.to_screen = parent_node->data.to_screen; |
197 // cannot escape, so we only need to consider transforms between the layer | 247 if (node->data.flattens_inherited_transform) |
198 // and its target when flattening (i.e., its draw transform). To compute the | 248 node->data.to_screen.FlattenTo2d(); |
199 // screen space transform when flattening is involved we combine three | |
200 // transforms, A * B * C, where A is the screen space transform of the | |
201 // target, B is the flattened draw transform of the layer's parent, and C is | |
202 // the local transform. | |
203 node->data.to_screen = target_node->data.to_screen; | |
204 gfx::Transform flattened; | |
205 ComputeTransform(parent_node->id, target_node->id, &flattened); | |
206 flattened.FlattenTo2d(); | |
207 node->data.to_screen.PreconcatTransform(flattened); | |
208 node->data.to_screen.PreconcatTransform(node->data.to_parent); | 249 node->data.to_screen.PreconcatTransform(node->data.to_parent); |
209 node->data.ancestors_are_invertible = | 250 node->data.ancestors_are_invertible = |
210 parent_node->data.ancestors_are_invertible; | 251 parent_node->data.ancestors_are_invertible; |
211 } else { | 252 node->data.node_and_ancestors_are_flat = |
212 node->data.to_screen = parent_node->data.to_screen; | 253 parent_node->data.node_and_ancestors_are_flat && |
213 node->data.to_screen.PreconcatTransform(node->data.to_parent); | 254 node->data.to_parent.IsFlat(); |
214 node->data.ancestors_are_invertible = | |
215 parent_node->data.ancestors_are_invertible; | |
216 } | 255 } |
217 | 256 |
218 if (!node->data.to_screen.GetInverse(&node->data.from_screen)) | 257 if (!node->data.to_screen.GetInverse(&node->data.from_screen)) |
219 node->data.ancestors_are_invertible = false; | 258 node->data.ancestors_are_invertible = false; |
220 } | 259 } |
221 | 260 |
222 void TransformTree::UpdateSublayerScale(TransformNode* node) { | 261 void TransformTree::UpdateSublayerScale(TransformNode* node) { |
223 // The sublayer scale depends on the screen space transform, so update it too. | 262 // The sublayer scale depends on the screen space transform, so update it too. |
224 node->data.sublayer_scale = | 263 node->data.sublayer_scale = |
225 node->data.needs_sublayer_scale | 264 node->data.needs_sublayer_scale |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
280 gfx::Transform inverse_delta(gfx::Transform::kSkipInitialization); | 319 gfx::Transform inverse_delta(gfx::Transform::kSkipInitialization); |
281 bool invertible_delta = delta.GetInverse(&inverse_delta); | 320 bool invertible_delta = delta.GetInverse(&inverse_delta); |
282 | 321 |
283 // The delta should be a translation, modulo floating point error, and should | 322 // The delta should be a translation, modulo floating point error, and should |
284 // therefore be invertible. | 323 // therefore be invertible. |
285 DCHECK(invertible_delta); | 324 DCHECK(invertible_delta); |
286 | 325 |
287 // Now that we have our scroll delta, we must apply it to each of our | 326 // Now that we have our scroll delta, we must apply it to each of our |
288 // combined, to/from matrices. | 327 // combined, to/from matrices. |
289 node->data.to_parent.PreconcatTransform(delta); | 328 node->data.to_parent.PreconcatTransform(delta); |
290 node->data.from_parent.ConcatTransform(inverse_delta); | |
291 node->data.to_target.PreconcatTransform(delta); | 329 node->data.to_target.PreconcatTransform(delta); |
292 node->data.from_target.ConcatTransform(inverse_delta); | 330 node->data.from_target.ConcatTransform(inverse_delta); |
293 node->data.to_screen.PreconcatTransform(delta); | 331 node->data.to_screen.PreconcatTransform(delta); |
294 node->data.from_screen.ConcatTransform(inverse_delta); | 332 node->data.from_screen.ConcatTransform(inverse_delta); |
295 } | 333 } |
296 | 334 |
297 } // namespace cc | 335 } // namespace cc |
OLD | NEW |