[iOS] Present an action sheet when long-pressing on PDF links
https://bugs.webkit.org/show_bug.cgi?id=185093
<rdar://problem/39356651>

Reviewed by Dan Bernstein.

* UIProcess/ios/WKPDFView.mm:
(-[WKPDFView dealloc]):

Called -[WKActionSheetAssistant cleanupSheet].

(-[WKPDFView web_setContentProviderData:suggestedFilename:]):

Created a WKActionSheetAssistant with the host view as the assistant view and
ourselves as the delegate.

(-[WKPDFView _URLWithPageIndex:]):

Added. Creates a URL to the current page with a page number fragment appended.

(-[WKPDFView _goToURL:atLocation:]):

Added. Navigates to a URL with a synthetic mouse click at a location in host view
coordinates.

(-[WKPDFView pdfHostViewController:goToURL:]):
(-[WKPDFView pdfHostViewController:goToPageIndex:withViewFrustum:]):

Called -_goToURL:atLocation:. Used -_URLWithPageIndex: to construct an NSURL from
a page index.

(-[WKPDFView _showActionSheetForURL:atLocation:]):

Added. Populates _positionInformation with a URL and location and calls
-[WKActionSheetAssistant showLinkSheet].

(-[WKPDFView pdfHostViewController:didLongPressURL:atLocation:]):
(-[WKPDFView pdfHostViewController:didLongPressPageIndex:atLocation:]):

Called -_showActionSheetForURL:atLocation:. Used -_URLWithPageIndex: to construct
an NSURL from a page index.

(-[WKPDFView positionInformationForActionSheetAssistant:]):

Returned _positionInformation.

(-[WKPDFView actionSheetAssistant:performAction:]):

Populated the pasteboard with plain text and URL representations of
_positionInformation.url.

(-[WKPDFView actionSheetAssistant:openElementAtLocation:]):

Called -_goToURL:atLocation.

(-[WKPDFView actionSheetAssistant:shareElementWithURL:rect:]):

Created a UIWKSelectionAssistant and called -showShareSheetFor:fromRect:.

(-[WKPDFView actionSheetAssistant:shouldIncludeAppLinkActionsForElement:]):

Returned API::UIClient::shouldIncludeAppLinkActionsForElement().

(-[WKPDFView actionSheetAssistant:decideActionsForElement:defaultActions:]):

Returned API::UIClient::actionsForElement()l


git-svn-id: http://svn.webkit.org/repository/webkit/trunk@231144 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/Source/WebKit/ChangeLog b/Source/WebKit/ChangeLog
index 9f66cac..2ca3cdf 100644
--- a/Source/WebKit/ChangeLog
+++ b/Source/WebKit/ChangeLog
@@ -1,5 +1,74 @@
 2018-04-28  Andy Estes  <aestes@apple.com>
 
+        [iOS] Present an action sheet when long-pressing on PDF links
+        https://bugs.webkit.org/show_bug.cgi?id=185093
+        <rdar://problem/39356651>
+
+        Reviewed by Dan Bernstein.
+
+        * UIProcess/ios/WKPDFView.mm:
+        (-[WKPDFView dealloc]):
+
+        Called -[WKActionSheetAssistant cleanupSheet].
+
+        (-[WKPDFView web_setContentProviderData:suggestedFilename:]):
+
+        Created a WKActionSheetAssistant with the host view as the assistant view and
+        ourselves as the delegate.
+
+        (-[WKPDFView _URLWithPageIndex:]):
+
+        Added. Creates a URL to the current page with a page number fragment appended.
+
+        (-[WKPDFView _goToURL:atLocation:]):
+
+        Added. Navigates to a URL with a synthetic mouse click at a location in host view
+        coordinates.
+
+        (-[WKPDFView pdfHostViewController:goToURL:]):
+        (-[WKPDFView pdfHostViewController:goToPageIndex:withViewFrustum:]):
+
+        Called -_goToURL:atLocation:. Used -_URLWithPageIndex: to construct an NSURL from
+        a page index.
+
+        (-[WKPDFView _showActionSheetForURL:atLocation:]):
+
+        Added. Populates _positionInformation with a URL and location and calls
+        -[WKActionSheetAssistant showLinkSheet].
+
+        (-[WKPDFView pdfHostViewController:didLongPressURL:atLocation:]):
+        (-[WKPDFView pdfHostViewController:didLongPressPageIndex:atLocation:]):
+
+        Called -_showActionSheetForURL:atLocation:. Used -_URLWithPageIndex: to construct
+        an NSURL from a page index.
+
+        (-[WKPDFView positionInformationForActionSheetAssistant:]):
+
+        Returned _positionInformation.
+
+        (-[WKPDFView actionSheetAssistant:performAction:]):
+
+        Populated the pasteboard with plain text and URL representations of
+        _positionInformation.url.
+
+        (-[WKPDFView actionSheetAssistant:openElementAtLocation:]):
+
+        Called -_goToURL:atLocation.
+
+        (-[WKPDFView actionSheetAssistant:shareElementWithURL:rect:]):
+
+        Created a UIWKSelectionAssistant and called -showShareSheetFor:fromRect:.
+
+        (-[WKPDFView actionSheetAssistant:shouldIncludeAppLinkActionsForElement:]):
+
+        Returned API::UIClient::shouldIncludeAppLinkActionsForElement().
+
+        (-[WKPDFView actionSheetAssistant:decideActionsForElement:defaultActions:]):
+
+        Returned API::UIClient::actionsForElement()l
+
+2018-04-28  Andy Estes  <aestes@apple.com>
+
         [iOS] Allow com.apple.WebKit.Networking to look up com.apple.wifi.manager
         https://bugs.webkit.org/show_bug.cgi?id=185114
         <rdar://problem/39808763>
