| 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 |