Title: [278394] trunk/Source/WebKit
Revision
278394
Author
wenson_hs...@apple.com
Date
2021-06-02 21:59:05 -0700 (Wed, 02 Jun 2021)

Log Message

[iOS] Show data detector context menu on long press inside image overlays
https://bugs.webkit.org/show_bug.cgi?id=226559
<rdar://problem/78789078>

Reviewed by Tim Horton.

Add additional support for data detectors that appear inside image overlays on iOS.

* Shared/ImageExtractionUpdateResult.h: Added.

Turn the `bool` propagated back to the UI process when calling `updateWithImageExtractionResult` into a separate
three-state enum instead; see changes below for more details.

* Shared/ios/InteractionInformationAtPosition.h:
* Shared/ios/InteractionInformationAtPosition.mm:
(WebKit::InteractionInformationAtPosition::encode const):
(WebKit::InteractionInformationAtPosition::decode):

Make some minor adjustments to `InteractionInformationAtPosition`:

-   Add `dataDetectorBounds`, which determines the bounds in root view coordinates of the data detector result
    corresponding to the hit-tested element.

-   Encode and decode `dataDetectorResults`, even if `isDataDetectorLink` is `false`. Unless the data detector
    is inside an image overlay, this (effectively) has no impact, since `dataDetectorResults` was previously
    only set if `isDataDetectorLink` was true.

* UIProcess/WebPageProxy.cpp:
(WebKit::WebPageProxy::updateWithImageExtractionResult):
* UIProcess/WebPageProxy.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView dataDetectionContextForPositionInformation:]):

Let `dataDetectorResults` take precedence over regular `bounds` when returning the context for the data
detector menu configuration.

(-[WKContentView positionInformationHasImageOverlayDataDetector]):

Add a helper method that returns `YES` in the case where the currently cached position information object
contains a text data detection result inside an image overlay.

(-[WKContentView _createTargetedContextMenuHintPreviewIfPossible]):

Use `dataDetectorBounds` instead of `bounds` when creating a fallback targeted preview for a data detection
result in an image overlay.

(-[WKContentView continueContextMenuInteraction:]):
(-[WKContentView continueContextMenuInteractionWithDataDetectors:]):

Adjust these codepaths so that we'll continue through to the data detector case instead of bailing early in the
case where both `isImageOverlayText` is set, and `dataDetectionResults` exist.

* WebKit.xcodeproj/project.pbxproj:
* WebProcess/WebPage/WebPage.cpp:
(WebKit::WebPage::findDataDetectionResultElementInImageOverlay):

Add a static helper to locate a data detector element underneath the given point, inside the given element's
image overlay in the user agent shadow root. Note that we check each of the element's bounds instead of using
a hit-test because we normally just hit-test to the text containers instead of the data detector containers.

(WebKit::WebPage::updateWithImageExtractionResult):
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::dataDetectorLinkPositionInformation):
(WebKit::dataDetectorImageOverlayPositionInformation):

Add a static helper function to populate the given `InteractionInformationAtPosition`, if it's over a data
detection result inside an image overlay.

(WebKit::elementPositionInformation): Call the above helper function.

Modified Paths

Added Paths

Diff

Modified: trunk/Source/WebKit/ChangeLog (278393 => 278394)


