Commit d03b128a authored by Chris Harrelson's avatar Chris Harrelson Committed by Commit Bot

Add a GeometryMapper fast-path to LayoutObject::LocalToAncestorRect.

The first intended use-case of this is use in the CompositingAssignments
update step for overlap testing.

Bug: 1100711

Change-Id: I75e69d0633187fdc80eec71a74811453c6875cef
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2339384Reviewed-by: default avatarXianzhu Wang <wangxianzhu@chromium.org>
Commit-Queue: Chris Harrelson <chrishtr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#795189}
parent 3aec2617
......@@ -3002,6 +3002,63 @@ FloatPoint LayoutObject::LocalToAncestorFloatPoint(
return transform_state.LastPlanarPoint();
}
bool LayoutObject::LocalToAncestorRectFastPath(
const PhysicalRect& rect,
const LayoutBoxModelObject* ancestor,
MapCoordinatesFlags mode,
PhysicalRect& result) const {
if (!(mode & kUseGeometryMapperMode))
return false;
// No other modes are supported.
if (mode & (~kUseGeometryMapperMode))
return false;
if (!ancestor)
ancestor = View();
if (ancestor == this)
return true;
AncestorSkipInfo skip_info(ancestor);
PropertyTreeState container_properties = PropertyTreeState::Uninitialized();
const LayoutObject* property_container =
GetPropertyContainer(&skip_info, &container_properties);
if (!property_container)
return false;
FloatRect mapping_rect(rect);
// This works because it's not possible to have any intervening clips,
// effects, transforms between |this| and |property_container|, and therefore
// FirstFragment().PaintOffset() is relative to the transform space defined by
// FirstFragment().LocalBorderBoxProperties() (if this == property_container)
// or property_container->FirstFragment().ContentsProperties().
mapping_rect.Move(FloatSize(FirstFragment().PaintOffset()));
if (property_container != ancestor) {
GeometryMapper::SourceToDestinationRect(
container_properties.Transform(),
ancestor->FirstFragment().LocalBorderBoxProperties().Transform(),
mapping_rect);
}
mapping_rect.Move(-FloatSize(ancestor->FirstFragment().PaintOffset()));
result = PhysicalRect::EnclosingRect(mapping_rect);
return true;
}
PhysicalRect LayoutObject::LocalToAncestorRect(
const PhysicalRect& rect,
const LayoutBoxModelObject* ancestor,
MapCoordinatesFlags mode) const {
PhysicalRect result;
if (LocalToAncestorRectFastPath(rect, ancestor, mode, result))
return result;
return PhysicalRect::EnclosingRect(
LocalToAncestorQuad(FloatRect(rect), ancestor, mode).BoundingBox());
}
FloatQuad LayoutObject::LocalToAncestorQuad(
const FloatQuad& local_quad,
const LayoutBoxModelObject* ancestor,
......
......@@ -243,6 +243,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
ContainingBlockFixedLayoutObjectInBody);
FRIEND_TEST_ALL_PREFIXES(LayoutObjectTest,
ContainingBlockAbsoluteLayoutObjectInBody);
FRIEND_TEST_ALL_PREFIXES(LayoutObjectTest, LocalToAncestorRectFastPath);
FRIEND_TEST_ALL_PREFIXES(
LayoutObjectTest,
ContainingBlockAbsoluteLayoutObjectShouldNotBeNonStaticallyPositionedInlineAncestor);
......@@ -1713,12 +1714,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// If TraverseDocumentBoundaries is specified, the result will be in the
// space of the local root frame.
// Otherwise, the result will be in the space of the containing frame.
// This method supports kUseGeometryMapper.
PhysicalRect LocalToAncestorRect(const PhysicalRect& rect,
const LayoutBoxModelObject* ancestor,
MapCoordinatesFlags mode = 0) const {
return PhysicalRect::EnclosingRect(
LocalToAncestorQuad(FloatRect(rect), ancestor, mode).BoundingBox());
}
MapCoordinatesFlags mode = 0) const;
// This method supports kUseGeometryMapper.
FloatQuad LocalRectToAncestorQuad(const PhysicalRect& rect,
const LayoutBoxModelObject* ancestor,
MapCoordinatesFlags mode = 0) const {
......@@ -1756,6 +1756,7 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
// Shorthands of the above LocalToAncestor* and AncestorToLocal* functions,
// with nullptr as the ancestor. See the above functions for the meaning of
// "absolute" coordinates.
// This method supports kUseGeometryMapper.
PhysicalRect LocalToAbsoluteRect(const PhysicalRect& rect,
MapCoordinatesFlags mode = 0) const {
return LocalToAncestorRect(rect, nullptr, mode);
......@@ -2794,6 +2795,11 @@ class CORE_EXPORT LayoutObject : public ImageResourceObserver,
const ComputedStyle* FirstLineStyleWithoutFallback() const;
private:
bool LocalToAncestorRectFastPath(const PhysicalRect& rect,
const LayoutBoxModelObject* ancestor,
MapCoordinatesFlags mode,
PhysicalRect& result) const;
FloatQuad LocalToAncestorQuadInternal(const FloatQuad&,
const LayoutBoxModelObject* ancestor,
MapCoordinatesFlags = 0) const;
......
......@@ -1326,4 +1326,66 @@ TEST_F(LayoutObjectTest, PerspectiveWithAnonymousTable) {
EXPECT_EQ(-0.01, decomposed.perspective_z);
}
TEST_F(LayoutObjectTest, LocalToAncestorRectFastPath) {
SetBodyInnerHTML(R"HTML(
<style>body { margin:0; }</style>
<div id=target
style="transform: translate(50px, 25px); width: 10px; height: 10px">
</div>
<div id=ancestor2 style="position: relative">
<div id=target2
style="transform: translate(75px, 15px); width: 10px; height: 10px">
</div>
</div>
)HTML");
LayoutObject* target = GetLayoutObjectByElementId("target");
PhysicalRect rect(0, 0, 10, 10);
PhysicalRect result;
EXPECT_TRUE(target->LocalToAncestorRectFastPath(
rect, nullptr, kUseGeometryMapperMode, result));
EXPECT_EQ(PhysicalRect(50, 25, 10, 10), result);
// Compare with non-fast path.
EXPECT_EQ(PhysicalRect(50, 25, 10, 10),
target->LocalToAncestorRect(rect, nullptr));
// No other modes are supported.
EXPECT_FALSE(target->LocalToAncestorRectFastPath(rect, nullptr, 0, result));
EXPECT_FALSE(
target->LocalToAncestorRectFastPath(rect, nullptr, kIsFixed, result));
EXPECT_FALSE(target->LocalToAncestorRectFastPath(rect, nullptr,
kIgnoreTransforms, result));
EXPECT_FALSE(target->LocalToAncestorRectFastPath(
rect, nullptr, kIgnoreStickyOffset, result));
EXPECT_FALSE(target->LocalToAncestorRectFastPath(
rect, nullptr, kIgnoreScrollOffset, result));
EXPECT_FALSE(target->LocalToAncestorRectFastPath(
rect, nullptr, kApplyRemoteMainFrameTransform, result));
EXPECT_EQ(PhysicalRect(50, 25, 10, 10),
target->LocalToAncestorRect(rect, nullptr, kUseGeometryMapperMode));
LayoutObject* target2 = GetLayoutObjectByElementId("target2");
LayoutObject* ancestor2 = GetLayoutObjectByElementId("ancestor2");
PhysicalRect result2;
EXPECT_TRUE(target2->LocalToAncestorRectFastPath(
rect, ToLayoutBoxModelObject(ancestor2), kUseGeometryMapperMode,
result2));
EXPECT_EQ(PhysicalRect(75, 15, 10, 10), result2);
EXPECT_EQ(
PhysicalRect(75, 15, 10, 10),
target2->LocalToAncestorRect(rect, ToLayoutBoxModelObject(ancestor2)));
// Compare with non-fast path.
EXPECT_TRUE(target2->LocalToAncestorRectFastPath(
rect, nullptr, kUseGeometryMapperMode, result2));
// 25 instead of 15, because #target is 10px high.
EXPECT_EQ(PhysicalRect(75, 25, 10, 10), result2);
EXPECT_EQ(PhysicalRect(75, 25, 10, 10),
target2->LocalToAncestorRect(rect, nullptr));
}
} // namespace blink
......@@ -26,6 +26,12 @@ enum MapCoordinatesMode {
// If the local root frame has a remote frame parent, apply the transformation
// from the local root frame to the remote main frame.
kApplyRemoteMainFrameTransform = 1 << 6,
// Whether to use GeometryMapper to optimize for speed. This can only be
// used it the callsites are in a lifecycle state >= kPrePaintClean.
// This flag is not implemented in all methods that take a MapCoordinatesMode
// parameter; see particular methods for more details.
kUseGeometryMapperMode = 1 << 7,
};
typedef unsigned MapCoordinatesFlags;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment