Skip to content

[css-anchor-position-1] Scroll adjustment not applied for position:fixed anchored boxes #47291

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 30, 2025

Conversation

anttijk
Copy link
Contributor

@anttijk anttijk commented Jun 27, 2025

de4580f

[css-anchor-position-1] Scroll adjustment not applied for position:fixed anchored boxes
https://bugs.webkit.org/show_bug.cgi?id=295002
rdar://154348421

Reviewed by Simon Fraser.

Compute scroll adjustment correctly for fixed positioned anchored boxes.

* LayoutTests/TestExpectations:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-006-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-002-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-004-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-005-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-006-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-007-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-008-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-009-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-010-expected.txt:
* Source/WebCore/page/LocalFrameView.cpp:
(WebCore::LocalFrameView::addViewportConstrainedObject):
(WebCore::LocalFrameView::removeViewportConstrainedObject):
(WebCore::LocalFrameView::hasAnchorPositionedViewportConstrainedObjects const):

See if any of the viewport constrained objects are anchor positioned.

(WebCore::LocalFrameView::clearCachedHasAnchorPositionedViewportConstrainedObjects):
(WebCore::LocalFrameView::shouldUpdateCompositingLayersAfterScrolling const):

We need to update compositing layers on every frame if there are fixed anchor positioned boxes.

(WebCore::LocalFrameView::updateAnchorPositionedAfterScroll):

We need to update anchor positions after document scroll too.

* Source/WebCore/page/LocalFrameView.h:
* Source/WebCore/platform/ScrollableArea.cpp:
(WebCore::ScrollableArea::scrollPositionChanged):
* Source/WebCore/platform/ScrollableArea.h:
(WebCore::ScrollableArea::updateAnchorPositionedAfterScroll):

Factor into a separate virtual function, invoked from ScrollableArea::scrollPositionChanged.

* Source/WebCore/rendering/RenderBox.cpp:
(WebCore::RenderBox::styleWillChange):

Clear the cached fixed-with-anchor bit if anchor positioned style changes.

* Source/WebCore/rendering/RenderLayer.cpp:
(WebCore::RenderLayer::updateLayerPositionsAfterOverflowScroll):
(WebCore::RenderLayer::updateLayerPositionsAfterDocumentScroll):
* Source/WebCore/rendering/RenderLayerScrollableArea.cpp:
(WebCore::RenderLayerScrollableArea::scrollTo):

Move to RenderLayer::updateLayerPositionsAfterOverflowScroll.

* Source/WebCore/style/AnchorPositionEvaluator.cpp:
(WebCore::Style::scrollOffsetFromAnchor):

Take fixed position into account when computing scroll offset.

(WebCore::Style::AnchorPositionEvaluator::updateSnapshottedScrollOffsets):

Use defaultAnchorForBox() to figure out if we need scroll compensation.

(WebCore::Style::AnchorPositionEvaluator::updatePositionsAfterScroll):
(WebCore::Style::AnchorPositionEvaluator::isAnchorPositioned):
(WebCore::Style::scrollOffsetFromAncestorContainer): Deleted.
(WebCore::Style::AnchorPositionEvaluator::updateAfterOverflowScroll): Deleted.
* Source/WebCore/style/AnchorPositionEvaluator.h:

Canonical link: https://commits.webkit.org/296811@main

e52b786

Misc iOS, visionOS, tvOS & watchOS macOS Linux Windows
✅ 🧪 style ✅ 🛠 ios ✅ 🛠 mac ✅ 🛠 wpe ✅ 🛠 win
✅ 🧪 bindings ✅ 🛠 ios-sim ✅ 🛠 mac-AS-debug ✅ 🧪 wpe-wk2 ⏳ 🧪 win-tests
✅ 🧪 webkitperl ✅ 🧪 ios-wk2 ✅ 🧪 api-mac ✅ 🧪 api-wpe
✅ 🧪 ios-wk2-wpt ✅ 🧪 mac-wk1 ✅ 🛠 wpe-cairo
✅ 🧪 api-ios ✅ 🧪 mac-wk2 ✅ 🛠 gtk
✅ 🛠 vision ✅ 🧪 mac-AS-debug-wk2 ✅ 🧪 gtk-wk2
✅ 🛠 vision-sim ✅ 🧪 mac-wk2-stress ✅ 🧪 api-gtk
✅ 🛠 🧪 merge ✅ 🧪 vision-wk2 ✅ 🧪 mac-intel-wk2 ✅ 🛠 playstation
✅ 🛠 tv ✅ 🛠 mac-safer-cpp
✅ 🛠 tv-sim
✅ 🛠 watch
✅ 🛠 watch-sim

