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