- 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)