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
[css-scroll-snap] make resnap follow scroll snap target if necessary #3979
[css-scroll-snap] make resnap follow scroll snap target if necessary #3979
Conversation
EWS run on previous version of this PR (hash 4655b02) |
4655b02
to
1d6586c
Compare
EWS run on previous version of this PR (hash 1d6586c) |
1d6586c
to
fa60119
Compare
EWS run on previous version of this PR (hash fa60119) |
fa60119
to
96fc315
Compare
EWS run on previous version of this PR (hash 96fc315) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Tests are failing, so it seems this needs more work.
|
||
template <typename T> | ||
struct SnapOffset { | ||
T offset; | ||
ScrollSnapStop stop; | ||
bool hasSnapAreaLargerThanViewport; | ||
unsigned snapTargetId; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than storing this extra ID, and the associated (and tricky to maintain) renderer -> ID map, can we just compute the snap offset for the focus thing and send it along as the "preferred snap offset" or "preferred snap index"?
Any way that doesn't involve maintaining a RenderBox -> ID map would be preferable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue with storing a snap index/offset is that it will change across layout, so when updateSnapOffsetsForScrollableArea
is called, we have no way to figure out what the corresponding index/offset is. Instead of having an extra map, would it be preferable to replace the HashSet<const RenderBox*>
already in RenderView
with a set of structs which hold the RenderBox
and id?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually this is not a great solution as we would have to do the work ourselves to maintain the set, due to the ids. This could of course work, but since we are maintaining the map in the same way as the set (which was on RenderView already), could you explain why this isn't preferable?
a0b60cb
to
18f2e06
Compare
EWS run on previous version of this PR (hash a0b60cb) |
EWS run on previous version of this PR (hash 18f2e06) |
18f2e06
to
1b22644
Compare
EWS run on previous version of this PR (hash 1b22644) |
1b22644
to
1b1e602
Compare
EWS run on previous version of this PR (hash 1b1e602) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for working on this tricky issue! I have a few comments, most of which are pretty minor, apart from one more serious concern about associated these new ids with the RenderView
and not the Element
.
if (activeHorizontalID && activeHorizontalIndex) { | ||
if (*activeHorizontalID != snapOffsetsHorizontal[*activeHorizontalIndex].snapTargetId) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If combined into one if statement, this would be a bit clearer, I think. For instance:
if (activeHorizontalID && activeHorizontalIndex &&
*activeHorizontalID != snapOffsetsHorizontal[*activeHorizontalIndex].snapTargetId)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we want to leave the logic like this for horizontal axis. This is due to an implementation detail where we need to choose an axis to prioritize the target for (we choose horizontal). This prevents us from trying to follow the target of the vertical axis when we are already following the target of the horizontal axis.
} | ||
|
||
// If we are snapped to multiple targets, save them | ||
if ((!activeHorizontalID && activeHorizontalIndex) && (!activeVerticalID && activeVerticalIndex) && snapOffsetsForAxis(ScrollEventAxis::Horizontal)[*activeHorizontalIndex].snapTargetId != snapOffsetsForAxis(ScrollEventAxis::Vertical)[*activeVerticalIndex].snapTargetId) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should probably join the if-else-if sequence above, just to make it clearer that this will not happen if we are preserving a previous snap point. I was a bit thrown off by this at first, which is why I mention it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At least to me it makes more sense to have them separate, as the first set of checks are for preserving the target for a particular axis, while the second check is for setting the targets if we don't have any. These seem logically separate to me. I updated the comment to make this difference a bit clearer.
@@ -957,11 +957,13 @@ RenderLayer* RenderView::takeStyleChangeLayerTreeMutationRoot() | |||
void RenderView::registerBoxWithScrollSnapPositions(const RenderBox& box) | |||
{ | |||
m_boxesWithScrollSnapPositions.add(&box); | |||
m_boxesWithScrollSnapPositionsIDMap.add(&box, m_boxesWithScrollSnapPositionsCurrentID++); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder about this approach. The specification says that resnapping after layout should be preserved according the element, but IIUC style change can destroy and recreate an element's RenderView
. Is there a way to rework this so that these identifiers are preserved when the RenderView
is recreated?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
While I'm not too familiar with the lifetime of RenderView
, at least while testing this change I didn't see the RenderView
being destroyed due to any style changes. However, another solution is to use the identifier()
function on each Element
. This also allows us to not maintain a map anymore, which Simon had some concerns about previously. This also might prevent any lifetime issues.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks. The new approach looks great to me.
1b1e602
to
6f4fc64
Compare
EWS run on previous version of this PR (hash 6f4fc64) |
6f4fc64
to
28cb69e
Compare
EWS run on previous version of this PR (hash 28cb69e) |
@nmoucht Also, it seems like the changelog in your commit message is out of date. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks good to me with the changes that @nt1m suggests. Thanks!
d086925
to
4babab7
Compare
EWS run on previous version of this PR (hash d086925) |
4babab7
to
f07c745
Compare
EWS run on previous version of this PR (hash 4babab7) |
EWS run on current version of this PR (hash f07c745) |
https://bugs.webkit.org/show_bug.cgi?id=244745 <rdar://99557242> Reviewed by Martin Robinson. CSS scroll snap spec (https://www.w3.org/TR/css-scroll-snap-1/#re-snap): "If multiple boxes were snapped before and their snap positions no longer coincide, then if one of them is focused or targeted, the scroll container must re-snap to that one and otherwise which one to re-snap to is UA-defined." To acheive this, we add an id to scroll offset which represents the associated element to that scroll offset. We also add a bool which represents wether the associated element is focused. The id of the currently snapped element is added to ScrollSnapAnimatorState and for each relayout, check if it is necessary to preserve the currently snapped element. * LayoutTests/imported/w3c/web-platform-tests/css/css-scroll-snap/snap-after-relayout/resnap-to-focused-expected.txt: * LayoutTests/imported/w3c/web-platform-tests/css/css-scroll-snap/snap-after-relayout/snap-to-different-targets-expected.txt: * Source/WebCore/page/FrameView.cpp: (WebCore::FrameView::updateSnapOffsets): * Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.cpp: (WebCore::updateSnapOffsetsForScrollableArea): (WebCore::convertOffsetInfo): * Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h: (WebCore::operator<<): * Source/WebCore/platform/ScrollSnapAnimatorState.cpp: (WebCore::ScrollSnapAnimatorState::setFocusedElementForAxis): (WebCore::ScrollSnapAnimatorState::preserveCurrentTargetForAxis): (WebCore::ScrollSnapAnimatorState::resnapAfterLayout): * Source/WebCore/platform/ScrollSnapAnimatorState.h: (WebCore::ScrollSnapAnimatorState::activeSnapIDForAxis const): (WebCore::ScrollSnapAnimatorState::setActiveSnapIndexIDForAxis): * Source/WebCore/platform/ScrollableArea.cpp: (WebCore::ScrollableArea::resnapAfterLayout): * Source/WebCore/rendering/RenderLayerScrollableArea.cpp: (WebCore::RenderLayerScrollableArea::updateSnapOffsets): * Source/WebKit/Shared/RemoteLayerTree/RemoteScrollingCoordinatorTransaction.cpp: (ArgumentCoder<SnapOffset<float>>::encode): (ArgumentCoder<SnapOffset<float>>::decode): Canonical link: https://commits.webkit.org/254773@main
f07c745
to
5ed2b1d
Compare
Committed 254773@main (5ed2b1d): https://commits.webkit.org/254773@main Reviewed commits have been landed. Closing PR #3979 and removing active labels. |
5ed2b1d
f07c745
π mac-debugπ tvπ§ͺ mac-wk1π tv-simπ watchπ§ͺ mac-AS-debug-wk2