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