Title: [246583] trunk/Source
Revision
246583
Author
[email protected]
Date
2019-06-19 02:43:57 -0700 (Wed, 19 Jun 2019)

Log Message

UIContextMenuInteraction implementation for WKContentView
https://bugs.webkit.org/show_bug.cgi?id=198986
<rdar://problem/51875189>

Reviewed by Andy Estes.

Source/WebCore/PAL:

Include + soft link DDContextMenuAction.

* pal/spi/ios/DataDetectorsUISPI.h:

Source/WebKit:

Implement UIContextMenuInteraction and its delegate as a
replacement for UIPreviewItemController in iOS 13.

In order to preserve existing behaviour as much as possible,
we check for the implementation of new WebKit API to configure
the menu. If that is not present, we attempt to convert
the results of the existing WebKit WKPreviewAction delegates
into something that works with UIContextMenus.

* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView setupInteraction]):
(-[WKContentView _contentsOfUserInterfaceItem:]):
(-[WKContentView _registerPreview]):
(-[WKContentView _unregisterPreview]):
(-[WKContentView _showLinkPreviewsPreferenceChanged:]):
(needsDeprecatedPreviewAPI):
(uiActionForPreviewAction):
(menuFromPreviewOrDefaults):
(titleForMenu):
(-[WKContentView assignLegacyDataForContextMenuInteraction]):
(-[WKContentView contextMenuInteraction:configurationForMenuAtLocation:]):
(-[WKContentView _contextMenuInteraction:configurationForMenuAtLocation:completion:]):
(-[WKContentView continueContextMenuInteraction:]):
(uiImageForImage):
(createTargetedPreview):
(-[WKContentView _targetedPreview]):
(-[WKContentView contextMenuInteraction:previewForHighlightingMenuWithConfiguration:]):
(-[WKContentView contextMenuInteractionWillPresent:]):
(-[WKContentView contextMenuInteraction:previewForDismissingMenuWithConfiguration:]):
(-[WKContentView contextMenuInteraction:willCommitWithAnimator:]):
(-[WKContentView contextMenuInteractionDidEnd:]):
(-[WKContentView shouldUsePreviewForLongPress]): Deleted.

Source/WTF:

Add USE_UICONTEXTMENU for iOS 13+.

* wtf/Platform.h:

Modified Paths

Diff

Modified: trunk/Source/WTF/ChangeLog (246582 => 246583)


--- trunk/Source/WTF/ChangeLog	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WTF/ChangeLog	2019-06-19 09:43:57 UTC (rev 246583)
@@ -1,3 +1,15 @@
+2019-06-18  Dean Jackson  <[email protected]>
+
+        UIContextMenuInteraction implementation for WKContentView
+        https://bugs.webkit.org/show_bug.cgi?id=198986
+        <rdar://problem/51875189>
+
+        Reviewed by Andy Estes.
+
+        Add USE_UICONTEXTMENU for iOS 13+.
+
+        * wtf/Platform.h:
+
 2019-06-18  Kenneth Russell  <[email protected]>
 
         Add preliminary ANGLE backend to WebCore

Modified: trunk/Source/WTF/wtf/Platform.h (246582 => 246583)


--- trunk/Source/WTF/wtf/Platform.h	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WTF/wtf/Platform.h	2019-06-19 09:43:57 UTC (rev 246583)
@@ -1585,3 +1585,7 @@
 #if (PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000 || PLATFORM(MAC) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101500)
 #define HAVE_APP_SSO 1
 #endif
+
+#if PLATFORM(IOS) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 130000
+#define USE_UICONTEXTMENU 1
+#endif

Modified: trunk/Source/WebCore/PAL/ChangeLog (246582 => 246583)


--- trunk/Source/WebCore/PAL/ChangeLog	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebCore/PAL/ChangeLog	2019-06-19 09:43:57 UTC (rev 246583)
@@ -1,3 +1,15 @@
+2019-06-18  Dean Jackson  <[email protected]>
+
+        UIContextMenuInteraction implementation for WKContentView
+        https://bugs.webkit.org/show_bug.cgi?id=198986
+        <rdar://problem/51875189>
+
+        Reviewed by Andy Estes.
+
+        Include + soft link DDContextMenuAction.
+
+        * pal/spi/ios/DataDetectorsUISPI.h:
+
 2019-06-18  Jiewen Tan  <[email protected]>
 
         Link to the new AppSSO private framework

Modified: trunk/Source/WebCore/PAL/pal/spi/ios/DataDetectorsUISPI.h (246582 => 246583)


--- trunk/Source/WebCore/PAL/pal/spi/ios/DataDetectorsUISPI.h	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebCore/PAL/pal/spi/ios/DataDetectorsUISPI.h	2019-06-19 09:43:57 UTC (rev 246583)
@@ -31,6 +31,9 @@
 #if USE(APPLE_INTERNAL_SDK)
 
 #import <DataDetectorsUI/DDAction.h>
+#if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
+#import <DataDetectorsUI/DDContextMenuAction.h>
+#endif
 #import <DataDetectorsUI/DDDetectionController.h>
 
 #else
@@ -46,6 +49,13 @@
 @property (readonly) NSString *actionUTI;
 @end
 
+#if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
+@class UIContextMenuConfiguration;
+@interface DDContextMenuAction
++ (UIContextMenuConfiguration *)contextMenuConfigurationWithURL:(NSURL *)URL inView:(UIView *)view context:(NSDictionary *)context menuIdentifier:(NSString *)menuIdentifier;
+@end
+#endif
+
 @protocol DDDetectionControllerInteractionDelegate <NSObject>
 @end
 
@@ -70,6 +80,9 @@
 @end
 
 SOFT_LINK_PRIVATE_FRAMEWORK(DataDetectorsUI)
+#if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
+SOFT_LINK_CLASS(DataDetectorsUI, DDContextMenuAction);
+#endif
 SOFT_LINK_CLASS(DataDetectorsUI, DDDetectionController)
 SOFT_LINK_CONSTANT(DataDetectorsUI, kDataDetectorsLeadingText, const NSString *)
 SOFT_LINK_CONSTANT(DataDetectorsUI, kDataDetectorsTrailingText, const NSString *)

Modified: trunk/Source/WebKit/ChangeLog (246582 => 246583)


