<!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>[218125] trunk</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/218125">218125</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2017-06-12 12:34:37 -0700 (Mon, 12 Jun 2017)</dd>
</dl>

<h3>Log Message</h3>
<pre>WebItemProviderPasteboard should call its completion block immediately after a synchronous load
https://bugs.webkit.org/show_bug.cgi?id=173225
<rdar://problem/32713144>

Reviewed by Tim Horton.

Source/WebCore:

Ensures that a completion block passed to doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout: will be
invoked immediately, if a synchronous timeout is specified and loading finishes before the synchronous timeout
is reached. To do this, we first factor out the completion logic into a new block. If the synchronous timeout
exists and dispatch_group_wait returns 0 (indicating that the dispatch group finished without hitting the
wait timeout) we simply invoke the block and return early; otherwise, we will register the completion block
using dispatch_group_notify.

Test: DataInteractionTests.WebItemProviderPasteboardLoading

* platform/ios/WebItemProviderPasteboard.mm:
(-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):

Tools:

Adds a new unit test to verify whether the completion block is called synchronously or asynchronously, in both
cases where the synchronous timeout is very large, and the synchronous timeout is not used (0).

* TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
(TestWebKitAPI::TEST):</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreplatformiosWebItemProviderPasteboardmm">trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsTestWebKitAPITestsiosDataInteractionTestsmm">trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (218124 => 218125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog   2017-06-12 19:19:38 UTC (rev 218124)
+++ trunk/Source/WebCore/ChangeLog      2017-06-12 19:34:37 UTC (rev 218125)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2017-06-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        WebItemProviderPasteboard should call its completion block immediately after a synchronous load
+        https://bugs.webkit.org/show_bug.cgi?id=173225
+        <rdar://problem/32713144>
+
+        Reviewed by Tim Horton.
+
+        Ensures that a completion block passed to doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout: will be
+        invoked immediately, if a synchronous timeout is specified and loading finishes before the synchronous timeout
+        is reached. To do this, we first factor out the completion logic into a new block. If the synchronous timeout
+        exists and dispatch_group_wait returns 0 (indicating that the dispatch group finished without hitting the
+        wait timeout) we simply invoke the block and return early; otherwise, we will register the completion block
+        using dispatch_group_notify.
+
+        Test: DataInteractionTests.WebItemProviderPasteboardLoading
+
+        * platform/ios/WebItemProviderPasteboard.mm:
+        (-[WebItemProviderPasteboard doAfterLoadingProvidedContentIntoFileURLs:synchronousTimeout:]):
+
</ins><span class="cx"> 2017-06-12  Jeremy Jones  <jeremyj@apple.com>
</span><span class="cx"> 
</span><span class="cx">         WebAVPlayerController minTime and maxTime should be calculated properties to provide correct values when streaming.
</span></span></pre></div>
<a id="trunkSourceWebCoreplatformiosWebItemProviderPasteboardmm"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm (218124 => 218125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm   2017-06-12 19:19:38 UTC (rev 218124)
+++ trunk/Source/WebCore/platform/ios/WebItemProviderPasteboard.mm      2017-06-12 19:34:37 UTC (rev 218125)
</span><span class="lines">@@ -484,15 +484,19 @@
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     RetainPtr<WebItemProviderPasteboard> retainedSelf = self;
</span><del>-    dispatch_group_notify(fileLoadingGroup.get(), dispatch_get_main_queue(), [retainedSelf, fileLoadingGroup, typeToFileURLMaps, completionBlock = makeBlockPtr(action), changeCountBeforeLoading] {
</del><ins>+    auto itemLoadCompletion = [retainedSelf, synchronousFileLoadingGroup, fileLoadingGroup, typeToFileURLMaps, completionBlock = makeBlockPtr(action), changeCountBeforeLoading] {
</ins><span class="cx">         if (changeCountBeforeLoading == retainedSelf->_changeCount)
</span><span class="cx">             retainedSelf->_typeToFileURLMaps = typeToFileURLMaps;
</span><span class="cx"> 
</span><span class="cx">         completionBlock([retainedSelf fileURLsForDataInteraction]);
</span><del>-    });
</del><ins>+    };
</ins><span class="cx"> 
</span><del>-    if (synchronousTimeout > 0)
-        dispatch_group_wait(synchronousFileLoadingGroup.get(), dispatch_time(DISPATCH_TIME_NOW, synchronousTimeout * NSEC_PER_SEC));
</del><ins>+    if (synchronousTimeout > 0 && !dispatch_group_wait(synchronousFileLoadingGroup.get(), dispatch_time(DISPATCH_TIME_NOW, synchronousTimeout * NSEC_PER_SEC))) {
+        itemLoadCompletion();
+        return;
+    }
+
+    dispatch_group_notify(fileLoadingGroup.get(), dispatch_get_main_queue(), itemLoadCompletion);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> - (WebItemProviderRegistrationInfoList *)registrationInfoAtIndex:(NSUInteger)index
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (218124 => 218125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog    2017-06-12 19:19:38 UTC (rev 218124)
+++ trunk/Tools/ChangeLog       2017-06-12 19:34:37 UTC (rev 218125)
</span><span class="lines">@@ -1,3 +1,17 @@
</span><ins>+2017-06-12  Wenson Hsieh  <wenson_hsieh@apple.com>
+
+        WebItemProviderPasteboard should call its completion block immediately after a synchronous load
+        https://bugs.webkit.org/show_bug.cgi?id=173225
+        <rdar://problem/32713144>
+
+        Reviewed by Tim Horton.
+
+        Adds a new unit test to verify whether the completion block is called synchronously or asynchronously, in both
+        cases where the synchronous timeout is very large, and the synchronous timeout is not used (0).
+
+        * TestWebKitAPI/Tests/ios/DataInteractionTests.mm:
+        (TestWebKitAPI::TEST):
+
</ins><span class="cx"> 2017-06-12  Jonathan Bedard  <jbedard@apple.com>
</span><span class="cx"> 
</span><span class="cx">         Return correct process names for iOS on-device testing
</span></span></pre></div>
<a id="trunkToolsTestWebKitAPITestsiosDataInteractionTestsmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm (218124 => 218125)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm      2017-06-12 19:19:38 UTC (rev 218124)
+++ trunk/Tools/TestWebKitAPI/Tests/ios/DataInteractionTests.mm 2017-06-12 19:34:37 UTC (rev 218125)
</span><span class="lines">@@ -39,6 +39,7 @@
</span><span class="cx"> #import <WebKit/WKPreferencesPrivate.h>
</span><span class="cx"> #import <WebKit/WKProcessPoolPrivate.h>
</span><span class="cx"> #import <WebKit/WKWebViewConfigurationPrivate.h>
</span><ins>+#import <WebKit/WebItemProviderPasteboard.h>
</ins><span class="cx"> #import <WebKit/_WKProcessPoolConfiguration.h>
</span><span class="cx"> 
</span><span class="cx"> typedef void (^FileLoadCompletionBlock)(NSURL *, BOOL, NSError *);
</span><span class="lines">@@ -848,6 +849,52 @@
</span><span class="cx">     [webView _simulatePrepareForDataInteractionSession:nil completion:^() { }];
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+TEST(DataInteractionTests, WebItemProviderPasteboardLoading)
+{
+    static NSString *fastString = @"This data loads quickly";
+    static NSString *slowString = @"This data loads slowly";
+
+    WebItemProviderPasteboard *pasteboard = [WebItemProviderPasteboard sharedInstance];
+    auto fastItem = adoptNS([[UIItemProvider alloc] init]);
+    [fastItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
+    {
+        completionBlock([fastString dataUsingEncoding:NSUTF8StringEncoding], nil);
+        return nil;
+    }];
+
+    auto slowItem = adoptNS([[UIItemProvider alloc] init]);
+    [slowItem registerDataRepresentationForTypeIdentifier:(NSString *)kUTTypeUTF8PlainText options:nil loadHandler:^NSProgress *(UIItemProviderDataLoadCompletionBlock completionBlock)
+    {
+        sleep(2);
+        completionBlock([slowString dataUsingEncoding:NSUTF8StringEncoding], nil);
+        return nil;
+    }];
+
+    __block bool hasRunFirstCompletionBlock = false;
+    pasteboard.itemProviders = @[ fastItem.get(), slowItem.get() ];
+    [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
+        EXPECT_EQ(2UL, urls.count);
+        auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
+        auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
+        EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
+        EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
+        hasRunFirstCompletionBlock = true;
+    } synchronousTimeout:600];
+    EXPECT_TRUE(hasRunFirstCompletionBlock);
+
+    __block bool hasRunSecondCompletionBlock = false;
+    [pasteboard doAfterLoadingProvidedContentIntoFileURLs:^(NSArray<NSURL *> *urls) {
+        EXPECT_EQ(2UL, urls.count);
+        auto firstString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[0] encoding:NSUTF8StringEncoding error:nil]);
+        auto secondString = adoptNS([[NSString alloc] initWithContentsOfURL:urls[1] encoding:NSUTF8StringEncoding error:nil]);
+        EXPECT_WK_STREQ(fastString, [firstString UTF8String]);
+        EXPECT_WK_STREQ(slowString, [secondString UTF8String]);
+        hasRunSecondCompletionBlock = true;
+    } synchronousTimeout:0];
+    EXPECT_FALSE(hasRunSecondCompletionBlock);
+    TestWebKitAPI::Util::run(&hasRunSecondCompletionBlock);
+}
+
</ins><span class="cx"> } // namespace TestWebKitAPI
</span><span class="cx"> 
</span><span class="cx"> #endif // ENABLE(DATA_INTERACTION)
</span></span></pre>
</div>
</div>

</body>
</html>