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::sourceToDestinationVisualRect( |
13 const FloatRect& rect, | |
14 const PropertyTreeState& sourceState, | |
15 const PropertyTreeState& destinationState, | |
16 bool& success) { | |
17 FloatRect result = localToVisualRectInAncestorSpace( | |
18 rect, sourceState, destinationState, success); | |
19 if (success) | |
20 return result; | |
21 return slowMapToVisualRectInDestinationSpace(rect, sourceState, | |
22 destinationState, success); | |
23 } | |
24 | |
25 FloatRect GeometryMapper::mapRectToDestinationSpace( | |
26 const FloatRect& rect, | 13 const FloatRect& rect, |
27 const PropertyTreeState& sourceState, | 14 const PropertyTreeState& sourceState, |
28 const PropertyTreeState& destinationState, | 15 const PropertyTreeState& destinationState, |
29 bool& success) { | 16 bool& success) { |
30 FloatRect result = | 17 FloatRect result = |
31 localToAncestorRect(rect, sourceState, destinationState, success); | 18 localToAncestorVisualRect(rect, sourceState, destinationState, success); |
32 if (success) | 19 if (success) |
33 return result; | 20 return result; |
34 return slowMapRectToDestinationSpace(rect, sourceState, destinationState, | 21 return slowSourceToDestinationVisualRect(rect, sourceState, destinationState, |
35 success); | 22 success); |
36 } | 23 } |
37 | 24 |
38 FloatRect GeometryMapper::slowMapToVisualRectInDestinationSpace( | 25 FloatRect GeometryMapper::sourceToDestinationRect( |
26 const FloatRect& rect, | |
27 const TransformPaintPropertyNode* sourceTransformNode, | |
28 const TransformPaintPropertyNode* destinationTransformNode, | |
29 bool& success) { | |
30 FloatRect result = localToAncestorRect(rect, sourceTransformNode, | |
31 destinationTransformNode, success); | |
32 if (success) | |
33 return result; | |
34 return slowSourceToDestinationRect(rect, sourceTransformNode, | |
35 destinationTransformNode, success); | |
36 } | |
37 | |
38 FloatRect GeometryMapper::slowSourceToDestinationVisualRect( | |
39 const FloatRect& rect, | 39 const FloatRect& rect, |
40 const PropertyTreeState& sourceState, | 40 const PropertyTreeState& sourceState, |
41 const PropertyTreeState& destinationState, | 41 const PropertyTreeState& destinationState, |
42 bool& success) { | 42 bool& success) { |
43 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( | 43 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( |
44 sourceState.transform(), destinationState.transform()); | 44 sourceState.transform(), destinationState.transform()); |
45 DCHECK(lcaTransform); | 45 DCHECK(lcaTransform); |
46 | 46 |
47 // Assume that the clip of destinationState is an ancestor of the clip of | 47 // Assume that the clip of destinationState is an ancestor of the clip of |
48 // sourceState and is under the space of lcaTransform. Otherwise | 48 // sourceState and is under the space of lcaTransform. Otherwise |
49 // localToAncestorClipRect() will fail. | 49 // localToAncestorClipRect() will fail. |
50 PropertyTreeState lcaState = destinationState; | 50 PropertyTreeState lcaState = destinationState; |
51 lcaState.setTransform(lcaTransform); | 51 lcaState.setTransform(lcaTransform); |
52 | 52 |
53 const auto clipRect = localToAncestorClipRect(sourceState, lcaState, success); | 53 FloatRect result = |
54 localToAncestorVisualRect(rect, sourceState, lcaState, success); | |
54 if (!success) | 55 if (!success) |
55 return rect; | 56 return result; |
56 | 57 |
57 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); | 58 return ancestorToLocalRect(result, lcaTransform, destinationState.transform(), |
chrishtr
2017/01/11 23:23:09
Why remove this?
Xianzhu
2017/01/11 23:54:43
Line 53-59 now becomes a call to localToAncestorVi
| |
58 DCHECK(success); | 59 success); |
59 result.intersect(clipRect); | |
60 | |
61 return ancestorToLocalRect(result, destinationState, lcaState, success); | |
62 } | 60 } |
63 | 61 |
64 FloatRect GeometryMapper::slowMapRectToDestinationSpace( | 62 FloatRect GeometryMapper::slowSourceToDestinationRect( |
65 const FloatRect& rect, | 63 const FloatRect& rect, |
66 const PropertyTreeState& sourceState, | 64 const TransformPaintPropertyNode* sourceTransformNode, |
67 const PropertyTreeState& destinationState, | 65 const TransformPaintPropertyNode* destinationTransformNode, |
68 bool& success) { | 66 bool& success) { |
69 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( | 67 const TransformPaintPropertyNode* lcaTransform = |
70 sourceState.transform(), destinationState.transform()); | 68 leastCommonAncestor(sourceTransformNode, destinationTransformNode); |
71 DCHECK(lcaTransform); | 69 DCHECK(lcaTransform); |
72 PropertyTreeState lcaState = sourceState; | |
73 lcaState.setTransform(lcaTransform); | |
74 | 70 |
75 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); | 71 FloatRect result = |
72 localToAncestorRect(rect, sourceTransformNode, lcaTransform, success); | |
76 DCHECK(success); | 73 DCHECK(success); |
77 | 74 |
78 return ancestorToLocalRect(result, destinationState, lcaState, success); | 75 return ancestorToLocalRect(result, lcaTransform, destinationTransformNode, |
76 success); | |
79 } | 77 } |
80 | 78 |
81 FloatRect GeometryMapper::localToVisualRectInAncestorSpace( | 79 FloatRect GeometryMapper::localToAncestorVisualRect( |
82 const FloatRect& rect, | 80 const FloatRect& rect, |
83 const PropertyTreeState& localState, | 81 const PropertyTreeState& localState, |
84 const PropertyTreeState& ancestorState, | 82 const PropertyTreeState& ancestorState, |
85 bool& success) { | 83 bool& success) { |
86 if (localState == ancestorState) { | 84 if (localState == ancestorState) { |
87 success = true; | 85 success = true; |
88 return rect; | 86 return rect; |
89 } | 87 } |
90 | 88 |
91 const auto& transformMatrix = | 89 const auto& transformMatrix = localToAncestorMatrix( |
92 localToAncestorMatrix(localState.transform(), ancestorState, success); | 90 localState.transform(), ancestorState.transform(), success); |
93 if (!success) | 91 if (!success) |
94 return rect; | 92 return rect; |
95 | 93 |
96 FloatRect mappedRect = transformMatrix.mapRect(rect); | 94 FloatRect mappedRect = transformMatrix.mapRect(rect); |
97 | 95 |
98 const auto clipRect = | 96 const auto clipRect = |
99 localToAncestorClipRect(localState, ancestorState, success); | 97 localToAncestorClipRect(localState, ancestorState, success); |
100 | 98 |
101 if (success) { | 99 if (success) { |
102 mappedRect.intersect(clipRect); | 100 mappedRect.intersect(clipRect); |
103 } else if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { | 101 } else if (!RuntimeEnabledFeatures::slimmingPaintV2Enabled()) { |
104 // On SPv1 we may fail when the paint invalidation container creates an | 102 // On SPv1 we may fail when the paint invalidation container creates an |
105 // overflow clip (in ancestorState) which is not in localState of an | 103 // overflow clip (in ancestorState) which is not in localState of an |
106 // out-of-flow positioned descendant. See crbug.com/513108 and layout test | 104 // out-of-flow positioned descendant. See crbug.com/513108 and layout test |
107 // compositing/overflow/handle-non-ancestor-clip-parent.html (run with | 105 // compositing/overflow/handle-non-ancestor-clip-parent.html (run with |
108 // --enable-prefer-compositing-to-lcd-text) for details. | 106 // --enable-prefer-compositing-to-lcd-text) for details. |
109 // Ignore it for SPv1 for now. | 107 // Ignore it for SPv1 for now. |
110 success = true; | 108 success = true; |
111 } else { | |
chrishtr
2017/01/11 23:23:09
Why remove this?
Xianzhu
2017/01/11 23:54:43
Now slowSourceToDestinationVisualRect (previously
chrishtr
2017/01/12 18:07:12
The DCHECK is to ensure that it's actually an ance
Xianzhu
2017/01/12 18:39:17
No DCHECK(success) here is mainly a requirement of
| |
112 DCHECK(success); | |
113 } | 109 } |
114 | 110 |
115 return mappedRect; | 111 return mappedRect; |
116 } | 112 } |
117 | 113 |
118 FloatRect GeometryMapper::localToAncestorRect( | 114 FloatRect GeometryMapper::localToAncestorRect( |
119 const FloatRect& rect, | 115 const FloatRect& rect, |
120 const PropertyTreeState& localState, | 116 const TransformPaintPropertyNode* localTransformNode, |
121 const PropertyTreeState& ancestorState, | 117 const TransformPaintPropertyNode* ancestorTransformNode, |
122 bool& success) { | 118 bool& success) { |
123 if (localState.transform() == ancestorState.transform()) { | 119 if (localTransformNode == ancestorTransformNode) { |
124 success = true; | 120 success = true; |
125 return rect; | 121 return rect; |
126 } | 122 } |
127 | 123 |
128 const auto& transformMatrix = | 124 const auto& transformMatrix = |
129 localToAncestorMatrix(localState.transform(), ancestorState, success); | 125 localToAncestorMatrix(localTransformNode, ancestorTransformNode, success); |
130 if (!success) | 126 if (!success) |
131 return rect; | 127 return rect; |
132 return transformMatrix.mapRect(rect); | 128 return transformMatrix.mapRect(rect); |
133 } | 129 } |
134 | 130 |
135 FloatRect GeometryMapper::ancestorToLocalRect( | 131 FloatRect GeometryMapper::ancestorToLocalRect( |
136 const FloatRect& rect, | 132 const FloatRect& rect, |
137 const PropertyTreeState& localState, | 133 const TransformPaintPropertyNode* ancestorTransformNode, |
138 const PropertyTreeState& ancestorState, | 134 const TransformPaintPropertyNode* localTransformNode, |
139 bool& success) { | 135 bool& success) { |
140 if (localState.transform() == ancestorState.transform()) { | 136 if (localTransformNode == ancestorTransformNode) { |
141 success = true; | 137 success = true; |
142 return rect; | 138 return rect; |
143 } | 139 } |
144 | 140 |
145 const auto& transformMatrix = | 141 const auto& transformMatrix = |
146 localToAncestorMatrix(localState.transform(), ancestorState, success); | 142 localToAncestorMatrix(localTransformNode, ancestorTransformNode, success); |
147 if (!success) | 143 if (!success) |
148 return rect; | 144 return rect; |
149 | 145 |
150 if (!transformMatrix.isInvertible()) { | 146 if (!transformMatrix.isInvertible()) { |
151 success = false; | 147 success = false; |
152 return rect; | 148 return rect; |
153 } | 149 } |
154 success = true; | 150 success = true; |
155 | 151 |
156 // TODO(chrishtr): Cache the inverse? | 152 // TODO(chrishtr): Cache the inverse? |
157 return transformMatrix.inverse().mapRect(rect); | 153 return transformMatrix.inverse().mapRect(rect); |
158 } | 154 } |
159 | 155 |
160 PrecomputedDataForAncestor& GeometryMapper::getPrecomputedDataForAncestor( | 156 PrecomputedDataForAncestor& GeometryMapper::getPrecomputedDataForAncestor( |
161 const PropertyTreeState& ancestorState) { | 157 const TransformPaintPropertyNode* ancestorTransformNode) { |
162 auto addResult = m_data.add(ancestorState.transform(), nullptr); | 158 auto addResult = m_data.add(ancestorTransformNode, nullptr); |
163 if (addResult.isNewEntry) | 159 if (addResult.isNewEntry) |
164 addResult.storedValue->value = PrecomputedDataForAncestor::create(); | 160 addResult.storedValue->value = PrecomputedDataForAncestor::create(); |
165 return *addResult.storedValue->value; | 161 return *addResult.storedValue->value; |
166 } | 162 } |
167 | 163 |
168 FloatRect GeometryMapper::localToAncestorClipRect( | 164 FloatRect GeometryMapper::localToAncestorClipRect( |
169 const PropertyTreeState& localState, | 165 const PropertyTreeState& localState, |
170 const PropertyTreeState& ancestorState, | 166 const PropertyTreeState& ancestorState, |
171 bool& success) { | 167 bool& success) { |
172 FloatRect clip(LayoutRect::infiniteIntRect()); | 168 FloatRect clip(LayoutRect::infiniteIntRect()); |
173 if (localState.clip() == ancestorState.clip()) { | 169 if (localState.clip() == ancestorState.clip()) { |
174 success = true; | 170 success = true; |
175 return clip; | 171 return clip; |
176 } | 172 } |
177 | 173 |
178 PrecomputedDataForAncestor& precomputedData = | 174 PrecomputedDataForAncestor& precomputedData = |
179 getPrecomputedDataForAncestor(ancestorState); | 175 getPrecomputedDataForAncestor(ancestorState.transform()); |
180 const ClipPaintPropertyNode* clipNode = localState.clip(); | 176 const ClipPaintPropertyNode* clipNode = localState.clip(); |
181 Vector<const ClipPaintPropertyNode*> intermediateNodes; | 177 Vector<const ClipPaintPropertyNode*> intermediateNodes; |
182 | 178 |
183 bool found = false; | |
184 // Iterate over the path from localState.clip to ancestorState.clip. Stop if | 179 // Iterate over the path from localState.clip to ancestorState.clip. Stop if |
185 // we've found a memoized (precomputed) clip for any particular node. | 180 // we've found a memoized (precomputed) clip for any particular node. |
186 while (clipNode) { | 181 while (clipNode && clipNode != ancestorState.clip()) { |
187 auto it = precomputedData.toAncestorClipRects.find(clipNode); | 182 auto it = precomputedData.toAncestorClipRects.find(clipNode); |
188 if (it != precomputedData.toAncestorClipRects.end()) { | 183 if (it != precomputedData.toAncestorClipRects.end()) { |
189 clip = it->value; | 184 clip = it->value; |
190 found = true; | |
191 break; | 185 break; |
192 } | 186 } |
193 intermediateNodes.push_back(clipNode); | 187 intermediateNodes.push_back(clipNode); |
194 | |
195 if (clipNode == ancestorState.clip()) | |
196 break; | |
197 | |
198 clipNode = clipNode->parent(); | 188 clipNode = clipNode->parent(); |
199 } | 189 } |
200 if (clipNode != ancestorState.clip() && !found) { | 190 if (!clipNode) { |
chrishtr
2017/01/11 23:23:09
What about if clipNode == ancestorState.clip()?
Xianzhu
2017/01/11 23:54:43
In the case we'll execute the loop below, the same
| |
201 success = false; | 191 success = false; |
202 return clip; | 192 return clip; |
203 } | 193 } |
204 | 194 |
205 // Iterate down from the top intermediate node found in the previous loop, | 195 // Iterate down from the top intermediate node found in the previous loop, |
206 // computing and memoizing clip rects as we go. | 196 // computing and memoizing clip rects as we go. |
207 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); | 197 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); |
208 ++it) { | 198 ++it) { |
209 if ((*it) != ancestorState.clip()) { | 199 success = false; |
210 success = false; | 200 const TransformationMatrix& transformMatrix = localToAncestorMatrix( |
211 const TransformationMatrix& transformMatrix = localToAncestorMatrix( | 201 (*it)->localTransformSpace(), ancestorState.transform(), success); |
212 (*it)->localTransformSpace(), ancestorState, success); | 202 if (!success) |
213 if (!success) | 203 return clip; |
214 return clip; | 204 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); |
215 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); | 205 clip.intersect(mappedRect); |
216 clip.intersect(mappedRect); | |
217 } | |
218 | |
219 precomputedData.toAncestorClipRects.set(*it, clip); | 206 precomputedData.toAncestorClipRects.set(*it, clip); |
220 } | 207 } |
221 | 208 |
222 success = true; | 209 success = true; |
223 return precomputedData.toAncestorClipRects.find(localState.clip())->value; | 210 return precomputedData.toAncestorClipRects.find(localState.clip())->value; |
224 } | 211 } |
225 | 212 |
226 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( | 213 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( |
227 const TransformPaintPropertyNode* localTransformNode, | 214 const TransformPaintPropertyNode* localTransformNode, |
228 const PropertyTreeState& ancestorState, | 215 const TransformPaintPropertyNode* ancestorTransformNode, |
229 bool& success) { | 216 bool& success) { |
230 if (localTransformNode == ancestorState.transform()) { | 217 if (localTransformNode == ancestorTransformNode) { |
231 success = true; | 218 success = true; |
232 return m_identity; | 219 return m_identity; |
233 } | 220 } |
234 | 221 |
235 PrecomputedDataForAncestor& precomputedData = | 222 PrecomputedDataForAncestor& precomputedData = |
236 getPrecomputedDataForAncestor(ancestorState); | 223 getPrecomputedDataForAncestor(ancestorTransformNode); |
237 | 224 |
238 const TransformPaintPropertyNode* transformNode = localTransformNode; | 225 const TransformPaintPropertyNode* transformNode = localTransformNode; |
239 Vector<const TransformPaintPropertyNode*> intermediateNodes; | 226 Vector<const TransformPaintPropertyNode*> intermediateNodes; |
240 TransformationMatrix transformMatrix; | 227 TransformationMatrix transformMatrix; |
241 | 228 |
242 // Iterate over the path from localTransformNode to ancestorState.transform. | 229 // Iterate over the path from localTransformNode to ancestorState.transform. |
243 // Stop if we've found a memoized (precomputed) transform for any particular | 230 // Stop if we've found a memoized (precomputed) transform for any particular |
244 // node. | 231 // node. |
245 while (transformNode) { | 232 while (transformNode && transformNode != ancestorTransformNode) { |
246 auto it = precomputedData.toAncestorTransforms.find(transformNode); | 233 auto it = precomputedData.toAncestorTransforms.find(transformNode); |
247 if (it != precomputedData.toAncestorTransforms.end()) { | 234 if (it != precomputedData.toAncestorTransforms.end()) { |
248 transformMatrix = it->value; | 235 transformMatrix = it->value; |
249 break; | 236 break; |
250 } | 237 } |
251 | |
252 if (transformNode == ancestorState.transform()) | |
253 break; | |
254 | |
255 intermediateNodes.push_back(transformNode); | 238 intermediateNodes.push_back(transformNode); |
256 transformNode = transformNode->parent(); | 239 transformNode = transformNode->parent(); |
257 } | 240 } |
258 if (!transformNode) { | 241 if (!transformNode) { |
259 success = false; | 242 success = false; |
260 return m_identity; | 243 return m_identity; |
261 } | 244 } |
262 | 245 |
263 // Iterate down from the top intermediate node found in the previous loop, | 246 // Iterate down from the top intermediate node found in the previous loop, |
264 // computing and memoizing transforms as we go. | 247 // computing and memoizing transforms as we go. |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
307 | 290 |
308 // Walk up until we find the ancestor. | 291 // Walk up until we find the ancestor. |
309 while (a != b) { | 292 while (a != b) { |
310 a = a->parent(); | 293 a = a->parent(); |
311 b = b->parent(); | 294 b = b->parent(); |
312 } | 295 } |
313 return a; | 296 return a; |
314 } | 297 } |
315 | 298 |
316 } // namespace blink | 299 } // namespace blink |
OLD | NEW |