Here is a stack trace fragment that helps explain both the scrollend events, and the sluggish scrolling:
```
#17 0x00007f49d774b463 in mozilla::layers::RemoteContentController::NotifyAPZStateChange (this=0x7f49bce0bbe0, aGuid=...,
aChange=mozilla::layers::GeckoContentController_APZStateChange::eTransformEnd, aArg=0, aInputBlockId=<error reading variable: Cannot access memory at address 0x0>)
at /home/botond/dev/projects/mozilla/central/gfx/layers/ipc/RemoteContentController.cpp:225
#18 0x00007f49d76c59a9 in mozilla::layers::AsyncPanZoomController::DispatchStateChangeNotification (this=this@entry=0x7f49a8e9c800,
aOldState=mozilla::layers::AsyncPanZoomController::SMOOTHMSD_SCROLL, aNewState=aNewState@entry=mozilla::layers::AsyncPanZoomController::NOTHING)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/AsyncPanZoomController.cpp:6468
#19 0x00007f49d76b8ff5 in mozilla::layers::AsyncPanZoomController::SetState (this=0x7f49a8e9c800, aNewState=mozilla::layers::AsyncPanZoomController::NOTHING)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/AsyncPanZoomController.cpp:6449
#20 mozilla::layers::AsyncPanZoomController::CancelAnimation (this=0x7f49a8e9c800,
aFlags=(mozilla::layers::ExcludeOverscroll | mozilla::layers::ScrollSnap | mozilla::layers::ExcludeWheel))
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/AsyncPanZoomController.cpp:4290
#21 0x00007f49d76f0d5e in mozilla::layers::OverscrollHandoffChain::CancelAnimations (this=0x7f49a8e4dbc0,
aFlags=(mozilla::layers::ExcludeOverscroll | mozilla::layers::ScrollSnap | mozilla::layers::ExcludeWheel))
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/OverscrollHandoffState.cpp:80
#22 mozilla::layers::InputQueue::CancelAnimationsForNewBlock (this=0x7f49d0314560, aBlock=0x7f49a8bc8ce0, aExtraFlags=mozilla::layers::ExcludeWheel)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/InputQueue.cpp:605
#23 mozilla::layers::InputQueue::ReceiveScrollWheelInput (this=this@entry=0x7f49d0314560, aTarget=..., aFlags=..., aEvent=...)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/InputQueue.cpp:361
#24 0x00007f49d76f01ad in mozilla::layers::InputQueue::ReceiveInputEvent (this=0x7f49d0314560, aTarget=..., aFlags=..., aEvent=..., aTouchBehaviors=...)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/InputQueue.cpp:54
```
We are calling `CancelAnimation()` at the time a wheel event is enqueued into the input queue, when we don't yet know whether it will be prevent-defaulted.
We are passing the `ExcludeWheel` flag to `CancelAnimation()`, so in the case where the browser is handling the wheel scrolls, we don't cancel the ongoing animation because it's of type `WheelScrollAnimation`.
But in the case where the page is handling the wheel scrolls with `scrollBy()`, the compositor animation is a `SmoothScrollAnimation`, and we do cancel it. This has the effect that the next `scrollBy()` will be relative to the current position, rather than relative to the destination of the previous animation (hence the sluggish scrolling), and also the effect of triggering a `scrollend` event.
Bug 1932985 Comment 9 Edit History
Note: The actual edited comment in the bug view page will always show the original commenter’s name and original timestamp.
Here is a stack trace fragment that helps explain both the scrollend events, and the sluggish scrolling:
```
#17 0x00007f49d774b463 in mozilla::layers::RemoteContentController::NotifyAPZStateChange (this=0x7f49bce0bbe0, aGuid=...,
aChange=mozilla::layers::GeckoContentController_APZStateChange::eTransformEnd, aArg=0, aInputBlockId=<error reading variable: Cannot access memory at address 0x0>)
at /home/botond/dev/projects/mozilla/central/gfx/layers/ipc/RemoteContentController.cpp:225
#18 0x00007f49d76c59a9 in mozilla::layers::AsyncPanZoomController::DispatchStateChangeNotification (this=this@entry=0x7f49a8e9c800,
aOldState=mozilla::layers::AsyncPanZoomController::SMOOTHMSD_SCROLL, aNewState=aNewState@entry=mozilla::layers::AsyncPanZoomController::NOTHING)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/AsyncPanZoomController.cpp:6468
#19 0x00007f49d76b8ff5 in mozilla::layers::AsyncPanZoomController::SetState (this=0x7f49a8e9c800, aNewState=mozilla::layers::AsyncPanZoomController::NOTHING)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/AsyncPanZoomController.cpp:6449
#20 mozilla::layers::AsyncPanZoomController::CancelAnimation (this=0x7f49a8e9c800,
aFlags=(mozilla::layers::ExcludeOverscroll | mozilla::layers::ScrollSnap | mozilla::layers::ExcludeWheel))
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/AsyncPanZoomController.cpp:4290
#21 0x00007f49d76f0d5e in mozilla::layers::OverscrollHandoffChain::CancelAnimations (this=0x7f49a8e4dbc0,
aFlags=(mozilla::layers::ExcludeOverscroll | mozilla::layers::ScrollSnap | mozilla::layers::ExcludeWheel))
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/OverscrollHandoffState.cpp:80
#22 mozilla::layers::InputQueue::CancelAnimationsForNewBlock (this=0x7f49d0314560, aBlock=0x7f49a8bc8ce0, aExtraFlags=mozilla::layers::ExcludeWheel)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/InputQueue.cpp:605
#23 mozilla::layers::InputQueue::ReceiveScrollWheelInput (this=this@entry=0x7f49d0314560, aTarget=..., aFlags=..., aEvent=...)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/InputQueue.cpp:361
#24 0x00007f49d76f01ad in mozilla::layers::InputQueue::ReceiveInputEvent (this=0x7f49d0314560, aTarget=..., aFlags=..., aEvent=..., aTouchBehaviors=...)
at /home/botond/dev/projects/mozilla/central/gfx/layers/apz/src/InputQueue.cpp:54
```
We are calling `CancelAnimation()` at the time a wheel event is enqueued into the input queue [here](https://searchfox.org/mozilla-central/rev/cdfe21b20eacfaa6712dd9821d6383859ce386c6/gfx/layers/apz/src/InputQueue.cpp#362), when we don't yet know whether it will be prevent-defaulted.
We are passing the `ExcludeWheel` flag to `CancelAnimation()`, so in the case where the browser is handling the wheel scrolls, we don't cancel the ongoing animation because it's of type `WheelScrollAnimation`.
But in the case where the page is handling the wheel scrolls with `scrollBy()`, the compositor animation is a `SmoothScrollAnimation`, and we do cancel it. This has the effect that the next `scrollBy()` will be relative to the current position, rather than relative to the destination of the previous animation (hence the sluggish scrolling), and also the effect of triggering a `scrollend` event.