<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[182975] trunk/Source/WebKit2</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/182975">182975</a></dd>
<dt>Author</dt> <dd>commit-queue@webkit.org</dd>
<dt>Date</dt> <dd>2015-04-17 15:28:05 -0700 (Fri, 17 Apr 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>WebKit client should be able to add view controller for link preview.
https://bugs.webkit.org/show_bug.cgi?id=143686

Add delegate methods to WKUIDelegatePrivate so that a WebKit client can prepare a view controller
for link preview and react to the dismissal of this view controller. Also connect WKContentView to
preview gesture recognizer and forwards the delegate callbacks to corresponding delegate methods
in WKUIDelegatePrivate.

Patch by Yongjun Zhang &lt;yongjun_zhang@apple.com&gt; on 2015-04-17
Reviewed by Beth Dakin.

* Platform/spi/ios/UIKitSPI.h:
* UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
* UIProcess/ios/WKContentView.mm:
(-[WKContentView willMoveToWindow:]):
* UIProcess/ios/WKContentViewInteraction.h:
* UIProcess/ios/WKContentViewInteraction.mm:
(-[WKContentView cleanupInteraction]):
(-[WKContentView gestureRecognizer:canPreventGestureRecognizer:]):
(-[WKContentView gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]):
(-[WKContentView gestureRecognizerShouldBegin:]):
(-[WKContentView previewViewControllerForPosition:inSourceView:]):
(-[WKContentView commitPreviewViewController:]):
(-[WKContentView willPresentPreviewViewController:forPosition:inSourceView:]):
(-[WKContentView didDismissPreviewViewController:committing:]):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebKit2ChangeLog">trunk/Source/WebKit2/ChangeLog</a></li>
<li><a href="#trunkSourceWebKit2PlatformspiiosUIKitSPIh">trunk/Source/WebKit2/Platform/spi/ios/UIKitSPI.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessAPICocoaWKUIDelegatePrivateh">trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWKContentViewmm">trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWKContentViewInteractionh">trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h</a></li>
<li><a href="#trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm">trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebKit2ChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/ChangeLog (182974 => 182975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/ChangeLog        2015-04-17 22:25:46 UTC (rev 182974)
+++ trunk/Source/WebKit2/ChangeLog        2015-04-17 22:28:05 UTC (rev 182975)
</span><span class="lines">@@ -1,3 +1,30 @@
</span><ins>+2015-04-17  Yongjun Zhang  &lt;yongjun_zhang@apple.com&gt;
+
+        WebKit client should be able to add view controller for link preview.
+        https://bugs.webkit.org/show_bug.cgi?id=143686
+
+        Add delegate methods to WKUIDelegatePrivate so that a WebKit client can prepare a view controller
+        for link preview and react to the dismissal of this view controller. Also connect WKContentView to
+        preview gesture recognizer and forwards the delegate callbacks to corresponding delegate methods
+        in WKUIDelegatePrivate.
+
+        Reviewed by Beth Dakin.
+
+        * Platform/spi/ios/UIKitSPI.h:
+        * UIProcess/API/Cocoa/WKUIDelegatePrivate.h:
+        * UIProcess/ios/WKContentView.mm:
+        (-[WKContentView willMoveToWindow:]):
+        * UIProcess/ios/WKContentViewInteraction.h:
+        * UIProcess/ios/WKContentViewInteraction.mm:
+        (-[WKContentView cleanupInteraction]):
+        (-[WKContentView gestureRecognizer:canPreventGestureRecognizer:]):
+        (-[WKContentView gestureRecognizer:shouldRecognizeSimultaneouslyWithGestureRecognizer:]):
+        (-[WKContentView gestureRecognizerShouldBegin:]):
+        (-[WKContentView previewViewControllerForPosition:inSourceView:]):
+        (-[WKContentView commitPreviewViewController:]):
+        (-[WKContentView willPresentPreviewViewController:forPosition:inSourceView:]):
+        (-[WKContentView didDismissPreviewViewController:committing:]):
+
</ins><span class="cx"> 2015-04-17  Beth Dakin  &lt;bdakin@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Force mouse events should go through normal mouse event handling code paths
</span></span></pre></div>
<a id="trunkSourceWebKit2PlatformspiiosUIKitSPIh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/Platform/spi/ios/UIKitSPI.h (182974 => 182975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/Platform/spi/ios/UIKitSPI.h        2015-04-17 22:25:46 UTC (rev 182974)
+++ trunk/Source/WebKit2/Platform/spi/ios/UIKitSPI.h        2015-04-17 22:28:05 UTC (rev 182975)
</span><span class="lines">@@ -46,6 +46,7 @@
</span><span class="cx"> #import &lt;UIKit/UIPeripheralHost_Private.h&gt;
</span><span class="cx"> #import &lt;UIKit/UIPickerContentView_Private.h&gt;
</span><span class="cx"> #import &lt;UIKit/UIPickerView_Private.h&gt;
</span><ins>+#import &lt;UIKit/UIPresentationController_Private.h&gt;
</ins><span class="cx"> #import &lt;UIKit/UIScrollView_Private.h&gt;
</span><span class="cx"> #import &lt;UIKit/UIStringDrawing_Private.h&gt;
</span><span class="cx"> #import &lt;UIKit/UITableViewCell_Private.h&gt;
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessAPICocoaWKUIDelegatePrivateh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h (182974 => 182975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h        2015-04-17 22:25:46 UTC (rev 182974)
+++ trunk/Source/WebKit2/UIProcess/API/Cocoa/WKUIDelegatePrivate.h        2015-04-17 22:28:05 UTC (rev 182975)
</span><span class="lines">@@ -30,6 +30,7 @@
</span><span class="cx"> #import &lt;WebKit/_WKActivatedElementInfo.h&gt;
</span><span class="cx"> #import &lt;WebKit/_WKSecurityOrigin.h&gt;
</span><span class="cx"> 
</span><ins>+@class UIViewController;
</ins><span class="cx"> @class _WKFrameHandle;
</span><span class="cx"> 
</span><span class="cx"> @protocol WKUIDelegatePrivate &lt;WKUIDelegate&gt;
</span><span class="lines">@@ -53,6 +54,9 @@
</span><span class="cx"> - (NSArray *)_webView:(WKWebView *)webView actionsForElement:(_WKActivatedElementInfo *)element defaultActions:(NSArray *)defaultActions;
</span><span class="cx"> - (void)_webView:(WKWebView *)webView didNotHandleTapAsClickAtPoint:(CGPoint)point;
</span><span class="cx"> - (BOOL)_webView:(WKWebView *)webView shouldRequestGeolocationAuthorizationForURL:(NSURL *)url isMainFrame:(BOOL)isMainFrame mainFrameURL:(NSURL *)mainFrameURL;
</span><ins>+- (UIViewController *)_webView:(WKWebView *)webView previewViewControllerForURL:(NSURL *)url;
+- (void)_webView:(WKWebView *)webView commitPreviewedViewController:(UIViewController *)previewedViewController;
+- (void)_webView:(WKWebView *)webView didDismissPreviewViewController:(UIViewController *)previewedViewController;
</ins><span class="cx"> #endif
</span><span class="cx"> 
</span><span class="cx"> @end
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWKContentViewmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm (182974 => 182975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm        2015-04-17 22:25:46 UTC (rev 182974)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentView.mm        2015-04-17 22:28:05 UTC (rev 182975)
</span><span class="lines">@@ -267,11 +267,23 @@
</span><span class="cx">     NSNotificationCenter *defaultCenter = [NSNotificationCenter defaultCenter];
</span><span class="cx">     UIWindow *window = self.window;
</span><span class="cx"> 
</span><del>-    if (window)
</del><ins>+    if (window) {
</ins><span class="cx">         [defaultCenter removeObserver:self name:UIWindowDidMoveToScreenNotification object:window];
</span><ins>+#if __IPHONE_OS_VERSION_MIN_REQUIRED &gt;= 90000
+        [window.rootViewController unregisterPreviewSourceView:self];
+        [_previewGestureRecognizer setDelegate:nil];
+        _previewGestureRecognizer.clear();
+#endif
+    }
</ins><span class="cx"> 
</span><del>-    if (newWindow)
</del><ins>+    if (newWindow) {
</ins><span class="cx">         [defaultCenter addObserver:self selector:@selector(_windowDidMoveToScreenNotification:) name:UIWindowDidMoveToScreenNotification object:newWindow];
</span><ins>+#if __IPHONE_OS_VERSION_MIN_REQUIRED &gt;= 90000
+        [newWindow.rootViewController registerPreviewSourceView:self previewingDelegate:self];
+        _previewGestureRecognizer = self.gestureRecognizers.lastObject;
+        [_previewGestureRecognizer setDelegate:self];
+#endif
+    }
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (void)didMoveToWindow
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWKContentViewInteractionh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h (182974 => 182975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h        2015-04-17 22:25:46 UTC (rev 182974)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.h        2015-04-17 22:28:05 UTC (rev 182975)
</span><span class="lines">@@ -115,6 +115,7 @@
</span><span class="cx">     RetainPtr&lt;WKAirPlayRoutePicker&gt; _airPlayRoutePicker;
</span><span class="cx">     RetainPtr&lt;WKFormInputSession&gt; _formInputSession;
</span><span class="cx">     RetainPtr&lt;WKFileUploadPanel&gt; _fileUploadPanel;
</span><ins>+    RetainPtr&lt;UIGestureRecognizer&gt; _previewGestureRecognizer;
</ins><span class="cx"> 
</span><span class="cx">     std::unique_ptr&lt;WebKit::SmartMagnificationController&gt; _smartMagnificationController;
</span><span class="cx"> 
</span><span class="lines">@@ -199,4 +200,9 @@
</span><span class="cx"> - (void)_becomeFirstResponderWithSelectionMovingForward:(BOOL)selectingForward completionHandler:(void (^)(BOOL didBecomeFirstResponder))completionHandler;
</span><span class="cx"> @end
</span><span class="cx"> 
</span><ins>+#if __IPHONE_OS_VERSION_MIN_REQUIRED &gt;= 90000
+@interface WKContentView (WKInteractionPreview) &lt;UIViewControllerPreviewingDelegate&gt;
+@end
+#endif
+
</ins><span class="cx"> #endif // PLATFORM(IOS)
</span></span></pre></div>
<a id="trunkSourceWebKit2UIProcessiosWKContentViewInteractionmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm (182974 => 182975)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm        2015-04-17 22:25:46 UTC (rev 182974)
+++ trunk/Source/WebKit2/UIProcess/ios/WKContentViewInteraction.mm        2015-04-17 22:28:05 UTC (rev 182975)
</span><span class="lines">@@ -41,6 +41,7 @@
</span><span class="cx"> #import &quot;WKFormInputControl.h&quot;
</span><span class="cx"> #import &quot;WKFormSelectControl.h&quot;
</span><span class="cx"> #import &quot;WKInspectorNodeSearchGestureRecognizer.h&quot;
</span><ins>+#import &quot;WKUIDelegatePrivate.h&quot;
</ins><span class="cx"> #import &quot;WKWebViewConfiguration.h&quot;
</span><span class="cx"> #import &quot;WKWebViewInternal.h&quot;
</span><span class="cx"> #import &quot;WKWebViewPrivate.h&quot;
</span><span class="lines">@@ -369,6 +370,9 @@
</span><span class="cx">     [_twoFingerDoubleTapGestureRecognizer setDelegate:nil];
</span><span class="cx">     [self removeGestureRecognizer:_twoFingerDoubleTapGestureRecognizer.get()];
</span><span class="cx"> 
</span><ins>+    [_previewGestureRecognizer setDelegate:nil];
+    [self removeGestureRecognizer:_previewGestureRecognizer.get()];
+
</ins><span class="cx">     _inspectorNodeSearchEnabled = NO;
</span><span class="cx">     if (_inspectorNodeSearchGestureRecognizer) {
</span><span class="cx">         [_inspectorNodeSearchGestureRecognizer setDelegate:nil];
</span><span class="lines">@@ -817,7 +821,7 @@
</span><span class="cx"> {
</span><span class="cx">     // A long-press gesture can not be recognized while panning, but a pan can be recognized
</span><span class="cx">     // during a long-press gesture.
</span><del>-    BOOL shouldNotPreventScrollViewGestures = preventingGestureRecognizer == _highlightLongPressGestureRecognizer || preventingGestureRecognizer == _longPressGestureRecognizer;
</del><ins>+    BOOL shouldNotPreventScrollViewGestures = preventingGestureRecognizer == _highlightLongPressGestureRecognizer || preventingGestureRecognizer == _longPressGestureRecognizer || preventingGestureRecognizer == _previewGestureRecognizer;
</ins><span class="cx">     return !(shouldNotPreventScrollViewGestures
</span><span class="cx">         &amp;&amp; ([preventedGestureRecognizer isKindOfClass:NSClassFromString(@&quot;UIScrollViewPanGestureRecognizer&quot;)] || [preventedGestureRecognizer isKindOfClass:NSClassFromString(@&quot;UIScrollViewPinchGestureRecognizer&quot;)]));
</span><span class="cx"> }
</span><span class="lines">@@ -848,6 +852,9 @@
</span><span class="cx">     if (isSamePair(gestureRecognizer, otherGestureRecognizer, _singleTapGestureRecognizer.get(), _textSelectionAssistant.get().singleTapGesture))
</span><span class="cx">         return YES;
</span><span class="cx"> 
</span><ins>+    if (isSamePair(gestureRecognizer, otherGestureRecognizer, _highlightLongPressGestureRecognizer.get(), _previewGestureRecognizer.get()))
+        return YES;
+
</ins><span class="cx">     return NO;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -942,6 +949,16 @@
</span><span class="cx">         }
</span><span class="cx">     }
</span><span class="cx"> 
</span><ins>+    if (gestureRecognizer == _previewGestureRecognizer) {
+        [self ensurePositionInformationIsUpToDate:point];
+        if (_positionInformation.clickableElementName != &quot;A&quot;)
+            return NO;
+
+        String absoluteLinkURL = _positionInformation.url;
+        if (absoluteLinkURL.isEmpty() || !WebCore::protocolIsInHTTPFamily(absoluteLinkURL))
+            return NO;
+    }
+
</ins><span class="cx">     return YES;
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -2987,6 +3004,55 @@
</span><span class="cx"> 
</span><span class="cx"> @end
</span><span class="cx"> 
</span><ins>+#if __IPHONE_OS_VERSION_MIN_REQUIRED &gt;= 90000
+
+@implementation WKContentView (WKInteractionPreview)
+
+- (UIViewController *)previewViewControllerForPosition:(CGPoint)position inSourceView:(UIView *)sourceView
+{
+    ASSERT(self == sourceView);
+
+    if (_positionInformation.clickableElementName != &quot;A&quot;)
+        return nil;
+
+    String absoluteLinkURL = _positionInformation.url;
+    if (absoluteLinkURL.isEmpty() || !WebCore::protocolIsInHTTPFamily(absoluteLinkURL))
+        return nil;
+
+    _highlightLongPressCanClick = NO;
+
+    NSURL *targetURL = [NSURL URLWithString:_positionInformation.url];
+    id&lt;WKUIDelegatePrivate&gt; uiDelegate = static_cast&lt;id &lt;WKUIDelegatePrivate&gt;&gt;([_webView UIDelegate]);
+    if ([uiDelegate respondsToSelector:@selector(_webView:previewViewControllerForURL:)])
+        return [uiDelegate _webView:_webView previewViewControllerForURL:targetURL];
+
+    return nil;
+}
+
+- (void)commitPreviewViewController:(UIViewController *)viewController
+{
+    id&lt;WKUIDelegatePrivate&gt; uiDelegate = static_cast&lt;id &lt;WKUIDelegatePrivate&gt;&gt;([_webView UIDelegate]);
+    if ([uiDelegate respondsToSelector:@selector(_webView:commitPreviewedViewController:)])
+        [uiDelegate _webView:_webView commitPreviewedViewController:viewController];
+}
+
+- (void)willPresentPreviewViewController:(UIViewController *)viewController forPosition:(CGPoint)position inSourceView:(UIView *)sourceView
+{
+    [self _cancelInteraction];
+    [[viewController presentationController] setSourceRect:_positionInformation.bounds];
+}
+
+- (void)didDismissPreviewViewController:(UIViewController *)viewController committing:(BOOL)committing
+{
+    id&lt;WKUIDelegatePrivate&gt; uiDelegate = static_cast&lt;id &lt;WKUIDelegatePrivate&gt;&gt;([_webView UIDelegate]);
+    if ([uiDelegate respondsToSelector:@selector(_webView:didDismissPreviewViewController:)])
+        [uiDelegate _webView:_webView didDismissPreviewViewController:viewController];
+}
+
+@end
+
+#endif
+
</ins><span class="cx"> // UITextRange, UITextPosition and UITextSelectionRect implementations for WK2
</span><span class="cx"> 
</span><span class="cx"> @implementation WKTextRange (UITextInputAdditions)
</span></span></pre>
</div>
</div>

</body>
</html>