Title: [291287] trunk/Source
Revision
291287
Author
wenson_hs...@apple.com
Date
2022-03-15 07:25:38 -0700 (Tue, 15 Mar 2022)

Log Message

[macOS] Tooltip no longer disappears after leaving hovered element
https://bugs.webkit.org/show_bug.cgi?id=237815
rdar://90187247

Reviewed by Tim Horton.

Source/WebKit:

On certain versions of macOS, AppKit's tooltip management system installs tracking areas (NSTrackingArea) using
`-addTrackingArea:` instead of tracking rects. This breaks our existing mechanism for keeping track of the
current tracking rect owner by overriding `-addTrackingRect:owner:userData:assumeInside:` (which assumes that
the only client that adds tracking rects is the tooltip manager). Since `-addTrackingRect:` isn't called,
`m_trackingRectOwner` remains nil, which causes both `sendToolTipMouseExited()` and `sendToolTipMouseEntered()`
to be no-ops.

To fix this, in the case where `m_trackingRectOwner` is nil, we instead fall back on `-[WKWebView trackingAreas]`
and look for an NSTrackingArea that's owned by AppKit's NSToolTipManager. We then send fake mouse enter/exit
events to this owner, the same way as we currently do.

* UIProcess/Cocoa/WebViewImpl.h:
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::addTrackingRect):
(WebKit::WebViewImpl::addTrackingRectWithTrackingNum):
(WebKit::WebViewImpl::addTrackingRectsWithTrackingNums):
(WebKit::WebViewImpl::toolTipTrackingAreaOwner const):
(WebKit::WebViewImpl::sendToolTipMouseExited):
(WebKit::WebViewImpl::sendToolTipMouseEntered):

Source/WebKitLegacy/mac:

Apply the same fix to legacy WebKit; see WebKit/ChangeLog for more information.

* WebView/WebHTMLView.mm:

Also wrap the owner in a WeakObjCPtr to avoid the possibility of calling methods on deallocated instances.

(-[WebHTMLView _toolTipOwnerForSendingMouseEvents]):
(-[WebHTMLView _sendToolTipMouseExited]):
(-[WebHTMLView _sendToolTipMouseEntered]):

Modified Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (291286 => 291287)


--- trunk/Source/WebKit/ChangeLog	2022-03-15 14:16:27 UTC (rev 291286)
+++ trunk/Source/WebKit/ChangeLog	2022-03-15 14:25:38 UTC (rev 291287)
@@ -1,3 +1,31 @@
+2022-03-15  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [macOS] Tooltip no longer disappears after leaving hovered element
+        https://bugs.webkit.org/show_bug.cgi?id=237815
+        rdar://90187247
+
+        Reviewed by Tim Horton.
+
+        On certain versions of macOS, AppKit's tooltip management system installs tracking areas (NSTrackingArea) using
+        `-addTrackingArea:` instead of tracking rects. This breaks our existing mechanism for keeping track of the
+        current tracking rect owner by overriding `-addTrackingRect:owner:userData:assumeInside:` (which assumes that
+        the only client that adds tracking rects is the tooltip manager). Since `-addTrackingRect:` isn't called,
+        `m_trackingRectOwner` remains nil, which causes both `sendToolTipMouseExited()` and `sendToolTipMouseEntered()`
+        to be no-ops.
+
+        To fix this, in the case where `m_trackingRectOwner` is nil, we instead fall back on `-[WKWebView trackingAreas]`
+        and look for an NSTrackingArea that's owned by AppKit's NSToolTipManager. We then send fake mouse enter/exit
+        events to this owner, the same way as we currently do.
+
+        * UIProcess/Cocoa/WebViewImpl.h:
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::addTrackingRect):
+        (WebKit::WebViewImpl::addTrackingRectWithTrackingNum):
+        (WebKit::WebViewImpl::addTrackingRectsWithTrackingNums):
+        (WebKit::WebViewImpl::toolTipTrackingAreaOwner const):
+        (WebKit::WebViewImpl::sendToolTipMouseExited):
+        (WebKit::WebViewImpl::sendToolTipMouseEntered):
+
 2022-03-15  Youenn Fablet  <you...@apple.com>
 
         Mark permission as denied if system forbids access to camera and/or microphone

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h (291286 => 291287)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h	2022-03-15 14:16:27 UTC (rev 291286)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h	2022-03-15 14:25:38 UTC (rev 291287)
@@ -737,6 +737,8 @@
 
     void viewWillMoveToWindowImpl(NSWindow *);
 
+    id toolTipOwnerForSendingMouseEvents() const;
+
 #if ENABLE(DRAG_SUPPORT)
     void sendDragEndToPage(CGPoint endPoint, NSDragOperation);
 #endif
