Title: [292316] trunk/Source
Revision
292316
Author
[email protected]
Date
2022-04-04 14:16:05 -0700 (Mon, 04 Apr 2022)

Log Message

[macOS] Add helper methods to install and uninstall VKCImageAnalysisOverlayView
https://bugs.webkit.org/show_bug.cgi?id=238714

Reviewed by Tim Horton.

Source/WebCore/PAL:

Add soft-linking support for VKCImageAnalysisOverlayView. See WebKit/ChangeLog for more details.

* pal/cocoa/VisionKitCoreSoftLink.h:
* pal/cocoa/VisionKitCoreSoftLink.mm:

Source/WebKit:

Add helper methods for adding and removing a temporary VKCImageAnalysisOverlayView as a subview of WKWebView.
See below for more details. No change in behavior (yet).

* UIProcess/Cocoa/WebViewImpl.h:
(WebKit::WebViewImpl::imageAnalysisInteractionBounds const):
(WebKit::WebViewImpl::imageAnalysisOverlayView const):
* UIProcess/Cocoa/WebViewImpl.mm:
(WebKit::WebViewImpl::processImageAnalyzerRequest):

Pull logic for processing an image analyzer request and invoking the completion handler on the main thread (via
`callOnMainRunLoop`) out into a separate helper method (to be used in a subsequent patch).

(WebKit::WebViewImpl::requestTextRecognition):
(-[WKImageAnalysisOverlayViewDelegate initWithWebViewImpl:]):

Add an Objective-C object that acts as a delegate for the image analysis overlay view. This is done to correctly
position the overlay, but also for a couple of additonal reasons below.

(-[WKImageAnalysisOverlayViewDelegate dealloc]):
(-[WKImageAnalysisOverlayViewDelegate observeValueForKeyPath:ofObject:change:context:]):

Add logic to steal first responder status away from VKCImageAnalysisOverlayView's internal text selection view
and restore it to the web view when there is no longer an active text selection in the overlay. This ensures
that key events are only routed to the image analysis overlay view in the case where the overlay actually
contains a text selection.

(-[WKImageAnalysisOverlayViewDelegate firstResponderIsInsideImageOverlay]):
(-[WKImageAnalysisOverlayViewDelegate imageAnalysisOverlay:shouldHandleKeyDownEvent:]):

Never allow the image overlay view to override Escape key handling.

(-[WKImageAnalysisOverlayViewDelegate contentsRectForImageAnalysisOverlayView:]):
(WebKit::WebViewImpl::installImageAnalysisOverlayView):
(WebKit::WebViewImpl::uninstallImageAnalysisOverlayView):
(WebKit::WebViewImpl::imageAnalysisOverlayViewHasCursorAtPoint const):

Allow the image analysis overlay view to set the mouse cursor when the mouse is over interactable content.

* UIProcess/mac/PageClientImplMac.mm:
(WebKit::PageClientImpl::setCursor):

Modified Paths

Diff

Modified: trunk/Source/WebCore/PAL/ChangeLog (292315 => 292316)


--- trunk/Source/WebCore/PAL/ChangeLog	2022-04-04 20:54:01 UTC (rev 292315)
+++ trunk/Source/WebCore/PAL/ChangeLog	2022-04-04 21:16:05 UTC (rev 292316)
@@ -1,3 +1,15 @@
+2022-04-04  Wenson Hsieh  <[email protected]>
+
+        [macOS] Add helper methods to install and uninstall VKCImageAnalysisOverlayView
+        https://bugs.webkit.org/show_bug.cgi?id=238714
+
+        Reviewed by Tim Horton.
+
+        Add soft-linking support for VKCImageAnalysisOverlayView. See WebKit/ChangeLog for more details.
+
+        * pal/cocoa/VisionKitCoreSoftLink.h:
+        * pal/cocoa/VisionKitCoreSoftLink.mm:
+
 2022-04-03  Tim Horton  <[email protected]>
 
         _WKDataTask doesn't work in macCatalyst

Modified: trunk/Source/WebCore/PAL/pal/cocoa/VisionKitCoreSoftLink.h (292315 => 292316)


--- trunk/Source/WebCore/PAL/pal/cocoa/VisionKitCoreSoftLink.h	2022-04-04 20:54:01 UTC (rev 292315)
+++ trunk/Source/WebCore/PAL/pal/cocoa/VisionKitCoreSoftLink.h	2022-04-04 21:16:05 UTC (rev 292316)
@@ -38,6 +38,7 @@
 SOFT_LINK_CLASS_FOR_HEADER(PAL, VKCImageAnalysis)
 #if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
 SOFT_LINK_CLASS_FOR_HEADER(PAL, VKCImageAnalysisInteraction)
