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/geometry/LayoutRect.h" | 7 #include "platform/geometry/LayoutRect.h" |
8 #include "platform/graphics/paint/ClipPaintPropertyNode.h" | |
9 #include "platform/graphics/paint/EffectPaintPropertyNode.h" | |
10 #include "platform/graphics/paint/TransformPaintPropertyNode.h" | |
11 | 8 |
12 namespace blink { | 9 namespace blink { |
13 | 10 |
14 FloatRect GeometryMapper::mapToVisualRectInDestinationSpace( | 11 FloatRect GeometryMapper::mapToVisualRectInDestinationSpace( |
15 const FloatRect& rect, | 12 const FloatRect& rect, |
16 const GeometryPropertyTreeState& sourceState, | 13 const PropertyTreeState& sourceState, |
17 const GeometryPropertyTreeState& destinationState, | 14 const PropertyTreeState& destinationState, |
18 bool& success) { | 15 bool& success) { |
19 FloatRect result = localToVisualRectInAncestorSpace( | 16 FloatRect result = localToVisualRectInAncestorSpace( |
20 rect, sourceState, destinationState, success); | 17 rect, sourceState, destinationState, success); |
21 if (success) | 18 if (success) |
22 return result; | 19 return result; |
23 return slowMapToVisualRectInDestinationSpace(rect, sourceState, | 20 return slowMapToVisualRectInDestinationSpace(rect, sourceState, |
24 destinationState, success); | 21 destinationState, success); |
25 } | 22 } |
26 | 23 |
27 FloatRect GeometryMapper::mapRectToDestinationSpace( | 24 FloatRect GeometryMapper::mapRectToDestinationSpace( |
28 const FloatRect& rect, | 25 const FloatRect& rect, |
29 const GeometryPropertyTreeState& sourceState, | 26 const PropertyTreeState& sourceState, |
30 const GeometryPropertyTreeState& destinationState, | 27 const PropertyTreeState& destinationState, |
31 bool& success) { | 28 bool& success) { |
32 FloatRect result = | 29 FloatRect result = |
33 localToAncestorRect(rect, sourceState, destinationState, success); | 30 localToAncestorRect(rect, sourceState, destinationState, success); |
34 if (success) | 31 if (success) |
35 return result; | 32 return result; |
36 return slowMapRectToDestinationSpace(rect, sourceState, destinationState, | 33 return slowMapRectToDestinationSpace(rect, sourceState, destinationState, |
37 success); | 34 success); |
38 } | 35 } |
39 | 36 |
40 FloatRect GeometryMapper::slowMapToVisualRectInDestinationSpace( | 37 FloatRect GeometryMapper::slowMapToVisualRectInDestinationSpace( |
41 const FloatRect& rect, | 38 const FloatRect& rect, |
42 const GeometryPropertyTreeState& sourceState, | 39 const PropertyTreeState& sourceState, |
43 const GeometryPropertyTreeState& destinationState, | 40 const PropertyTreeState& destinationState, |
44 bool& success) { | 41 bool& success) { |
45 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( | 42 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( |
46 sourceState.transform.get(), destinationState.transform.get()); | 43 sourceState.transform(), destinationState.transform()); |
47 DCHECK(lcaTransform); | 44 DCHECK(lcaTransform); |
48 | 45 |
49 // Assume that the clip of destinationState is an ancestor of the clip of sour
ceState | 46 // Assume that the clip of destinationState is an ancestor of the clip of sour
ceState |
50 // and is under the space of lcaTransform. Otherwise localToAncestorClipRect()
will fail. | 47 // and is under the space of lcaTransform. Otherwise localToAncestorClipRect()
will fail. |
51 GeometryPropertyTreeState lcaState = destinationState; | 48 PropertyTreeState lcaState = destinationState; |
52 lcaState.transform = lcaTransform; | 49 lcaState.setTransform(lcaTransform); |
53 | 50 |
54 const auto clipRect = localToAncestorClipRect(sourceState, lcaState, success); | 51 const auto clipRect = localToAncestorClipRect(sourceState, lcaState, success); |
55 if (!success) | 52 if (!success) |
56 return rect; | 53 return rect; |
57 | 54 |
58 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); | 55 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); |
59 DCHECK(success); | 56 DCHECK(success); |
60 result.intersect(clipRect); | 57 result.intersect(clipRect); |
61 | 58 |
62 const TransformationMatrix& destinationToLca = localToAncestorMatrix( | 59 const TransformationMatrix& destinationToLca = |
63 destinationState.transform.get(), lcaState, success); | 60 localToAncestorMatrix(destinationState.transform(), lcaState, success); |
64 DCHECK(success); | 61 DCHECK(success); |
65 if (destinationToLca.isInvertible()) { | 62 if (destinationToLca.isInvertible()) { |
66 success = true; | 63 success = true; |
67 return destinationToLca.inverse().mapRect(result); | 64 return destinationToLca.inverse().mapRect(result); |
68 } | 65 } |
69 success = false; | 66 success = false; |
70 return rect; | 67 return rect; |
71 } | 68 } |
72 | 69 |
73 FloatRect GeometryMapper::slowMapRectToDestinationSpace( | 70 FloatRect GeometryMapper::slowMapRectToDestinationSpace( |
74 const FloatRect& rect, | 71 const FloatRect& rect, |
75 const GeometryPropertyTreeState& sourceState, | 72 const PropertyTreeState& sourceState, |
76 const GeometryPropertyTreeState& destinationState, | 73 const PropertyTreeState& destinationState, |
77 bool& success) { | 74 bool& success) { |
78 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( | 75 const TransformPaintPropertyNode* lcaTransform = leastCommonAncestor( |
79 sourceState.transform.get(), destinationState.transform.get()); | 76 sourceState.transform(), destinationState.transform()); |
80 DCHECK(lcaTransform); | 77 DCHECK(lcaTransform); |
81 GeometryPropertyTreeState lcaState = sourceState; | 78 PropertyTreeState lcaState = sourceState; |
82 lcaState.transform = lcaTransform; | 79 lcaState.setTransform(lcaTransform); |
83 | 80 |
84 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); | 81 FloatRect result = localToAncestorRect(rect, sourceState, lcaState, success); |
85 DCHECK(success); | 82 DCHECK(success); |
86 | 83 |
87 const TransformationMatrix& destinationToLca = localToAncestorMatrix( | 84 const TransformationMatrix& destinationToLca = |
88 destinationState.transform.get(), lcaState, success); | 85 localToAncestorMatrix(destinationState.transform(), lcaState, success); |
89 DCHECK(success); | 86 DCHECK(success); |
90 if (destinationToLca.isInvertible()) { | 87 if (destinationToLca.isInvertible()) { |
91 success = true; | 88 success = true; |
92 return destinationToLca.inverse().mapRect(result); | 89 return destinationToLca.inverse().mapRect(result); |
93 } | 90 } |
94 success = false; | 91 success = false; |
95 return rect; | 92 return rect; |
96 } | 93 } |
97 | 94 |
98 FloatRect GeometryMapper::localToVisualRectInAncestorSpace( | 95 FloatRect GeometryMapper::localToVisualRectInAncestorSpace( |
99 const FloatRect& rect, | 96 const FloatRect& rect, |
100 const GeometryPropertyTreeState& localState, | 97 const PropertyTreeState& localState, |
101 const GeometryPropertyTreeState& ancestorState, | 98 const PropertyTreeState& ancestorState, |
102 bool& success) { | 99 bool& success) { |
103 const auto& transformMatrix = | 100 const auto& transformMatrix = |
104 localToAncestorMatrix(localState.transform.get(), ancestorState, success); | 101 localToAncestorMatrix(localState.transform(), ancestorState, success); |
105 if (!success) | 102 if (!success) |
106 return rect; | 103 return rect; |
107 | 104 |
108 FloatRect mappedRect = transformMatrix.mapRect(rect); | 105 FloatRect mappedRect = transformMatrix.mapRect(rect); |
109 | 106 |
110 const auto clipRect = | 107 const auto clipRect = |
111 localToAncestorClipRect(localState, ancestorState, success); | 108 localToAncestorClipRect(localState, ancestorState, success); |
112 DCHECK(success); | 109 DCHECK(success); |
113 | 110 |
114 mappedRect.intersect(clipRect); | 111 mappedRect.intersect(clipRect); |
115 return mappedRect; | 112 return mappedRect; |
116 } | 113 } |
117 | 114 |
118 FloatRect GeometryMapper::localToAncestorRect( | 115 FloatRect GeometryMapper::localToAncestorRect( |
119 const FloatRect& rect, | 116 const FloatRect& rect, |
120 const GeometryPropertyTreeState& localState, | 117 const PropertyTreeState& localState, |
121 const GeometryPropertyTreeState& ancestorState, | 118 const PropertyTreeState& ancestorState, |
122 bool& success) { | 119 bool& success) { |
123 const auto& transformMatrix = | 120 const auto& transformMatrix = |
124 localToAncestorMatrix(localState.transform.get(), ancestorState, success); | 121 localToAncestorMatrix(localState.transform(), ancestorState, success); |
125 if (!success) | 122 if (!success) |
126 return rect; | 123 return rect; |
127 return transformMatrix.mapRect(rect); | 124 return transformMatrix.mapRect(rect); |
128 } | 125 } |
129 | 126 |
130 FloatRect GeometryMapper::ancestorToLocalRect( | 127 FloatRect GeometryMapper::ancestorToLocalRect( |
131 const FloatRect& rect, | 128 const FloatRect& rect, |
132 const GeometryPropertyTreeState& localState, | 129 const PropertyTreeState& localState, |
133 const GeometryPropertyTreeState& ancestorState, | 130 const PropertyTreeState& ancestorState, |
134 bool& success) { | 131 bool& success) { |
135 const auto& transformMatrix = | 132 const auto& transformMatrix = |
136 localToAncestorMatrix(localState.transform.get(), ancestorState, success); | 133 localToAncestorMatrix(localState.transform(), ancestorState, success); |
137 if (!success) | 134 if (!success) |
138 return rect; | 135 return rect; |
139 | 136 |
140 if (!transformMatrix.isInvertible()) { | 137 if (!transformMatrix.isInvertible()) { |
141 success = false; | 138 success = false; |
142 return rect; | 139 return rect; |
143 } | 140 } |
144 success = true; | 141 success = true; |
145 | 142 |
146 // TODO(chrishtr): Cache the inverse? | 143 // TODO(chrishtr): Cache the inverse? |
147 return transformMatrix.inverse().mapRect(rect); | 144 return transformMatrix.inverse().mapRect(rect); |
148 } | 145 } |
149 | 146 |
150 PrecomputedDataForAncestor& GeometryMapper::getPrecomputedDataForAncestor( | 147 PrecomputedDataForAncestor& GeometryMapper::getPrecomputedDataForAncestor( |
151 const GeometryPropertyTreeState& ancestorState) { | 148 const PropertyTreeState& ancestorState) { |
152 auto addResult = m_data.add(ancestorState.transform.get(), nullptr); | 149 auto addResult = m_data.add(ancestorState.transform(), nullptr); |
153 if (addResult.isNewEntry) | 150 if (addResult.isNewEntry) |
154 addResult.storedValue->value = PrecomputedDataForAncestor::create(); | 151 addResult.storedValue->value = PrecomputedDataForAncestor::create(); |
155 return *addResult.storedValue->value; | 152 return *addResult.storedValue->value; |
156 } | 153 } |
157 | 154 |
158 FloatRect GeometryMapper::localToAncestorClipRect( | 155 FloatRect GeometryMapper::localToAncestorClipRect( |
159 const GeometryPropertyTreeState& localState, | 156 const PropertyTreeState& localState, |
160 const GeometryPropertyTreeState& ancestorState, | 157 const PropertyTreeState& ancestorState, |
161 bool& success) { | 158 bool& success) { |
162 PrecomputedDataForAncestor& precomputedData = | 159 PrecomputedDataForAncestor& precomputedData = |
163 getPrecomputedDataForAncestor(ancestorState); | 160 getPrecomputedDataForAncestor(ancestorState); |
164 const ClipPaintPropertyNode* clipNode = localState.clip.get(); | 161 const ClipPaintPropertyNode* clipNode = localState.clip(); |
165 Vector<const ClipPaintPropertyNode*> intermediateNodes; | 162 Vector<const ClipPaintPropertyNode*> intermediateNodes; |
166 FloatRect clip(LayoutRect::infiniteIntRect()); | 163 FloatRect clip(LayoutRect::infiniteIntRect()); |
167 | 164 |
168 bool found = false; | 165 bool found = false; |
169 // Iterate over the path from localState.clip to ancestorState.clip. Stop if w
e've found a memoized (precomputed) clip | 166 // Iterate over the path from localState.clip to ancestorState.clip. Stop if w
e've found a memoized (precomputed) clip |
170 // for any particular node. | 167 // for any particular node. |
171 while (clipNode) { | 168 while (clipNode) { |
172 auto it = precomputedData.toAncestorClipRects.find(clipNode); | 169 auto it = precomputedData.toAncestorClipRects.find(clipNode); |
173 if (it != precomputedData.toAncestorClipRects.end()) { | 170 if (it != precomputedData.toAncestorClipRects.end()) { |
174 clip = it->value; | 171 clip = it->value; |
175 found = true; | 172 found = true; |
176 break; | 173 break; |
177 } | 174 } |
178 intermediateNodes.append(clipNode); | 175 intermediateNodes.append(clipNode); |
179 | 176 |
180 if (clipNode == ancestorState.clip) | 177 if (clipNode == ancestorState.clip()) |
181 break; | 178 break; |
182 | 179 |
183 clipNode = clipNode->parent(); | 180 clipNode = clipNode->parent(); |
184 } | 181 } |
185 if (clipNode != ancestorState.clip && !found) { | 182 if (clipNode != ancestorState.clip() && !found) { |
186 success = false; | 183 success = false; |
187 return clip; | 184 return clip; |
188 } | 185 } |
189 | 186 |
190 // Iterate down from the top intermediate node found in the previous loop, com
puting and memoizing clip rects as we go. | 187 // Iterate down from the top intermediate node found in the previous loop, com
puting and memoizing clip rects as we go. |
191 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); | 188 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); |
192 ++it) { | 189 ++it) { |
193 if ((*it) != ancestorState.clip) { | 190 if ((*it) != ancestorState.clip()) { |
194 success = false; | 191 success = false; |
195 const TransformationMatrix& transformMatrix = localToAncestorMatrix( | 192 const TransformationMatrix& transformMatrix = localToAncestorMatrix( |
196 (*it)->localTransformSpace(), ancestorState, success); | 193 (*it)->localTransformSpace(), ancestorState, success); |
197 if (!success) | 194 if (!success) |
198 return clip; | 195 return clip; |
199 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); | 196 FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); |
200 clip.intersect(mappedRect); | 197 clip.intersect(mappedRect); |
201 } | 198 } |
202 | 199 |
203 precomputedData.toAncestorClipRects.set(*it, clip); | 200 precomputedData.toAncestorClipRects.set(*it, clip); |
204 } | 201 } |
205 | 202 |
206 success = true; | 203 success = true; |
207 return precomputedData.toAncestorClipRects.find(localState.clip.get())->value; | 204 return precomputedData.toAncestorClipRects.find(localState.clip())->value; |
208 } | 205 } |
209 | 206 |
210 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( | 207 const TransformationMatrix& GeometryMapper::localToAncestorMatrix( |
211 const TransformPaintPropertyNode* localTransformNode, | 208 const TransformPaintPropertyNode* localTransformNode, |
212 const GeometryPropertyTreeState& ancestorState, | 209 const PropertyTreeState& ancestorState, |
213 bool& success) { | 210 bool& success) { |
214 PrecomputedDataForAncestor& precomputedData = | 211 PrecomputedDataForAncestor& precomputedData = |
215 getPrecomputedDataForAncestor(ancestorState); | 212 getPrecomputedDataForAncestor(ancestorState); |
216 | 213 |
217 const TransformPaintPropertyNode* transformNode = localTransformNode; | 214 const TransformPaintPropertyNode* transformNode = localTransformNode; |
218 Vector<const TransformPaintPropertyNode*> intermediateNodes; | 215 Vector<const TransformPaintPropertyNode*> intermediateNodes; |
219 TransformationMatrix transformMatrix; | 216 TransformationMatrix transformMatrix; |
220 | 217 |
221 bool found = false; | 218 bool found = false; |
222 // Iterate over the path from localTransformNode to ancestorState.transform. S
top if we've found a memoized (precomputed) transform | 219 // Iterate over the path from localTransformNode to ancestorState.transform. S
top if we've found a memoized (precomputed) transform |
223 // for any particular node. | 220 // for any particular node. |
224 while (transformNode) { | 221 while (transformNode) { |
225 auto it = precomputedData.toAncestorTransforms.find(transformNode); | 222 auto it = precomputedData.toAncestorTransforms.find(transformNode); |
226 if (it != precomputedData.toAncestorTransforms.end()) { | 223 if (it != precomputedData.toAncestorTransforms.end()) { |
227 transformMatrix = it->value; | 224 transformMatrix = it->value; |
228 found = true; | 225 found = true; |
229 break; | 226 break; |
230 } | 227 } |
231 | 228 |
232 intermediateNodes.append(transformNode); | 229 intermediateNodes.append(transformNode); |
233 | 230 |
234 if (transformNode == ancestorState.transform) | 231 if (transformNode == ancestorState.transform()) |
235 break; | 232 break; |
236 | 233 |
237 transformNode = transformNode->parent(); | 234 transformNode = transformNode->parent(); |
238 } | 235 } |
239 if (!found && transformNode != ancestorState.transform) { | 236 if (!found && transformNode != ancestorState.transform()) { |
240 success = false; | 237 success = false; |
241 return m_identity; | 238 return m_identity; |
242 } | 239 } |
243 | 240 |
244 // Iterate down from the top intermediate node found in the previous loop, com
puting and memoizing transforms as we go. | 241 // Iterate down from the top intermediate node found in the previous loop, com
puting and memoizing transforms as we go. |
245 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); | 242 for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); |
246 it++) { | 243 it++) { |
247 if ((*it) != ancestorState.transform) { | 244 if ((*it) != ancestorState.transform()) { |
248 TransformationMatrix localTransformMatrix = (*it)->matrix(); | 245 TransformationMatrix localTransformMatrix = (*it)->matrix(); |
249 localTransformMatrix.applyTransformOrigin((*it)->origin()); | 246 localTransformMatrix.applyTransformOrigin((*it)->origin()); |
250 transformMatrix = transformMatrix * localTransformMatrix; | 247 transformMatrix = transformMatrix * localTransformMatrix; |
251 } | 248 } |
252 | 249 |
253 precomputedData.toAncestorTransforms.set(*it, transformMatrix); | 250 precomputedData.toAncestorTransforms.set(*it, transformMatrix); |
254 } | 251 } |
255 success = true; | 252 success = true; |
256 return precomputedData.toAncestorTransforms.find(localTransformNode)->value; | 253 return precomputedData.toAncestorTransforms.find(localTransformNode)->value; |
257 } | 254 } |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
290 | 287 |
291 // Walk up until we find the ancestor. | 288 // Walk up until we find the ancestor. |
292 while (a != b) { | 289 while (a != b) { |
293 a = a->parent(); | 290 a = a->parent(); |
294 b = b->parent(); | 291 b = b->parent(); |
295 } | 292 } |
296 return a; | 293 return a; |
297 } | 294 } |
298 | 295 |
299 } // namespace blink | 296 } // namespace blink |
OLD | NEW |