Chromium Code Reviews| Index: third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp |
| diff --git a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp |
| index 1f311419bea933c8545bf196c2d112687ca1adbc..71c62456052752bc27cc4494a541cf8483803185 100644 |
| --- a/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp |
| +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp |
| @@ -8,41 +8,104 @@ |
| #include "platform/graphics/paint/ClipPaintPropertyNode.h" |
| #include "platform/graphics/paint/EffectPaintPropertyNode.h" |
| #include "platform/graphics/paint/TransformPaintPropertyNode.h" |
| +#include "wtf/HashSet.h" |
| namespace blink { |
| -FloatRect GeometryMapper::LocalToVisualRectInAncestorSpace( |
| +PassRefPtr<TransformPaintPropertyNode> GeometryMapper::leastCommonAncestor(PassRefPtr<TransformPaintPropertyNode> a, PassRefPtr<TransformPaintPropertyNode> b) |
| +{ |
| + HashSet<RefPtr<TransformPaintPropertyNode>> intermediates; |
|
pdr.
2016/07/01 18:39:40
We may want to use a lowest common ancestor approa
chrishtr
2016/07/01 22:01:12
Refactored to reuse that code, templated for all p
|
| + RefPtr<TransformPaintPropertyNode> currA = a; |
| + RefPtr<TransformPaintPropertyNode> currB = b; |
| + while (currA || currB) { |
| + if (currA) { |
| + auto it = intermediates.find(currA); |
| + if (it != intermediates.end()) |
| + return *it; |
| + intermediates.add(currA); |
| + currA = currA->parent(); |
| + } |
| + |
| + if (currB) { |
| + auto it = intermediates.find(currB); |
| + if (it != intermediates.end()) |
| + return *it; |
| + intermediates.add(currB); |
| + currB = currB->parent(); |
| + } |
| + } |
| + CHECK(false); |
| + return nullptr; |
| +} |
| + |
| +FloatRect GeometryMapper::mapToVisualRectInDestinationSpace(const FloatRect& rect, |
| + const PropertyTreeState& sourceState, |
| + const PropertyTreeState& destinationState, |
| + bool* success) |
| +{ |
| + FloatRect result = localToVisualRectInAncestorSpace(rect, sourceState, destinationState, success); |
| + if (*success) |
| + return result; |
| + |
| + RefPtr<TransformPaintPropertyNode> lcaTransform = leastCommonAncestor(sourceState.transform.get(), destinationState.transform.get()); |
| + DCHECK(lcaTransform.get()); |
| + PropertyTreeState lcaState = sourceState; |
| + lcaState.transform = lcaTransform; |
| + |
| + result = localToAncestorMatrix(sourceState.transform.get(), lcaState, success).mapRect(rect); |
| + DCHECK(*success); |
| + |
| + const TransformationMatrix& destinationToLca = localToAncestorMatrix(destinationState.transform.get(), lcaState, success); |
| + DCHECK(*success); |
| + if (destinationToLca.isInvertible()) { |
| + *success = true; |
| + return destinationToLca.inverse().mapRect(result); |
| + } |
| + *success = false; |
| + return rect; |
| +} |
| + |
| +FloatRect GeometryMapper::localToVisualRectInAncestorSpace( |
| const FloatRect& rect, |
| const PropertyTreeState& localState, |
| - const PropertyTreeState& ancestorState) |
| + const PropertyTreeState& ancestorState, bool* success) |
| { |
| - const auto transformMatrix = LocalToAncestorMatrix(localState.transform, ancestorState); |
| + const auto transformMatrix = localToAncestorMatrix(localState.transform.get(), ancestorState, success); |
| + if (!(*success)) |
| + return rect; |
| + |
| FloatRect mappedRect = transformMatrix.mapRect(rect); |
| - const auto clipRect = LocalToAncestorClipRect(localState, ancestorState); |
| + const auto clipRect = localToAncestorClipRect(localState, ancestorState); |
| mappedRect.intersect(clipRect); |
| return mappedRect; |
| } |
| -FloatRect GeometryMapper::LocalToAncestorRect( |
| +FloatRect GeometryMapper::localToAncestorRect( |
| const FloatRect& rect, |
| const PropertyTreeState& localState, |
| - const PropertyTreeState& ancestorState) |
| + const PropertyTreeState& ancestorState, |
| + bool* success) |
| { |
| - const auto transformMatrix = LocalToAncestorMatrix(localState.transform, ancestorState); |
| + const auto transformMatrix = localToAncestorMatrix(localState.transform.get(), ancestorState, success); |
| + if (!(*success)) |
| + return rect; |
| return transformMatrix.mapRect(rect); |
| } |
| -FloatRect GeometryMapper::AncestorToLocalRect( |
| +FloatRect GeometryMapper::ancestorToLocalRect( |
| const FloatRect& rect, |
| const PropertyTreeState& localState, |
| const PropertyTreeState& ancestorState, bool* success) |
| { |
| - const auto& transformMatrix = LocalToAncestorMatrix(localState.transform, ancestorState); |
| + const auto& transformMatrix = localToAncestorMatrix(localState.transform.get(), ancestorState, success); |
| + if (!(*success)) |
| + return rect; |
| + |
| if (!transformMatrix.isInvertible()) { |
| *success = false; |
| - return FloatRect(); |
| + return rect; |
| } |
| *success = true; |
| @@ -50,20 +113,20 @@ FloatRect GeometryMapper::AncestorToLocalRect( |
| return transformMatrix.inverse().mapRect(rect); |
| } |
| -PrecomputedDataForAncestor& GeometryMapper::GetPrecomputedDataForAncestor(const PropertyTreeState& ancestorState) |
| +PrecomputedDataForAncestor& GeometryMapper::getPrecomputedDataForAncestor(const PropertyTreeState& ancestorState) |
| { |
| - auto addResult = m_data.add(ancestorState.transform, nullptr); |
| + auto addResult = m_data.add(ancestorState.transform.get(), nullptr); |
| if (addResult.isNewEntry) |
| addResult.storedValue->value = PrecomputedDataForAncestor::create(); |
| return *addResult.storedValue->value; |
| } |
| -const FloatRect& GeometryMapper::LocalToAncestorClipRect( |
| +const FloatRect& GeometryMapper::localToAncestorClipRect( |
| const PropertyTreeState& localState, |
| const PropertyTreeState& ancestorState) |
| { |
| - PrecomputedDataForAncestor& precomputedData = GetPrecomputedDataForAncestor(ancestorState); |
| - const ClipPaintPropertyNode* clipNode = localState.clip; |
| + PrecomputedDataForAncestor& precomputedData = getPrecomputedDataForAncestor(ancestorState); |
| + const ClipPaintPropertyNode* clipNode = localState.clip.get(); |
| Vector<const ClipPaintPropertyNode*> intermediateNodes; |
| FloatRect clip(LayoutRect::infiniteIntRect()); |
| @@ -90,7 +153,9 @@ const FloatRect& GeometryMapper::LocalToAncestorClipRect( |
| // Iterate down from the top intermediate node found in the previous loop, computing and memoizing clip rects as we go. |
| for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); ++it) { |
| if ((*it) != ancestorState.clip) { |
| - const TransformationMatrix transformMatrix = LocalToAncestorMatrix((*it)->localTransformSpace(), ancestorState); |
| + bool success = false; |
| + const TransformationMatrix transformMatrix = localToAncestorMatrix((*it)->localTransformSpace(), ancestorState, &success); |
| + DCHECK(success); |
| FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); |
| clip.intersect(mappedRect); |
| } |
| @@ -98,13 +163,13 @@ const FloatRect& GeometryMapper::LocalToAncestorClipRect( |
| precomputedData.toAncestorClipRects.set(*it, clip); |
| } |
| - return precomputedData.toAncestorClipRects.find(localState.clip)->value; |
| + return precomputedData.toAncestorClipRects.find(localState.clip.get())->value; |
| } |
| -const TransformationMatrix& GeometryMapper::LocalToAncestorMatrix( |
| +const TransformationMatrix& GeometryMapper::localToAncestorMatrix( |
| const TransformPaintPropertyNode* localTransformNode, |
| - const PropertyTreeState& ancestorState) { |
| - PrecomputedDataForAncestor& precomputedData = GetPrecomputedDataForAncestor(ancestorState); |
| + const PropertyTreeState& ancestorState, bool* success) { |
| + PrecomputedDataForAncestor& precomputedData = getPrecomputedDataForAncestor(ancestorState); |
| const TransformPaintPropertyNode* transformNode = localTransformNode; |
| Vector<const TransformPaintPropertyNode*> intermediateNodes; |
| @@ -128,8 +193,10 @@ const TransformationMatrix& GeometryMapper::LocalToAncestorMatrix( |
| transformNode = transformNode->parent(); |
| } |
| - // It's illegal to ask for a local-to-ancestor matrix when the ancestor is not an ancestor. |
| - DCHECK(transformNode == ancestorState.transform || found); |
| + if (!found && transformNode != ancestorState.transform) { |
| + *success = false; |
| + return m_identity; |
|
pdr.
2016/07/01 18:39:40
Instead of using a member, you can use a static li
chrishtr
2016/07/01 22:01:12
That doesn't work, because it requires a global co
|
| + } |
| // Iterate down from the top intermediate node found in the previous loop, computing and memoizing transforms as we go. |
| for (auto it = intermediateNodes.rbegin(); it != intermediateNodes.rend(); it++) { |
| @@ -141,6 +208,7 @@ const TransformationMatrix& GeometryMapper::LocalToAncestorMatrix( |
| precomputedData.toAncestorTransforms.set(*it, transformMatrix); |
| } |
| + *success = true; |
| return precomputedData.toAncestorTransforms.find(localTransformNode)->value; |
| } |