+SOFT_LINK_CLASS_FOR_HEADER(PAL, VKCImageAnalysisOverlayView)
 #endif
 
 #if USE(APPLE_INTERNAL_SDK)

Modified: trunk/Source/WebCore/PAL/pal/cocoa/VisionKitCoreSoftLink.mm (292315 => 292316)


--- trunk/Source/WebCore/PAL/pal/cocoa/VisionKitCoreSoftLink.mm	2022-04-04 20:54:01 UTC (rev 292315)
+++ trunk/Source/WebCore/PAL/pal/cocoa/VisionKitCoreSoftLink.mm	2022-04-04 21:16:05 UTC (rev 292316)
@@ -38,6 +38,7 @@
 SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT_AND_IS_OPTIONAL(PAL, VisionKitCore, VKCImageAnalysis, PAL_EXPORT, true)
 #if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
 SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT_AND_IS_OPTIONAL(PAL, VisionKitCore, VKCImageAnalysisInteraction, PAL_EXPORT, true)
+SOFT_LINK_CLASS_FOR_SOURCE_WITH_EXPORT_AND_IS_OPTIONAL(PAL, VisionKitCore, VKCImageAnalysisOverlayView, PAL_EXPORT, true)
 #endif
 
 #if USE(APPLE_INTERNAL_SDK)

Modified: trunk/Source/WebKit/ChangeLog (292315 => 292316)


--- trunk/Source/WebKit/ChangeLog	2022-04-04 20:54:01 UTC (rev 292315)
+++ trunk/Source/WebKit/ChangeLog	2022-04-04 21:16:05 UTC (rev 292316)
@@ -1,3 +1,51 @@
+2022-04-04  Wenson Hsieh  <[email protected]>
+
+        [macOS] Add helper methods to install and uninstall VKCImageAnalysisOverlayView
+        https://bugs.webkit.org/show_bug.cgi?id=238714
+
+        Reviewed by Tim Horton.
+
+        Add helper methods for adding and removing a temporary VKCImageAnalysisOverlayView as a subview of WKWebView.
+        See below for more details. No change in behavior (yet).
+
+        * UIProcess/Cocoa/WebViewImpl.h:
+        (WebKit::WebViewImpl::imageAnalysisInteractionBounds const):
+        (WebKit::WebViewImpl::imageAnalysisOverlayView const):
+        * UIProcess/Cocoa/WebViewImpl.mm:
+        (WebKit::WebViewImpl::processImageAnalyzerRequest):
+
+        Pull logic for processing an image analyzer request and invoking the completion handler on the main thread (via
+        `callOnMainRunLoop`) out into a separate helper method (to be used in a subsequent patch).
+
+        (WebKit::WebViewImpl::requestTextRecognition):
+        (-[WKImageAnalysisOverlayViewDelegate initWithWebViewImpl:]):
+
+        Add an Objective-C object that acts as a delegate for the image analysis overlay view. This is done to correctly
+        position the overlay, but also for a couple of additonal reasons below.
+
+        (-[WKImageAnalysisOverlayViewDelegate dealloc]):
+        (-[WKImageAnalysisOverlayViewDelegate observeValueForKeyPath:ofObject:change:context:]):
+
+        Add logic to steal first responder status away from VKCImageAnalysisOverlayView's internal text selection view
+        and restore it to the web view when there is no longer an active text selection in the overlay. This ensures
+        that key events are only routed to the image analysis overlay view in the case where the overlay actually
+        contains a text selection.
+
+        (-[WKImageAnalysisOverlayViewDelegate firstResponderIsInsideImageOverlay]):
+        (-[WKImageAnalysisOverlayViewDelegate imageAnalysisOverlay:shouldHandleKeyDownEvent:]):
+
+        Never allow the image overlay view to override Escape key handling.
+
+        (-[WKImageAnalysisOverlayViewDelegate contentsRectForImageAnalysisOverlayView:]):
+        (WebKit::WebViewImpl::installImageAnalysisOverlayView):
+        (WebKit::WebViewImpl::uninstallImageAnalysisOverlayView):
+        (WebKit::WebViewImpl::imageAnalysisOverlayViewHasCursorAtPoint const):
+
+        Allow the image analysis overlay view to set the mouse cursor when the mouse is over interactable content.
+
+        * UIProcess/mac/PageClientImplMac.mm:
+        (WebKit::PageClientImpl::setCursor):
+
 2022-04-04  Youenn Fablet  <[email protected]>
 
         Service-Worker-Navigation-Preload header not being sent when Navigation Preload is enabled.

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h (292315 => 292316)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h	2022-04-04 20:54:01 UTC (rev 292315)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.h	2022-04-04 21:16:05 UTC (rev 292316)
@@ -61,6 +61,7 @@
 OBJC_CLASS WKDOMPasteMenuDelegate;
 OBJC_CLASS WKEditorUndoTarget;
 OBJC_CLASS WKFullScreenWindowController;
