Branch: refs/heads/main
  Home:   https://github.com/WebKit/WebKit
  Commit: b2362a5d6b0dcee521bbc38c226ea2216e2422e7
      
https://github.com/WebKit/WebKit/commit/b2362a5d6b0dcee521bbc38c226ea2216e2422e7
  Author: Wenson Hsieh <wenson_hs...@apple.com>
  Date:   2023-03-27 (Mon, 27 Mar 2023)

  Changed paths:
    M 
LayoutTests/tiled-drawing/scrolling/fast-scroll-div-latched-mainframe-with-handler.html
    M Source/WebCore/WebCore.xcodeproj/project.pbxproj
    M Source/WebCore/page/scrolling/mac/ScrollerMac.mm
    M Source/WebCore/page/scrolling/mac/ScrollerPairMac.h
    M Source/WebCore/page/scrolling/mac/ScrollerPairMac.mm
    M Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.h
    M Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm
    A Source/WebCore/platform/mac/ScrollTypesMac.h

  Log Message:
  -----------
  [UI-side compositing] Safari occasionally crashes when scrolling underneath 
`NSScrollerImpPair`
https://bugs.webkit.org/show_bug.cgi?id=254484
rdar://107139674

Reviewed by Simon Fraser.

After the changes in 259592@main, we now update `NSScrollerImpPair` in response 
to various scrolling
-related events off of the scrolling thread, with a lock 
(`m_scrollerImpPairLock`) to prevent us
from concurrently updating the `NSScrollerImpPair`. However, this is actually 
insufficient to ensure
thread safety since `NSScrollerImpPair` internally schedules work on the main 
thread underneath
`-[NSScrollerImpPair endScrollGesture]`. As such, it's possible to end up 
calling methods on an
`NSTimer` that has already been destroyed.

Since we can't prevent `NSScrollerImpPair` from rescheduling its hide timer on 
the main thread, we
need to instead dispatch all of our other calls to update the imp pair on the 
main thread. To
achieve this, we introduce a new helper method on `ScrollerPairMac` to 
asynchronously dispatch to
the main thread from the scrolling thread with the `NSScrollerImpPair`, or call 
the block
immediately in the case where we're already on the main thread, and deploy this 
in all the places
where we currently update the `NSScrollerImpPair`. See below for more details.

I wasn't able to reproduce the crash in either a test, or manually in 
MiniBrowser/Safari, but I was
able to reproduce it and verify this fix by injecting a `sleep()` in 
`NSScrollerImpPair`, after the
hiding timer is deallocated but before the pointer is reset to nil.

* 
LayoutTests/tiled-drawing/scrolling/fast-scroll-div-latched-mainframe-with-handler.html:

Adjust a test to avoid flakiness after this change, since we now dispatch to 
the main thread before
updating the imp pair.

* Source/WebCore/WebCore.xcodeproj/project.pbxproj:
* Source/WebCore/page/scrolling/mac/ScrollerMac.mm:
(WebCore::ScrollerMac::attach):

Make this use the new getter for `scrollbarStyle()`.

(WebCore::ScrollerMac::setHostLayer):

Use another helper method here to avoid mutating `NSScrollerImpPair` from a 
background thread.

* Source/WebCore/page/scrolling/mac/ScrollerPairMac.h:

Make `ScrollerPairMac` thread-safe ref-counted, so that we can safely create 
references to it
from the scrolling thread, for blocks that are dispatched to the main thread.

We also remove `m_scrollerImpPairLock`, since all access to the 
`NSScrollerImpPair` now happens on
the main thread.

(WebCore::ScrollerPairMac::create):
(WebCore::ScrollerPairMac::lastKnownMousePosition const):
(WebCore::ScrollerPairMac::scrollbarStyle const):
(WebCore::ScrollerPairMac::scrollerImpVertical):
(WebCore::ScrollerPairMac::scrollerImpPair): Deleted.
(WebCore::ScrollerPairMac::WTF_RETURNS_LOCK): Deleted.
* Source/WebCore/page/scrolling/mac/ScrollerPairMac.mm:
(-[WebScrollerImpPairDelegateMac 
scrollerImpPair:updateScrollerStyleForNewRecommendedScrollerStyle:]):

Make this use the new `setScrollbarStyle` helpers, which internally dispatch 
onto the main thread
before attempting to access `NSScrollerImpPair`.

(WebCore::ScrollerPairMac::ScrollerPairMac):
(WebCore::ScrollerPairMac::init):

Drive-by adjustments: remove some unnecessary `WebCore::` namespacing, now that 
this entire class is
already in the WebCore namespace.

(WebCore::ScrollerPairMac::~ScrollerPairMac):

Also ensure that the underlying `NSScrollerImpPair` is also destroyed on the 
main thread.

(WebCore::ScrollerPairMac::handleWheelEventPhase):
(WebCore::ScrollerPairMac::viewWillStartLiveResize):
(WebCore::ScrollerPairMac::viewWillEndLiveResize):
(WebCore::ScrollerPairMac::contentsSizeChanged):
(WebCore::ScrollerPairMac::handleMouseEvent):
(WebCore::ScrollerPairMac::updateValues):

Deploy `ensureOnMainThreadWithProtectedThis` in various places where we update 
`NSScrollerImpPair`.

(WebCore::ScrollerPairMac::visibleSize const):
(WebCore::ScrollerPairMac::valuesForOrientation):
(WebCore::ScrollerPairMac::setVerticalScrollerImp):
(WebCore::ScrollerPairMac::setHorizontalScrollerImp):
(WebCore::ScrollerPairMac::setScrollbarStyle):
(WebCore::ScrollerPairMac::ensureOnMainThreadWithProtectedThis):

Add a helper here to make it easier to dispatch methods that mutate or update 
the `NSScrollerImpPair`
onto the main thread. If we're on the scrolling thread, this dispatches 
asynchronously on to the
main thread; otherwise, we'll run the block right away if we're already on the 
main thread.

* Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.h:

Turn `m_scrollerPair` into a `Ref`, now that the class is ref-counted.

* Source/WebCore/page/scrolling/mac/ScrollingTreeScrollingNodeDelegateMac.mm:
(WebCore::ScrollingTreeScrollingNodeDelegateMac::ScrollingTreeScrollingNodeDelegateMac):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::~ScrollingTreeScrollingNodeDelegateMac):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::updateFromStateNode):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::handleWheelEvent):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::updateScrollbarPainters):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::initScrollbars):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::updateScrollbarLayers):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::handleWheelEventPhase):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::handleMouseEventForScrollbars):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::viewWillStartLiveResize):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::viewWillEndLiveResize):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::viewSizeDidChange):
(WebCore::ScrollingTreeScrollingNodeDelegateMac::scrollbarStateForOrientation 
const):
* Source/WebCore/platform/mac/ScrollTypesMac.h: Added.
(WebCore::nsScrollerStyle):
(WebCore::scrollbarStyle):

Update all these call sites to use `->` instead of `.` when accessing 
`m_scrollerPair`.

Canonical link: https://commits.webkit.org/262194@main


_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to