@@ -820,7 +822,7 @@
     RetainPtr<NSTrackingArea> m_primaryTrackingArea;
 
     NSToolTipTag m_lastToolTipTag { 0 };
-    id m_trackingRectOwner { nil };
+    WeakObjCPtr<id> m_trackingRectOwner;
     void* m_trackingRectUserData { nullptr };
 
     RetainPtr<CALayer> m_rootLayer;

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm (291286 => 291287)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2022-03-15 14:16:27 UTC (rev 291286)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2022-03-15 14:25:38 UTC (rev 291287)
@@ -3883,7 +3883,7 @@
 
 NSTrackingRectTag WebViewImpl::addTrackingRect(CGRect, id owner, void* userData, bool assumeInside)
 {
-    ASSERT(m_trackingRectOwner == nil);
+    ASSERT(!m_trackingRectOwner);
     m_trackingRectOwner = owner;
     m_trackingRectUserData = userData;
     return TRACKING_RECT_TAG;
@@ -3892,7 +3892,7 @@
 NSTrackingRectTag WebViewImpl::addTrackingRectWithTrackingNum(CGRect, id owner, void* userData, bool assumeInside, int tag)
 {
     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
-    ASSERT(m_trackingRectOwner == nil);
+    ASSERT(!m_trackingRectOwner);
     m_trackingRectOwner = owner;
     m_trackingRectUserData = userData;
     return TRACKING_RECT_TAG;
@@ -3902,7 +3902,7 @@
 {
     ASSERT(count == 1);
     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
-    ASSERT(m_trackingRectOwner == nil);
+    ASSERT(!m_trackingRectOwner);
     m_trackingRectOwner = owner;
     m_trackingRectUserData = userDataList[0];
     trackingNums[0] = TRACKING_RECT_TAG;
@@ -3940,19 +3940,38 @@
     }
 }
 
+id WebViewImpl::toolTipOwnerForSendingMouseEvents() const
+{
+    if (id owner = m_trackingRectOwner.getAutoreleased())
+        return owner;
+
+    for (NSTrackingArea *trackingArea in view().trackingAreas) {
+        static Class managerClass;
+        static std::once_flag onceFlag;
+        std::call_once(onceFlag, [] {
+            managerClass = NSClassFromString(@"NSToolTipManager");
+        });
+
+        id owner = trackingArea.owner;
+        if ([owner class] == managerClass)
+            return owner;
+    }
+    return nil;
+}
+
 void WebViewImpl::sendToolTipMouseExited()
 {
     // Nothing matters except window, trackingNumber, and userData.
     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSEventTypeMouseExited
-                                                location:NSMakePoint(0, 0)
-                                           modifierFlags:0
-                                               timestamp:0
-                                            windowNumber:[m_view window].windowNumber
-                                                 context:NULL
-                                             eventNumber:0
-                                          trackingNumber:TRACKING_RECT_TAG
-                                                userData:m_trackingRectUserData];
-    [m_trackingRectOwner mouseExited:fakeEvent];
+        location:NSZeroPoint
+        modifierFlags:0
+        timestamp:0
+        windowNumber:[m_view window].windowNumber
+        context:nil
+        eventNumber:0
+        trackingNumber:TRACKING_RECT_TAG
+        userData:m_trackingRectUserData];
+    [toolTipOwnerForSendingMouseEvents() mouseExited:fakeEvent];
 }
 
 void WebViewImpl::sendToolTipMouseEntered()
@@ -3959,15 +3978,15 @@
 {
     // Nothing matters except window, trackingNumber, and userData.
     NSEvent *fakeEvent = [NSEvent enterExitEventWithType:NSEventTypeMouseEntered
-                                                location:NSMakePoint(0, 0)
-                                           modifierFlags:0
-                                               timestamp:0
-                                            windowNumber:[m_view window].windowNumber
-                                                 context:NULL
-                                             eventNumber:0
-                                          trackingNumber:TRACKING_RECT_TAG
-                                                userData:m_trackingRectUserData];
-    [m_trackingRectOwner mouseEntered:fakeEvent];
+        location:NSZeroPoint
+        modifierFlags:0
+        timestamp:0
+        windowNumber:[m_view window].windowNumber
+        context:nil
+        eventNumber:0
+        trackingNumber:TRACKING_RECT_TAG
+        userData:m_trackingRectUserData];
+    [toolTipOwnerForSendingMouseEvents() mouseEntered:fakeEvent];
 }
 
 NSString *WebViewImpl::stringForToolTip(NSToolTipTag tag)

Modified: trunk/Source/WebKitLegacy/mac/ChangeLog (291286 => 291287)