+OBJC_CLASS WKImageAnalysisOverlayViewDelegate;
 OBJC_CLASS WKImmediateActionController;
 OBJC_CLASS WKMouseTrackingObserver;
 OBJC_CLASS WKRevealItemPresenter;
@@ -86,6 +87,9 @@
 OBJC_CLASS WKPDFHUDView;
 #endif
 
+OBJC_CLASS VKCImageAnalysis;
+OBJC_CLASS VKCImageAnalysisOverlayView;
+
 namespace API {
 class HitTestResult;
 class Object;
@@ -595,6 +599,13 @@
     void computeHasImageAnalysisResults(const URL& imageURL, ShareableBitmap& imageBitmap, ImageAnalysisType, CompletionHandler<void(bool)>&&);
 #endif
 
+#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+    WebCore::FloatRect imageAnalysisInteractionBounds() const { return m_imageAnalysisInteractionBounds; }
+    VKCImageAnalysisOverlayView *imageAnalysisOverlayView() const { return m_imageAnalysisOverlayView.get(); }
+#endif
+
+    bool imageAnalysisOverlayViewHasCursorAtPoint(NSPoint locationInView) const;
+
     bool acceptsPreviewPanelControl(QLPreviewPanel *);
     void beginPreviewPanelControl(QLPreviewPanel *);
     void endPreviewPanelControl(QLPreviewPanel *);
@@ -677,6 +688,11 @@
     bool useMediaPlaybackControlsView() const;
     bool isRichlyEditableForTouchBar() const;
 
+#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+    void installImageAnalysisOverlayView(VKCImageAnalysis *);
+    void uninstallImageAnalysisOverlayView();
+#endif
+
     bool m_clientWantsMediaPlaybackControlsView { false };
     bool m_canCreateTouchBars { false };
     bool m_startedListeningToCustomizationEvents { false };
@@ -745,6 +761,7 @@
 
 #if ENABLE(IMAGE_ANALYSIS)
     CocoaImageAnalyzer *ensureImageAnalyzer();
+    int32_t processImageAnalyzerRequest(CocoaImageAnalyzerRequest *, CompletionHandler<void(CocoaImageAnalysis *, NSError *)>&&);
 #endif
 
     WeakObjCPtr<NSView<WebViewImplDelegate>> m_view;
@@ -891,6 +908,13 @@
     RetainPtr<CocoaImageAnalyzer> m_imageAnalyzer;
 #endif
 
+#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+    RetainPtr<VKCImageAnalysisOverlayView> m_imageAnalysisOverlayView;
+    RetainPtr<WKImageAnalysisOverlayViewDelegate> m_imageAnalysisOverlayViewDelegate;
+    uint32_t m_currentImageAnalysisRequestID { 0 };
+    WebCore::FloatRect m_imageAnalysisInteractionBounds;
+#endif
+
 #if HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)
     WeakObjCPtr<NSPopover> m_lastContextMenuTranslationPopover;
 #endif

Modified: trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm (292315 => 292316)


--- trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2022-04-04 20:54:01 UTC (rev 292315)
+++ trunk/Source/WebKit/UIProcess/Cocoa/WebViewImpl.mm	2022-04-04 21:16:05 UTC (rev 292316)
@@ -232,6 +232,15 @@
     return m_imageAnalyzer.get();
 }
 