--- trunk/Source/WebKit/ChangeLog	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/ChangeLog	2021-06-03 04:59:05 UTC (rev 278394)
@@ -1,3 +1,77 @@
+2021-06-02  Wenson Hsieh  <wenson_hs...@apple.com>
+
+        [iOS] Show data detector context menu on long press inside image overlays
+        https://bugs.webkit.org/show_bug.cgi?id=226559
+        <rdar://problem/78789078>
+
+        Reviewed by Tim Horton.
+
+        Add additional support for data detectors that appear inside image overlays on iOS.
+
+        * Shared/ImageExtractionUpdateResult.h: Added.
+
+        Turn the `bool` propagated back to the UI process when calling `updateWithImageExtractionResult` into a separate
+        three-state enum instead; see changes below for more details.
+
+        * Shared/ios/InteractionInformationAtPosition.h:
+        * Shared/ios/InteractionInformationAtPosition.mm:
+        (WebKit::InteractionInformationAtPosition::encode const):
+        (WebKit::InteractionInformationAtPosition::decode):
+
+        Make some minor adjustments to `InteractionInformationAtPosition`:
+
+        -   Add `dataDetectorBounds`, which determines the bounds in root view coordinates of the data detector result
+            corresponding to the hit-tested element.
+
+        -   Encode and decode `dataDetectorResults`, even if `isDataDetectorLink` is `false`. Unless the data detector
+            is inside an image overlay, this (effectively) has no impact, since `dataDetectorResults` was previously
+            only set if `isDataDetectorLink` was true.
+
+        * UIProcess/WebPageProxy.cpp:
+        (WebKit::WebPageProxy::updateWithImageExtractionResult):
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView dataDetectionContextForPositionInformation:]):
+
+        Let `dataDetectorResults` take precedence over regular `bounds` when returning the context for the data
+        detector menu configuration.
+
+        (-[WKContentView positionInformationHasImageOverlayDataDetector]):
+
+        Add a helper method that returns `YES` in the case where the currently cached position information object
+        contains a text data detection result inside an image overlay.
+
+        (-[WKContentView _createTargetedContextMenuHintPreviewIfPossible]):
+
+        Use `dataDetectorBounds` instead of `bounds` when creating a fallback targeted preview for a data detection
+        result in an image overlay.
+
+        (-[WKContentView continueContextMenuInteraction:]):
+        (-[WKContentView continueContextMenuInteractionWithDataDetectors:]):
+
+        Adjust these codepaths so that we'll continue through to the data detector case instead of bailing early in the
+        case where both `isImageOverlayText` is set, and `dataDetectionResults` exist.
+
+        * WebKit.xcodeproj/project.pbxproj:
+        * WebProcess/WebPage/WebPage.cpp:
+        (WebKit::WebPage::findDataDetectionResultElementInImageOverlay):
+
+        Add a static helper to locate a data detector element underneath the given point, inside the given element's
+        image overlay in the user agent shadow root. Note that we check each of the element's bounds instead of using
+        a hit-test because we normally just hit-test to the text containers instead of the data detector containers.
+
+        (WebKit::WebPage::updateWithImageExtractionResult):
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::dataDetectorLinkPositionInformation):
+        (WebKit::dataDetectorImageOverlayPositionInformation):
+
+        Add a static helper function to populate the given `InteractionInformationAtPosition`, if it's over a data
+        detection result inside an image overlay.
+
+        (WebKit::elementPositionInformation): Call the above helper function.
+
 2021-06-02  Alex Christensen  <achristen...@webkit.org>
 
         Fix WPT test resource-timing/cross-origin-redirects.html

Added: trunk/Source/WebKit/Shared/ImageExtractionUpdateResult.h (0 => 278394)


--- trunk/Source/WebKit/Shared/ImageExtractionUpdateResult.h	                        (rev 0)
+++ trunk/Source/WebKit/Shared/ImageExtractionUpdateResult.h	2021-06-03 04:59:05 UTC (rev 278394)
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2021 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#if ENABLE(IMAGE_EXTRACTION)
+
+#include <wtf/EnumTraits.h>
+
+namespace WebKit {
+
+enum class ImageExtractionUpdateResult : uint8_t {
+    NoText,
+    Text,
+    DataDetector,
+};
+
+} // namespace WebKit
+
+namespace WTF {
+
+template<> struct EnumTraits<WebKit::ImageExtractionUpdateResult> {
+    using values = EnumValues<
+        WebKit::ImageExtractionUpdateResult,
+        WebKit::ImageExtractionUpdateResult::NoText,
+        WebKit::ImageExtractionUpdateResult::Text,
+        WebKit::ImageExtractionUpdateResult::DataDetector
+    >;
+};
+
+} // namespace WTF
+
+#endif // ENABLE(IMAGE_EXTRACTION)

Modified: trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.h (278393 => 278394)


--- trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.h	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.h	2021-06-03 04:59:05 UTC (rev 278394)
@@ -94,6 +94,7 @@
 #if ENABLE(DATA_DETECTION)
     String dataDetectorIdentifier;
     RetainPtr<NSArray> dataDetectorResults;
+    WebCore::IntRect dataDetectorBounds;
 #endif
 
     std::optional<WebCore::ElementContext> elementContext;