--- trunk/Source/WebKit/ChangeLog	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebKit/ChangeLog	2019-06-19 09:43:57 UTC (rev 246583)
@@ -1,3 +1,45 @@
+2019-06-18  Dean Jackson  <[email protected]>
+
+        UIContextMenuInteraction implementation for WKContentView
+        https://bugs.webkit.org/show_bug.cgi?id=198986
+        <rdar://problem/51875189>
+
+        Reviewed by Andy Estes.
+
+        Implement UIContextMenuInteraction and its delegate as a
+        replacement for UIPreviewItemController in iOS 13.
+
+        In order to preserve existing behaviour as much as possible,
+        we check for the implementation of new WebKit API to configure
+        the menu. If that is not present, we attempt to convert
+        the results of the existing WebKit WKPreviewAction delegates
+        into something that works with UIContextMenus.
+
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView setupInteraction]):
+        (-[WKContentView _contentsOfUserInterfaceItem:]):
+        (-[WKContentView _registerPreview]):
+        (-[WKContentView _unregisterPreview]):
+        (-[WKContentView _showLinkPreviewsPreferenceChanged:]):
+        (needsDeprecatedPreviewAPI):
+        (uiActionForPreviewAction):
+        (menuFromPreviewOrDefaults):
+        (titleForMenu):
+        (-[WKContentView assignLegacyDataForContextMenuInteraction]):
+        (-[WKContentView contextMenuInteraction:configurationForMenuAtLocation:]):
+        (-[WKContentView _contextMenuInteraction:configurationForMenuAtLocation:completion:]):
+        (-[WKContentView continueContextMenuInteraction:]):
+        (uiImageForImage):
+        (createTargetedPreview):
+        (-[WKContentView _targetedPreview]):
+        (-[WKContentView contextMenuInteraction:previewForHighlightingMenuWithConfiguration:]):
+        (-[WKContentView contextMenuInteractionWillPresent:]):
+        (-[WKContentView contextMenuInteraction:previewForDismissingMenuWithConfiguration:]):
+        (-[WKContentView contextMenuInteraction:willCommitWithAnimator:]):
+        (-[WKContentView contextMenuInteractionDidEnd:]):
+        (-[WKContentView shouldUsePreviewForLongPress]): Deleted.
+
 2019-06-18  Ryan Haddad  <[email protected]>
 
         Unreviewed, rolling out r246575.

Modified: trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h (246582 => 246583)


--- trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebKit/Platform/spi/ios/UIKitSPI.h	2019-06-19 09:43:57 UTC (rev 246583)
@@ -87,6 +87,7 @@
 #import <UIKit/_UINavigationParallaxTransition.h>
 
 #if HAVE(LINK_PREVIEW)
+#import <UIKit/UIPreviewAction_Private.h>
 #import <UIKit/UIPreviewItemController.h>
 #endif
 
@@ -1066,6 +1067,10 @@
 @property (nonatomic, retain) id <NSCopying> inputElementIdentifier;
 @end
 
+@interface UIPreviewAction ()
+@property (nonatomic, strong) UIImage *image;
+@end
+
 #endif // USE(APPLE_INTERNAL_SDK)
 
 @interface UIGestureRecognizer (Staging_45970040)
@@ -1179,6 +1184,14 @@
 - (void)setNextPreviousItemsVisible:(BOOL)visible;
 @end
 
+#if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
+@interface UIContextMenuConfiguration (NeededUntil51288435Fixed)
+@property (nonatomic, copy) id <NSCopying> identifier;
+@property (nonatomic, copy) UIContextMenuContentPreviewProvider previewProvider;
+@property (nonatomic, copy) UIContextMenuActionProvider actionProvider;
+@end
+#endif
+
 WTF_EXTERN_C_BEGIN
 
 BOOL UIKeyboardEnabledInputModesAllowOneToManyShortcuts(void);

Modified: trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h (246582 => 246583)


--- trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebKit/UIProcess/API/Cocoa/WKUIDelegate.h	2019-06-19 09:43:57 UTC (rev 246583)
@@ -39,6 +39,12 @@
 @class WKWebViewConfiguration;
 @class WKWindowFeatures;
 
+#if TARGET_OS_IOS
+@class WKContextMenuElementInfo;
+@class UIContextMenuConfiguration;
+@protocol UIContextMenuInteractionCommitAnimating;
+#endif
+
 /*! A class conforming to the WKUIDelegate protocol provides methods for
  presenting native UI on behalf of a webpage.
  */
@@ -150,10 +156,54 @@
  @param webView The web view invoking the delegate method.
  @param previewingViewController The view controller that is being popped.
  */
-- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController WK_API_DEPRECATED("This API will be replaced", ios(10.0, WK_IOS_TBA));
+- (void)webView:(WKWebView *)webView commitPreviewingViewController:(UIViewController *)previewingViewController WK_API_DEPRECATED("webView:contextMenuForElement:willCommitWithAnimator:", ios(10.0, WK_IOS_TBA));
 
 #endif // TARGET_OS_IPHONE
 
