Changeset 210560 in webkit
- Timestamp:
- Jan 10, 2017 2:26:56 PM (7 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 47 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r210559 r210560 1 2017-01-10 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Implement "proximity" scroll snapping 4 https://bugs.webkit.org/show_bug.cgi?id=135994 5 <rdar://problem/18162418> 6 7 Reviewed by Dean Jackson. 8 9 Adds 3 new layout tests for proximity scroll snapping. Also tweaks some existing tests that test scroll snapping 10 after scrolling with momentum to use the custom heuristic for predicting scroll destination instead of platform 11 momentum scrolling. This ensures that the results of our layout tests that depend on predicting momentum scroll 12 destination are consistent across runs. 13 14 * tiled-drawing/scrolling/latched-div-with-scroll-snap.html: 15 * tiled-drawing/scrolling/scroll-snap/scroll-snap-iframe.html: 16 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow.html: 17 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-borders.html: 18 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-hidden-scrollbars.html: 19 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html: 20 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html: 21 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html: 22 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html: 23 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html: 24 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-overflow-stateless.html: 25 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-overflow.html: 26 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-padding.html: 27 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-rotated.html: 28 29 Force these tests to use platform-independent scrolling momentum prediction, by multiplying the last scroll 30 delta upon release by a constant factor. 31 32 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-then-proximity-expected.txt: Added. 33 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-then-proximity.html: Added. 34 35 Tests that after changing scroll-snap-type from mandatory to proximity, swiping downwards no longer snaps the 36 scroll offset to the second box, but instead leaves the scroll offset somewhere in the middle of the first box. 37 38 * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe-expected.txt: Added. 39 * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html: Added. 40 41 Tests that when scroll-snap-type is proximity in the mainframe, scrolling slightly downwards snaps the scroll 42 offset back up to the top; scrolling somewhere in the middle of the first box does not snap the scroll offset; 43 and scrolling near the end of the first box snaps the scroll offset to the second box. 44 45 * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-overflow-expected.txt: Added. 46 * tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-overflow.html: Added. 47 48 Similar to scroll-snap-proximity-mainframe.html, except for overflow scrolling instead of the mainframe. 49 50 * tiled-drawing/scrolling/scroll-snap/scroll-snap-scrolling-jumps-to-top.html: 51 1 52 2017-01-10 Chris Dumez <cdumez@apple.com> 2 53 -
trunk/LayoutTests/tiled-drawing/scrolling/latched-div-with-scroll-snap.html
r210024 r210560 75 75 write(`* Swiping ${momentum ? "with" : "without"} momentum in ${element.id} with scroll offset ${element.scrollLeft}`); 76 76 let location = locationInWindowCoordinates(element); 77 internals.setPlatformMomentumScrollingPredictionEnabled(false); 77 78 eventSender.monitorWheelEvents(); 78 79 eventSender.mouseMoveTo(location.x, location.y); -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-iframe.html
r188793 r210560 148 148 if (window.eventSender) { 149 149 eventSender.monitorWheelEvents(); 150 internals.setPlatformMomentumScrollingPredictionEnabled(false); 150 151 setTimeout(function() { scrollGlideTest('horizontalTarget') }, 0); 151 152 } -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow.html
r210024 r210560 124 124 if (window.eventSender) { 125 125 eventSender.monitorWheelEvents(); 126 internals.setPlatformMomentumScrollingPredictionEnabled(false); 126 127 setTimeout(scrollGlideTest, 0); 127 128 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-borders.html
r210024 r210560 178 178 if (window.eventSender) { 179 179 eventSender.monitorWheelEvents(); 180 internals.setPlatformMomentumScrollingPredictionEnabled(false); 180 181 setTimeout(function() { scrollGlideTest('horizontalTarget') }, 0); 181 182 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-hidden-scrollbars.html
r210117 r210560 45 45 } 46 46 47 internals.setPlatformMomentumScrollingPredictionEnabled(false); 47 48 eventSender.monitorWheelEvents(); 48 49 eventSender.mouseMoveTo(250, 250); -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html
r210024 r210560 92 92 if (window.eventSender) { 93 93 eventSender.monitorWheelEvents(); 94 internals.setPlatformMomentumScrollingPredictionEnabled(false); 94 95 setTimeout(scrollGlideTest, 0); 95 96 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html
r210024 r210560 92 92 if (window.eventSender) { 93 93 eventSender.monitorWheelEvents(); 94 internals.setPlatformMomentumScrollingPredictionEnabled(false); 94 95 setTimeout(scrollGlideTest, 0); 95 96 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html
r210024 r210560 91 91 if (window.eventSender) { 92 92 eventSender.monitorWheelEvents(); 93 internals.setPlatformMomentumScrollingPredictionEnabled(false); 93 94 setTimeout(scrollGlideTest, 0); 94 95 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html
r210024 r210560 53 53 if (window.eventSender) { 54 54 eventSender.monitorWheelEvents(); 55 internals.setPlatformMomentumScrollingPredictionEnabled(false); 55 56 setTimeout(scrollSnapTest, 0); 56 57 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html
r210024 r210560 92 92 if (window.eventSender) { 93 93 eventSender.monitorWheelEvents(); 94 internals.setPlatformMomentumScrollingPredictionEnabled(false); 94 95 setTimeout(scrollGlideTest, 0); 95 96 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-overflow-stateless.html
r210024 r210560 69 69 if (window.eventSender) { 70 70 eventSender.monitorWheelEvents(); 71 internals.setPlatformMomentumScrollingPredictionEnabled(false); 71 72 setTimeout(scrollSnapTest, 0); 72 73 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-overflow.html
r210024 r210560 168 168 if (window.eventSender) { 169 169 eventSender.monitorWheelEvents(); 170 internals.setPlatformMomentumScrollingPredictionEnabled(false); 170 171 setTimeout(function() { scrollGlideTest('horizontalTarget') }, 0); 171 172 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-padding.html
r210024 r210560 178 178 if (window.eventSender) { 179 179 eventSender.monitorWheelEvents(); 180 internals.setPlatformMomentumScrollingPredictionEnabled(false); 180 181 setTimeout(function() { scrollGlideTest('horizontalTarget') }, 0); 181 182 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-rotated.html
r210024 r210560 170 170 if (window.eventSender) { 171 171 eventSender.monitorWheelEvents(); 172 internals.setPlatformMomentumScrollingPredictionEnabled(false); 172 173 setTimeout(function() { scrollGlideTest('horizontalTarget') }, 0); 173 174 } else { -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-scrolling-jumps-to-top.html
r210024 r210560 35 35 testRunner.waitUntilDone(); 36 36 eventSender.monitorWheelEvents(); 37 internals.setPlatformMomentumScrollingPredictionEnabled(false); 37 38 eventSender.mouseMoveTo(container.offsetLeft + container.clientWidth / 2, container.offsetTop + container.clientHeight / 2); 38 39 -
trunk/Source/WebCore/ChangeLog
r210559 r210560 1 2017-01-10 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Implement "proximity" scroll snapping 4 https://bugs.webkit.org/show_bug.cgi?id=135994 5 <rdar://problem/18162418> 6 7 Reviewed by Dean Jackson. 8 9 Adds support for proximity scroll snapping. To do this, we introduce scroll offset ranges, a list of scroll 10 offset ranges that are plumbed alongside the list of scroll snap offsets. Similar to a snap offset, a snap 11 offset range contains scroll offsets on which scrolling is allowed to come to a rest within a scroll snapping 12 container. However, unlike normal snap offsets, scrolling may only come to rest within a snap offset range if 13 the predicted scroll offset already lies within the range. The new algorithm for selecting a target scroll snap 14 position given a destination offset is now: 15 16 - If the scroll destination lies within a snap offset range, return the scroll destination 17 - Otherwise, compute the nearest lower/upper snap offsets and lower/upper snap offset ranges 18 - If scrolling ended with no velocity, return the nearest snap offset 19 - If scrolling ended with positive velocity, choose the upper snap offset only if there is no snap offset 20 range in between the scroll destination and the snap offset; else, choose the lower snap offset 21 - If scrolling ended with negative velocity, choose the lower snap offset only if there is no snap offset 22 range in between the scroll destination and the snap offset; else, choose the upper snap offset 23 24 The extra rule accounting for scroll offset ranges in between the scroll destination and a potential snap offset 25 handles the corner case where the user scrolls with momentum very lightly away from a snap offset, such that the 26 predicted scroll destination is still within proximity of the snap offset. In this case, the regular (mandatory 27 scroll snapping) behavior would be to snap to the next offset in the direction of momentum scrolling, but 28 instead, it is more intuitive to return to the original snap position. 29 30 We also move scrolling prediction logic into ScrollingMomentumCalculator and adopt the platform 31 _NSScrollingMomentumCalculator's destinationOrigin property when computing the predicted scroll destination. 32 Previously, we were simply multiplying by an empirically-derived constant to approximate the scroll destination, 33 but now that we are supporting proximity scroll snapping, we need more exact scroll destinaton prediction in 34 order to make sure that scrolling to a snap offset range feels natural. 35 36 Tests: tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-then-proximity.html 37 tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-mainframe.html 38 tiled-drawing/scrolling/scroll-snap/scroll-snap-proximity-overflow.html 39 40 * WebCore.xcodeproj/project.pbxproj: 41 * page/scrolling/AsyncScrollingCoordinator.cpp: 42 (WebCore::setStateScrollingNodeSnapOffsetsAsFloat): 43 (WebCore::AsyncScrollingCoordinator::updateOverflowScrollingNode): 44 (WebCore::AsyncScrollingCoordinator::updateScrollSnapPropertiesWithFrameView): 45 46 Make boilerplate changes to plumb lists of horizontal and vertical snap offset ranges alongside the lists of 47 horizontal and vertical snap offsets. 48 49 * page/scrolling/AxisScrollSnapOffsets.cpp: 50 (WebCore::snapOffsetRangesToString): 51 (WebCore::indicesOfNearestSnapOffsetRanges): 52 (WebCore::indicesOfNearestSnapOffsets): 53 (WebCore::adjustAxisSnapOffsetsForScrollExtent): 54 (WebCore::computeAxisProximitySnapOffsetRanges): 55 (WebCore::updateSnapOffsetsForScrollableArea): 56 (WebCore::closestSnapOffset): 57 58 Adjust the snap offset selection algorithm to take snap offset ranges into account. See above for more details. 59 Additionally, augment snap offset update logic to emit snap offset ranges for proximity scroll snapping. To do 60 this, we run the following steps on the final list of processed snap offsets: 61 - Compute the proximity distance, which (for now) is arbitrarily 0.3 * the length or width of the scroll snap 62 port, depending on whether scroll snapping is taking place in the X or Y axis. 63 - For each pair of adjacent snap offsets, if they are more than 2 * proximity distance away from each other, 64 emit a snap offset range starting from (lower snap offset + proximity distance) and ending on (upper snap 65 offset + proximity distance). 66 67 * page/scrolling/AxisScrollSnapOffsets.h: 68 (WebCore::closestSnapOffset): Deleted. 69 * page/scrolling/ScrollSnapOffsetsInfo.h: 70 71 Introduce ScrollSnapOffsetsInfo, a struct which contains data relevant to scroll snapping. This includes 72 vertical and horizontal snap offsets, as well as vertical and horizontal snap offset ranges. Snap offset ranges 73 consist of a vector of ranges of scroll offsets. 74 75 * page/scrolling/ScrollingCoordinator.h: 76 * page/scrolling/ScrollingMomentumCalculator.cpp: 77 (WebCore::projectedInertialScrollDistance): 78 (WebCore::ScrollingMomentumCalculator::ScrollingMomentumCalculator): 79 (WebCore::ScrollingMomentumCalculator::setRetargetedScrollOffset): 80 (WebCore::ScrollingMomentumCalculator::predictedDestinationOffset): 81 (WebCore::ScrollingMomentumCalculator::create): 82 (WebCore::ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled): 83 (WebCore::BasicScrollingMomentumCalculator::BasicScrollingMomentumCalculator): 84 (WebCore::BasicScrollingMomentumCalculator::linearlyInterpolatedOffsetAtProgress): 85 (WebCore::BasicScrollingMomentumCalculator::initializeInterpolationCoefficientsIfNecessary): 86 (WebCore::BasicScrollingMomentumCalculator::initializeSnapProgressCurve): 87 * page/scrolling/ScrollingMomentumCalculator.h: 88 (WebCore::ScrollingMomentumCalculator::retargetedScrollOffset): 89 (WebCore::ScrollingMomentumCalculator::retargetedScrollOffsetDidChange): 90 91 Currently, the ScrollingMomentumCalculator is responsible for taking an initial position, initial velocity, and 92 target position and animating the scroll offset from the initial to target position. Now, we refactor the 93 ScrollingMomentumCalculator interface to no longer take a target offset upon initialization, and instead compute 94 the predicted scroll destination given initial position and velocity; clients of the ScrollingMomentumCalculator 95 then use this predicted scroll destination to compute a retargeted scroll offset and then call 96 setRetargetedScrollOffset on the calculator, which sets up an animation curve to the new retargeted offset. This 97 allows both the AppKit-based scrolling momentum calculator and platform-invariant momentum calculator to be used 98 interchangeably, while still allowing them to compute a destination offset from initial parameters of the 99 scroll. 100 101 * page/scrolling/ScrollingStateScrollingNode.cpp: 102 (WebCore::ScrollingStateScrollingNode::ScrollingStateScrollingNode): 103 (WebCore::ScrollingStateScrollingNode::setHorizontalSnapOffsets): 104 (WebCore::ScrollingStateScrollingNode::setVerticalSnapOffsets): 105 (WebCore::ScrollingStateScrollingNode::setHorizontalSnapOffsetRanges): 106 (WebCore::ScrollingStateScrollingNode::setVerticalSnapOffsetRanges): 107 * page/scrolling/ScrollingStateScrollingNode.h: 108 (WebCore::ScrollingStateScrollingNode::horizontalSnapOffsets): 109 (WebCore::ScrollingStateScrollingNode::verticalSnapOffsets): 110 (WebCore::ScrollingStateScrollingNode::horizontalSnapOffsetRanges): 111 (WebCore::ScrollingStateScrollingNode::verticalSnapOffsetRanges): 112 * page/scrolling/ScrollingTreeScrollingNode.cpp: 113 (WebCore::ScrollingTreeScrollingNode::commitStateBeforeChildren): 114 (WebCore::ScrollingTreeScrollingNode::dumpProperties): 115 * page/scrolling/ScrollingTreeScrollingNode.h: 116 (WebCore::ScrollingTreeScrollingNode::horizontalSnapOffsets): 117 (WebCore::ScrollingTreeScrollingNode::verticalSnapOffsets): 118 (WebCore::ScrollingTreeScrollingNode::horizontalSnapOffsetRanges): 119 (WebCore::ScrollingTreeScrollingNode::verticalSnapOffsetRanges): 120 121 Add more boilerplate support for snap offset ranges. 122 123 * page/scrolling/mac/ScrollingMomentumCalculatorMac.h: 124 * page/scrolling/mac/ScrollingMomentumCalculatorMac.mm: 125 (WebCore::ScrollingMomentumCalculator::create): 126 (WebCore::ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled): 127 (WebCore::ScrollingMomentumCalculatorMac::ScrollingMomentumCalculatorMac): 128 (WebCore::ScrollingMomentumCalculatorMac::scrollOffsetAfterElapsedTime): 129 (WebCore::ScrollingMomentumCalculatorMac::predictedDestinationOffset): 130 (WebCore::ScrollingMomentumCalculatorMac::retargetedScrollOffsetDidChange): 131 (WebCore::ScrollingMomentumCalculatorMac::animationDuration): 132 (WebCore::ScrollingMomentumCalculatorMac::requiresMomentumScrolling): 133 (WebCore::ScrollingMomentumCalculatorMac::ensurePlatformMomentumCalculator): 134 135 Hook into AppKit momentum scroll offset prediction. 136 137 * page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm: 138 (WebCore::convertToLayoutUnits): 139 (WebCore::ScrollingTreeFrameScrollingNodeMac::commitStateBeforeChildren): 140 * platform/ScrollableArea.cpp: 141 (WebCore::ScrollableArea::ensureSnapOffsetsInfo): 142 (WebCore::ScrollableArea::horizontalSnapOffsets): 143 (WebCore::ScrollableArea::horizontalSnapOffsetRanges): 144 (WebCore::ScrollableArea::verticalSnapOffsetRanges): 145 (WebCore::ScrollableArea::verticalSnapOffsets): 146 (WebCore::ScrollableArea::setHorizontalSnapOffsets): 147 (WebCore::ScrollableArea::setVerticalSnapOffsets): 148 (WebCore::ScrollableArea::setHorizontalSnapOffsetRanges): 149 (WebCore::ScrollableArea::setVerticalSnapOffsetRanges): 150 (WebCore::ScrollableArea::clearHorizontalSnapOffsets): 151 (WebCore::ScrollableArea::clearVerticalSnapOffsets): 152 * platform/ScrollableArea.h: 153 (WebCore::ScrollableArea::horizontalSnapOffsets): Deleted. 154 (WebCore::ScrollableArea::verticalSnapOffsets): Deleted. 155 * platform/cocoa/ScrollController.h: 156 * platform/cocoa/ScrollController.mm: 157 (WebCore::ScrollController::processWheelEventForScrollSnap): 158 159 Fix an issue where initial scrolling velocity would be set to zero at the end of a drag gesture. 160 161 (WebCore::ScrollController::updateScrollSnapState): 162 (WebCore::ScrollController::updateScrollSnapPoints): 163 (WebCore::ScrollController::setNearestScrollSnapIndexForAxisAndOffset): 164 * platform/cocoa/ScrollSnapAnimatorState.h: 165 (WebCore::ScrollSnapAnimatorState::snapOffsetsForAxis): 166 (WebCore::ScrollSnapAnimatorState::snapOffsetRangesForAxis): 167 (WebCore::ScrollSnapAnimatorState::setSnapOffsetsAndPositionRangesForAxis): 168 (WebCore::ScrollSnapAnimatorState::setSnapOffsetsForAxis): Deleted. 169 * platform/cocoa/ScrollSnapAnimatorState.mm: 170 (WebCore::ScrollSnapAnimatorState::setupAnimationForState): 171 (WebCore::ScrollSnapAnimatorState::targetOffsetForStartOffset): 172 (WebCore::projectedInertialScrollDistance): Deleted. 173 * rendering/RenderLayerCompositor.cpp: 174 (WebCore::RenderLayerCompositor::updateScrollCoordinatedLayer): 175 * testing/Internals.cpp: 176 (WebCore::Internals::setPlatformMomentumScrollingPredictionEnabled): 177 178 Add a new hook for layout tests to force scrolling momentum calculators to use the platform-invariant momentum 179 scrolling prediction heuristic instead of the platform-dependent one. 180 181 (WebCore::Internals::scrollSnapOffsets): 182 * testing/Internals.h: 183 * testing/Internals.idl: 184 1 185 2017-01-10 Chris Dumez <cdumez@apple.com> 2 186 -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r210555 r210560 6488 6488 F45C231D1995B73B00A6E2E3 /* AxisScrollSnapOffsets.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F45C231B1995B73B00A6E2E3 /* AxisScrollSnapOffsets.cpp */; }; 6489 6489 F45C231E1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h in Headers */ = {isa = PBXBuildFile; fileRef = F45C231C1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h */; settings = {ATTRIBUTES = (Private, ); }; }; 6490 F46729281E0DE68500ACC3D8 /* ScrollSnapOffsetsInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = F46729251E0DE5AB00ACC3D8 /* ScrollSnapOffsetsInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; 6490 6491 F478755419983AFF0024A287 /* ScrollSnapAnimatorState.h in Headers */ = {isa = PBXBuildFile; fileRef = F478755219983AFF0024A287 /* ScrollSnapAnimatorState.h */; settings = {ATTRIBUTES = (Private, ); }; }; 6491 6492 F478755519983AFF0024A287 /* ScrollSnapAnimatorState.mm in Sources */ = {isa = PBXBuildFile; fileRef = F478755319983AFF0024A287 /* ScrollSnapAnimatorState.mm */; }; … … 14510 14511 F45C231B1995B73B00A6E2E3 /* AxisScrollSnapOffsets.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AxisScrollSnapOffsets.cpp; sourceTree = "<group>"; }; 14511 14512 F45C231C1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AxisScrollSnapOffsets.h; sourceTree = "<group>"; }; 14513 F46729251E0DE5AB00ACC3D8 /* ScrollSnapOffsetsInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollSnapOffsetsInfo.h; sourceTree = "<group>"; }; 14512 14514 F478755219983AFF0024A287 /* ScrollSnapAnimatorState.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollSnapAnimatorState.h; sourceTree = "<group>"; }; 14513 14515 F478755319983AFF0024A287 /* ScrollSnapAnimatorState.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollSnapAnimatorState.mm; sourceTree = "<group>"; }; … … 16040 16042 9391A99A1629D6FF00297330 /* ScrollingTreeScrollingNode.cpp */, 16041 16043 9391A99B1629D70000297330 /* ScrollingTreeScrollingNode.h */, 16044 F46729251E0DE5AB00ACC3D8 /* ScrollSnapOffsetsInfo.h */, 16042 16045 7AAFE8CD19CB8672000F56D8 /* ScrollLatchingState.cpp */, 16043 16046 7AAFE8CE19CB8672000F56D8 /* ScrollLatchingState.h */, … … 26184 26187 BC5A86B60C3367E800EEA649 /* JSDOMSelection.h in Headers */, 26185 26188 C5137CF311A58378004ADB99 /* JSDOMStringList.h in Headers */, 26189 F46729281E0DE68500ACC3D8 /* ScrollSnapOffsetsInfo.h in Headers */, 26186 26190 BC64649811D82349006455B0 /* JSDOMStringMap.h in Headers */, 26187 26191 7694563D1214D97C0007CBAE /* JSDOMTokenList.h in Headers */, -
trunk/Source/WebCore/page/scrolling/AsyncScrollingCoordinator.cpp
r209087 r210560 66 66 } 67 67 68 static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, ScrollEventAxis axis, const Vector<LayoutUnit>* snapOffsets, float deviceScaleFactor)68 static inline void setStateScrollingNodeSnapOffsetsAsFloat(ScrollingStateScrollingNode& node, ScrollEventAxis axis, const Vector<LayoutUnit>* snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>* snapOffsetRanges, float deviceScaleFactor) 69 69 { 70 70 // FIXME: Incorporate current page scale factor in snapping to device pixel. Perhaps we should just convert to float here and let UI process do the pixel snapping? … … 75 75 snapOffsetsAsFloat.uncheckedAppend(roundToDevicePixel(offset, deviceScaleFactor, false)); 76 76 } 77 if (axis == ScrollEventAxis::Horizontal) 77 78 Vector<ScrollOffsetRange<float>> snapOffsetRangesAsFloat; 79 if (snapOffsetRanges) { 80 snapOffsetRangesAsFloat.reserveInitialCapacity(snapOffsetRanges->size()); 81 for (auto& range : *snapOffsetRanges) 82 snapOffsetRangesAsFloat.uncheckedAppend({ roundToDevicePixel(range.start, deviceScaleFactor, false), roundToDevicePixel(range.end, deviceScaleFactor, false) }); 83 } 84 if (axis == ScrollEventAxis::Horizontal) { 78 85 node.setHorizontalSnapOffsets(snapOffsetsAsFloat); 79 else 86 node.setHorizontalSnapOffsetRanges(snapOffsetRangesAsFloat); 87 } else { 80 88 node.setVerticalSnapOffsets(snapOffsetsAsFloat); 89 node.setVerticalSnapOffsetRanges(snapOffsetRangesAsFloat); 90 } 81 91 } 82 92 … … 538 548 node->setScrollableAreaSize(scrollingGeometry->scrollableAreaSize); 539 549 #if ENABLE(CSS_SCROLL_SNAP) 540 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, &scrollingGeometry->horizontalSnapOffsets, m_page->deviceScaleFactor());541 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, &scrollingGeometry->verticalSnapOffsets, m_page->deviceScaleFactor());550 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, &scrollingGeometry->horizontalSnapOffsets, &scrollingGeometry->horizontalSnapOffsetRanges, m_page->deviceScaleFactor()); 551 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, &scrollingGeometry->verticalSnapOffsets, &scrollingGeometry->verticalSnapOffsetRanges, m_page->deviceScaleFactor()); 542 552 node->setCurrentHorizontalSnapPointIndex(scrollingGeometry->currentHorizontalSnapPointIndex); 543 553 node->setCurrentVerticalSnapPointIndex(scrollingGeometry->currentVerticalSnapPointIndex); … … 683 693 { 684 694 if (auto node = downcast<ScrollingStateFrameScrollingNode>(m_scrollingStateTree->stateNodeForID(frameView.scrollLayerID()))) { 685 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, frameView.horizontalSnapOffsets(), m_page->deviceScaleFactor());686 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, frameView.verticalSnapOffsets(), m_page->deviceScaleFactor());695 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Horizontal, frameView.horizontalSnapOffsets(), frameView.horizontalSnapOffsetRanges(), m_page->deviceScaleFactor()); 696 setStateScrollingNodeSnapOffsetsAsFloat(*node, ScrollEventAxis::Vertical, frameView.verticalSnapOffsets(), frameView.verticalSnapOffsetRanges(), m_page->deviceScaleFactor()); 687 697 node->setCurrentHorizontalSnapPointIndex(frameView.currentHorizontalSnapPointIndex()); 688 698 node->setCurrentVerticalSnapPointIndex(frameView.currentVerticalSnapPointIndex()); -
trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.cpp
r210024 r210560 85 85 } 86 86 87 static String snapOffsetRangesToString(const Vector<ScrollOffsetRange<LayoutUnit>>& ranges) 88 { 89 StringBuilder s; 90 s.append("[ "); 91 for (auto range : ranges) 92 s.append(String::format("(%.1f, %.1f) ", range.start.toFloat(), range.end.toFloat())); 93 s.append("]"); 94 return s.toString(); 95 } 96 87 97 static String snapPortOrAreaToString(const LayoutRect& rect) 88 98 { … … 91 101 92 102 #endif 103 104 template <typename LayoutType> 105 static void indicesOfNearestSnapOffsetRanges(LayoutType offset, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, unsigned& lowerIndex, unsigned& upperIndex) 106 { 107 if (snapOffsetRanges.isEmpty()) { 108 lowerIndex = invalidSnapOffsetIndex; 109 upperIndex = invalidSnapOffsetIndex; 110 return; 111 } 112 113 int lowerIndexAsInt = -1; 114 int upperIndexAsInt = snapOffsetRanges.size(); 115 do { 116 int middleIndex = (lowerIndexAsInt + upperIndexAsInt) / 2; 117 auto& range = snapOffsetRanges[middleIndex]; 118 if (range.start < offset && offset < range.end) { 119 lowerIndexAsInt = middleIndex; 120 upperIndexAsInt = middleIndex; 121 break; 122 } 123 124 if (offset > range.end) 125 lowerIndexAsInt = middleIndex; 126 else 127 upperIndexAsInt = middleIndex; 128 } while (lowerIndexAsInt < upperIndexAsInt - 1); 129 130 if (offset <= snapOffsetRanges.first().start) 131 lowerIndex = invalidSnapOffsetIndex; 132 else 133 lowerIndex = lowerIndexAsInt; 134 135 if (offset >= snapOffsetRanges.last().end) 136 upperIndex = invalidSnapOffsetIndex; 137 else 138 upperIndex = upperIndexAsInt; 139 } 140 141 template <typename LayoutType> 142 static void indicesOfNearestSnapOffsets(LayoutType offset, const Vector<LayoutType>& snapOffsets, unsigned& lowerIndex, unsigned& upperIndex) 143 { 144 lowerIndex = 0; 145 upperIndex = snapOffsets.size() - 1; 146 while (lowerIndex < upperIndex - 1) { 147 int middleIndex = (lowerIndex + upperIndex) / 2; 148 auto middleOffset = snapOffsets[middleIndex]; 149 if (offset == middleOffset) { 150 upperIndex = middleIndex; 151 lowerIndex = middleIndex; 152 break; 153 } 154 155 if (offset > middleOffset) 156 lowerIndex = middleIndex; 157 else 158 upperIndex = middleIndex; 159 } 160 } 161 162 static void adjustAxisSnapOffsetsForScrollExtent(Vector<LayoutUnit>& snapOffsets, float maxScrollExtent) 163 { 164 if (snapOffsets.isEmpty()) 165 return; 166 167 std::sort(snapOffsets.begin(), snapOffsets.end()); 168 if (snapOffsets.last() != maxScrollExtent) 169 snapOffsets.append(maxScrollExtent); 170 if (snapOffsets.first()) 171 snapOffsets.insert(0, 0); 172 } 173 174 static void computeAxisProximitySnapOffsetRanges(const Vector<LayoutUnit>& snapOffsets, Vector<ScrollOffsetRange<LayoutUnit>>& offsetRanges, LayoutUnit scrollPortAxisLength) 175 { 176 // This is an arbitrary choice for what it means to be "in proximity" of a snap offset. We should play around with 177 // this and see what feels best. 178 static const float ratioOfScrollPortAxisLengthToBeConsideredForProximity = 0.3; 179 if (snapOffsets.size() < 2) 180 return; 181 182 // The extra rule accounting for scroll offset ranges in between the scroll destination and a potential snap offset 183 // handles the corner case where the user scrolls with momentum very lightly away from a snap offset, such that the 184 // predicted scroll destination is still within proximity of the snap offset. In this case, the regular (mandatory 185 // scroll snapping) behavior would be to snap to the next offset in the direction of momentum scrolling, but 186 // instead, it is more intuitive to either return to the original snap position (which we arbitrarily choose here) 187 // or scroll just outside of the snap offset range. This is another minor behavior tweak that we should play around 188 // with to see what feels best. 189 LayoutUnit proximityDistance = ratioOfScrollPortAxisLengthToBeConsideredForProximity * scrollPortAxisLength; 190 for (size_t index = 1; index < snapOffsets.size(); ++index) { 191 auto startOffset = snapOffsets[index - 1] + proximityDistance; 192 auto endOffset = snapOffsets[index] - proximityDistance; 193 if (startOffset < endOffset) 194 offsetRanges.append({ startOffset, endOffset }); 195 } 196 } 93 197 94 198 void updateSnapOffsetsForScrollableArea(ScrollableArea& scrollableArea, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle) … … 102 206 } 103 207 104 auto verticalSnapOffsets = std::make_unique<Vector<LayoutUnit>>(); 105 auto horizontalSnapOffsets = std::make_unique<Vector<LayoutUnit>>(); 208 Vector<LayoutUnit> verticalSnapOffsets; 209 Vector<LayoutUnit> horizontalSnapOffsets; 210 Vector<ScrollOffsetRange<LayoutUnit>> verticalSnapOffsetRanges; 211 Vector<ScrollOffsetRange<LayoutUnit>> horizontalSnapOffsetRanges; 106 212 HashSet<float> seenVerticalSnapOffsets; 107 213 HashSet<float> seenHorizontalSnapOffsets; … … 134 240 if (!seenHorizontalSnapOffsets.contains(absoluteScrollOffset)) { 135 241 seenHorizontalSnapOffsets.add(absoluteScrollOffset); 136 horizontalSnapOffsets ->append(absoluteScrollOffset);242 horizontalSnapOffsets.append(absoluteScrollOffset); 137 243 } 138 244 } … … 141 247 if (!seenVerticalSnapOffsets.contains(absoluteScrollOffset)) { 142 248 seenVerticalSnapOffsets.add(absoluteScrollOffset); 143 verticalSnapOffsets ->append(absoluteScrollOffset);249 verticalSnapOffsets.append(absoluteScrollOffset); 144 250 } 145 251 } 146 252 } 147 253 148 std::sort(horizontalSnapOffsets->begin(), horizontalSnapOffsets->end()); 149 if (horizontalSnapOffsets->size()) { 150 if (horizontalSnapOffsets->last() != maxScrollLeft) 151 horizontalSnapOffsets->append(maxScrollLeft); 152 if (horizontalSnapOffsets->first()) 153 horizontalSnapOffsets->insert(0, 0); 154 #if !LOG_DISABLED 155 LOG(Scrolling, " => Computed horizontal scroll snap offsets: %s", snapOffsetsToString(*horizontalSnapOffsets).utf8().data()); 156 #endif 157 scrollableArea.setHorizontalSnapOffsets(WTFMove(horizontalSnapOffsets)); 254 if (!horizontalSnapOffsets.isEmpty()) { 255 adjustAxisSnapOffsetsForScrollExtent(horizontalSnapOffsets, maxScrollLeft); 256 #if !LOG_DISABLED 257 LOG(Scrolling, " => Computed horizontal scroll snap offsets: %s", snapOffsetsToString(horizontalSnapOffsets).utf8().data()); 258 LOG(Scrolling, " => Computed horizontal scroll snap offset ranges: %s", snapOffsetRangesToString(horizontalSnapOffsetRanges).utf8().data()); 259 #endif 260 if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity) 261 computeAxisProximitySnapOffsetRanges(horizontalSnapOffsets, horizontalSnapOffsetRanges, scrollSnapPort.width()); 262 263 scrollableArea.setHorizontalSnapOffsets(horizontalSnapOffsets); 264 scrollableArea.setHorizontalSnapOffsetRanges(horizontalSnapOffsetRanges); 158 265 } else 159 266 scrollableArea.clearHorizontalSnapOffsets(); 160 267 161 std::sort(verticalSnapOffsets->begin(), verticalSnapOffsets->end()); 162 if (verticalSnapOffsets->size()) { 163 if (verticalSnapOffsets->last() != maxScrollTop) 164 verticalSnapOffsets->append(maxScrollTop); 165 if (verticalSnapOffsets->first()) 166 verticalSnapOffsets->insert(0, 0); 167 #if !LOG_DISABLED 168 LOG(Scrolling, " => Computed vertical scroll snap offsets: %s", snapOffsetsToString(*verticalSnapOffsets).utf8().data()); 169 #endif 170 scrollableArea.setVerticalSnapOffsets(WTFMove(verticalSnapOffsets)); 268 if (!verticalSnapOffsets.isEmpty()) { 269 adjustAxisSnapOffsetsForScrollExtent(verticalSnapOffsets, maxScrollTop); 270 #if !LOG_DISABLED 271 LOG(Scrolling, " => Computed vertical scroll snap offsets: %s", snapOffsetsToString(verticalSnapOffsets).utf8().data()); 272 LOG(Scrolling, " => Computed vertical scroll snap offset ranges: %s", snapOffsetRangesToString(verticalSnapOffsetRanges).utf8().data()); 273 #endif 274 if (scrollSnapType.strictness == ScrollSnapStrictness::Proximity) 275 computeAxisProximitySnapOffsetRanges(verticalSnapOffsets, verticalSnapOffsetRanges, scrollSnapPort.height()); 276 277 scrollableArea.setVerticalSnapOffsets(verticalSnapOffsets); 278 scrollableArea.setVerticalSnapOffsetRanges(verticalSnapOffsetRanges); 171 279 } else 172 280 scrollableArea.clearVerticalSnapOffsets(); 173 281 } 174 282 283 template <typename LayoutType> 284 LayoutType closestSnapOffset(const Vector<LayoutType>& snapOffsets, const Vector<ScrollOffsetRange<LayoutType>>& snapOffsetRanges, LayoutType scrollDestination, float velocity, unsigned& activeSnapIndex) 285 { 286 ASSERT(snapOffsets.size()); 287 activeSnapIndex = 0; 288 289 unsigned lowerSnapOffsetRangeIndex; 290 unsigned upperSnapOffsetRangeIndex; 291 indicesOfNearestSnapOffsetRanges<LayoutType>(scrollDestination, snapOffsetRanges, lowerSnapOffsetRangeIndex, upperSnapOffsetRangeIndex); 292 if (lowerSnapOffsetRangeIndex == upperSnapOffsetRangeIndex && upperSnapOffsetRangeIndex != invalidSnapOffsetIndex) { 293 activeSnapIndex = invalidSnapOffsetIndex; 294 return scrollDestination; 295 } 296 297 if (scrollDestination <= snapOffsets.first()) 298 return snapOffsets.first(); 299 300 activeSnapIndex = snapOffsets.size() - 1; 301 if (scrollDestination >= snapOffsets.last()) 302 return snapOffsets.last(); 303 304 unsigned lowerIndex; 305 unsigned upperIndex; 306 indicesOfNearestSnapOffsets<LayoutType>(scrollDestination, snapOffsets, lowerIndex, upperIndex); 307 LayoutType lowerSnapPosition = snapOffsets[lowerIndex]; 308 LayoutType upperSnapPosition = snapOffsets[upperIndex]; 309 if (!std::abs(velocity)) { 310 bool isCloserToLowerSnapPosition = scrollDestination - lowerSnapPosition <= upperSnapPosition - scrollDestination; 311 activeSnapIndex = isCloserToLowerSnapPosition ? lowerIndex : upperIndex; 312 return isCloserToLowerSnapPosition ? lowerSnapPosition : upperSnapPosition; 313 } 314 315 // Non-zero velocity indicates a flick gesture. Even if another snap point is closer, we should choose the one in the direction of the flick gesture 316 // as long as a scroll snap offset range does not lie between the scroll destination and the targeted snap offset. 317 if (velocity < 0) { 318 if (lowerSnapOffsetRangeIndex != invalidSnapOffsetIndex && lowerSnapPosition < snapOffsetRanges[lowerSnapOffsetRangeIndex].end) { 319 activeSnapIndex = upperIndex; 320 return upperSnapPosition; 321 } 322 activeSnapIndex = lowerIndex; 323 return lowerSnapPosition; 324 } 325 326 if (upperSnapOffsetRangeIndex != invalidSnapOffsetIndex && snapOffsetRanges[upperSnapOffsetRangeIndex].start < upperSnapPosition) { 327 activeSnapIndex = lowerIndex; 328 return lowerSnapPosition; 329 } 330 activeSnapIndex = upperIndex; 331 return upperSnapPosition; 332 } 333 334 LayoutUnit closestSnapOffset(const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges, LayoutUnit scrollDestination, float velocity, unsigned& activeSnapIndex) 335 { 336 return closestSnapOffset<LayoutUnit>(snapOffsets, snapOffsetRanges, scrollDestination, velocity, activeSnapIndex); 337 } 338 339 float closestSnapOffset(const Vector<float>& snapOffsets, const Vector<ScrollOffsetRange<float>>& snapOffsetRanges, float scrollDestination, float velocity, unsigned& activeSnapIndex) 340 { 341 return closestSnapOffset<float>(snapOffsets, snapOffsetRanges, scrollDestination, velocity, activeSnapIndex); 342 } 343 175 344 } // namespace WebCore 176 345 -
trunk/Source/WebCore/page/scrolling/AxisScrollSnapOffsets.h
r208179 r210560 28 28 #if ENABLE(CSS_SCROLL_SNAP) 29 29 30 #include "LayoutUnit.h" 31 #include "ScrollSnapOffsetsInfo.h" 30 32 #include "ScrollTypes.h" 31 33 #include <wtf/Vector.h> … … 40 42 void updateSnapOffsetsForScrollableArea(ScrollableArea&, HTMLElement& scrollingElement, const RenderBox& scrollingElementBox, const RenderStyle& scrollingElementStyle); 41 43 42 // closestSnapOffset is a templated function that takes in a Vector representing snap offsets as LayoutTypes (e.g. LayoutUnit or float) and 43 // as well as a VelocityType indicating the velocity (e.g. float, CGFloat, etc.) This function is templated because the UI process will now 44 // use pixel snapped floats to represent snap offsets rather than LayoutUnits. 45 template <typename LayoutType, typename VelocityType> 46 LayoutType closestSnapOffset(const Vector<LayoutType>& snapOffsets, LayoutType scrollDestination, VelocityType velocity, unsigned& activeSnapIndex) 47 { 48 ASSERT(snapOffsets.size()); 49 activeSnapIndex = 0; 50 if (scrollDestination <= snapOffsets.first()) 51 return snapOffsets.first(); 52 53 activeSnapIndex = snapOffsets.size() - 1; 54 if (scrollDestination >= snapOffsets.last()) 55 return snapOffsets.last(); 56 57 size_t lowerIndex = 0; 58 size_t upperIndex = snapOffsets.size() - 1; 59 while (lowerIndex < upperIndex - 1) { 60 size_t middleIndex = (lowerIndex + upperIndex) / 2; 61 if (scrollDestination < snapOffsets[middleIndex]) 62 upperIndex = middleIndex; 63 else if (scrollDestination > snapOffsets[middleIndex]) 64 lowerIndex = middleIndex; 65 else { 66 upperIndex = middleIndex; 67 lowerIndex = middleIndex; 68 break; 69 } 70 } 71 LayoutType lowerSnapPosition = snapOffsets[lowerIndex]; 72 LayoutType upperSnapPosition = snapOffsets[upperIndex]; 73 // Nonzero velocity indicates a flick gesture. Even if another snap point is closer, snap to the one in the direction of the flick gesture. 74 if (velocity) { 75 activeSnapIndex = (velocity < 0) ? lowerIndex : upperIndex; 76 return velocity < 0 ? lowerSnapPosition : upperSnapPosition; 77 } 78 79 bool isCloserToLowerSnapPosition = scrollDestination - lowerSnapPosition <= upperSnapPosition - scrollDestination; 80 activeSnapIndex = isCloserToLowerSnapPosition ? lowerIndex : upperIndex; 81 return isCloserToLowerSnapPosition ? lowerSnapPosition : upperSnapPosition; 82 } 44 const unsigned invalidSnapOffsetIndex = UINT_MAX; 45 WEBCORE_EXPORT LayoutUnit closestSnapOffset(const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges, LayoutUnit scrollDestination, float velocity, unsigned& activeSnapIndex); 46 WEBCORE_EXPORT float closestSnapOffset(const Vector<float>& snapOffsets, const Vector<ScrollOffsetRange<float>>& snapOffsetRanges, float scrollDestination, float velocity, unsigned& activeSnapIndex); 83 47 84 48 } // namespace WebCore -
trunk/Source/WebCore/page/scrolling/ScrollSnapOffsetsInfo.h
r210559 r210560 26 26 #pragma once 27 27 28 #include "ScrollingMomentumCalculator.h" 29 #include <wtf/RetainPtr.h> 30 31 #if HAVE(NSSCROLLING_FILTERS) 32 33 @class _NSScrollingMomentumCalculator; 28 #include <wtf/Vector.h> 34 29 35 30 namespace WebCore { 36 31 37 class ScrollingMomentumCalculatorMac final : public ScrollingMomentumCalculator { 38 public: 39 ScrollingMomentumCalculatorMac(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity); 40 41 private: 42 FloatPoint scrollOffsetAfterElapsedTime(Seconds) final; 43 Seconds animationDuration() final; 44 _NSScrollingMomentumCalculator *ensurePlatformMomentumCalculator(); 45 46 RetainPtr<_NSScrollingMomentumCalculator> m_platformMomentumCalculator; 47 bool m_requiresMomentumScrolling { true }; 32 template <typename T> 33 struct ScrollOffsetRange { 34 T start; 35 T end; 48 36 }; 49 37 50 } // namespace WebCore 38 template <typename T> 39 struct ScrollSnapOffsetsInfo { 40 Vector<T> horizontalSnapOffsets; 41 Vector<T> verticalSnapOffsets; 51 42 52 #endif // HAVE(NSSCROLLING_FILTERS) 43 // Snap offset ranges represent non-empty ranges of scroll offsets in which scrolling may rest after scroll snapping. 44 // These are used in two cases: (1) for proximity scroll snapping, where portions of areas between adjacent snap offsets 45 // may emit snap offset ranges, and (2) in the case where the snap area is larger than the snap port, in which case areas 46 // where the snap port fits within the snap area are considered to be valid snap positions. 47 Vector<ScrollOffsetRange<T>> horizontalSnapOffsetRanges; 48 Vector<ScrollOffsetRange<T>> verticalSnapOffsetRanges; 49 }; 50 51 }; // namespace WebCore -
trunk/Source/WebCore/page/scrolling/ScrollingCoordinator.h
r209087 r210560 30 30 #include "LayoutRect.h" 31 31 #include "PlatformWheelEvent.h" 32 #include "ScrollSnapOffsetsInfo.h" 32 33 #include "ScrollTypes.h" 33 34 #include <wtf/Forward.h> … … 171 172 Vector<LayoutUnit> horizontalSnapOffsets; 172 173 Vector<LayoutUnit> verticalSnapOffsets; 174 Vector<ScrollOffsetRange<LayoutUnit>> horizontalSnapOffsetRanges; 175 Vector<ScrollOffsetRange<LayoutUnit>> verticalSnapOffsetRanges; 173 176 unsigned currentHorizontalSnapPointIndex; 174 177 unsigned currentVerticalSnapPointIndex; -
trunk/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.cpp
r209087 r210560 33 33 34 34 static const Seconds scrollSnapAnimationDuration = 1_s; 35 36 ScrollingMomentumCalculator::ScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 35 static inline float projectedInertialScrollDistance(float initialWheelDelta) 36 { 37 // On macOS 10.10 and earlier, we don't have a platform scrolling momentum calculator, so we instead approximate the scroll destination 38 // by multiplying the initial wheel delta by a constant factor. By running a few experiments (i.e. logging scroll destination and initial 39 // wheel delta for many scroll gestures) we determined that this is a reasonable way to approximate where scrolling will take us without 40 // using _NSScrollingMomentumCalculator. 41 const static double inertialScrollPredictionFactor = 16.7; 42 return inertialScrollPredictionFactor * initialWheelDelta; 43 } 44 45 ScrollingMomentumCalculator::ScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 37 46 : m_initialDelta(initialDelta) 38 47 , m_initialVelocity(initialVelocity) 39 48 , m_initialScrollOffset(initialOffset.x(), initialOffset.y()) 40 , m_targetScrollOffset(targetOffset.x(), targetOffset.y())41 49 , m_viewportSize(viewportSize) 42 50 , m_contentSize(contentSize) … … 44 52 } 45 53 54 void ScrollingMomentumCalculator::setRetargetedScrollOffset(const FloatSize& target) 55 { 56 if (m_retargetedScrollOffset && m_retargetedScrollOffset == target) 57 return; 58 59 m_retargetedScrollOffset = target; 60 retargetedScrollOffsetDidChange(); 61 } 62 63 FloatSize ScrollingMomentumCalculator::predictedDestinationOffset() 64 { 65 float initialOffsetX = clampTo<float>(m_initialScrollOffset.width() + projectedInertialScrollDistance(m_initialDelta.width()), 0, m_contentSize.width() - m_viewportSize.width()); 66 float initialOffsetY = clampTo<float>(m_initialScrollOffset.height() + projectedInertialScrollDistance(m_initialDelta.height()), 0, m_contentSize.height() - m_viewportSize.height()); 67 return { initialOffsetX, initialOffsetY }; 68 } 69 46 70 #if !HAVE(NSSCROLLING_FILTERS) 47 71 48 std::unique_ptr<ScrollingMomentumCalculator> ScrollingMomentumCalculator::create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 49 { 50 return std::make_unique<BasicScrollingMomentumCalculator>(viewportSize, contentSize, initialOffset, targetOffset, initialDelta, initialVelocity); 72 std::unique_ptr<ScrollingMomentumCalculator> ScrollingMomentumCalculator::create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 73 { 74 return std::make_unique<BasicScrollingMomentumCalculator>(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity); 75 } 76 77 void ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled(bool) 78 { 51 79 } 52 80 53 81 #endif 54 82 55 BasicScrollingMomentumCalculator::BasicScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const Float Point& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity)56 : ScrollingMomentumCalculator(viewportSize, contentSize, initialOffset, targetOffset,initialDelta, initialVelocity)57 { 58 } 59 60 FloatSize BasicScrollingMomentumCalculator::linearlyInterpolatedOffsetAtProgress(float progress) const61 { 62 return m_initialScrollOffset + progress * ( m_targetScrollOffset- m_initialScrollOffset);83 BasicScrollingMomentumCalculator::BasicScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 84 : ScrollingMomentumCalculator(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity) 85 { 86 } 87 88 FloatSize BasicScrollingMomentumCalculator::linearlyInterpolatedOffsetAtProgress(float progress) 89 { 90 return m_initialScrollOffset + progress * (retargetedScrollOffset() - m_initialScrollOffset); 63 91 } 64 92 … … 121 149 } 122 150 123 FloatSize startToEndVector = m_targetScrollOffset- m_initialScrollOffset;151 FloatSize startToEndVector = retargetedScrollOffset() - m_initialScrollOffset; 124 152 float startToEndDistance = startToEndVector.diagonalLength(); 125 153 if (!startToEndDistance) { … … 141 169 m_snapAnimationCurveCoefficients[1] = 3 * (controlVector1 - m_initialScrollOffset); 142 170 m_snapAnimationCurveCoefficients[2] = 3 * (m_initialScrollOffset - 2 * controlVector1 + controlVector2); 143 m_snapAnimationCurveCoefficients[3] = 3 * (controlVector1 - controlVector2) - m_initialScrollOffset + m_targetScrollOffset;171 m_snapAnimationCurveCoefficients[3] = 3 * (controlVector1 - controlVector2) - m_initialScrollOffset + retargetedScrollOffset(); 144 172 m_forceLinearAnimationCurve = false; 145 173 } … … 180 208 static const float maxScrollSnapInitialProgress = 0.5; 181 209 182 FloatSize alignmentVector = m_initialDelta * ( m_targetScrollOffset- m_initialScrollOffset);210 FloatSize alignmentVector = m_initialDelta * (retargetedScrollOffset() - m_initialScrollOffset); 183 211 float initialProgress; 184 212 if (alignmentVector.width() + alignmentVector.height() > 0) 185 initialProgress = clampTo(m_initialDelta.diagonalLength() / ( m_targetScrollOffset- m_initialScrollOffset).diagonalLength(), minScrollSnapInitialProgress, maxScrollSnapInitialProgress);213 initialProgress = clampTo(m_initialDelta.diagonalLength() / (retargetedScrollOffset() - m_initialScrollOffset).diagonalLength(), minScrollSnapInitialProgress, maxScrollSnapInitialProgress); 186 214 else 187 215 initialProgress = minScrollSnapInitialProgress; -
trunk/Source/WebCore/page/scrolling/ScrollingMomentumCalculator.h
r209087 r210560 31 31 #include "PlatformWheelEvent.h" 32 32 #include "ScrollTypes.h" 33 #include <wtf/Optional.h> 33 34 #include <wtf/Seconds.h> 34 35 … … 40 41 class ScrollingMomentumCalculator { 41 42 public: 42 ScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity); 43 static std::unique_ptr<ScrollingMomentumCalculator> create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity); 43 ScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity); 44 static std::unique_ptr<ScrollingMomentumCalculator> create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity); 45 WEBCORE_EXPORT static void setPlatformMomentumScrollingPredictionEnabled(bool); 44 46 virtual ~ScrollingMomentumCalculator() { } 45 47 46 48 virtual FloatPoint scrollOffsetAfterElapsedTime(Seconds) = 0; 47 49 virtual Seconds animationDuration() = 0; 50 virtual FloatSize predictedDestinationOffset(); 51 void setRetargetedScrollOffset(const FloatSize&); 48 52 49 53 protected: 54 const FloatSize& retargetedScrollOffset() const { return m_retargetedScrollOffset.value(); } 55 virtual void retargetedScrollOffsetDidChange() { } 56 50 57 FloatSize m_initialDelta; 51 58 FloatSize m_initialVelocity; 52 59 FloatSize m_initialScrollOffset; 53 FloatSize m_targetScrollOffset;54 60 FloatSize m_viewportSize; 55 61 FloatSize m_contentSize; 62 63 private: 64 std::optional<FloatSize> m_retargetedScrollOffset; 56 65 }; 57 66 58 67 class BasicScrollingMomentumCalculator final : public ScrollingMomentumCalculator { 59 68 public: 60 BasicScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const Float Point& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity);69 BasicScrollingMomentumCalculator(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity); 61 70 62 71 private: … … 66 75 void initializeSnapProgressCurve(); 67 76 float animationProgressAfterElapsedTime(Seconds) const; 68 FloatSize linearlyInterpolatedOffsetAtProgress(float progress) const;77 FloatSize linearlyInterpolatedOffsetAtProgress(float progress); 69 78 FloatSize cubicallyInterpolatedOffsetAtProgress(float progress) const; 70 79 … … 74 83 bool m_forceLinearAnimationCurve { false }; 75 84 bool m_momentumCalculatorRequiresInitialization { true }; 85 std::optional<FloatSize> m_predictedDestinationOffset; 76 86 }; 77 87 -
trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.cpp
r200636 r210560 48 48 , m_scrollOrigin(stateNode.scrollOrigin()) 49 49 #if ENABLE(CSS_SCROLL_SNAP) 50 , m_horizontalSnapOffsets(stateNode.horizontalSnapOffsets()) 51 , m_verticalSnapOffsets(stateNode.verticalSnapOffsets()) 50 , m_snapOffsetsInfo(stateNode.m_snapOffsetsInfo) 52 51 #endif 53 52 , m_scrollableAreaParameters(stateNode.scrollableAreaParameters()) … … 109 108 void ScrollingStateScrollingNode::setHorizontalSnapOffsets(const Vector<float>& snapOffsets) 110 109 { 111 if (m_ horizontalSnapOffsets == snapOffsets)112 return; 113 114 m_ horizontalSnapOffsets = snapOffsets;110 if (m_snapOffsetsInfo.horizontalSnapOffsets == snapOffsets) 111 return; 112 113 m_snapOffsetsInfo.horizontalSnapOffsets = snapOffsets; 115 114 setPropertyChanged(HorizontalSnapOffsets); 116 115 } … … 118 117 void ScrollingStateScrollingNode::setVerticalSnapOffsets(const Vector<float>& snapOffsets) 119 118 { 120 if (m_ verticalSnapOffsets == snapOffsets)121 return; 122 123 m_ verticalSnapOffsets = snapOffsets;119 if (m_snapOffsetsInfo.verticalSnapOffsets == snapOffsets) 120 return; 121 122 m_snapOffsetsInfo.verticalSnapOffsets = snapOffsets; 124 123 setPropertyChanged(VerticalSnapOffsets); 124 } 125 126 void ScrollingStateScrollingNode::setHorizontalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>& scrollOffsetRanges) 127 { 128 if (m_snapOffsetsInfo.horizontalSnapOffsetRanges == scrollOffsetRanges) 129 return; 130 131 m_snapOffsetsInfo.horizontalSnapOffsetRanges = scrollOffsetRanges; 132 setPropertyChanged(HorizontalSnapOffsetRanges); 133 } 134 135 void ScrollingStateScrollingNode::setVerticalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>& scrollOffsetRanges) 136 { 137 if (m_snapOffsetsInfo.verticalSnapOffsetRanges == scrollOffsetRanges) 138 return; 139 140 m_snapOffsetsInfo.verticalSnapOffsetRanges = scrollOffsetRanges; 141 setPropertyChanged(VerticalSnapOffsetRanges); 125 142 } 126 143 -
trunk/Source/WebCore/page/scrolling/ScrollingStateScrollingNode.h
r208179 r210560 28 28 #if ENABLE(ASYNC_SCROLLING) || USE(COORDINATED_GRAPHICS) 29 29 30 #include "ScrollSnapOffsetsInfo.h" 30 31 #include "ScrollTypes.h" 31 32 #include "ScrollingCoordinator.h" … … 50 51 HorizontalSnapOffsets, 51 52 VerticalSnapOffsets, 53 HorizontalSnapOffsetRanges, 54 VerticalSnapOffsetRanges, 52 55 CurrentHorizontalSnapOffsetIndex, 53 56 CurrentVerticalSnapOffsetIndex, … … 72 75 73 76 #if ENABLE(CSS_SCROLL_SNAP) 74 const Vector<float>& horizontalSnapOffsets() const { return m_ horizontalSnapOffsets; }77 const Vector<float>& horizontalSnapOffsets() const { return m_snapOffsetsInfo.horizontalSnapOffsets; } 75 78 WEBCORE_EXPORT void setHorizontalSnapOffsets(const Vector<float>&); 76 79 77 const Vector<float>& verticalSnapOffsets() const { return m_ verticalSnapOffsets; }80 const Vector<float>& verticalSnapOffsets() const { return m_snapOffsetsInfo.verticalSnapOffsets; } 78 81 WEBCORE_EXPORT void setVerticalSnapOffsets(const Vector<float>&); 82 83 const Vector<ScrollOffsetRange<float>>& horizontalSnapOffsetRanges() const { return m_snapOffsetsInfo.horizontalSnapOffsetRanges; } 84 WEBCORE_EXPORT void setHorizontalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>&); 85 86 const Vector<ScrollOffsetRange<float>>& verticalSnapOffsetRanges() const { return m_snapOffsetsInfo.verticalSnapOffsetRanges; } 87 WEBCORE_EXPORT void setVerticalSnapOffsetRanges(const Vector<ScrollOffsetRange<float>>&); 79 88 80 89 unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; } … … 109 118 IntPoint m_scrollOrigin; 110 119 #if ENABLE(CSS_SCROLL_SNAP) 111 Vector<float> m_horizontalSnapOffsets; 112 Vector<float> m_verticalSnapOffsets; 120 ScrollSnapOffsetsInfo<float> m_snapOffsetsInfo; 113 121 unsigned m_currentHorizontalSnapPointIndex { 0 }; 114 122 unsigned m_currentVerticalSnapPointIndex { 0 }; -
trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.cpp
r208985 r210560 71 71 #if ENABLE(CSS_SCROLL_SNAP) 72 72 if (state.hasChangedProperty(ScrollingStateScrollingNode::HorizontalSnapOffsets)) 73 m_ horizontalSnapOffsets = state.horizontalSnapOffsets();73 m_snapOffsetsInfo.horizontalSnapOffsets = state.horizontalSnapOffsets(); 74 74 75 75 if (state.hasChangedProperty(ScrollingStateScrollingNode::VerticalSnapOffsets)) 76 m_verticalSnapOffsets = state.verticalSnapOffsets(); 76 m_snapOffsetsInfo.verticalSnapOffsets = state.verticalSnapOffsets(); 77 78 if (state.hasChangedProperty(ScrollingStateScrollingNode::HorizontalSnapOffsetRanges)) 79 m_snapOffsetsInfo.horizontalSnapOffsetRanges = state.horizontalSnapOffsetRanges(); 80 81 if (state.hasChangedProperty(ScrollingStateScrollingNode::VerticalSnapOffsetRanges)) 82 m_snapOffsetsInfo.verticalSnapOffsetRanges = state.verticalSnapOffsetRanges(); 77 83 78 84 if (state.hasChangedProperty(ScrollingStateScrollingNode::CurrentHorizontalSnapOffsetIndex)) … … 140 146 141 147 #if ENABLE(CSS_SCROLL_SNAP) 142 if (m_ horizontalSnapOffsets.size())143 ts.dumpProperty("horizontal snap offsets", m_ horizontalSnapOffsets);148 if (m_snapOffsetsInfo.horizontalSnapOffsets.size()) 149 ts.dumpProperty("horizontal snap offsets", m_snapOffsetsInfo.horizontalSnapOffsets); 144 150 145 if (m_ verticalSnapOffsets.size())146 ts.dumpProperty("horizontal snap offsets", m_ verticalSnapOffsets);151 if (m_snapOffsetsInfo.verticalSnapOffsets.size()) 152 ts.dumpProperty("horizontal snap offsets", m_snapOffsetsInfo.verticalSnapOffsets); 147 153 148 154 if (m_currentHorizontalSnapPointIndex) 149 ts.dumpProperty("current horizontal snap point index", m_ verticalSnapOffsets);155 ts.dumpProperty("current horizontal snap point index", m_currentHorizontalSnapPointIndex); 150 156 151 157 if (m_currentVerticalSnapPointIndex) -
trunk/Source/WebCore/page/scrolling/ScrollingTreeScrollingNode.h
r208666 r210560 29 29 30 30 #include "IntRect.h" 31 #include "ScrollSnapOffsetsInfo.h" 31 32 #include "ScrollTypes.h" 32 33 #include "ScrollingCoordinator.h" … … 57 58 58 59 #if ENABLE(CSS_SCROLL_SNAP) 59 const Vector<float>& horizontalSnapOffsets() const { return m_horizontalSnapOffsets; } 60 const Vector<float>& verticalSnapOffsets() const { return m_verticalSnapOffsets; } 60 const Vector<float>& horizontalSnapOffsets() const { return m_snapOffsetsInfo.horizontalSnapOffsets; } 61 const Vector<float>& verticalSnapOffsets() const { return m_snapOffsetsInfo.verticalSnapOffsets; } 62 const Vector<ScrollOffsetRange<float>>& horizontalSnapOffsetRanges() const { return m_snapOffsetsInfo.horizontalSnapOffsetRanges; } 63 const Vector<ScrollOffsetRange<float>>& verticalSnapOffsetRanges() const { return m_snapOffsetsInfo.verticalSnapOffsetRanges; } 61 64 unsigned currentHorizontalSnapPointIndex() const { return m_currentHorizontalSnapPointIndex; } 62 65 unsigned currentVerticalSnapPointIndex() const { return m_currentVerticalSnapPointIndex; } … … 103 106 IntPoint m_scrollOrigin; 104 107 #if ENABLE(CSS_SCROLL_SNAP) 105 Vector<float> m_horizontalSnapOffsets; 106 Vector<float> m_verticalSnapOffsets; 108 ScrollSnapOffsetsInfo<float> m_snapOffsetsInfo; 107 109 unsigned m_currentHorizontalSnapPointIndex { 0 }; 108 110 unsigned m_currentVerticalSnapPointIndex { 0 }; -
trunk/Source/WebCore/page/scrolling/mac/ScrollingMomentumCalculatorMac.h
r209477 r210560 37 37 class ScrollingMomentumCalculatorMac final : public ScrollingMomentumCalculator { 38 38 public: 39 ScrollingMomentumCalculatorMac(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const Float Point& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity);39 ScrollingMomentumCalculatorMac(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity); 40 40 41 41 private: 42 42 FloatPoint scrollOffsetAfterElapsedTime(Seconds) final; 43 43 Seconds animationDuration() final; 44 FloatSize predictedDestinationOffset() final; 45 void retargetedScrollOffsetDidChange() final; 44 46 _NSScrollingMomentumCalculator *ensurePlatformMomentumCalculator(); 47 bool requiresMomentumScrolling(); 45 48 46 49 RetainPtr<_NSScrollingMomentumCalculator> m_platformMomentumCalculator; 47 bool m_requiresMomentumScrolling { true }; 50 std::optional<bool> m_requiresMomentumScrolling; 51 FloatPoint m_initialDestinationOrigin; 48 52 }; 49 53 -
trunk/Source/WebCore/page/scrolling/mac/ScrollingMomentumCalculatorMac.mm
r209477 r210560 33 33 namespace WebCore { 34 34 35 std::unique_ptr<ScrollingMomentumCalculator> ScrollingMomentumCalculator::create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 35 static bool gEnablePlatformMomentumScrollingPrediction = true; 36 37 std::unique_ptr<ScrollingMomentumCalculator> ScrollingMomentumCalculator::create(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 36 38 { 37 return std::make_unique<ScrollingMomentumCalculatorMac>(viewportSize, contentSize, initialOffset, targetOffset,initialDelta, initialVelocity);39 return std::make_unique<ScrollingMomentumCalculatorMac>(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity); 38 40 } 39 41 40 ScrollingMomentumCalculatorMac::ScrollingMomentumCalculatorMac(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 41 : ScrollingMomentumCalculator(viewportSize, contentSize, initialOffset, targetOffset, initialDelta, initialVelocity) 42 , m_requiresMomentumScrolling(initialOffset != targetOffset || initialVelocity.area()) 42 void ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled(bool enabled) 43 { 44 gEnablePlatformMomentumScrollingPrediction = enabled; 45 } 46 47 ScrollingMomentumCalculatorMac::ScrollingMomentumCalculatorMac(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatSize& initialDelta, const FloatSize& initialVelocity) 48 : ScrollingMomentumCalculator(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity) 43 49 { 44 50 } … … 46 52 FloatPoint ScrollingMomentumCalculatorMac::scrollOffsetAfterElapsedTime(Seconds elapsedTime) 47 53 { 48 if (! m_requiresMomentumScrolling)49 return { m_targetScrollOffset.width(), m_targetScrollOffset.height() };54 if (!requiresMomentumScrolling()) 55 return { retargetedScrollOffset().width(), retargetedScrollOffset().height() }; 50 56 51 57 return [ensurePlatformMomentumCalculator() positionAfterDuration:elapsedTime.value()]; 52 58 } 53 59 60 FloatSize ScrollingMomentumCalculatorMac::predictedDestinationOffset() 61 { 62 if (!gEnablePlatformMomentumScrollingPrediction) 63 return ScrollingMomentumCalculator::predictedDestinationOffset(); 64 65 ensurePlatformMomentumCalculator(); 66 return { m_initialDestinationOrigin.x(), m_initialDestinationOrigin.y() }; 67 } 68 69 void ScrollingMomentumCalculatorMac::retargetedScrollOffsetDidChange() 70 { 71 _NSScrollingMomentumCalculator *calculator = ensurePlatformMomentumCalculator(); 72 calculator.destinationOrigin = NSMakePoint(retargetedScrollOffset().width(), retargetedScrollOffset().height()); 73 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 74 [calculator calculateToReachDestination]; 75 #endif 76 } 77 54 78 Seconds ScrollingMomentumCalculatorMac::animationDuration() 55 79 { 56 if (! m_requiresMomentumScrolling)80 if (!requiresMomentumScrolling()) 57 81 return 0_s; 58 82 59 83 return Seconds([ensurePlatformMomentumCalculator() durationUntilStop]); 84 } 85 86 bool ScrollingMomentumCalculatorMac::requiresMomentumScrolling() 87 { 88 if (m_requiresMomentumScrolling == std::nullopt) 89 m_requiresMomentumScrolling = m_initialScrollOffset != retargetedScrollOffset() || m_initialVelocity.area(); 90 return m_requiresMomentumScrolling.value(); 60 91 } 61 92 … … 69 100 NSPoint velocity = NSMakePoint(m_initialVelocity.width(), m_initialVelocity.height()); 70 101 m_platformMomentumCalculator = adoptNS([[_NSScrollingMomentumCalculator alloc] initWithInitialOrigin:origin velocity:velocity documentFrame:contentFrame constrainedClippingOrigin:NSZeroPoint clippingSize:m_viewportSize tolerance:NSMakeSize(1, 1)]); 71 [m_platformMomentumCalculator setDestinationOrigin:NSMakePoint(m_targetScrollOffset.width(), m_targetScrollOffset.height())]; 72 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101200 73 [m_platformMomentumCalculator calculateToReachDestination]; 74 #endif 102 m_initialDestinationOrigin = [m_platformMomentumCalculator destinationOrigin]; 75 103 return m_platformMomentumCalculator.get(); 76 104 } -
trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm
r210059 r210560 91 91 return snapOffsets; 92 92 } 93 94 static inline Vector<ScrollOffsetRange<LayoutUnit>> convertToLayoutUnits(const Vector<ScrollOffsetRange<float>>& snapOffsetRangesAsFloat) 95 { 96 Vector<ScrollOffsetRange<LayoutUnit>> snapOffsetRanges; 97 snapOffsetRanges.reserveInitialCapacity(snapOffsetRangesAsFloat.size()); 98 for (auto range : snapOffsetRangesAsFloat) 99 snapOffsetRanges.uncheckedAppend({ range.start, range.end }); 100 101 return snapOffsetRanges; 102 } 93 103 #endif 94 104 … … 147 157 148 158 #if ENABLE(CSS_SCROLL_SNAP) 149 if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::HorizontalSnapOffsets) )150 m_scrollController.updateScrollSnapPoints(ScrollEventAxis::Horizontal, convertToLayoutUnits(scrollingStateNode.horizontalSnapOffsets()) );151 152 if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::VerticalSnapOffsets) )153 m_scrollController.updateScrollSnapPoints(ScrollEventAxis::Vertical, convertToLayoutUnits(scrollingStateNode.verticalSnapOffsets()) );159 if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::HorizontalSnapOffsets) || scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::HorizontalSnapOffsetRanges)) 160 m_scrollController.updateScrollSnapPoints(ScrollEventAxis::Horizontal, convertToLayoutUnits(scrollingStateNode.horizontalSnapOffsets()), convertToLayoutUnits(scrollingStateNode.horizontalSnapOffsetRanges())); 161 162 if (scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::VerticalSnapOffsets) || scrollingStateNode.hasChangedProperty(ScrollingStateFrameScrollingNode::VerticalSnapOffsetRanges)) 163 m_scrollController.updateScrollSnapPoints(ScrollEventAxis::Vertical, convertToLayoutUnits(scrollingStateNode.verticalSnapOffsets()), convertToLayoutUnits(scrollingStateNode.verticalSnapOffsetRanges())); 154 164 155 165 if (scrollingStateNode.hasChangedProperty(ScrollingStateScrollingNode::CurrentHorizontalSnapOffsetIndex)) -
trunk/Source/WebCore/platform/ScrollableArea.cpp
r210117 r210560 49 49 virtual ~SameSizeAsScrollableArea(); 50 50 #if ENABLE(CSS_SCROLL_SNAP) 51 void* pointers[ 4];51 void* pointers[3]; 52 52 unsigned currentIndices[2]; 53 53 #else … … 426 426 427 427 #if ENABLE(CSS_SCROLL_SNAP) 428 void ScrollableArea::setHorizontalSnapOffsets(std::unique_ptr<Vector<LayoutUnit>> horizontalSnapOffsets) 429 { 430 ASSERT(horizontalSnapOffsets); 428 ScrollSnapOffsetsInfo<LayoutUnit>& ScrollableArea::ensureSnapOffsetsInfo() 429 { 430 if (!m_snapOffsetsInfo) 431 m_snapOffsetsInfo = std::make_unique<ScrollSnapOffsetsInfo<LayoutUnit>>(); 432 return *m_snapOffsetsInfo; 433 } 434 435 const Vector<LayoutUnit>* ScrollableArea::horizontalSnapOffsets() const 436 { 437 if (!m_snapOffsetsInfo) 438 return nullptr; 439 440 return &m_snapOffsetsInfo->horizontalSnapOffsets; 441 } 442 443 const Vector<ScrollOffsetRange<LayoutUnit>>* ScrollableArea::horizontalSnapOffsetRanges() const 444 { 445 if (!m_snapOffsetsInfo) 446 return nullptr; 447 448 return &m_snapOffsetsInfo->horizontalSnapOffsetRanges; 449 } 450 451 const Vector<ScrollOffsetRange<LayoutUnit>>* ScrollableArea::verticalSnapOffsetRanges() const 452 { 453 if (!m_snapOffsetsInfo) 454 return nullptr; 455 456 return &m_snapOffsetsInfo->verticalSnapOffsetRanges; 457 } 458 459 const Vector<LayoutUnit>* ScrollableArea::verticalSnapOffsets() const 460 { 461 if (!m_snapOffsetsInfo) 462 return nullptr; 463 464 return &m_snapOffsetsInfo->verticalSnapOffsets; 465 } 466 467 void ScrollableArea::setHorizontalSnapOffsets(const Vector<LayoutUnit>& horizontalSnapOffsets) 468 { 431 469 // Consider having a non-empty set of snap offsets as a cue to initialize the ScrollAnimator. 432 if (horizontalSnapOffsets ->size())470 if (horizontalSnapOffsets.size()) 433 471 scrollAnimator(); 434 472 435 m_horizontalSnapOffsets = WTFMove(horizontalSnapOffsets); 436 } 437 438 void ScrollableArea::setVerticalSnapOffsets(std::unique_ptr<Vector<LayoutUnit>> verticalSnapOffsets) 439 { 440 ASSERT(verticalSnapOffsets); 473 ensureSnapOffsetsInfo().horizontalSnapOffsets = horizontalSnapOffsets; 474 } 475 476 void ScrollableArea::setVerticalSnapOffsets(const Vector<LayoutUnit>& verticalSnapOffsets) 477 { 441 478 // Consider having a non-empty set of snap offsets as a cue to initialize the ScrollAnimator. 442 if (verticalSnapOffsets ->size())479 if (verticalSnapOffsets.size()) 443 480 scrollAnimator(); 444 481 445 m_verticalSnapOffsets = WTFMove(verticalSnapOffsets); 482 ensureSnapOffsetsInfo().verticalSnapOffsets = verticalSnapOffsets; 483 } 484 485 void ScrollableArea::setHorizontalSnapOffsetRanges(const Vector<ScrollOffsetRange<LayoutUnit>>& horizontalRanges) 486 { 487 ensureSnapOffsetsInfo().horizontalSnapOffsetRanges = horizontalRanges; 488 } 489 490 void ScrollableArea::setVerticalSnapOffsetRanges(const Vector<ScrollOffsetRange<LayoutUnit>>& verticalRanges) 491 { 492 ensureSnapOffsetsInfo().verticalSnapOffsetRanges = verticalRanges; 446 493 } 447 494 448 495 void ScrollableArea::clearHorizontalSnapOffsets() 449 496 { 450 m_horizontalSnapOffsets = nullptr; 497 if (!m_snapOffsetsInfo) 498 return; 499 500 m_snapOffsetsInfo->horizontalSnapOffsets = { }; 501 m_snapOffsetsInfo->horizontalSnapOffsetRanges = { }; 451 502 m_currentHorizontalSnapPointIndex = 0; 452 503 } … … 454 505 void ScrollableArea::clearVerticalSnapOffsets() 455 506 { 456 m_verticalSnapOffsets = nullptr; 507 if (!m_snapOffsetsInfo) 508 return; 509 510 m_snapOffsetsInfo->verticalSnapOffsets = { }; 511 m_snapOffsetsInfo->verticalSnapOffsetRanges = { }; 457 512 m_currentVerticalSnapPointIndex = 0; 458 513 } -
trunk/Source/WebCore/platform/ScrollableArea.h
r200342 r210560 27 27 #define ScrollableArea_h 28 28 29 #include "ScrollSnapOffsetsInfo.h" 29 30 #include "Scrollbar.h" 30 31 #include <wtf/Vector.h> … … 68 69 69 70 #if ENABLE(CSS_SCROLL_SNAP) 70 const Vector<LayoutUnit>* horizontalSnapOffsets() const { return m_horizontalSnapOffsets.get(); }; 71 const Vector<LayoutUnit>* verticalSnapOffsets() const { return m_verticalSnapOffsets.get(); }; 71 WEBCORE_EXPORT const Vector<LayoutUnit>* horizontalSnapOffsets() const; 72 WEBCORE_EXPORT const Vector<LayoutUnit>* verticalSnapOffsets() const; 73 WEBCORE_EXPORT const Vector<ScrollOffsetRange<LayoutUnit>>* horizontalSnapOffsetRanges() const; 74 WEBCORE_EXPORT const Vector<ScrollOffsetRange<LayoutUnit>>* verticalSnapOffsetRanges() const; 72 75 virtual void updateSnapOffsets() { }; 73 void setHorizontalSnapOffsets(std::unique_ptr<Vector<LayoutUnit>>); 74 void setVerticalSnapOffsets(std::unique_ptr<Vector<LayoutUnit>>); 76 void setHorizontalSnapOffsets(const Vector<LayoutUnit>&); 77 void setVerticalSnapOffsets(const Vector<LayoutUnit>&); 78 void setHorizontalSnapOffsetRanges(const Vector<ScrollOffsetRange<LayoutUnit>>&); 79 void setVerticalSnapOffsetRanges(const Vector<ScrollOffsetRange<LayoutUnit>>&); 75 80 void clearHorizontalSnapOffsets(); 76 81 void clearVerticalSnapOffsets(); … … 347 352 // scroll of the content. 348 353 virtual void setScrollOffset(const ScrollOffset&) = 0; 354 ScrollSnapOffsetsInfo<LayoutUnit>& ensureSnapOffsetsInfo(); 349 355 350 356 mutable std::unique_ptr<ScrollAnimator> m_scrollAnimator; … … 353 359 354 360 #if ENABLE(CSS_SCROLL_SNAP) 355 std::unique_ptr<Vector<LayoutUnit>> m_horizontalSnapOffsets; 356 std::unique_ptr<Vector<LayoutUnit>> m_verticalSnapOffsets; 361 std::unique_ptr<ScrollSnapOffsetsInfo<LayoutUnit>> m_snapOffsetsInfo; 357 362 unsigned m_currentHorizontalSnapPointIndex { 0 }; 358 363 unsigned m_currentVerticalSnapPointIndex { 0 }; -
trunk/Source/WebCore/platform/cocoa/ScrollController.h
r209087 r210560 38 38 #if ENABLE(CSS_SCROLL_SNAP) 39 39 #include "ScrollSnapAnimatorState.h" 40 #include "ScrollSnapOffsetsInfo.h" 40 41 #endif 41 42 … … 134 135 135 136 #if ENABLE(CSS_SCROLL_SNAP) 136 void updateScrollSnapPoints(ScrollEventAxis, const Vector<LayoutUnit>& );137 void updateScrollSnapPoints(ScrollEventAxis, const Vector<LayoutUnit>&, const Vector<ScrollOffsetRange<LayoutUnit>>&); 137 138 void setActiveScrollSnapIndexForAxis(ScrollEventAxis, unsigned); 138 139 void setActiveScrollSnapIndicesForOffset(int x, int y); -
trunk/Source/WebCore/platform/cocoa/ScrollController.mm
r210024 r210560 554 554 stopScrollSnapTimer(); 555 555 m_scrollSnapState->transitionToUserInteractionState(); 556 m_dragEndedScrollingVelocity = -wheelEvent.scrollingVelocity(); 556 557 break; 557 558 case WheelEventStatus::UserScrollEnd: 558 m_dragEndedScrollingVelocity = -wheelEvent.scrollingVelocity();559 559 m_scrollSnapState->transitionToSnapAnimationState(m_client.scrollExtent(), m_client.viewportSize(), m_client.pageScaleFactor(), m_client.scrollOffset()); 560 560 startScrollSnapTimer(); … … 562 562 case WheelEventStatus::InertialScrollBegin: 563 563 m_scrollSnapState->transitionToGlideAnimationState(m_client.scrollExtent(), m_client.viewportSize(), m_client.pageScaleFactor(), m_client.scrollOffset(), m_dragEndedScrollingVelocity, FloatSize(-wheelEvent.deltaX(), -wheelEvent.deltaY())); 564 m_dragEndedScrollingVelocity = { }; 564 565 isInertialScrolling = true; 565 566 break; … … 582 583 void ScrollController::updateScrollSnapState(const ScrollableArea& scrollableArea) 583 584 { 584 if (auto* snapOffsets = scrollableArea.horizontalSnapOffsets()) 585 updateScrollSnapPoints(ScrollEventAxis::Horizontal, *snapOffsets); 586 else 587 updateScrollSnapPoints(ScrollEventAxis::Horizontal, { }); 588 589 if (auto* snapOffsets = scrollableArea.verticalSnapOffsets()) 590 updateScrollSnapPoints(ScrollEventAxis::Vertical, *snapOffsets); 591 else 592 updateScrollSnapPoints(ScrollEventAxis::Vertical, { }); 593 } 594 595 void ScrollController::updateScrollSnapPoints(ScrollEventAxis axis, const Vector<LayoutUnit>& snapPoints) 585 if (auto* snapOffsets = scrollableArea.horizontalSnapOffsets()) { 586 if (auto* snapOffsetRanges = scrollableArea.horizontalSnapOffsetRanges()) 587 updateScrollSnapPoints(ScrollEventAxis::Horizontal, *snapOffsets, *snapOffsetRanges); 588 else 589 updateScrollSnapPoints(ScrollEventAxis::Horizontal, *snapOffsets, { }); 590 } else 591 updateScrollSnapPoints(ScrollEventAxis::Horizontal, { }, { }); 592 593 if (auto* snapOffsets = scrollableArea.verticalSnapOffsets()) { 594 if (auto* snapOffsetRanges = scrollableArea.verticalSnapOffsetRanges()) 595 updateScrollSnapPoints(ScrollEventAxis::Vertical, *snapOffsets, *snapOffsetRanges); 596 else 597 updateScrollSnapPoints(ScrollEventAxis::Vertical, *snapOffsets, { }); 598 } else 599 updateScrollSnapPoints(ScrollEventAxis::Vertical, { }, { }); 600 } 601 602 void ScrollController::updateScrollSnapPoints(ScrollEventAxis axis, const Vector<LayoutUnit>& snapPoints, const Vector<ScrollOffsetRange<LayoutUnit>>& snapRanges) 596 603 { 597 604 if (!m_scrollSnapState) { … … 605 612 m_scrollSnapState = nullptr; 606 613 else 607 m_scrollSnapState->setSnapOffsets ForAxis(axis, snapPoints);614 m_scrollSnapState->setSnapOffsetsAndPositionRangesForAxis(axis, snapPoints, snapRanges); 608 615 } 609 616 … … 681 688 682 689 unsigned activeIndex = 0; 683 closestSnapOffset <LayoutUnit, float>(snapState.snapOffsetsForAxis(axis), clampedOffset, 0, activeIndex);690 closestSnapOffset(snapState.snapOffsetsForAxis(axis), snapState.snapOffsetRangesForAxis(axis), clampedOffset, 0, activeIndex); 684 691 685 692 if (activeIndex == activeScrollSnapIndexForAxis(axis)) -
trunk/Source/WebCore/platform/cocoa/ScrollSnapAnimatorState.h
r209087 r210560 34 34 #include "LayoutPoint.h" 35 35 #include "PlatformWheelEvent.h" 36 #include "ScrollSnapOffsetsInfo.h" 36 37 #include "ScrollTypes.h" 37 38 #include "ScrollingMomentumCalculator.h" … … 49 50 class ScrollSnapAnimatorState { 50 51 public: 51 Vector<LayoutUnit>snapOffsetsForAxis(ScrollEventAxis axis) const52 const Vector<LayoutUnit>& snapOffsetsForAxis(ScrollEventAxis axis) const 52 53 { 53 54 return axis == ScrollEventAxis::Horizontal ? m_snapOffsetsX : m_snapOffsetsY; 54 55 } 55 56 56 void setSnapOffsetsForAxis(ScrollEventAxis axis, const Vector<LayoutUnit>& snapOffsets)57 const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRangesForAxis(ScrollEventAxis axis) const 57 58 { 58 if (axis == ScrollEventAxis::Horizontal) 59 return axis == ScrollEventAxis::Horizontal ? m_snapOffsetRangesX : m_snapOffsetRangesY; 60 } 61 62 void setSnapOffsetsAndPositionRangesForAxis(ScrollEventAxis axis, const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges) 63 { 64 if (axis == ScrollEventAxis::Horizontal) { 59 65 m_snapOffsetsX = snapOffsets; 60 else 66 m_snapOffsetRangesX = snapOffsetRanges; 67 } else { 61 68 m_snapOffsetsY = snapOffsets; 69 m_snapOffsetRangesY = snapOffsetRanges; 70 } 62 71 } 63 72 … … 86 95 87 96 private: 88 float targetOffsetForStartOffset( ScrollEventAxis, float maxScrollOffset, float startOffset, float pageScale, float delta, unsigned& outActiveSnapIndex) const;97 float targetOffsetForStartOffset(const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges, float maxScrollOffset, float startOffset, float predictedOffset, float pageScale, float delta, unsigned& outActiveSnapIndex) const; 89 98 void teardownAnimationForState(ScrollSnapState); 90 99 void setupAnimationForState(ScrollSnapState, const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset, const FloatSize& initialVelocity, const FloatSize& initialDelta); … … 93 102 94 103 Vector<LayoutUnit> m_snapOffsetsX; 104 Vector<ScrollOffsetRange<LayoutUnit>> m_snapOffsetRangesX; 95 105 unsigned m_activeSnapIndexX { 0 }; 96 106 Vector<LayoutUnit> m_snapOffsetsY; 107 Vector<ScrollOffsetRange<LayoutUnit>> m_snapOffsetRangesY; 97 108 unsigned m_activeSnapIndexY { 0 }; 98 109 -
trunk/Source/WebCore/platform/cocoa/ScrollSnapAnimatorState.mm
r209087 r210560 32 32 namespace WebCore { 33 33 34 static const float inertialScrollPredictionFactor = 10;35 static inline float projectedInertialScrollDistance(float initialWheelDelta)36 {37 return inertialScrollPredictionFactor * initialWheelDelta;38 }39 40 34 void ScrollSnapAnimatorState::transitionToSnapAnimationState(const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset) 41 35 { … … 54 48 return; 55 49 56 float targetOffsetX = targetOffsetForStartOffset(ScrollEventAxis::Horizontal, contentSize.width() - viewportSize.width(), initialOffset.x(), pageScale, initialDelta.width(), m_activeSnapIndexX); 57 float targetOffsetY = targetOffsetForStartOffset(ScrollEventAxis::Vertical, contentSize.height() - viewportSize.height(), initialOffset.y(), pageScale, initialDelta.height(), m_activeSnapIndexY); 58 m_momentumCalculator = ScrollingMomentumCalculator::create(viewportSize, contentSize, initialOffset, FloatPoint(targetOffsetX, targetOffsetY), initialDelta, initialVelocity); 50 m_momentumCalculator = ScrollingMomentumCalculator::create(viewportSize, contentSize, initialOffset, initialDelta, initialVelocity); 51 auto predictedScrollTarget = m_momentumCalculator->predictedDestinationOffset(); 52 float targetOffsetX = targetOffsetForStartOffset(m_snapOffsetsX, m_snapOffsetRangesX, contentSize.width() - viewportSize.width(), initialOffset.x(), predictedScrollTarget.width(), pageScale, initialDelta.width(), m_activeSnapIndexX); 53 float targetOffsetY = targetOffsetForStartOffset(m_snapOffsetsY, m_snapOffsetRangesY, contentSize.height() - viewportSize.height(), initialOffset.y(), predictedScrollTarget.height(), pageScale, initialDelta.height(), m_activeSnapIndexY); 54 m_momentumCalculator->setRetargetedScrollOffset({ targetOffsetX, targetOffsetY }); 59 55 m_startTime = MonotonicTime::now(); 60 56 m_currentState = state; … … 94 90 } 95 91 96 float ScrollSnapAnimatorState::targetOffsetForStartOffset( ScrollEventAxis axis, float maxScrollOffset, float startOffset, float pageScale, float initialDelta, unsigned& outActiveSnapIndex) const92 float ScrollSnapAnimatorState::targetOffsetForStartOffset(const Vector<LayoutUnit>& snapOffsets, const Vector<ScrollOffsetRange<LayoutUnit>>& snapOffsetRanges, float maxScrollOffset, float startOffset, float predictedOffset, float pageScale, float initialDelta, unsigned& outActiveSnapIndex) const 97 93 { 98 auto snapOffsets = snapOffsetsForAxis(axis); 99 if (!snapOffsets.size()) { 100 outActiveSnapIndex = 0; 94 if (snapOffsets.isEmpty()) { 95 outActiveSnapIndex = invalidSnapOffsetIndex; 101 96 return clampTo<float>(startOffset, 0, maxScrollOffset); 102 97 } 103 98 104 float projectedDestination = (startOffset + projectedInertialScrollDistance(initialDelta)) / pageScale;105 float targetOffset = closestSnapOffset<LayoutUnit, float>(snapOffsets, projectedDestination, initialDelta, outActiveSnapIndex);106 targetOffset = clampTo<float>(targetOffset, snapOffsets.first(), snapOffsets.last());107 targetOffset = clampTo<float>(targetOffset, 0, maxScrollOffset);99 float targetOffset = closestSnapOffset(snapOffsets, snapOffsetRanges, predictedOffset / pageScale, initialDelta, outActiveSnapIndex); 100 float minimumTargetOffset = std::max<float>(0, snapOffsets.first()); 101 float maximumTargetOffset = std::min<float>(maxScrollOffset, snapOffsets.last()); 102 targetOffset = clampTo<float>(targetOffset, minimumTargetOffset, maximumTargetOffset); 108 103 return pageScale * targetOffset; 109 104 } -
trunk/Source/WebCore/rendering/RenderLayerCompositor.cpp
r210436 r210560 3908 3908 if (const Vector<LayoutUnit>* offsets = layer.verticalSnapOffsets()) 3909 3909 scrollingGeometry.verticalSnapOffsets = *offsets; 3910 if (const Vector<ScrollOffsetRange<LayoutUnit>>* ranges = layer.horizontalSnapOffsetRanges()) 3911 scrollingGeometry.horizontalSnapOffsetRanges = *ranges; 3912 if (const Vector<ScrollOffsetRange<LayoutUnit>>* ranges = layer.verticalSnapOffsetRanges()) 3913 scrollingGeometry.verticalSnapOffsetRanges = *ranges; 3910 3914 scrollingGeometry.currentHorizontalSnapPointIndex = layer.currentHorizontalSnapPointIndex(); 3911 3915 scrollingGeometry.currentVerticalSnapPointIndex = layer.currentVerticalSnapPointIndex(); -
trunk/Source/WebCore/testing/Internals.cpp
r210432 r210560 118 118 #include "ScriptedAnimationController.h" 119 119 #include "ScrollingCoordinator.h" 120 #include "ScrollingMomentumCalculator.h" 120 121 #include "SerializedScriptValue.h" 121 122 #include "Settings.h" … … 3341 3342 } 3342 3343 3344 void Internals::setPlatformMomentumScrollingPredictionEnabled(bool enabled) 3345 { 3346 ScrollingMomentumCalculator::setPlatformMomentumScrollingPredictionEnabled(enabled); 3347 } 3348 3343 3349 ExceptionOr<String> Internals::scrollSnapOffsets(Element& element) 3344 3350 { … … 3368 3374 StringBuilder result; 3369 3375 3370 if (scrollableArea->horizontalSnapOffsets()) { 3371 result.appendLiteral("horizontal = "); 3372 appendOffsets(result, *scrollableArea->horizontalSnapOffsets()); 3373 } 3374 3375 if (scrollableArea->verticalSnapOffsets()) { 3376 if (result.length()) 3377 result.appendLiteral(", "); 3378 3379 result.appendLiteral("vertical = "); 3380 appendOffsets(result, *scrollableArea->verticalSnapOffsets()); 3376 if (auto* offsets = scrollableArea->horizontalSnapOffsets()) { 3377 if (offsets->size()) { 3378 result.appendLiteral("horizontal = "); 3379 appendOffsets(result, *offsets); 3380 } 3381 } 3382 3383 if (auto* offsets = scrollableArea->verticalSnapOffsets()) { 3384 if (offsets->size()) { 3385 if (result.length()) 3386 result.appendLiteral(", "); 3387 3388 result.appendLiteral("vertical = "); 3389 appendOffsets(result, *offsets); 3390 } 3381 3391 } 3382 3392 -
trunk/Source/WebCore/testing/Internals.h
r210432 r210560 480 480 #if ENABLE(CSS_SCROLL_SNAP) 481 481 ExceptionOr<String> scrollSnapOffsets(Element&); 482 void setPlatformMomentumScrollingPredictionEnabled(bool); 482 483 #endif 483 484 -
trunk/Source/WebCore/testing/Internals.idl
r210432 r210560 457 457 #if defined(ENABLE_CSS_SCROLL_SNAP) && ENABLE_CSS_SCROLL_SNAP 458 458 [MayThrowException] DOMString scrollSnapOffsets(Element element); 459 void setPlatformMomentumScrollingPredictionEnabled(boolean enabled); 459 460 #endif 460 461 -
trunk/Source/WebKit2/ChangeLog
r210545 r210560 1 2017-01-10 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Implement "proximity" scroll snapping 4 https://bugs.webkit.org/show_bug.cgi?id=135994 5 <rdar://problem/18162418> 6 7 Reviewed by Dean Jackson. 8 9 Adds boilerplate support for plumbing lists of snap offset ranges from the web process to the UI process 10 alongside the list of snap offsets. 11 12 * Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp: 13 (ArgumentCoder<ScrollingStateScrollingNode>::encode): 14 (ArgumentCoder<ScrollingStateScrollingNode>::decode): 15 * Shared/WebCoreArgumentCoders.cpp: 16 (IPC::ArgumentCoder<ScrollOffsetRange<float>>::encode): 17 (IPC::ArgumentCoder<ScrollOffsetRange<float>>::decode): 18 * Shared/WebCoreArgumentCoders.h: 19 * UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm: 20 (-[WKOverflowScrollViewDelegate scrollViewWillEndDragging:withVelocity:targetContentOffset:]): 21 * UIProcess/ios/RemoteScrollingCoordinatorProxyIOS.mm: 22 23 Adjust mainframe proximity scroll snapping logic to not subtract out the top content inset when there is no 24 active snap offset (i.e. when snapping rests in a snap offset range). Attempting to subtract out the top inset 25 in this case caused the scroll offset to jump after ending a drag with no momentum in a snap offset range. 26 27 (WebKit::RemoteScrollingCoordinatorProxy::adjustTargetContentOffsetForSnapping): 28 (WebKit::RemoteScrollingCoordinatorProxy::shouldSnapForMainFrameScrolling): 29 (WebKit::RemoteScrollingCoordinatorProxy::closestSnapOffsetForMainFrameScrolling): 30 1 31 2017-01-10 Zan Dobersek <zdobersek@igalia.com> 2 32 -
trunk/Source/WebKit2/Shared/Scrolling/RemoteScrollingCoordinatorTransaction.cpp
r208503 r210560 128 128 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::HorizontalSnapOffsets, horizontalSnapOffsets) 129 129 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::VerticalSnapOffsets, verticalSnapOffsets) 130 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::HorizontalSnapOffsetRanges, horizontalSnapOffsetRanges) 131 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::VerticalSnapOffsetRanges, verticalSnapOffsetRanges) 130 132 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::CurrentHorizontalSnapOffsetIndex, currentHorizontalSnapPointIndex) 131 133 SCROLLING_NODE_ENCODE(ScrollingStateScrollingNode::CurrentVerticalSnapOffsetIndex, currentVerticalSnapPointIndex) … … 203 205 SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::HorizontalSnapOffsets, Vector<float>, setHorizontalSnapOffsets); 204 206 SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::VerticalSnapOffsets, Vector<float>, setVerticalSnapOffsets); 207 SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::HorizontalSnapOffsetRanges, Vector<ScrollOffsetRange<float>>, setHorizontalSnapOffsetRanges) 208 SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::VerticalSnapOffsetRanges, Vector<ScrollOffsetRange<float>>, setVerticalSnapOffsetRanges) 205 209 SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::CurrentHorizontalSnapOffsetIndex, unsigned, setCurrentHorizontalSnapPointIndex); 206 210 SCROLLING_NODE_DECODE(ScrollingStateScrollingNode::CurrentVerticalSnapOffsetIndex, unsigned, setCurrentVerticalSnapPointIndex); -
trunk/Source/WebKit2/Shared/WebCoreArgumentCoders.cpp
r210360 r210560 2473 2473 #endif 2474 2474 2475 #if ENABLE(CSS_SCROLL_SNAP) 2476 2477 void ArgumentCoder<ScrollOffsetRange<float>>::encode(Encoder& encoder, const ScrollOffsetRange<float>& range) 2478 { 2479 encoder << range.start; 2480 encoder << range.end; 2481 } 2482 2483 bool ArgumentCoder<ScrollOffsetRange<float>>::decode(Decoder& decoder, ScrollOffsetRange<float>& range) 2484 { 2485 float start; 2486 if (!decoder.decode(start)) 2487 return false; 2488 2489 float end; 2490 if (!decoder.decode(end)) 2491 return false; 2492 2493 range.start = start; 2494 range.end = end; 2495 return true; 2496 } 2497 2498 #endif 2499 2475 2500 } // namespace IPC -
trunk/Source/WebKit2/Shared/WebCoreArgumentCoders.h
r208916 r210560 31 31 #include <WebCore/IndexedDB.h> 32 32 #include <WebCore/PaymentHeaders.h> 33 #include <WebCore/ScrollSnapOffsetsInfo.h> 33 34 34 35 namespace WTF { … … 600 601 #endif 601 602 603 #if ENABLE(CSS_SCROLL_SNAP) 604 605 template<> struct ArgumentCoder<WebCore::ScrollOffsetRange<float>> { 606 static void encode(Encoder&, const WebCore::ScrollOffsetRange<float>&); 607 static bool decode(Decoder&, WebCore::ScrollOffsetRange<float>&); 608 }; 609 610 #endif 611 602 612 } // namespace IPC 603 613 -
trunk/Source/WebKit2/UIProcess/Scrolling/ios/ScrollingTreeOverflowScrollingNodeIOS.mm
r208841 r210560 40 40 #if ENABLE(CSS_SCROLL_SNAP) 41 41 #import <WebCore/AxisScrollSnapOffsets.h> 42 #import <WebCore/ScrollSnapOffsetsInfo.h> 42 43 #endif 43 44 … … 89 90 if (!_scrollingTreeNode->horizontalSnapOffsets().isEmpty()) { 90 91 unsigned index; 91 float potentialSnapPosition = closestSnapOffset <float, CGFloat>(_scrollingTreeNode->horizontalSnapOffsets(), horizontalTarget, velocity.x, index);92 float potentialSnapPosition = closestSnapOffset(_scrollingTreeNode->horizontalSnapOffsets(), _scrollingTreeNode->horizontalSnapOffsetRanges(), horizontalTarget, velocity.x, index); 92 93 _scrollingTreeNode->setCurrentHorizontalSnapPointIndex(index); 93 94 if (horizontalTarget >= 0 && horizontalTarget <= scrollView.contentSize.width) … … 97 98 if (!_scrollingTreeNode->verticalSnapOffsets().isEmpty()) { 98 99 unsigned index; 99 float potentialSnapPosition = closestSnapOffset <float, CGFloat>(_scrollingTreeNode->verticalSnapOffsets(), verticalTarget, velocity.y, index);100 float potentialSnapPosition = closestSnapOffset(_scrollingTreeNode->verticalSnapOffsets(), _scrollingTreeNode->verticalSnapOffsetRanges(), verticalTarget, velocity.y, index); 100 101 _scrollingTreeNode->setCurrentVerticalSnapPointIndex(index); 101 102 if (verticalTarget >= 0 && verticalTarget <= scrollView.contentSize.height) -
trunk/Source/WebKit2/UIProcess/ios/RemoteScrollingCoordinatorProxyIOS.mm
r209967 r210560 40 40 #if ENABLE(CSS_SCROLL_SNAP) 41 41 #import <WebCore/AxisScrollSnapOffsets.h> 42 #import <WebCore/ScrollSnapOffsetsInfo.h> 42 43 #import <WebCore/ScrollTypes.h> 43 44 #import <WebCore/ScrollingTreeFrameScrollingNode.h> … … 125 126 if (shouldSnapForMainFrameScrolling(WebCore::ScrollEventAxis::Vertical)) { 126 127 float potentialSnapPosition = closestSnapOffsetForMainFrameScrolling(WebCore::ScrollEventAxis::Vertical, targetContentOffset->y, velocity.y, m_currentVerticalSnapPointIndex); 127 potentialSnapPosition -= topInset; 128 if (m_currentVerticalSnapPointIndex != invalidSnapOffsetIndex) 129 potentialSnapPosition -= topInset; 130 128 131 if (targetContentOffset->y > 0 && targetContentOffset->y < maxScrollOffsets.height) 129 132 targetContentOffset->y = std::min<float>(maxScrollOffsets.height, potentialSnapPosition); … … 143 146 const Vector<float>& snapOffsets = axis == ScrollEventAxis::Horizontal ? rootFrame->horizontalSnapOffsets() : rootFrame->verticalSnapOffsets(); 144 147 unsigned currentIndex = axis == ScrollEventAxis::Horizontal ? m_currentHorizontalSnapPointIndex : m_currentVerticalSnapPointIndex; 145 return (snapOffsets.size() > 0) && (currentIndex < snapOffsets.size());148 return snapOffsets.size() && (currentIndex < snapOffsets.size() || currentIndex == invalidSnapOffsetIndex); 146 149 } 147 150 return false; … … 154 157 ScrollingTreeFrameScrollingNode* rootFrame = static_cast<ScrollingTreeFrameScrollingNode*>(root); 155 158 const Vector<float>& snapOffsets = axis == ScrollEventAxis::Horizontal ? rootFrame->horizontalSnapOffsets() : rootFrame->verticalSnapOffsets(); 159 const Vector<ScrollOffsetRange<float>>& snapOffsetRanges = axis == ScrollEventAxis::Horizontal ? rootFrame->horizontalSnapOffsetRanges() : rootFrame->verticalSnapOffsetRanges(); 156 160 157 161 float scaledScrollDestination = scrollDestination / m_webPageProxy.displayedContentScale(); 158 float rawClosestSnapOffset = closestSnapOffset <float, float>(snapOffsets, scaledScrollDestination, velocity, currentIndex);162 float rawClosestSnapOffset = closestSnapOffset(snapOffsets, snapOffsetRanges, scaledScrollDestination, velocity, currentIndex); 159 163 return rawClosestSnapOffset * m_webPageProxy.displayedContentScale(); 160 164 }
Note: See TracChangeset
for help on using the changeset viewer.