--- trunk/Source/WebKitLegacy/mac/ChangeLog	2022-03-15 14:16:27 UTC (rev 291286)
+++ trunk/Source/WebKitLegacy/mac/ChangeLog	2022-03-15 14:25:38 UTC (rev 291287)
@@ -1,3 +1,21 @@
+2022-03-15  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [macOS] Tooltip no longer disappears after leaving hovered element
+        https://bugs.webkit.org/show_bug.cgi?id=237815
+        rdar://90187247
+
+        Reviewed by Tim Horton.
+
+        Apply the same fix to legacy WebKit; see WebKit/ChangeLog for more information.
+
+        * WebView/WebHTMLView.mm:
+
+        Also wrap the owner in a WeakObjCPtr to avoid the possibility of calling methods on deallocated instances.
+
+        (-[WebHTMLView _toolTipOwnerForSendingMouseEvents]):
+        (-[WebHTMLView _sendToolTipMouseExited]):
+        (-[WebHTMLView _sendToolTipMouseEntered]):
+
 2022-03-12  Tim Horton  <timothy_hor...@apple.com>
 
         Adopt FALLBACK_PLATFORM_NAME in place of FALLBACK_PLATFORM

Modified: trunk/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm (291286 => 291287)


--- trunk/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm	2022-03-15 14:16:27 UTC (rev 291286)
+++ trunk/Source/WebKitLegacy/mac/WebView/WebHTMLView.mm	2022-03-15 14:25:38 UTC (rev 291287)
@@ -948,7 +948,7 @@
     RetainPtr<NSString> toolTip;
     NSToolTipTag lastToolTipTag;
 
-    id trackingRectOwner;
+    WeakObjCPtr<id> trackingRectOwner;
     void* trackingRectUserData;
     
     RetainPtr<NSTimer> autoscrollTimer;
@@ -1713,7 +1713,7 @@
 
 - (NSTrackingRectTag)addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside
 {
-    ASSERT(_private->trackingRectOwner == nil);
+    ASSERT(!_private->trackingRectOwner);
     _private->trackingRectOwner = owner;
     _private->trackingRectUserData = data;
     return TRACKING_RECT_TAG;
@@ -1722,7 +1722,7 @@
 - (NSTrackingRectTag)_addTrackingRect:(NSRect)rect owner:(id)owner userData:(void *)data assumeInside:(BOOL)assumeInside useTrackingNum:(int)tag
 {
     ASSERT(tag == 0 || tag == TRACKING_RECT_TAG);
-    ASSERT(_private->trackingRectOwner == nil);
+    ASSERT(!_private->trackingRectOwner);
     _private->trackingRectOwner = owner;
     _private->trackingRectUserData = data;
     return TRACKING_RECT_TAG;
@@ -1732,7 +1732,7 @@
 {
     ASSERT(count == 1);
     ASSERT(trackingNums[0] == 0 || trackingNums[0] == TRACKING_RECT_TAG);
-    ASSERT(_private->trackingRectOwner == nil);
+    ASSERT(!_private->trackingRectOwner);
     _private->trackingRectOwner = owner;
     _private->trackingRectUserData = userDataList[0];
     trackingNums[0] = TRACKING_RECT_TAG;
@@ -1773,6 +1773,25 @@
     }
 }
 
+- (id)_toolTipOwnerForSendingMouseEvents
+{
+    if (id owner = _private->trackingRectOwner.getAutoreleased())
+        return owner;
+
+    for (NSTrackingArea *trackingArea in self.trackingAreas) {
+        static Class managerClass;
+        static std::once_flag onceFlag;
+        std::call_once(onceFlag, [] {
+            managerClass = NSClassFromString(@"NSToolTipManager");
+        });
+
+        id owner = trackingArea.owner;
+        if ([owner class] == managerClass)
+            return owner;
+    }
+    return nil;
+}
+
 - (void)_sendToolTipMouseExited
 {
     // Nothing matters except window, trackingNumber, and userData.
@@ -1785,7 +1804,7 @@
         eventNumber:0
         trackingNumber:TRACKING_RECT_TAG
         userData:_private->trackingRectUserData];
-    [_private->trackingRectOwner mouseExited:fakeEvent];
+    [self._toolTipOwnerForSendingMouseEvents mouseExited:fakeEvent];
 }
 
 - (void)_sendToolTipMouseEntered
@@ -1800,7 +1819,7 @@
         eventNumber:0
         trackingNumber:TRACKING_RECT_TAG
         userData:_private->trackingRectUserData];
-    [_private->trackingRectOwner mouseEntered:fakeEvent];
+    [self._toolTipOwnerForSendingMouseEvents mouseEntered:fakeEvent];
 }
 
 #endif // PLATFORM(MAC)
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to