diff --git a/Source/WebKit/UIProcess/ios/WKPDFView.mm b/Source/WebKit/UIProcess/ios/WKPDFView.mm
index 0d60750..2a0c100 100644
--- a/Source/WebKit/UIProcess/ios/WKPDFView.mm
+++ b/Source/WebKit/UIProcess/ios/WKPDFView.mm
@@ -28,20 +28,24 @@
 
 #if ENABLE(WKPDFVIEW)
 
+#import "APIUIClient.h"
 #import "FindClient.h"
+#import "WKActionSheetAssistant.h"
 #import "WKWebViewInternal.h"
 #import "WeakObjCPtr.h"
 #import "WebPageProxy.h"
 #import "_WKWebViewPrintFormatterInternal.h"
 #import <PDFKit/PDFHostViewController.h>
+#import <WebCore/WebCoreNSURLExtras.h>
 #import <wtf/BlockPtr.h>
 #import <wtf/MainThread.h>
 #import <wtf/RetainPtr.h>
 
-@interface WKPDFView () <PDFHostViewControllerDelegate>
+@interface WKPDFView () <PDFHostViewControllerDelegate, WKActionSheetAssistantDelegate>
 @end
 
 @implementation WKPDFView {
+    RetainPtr<WKActionSheetAssistant> _actionSheetAssistant;
     RetainPtr<NSData> _data;
     BlockPtr<void()> _findCompletion;
     RetainPtr<NSString> _findString;
@@ -53,12 +57,14 @@
     RetainPtr<PDFHostViewController> _hostViewController;
     CGSize _overlaidAccessoryViewsInset;
     RetainPtr<UIView> _pageNumberIndicator;
+    WebKit::InteractionInformationAtPosition _positionInformation;
     RetainPtr<NSString> _suggestedFilename;
     WebKit::WeakObjCPtr<WKWebView> _webView;
 }
 
 - (void)dealloc
 {
+    [_actionSheetAssistant cleanupSheet];
     [[_hostViewController view] removeFromSuperview];
     [_pageNumberIndicator removeFromSuperview];
     [super dealloc];
@@ -107,6 +113,9 @@
         [self removeFromSuperview];
         [scrollView addSubview:hostView];
 
+        _actionSheetAssistant = adoptNS([[WKActionSheetAssistant alloc] initWithView:hostView]);
+        [_actionSheetAssistant setDelegate:self];
+
         _pageNumberIndicator = hostViewController.pageNumberIndicator;
         [_fixedOverlayView addSubview:_pageNumberIndicator.get()];
 
@@ -362,27 +371,109 @@
         findCompletion();
 }
 