@anttijk anttijk self-assigned this Jun 27, 2025
@anttijk anttijk added the Layout and Rendering For bugs with layout and rendering of Web pages. label Jun 27, 2025
@anttijk anttijk force-pushed the anchor-scroll-fixed branch from b7c6dc0 to 87b333b Compare June 27, 2025 11:23
@@ -1006,6 +1006,9 @@ void RenderElement::styleWillChange(StyleDifference diff, const RenderStyle& new
if (drawsRootBackground && newStyle.hasEntirelyFixedBackground() && view().compositor().supportsFixedRootBackgroundCompositing())
newStyleSlowScroll = false;
}
// FIXME: Scrolling tree support for anchor positioning.
if (newStyle.position() == PositionType::Fixed && Style::AnchorPositionEvaluator::isAnchorPositioned(newStyle))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about sticky positioning?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sticky can't be anchor positioned, only fixed and absolute.

@@ -1176,7 +1179,7 @@ void RenderElement::willBeDestroyed()
if (!renderTreeBeingDestroyed() && element())
document().contentChangeObserver().rendererWillBeDestroyed(*element());
#endif
if (m_style.hasAnyFixedBackground() && !settings().fixedBackgroundsPaintRelativeToDocument())
if ((m_style.hasAnyFixedBackground() && !settings().fixedBackgroundsPaintRelativeToDocument()) || (m_style.position() == PositionType::Fixed && Style::AnchorPositionEvaluator::isAnchorPositioned(m_style)))
view().protectedFrameView()->removeSlowRepaintObject(*this);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not ideal to use the "slow repaint" logic for this; this is about needing to layout after scroll, not about painting. This is more like the setViewportConstrainedObjectsNeedLayout code path.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is about needing compositing update for every frame.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Basically LocalFrameView::shouldUpdateCompositingLayersAfterScrolling() needs to return true in this case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did a version using viewport constrained objects.