Modified: trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.mm (278393 => 278394)


--- trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.mm	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/Shared/ios/InteractionInformationAtPosition.mm	2021-06-03 04:59:05 UTC (rev 278394)
@@ -77,10 +77,9 @@
     encoder << handle;
 #if ENABLE(DATA_DETECTION)
     encoder << isDataDetectorLink;
-    if (isDataDetectorLink) {
-        encoder << dataDetectorIdentifier;
-        encoder << dataDetectorResults;
-    }
+    encoder << dataDetectorIdentifier;
+    encoder << dataDetectorResults;
+    encoder << dataDetectorBounds;
 #endif
 #if ENABLE(DATALIST_ELEMENT)
     encoder << preventTextInteraction;
@@ -189,17 +188,18 @@
 #if ENABLE(DATA_DETECTION)
     if (!decoder.decode(result.isDataDetectorLink))
         return false;
-    
-    if (result.isDataDetectorLink) {
-        if (!decoder.decode(result.dataDetectorIdentifier))
-            return false;
 
-        auto dataDetectorResults = IPC::decode<NSArray>(decoder, @[ [NSArray class], getDDScannerResultClass() ]);
-        if (!dataDetectorResults)
-            return false;
+    if (!decoder.decode(result.dataDetectorIdentifier))
+        return false;
 
-        result.dataDetectorResults = WTFMove(*dataDetectorResults);
-    }
+    auto dataDetectorResults = IPC::decode<NSArray>(decoder, @[ NSArray.class, getDDScannerResultClass() ]);
+    if (!dataDetectorResults)
+        return false;
+
+    result.dataDetectorResults = WTFMove(*dataDetectorResults);
+
+    if (!decoder.decode(result.dataDetectorBounds))
+        return false;
 #endif
 
 #if ENABLE(DATALIST_ELEMENT)

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.cpp (278393 => 278394)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.cpp	2021-06-03 04:59:05 UTC (rev 278394)
@@ -66,6 +66,7 @@
 #include "EventDispatcherMessages.h"
 #include "FormDataReference.h"
 #include "FrameInfoData.h"
+#include "ImageExtractionUpdateResult.h"
 #include "LegacyGlobalSettings.h"
 #include "LoadParameters.h"
 #include "Logging.h"
@@ -8481,10 +8482,10 @@
     pageClient().computeCanRevealImage(imageURL, imageBitmap, WTFMove(completion));
 }
 
-void WebPageProxy::updateWithImageExtractionResult(ImageExtractionResult&& results, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(bool textExistsAtLocation)>&& completionHandler)
+void WebPageProxy::updateWithImageExtractionResult(ImageExtractionResult&& results, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&& completionHandler)
 {
     if (!hasRunningProcess()) {
-        completionHandler(false);
+        completionHandler(ImageExtractionUpdateResult::NoText);
         return;
     }
 

Modified: trunk/Source/WebKit/UIProcess/WebPageProxy.h (278393 => 278394)


--- trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/UIProcess/WebPageProxy.h	2021-06-03 04:59:05 UTC (rev 278394)
@@ -406,6 +406,7 @@
 struct WebPopupItem;
 struct WebSpeechSynthesisVoice;
 
+enum class ImageExtractionUpdateResult : uint8_t;
 enum class NegotiatedLegacyTLS : bool;
 enum class ProcessSwapRequestedByClient : bool;
 enum class UndoOrRedo : bool;
@@ -1664,7 +1665,7 @@
 
 #if ENABLE(IMAGE_EXTRACTION)
     void requestImageExtraction(const URL& imageURL, const ShareableBitmap::Handle& imageData, CompletionHandler<void(WebCore::ImageExtractionResult&&)>&&);
-    void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(bool textExistsAtLocation)>&&);
+    void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&&);
     void computeCanRevealImage(const URL& imageURL, ShareableBitmap& imageBitmap, CompletionHandler<void(bool)>&&);
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (278393 => 278394)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2021-06-03 04:59:05 UTC (rev 278394)
@@ -7523,6 +7523,8 @@
     CGRect sourceRect;
     if (positionInformation.isLink)
         sourceRect = positionInformation.linkIndicator.textBoundingRectInRootViewCoordinates;
+    else if (!positionInformation.dataDetectorBounds.isEmpty())
+        sourceRect = positionInformation.dataDetectorBounds;
     else
         sourceRect = positionInformation.bounds;
 
@@ -8460,6 +8462,11 @@
     return _contextMenuInteractionTargetedPreview.get();
 }
 
+- (BOOL)positionInformationHasImageOverlayDataDetector
+{
+    return _positionInformation.isImageOverlayText && [_positionInformation.dataDetectorResults count];
+}
+
 - (UITargetedPreview *)_createTargetedContextMenuHintPreviewIfPossible
 {
     RetainPtr<UITargetedPreview> targetedPreview;
@@ -8474,8 +8481,10 @@
         targetedPreview = createTargetedPreview(image.get(), self, self.containerForContextMenuHintPreviews, _positionInformation.bounds, { }, nil);
     }
 
-    if (!targetedPreview)
-        targetedPreview = createFallbackTargetedPreview(self, self.containerForContextMenuHintPreviews, _positionInformation.bounds, nil);
+    if (!targetedPreview) {
+        auto boundsForFallbackPreview = self.positionInformationHasImageOverlayDataDetector ? _positionInformation.dataDetectorBounds : _positionInformation.bounds;
+        targetedPreview = createFallbackTargetedPreview(self, self.containerForContextMenuHintPreviews, boundsForFallbackPreview, nil);
+    }
 
     [self _updateTargetedPreviewScrollViewUsingContainerScrollingNodeID:_positionInformation.containerScrollingNodeID];
 
@@ -10281,7 +10290,7 @@
     if (!_positionInformation.touchCalloutEnabled)
         return continueWithContextMenuConfiguration(nil);
 
-    if (!_positionInformation.isLink && !_positionInformation.isImage && !_positionInformation.isAttachment)
+    if (!_positionInformation.isLink && !_positionInformation.isImage && !_positionInformation.isAttachment && !self.positionInformationHasImageOverlayDataDetector)
         return continueWithContextMenuConfiguration(nil);
 
     URL linkURL = _positionInformation.url;
@@ -10405,7 +10414,7 @@
 #if ENABLE(DATA_DETECTION)
         // FIXME: Support _javascript_ urls here. But make sure they don't show a preview.
         // <rdar://problem/50572283>
-        if (!linkURL.protocolIsInHTTPFamily() && !WebCore::DataDetection::canBePresentedByDataDetectors(linkURL)) {
+        if (!linkURL.protocolIsInHTTPFamily() && !WebCore::DataDetection::canBePresentedByDataDetectors(linkURL) && ![strongSelf positionInformationHasImageOverlayDataDetector]) {
             continueWithContextMenuConfiguration(nil);
             return;
         }
@@ -10449,20 +10458,29 @@
 }
 
 #if ENABLE(DATA_DETECTION)
+
 - (void)continueContextMenuInteractionWithDataDetectors:(void(^)(UIContextMenuConfiguration *))continueWithContextMenuConfiguration
 {
     BEGIN_BLOCK_OBJC_EXCEPTIONS
     auto ddContextMenuActionClass = getDDContextMenuActionClass();
-    URL linkURL = _positionInformation.url;
-    NSDictionary *context = [self dataDetectionContextForPositionInformation:_positionInformation];
-    UIContextMenuConfiguration *configurationFromDD = [ddContextMenuActionClass contextMenuConfigurationForURL:linkURL identifier:_positionInformation.dataDetectorIdentifier selectedText:[self selectedText] results:_positionInformation.dataDetectorResults.get() inView:self context:context menuIdentifier:nil];
+    auto context = retainPtr([self dataDetectionContextForPositionInformation:_positionInformation]);
+    RetainPtr<UIContextMenuConfiguration> configurationFromDataDetectors;
+
+    if (self.positionInformationHasImageOverlayDataDetector) {
+        DDScannerResult *scannerResult = [_positionInformation.dataDetectorResults firstObject];
+        configurationFromDataDetectors = [ddContextMenuActionClass contextMenuConfigurationWithResult:scannerResult.coreResult inView:self context:context.get() menuIdentifier:nil];
+    } else {
+        configurationFromDataDetectors = [ddContextMenuActionClass contextMenuConfigurationForURL:_positionInformation.url identifier:_positionInformation.dataDetectorIdentifier selectedText:[self selectedText] results:_positionInformation.dataDetectorResults.get() inView:self context:context.get() menuIdentifier:nil];
+        _page->startInteractionWithPositionInformation(_positionInformation);
+    }
+
     _contextMenuActionProviderDelegateNeedsOverride = YES;
-    _page->startInteractionWithPositionInformation(_positionInformation);
-    continueWithContextMenuConfiguration(configurationFromDD);
+    continueWithContextMenuConfiguration(configurationFromDataDetectors.get());
     END_BLOCK_OBJC_EXCEPTIONS
 }
