OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "platform/graphics/paint/GeometryMapper.h" | 5 #include "platform/graphics/paint/GeometryMapper.h" |
6 | 6 |
7 #include "platform/RuntimeEnabledFeatures.h" | 7 #include "platform/RuntimeEnabledFeatures.h" |
8 #include "platform/geometry/LayoutRect.h" | 8 #include "platform/geometry/LayoutRect.h" |
9 | 9 |
10 namespace blink { | 10 namespace blink { |
11 | 11 |
12 FloatRect GeometryMapper::mapToVisualRectInDestinationSpace( | 12 FloatRect GeometryMapper::mapToVisualRectInDestinationSpace( |
13 const FloatRect& rect, | 13 const FloatRect& rect, |
14 const PropertyTreeState& sourceState, | 14 const PropertyTreeState& sourceState, |
15 const PropertyTreeState& destinationState, | 15 const PropertyTreeState& destinationState, |
16 bool& success) { | 16 bool& success) { |
17 if (sourceState == destinationState) { | |
18 success = true; | |
19 return rect; | |
20 } | |
21 FloatRect result = localToVisualRectInAncestorSpace( | 17 FloatRect result = localToVisualRectInAncestorSpace( |
22 rect, sourceState, destinationState, success); | 18 rect, sourceState, destinationState, success); |
23 if (success) | 19 if (success) |
24 return result; | 20 return result; |
25 return slowMapToVisualRectInDestinationSpace(rect, sourceState, | 21 return slowMapToVisualRectInDestinationSpace(rect, sourceState, |
26 destinationState, success); | 22 destinationState, success); |
27 } | 23 } |
28 | 24 |
29 FloatRect GeometryMapper::mapRectToDestinationSpace( | 25 FloatRect GeometryMapper::mapRectToDestinationSpace( |
30 const FloatRect& rect, | 26 const FloatRect& rect, |
31 const PropertyTreeState& sourceState, | 27 const PropertyTreeState& sourceState, |
32 const PropertyTreeState& destinationState, | 28 const PropertyTreeState& destinationState, |
33 bool& success) { | 29 bool& success) { |
34 if (sourceState == destinationState) { | |
35 success = true; | |
36 return rect; | |
37 } | |
38 FloatRect result = | 30 FloatRect result = |
39 localToAncestorRect(rect, sourceState, destinationState, success); | 31 localToAncestorRect(rect, sourceState, destinationState, success); |
40 if (success) | 32 if (success) |
41 return result; | 33 return result; |
42 return slowMapRectToDestinationSpace(rect, sourceState, destinationState, | 34 return slowMapRectToDestinationSpace(rect, sourceState, destinationState, |
43 success); | 35 success); |
44 } | 36 } |
45 | 37 |
46 FloatRect GeometryMapper::slowMapToVisualRectInDestinationSpace( | 38 FloatRect GeometryMapper::slowMapToVisualRectInDestinationSpace( |
47 const FloatRect& rect, | 39 const FloatRect& rect, |
(...skipping 11 matching lines...) Expand all Loading... |
59 lcaState.setTransform(lcaTransform); | 51 lcaState.setTransform(lcaTransform); |
60 | 52 |
61 const auto clipRect = localToAncestorClipRect(sourceState, lcaState, success); | 53 const auto clipRect = localToAncestorClipRect(sourceState, lcaState, success); |
62 if (!success) | 54 if (!success) |
63 return rect; | 55 return rect; |
64 | 56 |
65 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); | 57 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); |
66 DCHECK(success); | 58 DCHECK(success); |
67 result.intersect(clipRect); | 59 result.intersect(clipRect); |
68 | 60 |
69 const TransformationMatrix& destinationToLca = | 61 return ancestorToLocalRect(result, destinationState, lcaState, success); |
70 localToAncestorMatrix(destinationState.transform(), lcaState, success); | |
71 DCHECK(success); | |
72 if (destinationToLca.isInvertible()) { | |
73 success = true; | |
74 return destinationToLca.inverse().mapRect(result); | |
75 } | |
76 success = false; | |
77 return rect; | |
78 } | 62 } |
79 | 63 |
80 FloatRect GeometryMapper::slowMapRectToDestinationSpace( | 64 FloatRect GeometryMapper::slowMapRectToDestinationSpace( |
81 const FloatRect& rect, | 65 const FloatRect& rect, |
82 const PropertyTreeState& sourceState, | 66 const PropertyTreeState& sourceState, |
83 const PropertyTreeState& destinationState, | 67 const PropertyTreeState& destinationState, |
84 bool& success) { | 68 bool& success) { |
85 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( | 69 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( |
86 sourceState.transform(), destinationState.transform()); | 70 sourceState.transform(), destinationState.transform()); |
87 DCHECK(lcaTransform); | 71 DCHECK(lcaTransform); |
88 PropertyTreeState lcaState = sourceState; | 72 PropertyTreeState lcaState = sourceState; |
89 lcaState.setTransform(lcaTransform); | 73 lcaState.setTransform(lcaTransform); |
90 | 74 |
91 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); | 75 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); |
92 DCHECK(success); | 76 DCHECK(success); |
93 | 77 |
94 const TransformationMatrix& destinationToLca = | 78 return ancestorToLocalRect(result, destinationState, lcaState, success); |
95 localToAncestorMatrix(destinationState.transform(), lcaState, success); | |
96 DCHECK(success); | |
97 if (destinationToLca.isInvertible()) { | |
98 success = true; | |
99 return destinationToLca.inverse().mapRect(result); | |
100 } | |
101 success = false; | |
102 return rect; | |
103 } | 79 } |
104 | 80 |
105 FloatRect GeometryMapper::localToVisualRectInAncestorSpace( | 81 FloatRect GeometryMapper::localToVisualRectInAncestorSpace( |
106 const FloatRect& rect, | 82 const FloatRect& rect, |
107 const PropertyTreeState& localState, | 83 const PropertyTreeState& localState, |
108 const PropertyTreeState& ancestorState, | 84 const PropertyTreeState& ancestorState, |
109 bool& success) { | 85 bool& success) { |
| 86 if (localState == ancestorState) { |
| 87 success = true; |
| 88 return rect; |
| 89 } |
| 90 |
110 const auto& transformMatrix = | 91 const auto& transformMatrix = |
111 localToAncestorMatrix(localState.transform(), ancestorState, success); | 92 localToAncestorMatrix(localState.transform(), ancestorState, success); |
112 if (!success) | 93 if (!success) |
113 return rect; | 94 return rect; |
114 | 95 |
115 FloatRect mappedRect = transformMatrix.mapRect(rect); | 96 FloatRect mappedRect = transformMatrix.mapRect(rect); |
116 | 97 |
117 const auto clipRect = | 98 const auto clipRect = |
118 localToAncestorClipRect(localState, ancestorState, success); | 99 localToAncestorClipRect(localState, ancestorState, success); |
119 | 100 |
(...skipping 12 matching lines...) Expand all Loading... |
132 } | 113 } |
133 | 114 |
134 return mappedRect; | 115 return mappedRect; |
135 } | 116 } |
136 | 117 |
137 FloatRect GeometryMapper::localToAncestorRect( | 118 FloatRect GeometryMapper::localToAncestorRect( |
138 const FloatRect& rect, | 119 const FloatRect& rect, |
139 const PropertyTreeState& localState, | 120 const PropertyTreeState& localState, |
140 const PropertyTreeState& ancestorState, | 121 const PropertyTreeState& ancestorState, |
141 bool& success) { | 122 bool& success) { |
| 123 if (localState.transform() == ancestorState.transform()) { |
| 124 success = true; |
| 125 return rect; |
| 126 } |
| 127 |
142 const auto& transformMatrix = | 128 const auto& transformMatrix = |
143 localToAncestorMatrix(localState.transform(), ancestorState, success); | 129 localToAncestorMatrix(localState.transform(), ancestorState, success); |
144 if (!success) | 130 if (!success) |
145 return rect; | 131 return rect; |
146 return transformMatrix.mapRect(rect); | 132 return transformMatrix.mapRect(rect); |
147 } | 133 } |
148 | 134 |
149 FloatRect GeometryMapper::ancestorToLocalRect( | 135 FloatRect GeometryMapper::ancestorToLocalRect( |
150 const FloatRect& rect, | 136 const FloatRect& rect, |
151 const PropertyTreeState& localState, | 137 const PropertyTreeState& localState, |
152 const PropertyTreeState& ancestorState, | 138 const PropertyTreeState& ancestorState, |
153 bool& success) { | 139 bool& success) { |
| 140 if (localState.transform() == ancestorState.transform()) { |
| 141 success = true; |
| 142 return rect; |
| 143 } |
| 144 |
154 const auto& transformMatrix = | 145 const auto& transformMatrix = |
155 localToAncestorMatrix(localState.transform(), ancestorState, success); | 146 localToAncestorMatrix(localState.transform(), ancestorState, success); |
156 if (!success) | 147 if (!success) |
157 return rect; | 148 return rect; |
158 | 149 |
159 if (!transformMatrix.isInvertible()) { | 150 if (!transformMatrix.isInvertible()) { |
160 success = false; | 151 success = false; |
161 return rect; | 152 return rect; |
162 } | 153 } |
163 success = true; | 154 success = true; |
164 | 155 |
165 // TODO(chrishtr): Cache the inverse? | 156 // TODO(chrishtr): Cache the inverse? |
166 return transformMatrix.inverse().mapRect(rect); | 157 return transformMatrix.inverse().mapRect(rect); |
167 } | 158 } |
168 | 159 |
169 PrecomputedDataForAncestor& GeometryMapper::getPrecomputedDataForAncestor( | 160 PrecomputedDataForAncestor& GeometryMapper::getPrecomputedDataForAncestor( |
170 const PropertyTreeState& ancestorState) { | 161 const PropertyTreeState& ancestorState) { |
171 auto addResult = m_data.add(ancestorState.transform(), nullptr); | 162 auto addResult = m_data.add(ancestorState.transform(), nullptr); |
172 if (addResult.isNewEntry) | 163 if (addResult.isNewEntry) |
173 addResult.storedValue->value = PrecomputedDataForAncestor::create(); | 164 addResult.storedValue->value = PrecomputedDataForAncestor::create(); |
174 return *addResult.storedValue->value; | 165 return *addResult.storedValue->value; |
175 } | 166 } |
176 | 167 |
177 FloatRect GeometryMapper::localToAncestorClipRect( | 168 FloatRect GeometryMapper::localToAncestorClipRect( |
178 const PropertyTreeState& localState, | 169 const PropertyTreeState& localState, |
179 const PropertyTreeState& ancestorState, | 170 const PropertyTreeState& ancestorState, |
180 bool& success) { | 171 bool& success) { |
| 172 FloatRect clip(LayoutRect::infiniteIntRect()); |
| 173 if (localState.clip() == ancestorState.clip()) { |
| 174 success = true; |
| 175 return clip; |
| 176 } |
| 177 |
181 PrecomputedDataForAncestor& precomputedData = | 178 PrecomputedDataForAncestor& precomputedData = |
182 getPrecomputedDataForAncestor(ancestorState); | 179 getPrecomputedDataForAncestor(ancestorState); |
183 const ClipPaintPropertyNode* clipNode = localState.clip(); | 180 const ClipPaintPropertyNode* clipNode = localState.clip(); |
184 Vector<const ClipPaintPropertyNode*> intermediateNodes; | 181 Vector<const ClipPaintPropertyNode*> intermediateNodes; |
185 FloatRect clip(LayoutRect::infiniteIntRect()); | |
186 | 182 |
187 bool found = false; | 183 bool found = false; |
188 // Iterate over the path from localState.clip to ancestorState.clip. Stop if | 184 // Iterate over the path from localState.clip to ancestorState.clip. Stop if |
189 // we've found a memoized (precomputed) clip for any particular node. | 185 // we've found a memoized (precomputed) clip for any particular node. |
190 while (clipNode) { | 186 while (clipNode) { |
191 auto it = precomputedData.toAncestorClipRects.find(clipNode); | 187 auto it = precomputedData.toAncestorClipRects.find(clipNode); |
192 if (it != precomputedData.toAncestorClipRects.end()) { | 188 if (it != precomputedData.toAncestorClipRects.end()) { |
193 clip = it->value; | 189 clip = it->value; |
194 found = true; | 190 found = true; |
195 break; | 191 break; |
(...skipping 28 matching lines...) Expand all Loading... |
224 } | 220 } |
225 | 221 |
226 success = true; | 222 success = true; |
227 return precomputedData.toAncestorClipRects.find(localState.clip())->value; | 223 return precomputedData.toAncestorClipRects.find(localState.clip())->value; |
228 } | 224 } |
229 | 225 |
230 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( | 226 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( |
231 const TransformPaintPropertyNode* localTransformNode, | 227 const TransformPaintPropertyNode* localTransformNode, |
232 const PropertyTreeState& ancestorState, | 228 const PropertyTreeState& ancestorState, |
233 bool& success) { | 229 bool& success) { |
| 230 if (localTransformNode == ancestorState.transform()) { |
| 231 success = true; |
| 232 return m_identity; |
| 233 } |
| 234 |
234 PrecomputedDataForAncestor& precomputedData = | 235 PrecomputedDataForAncestor& precomputedData = |
235 getPrecomputedDataForAncestor(ancestorState); | 236 getPrecomputedDataForAncestor(ancestorState); |
236 | 237 |
237 const TransformPaintPropertyNode* transformNode = localTransformNode; | 238 const TransformPaintPropertyNode* transformNode = localTransformNode; |
238 Vector<const TransformPaintPropertyNode*> intermediateNodes; | 239 Vector<const TransformPaintPropertyNode*> intermediateNodes; |
239 TransformationMatrix transformMatrix; | 240 TransformationMatrix transformMatrix; |
240 | 241 |
241 bool found = false; | |
242 // Iterate over the path from localTransformNode to ancestorState.transform. | 242 // Iterate over the path from localTransformNode to ancestorState.transform. |
243 // Stop if we've found a memoized (precomputed) transform for any particular | 243 // Stop if we've found a memoized (precomputed) transform for any particular |
244 // node. | 244 // node. |
245 while (transformNode) { | 245 while (transformNode) { |
246 auto it = precomputedData.toAncestorTransforms.find(transformNode); | 246 auto it = precomputedData.toAncestorTransforms.find(transformNode); |
247 if (it != precomputedData.toAncestorTransforms.end()) { | 247 if (it != precomputedData.toAncestorTransforms.end()) { |
248 transformMatrix = it->value; | 248 transformMatrix = it->value; |
249 found = true; | |
250 break; | 249 break; |
251 } | 250 } |
252 | 251 |
253 intermediateNodes.push_back(transformNode); | |
254 | |
255 if (transformNode == ancestorState.transform()) | 252 if (transformNode == ancestorState.transform()) |
256 break; | 253 break; |
257 | 254 |
| 255 intermediateNodes.push_back(transformNode); |
258 transformNode = transformNode->parent(); | 256 transformNode = transformNode->parent(); |
259 } | 257 } |
260 if (!found && transformNode != ancestorState.transform()) { | 258 if (!transformNode) { |
261 success = false; | 259 success = false; |
262 return m_identity; | 260 return m_identity; |
263 } | 261 } |
264 | 262 |
265 // Iterate down from the top intermediate node found in the previous loop, | 263 // Iterate down from the top intermediate node found in the previous loop, |
266 // computing and memoizing transforms as we go. | 264 // computing and memoizing transforms as we go. |
267 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); | 265 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); |
268 it++) { | 266 it++) { |
269 if ((*it) != ancestorState.transform()) { | 267 TransformationMatrix localTransformMatrix = (*it)->matrix(); |
270 TransformationMatrix localTransformMatrix = (*it)->matrix(); | 268 localTransformMatrix.applyTransformOrigin((*it)->origin()); |
271 localTransformMatrix.applyTransformOrigin((*it)->origin()); | 269 transformMatrix = transformMatrix * localTransformMatrix; |
272 transformMatrix = transformMatrix * localTransformMatrix; | |
273 } | |
274 | |
275 precomputedData.toAncestorTransforms.set(*it, transformMatrix); | 270 precomputedData.toAncestorTransforms.set(*it, transformMatrix); |
276 } | 271 } |
277 success = true; | 272 success = true; |
278 return precomputedData.toAncestorTransforms.find(localTransformNode)->value; | 273 return precomputedData.toAncestorTransforms.find(localTransformNode)->value; |
279 } | 274 } |
280 | 275 |
281 namespace { | 276 namespace { |
282 | 277 |
283 unsigned transformPropertyTreeNodeDepth( | 278 unsigned transformPropertyTreeNodeDepth( |
284 const TransformPaintPropertyNode* node) { | 279 const TransformPaintPropertyNode* node) { |
(...skipping 27 matching lines...) Expand all Loading... |
312 | 307 |
313 // Walk up until we find the ancestor. | 308 // Walk up until we find the ancestor. |
314 while (a != b) { | 309 while (a != b) { |
315 a = a->parent(); | 310 a = a->parent(); |
316 b = b->parent(); | 311 b = b->parent(); |
317 } | 312 } |
318 return a; | 313 return a; |
319 } | 314 } |
320 | 315 |
321 } // namespace blink | 316 } // namespace blink |
OLD | NEW |