<!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>[192314] 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/192314">192314</a></dd>
<dt>Author</dt> <dd>wenson_hsieh@apple.com</dd>
<dt>Date</dt> <dd>2015-11-11 10:15:56 -0800 (Wed, 11 Nov 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>UI-side scripts in WebKitTestRunner should wait until event handling completes before finishing
https://bugs.webkit.org/show_bug.cgi?id=151101
&lt;rdar://problem/23428601&gt;

Reviewed by Simon Fraser.

Tools:

WebKitTestRunner may still crash in the scenario where a marker event is dequeued and handled
after uiScriptComplete has been called. This patch teaches the UI script execution context to
defer script completion until all non-persistent tasks (currently tap, double tap and hardware
keyboard) have been handled, so marker events will no longer bleed through tests.

We accomplish this by changing the behavior of uiScriptComplete. When calling uiScriptComplete,
we store that a request to complete the UI-side script for the current parent callback has been
made. Subsequently, when a callback (either persistent or non-persistent) finishes invoking and
a request has been made to complete the UI script (this request may have been made when running
a previous callback) we check if all the non-persistent callbacks that have the same parent
callback as the current one have finished. If so, we complete the callback immediately;
otherwise, we wait until the in-flight non-persistent callbacks finish execution to complete the
UI script.

This patch also refactors some logic in UIScriptContext. It introduces a new convention for
assigning IDs to callbacks: IDs 1000 and above are treated as non-persistent callbacks, whereas
IDs between 0 and 999 are persistent task callbacks. This is similar to the existing convention
for assigning IDs in the 100s range to parent callbacks, and allows us to easily differentiate
between callbacks that are persistent and non-persistent, as well as determine when an existing
persistent callback must be unregistered before a new callback function can be set.

* WebKitTestRunner/UIScriptContext/UIScriptContext.cpp:
(isPersistentCallbackID):
(UIScriptContext::runUIScript):
(UIScriptContext::nextTaskCallbackID):
(UIScriptContext::prepareForAsyncTask):
(UIScriptContext::asyncTaskComplete):
(UIScriptContext::registerCallback):
(UIScriptContext::fireCallback):
(UIScriptContext::requestUIScriptCompletion):
(UIScriptContext::tryToCompleteUIScriptForCurrentParentCallback):
(UIScriptContext::currentParentCallbackHasOutstandingAsyncTasks):
(UIScriptContext::uiScriptComplete): Deleted.
* WebKitTestRunner/UIScriptContext/UIScriptContext.h:
(WTR::UIScriptContext::currentParentCallbackIsPendingCompletion):
* WebKitTestRunner/UIScriptContext/UIScriptController.cpp:
(WTR::UIScriptController::setWillBeginZoomingCallback):
(WTR::UIScriptController::willBeginZoomingCallback):
(WTR::UIScriptController::setDidEndZoomingCallback):
(WTR::UIScriptController::didEndZoomingCallback):
(WTR::UIScriptController::setDidShowKeyboardCallback):
(WTR::UIScriptController::didShowKeyboardCallback):
(WTR::UIScriptController::setDidHideKeyboardCallback):
(WTR::UIScriptController::didHideKeyboardCallback):
(WTR::UIScriptController::uiScriptComplete):
* WebKitTestRunner/UIScriptContext/UIScriptController.h:
* WebKitTestRunner/ios/UIScriptControllerIOS.mm:
(WTR::UIScriptController::doAsyncTask):
(WTR::UIScriptController::zoomToScale):
(WTR::UIScriptController::singleTapAtPoint):
(WTR::UIScriptController::doubleTapAtPoint):
(WTR::UIScriptController::typeCharacterUsingHardwareKeyboard):
(WTR::UIScriptController::platformSetWillBeginZoomingCallback):
(WTR::UIScriptController::platformSetDidEndZoomingCallback):
(WTR::UIScriptController::platformSetDidShowKeyboardCallback):
(WTR::UIScriptController::platformSetDidHideKeyboardCallback):
(WTR::UIScriptController::platformClearAllCallbacks): Deleted.
* WebKitTestRunner/mac/UIScriptControllerMac.mm:
(WTR::UIScriptController::doAsyncTask):

LayoutTests:

Ensures that all tests using UIScriptController properly complete the UI script from within
a completion callback.

* fast/events/ios/clicking-document-should-not-trigger-focus.html:
* fast/events/ios/input-value-after-oninput.html:
* fast/events/ios/single-tap-generates-click.html:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsfasteventsiosclickingdocumentshouldnottriggerfocushtml">trunk/LayoutTests/fast/events/ios/clicking-document-should-not-trigger-focus.html</a></li>
<li><a href="#trunkLayoutTestsfasteventsiosinputvalueafteroninputhtml">trunk/LayoutTests/fast/events/ios/input-value-after-oninput.html</a></li>
<li><a href="#trunkLayoutTestsfasteventsiossingletapgeneratesclickhtml">trunk/LayoutTests/fast/events/ios/single-tap-generates-click.html</a></li>
<li><a href="#trunkToolsChangeLog">trunk/Tools/ChangeLog</a></li>
<li><a href="#trunkToolsWebKitTestRunnerUIScriptContextUIScriptContextcpp">trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerUIScriptContextUIScriptContexth">trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.h</a></li>
<li><a href="#trunkToolsWebKitTestRunnerUIScriptContextUIScriptControllercpp">trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.cpp</a></li>
<li><a href="#trunkToolsWebKitTestRunnerUIScriptContextUIScriptControllerh">trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.h</a></li>
<li><a href="#trunkToolsWebKitTestRunneriosUIScriptControllerIOSmm">trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm</a></li>
<li><a href="#trunkToolsWebKitTestRunnermacUIScriptControllerMacmm">trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/LayoutTests/ChangeLog        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -1,3 +1,18 @@
</span><ins>+2015-11-10  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
+
+        UI-side scripts in WebKitTestRunner should wait until event handling completes before finishing
+        https://bugs.webkit.org/show_bug.cgi?id=151101
+        &lt;rdar://problem/23428601&gt;
+
+        Reviewed by Simon Fraser.
+
+        Ensures that all tests using UIScriptController properly complete the UI script from within
+        a completion callback.
+
+        * fast/events/ios/clicking-document-should-not-trigger-focus.html:
+        * fast/events/ios/input-value-after-oninput.html:
+        * fast/events/ios/single-tap-generates-click.html:
+
</ins><span class="cx"> 2015-11-10  Brady Eidson  &lt;beidson@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Modern IDB: Make indexes actually index.
</span></span></pre></div>
<a id="trunkLayoutTestsfasteventsiosclickingdocumentshouldnottriggerfocushtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/events/ios/clicking-document-should-not-trigger-focus.html (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/events/ios/clicking-document-should-not-trigger-focus.html        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/LayoutTests/fast/events/ios/clicking-document-should-not-trigger-focus.html        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -5,10 +5,14 @@
</span><span class="cx">     &lt;head&gt;
</span><span class="cx">         &lt;script id=&quot;ui-script&quot; type=&quot;text/plain&quot;&gt;
</span><span class="cx">             (function() {
</span><del>-                uiController.singleTapAtPoint(100, 300);
</del><ins>+                uiController.singleTapAtPoint(100, 300, function() {
+                    uiController.uiScriptComplete(&quot;&quot;);
+                });
</ins><span class="cx">             })();
</span><span class="cx">         &lt;/script&gt;
</span><span class="cx">         &lt;script&gt;
</span><ins>+            var uiScriptHasCompleted = false;
+            var clickHasBeenHandled = false;
</ins><span class="cx">             if (window.testRunner) {
</span><span class="cx">                 testRunner.dumpAsText();
</span><span class="cx">                 testRunner.waitUntilDone();
</span><span class="lines">@@ -24,11 +28,17 @@
</span><span class="cx">                 document.addEventListener(&quot;click&quot;, function() {
</span><span class="cx">                     document.body.appendChild(document.createTextNode(&quot;The currently focused element is of type &quot; + document.activeElement.tagName));
</span><span class="cx">                     document.body.appendChild(document.createElement(&quot;br&quot;));
</span><del>-                    if (window.testRunner)
</del><ins>+                    clickHasBeenHandled = true;
+                    if (window.testRunner &amp;&amp; uiScriptHasCompleted)
</ins><span class="cx">                         testRunner.notifyDone();
</span><span class="cx">                 });
</span><del>-                if (window.testRunner &amp;&amp; testRunner.runUIScript)
-                    testRunner.runUIScript(getUIScript(), function() { });
</del><ins>+                if (window.testRunner &amp;&amp; testRunner.runUIScript) {
+                    testRunner.runUIScript(getUIScript(), function() {
+                        uiScriptHasCompleted = true;
+                        if (clickHasBeenHandled)
+                            testRunner.notifyDone();
+                    });
+                }
</ins><span class="cx">             }
</span><span class="cx">         &lt;/script&gt;
</span><span class="cx">     &lt;/head&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfasteventsiosinputvalueafteroninputhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/events/ios/input-value-after-oninput.html (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/events/ios/input-value-after-oninput.html        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/LayoutTests/fast/events/ios/input-value-after-oninput.html        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -4,15 +4,18 @@
</span><span class="cx">     &lt;meta name=&quot;viewport&quot; content=&quot;initial-scale=1.0&quot;&gt;
</span><span class="cx">     &lt;script id=&quot;ui-script&quot; type=&quot;text/plain&quot;&gt;
</span><span class="cx">         (function() {
</span><del>-            uiController.singleTapAtPoint(50, 25, function() {
-                uiController.didShowKeyboardCallback = function() {
-                    uiController.typeCharacterUsingHardwareKeyboard(&quot;a&quot;, function() { });
-                }
-            });
</del><ins>+            uiController.didShowKeyboardCallback = function() {
+                uiController.typeCharacterUsingHardwareKeyboard(&quot;a&quot;, function() {
+                    uiController.uiScriptComplete();
+                });
+            }
+            uiController.singleTapAtPoint(50, 25, function() {});
</ins><span class="cx">         })();
</span><span class="cx">     &lt;/script&gt;
</span><span class="cx"> 
</span><span class="cx">     &lt;script&gt;
</span><ins>+        var uiScriptHasCompleted = false;
+        var oninputHasBeenHandled = false;
</ins><span class="cx">         if (window.testRunner) {
</span><span class="cx">             testRunner.dumpAsText();
</span><span class="cx">             testRunner.waitUntilDone();
</span><span class="lines">@@ -25,7 +28,9 @@
</span><span class="cx"> 
</span><span class="cx">         function handleValueChanged(value) {
</span><span class="cx">             document.getElementById(&quot;console&quot;).textContent = &quot;Successfully handled oninput, value is now \&quot;&quot; + value.toLowerCase() + &quot;\&quot;&quot;;
</span><del>-            testRunner.notifyDone();
</del><ins>+            oninputHasBeenHandled = true;
+            if (uiScriptHasCompleted)
+                testRunner.notifyDone();
</ins><span class="cx">         }
</span><span class="cx"> 
</span><span class="cx">         function runTest()
</span><span class="lines">@@ -33,7 +38,11 @@
</span><span class="cx">             if (!window.testRunner || !testRunner.runUIScript)
</span><span class="cx">                 return;
</span><span class="cx"> 
</span><del>-            testRunner.runUIScript(getUIScript(), function(result) { });
</del><ins>+            testRunner.runUIScript(getUIScript(), function() {
+                uiScriptHasCompleted = true;
+                if (oninputHasBeenHandled)
+                    testRunner.notifyDone();
+            });
</ins><span class="cx">         }
</span><span class="cx">     &lt;/script&gt;
</span><span class="cx"> &lt;/head&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfasteventsiossingletapgeneratesclickhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/events/ios/single-tap-generates-click.html (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/events/ios/single-tap-generates-click.html        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/LayoutTests/fast/events/ios/single-tap-generates-click.html        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -5,10 +5,14 @@
</span><span class="cx">     &lt;meta name=&quot;viewport&quot; content=&quot;width=device-width&quot;&gt;
</span><span class="cx">     &lt;script id=&quot;ui-script&quot; type=&quot;text/plain&quot;&gt;
</span><span class="cx">         (function() {
</span><del>-            uiController.singleTapAtPoint(50, 50);
</del><ins>+            uiController.singleTapAtPoint(50, 50, function() {
+                uiController.uiScriptComplete();
+            });
</ins><span class="cx">         })();
</span><span class="cx">     &lt;/script&gt;
</span><span class="cx">     &lt;script&gt;
</span><ins>+        var uiScriptHasCompleted = false;
+        var boxHasBeenClicked = false;
</ins><span class="cx">         if (window.testRunner) {
</span><span class="cx">             testRunner.dumpAsText();
</span><span class="cx">             testRunner.waitUntilDone();
</span><span class="lines">@@ -23,7 +27,9 @@
</span><span class="cx">         {
</span><span class="cx">             if (testRunner.runUIScript) {
</span><span class="cx">                 testRunner.runUIScript(getUIScript(), function() {
</span><del>-                    // Just wait for the tap.
</del><ins>+                    uiScriptHasCompleted = true;
+                    if (boxHasBeenClicked)
+                        testRunner.notifyDone();
</ins><span class="cx">                 });
</span><span class="cx">             }
</span><span class="cx">         }
</span><span class="lines">@@ -31,7 +37,8 @@
</span><span class="cx">         function boxClicked(event)
</span><span class="cx">         {
</span><span class="cx">             document.getElementById('target').textContent = 'PASS: received click event at ' + event.clientX + ' ' + event.clientY;
</span><del>-            if (window.testRunner)
</del><ins>+            boxHasBeenClicked = true;
+            if (uiScriptHasCompleted &amp;&amp; window.testRunner)
</ins><span class="cx">                 testRunner.notifyDone();
</span><span class="cx">         }
</span><span class="cx">     &lt;/script&gt;
</span></span></pre></div>
<a id="trunkToolsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Tools/ChangeLog (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/ChangeLog        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/Tools/ChangeLog        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -1,3 +1,71 @@
</span><ins>+2015-11-10  Wenson Hsieh  &lt;wenson_hsieh@apple.com&gt;
+
+        UI-side scripts in WebKitTestRunner should wait until event handling completes before finishing
+        https://bugs.webkit.org/show_bug.cgi?id=151101
+        &lt;rdar://problem/23428601&gt;
+
+        Reviewed by Simon Fraser.
+
+        WebKitTestRunner may still crash in the scenario where a marker event is dequeued and handled
+        after uiScriptComplete has been called. This patch teaches the UI script execution context to
+        defer script completion until all non-persistent tasks (currently tap, double tap and hardware
+        keyboard) have been handled, so marker events will no longer bleed through tests.
+
+        We accomplish this by changing the behavior of uiScriptComplete. When calling uiScriptComplete,
+        we store that a request to complete the UI-side script for the current parent callback has been
+        made. Subsequently, when a callback (either persistent or non-persistent) finishes invoking and
+        a request has been made to complete the UI script (this request may have been made when running
+        a previous callback) we check if all the non-persistent callbacks that have the same parent
+        callback as the current one have finished. If so, we complete the callback immediately;
+        otherwise, we wait until the in-flight non-persistent callbacks finish execution to complete the
+        UI script.
+
+        This patch also refactors some logic in UIScriptContext. It introduces a new convention for
+        assigning IDs to callbacks: IDs 1000 and above are treated as non-persistent callbacks, whereas
+        IDs between 0 and 999 are persistent task callbacks. This is similar to the existing convention
+        for assigning IDs in the 100s range to parent callbacks, and allows us to easily differentiate
+        between callbacks that are persistent and non-persistent, as well as determine when an existing
+        persistent callback must be unregistered before a new callback function can be set.
+
+        * WebKitTestRunner/UIScriptContext/UIScriptContext.cpp:
+        (isPersistentCallbackID):
+        (UIScriptContext::runUIScript):
+        (UIScriptContext::nextTaskCallbackID):
+        (UIScriptContext::prepareForAsyncTask):
+        (UIScriptContext::asyncTaskComplete):
+        (UIScriptContext::registerCallback):
+        (UIScriptContext::fireCallback):
+        (UIScriptContext::requestUIScriptCompletion):
+        (UIScriptContext::tryToCompleteUIScriptForCurrentParentCallback):
+        (UIScriptContext::currentParentCallbackHasOutstandingAsyncTasks):
+        (UIScriptContext::uiScriptComplete): Deleted.
+        * WebKitTestRunner/UIScriptContext/UIScriptContext.h:
+        (WTR::UIScriptContext::currentParentCallbackIsPendingCompletion):
+        * WebKitTestRunner/UIScriptContext/UIScriptController.cpp:
+        (WTR::UIScriptController::setWillBeginZoomingCallback):
+        (WTR::UIScriptController::willBeginZoomingCallback):
+        (WTR::UIScriptController::setDidEndZoomingCallback):
+        (WTR::UIScriptController::didEndZoomingCallback):
+        (WTR::UIScriptController::setDidShowKeyboardCallback):
+        (WTR::UIScriptController::didShowKeyboardCallback):
+        (WTR::UIScriptController::setDidHideKeyboardCallback):
+        (WTR::UIScriptController::didHideKeyboardCallback):
+        (WTR::UIScriptController::uiScriptComplete):
+        * WebKitTestRunner/UIScriptContext/UIScriptController.h:
+        * WebKitTestRunner/ios/UIScriptControllerIOS.mm:
+        (WTR::UIScriptController::doAsyncTask):
+        (WTR::UIScriptController::zoomToScale):
+        (WTR::UIScriptController::singleTapAtPoint):
+        (WTR::UIScriptController::doubleTapAtPoint):
+        (WTR::UIScriptController::typeCharacterUsingHardwareKeyboard):
+        (WTR::UIScriptController::platformSetWillBeginZoomingCallback):
+        (WTR::UIScriptController::platformSetDidEndZoomingCallback):
+        (WTR::UIScriptController::platformSetDidShowKeyboardCallback):
+        (WTR::UIScriptController::platformSetDidHideKeyboardCallback):
+        (WTR::UIScriptController::platformClearAllCallbacks): Deleted.
+        * WebKitTestRunner/mac/UIScriptControllerMac.mm:
+        (WTR::UIScriptController::doAsyncTask):
+
</ins><span class="cx"> 2015-11-10  Daniel Bates  &lt;dabates@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Teach Makefile to build LayoutTestRelay when building for iOS Simulator
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerUIScriptContextUIScriptContextcpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.cpp (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.cpp        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.cpp        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -36,6 +36,11 @@
</span><span class="cx"> 
</span><span class="cx"> using namespace WTR;
</span><span class="cx"> 
</span><ins>+static inline bool isPersistentCallbackID(unsigned callbackID)
+{
+    return callbackID &lt; firstNonPersistentCallbackID;
+}
+
</ins><span class="cx"> UIScriptContext::UIScriptContext(UIScriptContextDelegate&amp; delegate)
</span><span class="cx">     : m_context(Adopt, JSGlobalContextCreate(nullptr))
</span><span class="cx">     , m_delegate(delegate)
</span><span class="lines">@@ -59,20 +64,22 @@
</span><span class="cx">     
</span><span class="cx">     if (!hasOutstandingAsyncTasks()) {
</span><span class="cx">         JSValueRef stringifyException = nullptr;
</span><del>-        JSRetainPtr&lt;JSStringRef&gt; resultString(Adopt, JSValueToStringCopy(m_context.get(), result, &amp;stringifyException));
-        uiScriptComplete(resultString.get());
-        m_currentScriptCallbackID = 0;
</del><ins>+        requestUIScriptCompletion(JSValueToStringCopy(m_context.get(), result, &amp;stringifyException));
+        tryToCompleteUIScriptForCurrentParentCallback();
</ins><span class="cx">     }
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned UIScriptContext::nextTaskCallbackID()
</del><ins>+unsigned UIScriptContext::nextTaskCallbackID(CallbackType type)
</ins><span class="cx"> {
</span><del>-    return ++m_nextTaskCallbackID;
</del><ins>+    if (type == CallbackTypeNonPersistent)
+        return ++m_nextTaskCallbackID + firstNonPersistentCallbackID;
+
+    return type;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned UIScriptContext::prepareForAsyncTask(JSValueRef callback)
</del><ins>+unsigned UIScriptContext::prepareForAsyncTask(JSValueRef callback, CallbackType type)
</ins><span class="cx"> {
</span><del>-    unsigned callbackID = nextTaskCallbackID();
</del><ins>+    unsigned callbackID = nextTaskCallbackID(type);
</ins><span class="cx">     
</span><span class="cx">     JSValueProtect(m_context.get(), callback);
</span><span class="cx">     Task task;
</span><span class="lines">@@ -99,12 +106,16 @@
</span><span class="cx">     JSObjectCallAsFunction(m_context.get(), callbackObject, JSContextGetGlobalObject(m_context.get()), 0, nullptr, &amp;exception);
</span><span class="cx">     JSValueUnprotect(m_context.get(), task.callback);
</span><span class="cx">     
</span><ins>+    tryToCompleteUIScriptForCurrentParentCallback();
</ins><span class="cx">     m_currentScriptCallbackID = 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-unsigned UIScriptContext::registerCallback(JSValueRef taskCallback)
</del><ins>+unsigned UIScriptContext::registerCallback(JSValueRef taskCallback, CallbackType type)
</ins><span class="cx"> {
</span><del>-    return prepareForAsyncTask(taskCallback);
</del><ins>+    if (m_callbacks.contains(type))
+        unregisterCallback(type);
+
+    return prepareForAsyncTask(taskCallback, type);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UIScriptContext::unregisterCallback(unsigned callbackID)
</span><span class="lines">@@ -133,14 +144,31 @@
</span><span class="cx">     exception = nullptr;
</span><span class="cx">     JSObjectCallAsFunction(m_context.get(), callbackObject, JSContextGetGlobalObject(m_context.get()), 0, nullptr, &amp;exception);
</span><span class="cx">     
</span><ins>+    tryToCompleteUIScriptForCurrentParentCallback();
</ins><span class="cx">     m_currentScriptCallbackID = 0;
</span><span class="cx"> }
</span><span class="cx"> 
</span><del>-void UIScriptContext::uiScriptComplete(JSStringRef result)
</del><ins>+void UIScriptContext::requestUIScriptCompletion(JSStringRef result)
</ins><span class="cx"> {
</span><ins>+    ASSERT(m_currentScriptCallbackID);
+    if (currentParentCallbackIsPendingCompletion())
+        return;
+
+    // This request for the UI script to complete is not fulfilled until the last non-persistent task for the parent callback is finished.
+    m_uiScriptResultsPendingCompletion.add(m_currentScriptCallbackID, result ? JSStringRetain(result) : nullptr);
+}
+
+void UIScriptContext::tryToCompleteUIScriptForCurrentParentCallback()
+{
+    if (!currentParentCallbackIsPendingCompletion() || currentParentCallbackHasOutstandingAsyncTasks())
+        return;
+
+    JSStringRef result = m_uiScriptResultsPendingCompletion.take(m_currentScriptCallbackID);
</ins><span class="cx">     WKRetainPtr&lt;WKStringRef&gt; uiScriptResult = adoptWK(WKStringCreateWithJSString(result));
</span><span class="cx">     m_delegate.uiScriptDidComplete(uiScriptResult.get(), m_currentScriptCallbackID);
</span><span class="cx">     m_currentScriptCallbackID = 0;
</span><ins>+    if (result)
+        JSStringRelease(result);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSObjectRef UIScriptContext::objectFromRect(const WKRect&amp; rect) const
</span><span class="lines">@@ -155,3 +183,15 @@
</span><span class="cx">     return object;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+bool UIScriptContext::currentParentCallbackHasOutstandingAsyncTasks() const
+{
+    for (auto entry : m_callbacks) {
+        unsigned callbackID = entry.key;
+        Task task = entry.value;
+        if (task.parentScriptCallbackID == m_currentScriptCallbackID &amp;&amp; !isPersistentCallbackID(callbackID))
+            return true;
+    }
+
+    return false;
+}
+
</ins></span></pre></div>
<a id="trunkToolsWebKitTestRunnerUIScriptContextUIScriptContexth"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.h (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.h        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptContext.h        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -39,25 +39,35 @@
</span><span class="cx">     virtual void uiScriptDidComplete(WKStringRef result, unsigned callbackID) = 0;
</span><span class="cx"> };
</span><span class="cx"> 
</span><ins>+const unsigned firstNonPersistentCallbackID = 1000;
+
+typedef enum  {
+    CallbackTypeWillBeginZooming = 0,
+    CallbackTypeDidEndZooming,
+    CallbackTypeDidShowKeyboard,
+    CallbackTypeDidHideKeyboard,
+    CallbackTypeNonPersistent = firstNonPersistentCallbackID
+} CallbackType;
+
</ins><span class="cx"> class UIScriptContext {
</span><span class="cx"> public:
</span><span class="cx"> 
</span><span class="cx">     UIScriptContext(UIScriptContextDelegate&amp;);
</span><span class="cx"> 
</span><span class="cx">     void runUIScript(WKStringRef script, unsigned scriptCallbackID);
</span><del>-    void uiScriptComplete(JSStringRef);
</del><ins>+    void requestUIScriptCompletion(JSStringRef);
</ins><span class="cx"> 
</span><span class="cx">     // For one-shot tasks callbacks.
</span><del>-    unsigned prepareForAsyncTask(JSValueRef taskCallback);
</del><ins>+    unsigned prepareForAsyncTask(JSValueRef taskCallback, CallbackType);
</ins><span class="cx">     void asyncTaskComplete(unsigned taskCallbackID);
</span><span class="cx"> 
</span><span class="cx">     // For persistent callbacks.
</span><del>-    unsigned registerCallback(JSValueRef taskCallback);
</del><ins>+    unsigned registerCallback(JSValueRef taskCallback, CallbackType);
</ins><span class="cx">     JSValueRef callbackWithID(unsigned callbackID);
</span><span class="cx">     void unregisterCallback(unsigned callbackID);
</span><span class="cx">     void fireCallback(unsigned callbackID);
</span><span class="cx"> 
</span><del>-    unsigned nextTaskCallbackID();
</del><ins>+    unsigned nextTaskCallbackID(CallbackType);
</ins><span class="cx"> 
</span><span class="cx">     JSObjectRef objectFromRect(const WKRect&amp;) const;
</span><span class="cx"> 
</span><span class="lines">@@ -65,12 +75,16 @@
</span><span class="cx">     JSRetainPtr&lt;JSGlobalContextRef&gt; m_context;
</span><span class="cx">     
</span><span class="cx">     bool hasOutstandingAsyncTasks() const { return !m_callbacks.isEmpty(); }
</span><ins>+    bool currentParentCallbackIsPendingCompletion() const { return m_uiScriptResultsPendingCompletion.contains(m_currentScriptCallbackID); }
+    bool currentParentCallbackHasOutstandingAsyncTasks() const;
+    void tryToCompleteUIScriptForCurrentParentCallback();
</ins><span class="cx">     
</span><span class="cx">     struct Task {
</span><span class="cx">         unsigned parentScriptCallbackID { 0 };
</span><span class="cx">         JSValueRef callback { nullptr };
</span><span class="cx">     };
</span><span class="cx">     HashMap&lt;unsigned, Task&gt; m_callbacks;
</span><ins>+    HashMap&lt;unsigned, JSStringRef&gt; m_uiScriptResultsPendingCompletion;
</ins><span class="cx"> 
</span><span class="cx">     UIScriptContextDelegate&amp; m_delegate;
</span><span class="cx">     RefPtr&lt;UIScriptController&gt; m_controller;
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerUIScriptContextUIScriptControllercpp"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.cpp (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.cpp        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.cpp        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -55,46 +55,46 @@
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::setWillBeginZoomingCallback(JSValueRef callback)
</span><span class="cx"> {
</span><del>-    m_willBeginZoomingCallback = m_context.registerCallback(callback);
</del><ins>+    m_context.registerCallback(callback, CallbackTypeWillBeginZooming);
</ins><span class="cx">     platformSetWillBeginZoomingCallback();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSValueRef UIScriptController::willBeginZoomingCallback() const
</span><span class="cx"> {
</span><del>-    return m_context.callbackWithID(m_willBeginZoomingCallback);
</del><ins>+    return m_context.callbackWithID(CallbackTypeWillBeginZooming);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::setDidEndZoomingCallback(JSValueRef callback)
</span><span class="cx"> {
</span><del>-    m_didEndZoomingCallback = m_context.registerCallback(callback);
</del><ins>+    m_context.registerCallback(callback, CallbackTypeDidEndZooming);
</ins><span class="cx">     platformSetDidEndZoomingCallback();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSValueRef UIScriptController::didEndZoomingCallback() const
</span><span class="cx"> {
</span><del>-    return m_context.callbackWithID(m_didEndZoomingCallback);
</del><ins>+    return m_context.callbackWithID(CallbackTypeDidEndZooming);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::setDidShowKeyboardCallback(JSValueRef callback)
</span><span class="cx"> {
</span><del>-    m_didShowKeyboardCallback = m_context.registerCallback(callback);
</del><ins>+    m_context.registerCallback(callback, CallbackTypeDidShowKeyboard);
</ins><span class="cx">     platformSetDidShowKeyboardCallback();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSValueRef UIScriptController::didShowKeyboardCallback() const
</span><span class="cx"> {
</span><del>-    return m_context.callbackWithID(m_didShowKeyboardCallback);
</del><ins>+    return m_context.callbackWithID(CallbackTypeDidShowKeyboard);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::setDidHideKeyboardCallback(JSValueRef callback)
</span><span class="cx"> {
</span><del>-    m_didHideKeyboardCallback = m_context.registerCallback(callback);
</del><ins>+    m_context.registerCallback(callback, CallbackTypeDidHideKeyboard);
</ins><span class="cx">     platformSetDidHideKeyboardCallback();
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> JSValueRef UIScriptController::didHideKeyboardCallback() const
</span><span class="cx"> {
</span><del>-    return m_context.callbackWithID(m_didHideKeyboardCallback);
</del><ins>+    return m_context.callbackWithID(CallbackTypeDidHideKeyboard);
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> #if !PLATFORM(IOS)
</span><span class="lines">@@ -157,7 +157,7 @@
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::uiScriptComplete(JSStringRef result)
</span><span class="cx"> {
</span><del>-    m_context.uiScriptComplete(result);
</del><ins>+    m_context.requestUIScriptCompletion(result);
</ins><span class="cx">     platformClearAllCallbacks();
</span><span class="cx"> }
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnerUIScriptContextUIScriptControllerh"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.h (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.h        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/Tools/WebKitTestRunner/UIScriptContext/UIScriptController.h        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -84,11 +84,6 @@
</span><span class="cx">     JSObjectRef objectFromRect(const WKRect&amp;) const;
</span><span class="cx"> 
</span><span class="cx">     UIScriptContext&amp; m_context;
</span><del>-
-    unsigned m_willBeginZoomingCallback { 0 };
-    unsigned m_didEndZoomingCallback { 0 };
-    unsigned m_didShowKeyboardCallback { 0 };
-    unsigned m_didHideKeyboardCallback { 0 };
</del><span class="cx"> };
</span><span class="cx"> 
</span><span class="cx"> }
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunneriosUIScriptControllerIOSmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/Tools/WebKitTestRunner/ios/UIScriptControllerIOS.mm        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -42,7 +42,7 @@
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::doAsyncTask(JSValueRef callback)
</span><span class="cx"> {
</span><del>-    unsigned callbackID = m_context.prepareForAsyncTask(callback);
</del><ins>+    unsigned callbackID = m_context.prepareForAsyncTask(callback, CallbackTypeNonPersistent);
</ins><span class="cx"> 
</span><span class="cx">     dispatch_async(dispatch_get_main_queue(), ^{
</span><span class="cx">         m_context.asyncTaskComplete(callbackID);
</span><span class="lines">@@ -53,7 +53,7 @@
</span><span class="cx"> {
</span><span class="cx">     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()-&gt;platformView();
</span><span class="cx"> 
</span><del>-    unsigned callbackID = m_context.prepareForAsyncTask(callback);
</del><ins>+    unsigned callbackID = m_context.prepareForAsyncTask(callback, CallbackTypeNonPersistent);
</ins><span class="cx"> 
</span><span class="cx">     [webView zoomToScale:scale animated:YES completionHandler:^{
</span><span class="cx">         m_context.asyncTaskComplete(callbackID);
</span><span class="lines">@@ -77,7 +77,7 @@
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::singleTapAtPoint(long x, long y, JSValueRef callback)
</span><span class="cx"> {
</span><del>-    unsigned callbackID = m_context.prepareForAsyncTask(callback);
</del><ins>+    unsigned callbackID = m_context.prepareForAsyncTask(callback, CallbackTypeNonPersistent);
</ins><span class="cx"> 
</span><span class="cx">     [[HIDEventGenerator sharedHIDEventGenerator] tap:globalToContentCoordinates(TestController::singleton().mainWebView()-&gt;platformView(), x, y) completionBlock:^{
</span><span class="cx">         m_context.asyncTaskComplete(callbackID);
</span><span class="lines">@@ -86,7 +86,7 @@
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::doubleTapAtPoint(long x, long y, JSValueRef callback)
</span><span class="cx"> {
</span><del>-    unsigned callbackID = m_context.prepareForAsyncTask(callback);
</del><ins>+    unsigned callbackID = m_context.prepareForAsyncTask(callback, CallbackTypeNonPersistent);
</ins><span class="cx"> 
</span><span class="cx">     [[HIDEventGenerator sharedHIDEventGenerator] doubleTap:globalToContentCoordinates(TestController::singleton().mainWebView()-&gt;platformView(), x, y) completionBlock:^{
</span><span class="cx">         m_context.asyncTaskComplete(callbackID);
</span><span class="lines">@@ -95,7 +95,7 @@
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::typeCharacterUsingHardwareKeyboard(JSStringRef character, JSValueRef callback)
</span><span class="cx"> {
</span><del>-    unsigned callbackID = m_context.prepareForAsyncTask(callback);
</del><ins>+    unsigned callbackID = m_context.prepareForAsyncTask(callback, CallbackTypeNonPersistent);
</ins><span class="cx"> 
</span><span class="cx">     // Assumes that the keyboard is already shown.
</span><span class="cx">     [[HIDEventGenerator sharedHIDEventGenerator] keyDown:toWTFString(toWK(character)) completionBlock:^{
</span><span class="lines">@@ -129,7 +129,7 @@
</span><span class="cx"> {
</span><span class="cx">     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()-&gt;platformView();
</span><span class="cx">     webView.willBeginZoomingCallback = ^{
</span><del>-        m_context.fireCallback(m_willBeginZoomingCallback);
</del><ins>+        m_context.fireCallback(CallbackTypeWillBeginZooming);
</ins><span class="cx">     };
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -137,7 +137,7 @@
</span><span class="cx"> {
</span><span class="cx">     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()-&gt;platformView();
</span><span class="cx">     webView.didEndZoomingCallback = ^{
</span><del>-        m_context.fireCallback(m_didEndZoomingCallback);
</del><ins>+        m_context.fireCallback(CallbackTypeDidEndZooming);
</ins><span class="cx">     };
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -145,7 +145,7 @@
</span><span class="cx"> {
</span><span class="cx">     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()-&gt;platformView();
</span><span class="cx">     webView.didShowKeyboardCallback = ^{
</span><del>-        m_context.fireCallback(m_didShowKeyboardCallback);
</del><ins>+        m_context.fireCallback(CallbackTypeDidShowKeyboard);
</ins><span class="cx">     };
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="lines">@@ -153,17 +153,13 @@
</span><span class="cx"> {
</span><span class="cx">     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()-&gt;platformView();
</span><span class="cx">     webView.didHideKeyboardCallback = ^{
</span><del>-        m_context.fireCallback(m_didHideKeyboardCallback);
</del><ins>+        m_context.fireCallback(CallbackTypeDidHideKeyboard);
</ins><span class="cx">     };
</span><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::platformClearAllCallbacks()
</span><span class="cx"> {
</span><span class="cx">     TestRunnerWKWebView *webView = TestController::singleton().mainWebView()-&gt;platformView();
</span><del>-    m_didEndZoomingCallback = 0;
-    m_willBeginZoomingCallback = 0;
-    m_didHideKeyboardCallback = 0;
-    m_didShowKeyboardCallback = 0;
</del><span class="cx">     webView.didEndZoomingCallback = nil;
</span><span class="cx">     webView.willBeginZoomingCallback = nil;
</span><span class="cx">     webView.didHideKeyboardCallback = nil;
</span></span></pre></div>
<a id="trunkToolsWebKitTestRunnermacUIScriptControllerMacmm"></a>
<div class="modfile"><h4>Modified: trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm (192313 => 192314)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm        2015-11-11 18:12:53 UTC (rev 192313)
+++ trunk/Tools/WebKitTestRunner/mac/UIScriptControllerMac.mm        2015-11-11 18:15:56 UTC (rev 192314)
</span><span class="lines">@@ -32,7 +32,7 @@
</span><span class="cx"> 
</span><span class="cx"> void UIScriptController::doAsyncTask(JSValueRef callback)
</span><span class="cx"> {
</span><del>-    unsigned callbackID = m_context.prepareForAsyncTask(callback);
</del><ins>+    unsigned callbackID = m_context.prepareForAsyncTask(callback, CallbackTypeNonPersistent);
</ins><span class="cx"> 
</span><span class="cx">     dispatch_async(dispatch_get_main_queue(), ^{
</span><span class="cx">         m_context.asyncTaskComplete(callbackID);
</span></span></pre>
</div>
</div>

</body>
</html>