-#endif
 
+#endif // ENABLE(DATA_DETECTION)
+
 - (NSArray<UIMenuElement *> *)_contextMenuInteraction:(UIContextMenuInteraction *)interaction overrideSuggestedActionsForConfiguration:(UIContextMenuConfiguration *)configuration
 {
     // If we're here we're in the legacy path, which ignores the suggested actions anyway.

Modified: trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj (278393 => 278394)


--- trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/WebKit.xcodeproj/project.pbxproj	2021-06-03 04:59:05 UTC (rev 278394)
@@ -5985,6 +5985,7 @@
 		F4975CF12624B80A003C626E /* WKImageExtractionPreviewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WKImageExtractionPreviewController.h; sourceTree = "<group>"; };
 		F4975CF32624B918003C626E /* WKImageExtractionPreviewController.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKImageExtractionPreviewController.mm; sourceTree = "<group>"; };
 		F4A6D6BB254CA3E900B65FAA /* SharedDisplayListHandle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SharedDisplayListHandle.h; sourceTree = "<group>"; };
+		F4A7CE842667EB4E00228685 /* ImageExtractionUpdateResult.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ImageExtractionUpdateResult.h; sourceTree = "<group>"; };
 		F4AC655E22A3140E00A05607 /* WebPreferencesDefaultValuesIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = WebPreferencesDefaultValuesIOS.mm; path = ios/WebPreferencesDefaultValuesIOS.mm; sourceTree = "<group>"; };
 		F4B378D021DDBBAB0095A378 /* WebUndoStepID.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = WebUndoStepID.h; sourceTree = "<group>"; };
 		F4BA33F025757E89000A3CE8 /* WKImageExtractionGestureRecognizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = WKImageExtractionGestureRecognizer.h; path = ios/WKImageExtractionGestureRecognizer.h; sourceTree = "<group>"; };
@@ -6719,6 +6720,7 @@
 				46AC532425DED81E003B57EC /* GPUProcessConnectionParameters.h */,
 				F40BBB40257FF46E0067463A /* GPUProcessWakeupMessageArguments.h */,
 				1AC75A1A1B3368270056745B /* HangDetectionDisabler.h */,
+				F4A7CE842667EB4E00228685 /* ImageExtractionUpdateResult.h */,
 				BCCF6B2312C93E7A008F9C35 /* ImageOptions.h */,
 				999B7ED82550E4A800F450A4 /* InspectorExtensionTypes.cpp */,
 				99BE3B1625433B9400C6551C /* InspectorExtensionTypes.h */,

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp (278393 => 278394)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.cpp	2021-06-03 04:59:05 UTC (rev 278394)
@@ -40,6 +40,7 @@
 #include "FormDataReference.h"
 #include "FrameTreeNodeData.h"
 #include "GeolocationPermissionRequestManager.h"
+#include "ImageExtractionUpdateResult.h"
 #include "InjectUserScriptImmediately.h"
 #include "InjectedBundle.h"
 #include "InjectedBundleScriptWorld.h"
@@ -4063,6 +4064,23 @@
     completionHandler(WTFMove(mainFrameResult));
 }
 
+std::optional<std::pair<Ref<WebCore::HTMLElement>, WebCore::IntRect>> WebPage::findDataDetectionResultElementInImageOverlay(const FloatPoint& location, const HTMLElement& imageOverlayHost)
+{
+    Vector<Ref<HTMLElement>> dataDetectorElements;
+    for (auto& child : descendantsOfType<HTMLElement>(*imageOverlayHost.shadowRoot())) {
+        if (child.isImageOverlayDataDetectorResult())
+            dataDetectorElements.append(child);
+    }
+
+    for (auto& element : dataDetectorElements) {
+        auto elementBounds = element->boundsInRootViewSpace();
+        if (elementBounds.contains(roundedIntPoint(location)))
+            return {{ WTFMove(element), elementBounds }};
+    }
+
+    return std::nullopt;
+}
+
 #endif // ENABLE(DATA_DETECTION)
 
 #if PLATFORM(COCOA)