@@ -6012,6 +6013,9 @@ void RenderLayerCompositor::updateSynchronousScrollingNodes()
} else if (!layer->behavesAsFixed()) {
LOG_WITH_STREAM(Scrolling, stream << "RenderLayerCompositor::updateSynchronousScrollingNodes - root node slow-scrolling because of fixed backgrounds");
rootHasSlowRepaintObjects = true;
} else if (Style::AnchorPositionEvaluator::isAnchorPositioned(renderer.style())) {
LOG_WITH_STREAM(Scrolling, stream << "RenderLayerCompositor::updateSynchronousScrollingNodes - root node slow-scrolling because of a fixed anchored element");
rootHasSlowRepaintObjects = true;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, mixing layout with repainting.


auto offset = LayoutSize { };
for (auto* ancestor = descendant.container(); ancestor && ancestor != &ancestorContainer; ancestor = ancestor->container()) {
bool isFixedAnchor = anchor.isFixedPositioned();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need to consider sticky.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above.

for (auto* ancestor = descendant.container(); ancestor && ancestor != &ancestorContainer; ancestor = ancestor->container()) {
bool isFixedAnchor = anchor.isFixedPositioned();

for (auto* ancestor = anchor.container(); ancestor && ancestor != containingBlock; ancestor = ancestor->container()) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CheckedPtr?

@anttijk anttijk force-pushed the anchor-scroll-fixed branch from 87b333b to 6e95cfc Compare June 30, 2025 12:48
@anttijk anttijk requested a review from cdumez as a code owner June 30, 2025 12:48
@anttijk anttijk force-pushed the anchor-scroll-fixed branch from 6e95cfc to e52b786 Compare June 30, 2025 13:07
@anttijk anttijk added the merge-queue Applied to send a pull request to merge-queue label Jun 30, 2025
…xed anchored boxes

https://bugs.webkit.org/show_bug.cgi?id=295002
rdar://154348421

Reviewed by Simon Fraser.

Compute scroll adjustment correctly for fixed positioned anchored boxes.

* LayoutTests/TestExpectations:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-006-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-002-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-004-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-005-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-006-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-007-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-008-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-009-expected.txt:
* LayoutTests/imported/w3c/web-platform-tests/css/css-anchor-position/anchor-scroll-position-try-010-expected.txt:
* Source/WebCore/page/LocalFrameView.cpp:
(WebCore::LocalFrameView::addViewportConstrainedObject):
(WebCore::LocalFrameView::removeViewportConstrainedObject):
(WebCore::LocalFrameView::hasAnchorPositionedViewportConstrainedObjects const):

See if any of the viewport constrained objects are anchor positioned.

(WebCore::LocalFrameView::clearCachedHasAnchorPositionedViewportConstrainedObjects):
(WebCore::LocalFrameView::shouldUpdateCompositingLayersAfterScrolling const):

We need to update compositing layers on every frame if there are fixed anchor positioned boxes.

(WebCore::LocalFrameView::updateAnchorPositionedAfterScroll):

We need to update anchor positions after document scroll too.

* Source/WebCore/page/LocalFrameView.h:
* Source/WebCore/platform/ScrollableArea.cpp:
(WebCore::ScrollableArea::scrollPositionChanged):
* Source/WebCore/platform/ScrollableArea.h:
(WebCore::ScrollableArea::updateAnchorPositionedAfterScroll):

Factor into a separate virtual function, invoked from ScrollableArea::scrollPositionChanged.

* Source/WebCore/rendering/RenderBox.cpp:
(WebCore::RenderBox::styleWillChange):

Clear the cached fixed-with-anchor bit if anchor positioned style changes.

* Source/WebCore/rendering/RenderLayer.cpp:
(WebCore::RenderLayer::updateLayerPositionsAfterOverflowScroll):
(WebCore::RenderLayer::updateLayerPositionsAfterDocumentScroll):
* Source/WebCore/rendering/RenderLayerScrollableArea.cpp:
(WebCore::RenderLayerScrollableArea::scrollTo):

Move to RenderLayer::updateLayerPositionsAfterOverflowScroll.

* Source/WebCore/style/AnchorPositionEvaluator.cpp:
(WebCore::Style::scrollOffsetFromAnchor):

Take fixed position into account when computing scroll offset.

(WebCore::Style::AnchorPositionEvaluator::updateSnapshottedScrollOffsets):

Use defaultAnchorForBox() to figure out if we need scroll compensation.

(WebCore::Style::AnchorPositionEvaluator::updatePositionsAfterScroll):
(WebCore::Style::AnchorPositionEvaluator::isAnchorPositioned):
(WebCore::Style::scrollOffsetFromAncestorContainer): Deleted.
(WebCore::Style::AnchorPositionEvaluator::updateAfterOverflowScroll): Deleted.
* Source/WebCore/style/AnchorPositionEvaluator.h:

Canonical link: https://commits.webkit.org/296811@main
@webkit-commit-queue
Copy link
Collaborator

Committed 296811@main (de4580f): https://commits.webkit.org/296811@main

Reviewed commits have been landed. Closing PR #47291 and removing active labels.

@webkit-commit-queue webkit-commit-queue merged commit de4580f into WebKit:main Jun 30, 2025
@webkit-commit-queue webkit-commit-queue removed the merge-queue Applied to send a pull request to merge-queue label Jun 30, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Layout and Rendering For bugs with layout and rendering of Web pages.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants