| Index: third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp
|
| diff --git a/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp b/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp
|
| index 9fbdbbdc0334a6846b9c92221a2d739b6697cc32..f29810a3c90ae406eb4c6d4ab6d22dd2cbfe4616 100644
|
| --- a/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp
|
| +++ b/third_party/WebKit/Source/core/layout/LayoutBoxModelObjectTest.cpp
|
| @@ -249,4 +249,296 @@ TEST_F(LayoutBoxModelObjectTest, StickyPositionAnonymousContainer) {
|
| IntRect(15, 165, 100, 100),
|
| enclosingIntRect(getScrollContainerRelativeStickyBoxRect(constraints)));
|
| }
|
| +
|
| +// Verifies that the sticky constraints are correct when we have a simple case
|
| +// of nested position:sticky.
|
| +TEST_F(LayoutBoxModelObjectTest, StickyPositionNested) {
|
| + setBodyInnerHTML(
|
| + "<style>#scroller { height: 100px; width: 100px; overflow-y: auto; }"
|
| + "#prePadding { height: 50px }"
|
| + "#stickyParent { position: sticky; top: 0; height: 50px; }"
|
| + "#stickyChild { position: sticky; top: 0; height: 25px; }"
|
| + "#postPadding { height: 200px }</style>"
|
| + "<div id='scroller'><div id='prePadding'></div><div id='stickyParent'>"
|
| + "<div id='stickyChild'></div></div><div id='postPadding'></div></div>");
|
| +
|
| + // Make sure that the constraints are cached before scrolling, or they will
|
| + // simply be calculated post-scroll and thus not require offset correction.
|
| +
|
| + LayoutBoxModelObject* stickyParent =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent"));
|
| + stickyParent->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyChild =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyChild"));
|
| + stickyChild->updateStickyPositionConstraints();
|
| +
|
| + // Scroll the page down.
|
| + LayoutBoxModelObject* scroller =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("scroller"));
|
| + PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea();
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 100));
|
| + ASSERT_EQ(100.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // Both the parent and child sticky divs are attempting to place themselves at
|
| + // the top of the scrollable area. To achieve this the parent must offset on
|
| + // the y-axis against its starting position. The child is offset relative to
|
| + // its parent so the child should not move at all.
|
| +
|
| + EXPECT_EQ(LayoutSize(0, 50), stickyParent->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyChild->stickyPositionOffset());
|
| +}
|
| +
|
| +// Verifies that the sticky constraints are correct when the child has a
|
| +// larger edge constraint value than the parent.
|
| +TEST_F(LayoutBoxModelObjectTest, StickyPositionNestedChildLargerTop) {
|
| + setBodyInnerHTML(
|
| + "<style>#scroller { height: 100px; width: 100px; overflow-y: auto; }"
|
| + "#prePadding { height: 50px }"
|
| + "#stickyParent { position: sticky; top: 0; height: 50px; }"
|
| + "#stickyChild { position: sticky; top: 25px; height: 25px; }"
|
| + "#postPadding { height: 200px }</style>"
|
| + "<div id='scroller'><div id='prePadding'></div><div id='stickyParent'>"
|
| + "<div id='stickyChild'></div></div><div id='postPadding'></div></div>");
|
| +
|
| + // Make sure that the constraints are cached before scrolling, or they will
|
| + // simply be calculated post-scroll and thus not require offset correction.
|
| +
|
| + LayoutBoxModelObject* stickyParent =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent"));
|
| + stickyParent->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyChild =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyChild"));
|
| + stickyChild->updateStickyPositionConstraints();
|
| +
|
| + // Scroll the page down.
|
| + LayoutBoxModelObject* scroller =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("scroller"));
|
| + PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea();
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 100));
|
| + ASSERT_EQ(100.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // The parent is attempting to place itself at the top of the scrollable area,
|
| + // whilst the child is attempting to be 25 pixels from the top. To achieve
|
| + // this both must offset on the y-axis against their starting positions, but
|
| + // note the child is offset relative to the parent.
|
| + EXPECT_EQ(LayoutSize(0, 50), stickyParent->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 25), stickyChild->stickyPositionOffset());
|
| +}
|
| +
|
| +// Verifies that the sticky constraints are correct when the child has a
|
| +// smaller edge constraint value than the parent.
|
| +TEST_F(LayoutBoxModelObjectTest, StickyPositionNestedParentLargerTop) {
|
| + setBodyInnerHTML(
|
| + "<style>#scroller { height: 100px; width: 100px; overflow-y: auto; }"
|
| + "#prePadding { height: 50px }"
|
| + "#stickyParent { position: sticky; top: 25px; height: 50px; }"
|
| + "#stickyChild { position: sticky; top: 0; height: 25px; }"
|
| + "#postPadding { height: 200px }</style>"
|
| + "<div id='scroller'><div id='prePadding'></div><div id='stickyParent'>"
|
| + "<div id='stickyChild'></div></div><div id='postPadding'></div></div>");
|
| +
|
| + // Make sure that the constraints are cached before scrolling, or they will
|
| + // simply be calculated post-scroll and thus not require offset correction.
|
| +
|
| + LayoutBoxModelObject* stickyParent =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent"));
|
| + stickyParent->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyChild =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyChild"));
|
| + stickyChild->updateStickyPositionConstraints();
|
| +
|
| + // Scroll the page down.
|
| + LayoutBoxModelObject* scroller =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("scroller"));
|
| + PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea();
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 100));
|
| + ASSERT_EQ(100.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // The parent is attempting to place itself 25 pixels from the top of the
|
| + // scrollable area, whilst the child is attempting to be at the top. However,
|
| + // the child must stay contained within the parent, so it should be pushed
|
| + // down to the same height. As always, the child offset is relative.
|
| + EXPECT_EQ(LayoutSize(0, 75), stickyParent->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyChild->stickyPositionOffset());
|
| +}
|
| +
|
| +// Verifies that the sticky constraints are correct when the child has a large
|
| +// enough edge constraint value to try and push outside of its parent.
|
| +TEST_F(LayoutBoxModelObjectTest,
|
| + StickyPositionNestedChildPushingOutsideParent) {
|
| + setBodyInnerHTML(
|
| + "<style> #scroller { height: 100px; width: 100px; overflow-y: auto; }"
|
| + "#prePadding { height: 50px; }"
|
| + "#stickyParent { position: sticky; top: 0; height: 50px; }"
|
| + "#stickyChild { position: sticky; top: 50px; height: 25px; }"
|
| + "#postPadding { height: 200px }</style>"
|
| + "<div id='scroller'><div id='prePadding'></div><div id='stickyParent'>"
|
| + "<div id='stickyChild'></div></div><div id='postPadding'></div></div>");
|
| +
|
| + // Make sure that the constraints are cached before scrolling, or they will
|
| + // simply be calculated post-scroll and thus not require offset correction.
|
| +
|
| + LayoutBoxModelObject* stickyParent =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyParent"));
|
| + stickyParent->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyChild =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyChild"));
|
| + stickyChild->updateStickyPositionConstraints();
|
| +
|
| + // Scroll the page down.
|
| + LayoutBoxModelObject* scroller =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("scroller"));
|
| + PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea();
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 100));
|
| + ASSERT_EQ(100.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // The parent is attempting to place itself at the top of the scrollable area,
|
| + // whilst the child is attempting to be 50 pixels from the top. However, there
|
| + // is only 25 pixels of space for the child to move into, so it should be
|
| + // capped by that offset. As always, the child offset is relative.
|
| + EXPECT_EQ(LayoutSize(0, 50), stickyParent->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 25), stickyChild->stickyPositionOffset());
|
| +}
|
| +
|
| +// Verifies that the sticky constraints are correct in the case of triple
|
| +// nesting. Triple (or more) nesting must be tested as the grandchild sticky
|
| +// offset must be corrected for both the containing block and the viewport.
|
| +TEST_F(LayoutBoxModelObjectTest, StickyPositionNestedTripleNestedDiv) {
|
| + setBodyInnerHTML(
|
| + "<style>#scroller { height: 200px; width: 100px; overflow-y: auto; }"
|
| + "#prePadding { height: 50px; }"
|
| + "#sticky1 { position: sticky; top: 0; height: 100px; }"
|
| + "#sticky2 { position: sticky; top: 0; height: 75px; }"
|
| + "#sticky3 { position: sticky; top: 25px; height: 25px; }"
|
| + "#postPadding { height: 400px }</style>"
|
| + "<div id='scroller'><div id='prePadding'></div><div id='sticky1'>"
|
| + "<div id='sticky2'><div id='sticky3'></div></div></div>"
|
| + "<div id='postPadding'></div></div>");
|
| +
|
| + // Make sure that the constraints are cached before scrolling, or they will
|
| + // simply be calculated post-scroll and thus not require offset correction.
|
| +
|
| + LayoutBoxModelObject* stickyOne =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("sticky1"));
|
| + stickyOne->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyTwo =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("sticky2"));
|
| + stickyTwo->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyThree =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("sticky3"));
|
| + stickyThree->updateStickyPositionConstraints();
|
| +
|
| + // Scroll the page down.
|
| + LayoutBoxModelObject* scroller =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("scroller"));
|
| + PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea();
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 100));
|
| + ASSERT_EQ(100.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // The grandparent and parent divs are attempting to place themselves at the
|
| + // top of the scrollable area. The child div is attempting to place itself at
|
| + // an offset of 25 pixels to the top of the scrollable area. The result of
|
| + // this sticky offset calculation is quite simple, but internally the child
|
| + // offset has to offset both against its containing block and against its
|
| + // viewport ancestor (the grandparent).
|
| + EXPECT_EQ(LayoutSize(0, 50), stickyOne->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyTwo->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 25), stickyThree->stickyPositionOffset());
|
| +}
|
| +
|
| +// Verifies that the sticky constraints are correct in the case of tables.
|
| +// Tables are special as the containing block for all child elements is always
|
| +// the root level <table>.
|
| +TEST_F(LayoutBoxModelObjectTest, StickyPositionNestedTableExample) {
|
| + setBodyInnerHTML(
|
| + "<style>#scroller { height: 100px; width: 100px; overflow-y: auto; }"
|
| + "#prePadding { height: 50px; }"
|
| + "#stickyDiv { position: sticky; top: 0; height: 200px; }"
|
| + "#table { border-collapse: collapse; }"
|
| + "#stickyThead { position: sticky; top: 0px; }"
|
| + "#stickyTr { position: sticky; top: 0px; }"
|
| + "#stickyTh { position: sticky; top: 0px; }"
|
| + "#postPadding { height: 200px; }</style>"
|
| + "<div id='scroller'><div id='prePadding'></div><div id='stickyDiv'>"
|
| + "<table id='table'><thead id='stickyThead'><tr id='stickyTr'>"
|
| + "<th id='stickyTh'>Header</th></tr></thread><tbody><tr><td>0</td></tr>"
|
| + "<tr><td>1</td></tr><tr><td>2</td></tr><tr><td>3</td></tr></tbody>"
|
| + "</table></div><div id='postPadding'></div></div>");
|
| +
|
| + LOG(INFO) << document().body()->innerHTML();
|
| +
|
| + // Make sure that the constraints are cached before scrolling, or they will
|
| + // simply be calculated post-scroll and thus not require offset correction.
|
| +
|
| + LayoutBoxModelObject* stickyDiv =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyDiv"));
|
| + stickyDiv->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyThead =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyThead"));
|
| + stickyThead->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyTr =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyTr"));
|
| + stickyTr->updateStickyPositionConstraints();
|
| +
|
| + LayoutBoxModelObject* stickyTh =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("stickyTh"));
|
| + stickyTh->updateStickyPositionConstraints();
|
| +
|
| + // Scroll the page down.
|
| + LayoutBoxModelObject* scroller =
|
| + toLayoutBoxModelObject(getLayoutObjectByElementId("scroller"));
|
| + PaintLayerScrollableArea* scrollableArea = scroller->getScrollableArea();
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 150));
|
| + ASSERT_EQ(150.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // All sticky elements are attempting to stick to the top of the scrollable
|
| + // area. For the root sticky div, this requires an offset. All the other
|
| + // descendant sticky elements are positioned relatively so don't need offset.
|
| + EXPECT_EQ(LayoutSize(0, 100), stickyDiv->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyThead->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyTr->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyTh->stickyPositionOffset());
|
| +
|
| + // If we now scroll to the point where the overall sticky div starts to move,
|
| + // the table headers should continue to stick to the top of the scrollable
|
| + // area until they run out of <table> space to move in.
|
| +
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 275));
|
| + ASSERT_EQ(275.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // NOTE(smcgruer): Currently fails - the <th> also moves 12
|
| + // NOTE(smcgruer): I'm not sure that 12 is correct. My hankerchief math gets
|
| + // me something like (275 - 50 - 200) = 25? But it renders correct aisde from
|
| + // the <th>...
|
| + EXPECT_EQ(LayoutSize(0, 200), stickyDiv->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 12), stickyThead->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyTr->stickyPositionOffset());
|
| + EXPECT_EQ(LayoutSize(0, 0), stickyTh->stickyPositionOffset());
|
| +
|
| + // Finally, if we scroll so that the table is off the top of the page, the
|
| + // sticky header should go off the top with it.
|
| +
|
| + scrollableArea->scrollToAbsolutePosition(
|
| + FloatPoint(scrollableArea->scrollPosition().x(), 350));
|
| + ASSERT_EQ(350.0, scrollableArea->scrollPosition().y());
|
| +
|
| + // TODO(smcgruer): Do EXPECT_EQ for this scenario. It's currently broken
|
| + // anyway.
|
| +}
|
| +
|
| } // namespace blink
|
|
|