@@ -7458,11 +7476,11 @@
     });
 }
 
-void WebPage::updateWithImageExtractionResult(ImageExtractionResult&& result, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(bool)>&& completionHandler)
+void WebPage::updateWithImageExtractionResult(ImageExtractionResult&& result, const ElementContext& context, const FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&& completionHandler)
 {
     auto elementToUpdate = elementForContext(context);
     if (!is<HTMLElement>(elementToUpdate)) {
-        completionHandler(false);
+        completionHandler(ImageExtractionUpdateResult::NoText);
         return;
     }
 
@@ -7474,12 +7492,22 @@
     });
 
     auto nodeAtLocation = makeRefPtr(hitTestResult.innerNonSharedNode());
-    if (!nodeAtLocation || nodeAtLocation->shadowHost() != elementToUpdate) {
-        completionHandler(false);
-        return;
-    }
+    auto updateResult = ([&] {
+        if (!nodeAtLocation || nodeAtLocation->shadowHost() != elementToUpdate || !HTMLElement::isInsideImageOverlay(*nodeAtLocation))
+            return ImageExtractionUpdateResult::NoText;
 
-    completionHandler(HTMLElement::isImageOverlayText(*nodeAtLocation));
+#if ENABLE(DATA_DETECTION)
+        if (findDataDetectionResultElementInImageOverlay(location, downcast<HTMLElement>(*elementToUpdate)))
+            return ImageExtractionUpdateResult::DataDetector;
+#endif
+
+        if (HTMLElement::isImageOverlayText(*nodeAtLocation))
+            return ImageExtractionUpdateResult::Text;
+
+        return ImageExtractionUpdateResult::NoText;
+    })();
+
+    completionHandler(updateResult);
 }
 
 #endif // ENABLE(IMAGE_EXTRACTION)

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.h (278393 => 278394)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.h	2021-06-03 04:59:05 UTC (rev 278394)
@@ -310,6 +310,7 @@
 
 enum class FindOptions : uint16_t;
 enum class DragControllerAction : uint8_t;
+enum class ImageExtractionUpdateResult : uint8_t;
 enum class SyntheticEditingCommandType : uint8_t;
 
 struct BackForwardListItemState;
@@ -1153,6 +1154,8 @@
     void setDataDetectionResults(NSArray *);
     void detectDataInAllFrames(uint64_t, CompletionHandler<void(const DataDetectionResult&)>&&);
     void removeDataDetectedLinks(CompletionHandler<void(const DataDetectionResult&)>&&);
+    void handleClickForDataDetectionResult(const WebCore::DataDetectorElementInfo&, const WebCore::IntPoint&);
+    static std::optional<std::pair<Ref<WebCore::HTMLElement>, WebCore::IntRect>> findDataDetectionResultElementInImageOverlay(const WebCore::FloatPoint& locationInRootView, const WebCore::HTMLElement& host);
 #endif
 
     unsigned extendIncrementalRenderingSuppression();
@@ -1176,10 +1179,6 @@
     void handleSelectionServiceClick(WebCore::FrameSelection&, const Vector<String>& telephoneNumbers, const WebCore::IntPoint&);
 #endif
 
-#if ENABLE(DATA_DETECTION)
-    void handleClickForDataDetectionResult(const WebCore::DataDetectorElementInfo&, const WebCore::IntPoint&);
-#endif
-
     void didChangeScrollOffsetForFrame(WebCore::Frame*);
 
     void setMainFrameProgressCompleted(bool completed) { m_mainFrameProgressCompleted = completed; }
@@ -1404,7 +1403,7 @@
 
 #if ENABLE(IMAGE_EXTRACTION)
     void requestImageExtraction(WebCore::Element&, CompletionHandler<void(RefPtr<WebCore::Element>&&)>&&);