+#if TARGET_OS_IOS
+
+/**
+ * @abstract Called when a context menu interaction begins.
+ *
+ * @param webView The web view invoking the delegate method.
+ * @param elementInfo The elementInfo for the element the user is touching.
+ * @param completionHandler A completion handler to call once a it has been decided whether or not to show a context menu.
+ * Pass a valid UIContextMenuConfiguration to show a context menu, or pass nil to not show a context menu.
+ */
+
+- (void)webView:(WKWebView *)webView contextMenuConfigurationForElement:(WKContextMenuElementInfo *)elementInfo completionHandler:(void (^)(UIContextMenuConfiguration * _Nullable configuration))completionHandler WK_API_AVAILABLE(ios(WK_IOS_TBA));
+
+/**
+ * @abstract Called when the context menu configured by the UIContextMenuConfiguration from
+ * webView:contextMenuConfigurationForElement:completionHandler: is committed.
+ *
+ * @param webView The web view invoking the delegate method.
+ * @param elementInfo The elementInfo for the element the user is touching.
+ * @param animator The animator to use for the commit animation.
+ */
+
+- (void)webView:(WKWebView *)webView contextMenuForElement:(WKContextMenuElementInfo *)elementInfo willCommitWithAnimator:(id<UIContextMenuInteractionCommitAnimating>)animator WK_API_AVAILABLE(ios(WK_IOS_TBA));
+
+/**
+ * @abstract Called when the context menu will be presented.
+ *
+ * @param webView The web view invoking the delegate method.
+ * @param elementInfo The elementInfo for the element the user is touching.
+ */
+
+- (void)webView:(WKWebView *)webView contextMenuWillPresentForElement:(WKContextMenuElementInfo *)elementInfo WK_API_AVAILABLE(ios(WK_IOS_TBA));
+
+/**
+ * @abstract Called when the context menu ends.
+ *
+ * @param webView The web view invoking the delegate method.
+ * @param elementInfo The elementInfo for the element the user is touching.
+ */
+
+- (void)webView:(WKWebView *)webView contextMenuDidEndForElement:(WKContextMenuElementInfo *)elementInfo WK_API_AVAILABLE(ios(WK_IOS_TBA));
+
+#endif // TARGET_OS_IOS
+
 #if !TARGET_OS_IPHONE
 
 /*! @abstract Displays a file upload panel.

Modified: trunk/Source/WebKit/UIProcess/WKImagePreviewViewController.mm (246582 => 246583)


--- trunk/Source/WebKit/UIProcess/WKImagePreviewViewController.mm	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebKit/UIProcess/WKImagePreviewViewController.mm	2019-06-19 09:43:57 UTC (rev 246583)
@@ -32,16 +32,6 @@
 #import <WebCore/IntSize.h>
 #import <_WKElementAction.h>
 
-#if HAVE(LINK_PREVIEW)
-#if USE(APPLE_INTERNAL_SDK) && __has_include(<WebKitAdditions/WKImagePreviewViewControllerAdditions.mm>)
-#include <WebKitAdditions/WKImagePreviewViewControllerAdditions.mm>
-#else
-static void setAdditionalPreviewActionInfo(UIPreviewAction *, _WKElementAction *)
-{
-}
-#endif
-#endif
-
 @implementation WKImagePreviewViewController {
     RetainPtr<CGImageRef> _image;
     RetainPtr<UIImageView> _imageView;
@@ -112,7 +102,7 @@
         UIPreviewAction *previewAction = [UIPreviewAction actionWithTitle:imageAction.title style:UIPreviewActionStyleDefault handler:^(UIPreviewAction *action, UIViewController *previewViewController) {
             [imageAction runActionWithElementInfo:_activatedElementInfo.get()];
         }];
-        setAdditionalPreviewActionInfo(previewAction, imageAction);
+        previewAction.image = [_WKElementAction imageForElementActionType:imageAction.type];
 
         [previewActions addObject:previewAction];
     }

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h (246582 => 246583)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.h	2019-06-19 09:43:57 UTC (rev 246583)
@@ -59,10 +59,6 @@
 #import <wtf/WeakObjCPtr.h>
 #import <wtf/text/WTFString.h>
 
-#if USE(APPLE_INTERNAL_SDK) && __has_include(<WebKitAdditions/WKInteractionPreviewAdditions.h>)
-#import <WebKitAdditions/WKInteractionPreviewAdditions.h>
-#endif
-
 namespace API {
 class OpenPanelParameters;
 }
@@ -101,6 +97,7 @@
 @class UIHoverGestureRecognizer;
 @class WebEvent;
 @class WKActionSheetAssistant;
+@class WKContextMenuElementInfo;
 @class WKDrawingCoordinator;
 @class WKFocusedFormControlView;
 @class WKFormInputControl;
@@ -245,8 +242,13 @@
     RetainPtr<UIGestureRecognizer> _previewSecondaryGestureRecognizer;
     Vector<bool> _focusStateStack;
 #if HAVE(LINK_PREVIEW)
-#if USE(LONG_PRESS_FOR_LINK_PREVIEW)
-    LONG_PRESS_LINK_PREVIEW_MEMBERS
+#if USE(UICONTEXTMENU)
+    RetainPtr<UIContextMenuInteraction> _contextMenuInteraction;
+    RetainPtr<WKContextMenuElementInfo> _contextMenuElementInfo;
+    BOOL _showLinkPreviews;
+    RetainPtr<UIViewController> _contextMenuLegacyPreviewController;
+    RetainPtr<UIMenu> _contextMenuLegacyMenu;
+    BOOL _contextMenuHasRequestedLegacyData;
 #else
     RetainPtr<UIPreviewItemController> _previewItemController;
 #endif
@@ -532,17 +534,13 @@
 @end
 
 #if HAVE(LINK_PREVIEW)
-#if USE(LONG_PRESS_FOR_LINK_PREVIEW)
-@interface WKContentView (WKInteractionPreview) <LONG_PRESS_LINK_PREVIEW_PROTOCOL>
+#if USE(UICONTEXTMENU)
+@interface WKContentView (WKInteractionPreview) <UIContextMenuInteractionDelegate>
 #else
 @interface WKContentView (WKInteractionPreview) <UIPreviewItemDelegate>
 #endif
-
-@property (nonatomic, readonly) BOOL shouldUsePreviewForLongPress;
-
 - (void)_registerPreview;
 - (void)_unregisterPreview;
-
 @end
 #endif
 

Modified: trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm (246582 => 246583)


--- trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-06-19 06:55:13 UTC (rev 246582)
+++ trunk/Source/WebKit/UIProcess/ios/WKContentViewInteraction.mm	2019-06-19 09:43:57 UTC (rev 246583)
@@ -29,6 +29,7 @@
 #if PLATFORM(IOS_FAMILY)
 
 #import "APIUIClient.h"
+#import "CompletionHandlerCallChecker.h"
 #import "DocumentEditingContext.h"
 #import "EditableImageController.h"
 #import "InputViewUpdateDeferrer.h"
@@ -105,6 +106,8 @@
 #import <pal/spi/cocoa/DataDetectorsCoreSPI.h>
 #import <pal/spi/ios/DataDetectorsUISPI.h>
 #import <pal/spi/ios/GraphicsServicesSPI.h>
+#import <wtf/BlockObjCExceptions.h>
+#import <wtf/BlockPtr.h>
 #import <wtf/Optional.h>
 #import <wtf/RetainPtr.h>
 #import <wtf/SetForScope.h>
@@ -151,8 +154,9 @@
 SOFT_LINK_CONSTANT(ManagedConfiguration, MCFeatureDefinitionLookupAllowed, NSString *)
 #endif
 
-#if USE(APPLE_INTERNAL_SDK) && __has_include(<WebKitAdditions/WKInteractionPreviewAdditions.h>)
-#import <WebKitAdditions/WKInteractionPreviewAdditions.h>
+#if HAVE(LINK_PREVIEW) && USE(UICONTEXTMENU)
+static NSString * const webkitShowLinkPreviewsPreferenceKey = @"WebKitShowLinkPreviews";
+static NSString * const webkitShowLinkPreviewsPreferenceChangedNotification = @"WebKitShowLinkPreviewsPreferenceChanged";
 #endif
 
 #if PLATFORM(WATCHOS)
@@ -764,15 +768,11 @@
     [_highlightLongPressGestureRecognizer setDelay:highlightDelay];
     [_highlightLongPressGestureRecognizer setDelegate:self];
 
-#if HAVE(LINK_PREVIEW)
-    if (!self.shouldUsePreviewForLongPress)
+#if HAVE(LINK_PREVIEW) && !USE(UICONTEXTMENU)
+    [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
+    [self _createAndConfigureLongPressGestureRecognizer];
 #endif
-    {
-        [self addGestureRecognizer:_highlightLongPressGestureRecognizer.get()];
 
-        [self _createAndConfigureLongPressGestureRecognizer];
-    }
-
 #if ENABLE(DATA_INTERACTION)
     [self setupDragAndDropInteractions];
 #endif
@@ -7367,7 +7367,7 @@
 
 #if HAVE(LINK_PREVIEW)
     if ([userInterfaceItem isEqualToString:@"linkPreviewPopoverContents"]) {
-#if USE(LONG_PRESS_FOR_LINK_PREVIEW)
+#if USE(UICONTEXTMENU)
         return @{ userInterfaceItem: @{ @"pageURL": WTF::userVisibleString(_positionInformation.url) } };
 #else
         NSString *url = "" previewData][UIPreviewDataLink];
@@ -7411,17 +7411,588 @@
     return nil;
 }
 
-#if USE(LONG_PRESS_FOR_LINK_PREVIEW)
-#include <WebKitAdditions/WKInteractionPreviewAdditions.mm>
-#else
+#if USE(UICONTEXTMENU)
 
 @implementation WKContentView (WKInteractionPreview)
 
-- (BOOL)shouldUsePreviewForLongPress
+- (void)_registerPreview
 {
-    return NO;
+    if (!_webView.allowsLinkPreview)
+        return;
+
+    _contextMenuInteraction = adoptNS([[UIContextMenuInteraction alloc] initWithDelegate:self]);
+    _contextMenuHasRequestedLegacyData = NO;
+    [self addInteraction:_contextMenuInteraction.get()];
+
+    [self _showLinkPreviewsPreferenceChanged:nil];
+
+    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(_showLinkPreviewsPreferenceChanged:) name:webkitShowLinkPreviewsPreferenceChangedNotification object:nil];
 }
 
+- (void)_unregisterPreview
+{
+    if (!_contextMenuInteraction)
+        return;
+
+    [self removeInteraction:_contextMenuInteraction.get()];
+    _contextMenuInteraction = nil;
+
+    [[NSNotificationCenter defaultCenter] removeObserver:self name:webkitShowLinkPreviewsPreferenceChangedNotification object:nil];
+}
+
+- (void)_showLinkPreviewsPreferenceChanged:(NSNotification *)notification
+{
+    Boolean keyExistsAndHasValidFormat = false;
+    Boolean prefValue = CFPreferencesGetAppBooleanValue((__bridge CFStringRef)webkitShowLinkPreviewsPreferenceKey, kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
+    if (keyExistsAndHasValidFormat)
+        _showLinkPreviews = prefValue;
+    else
+        _showLinkPreviews = YES;
+}
+
+static bool needsDeprecatedPreviewAPI(id<WKUIDelegate> delegate)
+{
+    // FIXME: Replace these with booleans in UIDelegate.h.
+    return delegate
+    && ![delegate respondsToSelector:@selector(_webView:contextMenuConfigurationForElement:completionHandler:)]
+    && ![delegate respondsToSelector:@selector(webView:contextMenuConfigurationForElement:completionHandler:)]
+    && ![delegate respondsToSelector:@selector(_webView:contextMenuForElement:willCommitWithAnimator:)]
+    && ![delegate respondsToSelector:@selector(webView:contextMenuForElement:willCommitWithAnimator:)]
+    && ![delegate respondsToSelector:@selector(_webView:contextMenuWillPresentForElement:)]
+    && ![delegate respondsToSelector:@selector(webView:contextMenuWillPresentForElement:)]
+    && ![delegate respondsToSelector:@selector(_webView:contextMenuDidEndForElement:)]
+    && ![delegate respondsToSelector:@selector(webView:contextMenuDidEndForElement:)]
+    && ([delegate respondsToSelector:@selector(webView:shouldPreviewElement:)]
+        || [delegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]
+        || [delegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]
+        || [delegate respondsToSelector:@selector(_webView:previewViewControllerForURL:defaultActions:elementInfo:)]
+        || [delegate respondsToSelector:@selector(_webView:previewViewControllerForURL:)]
+        || [delegate respondsToSelector:@selector(_webView:previewViewControllerForImage:alternateURL:defaultActions:elementInfo:)]);
+}
+
+ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+static NSArray<WKPreviewAction *> *wkPreviewActionsFromElementActions(NSArray<_WKElementAction *> *elementActions, _WKActivatedElementInfo *elementInfo)
+{
+    NSMutableArray<WKPreviewAction *> *previewActions = [NSMutableArray arrayWithCapacity:[elementActions count]];
+    for (_WKElementAction *elementAction in elementActions) {
+        WKPreviewAction *previewAction = [WKPreviewAction actionWithIdentifier:previewIdentifierForElementAction(elementAction) title:elementAction.title style:UIPreviewActionStyleDefault handler:^(UIPreviewAction *, UIViewController *) {
+            [elementAction runActionWithElementInfo:elementInfo];
+        }];
+        previewAction.image = [_WKElementAction imageForElementActionType:elementAction.type];
+        [previewActions addObject:previewAction];
+    }
+    return previewActions;
+}
+
+static UIAction *uiActionForPreviewAction(UIPreviewAction *previewAction, UIViewController *previewViewController)
+{
+    // UIPreviewActionItem.image is SPI, so no external clients will be able
+    // to provide glyphs for actions <rdar://problem/50151855>.
+    // However, they should migrate to the new API.
+
+    return [UIAction actionWithTitle:previewAction.title image:previewAction.image identifier:nil handler:^(UIAction *action) {
+        previewAction.handler(previewAction, previewViewController);
+    }];
+}
+ALLOW_DEPRECATED_DECLARATIONS_END
+
+static NSArray<UIMenuElement *> *menuElementsFromPreviewOrDefaults(UIViewController *previewViewController, const RetainPtr<NSArray>& defaultElementActions, RetainPtr<_WKActivatedElementInfo> elementInfo)
+{
+    auto actions = [NSMutableArray arrayWithCapacity:defaultElementActions.get().count];
+
+    // One of the delegates may have provided a UIViewController with a previewActionItems array. If so,
+    // we need to convert each UIPreviewActionItem into a UIAction.
+    if (previewViewController) {
+        ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+        NSArray<id<UIPreviewActionItem>> *previewActions = previewViewController.previewActionItems;
+        for (UIPreviewAction *previewAction in previewActions)
+            [actions addObject:uiActionForPreviewAction(previewAction, previewViewController)];
+        ALLOW_DEPRECATED_DECLARATIONS_END
+    }
+
+    if (![actions count]) {
+        // We either didn't get a custom preview UIViewController, or it didn't provide any actions
+        // so we should use the default set.
+        for (_WKElementAction *elementAction in defaultElementActions.get()) {
+            UIImage *image = [_WKElementAction imageForElementActionType:elementAction.type];
+
+            [actions addObject:[UIAction actionWithTitle:elementAction.title image:image identifier:nil handler:^(UIAction *) {
+                [elementAction runActionWithElementInfo:elementInfo.get()];
+            }]];
+        }
+    }
+
+    return actions;
+}
+
+static UIMenu *menuFromPreviewOrDefaults(UIViewController *previewViewController, const RetainPtr<NSArray>& defaultElementActions, RetainPtr<_WKActivatedElementInfo> elementInfo, NSString *title)
+{
+    auto actions = menuElementsFromPreviewOrDefaults(previewViewController, defaultElementActions, elementInfo);
+    return [UIMenu menuWithTitle:title children:actions];
+}
+
+static NSString *titleForMenu(bool isLink, bool showLinkPreviews, const URL& url, const String& title)
+{
+    if (isLink && !showLinkPreviews) {
+        if (!url.isEmpty()) {
+            if (WTF::protocolIsJavaScript(url))
+                return WEB_UI_STRING_KEY("_javascript_", "_javascript_ Action Sheet Title", "Title for action sheet for _javascript_ link");
+            return WTF::userVisibleString(url);
+        }
+    } else if (!isLink && !title.isEmpty())
+        return title;
+
+    return nil;
+}
+
+- (void)assignLegacyDataForContextMenuInteraction
+{
+    ASSERT(!_contextMenuHasRequestedLegacyData);
+    if (_contextMenuHasRequestedLegacyData)
+        return;
+    _contextMenuHasRequestedLegacyData = YES;
+
+    if (!_webView)
+        return;
+    auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(_webView.UIDelegate);
+    if (!uiDelegate)
+        return;
+
+    const auto& url = ""
+
+    _page->startInteractionWithElementAtPosition(_positionInformation.request.point);
+
+    UIViewController *previewViewController = nil;
+
+    auto elementInfo = adoptNS([[_WKActivatedElementInfo alloc] _initWithInteractionInformationAtPosition:_positionInformation]);
+
+    if (_positionInformation.isLink) {
+        _longPressCanClick = NO;
+
+        RetainPtr<NSArray<_WKElementAction *>> defaultActionsFromAssistant = [_actionSheetAssistant defaultActionsForLinkSheet:elementInfo.get()];
+
+        // FIXME: Animated images go here.
+
+        ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+        if ([uiDelegate respondsToSelector:@selector(webView:previewingViewControllerForElement:defaultActions:)]) {
+            auto defaultActions = wkPreviewActionsFromElementActions(defaultActionsFromAssistant.get(), elementInfo.get());
+            auto previewElementInfo = adoptNS([[WKPreviewElementInfo alloc] _initWithLinkURL:url]);
+            previewViewController = [uiDelegate webView:_webView previewingViewControllerForElement:previewElementInfo.get() defaultActions:defaultActions];
+        } else if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForURL:defaultActions:elementInfo:)])
+            previewViewController = [uiDelegate _webView:_webView previewViewControllerForURL:url defaultActions:defaultActionsFromAssistant.get() elementInfo:elementInfo.get()];
+        else if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForURL:)])
+            previewViewController = [uiDelegate _webView:_webView previewViewControllerForURL:url];
+        ALLOW_DEPRECATED_DECLARATIONS_END
+
+#if USE(DATA_DETECTORS_FOR_DEFAULT_PREVIEW)
+        // Previously, UIPreviewItemController would detect the case where there was no previewViewController
+        // and create one. We need to replicate this code for the new API.
+        if (!previewViewController) {
+            auto ddContextMenuActionClass = getDDContextMenuActionClass();
+            if ([ddContextMenuActionClass respondsToSelector:@selector(contextMenuConfigurationForURL:identifier:selectedText:results:inView:context:menuIdentifier:)]) {
+                BEGIN_BLOCK_OBJC_EXCEPTIONS;
+                NSDictionary *context = [self dataDetectionContextForPositionInformation:_positionInformation];
+                RetainPtr<UIContextMenuConfiguration> dataDetectorsResult = [ddContextMenuActionClass contextMenuConfigurationForURL:url identifier:_positionInformation.dataDetectorIdentifier selectedText:self.selectedText results:_positionInformation.dataDetectorResults.get() inView:self context:context menuIdentifier:nil];
+                if (_showLinkPreviews && dataDetectorsResult && dataDetectorsResult.get().previewProvider)
+                    _contextMenuLegacyPreviewController = dataDetectorsResult.get().previewProvider();
+                if (dataDetectorsResult && dataDetectorsResult.get().actionProvider) {
+                    auto menuElements = menuElementsFromPreviewOrDefaults(nil, defaultActionsFromAssistant, elementInfo);
+                    _contextMenuLegacyMenu = dataDetectorsResult.get().actionProvider(menuElements);
+                }
+                END_BLOCK_OBJC_EXCEPTIONS;
+            }
+            return;
+        }
+#endif
+
+        auto menuTitle = titleForMenu(true, _showLinkPreviews, url, _positionInformation.title);
+        _contextMenuLegacyMenu = menuFromPreviewOrDefaults(previewViewController, defaultActionsFromAssistant, elementInfo, menuTitle);
+
+    } else if (_positionInformation.isImage) {
+        NSURL *nsURL = (NSURL *)url;
+        RetainPtr<NSDictionary> imageInfo;
+        ASSERT(_positionInformation.image);
+        auto cgImage = _positionInformation.image->makeCGImageCopy();
+        auto uiImage = adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
+
+        if ([uiDelegate respondsToSelector:@selector(_webView:alternateURLFromImage:userInfo:)]) {
+            NSDictionary *userInfo;
+            nsURL = [uiDelegate _webView:_webView alternateURLFromImage:uiImage.get() userInfo:&userInfo];
+            imageInfo = userInfo;
+        }
+
+        ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+        if ([uiDelegate respondsToSelector:@selector(_webView:willPreviewImageWithURL:)])
+            [uiDelegate _webView:_webView willPreviewImageWithURL:_positionInformation.imageURL];
+
+        RetainPtr<NSArray<_WKElementAction *>> defaultActionsFromAssistant = [_actionSheetAssistant defaultActionsForImageSheet:elementInfo.get()];
+
+        if (imageInfo && [uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForImage:alternateURL:defaultActions:elementInfo:)])
+            previewViewController = [uiDelegate _webView:_webView previewViewControllerForImage:uiImage.get() alternateURL:nsURL defaultActions:defaultActionsFromAssistant.get() elementInfo:elementInfo.get()];
+        else
+            previewViewController = [[WKImagePreviewViewController alloc] initWithCGImage:cgImage defaultActions:defaultActionsFromAssistant.get() elementInfo:elementInfo.get()];
+        ALLOW_DEPRECATED_DECLARATIONS_END
+
+        auto menuTitle = titleForMenu(false, _showLinkPreviews, url, _positionInformation.title);
+        _contextMenuLegacyMenu = menuFromPreviewOrDefaults(previewViewController, defaultActionsFromAssistant, elementInfo, menuTitle);
+    }
+
+    _contextMenuLegacyPreviewController = _showLinkPreviews ? previewViewController : nullptr;
+}
+
+- (UIContextMenuConfiguration *)contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location
+{
+    // Required to conform to UIContextMenuInteractionDelegate, but SPI version should be called instead.
+    ASSERT_NOT_REACHED();
+    return nil;
+}
+
+- (void)_contextMenuInteraction:(UIContextMenuInteraction *)interaction configurationForMenuAtLocation:(CGPoint)location completion:(void(^)(UIContextMenuConfiguration *))completion
+{
+    if (!_webView)
+        return completion(nil);
+
+    if (!_webView.configuration._longPressActionsEnabled)
+        return completion(nil);
+
+    const auto position = [interaction locationInView:self];
+    WebKit::InteractionInformationRequest request { WebCore::roundedIntPoint(position) };
+    request.includeSnapshot = true;
+    request.includeLinkIndicator = true;
+
+    [self doAfterPositionInformationUpdate:[weakSelf = WeakObjCPtr<WKContentView>(self), completion = makeBlockPtr(completion)] (WebKit::InteractionInformationAtPosition) {
+        auto strongSelf = weakSelf.get();
+        if (!strongSelf)
+            return completion(nil);
+        [strongSelf continueContextMenuInteraction:completion.get()];
+    } forRequest:request];
+}
+
+- (void)continueContextMenuInteraction:(void(^)(UIContextMenuConfiguration *))completion
+{
+    if (!_positionInformation.touchCalloutEnabled)
+        return completion(nil);
+
+    if (!_positionInformation.isLink && !_positionInformation.isImage && !_positionInformation.isAttachment)
+        return completion(nil);
+
+    URL linkURL = _positionInformation.url;
+
+    if (_positionInformation.isLink && linkURL.isEmpty())
+        return completion(nil);
+
+    auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(_webView.UIDelegate);
+    if (!uiDelegate)
+        return completion(nil);
+
+    if (needsDeprecatedPreviewAPI(uiDelegate)) {
+
+        if (_positionInformation.isLink) {
+            ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+            if ([uiDelegate respondsToSelector:@selector(webView:shouldPreviewElement:)]) {
+                auto previewElementInfo = adoptNS([[WKPreviewElementInfo alloc] _initWithLinkURL:linkURL]);
+                if (![uiDelegate webView:_webView shouldPreviewElement:previewElementInfo.get()])
+                    return completion(nil);
+            }
+            ALLOW_DEPRECATED_DECLARATIONS_END
+
+            // FIXME: Support _javascript_ urls here. But make sure they don't show a preview.
+            // <rdar://problem/50572283>
+            if (!linkURL.protocolIsInHTTPFamily()) {
+#if ENABLE(DATA_DETECTION)
+                if (!WebCore::DataDetection::canBePresentedByDataDetectors(linkURL))
+                    return completion(nil);
+#endif
+            }
+        }
+
+        _contextMenuLegacyPreviewController = nullptr;
+        _contextMenuLegacyMenu = nullptr;
+        _contextMenuHasRequestedLegacyData = NO;
+
+        UIContextMenuActionProvider actionMenuProvider = [weakSelf = WeakObjCPtr<WKContentView>(self)] (NSArray<UIMenuElement *> *suggestedActions) -> UIMenu * {
+            auto strongSelf = weakSelf.get();
+            if (!strongSelf)
+                return nil;
+            if (!strongSelf->_contextMenuHasRequestedLegacyData)
+                [strongSelf assignLegacyDataForContextMenuInteraction];
+
+            return strongSelf->_contextMenuLegacyMenu.get();
+        };
+
+        UIContextMenuContentPreviewProvider contentPreviewProvider = [weakSelf = WeakObjCPtr<WKContentView>(self)] () -> UIViewController * {
+            auto strongSelf = weakSelf.get();
+            if (!strongSelf)
+                return nil;
+            if (!strongSelf->_contextMenuHasRequestedLegacyData)
+                [strongSelf assignLegacyDataForContextMenuInteraction];
+
+            return strongSelf->_contextMenuLegacyPreviewController.get();
+        };
+
+        // FIXME: Should we provide an identifier and ASSERT in delegates if we don't match?
+        return completion([UIContextMenuConfiguration configurationWithIdentifier:nil previewProvider:contentPreviewProvider actionProvider:actionMenuProvider]);
+    }
+
+    auto completionBlock = makeBlockPtr([completion = makeBlockPtr(completion), linkURL = WTFMove(linkURL), weakSelf = WeakObjCPtr<WKContentView>(self)] (UIContextMenuConfiguration *configurationFromWKUIDelegate) mutable {
+
+        auto strongSelf = weakSelf.get();
+        if (!strongSelf)
+            return completion(nil);
+
+        if (!configurationFromWKUIDelegate) {
+
+            strongSelf->_contextMenuElementInfo = nil;
+
+            // At this point we have an object we might want to show a context menu for, but the
+            // client was unable to handle it. Before giving up, we ask DataDetectors.
+
+#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))
+                return completion(nil);
+
+            BEGIN_BLOCK_OBJC_EXCEPTIONS;
+            auto ddContextMenuActionClass = getDDContextMenuActionClass();
+            if ([ddContextMenuActionClass respondsToSelector:@selector(contextMenuConfigurationWithURL:inView:context:menuIdentifier:)]) {
+                NSDictionary *context = [strongSelf dataDetectionContextForPositionInformation:strongSelf->_positionInformation];
+                UIContextMenuConfiguration *configurationFromDD = [ddContextMenuActionClass contextMenuConfigurationForURL:linkURL identifier:strongSelf->_positionInformation.dataDetectorIdentifier selectedText:[strongSelf selectedText] results:strongSelf->_positionInformation.dataDetectorResults.get() inView:strongSelf.get() context:context menuIdentifier:nil];
+                if (strongSelf->_showLinkPreviews)
+                    return completion(configurationFromDD);
+                return completion([UIContextMenuConfiguration configurationWithIdentifier:[configurationFromDD identifier] previewProvider:[configurationFromDD previewProvider] actionProvider:[configurationFromDD actionProvider]]);
+            }
+            END_BLOCK_OBJC_EXCEPTIONS;
+#endif
+            return completion(nil);
+        }
+
+        id<NSCopying> identifier = [configurationFromWKUIDelegate identifier];
+        UIContextMenuContentPreviewProvider contentPreviewProvider = [configurationFromWKUIDelegate previewProvider];
+        UIContextMenuActionProvider actionMenuProvider = [configurationFromWKUIDelegate actionProvider];
+
+        auto actionProviderWrapper = [actionProviderFromUIDelegate = makeBlockPtr(actionMenuProvider), weakSelf = WTFMove(weakSelf)] (NSArray<UIMenuElement *> *suggestedActions) -> UIMenu * {
+            auto strongSelf = weakSelf.get();
+            if (!strongSelf)
+                return nil;
+
+            auto elementInfo = adoptNS([[_WKActivatedElementInfo alloc] _initWithInteractionInformationAtPosition:strongSelf->_positionInformation]);
+            RetainPtr<NSArray<_WKElementAction *>> defaultActionsFromAssistant = strongSelf->_positionInformation.isLink ? [strongSelf->_actionSheetAssistant defaultActionsForLinkSheet:elementInfo.get()] : [strongSelf->_actionSheetAssistant defaultActionsForImageSheet:elementInfo.get()];
+
+            auto menuElements = menuElementsFromPreviewOrDefaults(nil, defaultActionsFromAssistant, elementInfo);
+
+            if (actionProviderFromUIDelegate)
+                return actionProviderFromUIDelegate(menuElements);
+
+            auto title = titleForMenu(strongSelf->_positionInformation.isLink, strongSelf->_showLinkPreviews, strongSelf->_positionInformation.url, strongSelf->_positionInformation.title);
+            return [UIMenu menuWithTitle:title children:menuElements];
+        };
+
+        completion([UIContextMenuConfiguration configurationWithIdentifier:identifier previewProvider:contentPreviewProvider actionProvider:actionProviderWrapper]);
+    });
+
+    _contextMenuElementInfo = wrapper(API::ContextMenuElementInfo::create(_positionInformation));
+    if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuConfigurationForElement:completionHandler:)]) {
+        auto checker = WebKit::CompletionHandlerCallChecker::create(uiDelegate, @selector(_webView:contextMenuConfigurationForElement:completionHandler:));
+        [uiDelegate _webView:_webView contextMenuConfigurationForElement:_contextMenuElementInfo.get() completionHandler:makeBlockPtr([completionBlock = WTFMove(completionBlock), checker = WTFMove(checker)] (UIContextMenuConfiguration *configuration) {
+            if (checker->completionHandlerHasBeenCalled())
+                return;
+            checker->didCallCompletionHandler();
+            completionBlock(configuration);
+        }).get()];
+    } else if (_positionInformation.isLink && [uiDelegate respondsToSelector:@selector(webView:contextMenuConfigurationForElement:completionHandler:)]) {
+        auto checker = WebKit::CompletionHandlerCallChecker::create(uiDelegate, @selector(webView:contextMenuConfigurationForElement:completionHandler:));
+        [uiDelegate webView:_webView contextMenuConfigurationForElement:_contextMenuElementInfo.get() completionHandler:makeBlockPtr([completionBlock = WTFMove(completionBlock), checker = WTFMove(checker)] (UIContextMenuConfiguration *configuration) {
+            if (checker->completionHandlerHasBeenCalled())
+                return;
+            checker->didCallCompletionHandler();
+            completionBlock(configuration);
+        }).get()];
+    } else
+        completionBlock(nil);
+}
+
+static RetainPtr<UIImage> uiImageForImage(WebCore::Image* image)
+{
+    if (!image)
+        return nil;
+
+    auto cgImage = image->nativeImage();
+    if (!cgImage)
+        return nil;
+
+    return adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
+}
+
+// FIXME: This should be merged with createTargetedDragPreview in DragDropInteractionState.
+static RetainPtr<UITargetedPreview> createTargetedPreview(UIImage *image, UIView *rootView, UIView *previewContainer, const WebCore::FloatRect& frameInRootViewCoordinates, const Vector<WebCore::FloatRect>& clippingRectsInFrameCoordinates, UIColor *backgroundColor)
+{
+    if (frameInRootViewCoordinates.isEmpty() || !image)
+        return nil;
+
+    WebCore::FloatRect frameInContainerCoordinates = [rootView convertRect:frameInRootViewCoordinates toView:previewContainer];
+    if (frameInContainerCoordinates.isEmpty())
+        return nil;
+
+    WebCore::FloatSize scalingRatio = frameInContainerCoordinates.size() / frameInRootViewCoordinates.size();
+    NSMutableArray *clippingRectValuesInFrameCoordinates = [NSMutableArray arrayWithCapacity:clippingRectsInFrameCoordinates.size()];
+
+    for (auto rect : clippingRectsInFrameCoordinates) {
+        rect.scale(scalingRatio);
+        [clippingRectValuesInFrameCoordinates addObject:[NSValue valueWithCGRect:rect]];
+    }
+
+    RetainPtr<UIPreviewParameters> parameters;
+    if (clippingRectValuesInFrameCoordinates.count)
+        parameters = adoptNS([[UIPreviewParameters alloc] initWithTextLineRects:clippingRectValuesInFrameCoordinates]);
+    else
+        parameters = adoptNS([[UIPreviewParameters alloc] init]);
+
+    if (backgroundColor)
+        [parameters setBackgroundColor:backgroundColor];
+
+    CGPoint centerInContainerCoordinates = { CGRectGetMidX(frameInContainerCoordinates), CGRectGetMidY(frameInContainerCoordinates) };
+    auto target = adoptNS([[UIPreviewTarget alloc] initWithContainer:previewContainer center:centerInContainerCoordinates]);
+
+    auto imageView = adoptNS([[UIImageView alloc] initWithImage:image]);
+    [imageView setFrame:frameInContainerCoordinates];
+    return adoptNS([[UITargetedPreview alloc] initWithView:imageView.get() parameters:parameters.get() target:target.get()]);
+}
+
+- (UITargetedPreview *)_targetedPreview
+{
+    if (_positionInformation.isLink && _positionInformation.linkIndicator.contentImage) {
+        [self _startSuppressingSelectionAssistantForReason:WebKit::InteractionIsHappening];
+
+        auto indicator = _positionInformation.linkIndicator;
+        auto textIndicatorImage = uiImageForImage(indicator.contentImage.get());
+
+        return createTargetedPreview(textIndicatorImage.get(), self, self.unscaledView, indicator.textBoundingRectInRootViewCoordinates, indicator.textRectsInBoundingRectCoordinates, [UIColor colorWithCGColor:cachedCGColor(indicator.estimatedBackgroundColor)]).autorelease();
+    }
+
+    if ((_positionInformation.isAttachment || _positionInformation.isImage) && _positionInformation.image) {
+        [self _startSuppressingSelectionAssistantForReason:WebKit::InteractionIsHappening];
+
+        RetainPtr<CGImageRef> cgImage = _positionInformation.image->makeCGImageCopy();
+        auto image = adoptNS([[UIImage alloc] initWithCGImage:cgImage.get()]);
+
+        return createTargetedPreview(image.get(), self, self.unscaledView, _positionInformation.bounds, { }, nil).autorelease();
+    }
+
+    return nil;
+}
+
+- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction previewForHighlightingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
+{
+    return [self _targetedPreview];
+}
+
+- (void)contextMenuInteractionWillPresent:(UIContextMenuInteraction *)interaction
+{
+    if (!_webView)
+        return;
+    auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(_webView.UIDelegate);
+    if (!uiDelegate)
+        return;
+    if ([uiDelegate respondsToSelector:@selector(webView:contextMenuWillPresentForElement:)])
+        [uiDelegate webView:_webView contextMenuWillPresentForElement:_contextMenuElementInfo.get()];
+    else if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuWillPresentForElement:)]) {
+        ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+        [uiDelegate _webView:_webView contextMenuWillPresentForElement:_contextMenuElementInfo.get()];
+        ALLOW_DEPRECATED_DECLARATIONS_END
+    }
+}
+
+- (UITargetedPreview *)contextMenuInteraction:(UIContextMenuInteraction *)interaction previewForDismissingMenuWithConfiguration:(UIContextMenuConfiguration *)configuration
+{
+    return [self _targetedPreview];
+}
+
+- (void)contextMenuInteraction:(UIContextMenuInteraction *)interaction willCommitWithAnimator:(id<UIContextMenuInteractionCommitAnimating>)animator
+{
+    if (!_webView)
+        return;
+
+    [self _stopSuppressingSelectionAssistantForReason:WebKit::InteractionIsHappening];
+
+    auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(_webView.UIDelegate);
+    if (!uiDelegate)
+        return;
+
+    if (needsDeprecatedPreviewAPI(uiDelegate)) {
+
+        if (_positionInformation.isImage) {
+            if ([uiDelegate respondsToSelector:@selector(_webView:commitPreviewedImageWithURL:)]) {
+                const auto& imageURL = _positionInformation.imageURL;
+                if (imageURL.isEmpty() || !(imageURL.protocolIsInHTTPFamily() || imageURL.protocolIs("data")))
+                    return;
+                ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+                [uiDelegate _webView:_webView commitPreviewedImageWithURL:(NSURL *)imageURL];
+                ALLOW_DEPRECATED_DECLARATIONS_END
+            }
+            return;
+        }
+
+        if ([uiDelegate respondsToSelector:@selector(webView:commitPreviewingViewController:)]) {
+            ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+            if (auto viewController = _contextMenuLegacyPreviewController.get())
+                [uiDelegate webView:_webView commitPreviewingViewController:viewController];
+            ALLOW_DEPRECATED_DECLARATIONS_END
+            return;
+        }
+
+        if ([uiDelegate respondsToSelector:@selector(_webView:commitPreviewedViewController:)]) {
+            ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+            if (auto viewController = _contextMenuLegacyPreviewController.get())
+                [uiDelegate _webView:_webView commitPreviewedViewController:viewController];
+            ALLOW_DEPRECATED_DECLARATIONS_END
+            return;
+        }
+
+        return;
+    }
+
+    if ([uiDelegate respondsToSelector:@selector(webView:contextMenuForElement:willCommitWithAnimator:)])
+        [uiDelegate webView:_webView contextMenuForElement:_contextMenuElementInfo.get() willCommitWithAnimator:animator];
+    else if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuForElement:willCommitWithAnimator:)]) {
+        ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+        [uiDelegate _webView:_webView contextMenuForElement:_contextMenuElementInfo.get() willCommitWithAnimator:animator];
+        ALLOW_DEPRECATED_DECLARATIONS_END
+    }
+}
+
+- (void)contextMenuInteractionDidEnd:(UIContextMenuInteraction *)interaction
+{
+    if (!_webView)
+        return;
+
+    [self _stopSuppressingSelectionAssistantForReason:WebKit::InteractionIsHappening];
+
+    // FIXME: This delegate is being called more than once by UIKit. <rdar://problem/51550291>
+    // This conditional avoids the WKUIDelegate being called twice too.
+    if (!_contextMenuElementInfo) {
+        auto uiDelegate = static_cast<id<WKUIDelegatePrivate>>(_webView.UIDelegate);
+        if ([uiDelegate respondsToSelector:@selector(webView:contextMenuDidEndForElement:)])
+            [uiDelegate webView:_webView contextMenuDidEndForElement:_contextMenuElementInfo.get()];
+        else if ([uiDelegate respondsToSelector:@selector(_webView:contextMenuDidEndForElement:)]) {
+            ALLOW_DEPRECATED_DECLARATIONS_BEGIN
+            [uiDelegate _webView:_webView contextMenuDidEndForElement:_contextMenuElementInfo.get()];
+            ALLOW_DEPRECATED_DECLARATIONS_END
+        }
+    }
+
+    _contextMenuLegacyPreviewController = nullptr;
+    _contextMenuLegacyMenu = nullptr;
+    _contextMenuHasRequestedLegacyData = NO;
+    _contextMenuElementInfo = nullptr;
+}
+
+@end
+
+#else
+
+@implementation WKContentView (WKInteractionPreview)
+
 - (void)_registerPreview
 {
     if (!_webView.allowsLinkPreview)
@@ -7766,7 +8337,7 @@
 
 @end
 
-#endif // USE(LONG_PRESS_FOR_LINK_PREVIEW)
+#endif // USE(UICONTEXTMENU)
 
 #endif // HAVE(LINK_PREVIEW)
 
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to