-- (void)pdfHostViewController:(PDFHostViewController *)controller goToURL:(NSURL *)url
+- (NSURL *)_URLWithPageIndex:(NSInteger)pageIndex
 {
-    WKWebView *webView = _webView.getAutoreleased();
-    if (!webView)
+    return [NSURL URLWithString:[NSString stringWithFormat:@"#page%ld", (long)pageIndex + 1] relativeToURL:[_webView URL]];
+}
+
+- (void)_goToURL:(NSURL *)url atLocation:(CGPoint)location
+{
+    auto page = [_webView _page];
+    if (!page)
         return;
 
+    UIView *hostView = [_hostViewController view];
+    CGPoint locationInScreen = [hostView.window convertPoint:[hostView convertPoint:location toView:nil] toWindow:nil];
+    page->navigateToPDFLinkWithSimulatedClick(url.absoluteString, WebCore::roundedIntPoint(location), WebCore::roundedIntPoint(locationInScreen));
+}
+
+- (void)pdfHostViewController:(PDFHostViewController *)controller goToURL:(NSURL *)url
+{
     // FIXME: We'd use the real tap location if we knew it.
-    WebCore::IntPoint point;
-    webView->_page->navigateToPDFLinkWithSimulatedClick(url.absoluteString, point, point);
+    [self _goToURL:url atLocation:CGPointMake(0, 0)];
 }
 
 - (void)pdfHostViewController:(PDFHostViewController *)controller goToPageIndex:(NSInteger)pageIndex withViewFrustum:(CGRect)documentViewRect
 {
+    [self _goToURL:[self _URLWithPageIndex:pageIndex] atLocation:documentViewRect.origin];
+}
+
+- (void)_showActionSheetForURL:(NSURL *)url atLocation:(CGPoint)location
+{
     WKWebView *webView = _webView.getAutoreleased();
     if (!webView)
         return;
 
-    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"#page%ld", (long)pageIndex + 1] relativeToURL:webView.URL];
-    CGPoint documentPoint = documentViewRect.origin;
-    CGPoint screenPoint = [self.window convertPoint:[self convertPoint:documentPoint toView:nil] toWindow:nil];
-    webView->_page->navigateToPDFLinkWithSimulatedClick(url.absoluteString, WebCore::roundedIntPoint(documentPoint), WebCore::roundedIntPoint(screenPoint));
+    CGPoint locationInHostView = [webView.scrollView convertPoint:location toView:[_hostViewController view]];
+
+    WebKit::InteractionInformationAtPosition positionInformation;
+    positionInformation.bounds = WebCore::roundedIntRect(CGRect { locationInHostView, CGSizeMake(0, 0) });
+    positionInformation.request.point = WebCore::roundedIntPoint(locationInHostView);
+    positionInformation.url = url;
+
+    _positionInformation = WTFMove(positionInformation);
+    [_actionSheetAssistant showLinkSheet];
+}
+
+- (void)pdfHostViewController:(PDFHostViewController *)controller didLongPressURL:(NSURL *)url atLocation:(CGPoint)location
+{
+    [self _showActionSheetForURL:url atLocation:location];
+}
+
+- (void)pdfHostViewController:(PDFHostViewController *)controller didLongPressPageIndex:(NSInteger)pageIndex atLocation:(CGPoint)location
+{
+    [self _showActionSheetForURL:[self _URLWithPageIndex:pageIndex] atLocation:location];
+}
+
+#pragma mark WKActionSheetAssistantDelegate
+
+- (std::optional<WebKit::InteractionInformationAtPosition>)positionInformationForActionSheetAssistant:(WKActionSheetAssistant *)assistant
+{
+    return _positionInformation;
+}
+
+- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant performAction:(WebKit::SheetAction)action
+{
+    if (action != WebKit::SheetAction::Copy)
+        return;
+
+    NSDictionary *representations = @{
+        (NSString *)kUTTypeUTF8PlainText : (NSString *)_positionInformation.url,
+        (NSString *)kUTTypeURL : (NSURL *)_positionInformation.url,
+    };
+
+    [UIPasteboard generalPasteboard].items = @[ representations ];
+}
+
+- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant openElementAtLocation:(CGPoint)location
+{
+    [self _goToURL:_positionInformation.url atLocation:location];
+}
+
+- (void)actionSheetAssistant:(WKActionSheetAssistant *)assistant shareElementWithURL:(NSURL *)url rect:(CGRect)boundingRect
+{
+    auto selectionAssistant = adoptNS([[UIWKSelectionAssistant alloc] initWithView:[_hostViewController view]]);
+    [selectionAssistant showShareSheetFor:WebCore::userVisibleString(url) fromRect:boundingRect];
+}
+
+#if HAVE(APP_LINKS)
+- (BOOL)actionSheetAssistant:(WKActionSheetAssistant *)assistant shouldIncludeAppLinkActionsForElement:(_WKActivatedElementInfo *)element
+{
+    auto page = [_webView _page];
+    if (!page)
+        return NO;
+
+    return page->uiClient().shouldIncludeAppLinkActionsForElement(element);
+}
+#endif
+
+- (RetainPtr<NSArray>)actionSheetAssistant:(WKActionSheetAssistant *)assistant decideActionsForElement:(_WKActivatedElementInfo *)element defaultActions:(RetainPtr<NSArray>)defaultActions
+{
+    auto page = [_webView _page];
+    if (!page)
+        return nil;
+
+    return page->uiClient().actionsForElement(element, WTFMove(defaultActions));
 }
 
 @end