+int32_t WebViewImpl::processImageAnalyzerRequest(CocoaImageAnalyzerRequest *request, CompletionHandler<void(CocoaImageAnalysis *, NSError *)>&& completion)
+{
+    return [ensureImageAnalyzer() processRequest:request progressHandler:nil completionHandler:makeBlockPtr([completion = WTFMove(completion)] (CocoaImageAnalysis *result, NSError *error) mutable {
+        callOnMainRunLoop([completion = WTFMove(completion), result = RetainPtr { result }, error = RetainPtr { error }] () mutable {
+            completion(result.get(), error.get());
+        });
+    }).get()];
+}
+
 static RetainPtr<CocoaImageAnalyzerRequest> createImageAnalyzerRequest(CGImageRef image, const URL& imageURL, const URL& pageURL, VKAnalysisTypes types)
 {
     auto request = createImageAnalyzerRequest(image, types);
@@ -264,12 +273,11 @@
 
     auto request = createImageAnalyzerRequest(cgImage.get(), imageURL, [NSURL _web_URLWithWTFString:m_page->currentURL()], VKAnalysisTypeText);
     auto startTime = MonotonicTime::now();
-    [ensureImageAnalyzer() processRequest:request.get() progressHandler:nil completionHandler:makeBlockPtr([completion = WTFMove(completion), startTime] (CocoaImageAnalysis *analysis, NSError *) mutable {
-        callOnMainRunLoop([completion = WTFMove(completion), result = makeTextRecognitionResult(analysis), startTime] () mutable {
-            RELEASE_LOG(Images, "Image analysis completed in %.0f ms (found text? %d)", (MonotonicTime::now() - startTime).milliseconds(), !result.isEmpty());
-            completion(WTFMove(result));
-        });
-    }).get()];
+    processImageAnalyzerRequest(request.get(), [completion = WTFMove(completion), startTime] (CocoaImageAnalysis *analysis, NSError *) mutable {
+        auto result = makeTextRecognitionResult(analysis);
+        RELEASE_LOG(Images, "Image analysis completed in %.0f ms (found text? %d)", (MonotonicTime::now() - startTime).milliseconds(), !result.isEmpty());
+        completion(WTFMove(result));
+    });
 }
 
 void WebViewImpl::computeHasImageAnalysisResults(const URL& imageURL, ShareableBitmap& imageBitmap, ImageAnalysisType type, CompletionHandler<void(bool)>&& completion)
@@ -1088,6 +1096,92 @@
 
 @end
 
