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 | 6 |
7 #include "base/logging.h" | 7 #include "base/logging.h" |
| 8 #include "cc/base/math_util.h" |
8 #include "cc/trees/property_tree.h" | 9 #include "cc/trees/property_tree.h" |
9 | 10 |
10 namespace cc { | 11 namespace cc { |
11 | 12 |
12 template <typename T> | 13 template <typename T> |
13 PropertyTree<T>::PropertyTree() { | 14 PropertyTree<T>::PropertyTree() { |
14 nodes_.push_back(T()); | 15 nodes_.push_back(T()); |
15 back()->id = 0; | 16 back()->id = 0; |
16 back()->parent_id = -1; | 17 back()->parent_id = -1; |
17 } | 18 } |
(...skipping 10 matching lines...) Expand all Loading... |
28 node.parent_id = parent_id; | 29 node.parent_id = parent_id; |
29 node.id = static_cast<int>(nodes_.size()) - 1; | 30 node.id = static_cast<int>(nodes_.size()) - 1; |
30 return node.id; | 31 return node.id; |
31 } | 32 } |
32 | 33 |
33 template class PropertyTree<TransformNode>; | 34 template class PropertyTree<TransformNode>; |
34 template class PropertyTree<ClipNode>; | 35 template class PropertyTree<ClipNode>; |
35 | 36 |
36 TransformNodeData::TransformNodeData() | 37 TransformNodeData::TransformNodeData() |
37 : target_id(-1), | 38 : target_id(-1), |
| 39 content_target_id(-1), |
| 40 needs_local_transform_update(true), |
38 is_invertible(true), | 41 is_invertible(true), |
39 ancestors_are_invertible(true), | 42 ancestors_are_invertible(true), |
40 is_animated(false), | 43 is_animated(false), |
41 to_screen_is_animated(false), | 44 to_screen_is_animated(false), |
42 flattens(false) { | 45 flattens(false), |
| 46 scrolls(false), |
| 47 needs_sublayer_scale(false), |
| 48 layer_scale_factor(1.0f) { |
43 } | 49 } |
44 | 50 |
45 TransformNodeData::~TransformNodeData() { | 51 TransformNodeData::~TransformNodeData() { |
46 } | 52 } |
47 | 53 |
48 ClipNodeData::ClipNodeData() : transform_id(-1), target_id(-1) { | 54 ClipNodeData::ClipNodeData() : transform_id(-1), target_id(-1) { |
49 } | 55 } |
50 | 56 |
51 bool TransformTree::ComputeTransform(int source_id, | 57 bool TransformTree::ComputeTransform(int source_id, |
52 int dest_id, | 58 int dest_id, |
(...skipping 19 matching lines...) Expand all Loading... |
72 | 78 |
73 return no_singular_matrices_to_lca && no_singular_matrices_from_lca; | 79 return no_singular_matrices_to_lca && no_singular_matrices_from_lca; |
74 } | 80 } |
75 | 81 |
76 bool TransformTree::Are2DAxisAligned(int source_id, int dest_id) const { | 82 bool TransformTree::Are2DAxisAligned(int source_id, int dest_id) const { |
77 gfx::Transform transform; | 83 gfx::Transform transform; |
78 return ComputeTransform(source_id, dest_id, &transform) && | 84 return ComputeTransform(source_id, dest_id, &transform) && |
79 transform.Preserves2dAxisAlignment(); | 85 transform.Preserves2dAxisAlignment(); |
80 } | 86 } |
81 | 87 |
82 void TransformTree::UpdateScreenSpaceTransform(int id) { | 88 void TransformTree::UpdateTransforms(int id) { |
83 TransformNode* current_node = Node(id); | 89 TransformNode* node = Node(id); |
84 TransformNode* parent_node = parent(current_node); | 90 TransformNode* parent_node = parent(node); |
85 TransformNode* target_node = Node(current_node->data.target_id); | 91 TransformNode* target_node = Node(node->data.target_id); |
86 | 92 if (node->data.needs_local_transform_update) |
87 if (!parent_node) { | 93 UpdateLocalTransform(node); |
88 current_node->data.to_screen = current_node->data.to_parent; | 94 UpdateLocalTransform(node); |
89 current_node->data.ancestors_are_invertible = true; | 95 UpdateScreenSpaceTransform(node, parent_node, target_node); |
90 current_node->data.to_screen_is_animated = false; | 96 UpdateSublayerScale(node); |
91 } else if (parent_node->data.flattens) { | 97 UpdateTargetSpaceTransform(node, target_node); |
92 // Flattening is tricky. Once a layer is drawn into its render target, it | 98 UpdateIsAnimated(node, parent_node); |
93 // cannot escape, so we only need to consider transforms between the layer | 99 UpdateSnapping(node); |
94 // and its target when flattening (i.e., its draw transform). To compute the | |
95 // screen space transform when flattening is involved we combine three | |
96 // transforms, A * B * C, where A is the screen space transform of the | |
97 // target, B is the flattened draw transform of the layer's parent, and C is | |
98 // the local transform. | |
99 current_node->data.to_screen = target_node->data.to_screen; | |
100 gfx::Transform flattened; | |
101 ComputeTransform(parent_node->id, target_node->id, &flattened); | |
102 flattened.FlattenTo2d(); | |
103 current_node->data.to_screen.PreconcatTransform(flattened); | |
104 current_node->data.to_screen.PreconcatTransform( | |
105 current_node->data.to_parent); | |
106 current_node->data.ancestors_are_invertible = | |
107 parent_node->data.ancestors_are_invertible; | |
108 } else { | |
109 current_node->data.to_screen = parent_node->data.to_screen; | |
110 current_node->data.to_screen.PreconcatTransform( | |
111 current_node->data.to_parent); | |
112 current_node->data.ancestors_are_invertible = | |
113 parent_node->data.ancestors_are_invertible; | |
114 } | |
115 if (!current_node->data.to_screen.GetInverse(¤t_node->data.from_screen)) | |
116 current_node->data.ancestors_are_invertible = false; | |
117 | |
118 if (parent_node) { | |
119 current_node->data.to_screen_is_animated = | |
120 current_node->data.is_animated || | |
121 parent_node->data.to_screen_is_animated; | |
122 } | |
123 } | 100 } |
124 | 101 |
125 bool TransformTree::IsDescendant(int desc_id, int source_id) const { | 102 bool TransformTree::IsDescendant(int desc_id, int source_id) const { |
126 while (desc_id != source_id) { | 103 while (desc_id != source_id) { |
127 if (desc_id < 0) | 104 if (desc_id < 0) |
128 return false; | 105 return false; |
129 desc_id = Node(desc_id)->parent_id; | 106 desc_id = Node(desc_id)->parent_id; |
130 } | 107 } |
131 return true; | 108 return true; |
132 } | 109 } |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
189 bool all_are_invertible = true; | 166 bool all_are_invertible = true; |
190 for (; current && current->id > source_id; current = parent(current)) { | 167 for (; current && current->id > source_id; current = parent(current)) { |
191 transform->PreconcatTransform(current->data.from_parent); | 168 transform->PreconcatTransform(current->data.from_parent); |
192 if (!current->data.is_invertible) | 169 if (!current->data.is_invertible) |
193 all_are_invertible = false; | 170 all_are_invertible = false; |
194 } | 171 } |
195 | 172 |
196 return all_are_invertible; | 173 return all_are_invertible; |
197 } | 174 } |
198 | 175 |
| 176 void TransformTree::UpdateLocalTransform(TransformNode* node) { |
| 177 gfx::Transform transform = node->data.post_local; |
| 178 transform.Translate(-node->data.scroll_offset.x(), |
| 179 -node->data.scroll_offset.y()); |
| 180 transform.PreconcatTransform(node->data.local); |
| 181 transform.PreconcatTransform(node->data.pre_local); |
| 182 node->data.set_to_parent(transform); |
| 183 node->data.needs_local_transform_update = false; |
| 184 } |
| 185 |
| 186 void TransformTree::UpdateScreenSpaceTransform(TransformNode* node, |
| 187 TransformNode* parent_node, |
| 188 TransformNode* target_node) { |
| 189 if (!parent_node) { |
| 190 node->data.to_screen = node->data.to_parent; |
| 191 node->data.ancestors_are_invertible = true; |
| 192 node->data.to_screen_is_animated = false; |
| 193 } else if (parent_node->data.flattens) { |
| 194 // Flattening is tricky. Once a layer is drawn into its render target, it |
| 195 // cannot escape, so we only need to consider transforms between the layer |
| 196 // and its target when flattening (i.e., its draw transform). To compute the |
| 197 // screen space transform when flattening is involved we combine three |
| 198 // transforms, A * B * C, where A is the screen space transform of the |
| 199 // target, B is the flattened draw transform of the layer's parent, and C is |
| 200 // the local transform. |
| 201 node->data.to_screen = target_node->data.to_screen; |
| 202 gfx::Transform flattened; |
| 203 ComputeTransform(parent_node->id, target_node->id, &flattened); |
| 204 flattened.FlattenTo2d(); |
| 205 node->data.to_screen.PreconcatTransform(flattened); |
| 206 node->data.to_screen.PreconcatTransform(node->data.to_parent); |
| 207 node->data.ancestors_are_invertible = |
| 208 parent_node->data.ancestors_are_invertible; |
| 209 } else { |
| 210 node->data.to_screen = parent_node->data.to_screen; |
| 211 node->data.to_screen.PreconcatTransform(node->data.to_parent); |
| 212 node->data.ancestors_are_invertible = |
| 213 parent_node->data.ancestors_are_invertible; |
| 214 } |
| 215 |
| 216 if (!node->data.to_screen.GetInverse(&node->data.from_screen)) |
| 217 node->data.ancestors_are_invertible = false; |
| 218 } |
| 219 |
| 220 void TransformTree::UpdateSublayerScale(TransformNode* node) { |
| 221 // The sublayer scale depends on the screen space transform, so update it too. |
| 222 node->data.sublayer_scale = |
| 223 node->data.needs_sublayer_scale |
| 224 ? MathUtil::ComputeTransform2dScaleComponents( |
| 225 node->data.to_screen, node->data.layer_scale_factor) |
| 226 : gfx::Vector2dF(1.0f, 1.0f); |
| 227 } |
| 228 |
| 229 void TransformTree::UpdateTargetSpaceTransform(TransformNode* node, |
| 230 TransformNode* target_node) { |
| 231 node->data.to_target.MakeIdentity(); |
| 232 if (node->data.needs_sublayer_scale) { |
| 233 node->data.to_target.Scale(node->data.sublayer_scale.x(), |
| 234 node->data.sublayer_scale.y()); |
| 235 } else { |
| 236 const bool target_is_root_surface = target_node->id == 1; |
| 237 // In order to include the root transform for the root surface, we walk up |
| 238 // to the root of the transform tree in ComputeTransform. |
| 239 int target_id = target_is_root_surface ? 0 : target_node->id; |
| 240 if (target_node) { |
| 241 node->data.to_target.Scale(target_node->data.sublayer_scale.x(), |
| 242 target_node->data.sublayer_scale.y()); |
| 243 } |
| 244 |
| 245 gfx::Transform unscaled_target_transform; |
| 246 ComputeTransform(node->id, target_id, &unscaled_target_transform); |
| 247 node->data.to_target.PreconcatTransform(unscaled_target_transform); |
| 248 } |
| 249 |
| 250 if (!node->data.to_target.GetInverse(&node->data.from_target)) |
| 251 node->data.ancestors_are_invertible = false; |
| 252 } |
| 253 |
| 254 void TransformTree::UpdateIsAnimated(TransformNode* node, |
| 255 TransformNode* parent_node) { |
| 256 if (parent_node) { |
| 257 node->data.to_screen_is_animated = |
| 258 node->data.is_animated || parent_node->data.to_screen_is_animated; |
| 259 } |
| 260 } |
| 261 |
| 262 void TransformTree::UpdateSnapping(TransformNode* node) { |
| 263 if (!node->data.scrolls || node->data.to_screen_is_animated || |
| 264 !node->data.to_target.IsScaleOrTranslation()) { |
| 265 return; |
| 266 } |
| 267 |
| 268 // Scroll snapping must be done in target space (the pixels we care about). |
| 269 // This means we effectively snap the target space transform. If TT is the |
| 270 // target space transform and TT' is TT with its translation components |
| 271 // rounded, then what we're after is the scroll delta X, where TT * X = TT'. |
| 272 // I.e., we want a transform that will realize our scroll snap. It follows |
| 273 // that X = TT^-1 * TT'. We cache TT and TT^-1 to make this more efficient. |
| 274 gfx::Transform rounded = node->data.to_target; |
| 275 rounded.RoundTranslationComponents(); |
| 276 gfx::Transform delta = node->data.from_target; |
| 277 delta *= rounded; |
| 278 gfx::Transform inverse_delta(gfx::Transform::kSkipInitialization); |
| 279 bool invertible_delta = delta.GetInverse(&inverse_delta); |
| 280 |
| 281 // The delta should be a translation, modulo floating point error, and should |
| 282 // therefore be invertible. |
| 283 DCHECK(invertible_delta); |
| 284 |
| 285 // Now that we have our scroll delta, we must apply it to each of our |
| 286 // combined, to/from matrices. |
| 287 node->data.to_parent.PreconcatTransform(delta); |
| 288 node->data.from_parent.ConcatTransform(inverse_delta); |
| 289 node->data.to_target.PreconcatTransform(delta); |
| 290 node->data.from_target.ConcatTransform(inverse_delta); |
| 291 node->data.to_screen.PreconcatTransform(delta); |
| 292 node->data.from_screen.ConcatTransform(inverse_delta); |
| 293 } |
| 294 |
199 } // namespace cc | 295 } // namespace cc |
OLD | NEW |