Changeset 286724 in webkit
- Timestamp:
- Dec 8, 2021, 1:26:01 PM (5 years ago)
- Location:
- branches/safari-612.4.2.1-branch/Source/WebKit
- Files:
-
- 6 edited
-
ChangeLog (modified) (1 diff)
-
Shared/ScrollingAccelerationCurve.cpp (modified) (5 diffs)
-
Shared/ScrollingAccelerationCurve.h (modified) (4 diffs)
-
Shared/mac/ScrollingAccelerationCurveMac.mm (modified) (5 diffs)
-
WebProcess/WebPage/MomentumEventDispatcher.cpp (modified) (10 diffs)
-
WebProcess/WebPage/MomentumEventDispatcher.h (modified) (4 diffs)
Legend:
- Unmodified
- Added
- Removed
-
branches/safari-612.4.2.1-branch/Source/WebKit/ChangeLog
r286723 r286724 1 2021-12-03 Russell Epstein <repstein@apple.com> 2 3 Cherry-pick r286483. rdar://problem/85928816 4 5 MomentumEventDispatcher curve sometimes doesn't match the system curve 6 https://bugs.webkit.org/show_bug.cgi?id=233801 7 <rdar://problem/85870287> 8 9 Reviewed by Simon Fraser. 10 11 Three small changes to get us closer to the system curve: 12 13 1) Fetch the momentum event dispatch interval from the system, and use 14 it to scale the momentum start event's delta (which we use as our 15 initial velocity) into the "ideal" curve's frame rate (which is always 16 60fps regardless). 17 18 2) Back-date the animation start time to the fingers-down phase end event, 19 so that the momentum start phase has a delta. This seems to match what 20 the system does. 21 22 3) Switch to MonotonicTime for the animation time, since it doesn't need 23 to be in the same timebase as events (which are oddly in WallTime), and 24 certainly should be monotonic. 25 26 * Shared/ScrollingAccelerationCurve.cpp: 27 (WebKit::ScrollingAccelerationCurve::ScrollingAccelerationCurve): 28 (WebKit::ScrollingAccelerationCurve::interpolate): 29 (WebKit::ScrollingAccelerationCurve::encode const): 30 (WebKit::ScrollingAccelerationCurve::decode): 31 (WebKit::operator<<): 32 * Shared/ScrollingAccelerationCurve.h: 33 (WebKit::ScrollingAccelerationCurve::frameRate): 34 (WebKit::ScrollingAccelerationCurve::operator== const): 35 * Shared/mac/ScrollingAccelerationCurveMac.mm: 36 (WebKit::fromIOHIDCurve): 37 (WebKit::fromIOHIDCurveArrayWithAcceleration): 38 (WebKit::fromIOHIDDevice): 39 Fetch and propagate the dispatch frame rate. This isn't *really* a 40 ScrollingAccelerationCurve property, but neither is `resolution`; 41 this is just currently the only place we look up HID properties 42 and push them to the Web Content process; some re-architecture is 43 warranted here in the future. 44 45 * WebProcess/WebPage/MomentumEventDispatcher.cpp: 46 (WebKit::MomentumEventDispatcher::handleWheelEvent): 47 Keep track of the last fingers-down phase ended event timestamp. 48 49 (WebKit::MomentumEventDispatcher::didStartMomentumPhase): 50 Backdate the start time so that the first event has the appropriate delta. 51 Divide out the dispatch frame rate so that the initial velocity is 52 as if the curve were running at 60fps (since we *will* run it at 60fps and interpolate). 53 54 (WebKit::MomentumEventDispatcher::didEndMomentumPhase): 55 (WebKit::MomentumEventDispatcher::consumeDeltaForTime): 56 (WebKit::MomentumEventDispatcher::displayWasRefreshed): 57 Factor the consume-a-delta-from-the-ideal-curve code out from displayWasRefreshed 58 so we can use it in the start phase too. 59 60 (WebKit::MomentumEventDispatcher::offsetAtTime): 61 (WebKit::MomentumEventDispatcher::computeNextDelta): 62 Rename idealCurveFrameRate->idealCurveFrameInterval for accuracy. 63 64 * WebProcess/WebPage/MomentumEventDispatcher.h: 65 66 67 git-svn-id: https://svn.webkit.org/repository/webkit/trunk@286483 268f45cc-cd09-0410-ab3c-d52691b4dbfc 68 69 2021-12-02 Tim Horton <timothy_horton@apple.com> 70 71 MomentumEventDispatcher curve sometimes doesn't match the system curve 72 https://bugs.webkit.org/show_bug.cgi?id=233801 73 <rdar://problem/85870287> 74 75 Reviewed by Simon Fraser. 76 77 Three small changes to get us closer to the system curve: 78 79 1) Fetch the momentum event dispatch interval from the system, and use 80 it to scale the momentum start event's delta (which we use as our 81 initial velocity) into the "ideal" curve's frame rate (which is always 82 60fps regardless). 83 84 2) Back-date the animation start time to the fingers-down phase end event, 85 so that the momentum start phase has a delta. This seems to match what 86 the system does. 87 88 3) Switch to MonotonicTime for the animation time, since it doesn't need 89 to be in the same timebase as events (which are oddly in WallTime), and 90 certainly should be monotonic. 91 92 * Shared/ScrollingAccelerationCurve.cpp: 93 (WebKit::ScrollingAccelerationCurve::ScrollingAccelerationCurve): 94 (WebKit::ScrollingAccelerationCurve::interpolate): 95 (WebKit::ScrollingAccelerationCurve::encode const): 96 (WebKit::ScrollingAccelerationCurve::decode): 97 (WebKit::operator<<): 98 * Shared/ScrollingAccelerationCurve.h: 99 (WebKit::ScrollingAccelerationCurve::frameRate): 100 (WebKit::ScrollingAccelerationCurve::operator== const): 101 * Shared/mac/ScrollingAccelerationCurveMac.mm: 102 (WebKit::fromIOHIDCurve): 103 (WebKit::fromIOHIDCurveArrayWithAcceleration): 104 (WebKit::fromIOHIDDevice): 105 Fetch and propagate the dispatch frame rate. This isn't *really* a 106 ScrollingAccelerationCurve property, but neither is `resolution`; 107 this is just currently the only place we look up HID properties 108 and push them to the Web Content process; some re-architecture is 109 warranted here in the future. 110 111 * WebProcess/WebPage/MomentumEventDispatcher.cpp: 112 (WebKit::MomentumEventDispatcher::handleWheelEvent): 113 Keep track of the last fingers-down phase ended event timestamp. 114 115 (WebKit::MomentumEventDispatcher::didStartMomentumPhase): 116 Backdate the start time so that the first event has the appropriate delta. 117 Divide out the dispatch frame rate so that the initial velocity is 118 as if the curve were running at 60fps (since we *will* run it at 60fps and interpolate). 119 120 (WebKit::MomentumEventDispatcher::didEndMomentumPhase): 121 (WebKit::MomentumEventDispatcher::consumeDeltaForTime): 122 (WebKit::MomentumEventDispatcher::displayWasRefreshed): 123 Factor the consume-a-delta-from-the-ideal-curve code out from displayWasRefreshed 124 so we can use it in the start phase too. 125 126 (WebKit::MomentumEventDispatcher::offsetAtTime): 127 (WebKit::MomentumEventDispatcher::computeNextDelta): 128 Rename idealCurveFrameRate->idealCurveFrameInterval for accuracy. 129 130 * WebProcess/WebPage/MomentumEventDispatcher.h: 131 1 132 2021-12-03 Russell Epstein <repstein@apple.com> 2 133 -
branches/safari-612.4.2.1-branch/Source/WebKit/Shared/ScrollingAccelerationCurve.cpp
r286717 r286724 35 35 namespace WebKit { 36 36 37 ScrollingAccelerationCurve::ScrollingAccelerationCurve(float gainLinear, float gainParabolic, float gainCubic, float gainQuartic, float tangentSpeedLinear, float tangentSpeedParabolicRoot, float resolution )38 : m_parameters { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, resolution }37 ScrollingAccelerationCurve::ScrollingAccelerationCurve(float gainLinear, float gainParabolic, float gainCubic, float gainQuartic, float tangentSpeedLinear, float tangentSpeedParabolicRoot, float resolution, float frameRate) 38 : m_parameters { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, resolution, frameRate } 39 39 { 40 40 } … … 54 54 auto tangentSpeedParabolicRoot = interpolate(from.m_parameters.tangentSpeedParabolicRoot, to.m_parameters.tangentSpeedParabolicRoot); 55 55 56 return { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, from.m_parameters.resolution };56 return { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, from.m_parameters.resolution, from.m_parameters.frameRate }; 57 57 } 58 58 … … 128 128 129 129 encoder << m_parameters.resolution; 130 encoder << m_parameters.frameRate; 130 131 } 131 132 … … 155 156 if (!decoder.decode(resolution)) 156 157 return std::nullopt; 158 float frameRate; 159 if (!decoder.decode(frameRate)) 160 return std::nullopt; 157 161 158 return { { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, resolution } };162 return { { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, resolution, frameRate } }; 159 163 } 160 164 … … 172 176 ts.dumpProperty("tangentSpeedParabolicRoot", curve.m_parameters.tangentSpeedParabolicRoot); 173 177 ts.dumpProperty("resolution", curve.m_parameters.resolution); 178 ts.dumpProperty("frameRate", curve.m_parameters.frameRate); 174 179 175 180 return ts; -
branches/safari-612.4.2.1-branch/Source/WebKit/Shared/ScrollingAccelerationCurve.h
r286717 r286724 42 42 class ScrollingAccelerationCurve { 43 43 public: 44 ScrollingAccelerationCurve(float gainLinear, float gainParabolic, float gainCubic, float gainQuartic, float tangentSpeedLinear, float tangentSpeedParabolicRoot, float resolution );44 ScrollingAccelerationCurve(float gainLinear, float gainParabolic, float gainCubic, float gainQuartic, float tangentSpeedLinear, float tangentSpeedParabolicRoot, float resolution, float frameRate); 45 45 46 46 static std::optional<ScrollingAccelerationCurve> fromNativeWheelEvent(const NativeWebWheelEvent&); … … 49 49 50 50 float accelerationFactor(float); 51 float frameRate() const { return m_parameters.frameRate; } 51 52 52 53 void encode(IPC::Encoder&) const; … … 61 62 && m_parameters.tangentSpeedLinear == other.m_parameters.tangentSpeedLinear 62 63 && m_parameters.tangentSpeedParabolicRoot == other.m_parameters.tangentSpeedParabolicRoot 63 && m_parameters.resolution == other.m_parameters.resolution; 64 && m_parameters.resolution == other.m_parameters.resolution 65 && m_parameters.frameRate == other.m_parameters.frameRate; 64 66 } 65 67 … … 80 82 float tangentSpeedLinear { 0 }; 81 83 float tangentSpeedParabolicRoot { 0 }; 84 85 // FIXME: Resolution and frame rate are not technically properties 86 // of the curve, just required to use it; they should be plumbed separately. 82 87 float resolution { 0 }; 88 float frameRate { 0 }; 83 89 } m_parameters; 84 90 -
branches/safari-612.4.2.1-branch/Source/WebKit/Shared/mac/ScrollingAccelerationCurveMac.mm
r286717 r286724 40 40 } 41 41 42 static float fromCFNumber(CFNumberRef number) 43 { 44 float value; 45 CFNumberGetValue(number, kCFNumberFloatType, &value); 46 return value; 47 } 48 42 49 static float readFixedPointParameter(NSDictionary *parameters, const char *key) 43 50 { … … 45 52 } 46 53 47 static ScrollingAccelerationCurve fromIOHIDCurve(NSDictionary *parameters, float resolution )54 static ScrollingAccelerationCurve fromIOHIDCurve(NSDictionary *parameters, float resolution, float frameRate) 48 55 { 49 56 auto gainLinear = readFixedPointParameter(parameters, kHIDAccelGainLinearKey); … … 55 62 auto tangentSpeedParabolicRoot = readFixedPointParameter(parameters, kHIDAccelTangentSpeedParabolicRootKey); 56 63 57 return { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, resolution };64 return { gainLinear, gainParabolic, gainCubic, gainQuartic, tangentSpeedLinear, tangentSpeedParabolicRoot, resolution, frameRate }; 58 65 } 59 66 60 static ScrollingAccelerationCurve fromIOHIDCurveArrayWithAcceleration(NSArray<NSDictionary *> *ioHIDCurves, float desiredAcceleration, float resolution )67 static ScrollingAccelerationCurve fromIOHIDCurveArrayWithAcceleration(NSArray<NSDictionary *> *ioHIDCurves, float desiredAcceleration, float resolution, float frameRate) 61 68 { 62 69 __block size_t currentIndex = 0; … … 65 72 [ioHIDCurves enumerateObjectsUsingBlock:^(NSDictionary *parameters, NSUInteger i, BOOL *) { 66 73 auto curveAcceleration = readFixedPointParameter(parameters, kHIDAccelIndexKey); 67 auto curve = fromIOHIDCurve(parameters, resolution );74 auto curve = fromIOHIDCurve(parameters, resolution, frameRate); 68 75 69 76 if (desiredAcceleration > curveAcceleration) … … 117 124 } 118 125 119 auto scrollAcceleration = adoptCF(dynamic_cf_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(ioHIDService.get(), scrollAccelerationType.get())));120 if (!scrollAcceleration ) {126 auto scrollAccelerationCF = adoptCF(dynamic_cf_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(ioHIDService.get(), scrollAccelerationType.get()))); 127 if (!scrollAccelerationCF) { 121 128 RELEASE_LOG(ScrollAnimations, "ScrollingAccelerationCurve::fromIOHIDDevice failed to look up acceleration value"); 122 129 return std::nullopt; 123 130 } 131 auto scrollAcceleration = fromFixedPoint(fromCFNumber(scrollAccelerationCF.get())); 124 132 125 auto resolution = adoptCF(dynamic_cf_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(ioHIDService.get(), CFSTR(kIOHIDScrollResolutionKey))));126 if (!resolution ) {133 auto resolutionCF = adoptCF(dynamic_cf_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(ioHIDService.get(), CFSTR(kIOHIDScrollResolutionKey)))); 134 if (!resolutionCF) { 127 135 RELEASE_LOG(ScrollAnimations, "ScrollingAccelerationCurve::fromIOHIDDevice failed to look up resolution"); 128 136 return std::nullopt; 129 137 } 138 auto resolution = fromFixedPoint([(NSNumber *)resolutionCF.get() floatValue]); 130 139 131 return fromIOHIDCurveArrayWithAcceleration((NSArray *)curves.get(), fromFixedPoint([(NSNumber *)scrollAcceleration.get() floatValue]), fromFixedPoint([(NSNumber *)resolution.get() floatValue])); 140 static CFStringRef dispatchFrameRateKey = CFSTR("ScrollMomentumDispatchRate"); 141 static constexpr float defaultDispatchFrameRate = 60; 142 auto frameRateCF = adoptCF(dynamic_cf_cast<CFNumberRef>(IOHIDServiceClientCopyProperty(ioHIDService.get(), dispatchFrameRateKey))); 143 float frameRate = frameRateCF ? fromCFNumber(frameRateCF.get()) : defaultDispatchFrameRate; 144 145 return fromIOHIDCurveArrayWithAcceleration((NSArray *)curves.get(), scrollAcceleration, resolution, frameRate); 132 146 } 133 147 -
branches/safari-612.4.2.1-branch/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.cpp
r286722 r286724 40 40 static constexpr Seconds deltaHistoryMaximumAge = 500_ms; 41 41 static constexpr Seconds deltaHistoryMaximumInterval = 150_ms; 42 static constexpr Seconds idealCurveFrameRate = 1_s / 60; 42 static constexpr float idealCurveFrameRate = 60; 43 static constexpr Seconds idealCurveFrameInterval = 1_s / idealCurveFrameRate; 43 44 44 45 MomentumEventDispatcher::MomentumEventDispatcher(EventDispatcher& dispatcher) … … 96 97 m_lastActivePhaseDelta = *lastActivePhaseDelta; 97 98 } 99 100 if (event.phase() == WebWheelEvent::PhaseEnded) 101 m_lastEndedEventTimestamp = event.ioHIDEventTimestamp(); 98 102 99 103 if (eventShouldStartSyntheticMomentumPhase(pageIdentifier, event)) … … 160 164 void MomentumEventDispatcher::didStartMomentumPhase(WebCore::PageIdentifier pageIdentifier, const WebWheelEvent& event) 161 165 { 166 auto momentumStartInterval = event.ioHIDEventTimestamp() - m_lastEndedEventTimestamp; 167 162 168 m_currentGesture.active = true; 163 169 m_currentGesture.pageIdentifier = pageIdentifier; 164 170 m_currentGesture.initiatingEvent = event; 165 171 m_currentGesture.currentOffset = { }; 166 m_currentGesture.startTime = WallTime::now();172 m_currentGesture.startTime = MonotonicTime::now() - momentumStartInterval; 167 173 m_currentGesture.accelerationCurve = [&] () -> std::optional<ScrollingAccelerationCurve> { 168 174 auto curveIterator = m_accelerationCurves.find(m_currentGesture.pageIdentifier); … … 177 183 // directly when the frame interval is within 20fps of idealCurveFrameRate; 178 184 // we should perhaps do the same. 179 buildOffsetTableWithInitialDelta(*event.rawPlatformDelta()); 180 181 dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseBegan, { }); 185 float idealCurveMultiplier = m_currentGesture.accelerationCurve->frameRate() / idealCurveFrameRate; 186 buildOffsetTableWithInitialDelta(*event.rawPlatformDelta() * idealCurveMultiplier); 187 188 dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseBegan, consumeDeltaForCurrentTime()); 182 189 } 183 190 … … 188 195 dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseEnded, { }); 189 196 190 RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher saw momentum end phase with total offset %.1f %.1f, duration %f (event offset would have been %.1f %.1f)", m_currentGesture.currentOffset.width(), m_currentGesture.currentOffset.height(), ( WallTime::now() - m_currentGesture.startTime).seconds(), m_currentGesture.accumulatedEventOffset.width(), m_currentGesture.accumulatedEventOffset.height());197 RELEASE_LOG(ScrollAnimations, "MomentumEventDispatcher saw momentum end phase with total offset %.1f %.1f, duration %f (event offset would have been %.1f %.1f)", m_currentGesture.currentOffset.width(), m_currentGesture.currentOffset.height(), (MonotonicTime::now() - m_currentGesture.startTime).seconds(), m_currentGesture.accumulatedEventOffset.width(), m_currentGesture.accumulatedEventOffset.height()); 191 198 192 199 stopDisplayLink(); … … 252 259 } 253 260 254 void MomentumEventDispatcher::displayWasRefreshed(WebCore::PlatformDisplayID displayID, const WebCore::DisplayUpdate&) 255 { 256 if (!m_currentGesture.active) 257 return; 258 259 if (displayID != this->displayID()) 260 return; 261 262 auto animationTime = WallTime::now() - m_currentGesture.startTime; 261 WebCore::FloatSize MomentumEventDispatcher::consumeDeltaForCurrentTime() 262 { 263 auto animationTime = MonotonicTime::now() - m_currentGesture.startTime; 263 264 auto desiredOffset = offsetAtTime(animationTime); 264 265 … … 270 271 #endif 271 272 272 dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseChanged, -delta);273 274 273 m_currentGesture.currentOffset += delta; 274 275 return -delta; 276 } 277 278 void MomentumEventDispatcher::displayWasRefreshed(WebCore::PlatformDisplayID displayID, const WebCore::DisplayUpdate&) 279 { 280 if (!m_currentGesture.active) 281 return; 282 283 if (displayID != this->displayID()) 284 return; 285 286 dispatchSyntheticMomentumEvent(WebWheelEvent::PhaseChanged, consumeDeltaForCurrentTime()); 275 287 } 276 288 … … 344 356 return { }; 345 357 346 float fractionalFrameNumber = time.seconds() / idealCurveFrame Rate.seconds();358 float fractionalFrameNumber = time.seconds() / idealCurveFrameInterval.seconds(); 347 359 unsigned long lowerFrameNumber = std::min<unsigned long>(m_currentGesture.offsetTable.size() - 1, floor(fractionalFrameNumber)); 348 360 unsigned long upperFrameNumber = std::min<unsigned long>(m_currentGesture.offsetTable.size() - 1, lowerFrameNumber + 1); … … 380 392 WebCore::FloatSize unacceleratedDelta = currentUnacceleratedDelta; 381 393 382 float decayRate = momentumDecayRate(unacceleratedDelta, idealCurveFrame Rate);394 float decayRate = momentumDecayRate(unacceleratedDelta, idealCurveFrameInterval); 383 395 unacceleratedDelta.scale(decayRate); 384 396 … … 404 416 405 417 // The delta queue operates on pre-acceleration deltas, so insert the new event *before* accelerating. 406 didReceiveScrollEventWithInterval(quantizedUnacceleratedDelta, idealCurveFrame Rate);418 didReceiveScrollEventWithInterval(quantizedUnacceleratedDelta, idealCurveFrameInterval); 407 419 408 420 auto accelerateAxis = [&] (HistoricalDeltas& deltas, float value) { -
branches/safari-612.4.2.1-branch/Source/WebKit/WebProcess/WebPage/MomentumEventDispatcher.h
r286722 r286724 40 40 #include <memory> 41 41 #include <wtf/Deque.h> 42 #include <wtf/MonotonicTime.h> 42 43 #include <wtf/Noncopyable.h> 43 44 … … 81 82 void buildOffsetTableWithInitialDelta(WebCore::FloatSize); 82 83 84 // Once consumed, this delta *must* be dispatched in an event. 85 WebCore::FloatSize consumeDeltaForCurrentTime(); 86 83 87 WebCore::FloatSize offsetAtTime(Seconds); 84 88 std::pair<WebCore::FloatSize, WebCore::FloatSize> computeNextDelta(WebCore::FloatSize currentUnacceleratedDelta); … … 97 101 98 102 std::optional<WallTime> m_lastScrollTimestamp; 103 WallTime m_lastEndedEventTimestamp; 99 104 std::optional<WebWheelEvent> m_lastIncomingEvent; 100 105 WebCore::RectEdges<bool> m_lastRubberBandableEdges; … … 111 116 112 117 WebCore::FloatSize currentOffset; 113 WallTime startTime;118 MonotonicTime startTime; 114 119 115 120 Vector<WebCore::FloatSize> offsetTable;
Note:
See TracChangeset
for help on using the changeset viewer.