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 |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..ab79a470925ca4f7fb9f62990916b512122327cd |
| --- /dev/null |
| +++ b/third_party/WebKit/Source/platform/graphics/paint/GeometryMapper.cpp |
| @@ -0,0 +1,146 @@ |
| +// Copyright 2016 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "platform/graphics/paint/GeometryMapper.h" |
| + |
| +#include "platform/geometry/LayoutRect.h" |
| +#include "platform/graphics/paint/ClipPaintPropertyNode.h" |
| +#include "platform/graphics/paint/EffectPaintPropertyNode.h" |
| +#include "platform/graphics/paint/TransformPaintPropertyNode.h" |
| + |
| +namespace blink { |
| + |
| +FloatRect GeometryMapper::LocalToVisibleRectInAncestorSpace( |
| + const FloatRect& rect, |
| + const PropertyTreeState& localState, |
| + const PropertyTreeState& ancestorState) |
| +{ |
| + const auto transformMatrix = LocalToAncestorMatrix(localState.transform, ancestorState); |
| + FloatRect mappedRect = transformMatrix.mapRect(rect); |
| + |
| + const auto clipRect = LocalToAncestorClipRect(localState, ancestorState); |
| + |
| + mappedRect.intersect(clipRect); |
| + return mappedRect; |
| +} |
| + |
| +FloatRect GeometryMapper::LocalToAncestorRect( |
| + const FloatRect& rect, |
| + const PropertyTreeState& localState, |
| + const PropertyTreeState& ancestorState) |
| +{ |
| + const auto transformMatrix = LocalToAncestorMatrix(localState.transform, ancestorState); |
| + return transformMatrix.mapRect(rect); |
| +} |
| + |
| +FloatRect GeometryMapper::AncestorToLocalRect( |
| + const FloatRect& rect, |
| + const PropertyTreeState& localState, |
| + const PropertyTreeState& ancestorState, bool* success) |
| +{ |
| + const auto& transformMatrix = LocalToAncestorMatrix(localState.transform, ancestorState); |
| + if (!transformMatrix.isInvertible()) { |
| + *success = false; |
| + return FloatRect(); |
| + } |
| + *success = true; |
| + |
| + // TODO(chrishtr): Cache the inverse? |
| + return transformMatrix.inverse().mapRect(rect); |
| +} |
| + |
| +PrecomputedDataForAncestor* GeometryMapper::GetPrecomputedDataForAncestor(const PropertyTreeState& ancestorState) |
|
Xianzhu
2016/06/22 23:20:30
Can this return a reference?
chrishtr
2016/06/23 00:18:26
Done.
|
| +{ |
| + auto first = m_data.add(ancestorState.transform, PrecomputedDataForAncestor()); |
|
wkorman
2016/06/22 23:33:32
nit: believe this will always construct an empty P
chrishtr
2016/06/23 00:18:26
Done.
|
| + auto second = first.storedValue; |
| + return &second->value; |
|
Xianzhu
2016/06/22 23:20:30
It looks not clear what 'first' and 'second' are.
chrishtr
2016/06/23 00:18:26
Done.
|
| +} |
| + |
| +const FloatRect GeometryMapper::LocalToAncestorClipRect( |
|
Xianzhu
2016/06/22 23:20:30
Return a reference?
chrishtr
2016/06/23 00:18:26
Done.
|
| + const PropertyTreeState& localState, |
| + const PropertyTreeState& ancestorState) |
| +{ |
| + PrecomputedDataForAncestor* precomputedData = GetPrecomputedDataForAncestor(ancestorState); |
| + const ClipPaintPropertyNode* clipNode = localState.clip; |
| + Vector<const ClipPaintPropertyNode*> intermediateNodes; |
| + FloatRect clip(LayoutRect::infiniteIntRect()); |
| + |
| + bool found = false; |
| + // Iterate over the path from localState.clip to ancestorState.clip. Stop if we've found a memoized (precomputed) clip |
| + // for any particular node. |
| + while (clipNode) { |
| + auto it = precomputedData->toAncestorClipRects.find(clipNode); |
|
wkorman
2016/06/22 23:33:32
There should only be zero or one, right? Can we us
chrishtr
2016/06/23 00:18:26
get returns a temporary according the compiler, an
|
| + if (it != precomputedData->toAncestorClipRects.end()) { |
| + clip = it->value; |
| + found = true; |
| + break; |
| + } |
| + intermediateNodes.append(clipNode); |
| + |
| + if (clipNode == ancestorState.clip) |
| + break; |
| + |
| + clipNode = clipNode->parent(); |
| + } |
| + // It's illegal to ask for a local-to-ancestor clip when the ancestor is not an ancestor. |
| + DCHECK(clipNode == ancestorState.clip || found); |
| + |
| + // 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); |
| + FloatRect mappedRect = transformMatrix.mapRect((*it)->clipRect().rect()); |
| + clip.intersect(mappedRect); |
| + } |
| + |
| + precomputedData->toAncestorClipRects.set(*it, clip); |
| + } |
| + |
| + return precomputedData->toAncestorClipRects.find(localState.clip)->value; |
| +} |
| + |
| +const TransformationMatrix GeometryMapper::LocalToAncestorMatrix( |
| + const TransformPaintPropertyNode* localTransformNode, |
| + const PropertyTreeState& ancestorState) { |
|
Xianzhu
2016/06/22 23:20:30
Return a reference?
|
| + PrecomputedDataForAncestor* precomputedData = GetPrecomputedDataForAncestor(ancestorState); |
| + |
| + const TransformPaintPropertyNode* transformNode = localTransformNode; |
| + Vector<const TransformPaintPropertyNode*> intermediateNodes; |
| + TransformationMatrix transformMatrix; |
| + |
| + bool found = false; |
| + // Iterate over the path from localTransformNode to ancestorState.transform. Stop if we've found a memoized (precomputed) transform |
| + // for any particular node. |
| + while (transformNode) { |
| + auto it = precomputedData->toAncestorTransforms.find(transformNode); |
| + if (it != precomputedData->toAncestorTransforms.end()) { |
| + transformMatrix = it->value; |
| + found = true; |
| + break; |
| + } |
| + |
| + intermediateNodes.append(transformNode); |
| + |
| + if (transformNode == ancestorState.transform) |
| + break; |
| + |
| + 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); |
| + |
| + // 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++) { |
| + if ((*it) != ancestorState.transform) { |
| + TransformationMatrix localTransformMatrix = (*it)->matrix(); |
| + localTransformMatrix.applyTransformOrigin((*it)->origin()); |
| + transformMatrix = localTransformMatrix * transformMatrix; |
| + } |
| + |
| + precomputedData->toAncestorTransforms.set(*it, transformMatrix); |
| + } |
| + return precomputedData->toAncestorTransforms.find(localTransformNode)->value; |
| +} |
| + |
| +} // namespace blink |