Changeset 209070 in webkit
- Timestamp:
- Nov 29, 2016 8:10:55 AM (7 years ago)
- Location:
- trunk
- Files:
-
- 6 added
- 27 edited
- 1 copied
Legend:
- Unmodified
- Added
- Removed
-
trunk/LayoutTests/ChangeLog
r209069 r209070 1 2016-11-29 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Scroll snapping on Mac should use AppKit animations 4 https://bugs.webkit.org/show_bug.cgi?id=147261 5 <rdar://problem/29395293> 6 7 Reviewed by Brent Fulgham. 8 9 Fixes 8 previously failing scroll snapping tests in the tiled-drawing/scrolling/scroll-snap directory and 10 removes them from TestExpectations. Also adds a new layout test. See WebCore/ChangeLog for more details. 11 12 * platform/mac-wk2/TestExpectations: 13 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow-expected.txt: 14 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-borders-expected.txt: 15 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html: 16 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html: 17 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal-expected.txt: Added. 18 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical-then-horizontal.html: Added. 19 * tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html: 20 1 21 2016-11-29 Brady Eidson <beidson@apple.com> 2 22 -
trunk/LayoutTests/platform/mac-wk2/TestExpectations
r208915 r209070 265 265 266 266 webkit.org/b/162505 tiled-drawing/scrolling/latched-div-with-scroll-snap.html [ Pass Failure ] 267 268 webkit.org/b/148405 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow.html [ Pass Failure ]269 270 webkit.org/b/148407 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-horizontal.html [ Pass Failure ]271 267 webkit.org/b/148407 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html [ Pass Failure ] 272 268 webkit.org/b/148407 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html [ Pass Failure ] 273 webkit.org/b/148407 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html [ Pass Failure ] 274 275 webkit.org/b/148408 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-borders.html [ Pass Failure ] 276 webkit.org/b/148408 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-overflow.html [ Pass Failure ] 277 webkit.org/b/148408 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-rotated.html [ Pass Failure ] 278 webkit.org/b/148408 tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-padding.html [ Pass Failure ] 279 webkit.org/b/148408 tiled-drawing/scrolling/scroll-snap/scroll-snap-iframe.html [ Pass Failure ] 269 280 270 webkit.org/b/148408 tiled-drawing/scrolling/root-overflow-with-mousewheel.html [ Pass Failure Timeout ] 281 271 -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-2d-overflow-expected.txt
r197571 r209070 1 1 PASS div successfully scrolled diagonally. 2 2 PASS div successfully snapped diagonally. 3 FAIL div did not honor 2D snap points. (single axis scroll followed by flick on other axis) 3 PASS div successfully snapped after dragging along one axis and then scrolling in the other. 4 4 PASS successfullyParsed is true 5 5 -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-borders-expected.txt
r197571 r209070 5 5 PASS div honored snap points. 6 6 Testing scroll-snap glide for verticalTarget: 7 FAIL div did not honor snap points. Expected 300, but got 50 7 PASS div scrolled to next window. 8 8 Testing scroll-snap snap for verticalTarget: 9 FAIL div did not snap back to proper location for verticalTarget. Expected 50, but got 0 9 PASS div honored snap points. 10 10 PASS successfullyParsed is true 11 11 -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-horizontal.html
r188793 r209070 34 34 // The div should have snapped back to the previous position 35 35 if (divTarget.scrollLeft != divScrollPositionBeforeSnap) 36 testFailed( "div did not snap back to proper location.");36 testFailed(`div did not snap back to proper location. ${divTarget.scrollLeft} vs. ${divScrollPositionBeforeSnap}`); 37 37 else 38 38 testPassed("div honored snap points."); … … 64 64 testPassed("div scrolled to next window."); 65 65 else 66 testFailed( "div did not honor snap points.");66 testFailed(`div did not honor snap points. ${divTarget.scrollLeft} vs. ${window.innerWidth}`); 67 67 68 68 setTimeout(scrollSnapTest, 0); -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-slow-vertical.html
r188793 r209070 34 34 // The div should have snapped back to the previous position 35 35 if (divTarget.scrollTop != divScrollPositionBeforeSnap) 36 testFailed( "div did not snap back to proper location.");36 testFailed(`div did not snap back to proper location. (${divTarget.scrollTop} vs. ${divScrollPositionBeforeSnap})`); 37 37 else 38 38 testPassed("div honored snap points."); … … 64 64 testPassed("div scrolled to next window."); 65 65 else 66 testFailed( "div did not honor snap points.");66 testFailed(`div did not honor snap points. (${divTarget.scrollTop} vs. ${window.innerHeight})`); 67 67 68 68 setTimeout(scrollSnapTest, 0); … … 89 89 90 90 function onLoad() { 91 92 91 if (window.eventSender) { 93 92 eventSender.monitorWheelEvents(); -
trunk/LayoutTests/tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-mainframe-vertical.html
r188793 r209070 34 34 // The div should have snapped back to the previous position 35 35 if (divTarget.scrollTop != divScrollPositionBeforeSnap) 36 testFailed( "div did not snap back to proper location.");36 testFailed(`div did not snap back to proper location. (${divTarget.scrollTop} vs. ${divScrollPositionBeforeSnap})`); 37 37 else 38 38 testPassed("div honored snap points."); … … 64 64 testPassed("div scrolled to next window."); 65 65 else 66 testFailed( "div did not honor snap points.");66 testFailed(`div did not honor snap points. (${divTarget.scrollTop} vs. ${window.innerHeight})`); 67 67 68 68 setTimeout(scrollSnapTest, 0); -
trunk/Source/WTF/ChangeLog
r209058 r209070 1 2016-11-29 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Scroll snapping on Mac should use AppKit animations 4 https://bugs.webkit.org/show_bug.cgi?id=147261 5 <rdar://problem/29395293> 6 7 Reviewed by Brent Fulgham. 8 9 Introduce HAVE(NSSCROLLING_FILTERS), which is on for macOS El Capitan and later. 10 11 * wtf/Platform.h: 12 1 13 2016-11-28 Darin Adler <darin@apple.com> 2 14 -
trunk/Source/WTF/wtf/Platform.h
r208761 r209070 552 552 #endif 553 553 554 #if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100 555 #define HAVE_NSSCROLLING_FILTERS 1 556 #else 557 #define HAVE_NSSCROLLING_FILTERS 0 558 #endif 559 554 560 /* OS X defines a series of platform macros for debugging. */ 555 561 /* Some of them are really annoying because they use common names (e.g. check()). */ -
trunk/Source/WebCore/ChangeLog
r209069 r209070 1 2016-11-29 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Scroll snapping on Mac should use AppKit animations 4 https://bugs.webkit.org/show_bug.cgi?id=147261 5 <rdar://problem/29395293> 6 7 Reviewed by Brent Fulgham. 8 9 Refactors the scroll snapping animation logic to support arbitrary scrolling momentum calculators and 10 introduces ScrollingMomentumCalculatorMac, which wraps AppKit's _NSScrollingMomentumCalculator. On macOS El 11 Capitan and later, we use the platform scrolling momentum calculator and for all other cases, we fall back to 12 the preexissting platform-invariant momentum calculator. 13 14 Previously, the scroll snapping animation logic was shared between the ScrollSnapAnimatorState and 15 ScrollController -- namely, the ScrollController would update various parameters of the ScrollSnapAnimatorState 16 and then tell it to compute animation-specific constants and coefficients. After this patch, ScrollController 17 will no longer directly set the ScrollSnapAnimatorState's member variables. Instead, it will tell the animator 18 state to transition to a new ScrollSnapState with the necessary parameters, and the ScrollSnapAnimatorState is 19 responsible for modifying itself accordingly. Furthermore, logic pertaining to computing animated scroll offsets 20 is now split out into a new ScrollingMomentumCalculator, which may have different platform-dependent 21 implementations. The correct calculator is initialized via ScrollingMomentumCalculator::create, which currently 22 returns a ScrollingMomentumCalculatorMac on El Capitan and later, and a BasicScrollingMomentumCalculator 23 otherwise. 24 25 The new abstracted ScrollingMomentumCalculator is initialized with various parameters describing the scrolled 26 content and viewport, as well as the initial and target scrolling offsets. The momentum calculator is then able 27 to compute the animated scroll offset at any given elapsed time, as well as the total duration of the snapping 28 animation. The ScrollController's scroll snap timer uses this information (via the ScrollSnapAnimatorState) to 29 animate its client's scroll offset during a snap or glide. 30 31 Also reenables 8 failing and/or flaky scroll snapping tests and adds a new layout test. This patch addresses 32 two causes for failures and flakiness in these scroll snapping tests: 33 34 1. When starting or stopping the scroll snap animation timer, we call deferTestsForReason and 35 removeTestDeferralForReason, respectively. These were actually noops for the first simulated scroll gesture 36 on each of the failing mainframe scrolling tests due to m_expectsWheelEventTestTrigger being false. This 37 member variable is updated when AsyncScrollingCoordinator::frameViewLayoutUpdated is invoked, wherein we 38 call ScrollingStateFrameScrollingNode::setExpectsWheelEventTestTrigger(true) when the test has started 39 monitoring wheel events. However, if this does not happen before scrolling begins in the test (which is the 40 case here), then the mainframe scrolling node will not expect a wheel event test trigger even though 41 eventSender.monitorWheelEvents() has been called. To fix this, we simply make the Page trigger a layout of 42 the main FrameView when first ensuring the wheel event test trigger on the Page. 43 44 2. The second reason for flakiness affects both overflow and mainframe scrolling. Previously, due to the way 45 we would wait for multiple momentum scroll events before starting to glide, we would end up starting the 46 scroll snap timer for a snapping animation, stopping it, and then starting it again for the glide animation. 47 Thus, if the wheel event test trigger's timer fires right after the scroll snap timer stops and before it 48 starts again due to a glide animation, it will erroneously think that scroll snapping is complete, even 49 though it's only just about to begin! Now that we know scrolling velocity when we receive the initial 50 "momentum begin", we now directly transition the scroll snap state from a snapping state to a gliding state 51 and no longer stop and start the timer during this transition, which means that the test trigger will be 52 deferred for at least the entire duration of the scroll snapping animation (starting right after the first 53 "drag end" wheel event). 54 55 Test: tiled-drawing/scrolling/scroll-snap/scroll-snap-mandatory-vertical-then-horizontal.html 56 57 * WebCore.xcodeproj/project.pbxproj: 58 * page/EventHandler.cpp: 59 (WebCore::handleWheelEventInAppropriateEnclosingBox): 60 (WebCore::EventHandler::defaultWheelEventHandler): 61 * page/Page.cpp: 62 (WebCore::Page::ensureTestTrigger): 63 64 Addresses test failures by forcing the mainframe scrolling node to expect wheel event test triggers. 65 66 * page/WheelEventDeltaFilter.cpp: 67 (WebCore::WheelEventDeltaFilter::create): 68 (WebCore::WheelEventDeltaFilter::filteredVelocity): 69 * page/WheelEventDeltaFilter.h: 70 * page/mac/WheelEventDeltaFilterMac.mm: 71 (WebCore::WheelEventDeltaFilterMac::updateFromDelta): 72 73 Add support for plumbing filtered scrolling velocity over to the ScrollController. 74 75 * page/scrolling/ScrollingMomentumCalculator.cpp: Copied from Source/WebCore/platform/cocoa/ScrollSnapAnimatorState.mm. 76 (WebCore::ScrollingMomentumCalculator::ScrollingMomentumCalculator): 77 (WebCore::ScrollingMomentumCalculator::create): 78 79 Creates a platform-independent BasicScrollingMomentumCalculator. 80 81 (WebCore::BasicScrollingMomentumCalculator::BasicScrollingMomentumCalculator): 82 (WebCore::BasicScrollingMomentumCalculator::linearlyInterpolatedOffsetAtProgress): 83 (WebCore::BasicScrollingMomentumCalculator::cubicallyInterpolatedOffsetAtProgress): 84 (WebCore::BasicScrollingMomentumCalculator::scrollOffsetAfterElapsedTime): 85 (WebCore::BasicScrollingMomentumCalculator::animationDuration): 86 (WebCore::BasicScrollingMomentumCalculator::initializeInterpolationCoefficientsIfNecessary): 87 (WebCore::BasicScrollingMomentumCalculator::initializeSnapProgressCurve): 88 (WebCore::BasicScrollingMomentumCalculator::animationProgressAfterElapsedTime): 89 90 Interpolation logic ported over from ScrollSnapAnimatorState. 91 92 * page/scrolling/ScrollingMomentumCalculator.h: Added. 93 (WebCore::ScrollingMomentumCalculator::~ScrollingMomentumCalculator): 94 * page/scrolling/mac/ScrollingMomentumCalculatorMac.h: Copied from Source/WebCore/page/WheelEventDeltaFilter.h. 95 * page/scrolling/mac/ScrollingMomentumCalculatorMac.mm: Added. 96 (WebCore::ScrollingMomentumCalculator::create): 97 98 Creates a ScrollingMomentumCalculatorMac. 99 100 (WebCore::ScrollingMomentumCalculatorMac::ScrollingMomentumCalculatorMac): 101 (WebCore::ScrollingMomentumCalculatorMac::scrollOffsetAfterElapsedTime): 102 (WebCore::ScrollingMomentumCalculatorMac::animationDuration): 103 (WebCore::ScrollingMomentumCalculatorMac::ensurePlatformMomentumCalculator): 104 * page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.h: 105 * page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm: 106 (WebCore::ScrollingTreeFrameScrollingNodeMac::scrollOffset): 107 (WebCore::ScrollingTreeFrameScrollingNodeMac::viewportSize): 108 (WebCore::ScrollingTreeFrameScrollingNodeMac::scrollOffsetOnAxis): Deleted. 109 * platform/PlatformWheelEvent.h: 110 (WebCore::PlatformWheelEvent::copyWithDeltasAndVelocity): 111 (WebCore::PlatformWheelEvent::scrollingVelocity): 112 (WebCore::PlatformWheelEvent::copyWithDeltas): Deleted. 113 * platform/ScrollAnimator.cpp: 114 (WebCore::ScrollAnimator::scrollOffset): 115 (WebCore::ScrollAnimator::viewportSize): 116 (WebCore::ScrollAnimator::scrollOffsetOnAxis): Deleted. 117 * platform/ScrollAnimator.h: 118 * platform/cocoa/ScrollController.h: 119 * platform/cocoa/ScrollController.mm: 120 (WebCore::otherScrollEventAxis): 121 (WebCore::ScrollController::ScrollController): 122 (WebCore::ScrollController::shouldOverrideInertialScrolling): 123 (WebCore::ScrollController::scheduleStatelessScrollSnap): 124 (WebCore::ScrollController::statelessSnapTransitionTimerFired): 125 (WebCore::ScrollController::startDeferringTestsDueToScrollSnapping): 126 (WebCore::ScrollController::stopDeferringTestsDueToScrollSnapping): 127 (WebCore::ScrollController::processWheelEventForScrollSnap): 128 (WebCore::ScrollController::updateScrollSnapState): 129 (WebCore::ScrollController::updateScrollSnapPoints): 130 131 Update the ScrollController's ScrollSnapAnimationState for both vertical and horizontal axes. If both axes lack 132 any snap points, the pointer to the animation state will be nulled out; otherwise, the animation state will 133 exist. 134 135 (WebCore::ScrollController::startScrollSnapTimer): 136 (WebCore::ScrollController::stopScrollSnapTimer): 137 (WebCore::ScrollController::scrollSnapTimerFired): 138 (WebCore::ScrollController::activeScrollSnapIndexForAxis): 139 (WebCore::ScrollController::setActiveScrollSnapIndexForAxis): 140 (WebCore::ScrollController::setNearestScrollSnapIndexForAxisAndOffset): 141 (WebCore::ScrollController::setActiveScrollSnapIndicesForOffset): 142 (WebCore::ScrollController::scrollSnapPointState): Deleted. 143 (WebCore::ScrollController::processWheelEventForScrollSnapOnAxis): Deleted. 144 (WebCore::ScrollController::shouldOverrideWheelEvent): Deleted. 145 (WebCore::projectedInertialScrollDistance): Deleted. 146 (WebCore::ScrollController::beginScrollSnapAnimation): Deleted. 147 (WebCore::ScrollController::endScrollSnapAnimation): Deleted. 148 (WebCore::ScrollController::initializeScrollSnapAnimationParameters): Deleted. 149 (WebCore::ScrollController::isSnappingOnAxis): Deleted. 150 * platform/cocoa/ScrollSnapAnimatorState.h: 151 (WebCore::ScrollSnapAnimatorState::snapOffsetsForAxis): 152 (WebCore::ScrollSnapAnimatorState::setSnapOffsetsForAxis): 153 (WebCore::ScrollSnapAnimatorState::currentState): 154 (WebCore::ScrollSnapAnimatorState::activeSnapIndexForAxis): 155 (WebCore::ScrollSnapAnimatorState::setActiveSnapIndexForAxis): 156 * platform/cocoa/ScrollSnapAnimatorState.mm: 157 (WebCore::projectedInertialScrollDistance): 158 (WebCore::ScrollSnapAnimatorState::transitionToSnapAnimationState): 159 (WebCore::ScrollSnapAnimatorState::transitionToGlideAnimationState): 160 (WebCore::ScrollSnapAnimatorState::transitionToUserInteractionState): 161 (WebCore::ScrollSnapAnimatorState::transitionToDestinationReachedState): 162 163 These methods are used to update the ScrollSnapAnimationState. These state transitions should (and do) 164 encapsulate all changes that need to be made to the animation state; in other words, the ScrollController should 165 no longer be reaching directly into the ScrollSnapAnimatorState to change member variables. 166 167 (WebCore::ScrollSnapAnimatorState::setupAnimationForState): 168 (WebCore::ScrollSnapAnimatorState::teardownAnimationForState): 169 (WebCore::ScrollSnapAnimatorState::currentAnimatedScrollOffset): 170 (WebCore::ScrollSnapAnimatorState::targetOffsetForStartOffset): 171 (WebCore::ScrollSnapAnimatorState::ScrollSnapAnimatorState): Deleted. 172 (WebCore::ScrollSnapAnimatorState::pushInitialWheelDelta): Deleted. 173 (WebCore::ScrollSnapAnimatorState::averageInitialWheelDelta): Deleted. 174 (WebCore::ScrollSnapAnimatorState::clearInitialWheelDeltaWindow): Deleted. 175 (WebCore::ScrollSnapAnimatorState::isSnapping): Deleted. 176 (WebCore::ScrollSnapAnimatorState::canReachTargetWithCurrentInitialScrollDelta): Deleted. 177 (WebCore::ScrollSnapAnimatorState::wheelDeltaTrackingIsInProgress): Deleted. 178 (WebCore::ScrollSnapAnimatorState::hasFinishedTrackingWheelDeltas): Deleted. 179 (WebCore::ScrollSnapAnimatorState::interpolatedOffsetAtProgress): Deleted. 180 (WebCore::ScrollSnapAnimationCurveState::initializeSnapProgressCurve): Deleted. 181 (WebCore::ScrollSnapAnimationCurveState::initializeInterpolationCoefficientsIfNecessary): Deleted. 182 (WebCore::ScrollSnapAnimationCurveState::interpolatedPositionAtProgress): Deleted. 183 (WebCore::ScrollSnapAnimationCurveState::shouldCompleteSnapAnimationImmediatelyAtTime): Deleted. 184 (WebCore::ScrollSnapAnimationCurveState::animationProgressAtTime): Deleted. 185 186 The ScrollSnapAnimatorState now tracks state across both axes. This simplifies coordinating scroll snapping in 187 both horizontal and vertical axes and fixes the issue of the scroll offset not snapping when performing a scroll 188 in one direction without momentum, then scrolling with momentum in the other direction in a single gesture. 189 190 * platform/spi/mac/NSScrollingMomentumCalculatorSPI.h: Added. 191 1 192 2016-11-29 Brady Eidson <beidson@apple.com> 2 193 -
trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj
r208993 r209070 2160 2160 517B25A91CC82B2A0061C011 /* IDBConnectionProxy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517B25A71CC820320061C011 /* IDBConnectionProxy.cpp */; }; 2161 2161 517B25AA1CC82B2A0061C011 /* IDBConnectionProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 517B25A81CC820320061C011 /* IDBConnectionProxy.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2162 517DEEE51DE94ADC00B91644 /* ScrollingMomentumCalculatorMac.mm in Sources */ = {isa = PBXBuildFile; fileRef = 517DEEE31DE94ADC00B91644 /* ScrollingMomentumCalculatorMac.mm */; }; 2163 517DEEE81DE94B0800B91644 /* ScrollingMomentumCalculatorMac.h in Headers */ = {isa = PBXBuildFile; fileRef = 517DEEE71DE94B0800B91644 /* ScrollingMomentumCalculatorMac.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2162 2164 517FBA1E151AB17C00B57959 /* DOMWindowExtension.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 517FBA17151AA71B00B57959 /* DOMWindowExtension.cpp */; }; 2163 2165 5185FC741BB4C4E80012898F /* DOMWindowIndexedDatabase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51D7196C181106DF0016DC51 /* DOMWindowIndexedDatabase.cpp */; }; … … 2258 2260 51C0AA390F2AA10A001648C2 /* CachedFrame.h in Headers */ = {isa = PBXBuildFile; fileRef = 51C0AA380F2AA10A001648C2 /* CachedFrame.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2259 2261 51C0AA410F2AA15E001648C2 /* CachedFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51C0AA400F2AA15E001648C2 /* CachedFrame.cpp */; }; 2262 51C61B0A1DE536E7008A212D /* ScrollingMomentumCalculator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51C61B081DE536E7008A212D /* ScrollingMomentumCalculator.cpp */; }; 2263 51C61B0B1DE536E7008A212D /* ScrollingMomentumCalculator.h in Headers */ = {isa = PBXBuildFile; fileRef = 51C61B091DE536E7008A212D /* ScrollingMomentumCalculator.h */; settings = {ATTRIBUTES = (Private, ); }; }; 2260 2264 51C81B890C4422F70019ECE3 /* FTPDirectoryParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 51C81B870C4422F70019ECE3 /* FTPDirectoryParser.cpp */; }; 2261 2265 51C81B8A0C4422F70019ECE3 /* FTPDirectoryParser.h in Headers */ = {isa = PBXBuildFile; fileRef = 51C81B880C4422F70019ECE3 /* FTPDirectoryParser.h */; }; … … 9397 9401 517B25A71CC820320061C011 /* IDBConnectionProxy.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = IDBConnectionProxy.cpp; sourceTree = "<group>"; }; 9398 9402 517B25A81CC820320061C011 /* IDBConnectionProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = IDBConnectionProxy.h; sourceTree = "<group>"; }; 9403 517DEEE31DE94ADC00B91644 /* ScrollingMomentumCalculatorMac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollingMomentumCalculatorMac.mm; sourceTree = "<group>"; }; 9404 517DEEE71DE94B0800B91644 /* ScrollingMomentumCalculatorMac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingMomentumCalculatorMac.h; sourceTree = "<group>"; }; 9399 9405 517FBA17151AA71B00B57959 /* DOMWindowExtension.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DOMWindowExtension.cpp; sourceTree = "<group>"; }; 9400 9406 517FBA18151AA71B00B57959 /* DOMWindowExtension.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DOMWindowExtension.h; sourceTree = "<group>"; }; … … 9457 9463 51C0AA380F2AA10A001648C2 /* CachedFrame.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CachedFrame.h; sourceTree = "<group>"; }; 9458 9464 51C0AA400F2AA15E001648C2 /* CachedFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CachedFrame.cpp; sourceTree = "<group>"; }; 9465 51C61B081DE536E7008A212D /* ScrollingMomentumCalculator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ScrollingMomentumCalculator.cpp; sourceTree = "<group>"; }; 9466 51C61B091DE536E7008A212D /* ScrollingMomentumCalculator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ScrollingMomentumCalculator.h; sourceTree = "<group>"; }; 9467 51C61B0C1DE5383D008A212D /* NSScrollingMomentumCalculatorSPI.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSScrollingMomentumCalculatorSPI.h; sourceTree = "<group>"; }; 9459 9468 51C81B870C4422F70019ECE3 /* FTPDirectoryParser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = FTPDirectoryParser.cpp; sourceTree = "<group>"; }; 9460 9469 51C81B880C4422F70019ECE3 /* FTPDirectoryParser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = FTPDirectoryParser.h; sourceTree = "<group>"; }; … … 15946 15955 F45C231B1995B73B00A6E2E3 /* AxisScrollSnapOffsets.cpp */, 15947 15956 F45C231C1995B73B00A6E2E3 /* AxisScrollSnapOffsets.h */, 15957 51C61B081DE536E7008A212D /* ScrollingMomentumCalculator.cpp */, 15958 51C61B091DE536E7008A212D /* ScrollingMomentumCalculator.h */, 15948 15959 0F605AEA15F94848004DF0C0 /* ScrollingConstraints.cpp */, 15949 15960 0F605AEB15F94848004DF0C0 /* ScrollingConstraints.h */, … … 15987 15998 isa = PBXGroup; 15988 15999 children = ( 16000 517DEEE71DE94B0800B91644 /* ScrollingMomentumCalculatorMac.h */, 16001 517DEEE31DE94ADC00B91644 /* ScrollingMomentumCalculatorMac.mm */, 15989 16002 9391A990162746CB00297330 /* ScrollingCoordinatorMac.h */, 15990 16003 1AF62EE314DA22A70041556C /* ScrollingCoordinatorMac.mm */, … … 18504 18517 7C0406121C66EE9C00AF0711 /* NSScrollerImpSPI.h */, 18505 18518 F40EA8AA1B867D6500CE5581 /* NSScrollingInputFilterSPI.h */, 18519 51C61B0C1DE5383D008A212D /* NSScrollingMomentumCalculatorSPI.h */, 18506 18520 2DCB837719F99BBA00A7FBE4 /* NSSharingServicePickerSPI.h */, 18507 18521 2DCB837819F99BBA00A7FBE4 /* NSSharingServiceSPI.h */, … … 25774 25788 516953981329A3C800B92D04 /* IconDatabaseBase.h in Headers */, 25775 25789 51E1ECBE0C91C90400DC255B /* IconDatabaseClient.h in Headers */, 25790 517DEEE81DE94B0800B91644 /* ScrollingMomentumCalculatorMac.h in Headers */, 25776 25791 513F14540AB634C400094DDF /* IconLoader.h in Headers */, 25777 25792 51E1ECC10C91C90400DC255B /* IconRecord.h in Headers */, … … 26335 26350 46DFF49C1DC2620B00B80B48 /* JSShadowRootMode.h in Headers */, 26336 26351 CD9DE17B17AAC75B00EA386D /* JSSourceBuffer.h in Headers */, 26352 51C61B0B1DE536E7008A212D /* ScrollingMomentumCalculator.h in Headers */, 26337 26353 CD9DE17D17AAC75B00EA386D /* JSSourceBufferList.h in Headers */, 26338 26354 AA7FEEAD16A4E74B004C0C33 /* JSSpeechSynthesis.h in Headers */, … … 29356 29372 2D5036681BCDDDC400E20BB3 /* GestureEvents.cpp in Sources */, 29357 29373 B2AFFC830D00A5C10030074D /* GlyphPageMac.cpp in Sources */, 29374 51C61B0A1DE536E7008A212D /* ScrollingMomentumCalculator.cpp in Sources */, 29358 29375 BC53C6080DA56C570021EB5D /* Gradient.cpp in Sources */, 29359 29376 BC53C60B0DA56CF10021EB5D /* GradientCG.cpp in Sources */, … … 30926 30943 083DAEA60F01A7FB00342754 /* RenderTextControlMultiLine.cpp in Sources */, 30927 30944 083DAEA80F01A7FB00342754 /* RenderTextControlSingleLine.cpp in Sources */, 30945 517DEEE51DE94ADC00B91644 /* ScrollingMomentumCalculatorMac.mm in Sources */, 30928 30946 BCEA488D097D93020094C9E4 /* RenderTextFragment.cpp in Sources */, 30929 30947 E4C91A18180999FB00A17F6D /* RenderTextLineBoxes.cpp in Sources */, -
trunk/Source/WebCore/page/EventHandler.cpp
r208903 r209070 304 304 } 305 305 306 static inline bool handleWheelEventInAppropriateEnclosingBox(Node* startNode, WheelEvent& wheelEvent, Element** stopElement, const FloatSize& filteredPlatformDelta )306 static inline bool handleWheelEventInAppropriateEnclosingBox(Node* startNode, WheelEvent& wheelEvent, Element** stopElement, const FloatSize& filteredPlatformDelta, const FloatPoint& filteredVelocity) 307 307 { 308 308 bool shouldHandleEvent = wheelEvent.deltaX() || wheelEvent.deltaY(); … … 325 325 const PlatformWheelEvent* platformEvent = wheelEvent.wheelEvent(); 326 326 bool scrollingWasHandled; 327 if (platformEvent != nullptr) 328 scrollingWasHandled = boxLayer->handleWheelEvent(platformEvent->copyWithDeltas(filteredPlatformDelta.width(), filteredPlatformDelta.height())); 329 else 327 if (platformEvent != nullptr) { 328 auto copiedEvent = platformEvent->copyWithDeltasAndVelocity(filteredPlatformDelta.width(), filteredPlatformDelta.height(), filteredVelocity); 329 scrollingWasHandled = boxLayer->handleWheelEvent(copiedEvent); 330 } else 330 331 scrollingWasHandled = didScrollInScrollableArea(boxLayer, wheelEvent); 331 332 … … 2758 2759 2759 2760 FloatSize filteredPlatformDelta(wheelEvent.deltaX(), wheelEvent.deltaY()); 2761 FloatPoint filteredVelocity; 2760 2762 if (const PlatformWheelEvent* platformWheelEvent = wheelEvent.wheelEvent()) { 2761 2763 filteredPlatformDelta.setWidth(platformWheelEvent->deltaX()); … … 2767 2769 Element* stopElement = latchedState ? latchedState->previousWheelScrolledElement() : nullptr; 2768 2770 2769 if (m_frame.mainFrame().wheelEventDeltaFilter()->isFilteringDeltas()) 2771 if (m_frame.mainFrame().wheelEventDeltaFilter()->isFilteringDeltas()) { 2770 2772 filteredPlatformDelta = m_frame.mainFrame().wheelEventDeltaFilter()->filteredDelta(); 2773 filteredVelocity = m_frame.mainFrame().wheelEventDeltaFilter()->filteredVelocity(); 2774 } 2771 2775 #else 2772 2776 Element* stopElement = nullptr; … … 2774 2778 2775 2779 2776 if (handleWheelEventInAppropriateEnclosingBox(startNode, wheelEvent, &stopElement, filteredPlatformDelta ))2780 if (handleWheelEventInAppropriateEnclosingBox(startNode, wheelEvent, &stopElement, filteredPlatformDelta, filteredVelocity)) 2777 2781 wheelEvent.setDefaultHandled(); 2778 2782 -
trunk/Source/WebCore/page/Page.cpp
r208985 r209070 1994 1994 WheelEventTestTrigger& Page::ensureTestTrigger() 1995 1995 { 1996 if (!m_testTrigger) 1996 if (!m_testTrigger) { 1997 1997 m_testTrigger = adoptRef(new WheelEventTestTrigger()); 1998 if (auto* frameView = mainFrame().view()) 1999 frameView->layout(); 2000 } 1998 2001 1999 2002 return *m_testTrigger; -
trunk/Source/WebCore/page/WheelEventDeltaFilter.cpp
r208662 r209070 27 27 #include "WheelEventDeltaFilter.h" 28 28 29 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 10110029 #if HAVE(NSSCROLLING_FILTERS) 30 30 #include "WheelEventDeltaFilterMac.h" 31 31 #endif … … 47 47 std::unique_ptr<WheelEventDeltaFilter> WheelEventDeltaFilter::create() 48 48 { 49 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 10110049 #if HAVE(NSSCROLLING_FILTERS) 50 50 return std::make_unique<WheelEventDeltaFilterMac>(); 51 51 #else … … 62 62 { 63 63 return m_currentFilteredDelta; 64 } 65 66 FloatPoint WheelEventDeltaFilter::filteredVelocity() const 67 { 68 return m_currentFilteredVelocity; 64 69 } 65 70 -
trunk/Source/WebCore/page/WheelEventDeltaFilter.h
r208179 r209070 26 26 #pragma once 27 27 28 #include "FloatPoint.h" 28 29 #include "FloatSize.h" 29 30 #include <wtf/Deque.h> … … 40 41 WEBCORE_EXPORT virtual void beginFilteringDeltas() = 0; 41 42 WEBCORE_EXPORT virtual void endFilteringDeltas() = 0; 43 WEBCORE_EXPORT FloatPoint filteredVelocity() const; 42 44 WEBCORE_EXPORT bool isFilteringDeltas() const; 43 45 WEBCORE_EXPORT FloatSize filteredDelta() const; … … 45 47 protected: 46 48 FloatSize m_currentFilteredDelta; 49 FloatPoint m_currentFilteredVelocity; 47 50 bool m_isFilteringDeltas { false }; 48 51 }; -
trunk/Source/WebCore/page/mac/WheelEventDeltaFilterMac.mm
r191473 r209070 26 26 #include "config.h" 27 27 28 #if PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 10110028 #if HAVE(NSSCROLLING_FILTERS) 29 29 30 30 #include "WheelEventDeltaFilterMac.h" … … 56 56 NSPoint filteredVelocityResult; 57 57 [m_predominantAxisFilter filterInputDelta:NSPoint(FloatPoint(delta.width(), delta.height())) timestamp:monotonicallyIncreasingTime() - m_beginFilteringDeltasTime outputDelta:&filteredDeltaResult velocity:&filteredVelocityResult]; 58 m_currentFilteredVelocity = FloatPoint(filteredVelocityResult); 58 59 m_currentFilteredDelta = FloatSize(filteredDeltaResult.x, filteredDeltaResult.y); 59 60 } … … 69 70 } 70 71 71 #endif /* PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100*/72 #endif /* HAVE(NSSCROLLING_FILTERS) */ -
trunk/Source/WebCore/page/scrolling/mac/ScrollingMomentumCalculatorMac.h
r209069 r209070 1 1 /* 2 * Copyright (C) 201 5Apple Inc. All rights reserved.2 * Copyright (C) 2016 Apple Inc. All rights reserved. 3 3 * 4 4 * Redistribution and use in source and binary forms, with or without … … 26 26 #pragma once 27 27 28 #include "FloatSize.h" 29 #include <wtf/Deque.h> 28 #include "ScrollingMomentumCalculator.h" 29 #include <wtf/RetainPtr.h> 30 31 #if HAVE(NSSCROLLING_FILTERS) 32 33 @class _NSScrollingMomentumCalculator; 30 34 31 35 namespace WebCore { 32 36 33 class WheelEventDeltaFilter {37 class ScrollingMomentumCalculatorMac final : public ScrollingMomentumCalculator { 34 38 public: 35 WheelEventDeltaFilter(); 36 virtual ~WheelEventDeltaFilter(); 37 38 WEBCORE_EXPORT static std::unique_ptr<WheelEventDeltaFilter> create(); 39 WEBCORE_EXPORT virtual void updateFromDelta(const FloatSize&) = 0; 40 WEBCORE_EXPORT virtual void beginFilteringDeltas() = 0; 41 WEBCORE_EXPORT virtual void endFilteringDeltas() = 0; 42 WEBCORE_EXPORT bool isFilteringDeltas() const; 43 WEBCORE_EXPORT FloatSize filteredDelta() const; 44 45 protected: 46 FloatSize m_currentFilteredDelta; 47 bool m_isFilteringDeltas { false }; 48 }; 49 50 enum class DominantScrollGestureDirection { 51 None, 52 Vertical, 53 Horizontal 54 }; 55 56 class BasicWheelEventDeltaFilter final : public WheelEventDeltaFilter { 57 public: 58 BasicWheelEventDeltaFilter(); 59 void updateFromDelta(const FloatSize&) override; 60 void beginFilteringDeltas() override; 61 void endFilteringDeltas() override; 39 ScrollingMomentumCalculatorMac(const FloatSize& viewportSize, const FloatSize& contentSize, const FloatPoint& initialOffset, const FloatPoint& targetOffset, const FloatSize& initialDelta, const FloatPoint& initialVelocity); 62 40 63 41 private: 64 DominantScrollGestureDirection dominantScrollGestureDirection() const; 42 FloatPoint scrollOffsetAfterElapsedTime(double time) final; 43 double animationDuration() final; 44 _NSScrollingMomentumCalculator *ensurePlatformMomentumCalculator(); 65 45 66 Deque<FloatSize> m_recentWheelEventDeltas;46 RetainPtr<_NSScrollingMomentumCalculator> m_platformMomentumCalculator; 67 47 }; 68 48 69 49 } // namespace WebCore 50 51 #endif // HAVE(NSSCROLLING_FILTERS) -
trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.h
r208503 r209070 85 85 86 86 #if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC) 87 LayoutUnit scrollOffsetOnAxis(ScrollEventAxis) const override;87 FloatPoint scrollOffset() const override; 88 88 void immediateScrollOnAxis(ScrollEventAxis, float delta) override; 89 89 float pageScaleFactor() const override; … … 91 91 void stopScrollSnapTimer() override; 92 92 LayoutSize scrollExtent() const override; 93 FloatSize viewportSize() const override; 93 94 #endif 94 95 -
trunk/Source/WebCore/page/scrolling/mac/ScrollingTreeFrameScrollingNodeMac.mm
r208985 r209070 582 582 583 583 #if ENABLE(CSS_SCROLL_SNAP) 584 LayoutUnit ScrollingTreeFrameScrollingNodeMac::scrollOffsetOnAxis(ScrollEventAxis axis) const 585 { 586 const FloatPoint& currentPosition = scrollPosition(); 587 return axis == ScrollEventAxis::Horizontal ? currentPosition.x() : currentPosition.y(); 584 FloatPoint ScrollingTreeFrameScrollingNodeMac::scrollOffset() const 585 { 586 return scrollPosition(); 588 587 } 589 588 … … 619 618 return LayoutSize(totalContentsSize()); 620 619 } 620 621 FloatSize ScrollingTreeFrameScrollingNodeMac::viewportSize() const 622 { 623 return scrollableAreaSize(); 624 } 625 621 626 #endif 622 627 -
trunk/Source/WebCore/platform/PlatformWheelEvent.h
r198805 r209070 27 27 #define PlatformWheelEvent_h 28 28 29 #include "FloatPoint.h" 29 30 #include "IntPoint.h" 30 31 #include "PlatformEvent.h" … … 120 121 } 121 122 122 PlatformWheelEvent copyWithDeltas (float deltaX, float deltaY) const123 PlatformWheelEvent copyWithDeltasAndVelocity(float deltaX, float deltaY, FloatPoint velocity) const 123 124 { 124 125 PlatformWheelEvent copy = *this; 125 126 copy.m_deltaX = deltaX; 126 127 copy.m_deltaY = deltaY; 128 copy.m_scrollingVelocity = velocity; 127 129 return copy; 128 130 } … … 167 169 #endif 168 170 171 FloatPoint scrollingVelocity() const { return m_scrollingVelocity; } 172 169 173 #if PLATFORM(WIN) 170 174 PlatformWheelEvent(HWND, WPARAM, LPARAM, bool isMouseHWheel); … … 181 185 PlatformWheelEventGranularity m_granularity; 182 186 bool m_directionInvertedFromDevice; 187 FloatPoint m_scrollingVelocity; 183 188 #if PLATFORM(COCOA) 184 189 bool m_hasPreciseScrollingDeltas; -
trunk/Source/WebCore/platform/ScrollAnimator.cpp
r195661 r209070 202 202 } 203 203 204 LayoutUnit ScrollAnimator::scrollOffsetOnAxis(ScrollEventAxis axis) const205 { 206 return axis == ScrollEventAxis::Horizontal ? m_currentPosition.x() : m_currentPosition.y();204 FloatPoint ScrollAnimator::scrollOffset() const 205 { 206 return m_currentPosition; 207 207 } 208 208 … … 222 222 return m_scrollableArea.contentsSize(); 223 223 } 224 225 FloatSize ScrollAnimator::viewportSize() const 226 { 227 return m_scrollableArea.visibleSize(); 228 } 229 224 230 #endif 225 231 -
trunk/Source/WebCore/platform/ScrollAnimator.h
r195810 r209070 135 135 #endif 136 136 void updateScrollSnapState(); 137 LayoutUnit scrollOffsetOnAxis(ScrollEventAxis) const override;137 FloatPoint scrollOffset() const override; 138 138 void immediateScrollOnAxis(ScrollEventAxis, float delta) override; 139 139 bool activeScrollSnapIndexDidChange() const; 140 140 unsigned activeScrollSnapIndexForAxis(ScrollEventAxis) const; 141 141 LayoutSize scrollExtent() const override; 142 FloatSize viewportSize() const override; 142 143 #endif 143 144 -
trunk/Source/WebCore/platform/cocoa/ScrollController.h
r202611 r209070 82 82 83 83 #if ENABLE(CSS_SCROLL_SNAP) 84 virtual LayoutUnit scrollOffsetOnAxis(ScrollEventAxis) const = 0;84 virtual FloatPoint scrollOffset() const = 0; 85 85 virtual void immediateScrollOnAxis(ScrollEventAxis, float delta) = 0; 86 86 virtual void startScrollSnapTimer() … … 105 105 106 106 virtual LayoutSize scrollExtent() const = 0; 107 #endif 107 virtual FloatSize viewportSize() const = 0; 108 #endif 109 }; 110 111 enum class WheelEventStatus { 112 UserScrollBegin, 113 UserScrolling, 114 UserScrollEnd, 115 InertialScrollBegin, 116 InertialScrolling, 117 InertialScrollEnd, 118 StatelessScrollEvent, 119 Unknown 108 120 }; 109 121 … … 145 157 146 158 #if ENABLE(CSS_SCROLL_SNAP) 147 LayoutUnit scrollOffsetOnAxis(ScrollEventAxis) const;148 159 void setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis, int); 149 ScrollSnapAnimatorState& scrollSnapPointState(ScrollEventAxis);150 const ScrollSnapAnimatorState& scrollSnapPointState(ScrollEventAxis) const;151 160 #if PLATFORM(MAC) 152 161 void scrollSnapTimerFired(); … … 154 163 void stopScrollSnapTimer(); 155 164 156 void processWheelEventForScrollSnapOnAxis(ScrollEventAxis, const PlatformWheelEvent&); 157 bool shouldOverrideWheelEvent(ScrollEventAxis, const PlatformWheelEvent&) const; 158 159 void beginScrollSnapAnimation(ScrollEventAxis, ScrollSnapState); 160 161 void endScrollSnapAnimation(ScrollSnapState); 162 void initializeScrollSnapAnimationParameters(); 163 bool isSnappingOnAxis(ScrollEventAxis) const; 164 165 bool shouldOverrideInertialScrolling() const; 166 void statelessSnapTransitionTimerFired(); 167 void startDeferringTestsDueToScrollSnapping(); 168 void stopDeferringTestsDueToScrollSnapping(); 169 void scheduleStatelessScrollSnap(); 165 170 #endif 166 171 #endif 167 172 168 173 ScrollControllerClient& m_client; 169 174 175 #if PLATFORM(MAC) 170 176 CFTimeInterval m_lastMomentumScrollTimestamp { 0 }; 177 #endif 171 178 FloatSize m_overflowScrollDelta; 172 179 FloatSize m_stretchScrollForce; … … 182 189 183 190 #if ENABLE(CSS_SCROLL_SNAP) 184 bool m_expectingHorizontalStatelessScrollSnap { false }; 185 bool m_expectingVerticalStatelessScrollSnap { false }; 186 std::unique_ptr<ScrollSnapAnimatorState> m_horizontalScrollSnapState; 187 std::unique_ptr<ScrollSnapAnimatorState> m_verticalScrollSnapState; 188 std::unique_ptr<ScrollSnapAnimationCurveState> m_scrollSnapCurveState; 189 #if PLATFORM(MAC) 191 std::unique_ptr<ScrollSnapAnimatorState> m_scrollSnapState; 192 #if PLATFORM(MAC) 193 FloatPoint m_dragEndedScrollingVelocity; 194 RunLoop::Timer<ScrollController> m_statelessSnapTransitionTimer; 190 195 RunLoop::Timer<ScrollController> m_scrollSnapTimer; 191 196 #endif 192 197 #endif 193 198 199 #if PLATFORM(MAC) 194 200 bool m_inScrollGesture { false }; 195 201 bool m_momentumScrollInProgress { false }; 196 202 bool m_ignoreMomentumScrolls { false }; 197 203 bool m_snapRubberbandTimerIsActive { false }; 204 #endif 205 198 206 bool m_activeScrollSnapIndexDidChange { false }; 199 207 }; -
trunk/Source/WebCore/platform/cocoa/ScrollController.mm
r202611 r209070 75 75 #endif 76 76 77 #if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC)78 static const float inertialScrollPredictionFactor = 16.7;79 static const double statelessScrollSnapDelay = 0.5;80 #endif81 82 77 #if PLATFORM(MAC) 83 enum class WheelEventStatus {84 UserScrollBegin,85 UserScrolling,86 UserScrollEnd,87 InertialScrollBegin,88 InertialScrolling,89 InertialScrollEnd,90 StatelessScrollEvent,91 Unknown92 };93 94 78 static float elasticDeltaForTimeDelta(float initialPosition, float initialVelocity, float elapsedTime) 95 79 { … … 117 101 return multiplier; 118 102 } 103 104 static ScrollEventAxis otherScrollEventAxis(ScrollEventAxis axis) 105 { 106 return axis == ScrollEventAxis::Horizontal ? ScrollEventAxis::Vertical : ScrollEventAxis::Horizontal; 107 } 119 108 #endif 120 109 … … 125 114 #endif 126 115 #if ENABLE(CSS_SCROLL_SNAP) && PLATFORM(MAC) 116 , m_statelessSnapTransitionTimer(RunLoop::current(), this, &ScrollController::statelessSnapTransitionTimerFired) 127 117 , m_scrollSnapTimer(RunLoop::current(), this, &ScrollController::scrollSnapTimerFired) 128 118 #endif … … 467 457 468 458 #if ENABLE(CSS_SCROLL_SNAP) 469 ScrollSnapAnimatorState& ScrollController::scrollSnapPointState(ScrollEventAxis axis)470 {471 ASSERT(axis != ScrollEventAxis::Horizontal || m_horizontalScrollSnapState);472 ASSERT(axis != ScrollEventAxis::Vertical || m_verticalScrollSnapState);473 474 return (axis == ScrollEventAxis::Horizontal) ? *m_horizontalScrollSnapState : *m_verticalScrollSnapState;475 }476 477 const ScrollSnapAnimatorState& ScrollController::scrollSnapPointState(ScrollEventAxis axis) const478 {479 ASSERT(axis != ScrollEventAxis::Horizontal || m_horizontalScrollSnapState);480 ASSERT(axis != ScrollEventAxis::Vertical || m_verticalScrollSnapState);481 482 return (axis == ScrollEventAxis::Horizontal) ? *m_horizontalScrollSnapState : *m_verticalScrollSnapState;483 }484 459 485 460 #if PLATFORM(MAC) … … 524 499 } 525 500 526 void ScrollController::processWheelEventForScrollSnapOnAxis(ScrollEventAxis axis, const PlatformWheelEvent& event) 527 { 528 ScrollSnapAnimatorState& snapState = scrollSnapPointState(axis); 529 530 float wheelDelta = axis == ScrollEventAxis::Horizontal ? -event.deltaX() : -event.deltaY(); 531 WheelEventStatus wheelStatus = toWheelEventStatus(event.phase(), event.momentumPhase()); 532 533 switch (wheelStatus) { 501 bool ScrollController::shouldOverrideInertialScrolling() const 502 { 503 if (!m_scrollSnapState) 504 return false; 505 506 ScrollSnapState scrollSnapState = m_scrollSnapState->currentState(); 507 return scrollSnapState == ScrollSnapState::Gliding || scrollSnapState == ScrollSnapState::DestinationReached; 508 } 509 510 void ScrollController::scheduleStatelessScrollSnap() 511 { 512 stopScrollSnapTimer(); 513 m_statelessSnapTransitionTimer.stop(); 514 if (!m_scrollSnapState) 515 return; 516 517 static const double statelessScrollSnapDelay = 0.75; 518 m_statelessSnapTransitionTimer.startOneShot(statelessScrollSnapDelay); 519 startDeferringTestsDueToScrollSnapping(); 520 } 521 522 void ScrollController::statelessSnapTransitionTimerFired() 523 { 524 if (!m_scrollSnapState) 525 return; 526 527 m_scrollSnapState->transitionToSnapAnimationState(m_client.scrollExtent(), m_client.viewportSize(), m_client.pageScaleFactor(), m_client.scrollOffset()); 528 startScrollSnapTimer(); 529 } 530 531 void ScrollController::startDeferringTestsDueToScrollSnapping() 532 { 533 m_client.deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress); 534 } 535 536 void ScrollController::stopDeferringTestsDueToScrollSnapping() 537 { 538 m_client.removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress); 539 } 540 541 bool ScrollController::processWheelEventForScrollSnap(const PlatformWheelEvent& wheelEvent) 542 { 543 if (!m_scrollSnapState) 544 return true; 545 546 if (m_scrollSnapState->snapOffsetsForAxis(ScrollEventAxis::Horizontal).isEmpty() && m_scrollSnapState->snapOffsetsForAxis(ScrollEventAxis::Vertical).isEmpty()) 547 return true; 548 549 WheelEventStatus status = toWheelEventStatus(wheelEvent.phase(), wheelEvent.momentumPhase()); 550 bool isInertialScrolling = false; 551 switch (status) { 534 552 case WheelEventStatus::UserScrollBegin: 535 553 case WheelEventStatus::UserScrolling: 536 endScrollSnapAnimation(ScrollSnapState::UserInteraction); 554 stopScrollSnapTimer(); 555 m_scrollSnapState->transitionToUserInteractionState(); 537 556 break; 538 539 557 case WheelEventStatus::UserScrollEnd: 540 beginScrollSnapAnimation(axis, ScrollSnapState::Snapping); 558 m_dragEndedScrollingVelocity = -wheelEvent.scrollingVelocity(); 559 m_scrollSnapState->transitionToSnapAnimationState(m_client.scrollExtent(), m_client.viewportSize(), m_client.pageScaleFactor(), m_client.scrollOffset()); 560 startScrollSnapTimer(); 541 561 break; 542 543 562 case WheelEventStatus::InertialScrollBegin: 544 // Begin tracking wheel deltas for glide prediction. 545 endScrollSnapAnimation(ScrollSnapState::UserInteraction); 546 snapState.pushInitialWheelDelta(wheelDelta); 547 snapState.m_beginTrackingWheelDeltaOffset = m_client.scrollOffsetOnAxis(axis); 563 m_scrollSnapState->transitionToGlideAnimationState(m_client.scrollExtent(), m_client.viewportSize(), m_client.pageScaleFactor(), m_client.scrollOffset(), m_dragEndedScrollingVelocity, FloatSize(-wheelEvent.deltaX(), -wheelEvent.deltaY())); 564 isInertialScrolling = true; 548 565 break; 549 550 566 case WheelEventStatus::InertialScrolling: 551 // This check for DestinationReached ensures that we don't receive another set of momentum events after ending the last glide. 552 if (snapState.m_currentState != ScrollSnapState::Gliding && snapState.m_currentState != ScrollSnapState::DestinationReached) { 553 if (snapState.wheelDeltaTrackingIsInProgress() && wheelDelta) 554 snapState.pushInitialWheelDelta(wheelDelta); 555 556 if (snapState.hasFinishedTrackingWheelDeltas() && snapState.averageInitialWheelDelta()) 557 beginScrollSnapAnimation(axis, ScrollSnapState::Gliding); 558 } 567 case WheelEventStatus::InertialScrollEnd: 568 isInertialScrolling = true; 559 569 break; 560 561 case WheelEventStatus::InertialScrollEnd: 562 if (snapState.wheelDeltaTrackingIsInProgress() && snapState.averageInitialWheelDelta()) 563 beginScrollSnapAnimation(axis, ScrollSnapState::Gliding); 564 565 snapState.clearInitialWheelDeltaWindow(); 566 snapState.m_shouldOverrideWheelEvent = false; 570 case WheelEventStatus::StatelessScrollEvent: 571 m_scrollSnapState->transitionToUserInteractionState(); 572 scheduleStatelessScrollSnap(); 567 573 break; 568 569 case WheelEventStatus::StatelessScrollEvent:570 endScrollSnapAnimation(ScrollSnapState::UserInteraction);571 snapState.clearInitialWheelDeltaWindow();572 snapState.m_shouldOverrideWheelEvent = false;573 m_scrollSnapTimer.startOneShot(statelessScrollSnapDelay);574 if (axis == ScrollEventAxis::Horizontal)575 m_expectingHorizontalStatelessScrollSnap = true;576 else577 m_expectingVerticalStatelessScrollSnap = true;578 break;579 580 574 case WheelEventStatus::Unknown: 581 575 ASSERT_NOT_REACHED(); 582 576 break; 583 577 } 584 } 585 586 bool ScrollController::shouldOverrideWheelEvent(ScrollEventAxis axis, const PlatformWheelEvent& event) const 587 { 588 const ScrollSnapAnimatorState& snapState = scrollSnapPointState(axis); 589 590 return snapState.m_shouldOverrideWheelEvent && toWheelEventStatus(event.phase(), event.momentumPhase()) == WheelEventStatus::InertialScrolling; 591 } 592 593 bool ScrollController::processWheelEventForScrollSnap(const PlatformWheelEvent& wheelEvent) 594 { 595 bool shouldAllowWheelEventToPropagate = true; 596 if (m_verticalScrollSnapState) { 597 processWheelEventForScrollSnapOnAxis(ScrollEventAxis::Vertical, wheelEvent); 598 shouldAllowWheelEventToPropagate &= !shouldOverrideWheelEvent(ScrollEventAxis::Vertical, wheelEvent); 599 } 600 if (m_horizontalScrollSnapState) { 601 processWheelEventForScrollSnapOnAxis(ScrollEventAxis::Horizontal, wheelEvent); 602 shouldAllowWheelEventToPropagate &= !shouldOverrideWheelEvent(ScrollEventAxis::Horizontal, wheelEvent); 603 } 604 return shouldAllowWheelEventToPropagate; 605 } 606 #endif 578 579 return !(isInertialScrolling && shouldOverrideInertialScrolling()); 580 } 607 581 608 582 void ScrollController::updateScrollSnapState(const ScrollableArea& scrollableArea) 609 583 { 610 // FIXME: Currently, scroll snap animators are recreated even though the snap offsets alone can be updated. 611 if (scrollableArea.horizontalSnapOffsets()) 612 m_horizontalScrollSnapState = std::make_unique<ScrollSnapAnimatorState>(ScrollEventAxis::Horizontal, *scrollableArea.horizontalSnapOffsets()); 613 else if (m_horizontalScrollSnapState) 614 m_horizontalScrollSnapState = nullptr; 615 616 if (scrollableArea.verticalSnapOffsets()) 617 m_verticalScrollSnapState = std::make_unique<ScrollSnapAnimatorState>(ScrollEventAxis::Vertical, *scrollableArea.verticalSnapOffsets()); 618 else if (m_verticalScrollSnapState) 619 m_verticalScrollSnapState = nullptr; 584 if (auto* snapOffsets = scrollableArea.horizontalSnapOffsets()) 585 updateScrollSnapPoints(ScrollEventAxis::Horizontal, *snapOffsets); 586 587 if (auto* snapOffsets = scrollableArea.verticalSnapOffsets()) 588 updateScrollSnapPoints(ScrollEventAxis::Vertical, *snapOffsets); 620 589 } 621 590 622 591 void ScrollController::updateScrollSnapPoints(ScrollEventAxis axis, const Vector<LayoutUnit>& snapPoints) 623 592 { 624 // FIXME: Currently, scroll snap animators are recreated even though the snap offsets alone can be updated. 625 if (axis == ScrollEventAxis::Horizontal) 626 m_horizontalScrollSnapState = !snapPoints.isEmpty() ? std::make_unique<ScrollSnapAnimatorState>(ScrollEventAxis::Horizontal, snapPoints) : nullptr; 627 628 if (axis == ScrollEventAxis::Vertical) 629 m_verticalScrollSnapState = !snapPoints.isEmpty() ? std::make_unique<ScrollSnapAnimatorState>(ScrollEventAxis::Vertical, snapPoints) : nullptr; 630 } 631 632 #if PLATFORM(MAC) 593 if (!m_scrollSnapState) { 594 if (snapPoints.isEmpty()) 595 return; 596 597 m_scrollSnapState = std::make_unique<ScrollSnapAnimatorState>(); 598 } 599 600 if (snapPoints.isEmpty() && m_scrollSnapState->snapOffsetsForAxis(otherScrollEventAxis(axis)).isEmpty()) 601 m_scrollSnapState = nullptr; 602 else 603 m_scrollSnapState->setSnapOffsetsForAxis(axis, snapPoints); 604 } 605 633 606 void ScrollController::startScrollSnapTimer() 634 607 { 635 if (!m_scrollSnapTimer.isActive()) { 636 m_client.startScrollSnapTimer(); 637 m_scrollSnapTimer.startRepeating(1.0 / 60.0); 638 } 639 608 if (m_scrollSnapTimer.isActive()) 609 return; 610 611 startDeferringTestsDueToScrollSnapping(); 612 m_client.startScrollSnapTimer(); 613 m_scrollSnapTimer.startRepeating(1.0 / 60.0); 614 } 615 616 void ScrollController::stopScrollSnapTimer() 617 { 640 618 if (!m_scrollSnapTimer.isActive()) 641 619 return; 642 620 643 m_client.deferTestsForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress); 644 } 645 646 void ScrollController::stopScrollSnapTimer() 647 { 621 stopDeferringTestsDueToScrollSnapping(); 648 622 m_client.stopScrollSnapTimer(); 649 623 m_scrollSnapTimer.stop(); 650 651 if (m_scrollSnapTimer.isActive())652 return;653 654 m_client.removeTestDeferralForReason(reinterpret_cast<WheelEventTestTrigger::ScrollableAreaIdentifier>(this), WheelEventTestTrigger::ScrollSnapInProgress);655 624 } 656 625 657 626 void ScrollController::scrollSnapTimerFired() 658 627 { 659 if (m_expectingHorizontalStatelessScrollSnap || m_expectingVerticalStatelessScrollSnap) { 660 if (m_expectingHorizontalStatelessScrollSnap) 661 beginScrollSnapAnimation(ScrollEventAxis::Horizontal, ScrollSnapState::Snapping); 662 if (m_expectingVerticalStatelessScrollSnap) 663 beginScrollSnapAnimation(ScrollEventAxis::Vertical, ScrollSnapState::Snapping); 664 return; 665 } 666 667 bool snapOnHorizontalAxis = isSnappingOnAxis(ScrollEventAxis::Horizontal); 668 bool snapOnVerticalAxis = isSnappingOnAxis(ScrollEventAxis::Vertical); 669 if (snapOnHorizontalAxis && !m_horizontalScrollSnapState->canReachTargetWithCurrentInitialScrollDelta()) { 670 m_horizontalScrollSnapState->m_currentState = ScrollSnapState::DestinationReached; 671 snapOnHorizontalAxis = false; 672 } 673 if (snapOnVerticalAxis && !m_verticalScrollSnapState->canReachTargetWithCurrentInitialScrollDelta()) { 674 m_verticalScrollSnapState->m_currentState = ScrollSnapState::DestinationReached; 675 snapOnVerticalAxis = false; 676 } 677 if (!snapOnHorizontalAxis && !snapOnVerticalAxis) { 678 endScrollSnapAnimation(ScrollSnapState::DestinationReached); 679 return; 680 } 681 682 double currentTime = monotonicallyIncreasingTime(); 683 if (m_scrollSnapCurveState->shouldCompleteSnapAnimationImmediatelyAtTime(currentTime)) { 684 float finalHorizontalDelta = 0; 685 float finalVerticalDelta = 0; 686 if (snapOnHorizontalAxis) 687 finalHorizontalDelta = m_horizontalScrollSnapState->m_targetOffset - m_client.scrollOffsetOnAxis(ScrollEventAxis::Horizontal); 688 if (snapOnVerticalAxis) 689 finalVerticalDelta = m_verticalScrollSnapState->m_targetOffset - m_client.scrollOffsetOnAxis(ScrollEventAxis::Vertical); 690 691 if (finalHorizontalDelta || finalVerticalDelta) 692 m_client.immediateScrollBy(FloatSize(finalHorizontalDelta, finalVerticalDelta)); 693 694 endScrollSnapAnimation(ScrollSnapState::DestinationReached); 695 return; 696 } 697 698 float animationProgress = m_scrollSnapCurveState->animationProgressAtTime(currentTime); 699 float horizontalDelta = 0; 700 float verticalDelta = 0; 701 if (m_scrollSnapCurveState->shouldAnimateDirectlyToSnapPoint) { 702 if (snapOnHorizontalAxis) 703 horizontalDelta = m_horizontalScrollSnapState->interpolatedOffsetAtProgress(animationProgress) - m_client.scrollOffsetOnAxis(ScrollEventAxis::Horizontal); 704 if (snapOnVerticalAxis) 705 verticalDelta = m_verticalScrollSnapState->interpolatedOffsetAtProgress(animationProgress) - m_client.scrollOffsetOnAxis(ScrollEventAxis::Vertical); 706 707 } else { 708 FloatPoint interpolatedPoint = m_scrollSnapCurveState->interpolatedPositionAtProgress(animationProgress); 709 horizontalDelta = interpolatedPoint.x() - m_client.scrollOffsetOnAxis(ScrollEventAxis::Horizontal); 710 verticalDelta = interpolatedPoint.y() - m_client.scrollOffsetOnAxis(ScrollEventAxis::Vertical); 711 } 712 713 if (horizontalDelta || verticalDelta) 714 m_client.immediateScrollBy(FloatSize(horizontalDelta, verticalDelta)); 715 } 716 717 static inline float projectedInertialScrollDistance(float initialWheelDelta) 718 { 719 // FIXME: Experiments with inertial scrolling show a fairly consistent linear relationship between initial wheel delta and total distance scrolled. 720 // In the future, we'll want to find a more accurate way of inertial scroll prediction. 721 return inertialScrollPredictionFactor * initialWheelDelta; 722 } 723 #endif 628 if (!m_scrollSnapState) { 629 ASSERT_NOT_REACHED(); 630 return; 631 } 632 633 bool isAnimationComplete; 634 auto animationOffset = m_scrollSnapState->currentAnimatedScrollOffset(isAnimationComplete); 635 auto currentOffset = m_client.scrollOffset(); 636 m_client.immediateScrollByWithoutContentEdgeConstraints(FloatSize(animationOffset.x() - currentOffset.x(), animationOffset.y() - currentOffset.y())); 637 if (isAnimationComplete) { 638 m_scrollSnapState->transitionToDestinationReachedState(); 639 stopScrollSnapTimer(); 640 } 641 } 642 #else 643 void ScrollController::updateScrollSnapState(const ScrollableArea&) 644 { 645 } 646 #endif // PLATFORM(MAC) 724 647 725 648 unsigned ScrollController::activeScrollSnapIndexForAxis(ScrollEventAxis axis) const 726 649 { 727 if ( (axis == ScrollEventAxis::Horizontal) && !m_horizontalScrollSnapState)650 if (!m_scrollSnapState) 728 651 return 0; 729 if ((axis == ScrollEventAxis::Vertical) && !m_verticalScrollSnapState) 730 return 0; 731 732 const ScrollSnapAnimatorState& snapState = scrollSnapPointState(axis); 733 return snapState.m_activeSnapIndex; 652 653 return m_scrollSnapState->activeSnapIndexForAxis(axis); 734 654 } 735 655 736 656 void ScrollController::setActiveScrollSnapIndexForAxis(ScrollEventAxis axis, unsigned index) 737 657 { 738 auto* snapState = (axis == ScrollEventAxis::Horizontal) ? m_horizontalScrollSnapState.get() : m_verticalScrollSnapState.get(); 739 if (!snapState) 740 return; 741 742 snapState->m_activeSnapIndex = index; 658 if (!m_scrollSnapState) 659 return; 660 661 m_scrollSnapState->setActiveSnapIndexForAxis(axis, index); 743 662 } 744 663 745 664 void ScrollController::setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis axis, int offset) 746 665 { 666 if (!m_scrollSnapState) 667 return; 668 747 669 float scaleFactor = m_client.pageScaleFactor(); 748 ScrollSnapAnimatorState& snapState = scrollSnapPointState(axis); 749 750 LayoutUnit clampedOffset = std::min(std::max(LayoutUnit(offset / scaleFactor), snapState.m_snapOffsets.first()), snapState.m_snapOffsets.last()); 670 ScrollSnapAnimatorState& snapState = *m_scrollSnapState; 671 672 auto snapOffsets = snapState.snapOffsetsForAxis(axis); 673 if (!snapOffsets.size()) 674 return; 675 676 LayoutUnit clampedOffset = std::min(std::max(LayoutUnit(offset / scaleFactor), snapOffsets.first()), snapOffsets.last()); 751 677 752 678 unsigned activeIndex = 0; 753 (void)closestSnapOffset<LayoutUnit, float>(snapState.m_snapOffsets, clampedOffset, 0, activeIndex);754 755 if (activeIndex == snapState.m_activeSnapIndex)679 closestSnapOffset<LayoutUnit, float>(snapState.snapOffsetsForAxis(axis), clampedOffset, 0, activeIndex); 680 681 if (activeIndex == activeScrollSnapIndexForAxis(axis)) 756 682 return; 757 683 758 684 m_activeScrollSnapIndexDidChange = true; 759 s napState.m_activeSnapIndex = activeIndex;685 setActiveScrollSnapIndexForAxis(axis, activeIndex); 760 686 } 761 687 762 688 void ScrollController::setActiveScrollSnapIndicesForOffset(int x, int y) 763 689 { 764 if (m_horizontalScrollSnapState) 765 setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis::Horizontal, x); 766 if (m_verticalScrollSnapState) 767 setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis::Vertical, y); 768 } 769 770 #if PLATFORM(MAC) 771 void ScrollController::beginScrollSnapAnimation(ScrollEventAxis axis, ScrollSnapState newState) 772 { 773 ASSERT(newState == ScrollSnapState::Gliding || newState == ScrollSnapState::Snapping); 774 if (m_expectingHorizontalStatelessScrollSnap || m_expectingVerticalStatelessScrollSnap) { 775 m_expectingHorizontalStatelessScrollSnap = false; 776 m_expectingVerticalStatelessScrollSnap = false; 777 stopScrollSnapTimer(); 778 } 779 ScrollSnapAnimatorState& snapState = scrollSnapPointState(axis); 780 781 LayoutUnit offset = m_client.scrollOffsetOnAxis(axis); 782 float initialWheelDelta = newState == ScrollSnapState::Gliding ? snapState.averageInitialWheelDelta() : 0; 783 LayoutUnit scaledProjectedScrollDestination = newState == ScrollSnapState::Gliding ? snapState.m_beginTrackingWheelDeltaOffset + LayoutUnit(projectedInertialScrollDistance(initialWheelDelta)) : offset; 784 if (snapState.m_snapOffsets.isEmpty()) 785 return; 786 787 float scaleFactor = m_client.pageScaleFactor(); 788 LayoutUnit originalProjectedScrollDestination = scaledProjectedScrollDestination / scaleFactor; 789 790 LayoutUnit clampedScrollDestination = std::min(std::max(originalProjectedScrollDestination, snapState.m_snapOffsets.first()), snapState.m_snapOffsets.last()); 791 snapState.m_initialOffset = offset; 792 m_activeScrollSnapIndexDidChange = false; 793 snapState.m_targetOffset = scaleFactor * closestSnapOffset<LayoutUnit, float>(snapState.m_snapOffsets, clampedScrollDestination, initialWheelDelta, snapState.m_activeSnapIndex); 794 if (snapState.m_initialOffset == snapState.m_targetOffset) 795 return; 796 797 LayoutUnit scrollExtent = (axis == ScrollEventAxis::Horizontal) ? m_client.scrollExtent().width() : m_client.scrollExtent().height(); 798 LayoutUnit projectedScrollDestination = clampedScrollDestination; 799 if (originalProjectedScrollDestination < 0 || originalProjectedScrollDestination > scrollExtent) 800 projectedScrollDestination = originalProjectedScrollDestination; 801 802 m_activeScrollSnapIndexDidChange = true; 803 snapState.m_currentState = newState; 804 if (newState == ScrollSnapState::Gliding) { 805 // Check if the other scroll axis needs to animate to the nearest snap point. 806 snapState.m_initialScrollDelta = initialWheelDelta; 807 snapState.m_shouldOverrideWheelEvent = true; 808 snapState.clearInitialWheelDeltaWindow(); 809 ScrollEventAxis otherAxis = axis == ScrollEventAxis::Horizontal ? ScrollEventAxis::Vertical : ScrollEventAxis::Horizontal; 810 if ((otherAxis == ScrollEventAxis::Horizontal && m_horizontalScrollSnapState && m_horizontalScrollSnapState->m_currentState == ScrollSnapState::UserInteraction) 811 || (otherAxis == ScrollEventAxis::Vertical && m_verticalScrollSnapState && m_verticalScrollSnapState->m_currentState == ScrollSnapState::UserInteraction)) { 812 813 ScrollSnapAnimatorState& otherState = scrollSnapPointState(otherAxis); 814 if (!otherState.averageInitialWheelDelta()) { 815 float offsetOnOtherAxis = m_client.scrollOffsetOnAxis(otherAxis); 816 float snapOffsetForOtherAxis = scaleFactor * closestSnapOffset<LayoutUnit, float>(otherState.m_snapOffsets, offsetOnOtherAxis, 0, otherState.m_activeSnapIndex); 817 if (offsetOnOtherAxis != snapOffsetForOtherAxis) { 818 otherState.m_initialOffset = offsetOnOtherAxis; 819 otherState.m_targetOffset = snapOffsetForOtherAxis; 820 otherState.m_initialScrollDelta = 0; 821 otherState.m_currentState = ScrollSnapState::Gliding; 822 } 823 } 824 } 825 826 } else { 827 snapState.m_initialScrollDelta = initialWheelDelta; 828 } 829 initializeScrollSnapAnimationParameters(); 830 startScrollSnapTimer(); 831 } 832 833 void ScrollController::endScrollSnapAnimation(ScrollSnapState newState) 834 { 835 ASSERT(newState == ScrollSnapState::DestinationReached || newState == ScrollSnapState::UserInteraction); 836 if (m_horizontalScrollSnapState) 837 m_horizontalScrollSnapState->m_currentState = newState; 838 839 if (m_verticalScrollSnapState) 840 m_verticalScrollSnapState->m_currentState = newState; 841 842 stopScrollSnapTimer(); 843 } 844 845 void ScrollController::initializeScrollSnapAnimationParameters() 846 { 847 if (!m_scrollSnapCurveState) 848 m_scrollSnapCurveState = std::make_unique<ScrollSnapAnimationCurveState>(); 849 850 bool isSnappingOnHorizontalAxis = isSnappingOnAxis(ScrollEventAxis::Horizontal); 851 bool isSnappingOnVerticalAxis = isSnappingOnAxis(ScrollEventAxis::Vertical); 852 FloatSize initialVector(isSnappingOnHorizontalAxis ? m_horizontalScrollSnapState->m_initialOffset : m_client.scrollOffsetOnAxis(ScrollEventAxis::Horizontal), 853 isSnappingOnVerticalAxis ? m_verticalScrollSnapState->m_initialOffset : m_client.scrollOffsetOnAxis(ScrollEventAxis::Vertical)); 854 FloatSize targetVector(isSnappingOnHorizontalAxis ? m_horizontalScrollSnapState->m_targetOffset : m_client.scrollOffsetOnAxis(ScrollEventAxis::Horizontal), 855 isSnappingOnVerticalAxis ? m_verticalScrollSnapState->m_targetOffset : m_client.scrollOffsetOnAxis(ScrollEventAxis::Vertical)); 856 FloatSize initialDelta(isSnappingOnHorizontalAxis ? m_horizontalScrollSnapState->m_initialScrollDelta : 0, 857 isSnappingOnVerticalAxis ? m_verticalScrollSnapState->m_initialScrollDelta : 0); 858 859 // Animate directly by default. This flag will be changed as necessary if interpolation is possible. 860 m_scrollSnapCurveState->shouldAnimateDirectlyToSnapPoint = true; 861 m_scrollSnapCurveState->initializeSnapProgressCurve(initialVector, targetVector, initialDelta); 862 if (isSnappingOnHorizontalAxis && isSnappingOnVerticalAxis) 863 m_scrollSnapCurveState->initializeInterpolationCoefficientsIfNecessary(initialVector, targetVector, initialDelta); 864 } 865 866 bool ScrollController::isSnappingOnAxis(ScrollEventAxis axis) const 867 { 868 if (axis == ScrollEventAxis::Horizontal) 869 return m_horizontalScrollSnapState && m_horizontalScrollSnapState->isSnapping(); 870 871 return m_verticalScrollSnapState && m_verticalScrollSnapState->isSnapping(); 872 } 873 874 #endif 690 if (!m_scrollSnapState) 691 return; 692 693 setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis::Horizontal, x); 694 setNearestScrollSnapIndexForAxisAndOffset(ScrollEventAxis::Vertical, y); 695 } 875 696 #endif 876 697 -
trunk/Source/WebCore/platform/cocoa/ScrollSnapAnimatorState.h
r188641 r209070 32 32 #include "FloatPoint.h" 33 33 #include "FloatSize.h" 34 #include "Layout Unit.h"34 #include "LayoutPoint.h" 35 35 #include "PlatformWheelEvent.h" 36 36 #include "ScrollTypes.h" 37 #include "ScrollingMomentumCalculator.h" 37 38 38 39 namespace WebCore { … … 45 46 }; 46 47 47 struct ScrollSnapAnimatorState { 48 ScrollSnapAnimatorState(ScrollEventAxis, const Vector<LayoutUnit>&); 48 class ScrollSnapAnimatorState { 49 public: 50 Vector<LayoutUnit> snapOffsetsForAxis(ScrollEventAxis axis) const 51 { 52 return axis == ScrollEventAxis::Horizontal ? m_snapOffsetsX : m_snapOffsetsY; 53 } 49 54 50 void pushInitialWheelDelta(float); 51 float averageInitialWheelDelta() const; 52 void clearInitialWheelDeltaWindow(); 53 bool isSnapping() const; 54 bool canReachTargetWithCurrentInitialScrollDelta() const; 55 bool wheelDeltaTrackingIsInProgress() const; 56 bool hasFinishedTrackingWheelDeltas() const; 57 float interpolatedOffsetAtProgress(float) const; 58 59 static const int wheelDeltaWindowSize = 3; 55 void setSnapOffsetsForAxis(ScrollEventAxis axis, const Vector<LayoutUnit>& snapOffsets) 56 { 57 if (axis == ScrollEventAxis::Horizontal) 58 m_snapOffsetsX = snapOffsets; 59 else 60 m_snapOffsetsY = snapOffsets; 61 } 60 62 61 Vector<LayoutUnit> m_snapOffsets; 62 ScrollEventAxis m_axis; 63 // Used to track both snapping and gliding behaviors. 64 ScrollSnapState m_currentState; 65 LayoutUnit m_initialOffset; 66 LayoutUnit m_targetOffset; 67 // Used to track gliding behavior. 68 LayoutUnit m_beginTrackingWheelDeltaOffset; 69 int m_numWheelDeltasTracked { 0 }; 70 unsigned m_activeSnapIndex { 0 }; 71 float m_wheelDeltaWindow[wheelDeltaWindowSize]; 72 float m_initialScrollDelta { 0 }; 73 bool m_shouldOverrideWheelEvent { false }; 63 ScrollSnapState currentState() const { return m_currentState; } 64 65 unsigned activeSnapIndexForAxis(ScrollEventAxis axis) const 66 { 67 return axis == ScrollEventAxis::Horizontal ? m_activeSnapIndexX : m_activeSnapIndexY; 68 } 69 70 void setActiveSnapIndexForAxis(ScrollEventAxis axis, unsigned index) 71 { 72 if (axis == ScrollEventAxis::Horizontal) 73 m_activeSnapIndexX = index; 74 else 75 m_activeSnapIndexY = index; 76 } 77 78 FloatPoint currentAnimatedScrollOffset(bool& isAnimationComplete) const; 79 80 // State transition helpers. 81 void transitionToSnapAnimationState(const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset); 82 void transitionToGlideAnimationState(const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset, const FloatPoint& initialVelocity, const FloatSize& initialDelta); 83 void transitionToUserInteractionState(); 84 void transitionToDestinationReachedState(); 85 86 private: 87 float targetOffsetForStartOffset(ScrollEventAxis, float maxScrollOffset, float startOffset, float pageScale, float delta, unsigned& outActiveSnapIndex) const; 88 void teardownAnimationForState(ScrollSnapState); 89 void setupAnimationForState(ScrollSnapState, const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset, const FloatPoint& initialVelocity, const FloatSize& initialDelta); 90 91 ScrollSnapState m_currentState { ScrollSnapState::UserInteraction }; 92 93 Vector<LayoutUnit> m_snapOffsetsX; 94 unsigned m_activeSnapIndexX { 0 }; 95 Vector<LayoutUnit> m_snapOffsetsY; 96 unsigned m_activeSnapIndexY { 0 }; 97 98 double m_startTime { 0 }; 99 std::unique_ptr<ScrollingMomentumCalculator> m_momentumCalculator; 74 100 }; 75 76 /**77 * Stores state variables necessary to coordinate snapping animations between78 * horizontal and vertical axes.79 */80 struct ScrollSnapAnimationCurveState {81 82 void initializeSnapProgressCurve(const FloatSize&, const FloatSize&, const FloatSize&);83 void initializeInterpolationCoefficientsIfNecessary(const FloatSize&, const FloatSize&, const FloatSize&);84 FloatPoint interpolatedPositionAtProgress(float) const;85 bool shouldCompleteSnapAnimationImmediatelyAtTime(double) const;86 float animationProgressAtTime(double) const;87 88 bool shouldAnimateDirectlyToSnapPoint { false };89 90 private:91 double m_startTime { 0 };92 float m_snapAnimationCurveMagnitude { 0 };93 float m_snapAnimationDecayFactor { 0 };94 FloatSize m_snapAnimationCurveCoefficients[4] { };95 };96 97 101 98 102 } // namespace WebCore -
trunk/Source/WebCore/platform/cocoa/ScrollSnapAnimatorState.mm
r188641 r209070 27 27 #include "ScrollSnapAnimatorState.h" 28 28 #include <wtf/CurrentTime.h> 29 #include <wtf/MathExtras.h> 29 30 30 31 #if ENABLE(CSS_SCROLL_SNAP) … … 32 33 namespace WebCore { 33 34 34 ScrollSnapAnimatorState::ScrollSnapAnimatorState(ScrollEventAxis axis, const Vector<LayoutUnit>& snapOffsets) 35 : m_snapOffsets(snapOffsets) 36 , m_axis(axis) 37 , m_currentState(ScrollSnapState::DestinationReached) 38 , m_initialOffset(0) 39 , m_targetOffset(0) 40 , m_beginTrackingWheelDeltaOffset(0) 35 static const float inertialScrollPredictionFactor = 10; 36 static inline float projectedInertialScrollDistance(float initialWheelDelta) 41 37 { 38 return inertialScrollPredictionFactor * initialWheelDelta; 42 39 } 43 40 44 void ScrollSnapAnimatorState:: pushInitialWheelDelta(float wheelDelta)41 void ScrollSnapAnimatorState::transitionToSnapAnimationState(const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset) 45 42 { 46 if (m_numWheelDeltasTracked < wheelDeltaWindowSize) 47 m_wheelDeltaWindow[m_numWheelDeltasTracked++] = wheelDelta; 43 setupAnimationForState(ScrollSnapState::Snapping, contentSize, viewportSize, pageScale, initialOffset, { }, { }); 48 44 } 49 45 50 float ScrollSnapAnimatorState::averageInitialWheelDelta() const 46 void ScrollSnapAnimatorState::transitionToGlideAnimationState(const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset, const FloatPoint& initialVelocity, const FloatSize& initialDelta) 51 47 { 52 if (!m_numWheelDeltasTracked)53 return 0; 48 setupAnimationForState(ScrollSnapState::Gliding, contentSize, viewportSize, pageScale, initialOffset, initialVelocity, initialDelta); 49 } 54 50 55 float sum = 0; 56 int numZeroDeltas = 0; 57 for (int i = 0; i < m_numWheelDeltasTracked; ++i) { 58 sum += m_wheelDeltaWindow[i]; 59 if (!m_wheelDeltaWindow[i]) 60 numZeroDeltas++; 51 void ScrollSnapAnimatorState::setupAnimationForState(ScrollSnapState state, const FloatSize& contentSize, const FloatSize& viewportSize, float pageScale, const FloatPoint& initialOffset, const FloatPoint& initialVelocity, const FloatSize& initialDelta) 52 { 53 ASSERT(state == ScrollSnapState::Snapping || state == ScrollSnapState::Gliding); 54 if (m_currentState == state) 55 return; 56 57 float targetOffsetX = targetOffsetForStartOffset(ScrollEventAxis::Horizontal, contentSize.width() - viewportSize.width(), initialOffset.x(), pageScale, initialDelta.width(), m_activeSnapIndexX); 58 float targetOffsetY = targetOffsetForStartOffset(ScrollEventAxis::Vertical, contentSize.height() - viewportSize.height(), initialOffset.y(), pageScale, initialDelta.height(), m_activeSnapIndexY); 59 m_momentumCalculator = ScrollingMomentumCalculator::create(viewportSize, contentSize, initialOffset, FloatPoint(targetOffsetX, targetOffsetY), initialDelta, initialVelocity); 60 m_startTime = monotonicallyIncreasingTime(); 61 m_currentState = state; 62 } 63 64 void ScrollSnapAnimatorState::transitionToUserInteractionState() 65 { 66 teardownAnimationForState(ScrollSnapState::UserInteraction); 67 } 68 69 void ScrollSnapAnimatorState::transitionToDestinationReachedState() 70 { 71 teardownAnimationForState(ScrollSnapState::DestinationReached); 72 } 73 74 void ScrollSnapAnimatorState::teardownAnimationForState(ScrollSnapState state) 75 { 76 ASSERT(state == ScrollSnapState::UserInteraction || state == ScrollSnapState::DestinationReached); 77 if (m_currentState == state) 78 return; 79 80 m_momentumCalculator = nullptr; 81 m_startTime = 0; 82 m_currentState = state; 83 } 84 85 FloatPoint ScrollSnapAnimatorState::currentAnimatedScrollOffset(bool& isAnimationComplete) const 86 { 87 if (!m_momentumCalculator) { 88 isAnimationComplete = true; 89 return { }; 61 90 } 62 91 63 return m_numWheelDeltasTracked == numZeroDeltas ? 0 : sum / (m_numWheelDeltasTracked - numZeroDeltas); 92 double elapsedTime = monotonicallyIncreasingTime() - m_startTime; 93 isAnimationComplete = elapsedTime >= m_momentumCalculator->animationDuration(); 94 return m_momentumCalculator->scrollOffsetAfterElapsedTime(elapsedTime); 64 95 } 65 96 66 void ScrollSnapAnimatorState::clearInitialWheelDeltaWindow() 97 float ScrollSnapAnimatorState::targetOffsetForStartOffset(ScrollEventAxis axis, float maxScrollOffset, float startOffset, float pageScale, float initialDelta, unsigned& outActiveSnapIndex) const 67 98 { 68 for (int i = 0; i < m_numWheelDeltasTracked; ++i) 69 m_wheelDeltaWindow[i] = 0; 99 auto snapOffsets = snapOffsetsForAxis(axis); 100 if (!snapOffsets.size()) { 101 outActiveSnapIndex = 0; 102 return clampTo<float>(startOffset, 0, maxScrollOffset); 103 } 70 104 71 m_numWheelDeltasTracked = 0; 72 } 73 74 bool ScrollSnapAnimatorState::isSnapping() const 75 { 76 return m_currentState == ScrollSnapState::Gliding || m_currentState == ScrollSnapState::Snapping; 77 } 78 79 bool ScrollSnapAnimatorState::canReachTargetWithCurrentInitialScrollDelta() const 80 { 81 if (m_initialOffset == m_targetOffset || !m_initialScrollDelta) 82 return true; 83 84 return m_initialOffset < m_targetOffset ? m_initialScrollDelta > 0 : m_initialScrollDelta < 0; 85 } 86 87 bool ScrollSnapAnimatorState::wheelDeltaTrackingIsInProgress() const 88 { 89 return m_numWheelDeltasTracked && m_numWheelDeltasTracked < wheelDeltaWindowSize; 90 } 91 92 bool ScrollSnapAnimatorState::hasFinishedTrackingWheelDeltas() const 93 { 94 return m_numWheelDeltasTracked == wheelDeltaWindowSize; 95 } 96 97 float ScrollSnapAnimatorState::interpolatedOffsetAtProgress(float progress) const 98 { 99 progress = std::max(0.0f, std::min(1.0f, progress)); 100 return m_initialOffset + progress * (m_targetOffset - m_initialOffset); 101 } 102 103 static const int maxNumScrollSnapParameterEstimationIterations = 10; 104 static const float scrollSnapDecayFactorConvergenceThreshold = 0.001; 105 static const float initialScrollSnapCurveMagnitude = 1.1; 106 static const float minScrollSnapInitialProgress = 0.15; 107 static const float maxScrollSnapInitialProgress = 0.5; 108 static const double scrollSnapAnimationDuration = 0.5; 109 110 /** 111 * Computes and sets parameters required for tracking the progress of a snap animation curve, interpolated 112 * or linear. The progress curve s(t) maps time t to progress s; both variables are in the interval [0, 1]. 113 * The time input t is 0 when the current time is the start of the animation, t = m_startTime, and 1 when the 114 * current time is at or after the end of the animation, t = m_startTime + m_scrollSnapAnimationDuration. 115 * 116 * In this exponential progress model, s(t) = A - A * b^(-kt), where k = 60T is the number of frames in the 117 * animation (assuming 60 FPS and an animation duration of T) and A, b are reals greater than or equal to 1. 118 * Also note that we are given the initial progress, a value indicating the portion of the curve which our 119 * initial scroll delta takes us. This is important when matching the initial speed of the animation to the 120 * user's initial momentum scrolling speed. Let this initial progress amount equal v_0. I clamp this initial 121 * progress amount to a minimum or maximum value. 122 * 123 * A is referred to as the curve magnitude, while b is referred to as the decay factor. We solve for A and b, 124 * keeping the following constraints in mind: 125 * 1. s(0) = 0 126 * 2. s(1) = 1 127 * 3. s(1/k) = v_0 128 * 129 * First, observe that s(0) = 0 holds for appropriate values of A, b. Solving for the remaining constraints 130 * yields a nonlinear system of two equations. In lieu of a purely analytical solution, an alternating 131 * optimization scheme is used to approximate A and b. This technique converges quickly (within 5 iterations 132 * or so) for appropriate values of v_0. The optimization terminates early when the decay factor changes by 133 * less than a threshold between one iteration and the next. 134 */ 135 void ScrollSnapAnimationCurveState::initializeSnapProgressCurve(const FloatSize& initialVector, const FloatSize& targetVector, const FloatSize& initialDelta) 136 { 137 float initialProgress = std::max(minScrollSnapInitialProgress, std::min(initialDelta.diagonalLength() / (targetVector - initialVector).diagonalLength(), maxScrollSnapInitialProgress)); 138 float previousDecayFactor = 1.0f; 139 m_snapAnimationCurveMagnitude = initialScrollSnapCurveMagnitude; 140 for (int i = 0; i < maxNumScrollSnapParameterEstimationIterations; ++i) { 141 m_snapAnimationDecayFactor = m_snapAnimationCurveMagnitude / (m_snapAnimationCurveMagnitude - initialProgress); 142 m_snapAnimationCurveMagnitude = 1.0f / (1.0f - std::pow(m_snapAnimationDecayFactor, -60.0f * scrollSnapAnimationDuration)); 143 if (std::abs(m_snapAnimationDecayFactor - previousDecayFactor) < scrollSnapDecayFactorConvergenceThreshold) 144 break; 145 146 previousDecayFactor = m_snapAnimationDecayFactor; 147 } 148 m_startTime = monotonicallyIncreasingTime(); 149 } 150 151 /** 152 * Computes and sets coefficients required for interpolated snapping when scrolling in 2 dimensions, given 153 * initial conditions (the initial and target vectors, along with the initial wheel delta as a vector). The 154 * path is a cubic Bezier curve of the form p(s) = INITIAL + (C_1 * s) + (C_2 * s^2) + (C_3 * s^3) where each 155 * C_i is a 2D vector and INITIAL is the vector representing the initial scroll offset. s is a real in the 156 * interval [0, 1] indicating the "progress" of the curve (i.e. how much of the curve has been traveled). 157 * 158 * The curve has 4 control points, the first and last of which are the initial and target points, respectively. 159 * The distances between adjacent control points are constrained to be the same, making the convex hull an 160 * isosceles trapezoid with 3 sides of equal length. Additionally, the vector from the first control point to 161 * the second points in the same direction as the initial scroll delta. These constraints ensure two properties: 162 * 1. The direction of the snap animation at s=0 will be equal to the direction of the initial scroll delta. 163 * 2. Points at regular intervals of s will be evenly spread out. 164 * 165 * If the initial scroll direction is orthogonal to or points in the opposite direction as the vector from the 166 * initial point to the target point, initialization returns early and sets the curve to animate directly to the 167 * snap point without interpolation. 168 */ 169 void ScrollSnapAnimationCurveState::initializeInterpolationCoefficientsIfNecessary(const FloatSize& initialVector, const FloatSize& targetVector, const FloatSize& initialDelta) 170 { 171 FloatSize startToEndVector = targetVector - initialVector; 172 float startToEndDistance = startToEndVector.diagonalLength(); 173 float initialDeltaMagnitude = initialDelta.diagonalLength(); 174 float cosTheta = initialDelta.isZero() ? 0 : (initialDelta.width() * startToEndVector.width() + initialDelta.height() * startToEndVector.height()) / (std::max(1.0f, initialDeltaMagnitude) * startToEndDistance); 175 if (cosTheta <= 0) 176 return; 177 178 float sideLength = startToEndDistance / (2.0f * cosTheta + 1.0f); 179 FloatSize controlVector1 = initialVector + sideLength * initialDelta / initialDeltaMagnitude; 180 FloatSize controlVector2 = controlVector1 + (sideLength * startToEndVector / startToEndDistance); 181 m_snapAnimationCurveCoefficients[0] = initialVector; 182 m_snapAnimationCurveCoefficients[1] = 3 * (controlVector1 - initialVector); 183 m_snapAnimationCurveCoefficients[2] = 3 * (initialVector - 2 * controlVector1 + controlVector2); 184 m_snapAnimationCurveCoefficients[3] = 3 * (controlVector1 - controlVector2) - initialVector + targetVector; 185 shouldAnimateDirectlyToSnapPoint = false; 186 } 187 188 FloatPoint ScrollSnapAnimationCurveState::interpolatedPositionAtProgress(float progress) const 189 { 190 ASSERT(!shouldAnimateDirectlyToSnapPoint); 191 progress = std::max(0.0f, std::min(1.0f, progress)); 192 FloatPoint interpolatedPoint(0.0f, 0.0f); 193 for (int i = 0; i < 4; ++i) 194 interpolatedPoint += std::pow(progress, i) * m_snapAnimationCurveCoefficients[i]; 195 196 return interpolatedPoint; 197 } 198 199 bool ScrollSnapAnimationCurveState::shouldCompleteSnapAnimationImmediatelyAtTime(double time) const 200 { 201 return m_startTime + scrollSnapAnimationDuration < time; 202 } 203 204 float ScrollSnapAnimationCurveState::animationProgressAtTime(double time) const 205 { 206 float timeProgress = std::max(0.0, std::min(1.0, (time - m_startTime) / scrollSnapAnimationDuration)); 207 return std::min(1.0, m_snapAnimationCurveMagnitude * (1.0 - std::pow(m_snapAnimationDecayFactor, -60.0f * scrollSnapAnimationDuration * timeProgress))); 105 float projectedDestination = (startOffset + projectedInertialScrollDistance(initialDelta)) / pageScale; 106 float targetOffset = closestSnapOffset<LayoutUnit, float>(snapOffsets, projectedDestination, initialDelta, outActiveSnapIndex); 107 targetOffset = clampTo<float>(targetOffset, snapOffsets.first(), snapOffsets.last()); 108 targetOffset = clampTo<float>(targetOffset, 0, maxScrollOffset); 109 return pageScale * targetOffset; 208 110 } 209 111 -
trunk/Source/WebKit2/ChangeLog
r209067 r209070 1 2016-11-29 Wenson Hsieh <wenson_hsieh@apple.com> 2 3 Scroll snapping on Mac should use AppKit animations 4 https://bugs.webkit.org/show_bug.cgi?id=147261 5 <rdar://problem/29395293> 6 7 Reviewed by Brent Fulgham. 8 9 Add some logic to plumb filtered wheel velocity over to WebCore in the case of mainframe scrolling. See 10 WebCore/ChangeLog for more details. 11 12 * WebProcess/WebPage/EventDispatcher.cpp: 13 (WebKit::EventDispatcher::wheelEvent): 14 1 15 2016-11-21 Brian Burg <bburg@apple.com> 2 16 -
trunk/Source/WebKit2/WebProcess/WebPage/EventDispatcher.cpp
r208499 r209070 108 108 m_recentWheelEventDeltaFilter->updateFromDelta(FloatSize(platformWheelEvent.deltaX(), platformWheelEvent.deltaY())); 109 109 FloatSize filteredDelta = m_recentWheelEventDeltaFilter->filteredDelta(); 110 platformWheelEvent = platformWheelEvent.copyWithDeltas (filteredDelta.width(), filteredDelta.height());110 platformWheelEvent = platformWheelEvent.copyWithDeltasAndVelocity(filteredDelta.width(), filteredDelta.height(), m_recentWheelEventDeltaFilter->filteredVelocity()); 111 111 } 112 112 #endif
Note: See TracChangeset
for help on using the changeset viewer.