+#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+
+@interface WKImageAnalysisOverlayViewDelegate : NSObject<VKCImageAnalysisOverlayViewDelegate>
+- (instancetype)initWithWebViewImpl:(WebKit::WebViewImpl&)impl;
+@end
+
+@implementation WKImageAnalysisOverlayViewDelegate {
+    WeakPtr<WebKit::WebViewImpl> _impl;
+    __weak VKCImageAnalysisOverlayView *_overlayView;
+    __weak NSResponder *_lastOverlayResponderView;
+}
+
+static void* imageOverlayObservationContext = &imageOverlayObservationContext;
+
+- (instancetype)initWithWebViewImpl:(WebKit::WebViewImpl&)impl
+{
+    if (!(self = [super init]))
+        return nil;
+
+    _impl = impl;
+    _overlayView = impl.imageAnalysisOverlayView();
+    [_overlayView addObserver:self forKeyPath:@"hasActiveTextSelection" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:imageOverlayObservationContext];
+    return self;
+}
+
+- (void)dealloc
+{
+    [_overlayView removeObserver:self forKeyPath:@"hasActiveTextSelection"];
+    [super dealloc];
+}
+
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
+{
+    if (context != imageOverlayObservationContext)
+        return;
+
+    BOOL oldHasActiveTextSelection = [change[NSKeyValueChangeOldKey] boolValue];
+    BOOL newHasActiveTextSelection = [change[NSKeyValueChangeNewKey] boolValue];
+    __weak auto webView = _impl ? _impl->view() : nil;
+    auto currentResponder = webView.window.firstResponder;
+    if (oldHasActiveTextSelection && !newHasActiveTextSelection) {
+        if (self.firstResponderIsInsideImageOverlay) {
+            _lastOverlayResponderView = currentResponder;
+            [webView.window makeFirstResponder:webView];
+        }
+    } else if (!oldHasActiveTextSelection && newHasActiveTextSelection) {
+        if (_lastOverlayResponderView && currentResponder != _lastOverlayResponderView)
+            [webView.window makeFirstResponder:_lastOverlayResponderView];
+    }
+}
+
+- (BOOL)firstResponderIsInsideImageOverlay
+{
+    if (!_impl)
+        return NO;
+
+    for (auto view = dynamic_objc_cast<NSView>(_impl->view().window.firstResponder); view; view = view.superview) {
+        if (view == _overlayView)
+            return YES;
+    }
+    return NO;
+}
+
+#pragma mark - VKCImageAnalysisOverlayViewDelegate
+
+- (BOOL)imageAnalysisOverlay:(VKCImageAnalysisOverlayView *)overlayView shouldHandleKeyDownEvent:(NSEvent *)event
+{
+    return ![event.charactersIgnoringModifiers isEqualToString:@"\e"];
+}
+
+- (CGRect)contentsRectForImageAnalysisOverlayView:(VKCImageAnalysisOverlayView *)overlayView
+{
+    if (!_impl)
+        return CGRectMake(0, 0, 1, 1);
+
+    auto unitInteractionRect = _impl->imageAnalysisInteractionBounds();
+    WebCore::FloatRect unobscuredRect = _impl->view().bounds;
+    unitInteractionRect.moveBy(-unobscuredRect.location());
+    unitInteractionRect.scale(1 / unobscuredRect.size());
+    return unitInteractionRect;
+}
+
+@end
+
+#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+
 namespace WebKit {
 
 NSTouchBar *WebViewImpl::makeTouchBar()
@@ -5834,6 +5928,45 @@
 
 #endif // ENABLE(REVEAL)
 
+#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+
+void WebViewImpl::installImageAnalysisOverlayView(VKCImageAnalysis *analysis)
+{
+    if (!m_imageAnalysisOverlayView) {
+        m_imageAnalysisOverlayView = adoptNS([PAL::allocVKCImageAnalysisOverlayViewInstance() initWithFrame:[m_view bounds]]);
+        m_imageAnalysisOverlayViewDelegate = adoptNS([[WKImageAnalysisOverlayViewDelegate alloc] initWithWebViewImpl:*this]);
+        [m_imageAnalysisOverlayView setDelegate:m_imageAnalysisOverlayViewDelegate.get()];
+        [m_imageAnalysisOverlayView setActiveInteractionTypes:VKImageAnalysisInteractionTypeTextSelection | VKImageAnalysisInteractionTypeDataDetectors];
+        [m_imageAnalysisOverlayView setWantsAutomaticContentsRectCalculation:NO];
+    }
+
+    [m_imageAnalysisOverlayView setAnalysis:analysis];
+    [m_view addSubview:m_imageAnalysisOverlayView.get()];
+}
+
+void WebViewImpl::uninstallImageAnalysisOverlayView()
+{
+    if (!m_imageAnalysisOverlayView)
+        return;
+
+    [m_imageAnalysisOverlayView removeFromSuperview];
+    m_imageAnalysisOverlayViewDelegate = nil;
+    m_imageAnalysisOverlayView = nil;
+    m_imageAnalysisInteractionBounds = { };
+}
+
+#endif // ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+
+bool WebViewImpl::imageAnalysisOverlayViewHasCursorAtPoint(NSPoint locationInView) const
+{
+#if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS)
+    return [m_imageAnalysisOverlayView interactableItemExistsAtPoint:locationInView];
+#else
+    UNUSED_PARAM(locationInView);
+    return false;
+#endif
+}
+
 } // namespace WebKit
 
 #endif // PLATFORM(MAC)

Modified: trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.mm (292315 => 292316)


--- trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.mm	2022-04-04 20:54:01 UTC (rev 292315)
+++ trunk/Source/WebKit/UIProcess/mac/PageClientImplMac.mm	2022-04-04 21:16:05 UTC (rev 292316)
@@ -322,7 +322,8 @@
     if (!window)
         return;
 
-    if ([window windowNumber] != [NSWindow windowNumberAtPoint:[NSEvent mouseLocation] belowWindowWithWindowNumber:0])
+    auto mouseLocationInScreen = NSEvent.mouseLocation;
+    if (window.windowNumber != [NSWindow windowNumberAtPoint:mouseLocationInScreen belowWindowWithWindowNumber:0])
         return;
 
     NSCursor *platformCursor = cursor.platformCursor();
@@ -329,6 +330,9 @@
     if ([NSCursor currentCursor] == platformCursor)
         return;
 
+    if (m_impl->imageAnalysisOverlayViewHasCursorAtPoint([m_view convertPoint:mouseLocationInScreen fromView:nil]))
+        return;
+
     [platformCursor set];
 
     if (cursor.type() == WebCore::Cursor::Type::None) {
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to