-    void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(bool)>&&);
+    void updateWithImageExtractionResult(WebCore::ImageExtractionResult&&, const WebCore::ElementContext&, const WebCore::FloatPoint& location, CompletionHandler<void(ImageExtractionUpdateResult)>&&);
 #endif
 
 #if HAVE(TRANSLATION_UI_SERVICES) && ENABLE(CONTEXT_MENUS)

Modified: trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in (278393 => 278394)


--- trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/WebProcess/WebPage/WebPage.messages.in	2021-06-03 04:59:05 UTC (rev 278394)
@@ -643,6 +643,6 @@
 #endif
 
 #if ENABLE(IMAGE_EXTRACTION)
-    UpdateWithImageExtractionResult(struct WebCore::ImageExtractionResult result, struct WebCore::ElementContext element, WebCore::FloatPoint location) -> (bool textExistsAtLocation) Async
+    UpdateWithImageExtractionResult(struct WebCore::ImageExtractionResult result, struct WebCore::ElementContext element, WebCore::FloatPoint location) -> (enum:uint8_t WebKit::ImageExtractionUpdateResult result) Async
 #endif
 }

Modified: trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm (278393 => 278394)


--- trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-06-03 04:57:45 UTC (rev 278393)
+++ trunk/Source/WebKit/WebProcess/WebPage/ios/WebPageIOS.mm	2021-06-03 04:59:05 UTC (rev 278394)
@@ -148,6 +148,7 @@
 #import <wtf/SetForScope.h>
 #import <wtf/SoftLinking.h>
 #import <wtf/cocoa/Entitlements.h>
+#import <wtf/text/StringToIntegerConversion.h>
 #import <wtf/text/TextStream.h>
 
 #if ENABLE(ATTACHMENT_ELEMENT)
@@ -2747,6 +2748,7 @@
         return;
     
     info.isDataDetectorLink = true;
+    info.dataDetectorBounds = info.bounds;
     const int dataDetectionExtendedContextLength = 350;
     info.dataDetectorIdentifier = DataDetection::dataDetectorIdentifier(element);
     if (auto* results = element.document().frame()->dataDetectionResultsIfExists())
@@ -2762,8 +2764,39 @@
         dataDetectionExtendedContextLength, SelectionDirection::Forward));
 }
 
-#endif
+static void dataDetectorImageOverlayPositionInformation(const HTMLElement& overlayHost, const InteractionInformationRequest& request, InteractionInformationAtPosition& info)
+{
+    auto frame = makeRefPtr(overlayHost.document().frame());
+    if (!frame)
+        return;
 
+    auto elementAndBounds = WebPage::findDataDetectionResultElementInImageOverlay(request.point, overlayHost);
+    if (!elementAndBounds)
+        return;
+
+    auto [foundElement, elementBounds] = *elementAndBounds;
+    auto identifierValue = parseInteger<uint64_t>(foundElement->attributeWithoutSynchronization(HTMLNames::x_apple_data_detectors_resultAttr));
+    if (!identifierValue)
+        return;
+
+    auto identifier = makeObjectIdentifier<ImageOverlayDataDetectionResultIdentifierType>(*identifierValue);
+    if (!identifier.isValid())
+        return;
+
+    auto* dataDetectionResults = frame->dataDetectionResultsIfExists();
+    if (!dataDetectionResults)
+        return;
+
+    auto dataDetectionResult = retainPtr(dataDetectionResults->imageOverlayDataDetectionResult(identifier));
+    if (!dataDetectionResult)
+        return;
+
+    info.dataDetectorBounds = WTFMove(elementBounds);
+    info.dataDetectorResults = @[ dataDetectionResult.get() ];
+}
+
+#endif // ENABLE(DATA_DETECTION)
+
 static std::optional<std::pair<RenderImage&, Image&>> imageRendererAndImage(Element& element)
 {
     if (!is<RenderImage>(element.renderer()))
@@ -2863,6 +2896,11 @@
         boundsPositionInformation(*renderer, info);
     }
 
+#if ENABLE(DATA_DETECTION)
+    if (info.isImageOverlayText && is<HTMLElement>(element))
+        dataDetectorImageOverlayPositionInformation(downcast<HTMLElement>(element), request, info);
+#endif
+
     info.elementContext = page.contextForElement(element);
 }
     
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to