Title: [233977] branches/safari-606-branch
Revision
233977
Author
[email protected]
Date
2018-07-18 22:40:13 -0700 (Wed, 18 Jul 2018)

Log Message

Cherry-pick r233891. rdar://problem/42345327

    Add an SPI hook to allow clients to yield document parsing and script execution
    https://bugs.webkit.org/show_bug.cgi?id=187682
    <rdar://problem/42207453>

    Reviewed by Ryosuke Niwa.

    Source/WebCore:

    Using a single web process for both the Reader page and original web page on watchOS has multiple benefits,
    including: (1) allowing the user to bail out of Reader and view the original web page without having to load it
    again, and (2) improving the bringup time of the Reader page, since subresources are already cached in process
    and we don't eat the additional cost of a web process launch if prewarming fails.

    However, this has some drawbacks as well, one of which is that main thread work being done on behalf of the
    original page may contend with work being done to load and render the Reader page. This is especially bad when
    the page is in the middle of executing heavy script after Safari has already detected that the Reader version of
    the page is available, but before it has finished loading the Reader page. The result is that script on the
    original page may block the first paint of the Reader page (on New York Times articles, this often leads to an
    apparent page load time of 25-35 seconds before the user sees anything besides a blank screen).

    To mitigate this, we introduce a way for injected bundle clients to yield parsing and async script execution on
    a document. This capability is surfaced in the form of an opaque token which clients may request from a
    WKDOMDocument. Construction of the token causes the document to begin yielding and defer execution of previously
    scheduled scripts, only if there were no active tokens on the document already. Similarly, destruction of all
    active tokens on the document causes it to stop yielding and resume execution of scripts if needed.

    Tests:  ParserYieldTokenTests.PreventDocumentLoadByTakingParserYieldToken
            ParserYieldTokenTests.TakeMultipleParserYieldTokens
            ParserYieldTokenTests.DeferredScriptExecutesBeforeDocumentLoadWhenTakingParserYieldToken
            ParserYieldTokenTests.AsyncScriptRunsWhenFetched

    * dom/Document.cpp:
    (WebCore::Document::implicitOpen):

    If the parser yield token was taken before the document's parser was created, tell the parser's scheduler to
    start yielding immediately after creation.

    (WebCore::DocumentParserYieldToken::DocumentParserYieldToken):
    (WebCore::DocumentParserYieldToken::~DocumentParserYieldToken):
    * dom/Document.h:

    Introduce a parser yield count to Document; as long as this count is greater than 0, we consider the Document to
    have active yield tokens. When constructing or destroying a ParserYieldToken, we increment and decrement the
    parser yield count (respectively).

    (WebCore::Document::createParserYieldToken):
    (WebCore::Document::hasActiveParserYieldToken const):
    * dom/DocumentParser.h:
    (WebCore::DocumentParser::didBeginYieldingParser):
    (WebCore::DocumentParser::didEndYieldingParser):

    Hooks for Document to tell its parser that we've started or finished yielding. This updates a flag on the
    parser's scheduler which is consulted when we determine whether to yield before a pumping token or executing
    script.

    * dom/ScriptRunner.cpp:
    (WebCore::ScriptRunner::resume):
    (WebCore::ScriptRunner::notifyFinished):
    * dom/ScriptRunner.h:
    (WebCore::ScriptRunner::didBeginYieldingParser):
    (WebCore::ScriptRunner::didEndYieldingParser):

    Hooks for Document to tell its ScriptRunner that we've started or finished yielding. These wrap calls to suspend
    and resume.

    * html/parser/HTMLDocumentParser.cpp:
    (WebCore::HTMLDocumentParser::didBeginYieldingParser):
    (WebCore::HTMLDocumentParser::didEndYieldingParser):

    Plumb to didBegin/didEnd calls to the HTMLParserScheduler.

    * html/parser/HTMLDocumentParser.h:
    * html/parser/HTMLParserScheduler.cpp:
    (WebCore::HTMLParserScheduler::shouldYieldBeforeExecutingScript):
    * html/parser/HTMLParserScheduler.h:
    (WebCore::HTMLParserScheduler::shouldYieldBeforeToken):

    Consult a flag when determining whether to yield. This flag is set to true only while the document has an active
    parser yield token.

    (WebCore::HTMLParserScheduler::isScheduledForResume const):

    Consider the parser scheduler to be scheduled for resume if there are active tokens. Without this change, we
    incorrectly consider the document to be finished loading when we have yield tokens, since it appears that the
    parser is no longer scheduled to pump its tokenizer.

    (WebCore::HTMLParserScheduler::didBeginYieldingParser):
    (WebCore::HTMLParserScheduler::didEndYieldingParser):

    When the Document begins yielding due to the documet having active tokens or ends yielding after the document
    loses all of its yield tokens, update a flag on the parser scheduler. After we finish yielding, additionally
    reschedule the parser if needed to ensure that we continue parsing the document; without this additional change
    to resume, we'll never get the document load or load events after relinquishing the yield token.

    Source/WebKit:

    Add hooks to WKDOMDocument to create and return an internal WKDOMDocumentParserYieldToken object, whose lifetime
    is tied to a document parser yield token. See WebCore ChangeLog for more detail.

    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.h:
    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm:
    (-[WKDOMDocumentParserYieldToken initWithDocument:]):
    (-[WKDOMDocument parserYieldToken]):

    Tools:

    Add a few tests to exercise the new document yield token SPI, verifying that clients can use the SPI to defer
    document load, and that doing so doesn't cause deferred `script` to execute in the wrong order (i.e. before
    synchronous script, or after "DOMContentLoaded").

    * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm: Added.
    (-[ParserYieldTokenPlugIn takeDocumentParserTokenAfterCommittingLoad]):
    (-[ParserYieldTokenPlugIn releaseDocumentParserToken]):
    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didCommitLoadForFrame:]):
    (-[ParserYieldTokenPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishDocumentLoadForFrame:]):
    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishLoadForFrame:]):

    Add an injected bundle object that knows how to take and release multiple document parser yield tokens.

    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h: Added.
    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm: Added.
    (+[ParserYieldTokenTestWebView webView]):
    (-[ParserYieldTokenTestWebView bundle]):
    (-[ParserYieldTokenTestWebView schemeHandler]):
    (-[ParserYieldTokenTestWebView didFinishDocumentLoad]):
    (-[ParserYieldTokenTestWebView didFinishLoad]):
    (waitForDelay):
    (TEST):
    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h: Added.
    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm: Added.
    (-[TestURLSchemeHandler webView:startURLSchemeTask:]):
    (-[TestURLSchemeHandler webView:stopURLSchemeTask:]):
    (-[TestURLSchemeHandler setStartURLSchemeTaskHandler:]):
    (-[TestURLSchemeHandler startURLSchemeTaskHandler]):
    (-[TestURLSchemeHandler setStopURLSchemeTaskHandler:]):
    (-[TestURLSchemeHandler stopURLSchemeTaskHandler]):

    Add a new test helper class to handle custom schemes via a block-based API.

    * TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html: Added.

    New test HTML page that contains a deferred script element, a synchronous script element, another deferred
    script element, and then some text, images, and links.

    * TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html: Added.

    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233891 268f45cc-cd09-0410-ab3c-d52691b4dbfc

Modified Paths

Added Paths

Diff

Modified: branches/safari-606-branch/Source/WebCore/ChangeLog (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/ChangeLog	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/ChangeLog	2018-07-19 05:40:13 UTC (rev 233977)
@@ -1,5 +1,254 @@
 2018-07-18  Babak Shafiei  <[email protected]>
 
+        Cherry-pick r233891. rdar://problem/42345327
+
+    Add an SPI hook to allow clients to yield document parsing and script execution
+    https://bugs.webkit.org/show_bug.cgi?id=187682
+    <rdar://problem/42207453>
+    
+    Reviewed by Ryosuke Niwa.
+    
+    Source/WebCore:
+    
+    Using a single web process for both the Reader page and original web page on watchOS has multiple benefits,
+    including: (1) allowing the user to bail out of Reader and view the original web page without having to load it
+    again, and (2) improving the bringup time of the Reader page, since subresources are already cached in process
+    and we don't eat the additional cost of a web process launch if prewarming fails.
+    
+    However, this has some drawbacks as well, one of which is that main thread work being done on behalf of the
+    original page may contend with work being done to load and render the Reader page. This is especially bad when
+    the page is in the middle of executing heavy script after Safari has already detected that the Reader version of
+    the page is available, but before it has finished loading the Reader page. The result is that script on the
+    original page may block the first paint of the Reader page (on New York Times articles, this often leads to an
+    apparent page load time of 25-35 seconds before the user sees anything besides a blank screen).
+    
+    To mitigate this, we introduce a way for injected bundle clients to yield parsing and async script execution on
+    a document. This capability is surfaced in the form of an opaque token which clients may request from a
+    WKDOMDocument. Construction of the token causes the document to begin yielding and defer execution of previously
+    scheduled scripts, only if there were no active tokens on the document already. Similarly, destruction of all
+    active tokens on the document causes it to stop yielding and resume execution of scripts if needed.
+    
+    Tests:  ParserYieldTokenTests.PreventDocumentLoadByTakingParserYieldToken
+            ParserYieldTokenTests.TakeMultipleParserYieldTokens
+            ParserYieldTokenTests.DeferredScriptExecutesBeforeDocumentLoadWhenTakingParserYieldToken
+            ParserYieldTokenTests.AsyncScriptRunsWhenFetched
+    
+    * dom/Document.cpp:
+    (WebCore::Document::implicitOpen):
+    
+    If the parser yield token was taken before the document's parser was created, tell the parser's scheduler to
+    start yielding immediately after creation.
+    
+    (WebCore::DocumentParserYieldToken::DocumentParserYieldToken):
+    (WebCore::DocumentParserYieldToken::~DocumentParserYieldToken):
+    * dom/Document.h:
+    
+    Introduce a parser yield count to Document; as long as this count is greater than 0, we consider the Document to
+    have active yield tokens. When constructing or destroying a ParserYieldToken, we increment and decrement the
+    parser yield count (respectively).
+    
+    (WebCore::Document::createParserYieldToken):
+    (WebCore::Document::hasActiveParserYieldToken const):
+    * dom/DocumentParser.h:
+    (WebCore::DocumentParser::didBeginYieldingParser):
+    (WebCore::DocumentParser::didEndYieldingParser):
+    
+    Hooks for Document to tell its parser that we've started or finished yielding. This updates a flag on the
+    parser's scheduler which is consulted when we determine whether to yield before a pumping token or executing
+    script.
+    
+    * dom/ScriptRunner.cpp:
+    (WebCore::ScriptRunner::resume):
+    (WebCore::ScriptRunner::notifyFinished):
+    * dom/ScriptRunner.h:
+    (WebCore::ScriptRunner::didBeginYieldingParser):
+    (WebCore::ScriptRunner::didEndYieldingParser):
+    
+    Hooks for Document to tell its ScriptRunner that we've started or finished yielding. These wrap calls to suspend
+    and resume.
+    
+    * html/parser/HTMLDocumentParser.cpp:
+    (WebCore::HTMLDocumentParser::didBeginYieldingParser):
+    (WebCore::HTMLDocumentParser::didEndYieldingParser):
+    
+    Plumb to didBegin/didEnd calls to the HTMLParserScheduler.
+    
+    * html/parser/HTMLDocumentParser.h:
+    * html/parser/HTMLParserScheduler.cpp:
+    (WebCore::HTMLParserScheduler::shouldYieldBeforeExecutingScript):
+    * html/parser/HTMLParserScheduler.h:
+    (WebCore::HTMLParserScheduler::shouldYieldBeforeToken):
+    
+    Consult a flag when determining whether to yield. This flag is set to true only while the document has an active
+    parser yield token.
+    
+    (WebCore::HTMLParserScheduler::isScheduledForResume const):
+    
+    Consider the parser scheduler to be scheduled for resume if there are active tokens. Without this change, we
+    incorrectly consider the document to be finished loading when we have yield tokens, since it appears that the
+    parser is no longer scheduled to pump its tokenizer.
+    
+    (WebCore::HTMLParserScheduler::didBeginYieldingParser):
+    (WebCore::HTMLParserScheduler::didEndYieldingParser):
+    
+    When the Document begins yielding due to the documet having active tokens or ends yielding after the document
+    loses all of its yield tokens, update a flag on the parser scheduler. After we finish yielding, additionally
+    reschedule the parser if needed to ensure that we continue parsing the document; without this additional change
+    to resume, we'll never get the document load or load events after relinquishing the yield token.
+    
+    Source/WebKit:
+    
+    Add hooks to WKDOMDocument to create and return an internal WKDOMDocumentParserYieldToken object, whose lifetime
+    is tied to a document parser yield token. See WebCore ChangeLog for more detail.
+    
+    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.h:
+    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm:
+    (-[WKDOMDocumentParserYieldToken initWithDocument:]):
+    (-[WKDOMDocument parserYieldToken]):
+    
+    Tools:
+    
+    Add a few tests to exercise the new document yield token SPI, verifying that clients can use the SPI to defer
+    document load, and that doing so doesn't cause deferred `script` to execute in the wrong order (i.e. before
+    synchronous script, or after "DOMContentLoaded").
+    
+    * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm: Added.
+    (-[ParserYieldTokenPlugIn takeDocumentParserTokenAfterCommittingLoad]):
+    (-[ParserYieldTokenPlugIn releaseDocumentParserToken]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didCommitLoadForFrame:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishDocumentLoadForFrame:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishLoadForFrame:]):
+    
+    Add an injected bundle object that knows how to take and release multiple document parser yield tokens.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h: Added.
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm: Added.
+    (+[ParserYieldTokenTestWebView webView]):
+    (-[ParserYieldTokenTestWebView bundle]):
+    (-[ParserYieldTokenTestWebView schemeHandler]):
+    (-[ParserYieldTokenTestWebView didFinishDocumentLoad]):
+    (-[ParserYieldTokenTestWebView didFinishLoad]):
+    (waitForDelay):
+    (TEST):
+    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h: Added.
+    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm: Added.
+    (-[TestURLSchemeHandler webView:startURLSchemeTask:]):
+    (-[TestURLSchemeHandler webView:stopURLSchemeTask:]):
+    (-[TestURLSchemeHandler setStartURLSchemeTaskHandler:]):
+    (-[TestURLSchemeHandler startURLSchemeTaskHandler]):
+    (-[TestURLSchemeHandler setStopURLSchemeTaskHandler:]):
+    (-[TestURLSchemeHandler stopURLSchemeTaskHandler]):
+    
+    Add a new test helper class to handle custom schemes via a block-based API.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html: Added.
+    
+    New test HTML page that contains a deferred script element, a synchronous script element, another deferred
+    script element, and then some text, images, and links.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html: Added.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233891 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2018-07-17  Wenson Hsieh  <[email protected]>
+
+            Add an SPI hook to allow clients to yield document parsing and script execution
+            https://bugs.webkit.org/show_bug.cgi?id=187682
+            <rdar://problem/42207453>
+
+            Reviewed by Ryosuke Niwa.
+
+            Using a single web process for both the Reader page and original web page on watchOS has multiple benefits,
+            including: (1) allowing the user to bail out of Reader and view the original web page without having to load it
+            again, and (2) improving the bringup time of the Reader page, since subresources are already cached in process
+            and we don't eat the additional cost of a web process launch if prewarming fails.
+
+            However, this has some drawbacks as well, one of which is that main thread work being done on behalf of the
+            original page may contend with work being done to load and render the Reader page. This is especially bad when
+            the page is in the middle of executing heavy script after Safari has already detected that the Reader version of
+            the page is available, but before it has finished loading the Reader page. The result is that script on the
+            original page may block the first paint of the Reader page (on New York Times articles, this often leads to an
+            apparent page load time of 25-35 seconds before the user sees anything besides a blank screen).
+
+            To mitigate this, we introduce a way for injected bundle clients to yield parsing and async script execution on
+            a document. This capability is surfaced in the form of an opaque token which clients may request from a
+            WKDOMDocument. Construction of the token causes the document to begin yielding and defer execution of previously
+            scheduled scripts, only if there were no active tokens on the document already. Similarly, destruction of all
+            active tokens on the document causes it to stop yielding and resume execution of scripts if needed.
+
+            Tests:  ParserYieldTokenTests.PreventDocumentLoadByTakingParserYieldToken
+                    ParserYieldTokenTests.TakeMultipleParserYieldTokens
+                    ParserYieldTokenTests.DeferredScriptExecutesBeforeDocumentLoadWhenTakingParserYieldToken
+                    ParserYieldTokenTests.AsyncScriptRunsWhenFetched
+
+            * dom/Document.cpp:
+            (WebCore::Document::implicitOpen):
+
+            If the parser yield token was taken before the document's parser was created, tell the parser's scheduler to
+            start yielding immediately after creation.
+
+            (WebCore::DocumentParserYieldToken::DocumentParserYieldToken):
+            (WebCore::DocumentParserYieldToken::~DocumentParserYieldToken):
+            * dom/Document.h:
+
+            Introduce a parser yield count to Document; as long as this count is greater than 0, we consider the Document to
+            have active yield tokens. When constructing or destroying a ParserYieldToken, we increment and decrement the
+            parser yield count (respectively).
+
+            (WebCore::Document::createParserYieldToken):
+            (WebCore::Document::hasActiveParserYieldToken const):
+            * dom/DocumentParser.h:
+            (WebCore::DocumentParser::didBeginYieldingParser):
+            (WebCore::DocumentParser::didEndYieldingParser):
+
+            Hooks for Document to tell its parser that we've started or finished yielding. This updates a flag on the
+            parser's scheduler which is consulted when we determine whether to yield before a pumping token or executing
+            script.
+
+            * dom/ScriptRunner.cpp:
+            (WebCore::ScriptRunner::resume):
+            (WebCore::ScriptRunner::notifyFinished):
+            * dom/ScriptRunner.h:
+            (WebCore::ScriptRunner::didBeginYieldingParser):
+            (WebCore::ScriptRunner::didEndYieldingParser):
+
+            Hooks for Document to tell its ScriptRunner that we've started or finished yielding. These wrap calls to suspend
+            and resume.
+
+            * html/parser/HTMLDocumentParser.cpp:
+            (WebCore::HTMLDocumentParser::didBeginYieldingParser):
+            (WebCore::HTMLDocumentParser::didEndYieldingParser):
+
+            Plumb to didBegin/didEnd calls to the HTMLParserScheduler.
+
+            * html/parser/HTMLDocumentParser.h:
+            * html/parser/HTMLParserScheduler.cpp:
+            (WebCore::HTMLParserScheduler::shouldYieldBeforeExecutingScript):
+            * html/parser/HTMLParserScheduler.h:
+            (WebCore::HTMLParserScheduler::shouldYieldBeforeToken):
+
+            Consult a flag when determining whether to yield. This flag is set to true only while the document has an active
+            parser yield token.
+
+            (WebCore::HTMLParserScheduler::isScheduledForResume const):
+
+            Consider the parser scheduler to be scheduled for resume if there are active tokens. Without this change, we
+            incorrectly consider the document to be finished loading when we have yield tokens, since it appears that the
+            parser is no longer scheduled to pump its tokenizer.
+
+            (WebCore::HTMLParserScheduler::didBeginYieldingParser):
+            (WebCore::HTMLParserScheduler::didEndYieldingParser):
+
+            When the Document begins yielding due to the documet having active tokens or ends yielding after the document
+            loses all of its yield tokens, update a flag on the parser scheduler. After we finish yielding, additionally
+            reschedule the parser if needed to ensure that we continue parsing the document; without this additional change
+            to resume, we'll never get the document load or load events after relinquishing the yield token.
+
+2018-07-18  Babak Shafiei  <[email protected]>
+
         Cherry-pick r233936. rdar://problem/42354941
 
     Unreviewed API Test fix; restored a line inadventantly removed in r233926.

Modified: branches/safari-606-branch/Source/WebCore/dom/Document.cpp (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/dom/Document.cpp	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/dom/Document.cpp	2018-07-19 05:40:13 UTC (rev 233977)
@@ -2686,6 +2686,10 @@
 
     cancelParsing();
     m_parser = createParser();
+
+    if (hasActiveParserYieldToken())
+        m_parser->didBeginYieldingParser();
+
     setParsing(true);
     setReadyState(Loading);
 }
@@ -6901,6 +6905,31 @@
     frame()->loader().checkLoadComplete();
 }
 
+DocumentParserYieldToken::DocumentParserYieldToken(Document& document)
+    : m_document(makeWeakPtr(document))
+{
+    if (++document.m_parserYieldTokenCount != 1)
+        return;
+
+    document.scriptRunner()->didBeginYieldingParser();
+    if (auto* parser = document.parser())
+        parser->didBeginYieldingParser();
+}
+
+DocumentParserYieldToken::~DocumentParserYieldToken()
+{
+    if (!m_document)
+        return;
+
+    ASSERT(m_document->m_parserYieldTokenCount);
+    if (--m_document->m_parserYieldTokenCount)
+        return;
+
+    m_document->scriptRunner()->didEndYieldingParser();
+    if (auto* parser = m_document->parser())
+        parser->didEndYieldingParser();
+}
+
 static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2)
 {
     if (!obj1 || !obj2)

Modified: branches/safari-606-branch/Source/WebCore/dom/Document.h (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/dom/Document.h	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/dom/Document.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -317,6 +317,15 @@
     RefPtr<CanvasRenderingContext2D>
 >;
 
+class DocumentParserYieldToken {
+public:
+    WEBCORE_EXPORT DocumentParserYieldToken(Document&);
+    WEBCORE_EXPORT ~DocumentParserYieldToken();
+
+private:
+    WeakPtr<Document> m_document;
+};
+
 class Document
     : public ContainerNode
     , public TreeScope
@@ -1266,6 +1275,13 @@
     void incrementActiveParserCount() { ++m_activeParserCount; }
     void decrementActiveParserCount();
 
+    std::unique_ptr<DocumentParserYieldToken> createParserYieldToken()
+    {
+        return std::make_unique<DocumentParserYieldToken>(*this);
+    }
+
+    bool hasActiveParserYieldToken() const { return m_parserYieldTokenCount; }
+
     DocumentSharedObjectPool* sharedObjectPool() { return m_sharedObjectPool.get(); }
 
     void invalidateMatchedPropertiesCacheAndForceStyleRecalc();
@@ -1460,6 +1476,7 @@
     virtual Ref<Document> cloneDocumentWithoutChildren() const;
 
 private:
+    friend class DocumentParserYieldToken;
     friend class Node;
     friend class IgnoreDestructiveWriteCountIncrementer;
     friend class IgnoreOpensDuringUnloadCountIncrementer;
@@ -1578,6 +1595,8 @@
     Ref<CachedResourceLoader> m_cachedResourceLoader;
     RefPtr<DocumentParser> m_parser;
 
+    unsigned m_parserYieldTokenCount { 0 };
+
     // Document URLs.
     URL m_url; // Document.URL: The URL from which this document was retrieved.
     URL m_baseURL; // Node.baseURI: The URL to use when resolving relative URLs.

Modified: branches/safari-606-branch/Source/WebCore/dom/DocumentParser.h (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/dom/DocumentParser.h	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/dom/DocumentParser.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -96,6 +96,9 @@
     virtual void suspendScheduledTasks();
     virtual void resumeScheduledTasks();
 
+    virtual void didBeginYieldingParser() { }
+    virtual void didEndYieldingParser() { }
+
 protected:
     explicit DocumentParser(Document&);
 

Modified: branches/safari-606-branch/Source/WebCore/dom/ScriptRunner.cpp (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/dom/ScriptRunner.cpp	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/dom/ScriptRunner.cpp	2018-07-19 05:40:13 UTC (rev 233977)
@@ -82,7 +82,7 @@
 
 void ScriptRunner::resume()
 {
-    if (hasPendingScripts())
+    if (hasPendingScripts() && !m_document.hasActiveParserYieldToken())
         m_timer.startOneShot(0_s);
 }
 
@@ -95,7 +95,9 @@
         m_scriptsToExecuteSoon.append(m_pendingAsyncScripts.take(pendingScript)->ptr());
     }
     pendingScript.clearClient();
-    m_timer.startOneShot(0_s);
+
+    if (!m_document.hasActiveParserYieldToken())
+        m_timer.startOneShot(0_s);
 }
 
 void ScriptRunner::timerFired()

Modified: branches/safari-606-branch/Source/WebCore/dom/ScriptRunner.h (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/dom/ScriptRunner.h	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/dom/ScriptRunner.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -50,6 +50,9 @@
     void resume();
     void notifyScriptReady(ScriptElement*, ExecutionType);
 
+    void didBeginYieldingParser() { suspend(); }
+    void didEndYieldingParser() { resume(); }
+
 private:
     void timerFired();
 

Modified: branches/safari-606-branch/Source/WebCore/html/parser/HTMLDocumentParser.cpp (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/html/parser/HTMLDocumentParser.cpp	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/html/parser/HTMLDocumentParser.cpp	2018-07-19 05:40:13 UTC (rev 233977)
@@ -148,6 +148,16 @@
     return inPumpSession() || isWaitingForScripts() || isScheduledForResume() || isExecutingScript();
 }
 
+void HTMLDocumentParser::didBeginYieldingParser()
+{
+    m_parserScheduler->didBeginYieldingParser();
+}
+
+void HTMLDocumentParser::didEndYieldingParser()
+{
+    m_parserScheduler->didEndYieldingParser();
+}
+
 bool HTMLDocumentParser::isParsingFragment() const
 {
     return m_treeBuilder->isParsingFragment();

Modified: branches/safari-606-branch/Source/WebCore/html/parser/HTMLDocumentParser.h (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/html/parser/HTMLDocumentParser.h	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/html/parser/HTMLDocumentParser.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -121,6 +121,9 @@
     bool inPumpSession() const;
     bool shouldDelayEnd() const;
 
+    void didBeginYieldingParser() final;
+    void didEndYieldingParser() final;
+
     HTMLParserOptions m_options;
     HTMLInputStream m_input;
 

Modified: branches/safari-606-branch/Source/WebCore/html/parser/HTMLParserScheduler.cpp (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/html/parser/HTMLParserScheduler.cpp	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/html/parser/HTMLParserScheduler.cpp	2018-07-19 05:40:13 UTC (rev 233977)
@@ -111,6 +111,10 @@
     RefPtr<Document> document = m_parser.document();
     bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
     session.didSeeScript = true;
+
+    if (UNLIKELY(m_documentHasActiveParserYieldTokens))
+        return true;
+
     return needsFirstPaint && document->isLayoutTimerActive();
 }
 

Modified: branches/safari-606-branch/Source/WebCore/html/parser/HTMLParserScheduler.h (233976 => 233977)


--- branches/safari-606-branch/Source/WebCore/html/parser/HTMLParserScheduler.h	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebCore/html/parser/HTMLParserScheduler.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -69,6 +69,9 @@
         if (WebThreadShouldYield())
             return true;
 #endif
+        if (UNLIKELY(m_documentHasActiveParserYieldTokens))
+            return true;
+
         if (UNLIKELY(session.processedTokens > numberOfTokensBeforeCheckingForYield || session.didSeeScript))
             return checkForYield(session);
 
@@ -78,11 +81,26 @@
     bool shouldYieldBeforeExecutingScript(PumpSession&);
 
     void scheduleForResume();
-    bool isScheduledForResume() const { return m_isSuspendedWithActiveTimer || m_continueNextChunkTimer.isActive(); }
+    bool isScheduledForResume() const { return m_isSuspendedWithActiveTimer || m_continueNextChunkTimer.isActive() || m_documentHasActiveParserYieldTokens; }
 
     void suspend();
     void resume();
 
+    void didBeginYieldingParser()
+    {
+        ASSERT(!m_documentHasActiveParserYieldTokens);
+        m_documentHasActiveParserYieldTokens = true;
+    }
+
+    void didEndYieldingParser()
+    {
+        ASSERT(m_documentHasActiveParserYieldTokens);
+        m_documentHasActiveParserYieldTokens = false;
+
+        if (!isScheduledForResume())
+            scheduleForResume();
+    }
+
 private:
     static const unsigned numberOfTokensBeforeCheckingForYield = 4096; // Performance optimization
 
@@ -112,6 +130,7 @@
 #if !ASSERT_DISABLED
     bool m_suspended;
 #endif
+    bool m_documentHasActiveParserYieldTokens { false };
 };
 
 } // namespace WebCore

Modified: branches/safari-606-branch/Source/WebKit/ChangeLog (233976 => 233977)


--- branches/safari-606-branch/Source/WebKit/ChangeLog	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebKit/ChangeLog	2018-07-19 05:40:13 UTC (rev 233977)
@@ -1,5 +1,176 @@
 2018-07-18  Babak Shafiei  <[email protected]>
 
+        Cherry-pick r233891. rdar://problem/42345327
+
+    Add an SPI hook to allow clients to yield document parsing and script execution
+    https://bugs.webkit.org/show_bug.cgi?id=187682
+    <rdar://problem/42207453>
+    
+    Reviewed by Ryosuke Niwa.
+    
+    Source/WebCore:
+    
+    Using a single web process for both the Reader page and original web page on watchOS has multiple benefits,
+    including: (1) allowing the user to bail out of Reader and view the original web page without having to load it
+    again, and (2) improving the bringup time of the Reader page, since subresources are already cached in process
+    and we don't eat the additional cost of a web process launch if prewarming fails.
+    
+    However, this has some drawbacks as well, one of which is that main thread work being done on behalf of the
+    original page may contend with work being done to load and render the Reader page. This is especially bad when
+    the page is in the middle of executing heavy script after Safari has already detected that the Reader version of
+    the page is available, but before it has finished loading the Reader page. The result is that script on the
+    original page may block the first paint of the Reader page (on New York Times articles, this often leads to an
+    apparent page load time of 25-35 seconds before the user sees anything besides a blank screen).
+    
+    To mitigate this, we introduce a way for injected bundle clients to yield parsing and async script execution on
+    a document. This capability is surfaced in the form of an opaque token which clients may request from a
+    WKDOMDocument. Construction of the token causes the document to begin yielding and defer execution of previously
+    scheduled scripts, only if there were no active tokens on the document already. Similarly, destruction of all
+    active tokens on the document causes it to stop yielding and resume execution of scripts if needed.
+    
+    Tests:  ParserYieldTokenTests.PreventDocumentLoadByTakingParserYieldToken
+            ParserYieldTokenTests.TakeMultipleParserYieldTokens
+            ParserYieldTokenTests.DeferredScriptExecutesBeforeDocumentLoadWhenTakingParserYieldToken
+            ParserYieldTokenTests.AsyncScriptRunsWhenFetched
+    
+    * dom/Document.cpp:
+    (WebCore::Document::implicitOpen):
+    
+    If the parser yield token was taken before the document's parser was created, tell the parser's scheduler to
+    start yielding immediately after creation.
+    
+    (WebCore::DocumentParserYieldToken::DocumentParserYieldToken):
+    (WebCore::DocumentParserYieldToken::~DocumentParserYieldToken):
+    * dom/Document.h:
+    
+    Introduce a parser yield count to Document; as long as this count is greater than 0, we consider the Document to
+    have active yield tokens. When constructing or destroying a ParserYieldToken, we increment and decrement the
+    parser yield count (respectively).
+    
+    (WebCore::Document::createParserYieldToken):
+    (WebCore::Document::hasActiveParserYieldToken const):
+    * dom/DocumentParser.h:
+    (WebCore::DocumentParser::didBeginYieldingParser):
+    (WebCore::DocumentParser::didEndYieldingParser):
+    
+    Hooks for Document to tell its parser that we've started or finished yielding. This updates a flag on the
+    parser's scheduler which is consulted when we determine whether to yield before a pumping token or executing
+    script.
+    
+    * dom/ScriptRunner.cpp:
+    (WebCore::ScriptRunner::resume):
+    (WebCore::ScriptRunner::notifyFinished):
+    * dom/ScriptRunner.h:
+    (WebCore::ScriptRunner::didBeginYieldingParser):
+    (WebCore::ScriptRunner::didEndYieldingParser):
+    
+    Hooks for Document to tell its ScriptRunner that we've started or finished yielding. These wrap calls to suspend
+    and resume.
+    
+    * html/parser/HTMLDocumentParser.cpp:
+    (WebCore::HTMLDocumentParser::didBeginYieldingParser):
+    (WebCore::HTMLDocumentParser::didEndYieldingParser):
+    
+    Plumb to didBegin/didEnd calls to the HTMLParserScheduler.
+    
+    * html/parser/HTMLDocumentParser.h:
+    * html/parser/HTMLParserScheduler.cpp:
+    (WebCore::HTMLParserScheduler::shouldYieldBeforeExecutingScript):
+    * html/parser/HTMLParserScheduler.h:
+    (WebCore::HTMLParserScheduler::shouldYieldBeforeToken):
+    
+    Consult a flag when determining whether to yield. This flag is set to true only while the document has an active
+    parser yield token.
+    
+    (WebCore::HTMLParserScheduler::isScheduledForResume const):
+    
+    Consider the parser scheduler to be scheduled for resume if there are active tokens. Without this change, we
+    incorrectly consider the document to be finished loading when we have yield tokens, since it appears that the
+    parser is no longer scheduled to pump its tokenizer.
+    
+    (WebCore::HTMLParserScheduler::didBeginYieldingParser):
+    (WebCore::HTMLParserScheduler::didEndYieldingParser):
+    
+    When the Document begins yielding due to the documet having active tokens or ends yielding after the document
+    loses all of its yield tokens, update a flag on the parser scheduler. After we finish yielding, additionally
+    reschedule the parser if needed to ensure that we continue parsing the document; without this additional change
+    to resume, we'll never get the document load or load events after relinquishing the yield token.
+    
+    Source/WebKit:
+    
+    Add hooks to WKDOMDocument to create and return an internal WKDOMDocumentParserYieldToken object, whose lifetime
+    is tied to a document parser yield token. See WebCore ChangeLog for more detail.
+    
+    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.h:
+    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm:
+    (-[WKDOMDocumentParserYieldToken initWithDocument:]):
+    (-[WKDOMDocument parserYieldToken]):
+    
+    Tools:
+    
+    Add a few tests to exercise the new document yield token SPI, verifying that clients can use the SPI to defer
+    document load, and that doing so doesn't cause deferred `script` to execute in the wrong order (i.e. before
+    synchronous script, or after "DOMContentLoaded").
+    
+    * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm: Added.
+    (-[ParserYieldTokenPlugIn takeDocumentParserTokenAfterCommittingLoad]):
+    (-[ParserYieldTokenPlugIn releaseDocumentParserToken]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didCommitLoadForFrame:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishDocumentLoadForFrame:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishLoadForFrame:]):
+    
+    Add an injected bundle object that knows how to take and release multiple document parser yield tokens.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h: Added.
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm: Added.
+    (+[ParserYieldTokenTestWebView webView]):
+    (-[ParserYieldTokenTestWebView bundle]):
+    (-[ParserYieldTokenTestWebView schemeHandler]):
+    (-[ParserYieldTokenTestWebView didFinishDocumentLoad]):
+    (-[ParserYieldTokenTestWebView didFinishLoad]):
+    (waitForDelay):
+    (TEST):
+    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h: Added.
+    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm: Added.
+    (-[TestURLSchemeHandler webView:startURLSchemeTask:]):
+    (-[TestURLSchemeHandler webView:stopURLSchemeTask:]):
+    (-[TestURLSchemeHandler setStartURLSchemeTaskHandler:]):
+    (-[TestURLSchemeHandler startURLSchemeTaskHandler]):
+    (-[TestURLSchemeHandler setStopURLSchemeTaskHandler:]):
+    (-[TestURLSchemeHandler stopURLSchemeTaskHandler]):
+    
+    Add a new test helper class to handle custom schemes via a block-based API.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html: Added.
+    
+    New test HTML page that contains a deferred script element, a synchronous script element, another deferred
+    script element, and then some text, images, and links.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html: Added.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233891 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2018-07-17  Wenson Hsieh  <[email protected]>
+
+            Add an SPI hook to allow clients to yield document parsing and script execution
+            https://bugs.webkit.org/show_bug.cgi?id=187682
+            <rdar://problem/42207453>
+
+            Reviewed by Ryosuke Niwa.
+
+            Add hooks to WKDOMDocument to create and return an internal WKDOMDocumentParserYieldToken object, whose lifetime
+            is tied to a document parser yield token. See WebCore ChangeLog for more detail.
+
+            * WebProcess/InjectedBundle/API/mac/WKDOMDocument.h:
+            * WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm:
+            (-[WKDOMDocumentParserYieldToken initWithDocument:]):
+            (-[WKDOMDocument parserYieldToken]):
+
+2018-07-18  Babak Shafiei  <[email protected]>
+
         Cherry-pick r233940. rdar://problem/42359640
 
     CRASH at WebKit: WebKit::WebFullScreenManagerProxy::saveScrollPosition

Modified: branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.h (233976 => 233977)


--- branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.h	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -42,6 +42,8 @@
 
 @property(readonly) WKDOMElement *body;
 
+- (id)parserYieldToken WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
+
 @end
 
 #endif // WK_API_ENABLED

Modified: branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm (233976 => 233977)


--- branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm	2018-07-19 05:40:13 UTC (rev 233977)
@@ -35,6 +35,23 @@
 #import <WebCore/Text.h>
 #import <WebCore/markup.h>
 
+@interface WKDOMDocumentParserYieldToken : NSObject
+
+@end
+
+@implementation WKDOMDocumentParserYieldToken {
+    std::unique_ptr<WebCore::DocumentParserYieldToken> _token;
+}
+
+- (instancetype)initWithDocument:(WebCore::Document&)document
+{
+    if (self = [super init])
+        _token = document.createParserYieldToken();
+    return self;
+}
+
+@end
+
 @implementation WKDOMDocument
 
 - (WKDOMElement *)createElement:(NSString *)tagName
@@ -66,6 +83,11 @@
     return WebKit::toWKDOMNode(createFragmentFromText(downcast<WebCore::Document>(*_impl).createRange().get(), text).ptr());
 }
 
+- (id)parserYieldToken
+{
+    return [[[WKDOMDocumentParserYieldToken alloc] initWithDocument:downcast<WebCore::Document>(*_impl)] autorelease];
+}
+
 @end
 
 #endif // WK_API_ENABLED

Modified: branches/safari-606-branch/Tools/ChangeLog (233976 => 233977)


--- branches/safari-606-branch/Tools/ChangeLog	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Tools/ChangeLog	2018-07-19 05:40:13 UTC (rev 233977)
@@ -1,5 +1,210 @@
 2018-07-18  Babak Shafiei  <[email protected]>
 
+        Cherry-pick r233891. rdar://problem/42345327
+
+    Add an SPI hook to allow clients to yield document parsing and script execution
+    https://bugs.webkit.org/show_bug.cgi?id=187682
+    <rdar://problem/42207453>
+    
+    Reviewed by Ryosuke Niwa.
+    
+    Source/WebCore:
+    
+    Using a single web process for both the Reader page and original web page on watchOS has multiple benefits,
+    including: (1) allowing the user to bail out of Reader and view the original web page without having to load it
+    again, and (2) improving the bringup time of the Reader page, since subresources are already cached in process
+    and we don't eat the additional cost of a web process launch if prewarming fails.
+    
+    However, this has some drawbacks as well, one of which is that main thread work being done on behalf of the
+    original page may contend with work being done to load and render the Reader page. This is especially bad when
+    the page is in the middle of executing heavy script after Safari has already detected that the Reader version of
+    the page is available, but before it has finished loading the Reader page. The result is that script on the
+    original page may block the first paint of the Reader page (on New York Times articles, this often leads to an
+    apparent page load time of 25-35 seconds before the user sees anything besides a blank screen).
+    
+    To mitigate this, we introduce a way for injected bundle clients to yield parsing and async script execution on
+    a document. This capability is surfaced in the form of an opaque token which clients may request from a
+    WKDOMDocument. Construction of the token causes the document to begin yielding and defer execution of previously
+    scheduled scripts, only if there were no active tokens on the document already. Similarly, destruction of all
+    active tokens on the document causes it to stop yielding and resume execution of scripts if needed.
+    
+    Tests:  ParserYieldTokenTests.PreventDocumentLoadByTakingParserYieldToken
+            ParserYieldTokenTests.TakeMultipleParserYieldTokens
+            ParserYieldTokenTests.DeferredScriptExecutesBeforeDocumentLoadWhenTakingParserYieldToken
+            ParserYieldTokenTests.AsyncScriptRunsWhenFetched
+    
+    * dom/Document.cpp:
+    (WebCore::Document::implicitOpen):
+    
+    If the parser yield token was taken before the document's parser was created, tell the parser's scheduler to
+    start yielding immediately after creation.
+    
+    (WebCore::DocumentParserYieldToken::DocumentParserYieldToken):
+    (WebCore::DocumentParserYieldToken::~DocumentParserYieldToken):
+    * dom/Document.h:
+    
+    Introduce a parser yield count to Document; as long as this count is greater than 0, we consider the Document to
+    have active yield tokens. When constructing or destroying a ParserYieldToken, we increment and decrement the
+    parser yield count (respectively).
+    
+    (WebCore::Document::createParserYieldToken):
+    (WebCore::Document::hasActiveParserYieldToken const):
+    * dom/DocumentParser.h:
+    (WebCore::DocumentParser::didBeginYieldingParser):
+    (WebCore::DocumentParser::didEndYieldingParser):
+    
+    Hooks for Document to tell its parser that we've started or finished yielding. This updates a flag on the
+    parser's scheduler which is consulted when we determine whether to yield before a pumping token or executing
+    script.
+    
+    * dom/ScriptRunner.cpp:
+    (WebCore::ScriptRunner::resume):
+    (WebCore::ScriptRunner::notifyFinished):
+    * dom/ScriptRunner.h:
+    (WebCore::ScriptRunner::didBeginYieldingParser):
+    (WebCore::ScriptRunner::didEndYieldingParser):
+    
+    Hooks for Document to tell its ScriptRunner that we've started or finished yielding. These wrap calls to suspend
+    and resume.
+    
+    * html/parser/HTMLDocumentParser.cpp:
+    (WebCore::HTMLDocumentParser::didBeginYieldingParser):
+    (WebCore::HTMLDocumentParser::didEndYieldingParser):
+    
+    Plumb to didBegin/didEnd calls to the HTMLParserScheduler.
+    
+    * html/parser/HTMLDocumentParser.h:
+    * html/parser/HTMLParserScheduler.cpp:
+    (WebCore::HTMLParserScheduler::shouldYieldBeforeExecutingScript):
+    * html/parser/HTMLParserScheduler.h:
+    (WebCore::HTMLParserScheduler::shouldYieldBeforeToken):
+    
+    Consult a flag when determining whether to yield. This flag is set to true only while the document has an active
+    parser yield token.
+    
+    (WebCore::HTMLParserScheduler::isScheduledForResume const):
+    
+    Consider the parser scheduler to be scheduled for resume if there are active tokens. Without this change, we
+    incorrectly consider the document to be finished loading when we have yield tokens, since it appears that the
+    parser is no longer scheduled to pump its tokenizer.
+    
+    (WebCore::HTMLParserScheduler::didBeginYieldingParser):
+    (WebCore::HTMLParserScheduler::didEndYieldingParser):
+    
+    When the Document begins yielding due to the documet having active tokens or ends yielding after the document
+    loses all of its yield tokens, update a flag on the parser scheduler. After we finish yielding, additionally
+    reschedule the parser if needed to ensure that we continue parsing the document; without this additional change
+    to resume, we'll never get the document load or load events after relinquishing the yield token.
+    
+    Source/WebKit:
+    
+    Add hooks to WKDOMDocument to create and return an internal WKDOMDocumentParserYieldToken object, whose lifetime
+    is tied to a document parser yield token. See WebCore ChangeLog for more detail.
+    
+    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.h:
+    * WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm:
+    (-[WKDOMDocumentParserYieldToken initWithDocument:]):
+    (-[WKDOMDocument parserYieldToken]):
+    
+    Tools:
+    
+    Add a few tests to exercise the new document yield token SPI, verifying that clients can use the SPI to defer
+    document load, and that doing so doesn't cause deferred `script` to execute in the wrong order (i.e. before
+    synchronous script, or after "DOMContentLoaded").
+    
+    * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm: Added.
+    (-[ParserYieldTokenPlugIn takeDocumentParserTokenAfterCommittingLoad]):
+    (-[ParserYieldTokenPlugIn releaseDocumentParserToken]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didCommitLoadForFrame:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishDocumentLoadForFrame:]):
+    (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishLoadForFrame:]):
+    
+    Add an injected bundle object that knows how to take and release multiple document parser yield tokens.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h: Added.
+    * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm: Added.
+    (+[ParserYieldTokenTestWebView webView]):
+    (-[ParserYieldTokenTestWebView bundle]):
+    (-[ParserYieldTokenTestWebView schemeHandler]):
+    (-[ParserYieldTokenTestWebView didFinishDocumentLoad]):
+    (-[ParserYieldTokenTestWebView didFinishLoad]):
+    (waitForDelay):
+    (TEST):
+    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h: Added.
+    * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm: Added.
+    (-[TestURLSchemeHandler webView:startURLSchemeTask:]):
+    (-[TestURLSchemeHandler webView:stopURLSchemeTask:]):
+    (-[TestURLSchemeHandler setStartURLSchemeTaskHandler:]):
+    (-[TestURLSchemeHandler startURLSchemeTaskHandler]):
+    (-[TestURLSchemeHandler setStopURLSchemeTaskHandler:]):
+    (-[TestURLSchemeHandler stopURLSchemeTaskHandler]):
+    
+    Add a new test helper class to handle custom schemes via a block-based API.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html: Added.
+    
+    New test HTML page that contains a deferred script element, a synchronous script element, another deferred
+    script element, and then some text, images, and links.
+    
+    * TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html: Added.
+    
+    
+    git-svn-id: https://svn.webkit.org/repository/webkit/trunk@233891 268f45cc-cd09-0410-ab3c-d52691b4dbfc
+
+    2018-07-17  Wenson Hsieh  <[email protected]>
+
+            Add an SPI hook to allow clients to yield document parsing and script execution
+            https://bugs.webkit.org/show_bug.cgi?id=187682
+            <rdar://problem/42207453>
+
+            Reviewed by Ryosuke Niwa.
+
+            Add a few tests to exercise the new document yield token SPI, verifying that clients can use the SPI to defer
+            document load, and that doing so doesn't cause deferred `script` to execute in the wrong order (i.e. before
+            synchronous script, or after "DOMContentLoaded").
+
+            * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
+            * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm: Added.
+            (-[ParserYieldTokenPlugIn takeDocumentParserTokenAfterCommittingLoad]):
+            (-[ParserYieldTokenPlugIn releaseDocumentParserToken]):
+            (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didCommitLoadForFrame:]):
+            (-[ParserYieldTokenPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
+            (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishDocumentLoadForFrame:]):
+            (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishLoadForFrame:]):
+
+            Add an injected bundle object that knows how to take and release multiple document parser yield tokens.
+
+            * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h: Added.
+            * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm: Added.
+            (+[ParserYieldTokenTestWebView webView]):
+            (-[ParserYieldTokenTestWebView bundle]):
+            (-[ParserYieldTokenTestWebView schemeHandler]):
+            (-[ParserYieldTokenTestWebView didFinishDocumentLoad]):
+            (-[ParserYieldTokenTestWebView didFinishLoad]):
+            (waitForDelay):
+            (TEST):
+            * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h: Added.
+            * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm: Added.
+            (-[TestURLSchemeHandler webView:startURLSchemeTask:]):
+            (-[TestURLSchemeHandler webView:stopURLSchemeTask:]):
+            (-[TestURLSchemeHandler setStartURLSchemeTaskHandler:]):
+            (-[TestURLSchemeHandler startURLSchemeTaskHandler]):
+            (-[TestURLSchemeHandler setStopURLSchemeTaskHandler:]):
+            (-[TestURLSchemeHandler stopURLSchemeTaskHandler]):
+
+            Add a new test helper class to handle custom schemes via a block-based API.
+
+            * TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html: Added.
+
+            New test HTML page that contains a deferred script element, a synchronous script element, another deferred
+            script element, and then some text, images, and links.
+
+            * TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html: Added.
+
+2018-07-18  Babak Shafiei  <[email protected]>
+
         Cherry-pick r233927. rdar://problem/42354954
 
     -_beginAnimatedResizeWithUpdates: can leave view in bad state if called during an existing animation

Modified: branches/safari-606-branch/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj (233976 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-07-19 02:01:20 UTC (rev 233976)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj	2018-07-19 05:40:13 UTC (rev 233977)
@@ -783,6 +783,9 @@
 		F43E3BBF20DADA1E00A4E7ED /* WKScrollViewTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F43E3BBE20DADA1E00A4E7ED /* WKScrollViewTests.mm */; };
 		F43E3BC120DADBC500A4E7ED /* fixed-nav-bar.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F43E3BC020DADB8000A4E7ED /* fixed-nav-bar.html */; };
 		F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */; };
+		F44C79FF20F9E8710014478C /* ParserYieldTokenTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44C79FE20F9E8710014478C /* ParserYieldTokenTests.mm */; };
+		F44C7A0020F9EEBF0014478C /* ParserYieldTokenPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */; };
+		F44C7A0520FAAE3C0014478C /* text-with-deferred-script.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F44C7A0420FAAE320014478C /* text-with-deferred-script.html */; };
 		F44D06451F395C26001A0E29 /* editor-state-test-harness.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F44D06441F395C0D001A0E29 /* editor-state-test-harness.html */; };
 		F44D06471F39627A001A0E29 /* EditorStateTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44D06461F395C4D001A0E29 /* EditorStateTests.mm */; };
 		F44D064A1F3962F2001A0E29 /* EditingTestHarness.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44D06491F3962E3001A0E29 /* EditingTestHarness.mm */; };
@@ -813,6 +816,8 @@
 		F4BFA68E1E4AD08000154298 /* DragAndDropPasteboardTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */; };
 		F4C2AB221DD6D95E00E06D5B /* enormous-video-with-sound.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */; };
 		F4C8797F2059D8D3009CD00B /* ScrollViewInsetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4C8797E2059D8D3009CD00B /* ScrollViewInsetTests.mm */; };
+		F4CD74C620FDACFA00DE3794 /* text-with-async-script.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4CD74C520FDACF500DE3794 /* text-with-async-script.html */; };
+		F4CD74C920FDB49600DE3794 /* TestURLSchemeHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4CD74C820FDB49600DE3794 /* TestURLSchemeHandler.mm */; };
 		F4D4F3B61E4E2BCB00BB2767 /* DataInteractionSimulator.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4D4F3B41E4E2BCB00BB2767 /* DataInteractionSimulator.mm */; };
 		F4D4F3B91E4E36E400BB2767 /* DataInteractionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4D4F3B71E4E36E400BB2767 /* DataInteractionTests.mm */; };
 		F4D5E4E81F0C5D38008C1A49 /* dragstart-clear-selection.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4D5E4E71F0C5D27008C1A49 /* dragstart-clear-selection.html */; };
@@ -900,7 +905,6 @@
 			dstPath = TestWebKitAPI.resources;
 			dstSubfolderSpec = 7;
 			files = (
-				46AE5A3720F9066D00E0873E /* SimpleServiceWorkerRegistrations-3.sqlite3 in Copy Resources */,
 				1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
 				379028B914FAC24C007E6B43 /* acceptsFirstMouse.html in Copy Resources */,
 				1C2B81871C8925A000A5529F /* Ahem.ttf in Copy Resources */,
@@ -1128,6 +1132,7 @@
 				BC909784125571CF00083756 /* simple.html in Copy Resources */,
 				51E5C7021919C3B200D8B3E1 /* simple2.html in Copy Resources */,
 				51E5C7031919C3B200D8B3E1 /* simple3.html in Copy Resources */,
+				46AE5A3720F9066D00E0873E /* SimpleServiceWorkerRegistrations-3.sqlite3 in Copy Resources */,
 				F4F405BD1D4C0D1C007A9707 /* skinny-autoplaying-video-with-audio.html in Copy Resources */,
 				C01A23F21266156700C9ED55 /* spacebar-scrolling.html in Copy Resources */,
 				E194E1BD177E53C7009C4D4E /* StopLoadingFromDidReceiveResponse.html in Copy Resources */,
@@ -1141,6 +1146,8 @@
 				524BBCA119E30C77002F1AF1 /* test.mp4 in Copy Resources */,
 				7AE9E5091AE5AE8B00CF874B /* test.pdf in Copy Resources */,
 				2E9896151D8F093800739892 /* text-and-password-inputs.html in Copy Resources */,
+				F4CD74C620FDACFA00DE3794 /* text-with-async-script.html in Copy Resources */,
+				F44C7A0520FAAE3C0014478C /* text-with-deferred-script.html in Copy Resources */,
 				F41AB9AA1EF4696B0083FA08 /* textarea-to-input.html in Copy Resources */,
 				F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */,
 				C540F784152E5A9A00A40C8C /* verboseMarkup.html in Copy Resources */,
@@ -1981,6 +1988,10 @@
 		F43E3BBE20DADA1E00A4E7ED /* WKScrollViewTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = WKScrollViewTests.mm; sourceTree = "<group>"; };
 		F43E3BC020DADB8000A4E7ED /* fixed-nav-bar.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "fixed-nav-bar.html"; sourceTree = "<group>"; };
 		F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "two-paragraph-contenteditable.html"; sourceTree = "<group>"; };
+		F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ParserYieldTokenPlugIn.mm; sourceTree = "<group>"; };
+		F44C79FD20F9E8710014478C /* ParserYieldTokenTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParserYieldTokenTests.h; sourceTree = "<group>"; };
+		F44C79FE20F9E8710014478C /* ParserYieldTokenTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ParserYieldTokenTests.mm; sourceTree = "<group>"; };
+		F44C7A0420FAAE320014478C /* text-with-deferred-script.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "text-with-deferred-script.html"; sourceTree = "<group>"; };
 		F44D06441F395C0D001A0E29 /* editor-state-test-harness.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "editor-state-test-harness.html"; sourceTree = "<group>"; };
 		F44D06461F395C4D001A0E29 /* EditorStateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EditorStateTests.mm; sourceTree = "<group>"; };
 		F44D06481F3962E3001A0E29 /* EditingTestHarness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EditingTestHarness.h; sourceTree = "<group>"; };
@@ -2015,6 +2026,9 @@
 		F4BFA68C1E4AD08000154298 /* DragAndDropPasteboardTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DragAndDropPasteboardTests.mm; sourceTree = "<group>"; };
 		F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "enormous-video-with-sound.html"; sourceTree = "<group>"; };
 		F4C8797E2059D8D3009CD00B /* ScrollViewInsetTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollViewInsetTests.mm; sourceTree = "<group>"; };
+		F4CD74C520FDACF500DE3794 /* text-with-async-script.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "text-with-async-script.html"; sourceTree = "<group>"; };
+		F4CD74C720FDB49600DE3794 /* TestURLSchemeHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestURLSchemeHandler.h; sourceTree = "<group>"; };
+		F4CD74C820FDB49600DE3794 /* TestURLSchemeHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TestURLSchemeHandler.mm; sourceTree = "<group>"; };
 		F4D4F3B41E4E2BCB00BB2767 /* DataInteractionSimulator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DataInteractionSimulator.mm; sourceTree = "<group>"; };
 		F4D4F3B51E4E2BCB00BB2767 /* DataInteractionSimulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataInteractionSimulator.h; sourceTree = "<group>"; };
 		F4D4F3B71E4E36E400BB2767 /* DataInteractionTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DataInteractionTests.mm; sourceTree = "<group>"; };
@@ -2280,6 +2294,9 @@
 				37A22AA51DCAA27200AFBFC4 /* ObservedRenderingProgressEventsAfterCrash.mm */,
 				CEA6CF2219CCF5BD0064F5A7 /* OpenAndCloseWindow.mm */,
 				CEBCA12E1E3A660100C73293 /* OverrideContentSecurityPolicy.mm */,
+				F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */,
+				F44C79FD20F9E8710014478C /* ParserYieldTokenTests.h */,
+				F44C79FE20F9E8710014478C /* ParserYieldTokenTests.mm */,
 				9BCB7C2620130600003E7C0C /* PasteHTML.mm */,
 				9BDCCD851F7D0B0700009A18 /* PasteImage.mm */,
 				F457A9B6202D5CDC00F7E9D5 /* PasteMixedContent.mm */,
@@ -2308,6 +2325,8 @@
 				2DFF7B6C1DA487AF00814614 /* SnapshotStore.mm */,
 				515BE1701D428BD100DD7C68 /* StoreBlobThenDelete.mm */,
 				1C734B5220788C4800F430EA /* SystemColors.mm */,
+				F4CD74C720FDB49600DE3794 /* TestURLSchemeHandler.h */,
+				F4CD74C820FDB49600DE3794 /* TestURLSchemeHandler.mm */,
 				5CB40B4D1F4B98BE007DC7B9 /* UIDelegate.mm */,
 				7CC3E1FA197E234100BE6252 /* UserContentController.mm */,
 				7C882E031C80C624006BF731 /* UserContentWorld.mm */,
@@ -2650,6 +2669,8 @@
 				9BD6D39F1F7B202000BD4962 /* sunset-in-cupertino-400px.gif */,
 				9BD6D39E1F7B201E00BD4962 /* sunset-in-cupertino-600px.jpg */,
 				2E9896141D8F092B00739892 /* text-and-password-inputs.html */,
+				F4CD74C520FDACF500DE3794 /* text-with-async-script.html */,
+				F44C7A0420FAAE320014478C /* text-with-deferred-script.html */,
 				F41AB9951EF4692C0083FA08 /* textarea-to-input.html */,
 				F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */,
 				51714EB21CF8C761004723C4 /* WebProcessKillIDBCleanup-1.html */,
@@ -3766,6 +3787,7 @@
 				7CCE7EC71A411A7E00447C4C /* PageVisibilityStateWithWindowChanges.mm in Sources */,
 				7CCE7F091A411AE600447C4C /* ParentFrame.cpp in Sources */,
 				7C83E0511D0A641800FEBCF3 /* ParsedContentRange.cpp in Sources */,
+				F44C79FF20F9E8710014478C /* ParserYieldTokenTests.mm in Sources */,
 				7CCE7F0A1A411AE600447C4C /* PasteboardNotifications.mm in Sources */,
 				9BCB7C2820130600003E7C0C /* PasteHTML.mm in Sources */,
 				9BDCCD871F7D0B0700009A18 /* PasteImage.mm in Sources */,
@@ -3850,6 +3872,7 @@
 				2D1C04A71D76298B000A6816 /* TestNavigationDelegate.mm in Sources */,
 				A14FC5901B8AE36F00D107EB /* TestProtocol.mm in Sources */,
 				7CCE7EAE1A411A3400447C4C /* TestsController.cpp in Sources */,
+				F4CD74C920FDB49600DE3794 /* TestURLSchemeHandler.mm in Sources */,
 				2EFF06D41D8AEDBB0004BB30 /* TestWKWebView.mm in Sources */,
 				F4517B672054C49500C26721 /* TestWKWebViewController.mm in Sources */,
 				F45033F5206BEC95009351CE /* TextAutosizingBoost.mm in Sources */,
@@ -3974,6 +3997,7 @@
 				518EE51920A78CE500E024F3 /* DoubleDefersLoadingPlugin.mm in Sources */,
 				5CB5B3C21FFC55CF00C27BB0 /* FrameHandleSerialization.mm in Sources */,
 				79C5D431209D768300F1E7CA /* InjectedBundleNodeHandleIsTextField.mm in Sources */,
+				F44C7A0020F9EEBF0014478C /* ParserYieldTokenPlugIn.mm in Sources */,
 				A13EBBAB1B87434600097110 /* PlatformUtilitiesCocoa.mm in Sources */,
 				1A4F81CF1BDFFD53004E672E /* RemoteObjectRegistryPlugIn.mm in Sources */,
 				A12DDC021E837C2400CF6CAE /* RenderedImageWithOptionsPlugIn.mm in Sources */,

Added: branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm (0 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm	                        (rev 0)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm	2018-07-19 05:40:13 UTC (rev 233977)
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#import "config.h"
+
+#if WK_API_ENABLED
+
+#import "ParserYieldTokenTests.h"
+#import <WebKit/WKDOMDocument.h>
+#import <WebKit/WKWebProcessPlugIn.h>
+#import <WebKit/WKWebProcessPlugInBrowserContextControllerPrivate.h>
+#import <WebKit/WKWebProcessPlugInLoadDelegate.h>
+#import <WebKit/_WKRemoteObjectInterface.h>
+#import <WebKit/_WKRemoteObjectRegistry.h>
+#import <wtf/RetainPtr.h>
+
+@interface ParserYieldTokenPlugIn : NSObject <WKWebProcessPlugIn, WKWebProcessPlugInLoadDelegate, ParserYieldTokenTestBundle>
+@end
+
+@implementation ParserYieldTokenPlugIn {
+    RetainPtr<NSMutableArray<NSObject *>> _parserYieldTokens;
+    RetainPtr<id<ParserYieldTokenTestRunner>> _testRunner;
+    RetainPtr<WKWebProcessPlugInBrowserContextController> _controller;
+    BOOL _loadCommitted;
+    NSUInteger _numberOfTokensToTakeAfterComittingLoad;
+}
+
+- (void)takeDocumentParserTokenAfterCommittingLoad
+{
+    if (_loadCommitted)
+        [_parserYieldTokens addObject:[_controller mainFrameDocument].parserYieldToken];
+    else
+        ++_numberOfTokensToTakeAfterComittingLoad;
+}
+
+- (void)releaseDocumentParserToken
+{
+    if (_loadCommitted)
+        [_parserYieldTokens removeObjectAtIndex:0];
+    else
+        --_numberOfTokensToTakeAfterComittingLoad;
+}
+
+- (void)webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController *)controller didCommitLoadForFrame:(WKWebProcessPlugInFrame *)frame
+{
+    _loadCommitted = YES;
+    while (_numberOfTokensToTakeAfterComittingLoad) {
+        [self takeDocumentParserTokenAfterCommittingLoad];
+        --_numberOfTokensToTakeAfterComittingLoad;
+    }
+}
+
+- (void)webProcessPlugIn:(WKWebProcessPlugInController *)plugInController didCreateBrowserContextController:(WKWebProcessPlugInBrowserContextController *)browserContextController
+{
+    _parserYieldTokens = adoptNS([NSMutableArray new]);
+    _controller = browserContextController;
+    browserContextController.loadDelegate = self;
+    [browserContextController._remoteObjectRegistry registerExportedObject:self interface:[_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(ParserYieldTokenTestBundle)]];
+    _testRunner = [browserContextController._remoteObjectRegistry remoteObjectProxyWithInterface:[_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(ParserYieldTokenTestRunner)]];
+}
+
+- (void)webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController*)controller didFinishDocumentLoadForFrame:(WKWebProcessPlugInFrame *)frame
+{
+    [_testRunner didFinishDocumentLoad];
+}
+
+- (void)webProcessPlugInBrowserContextController:(WKWebProcessPlugInBrowserContextController*)controller didFinishLoadForFrame:(WKWebProcessPlugInFrame *)frame
+{
+    [_testRunner didFinishLoad];
+}
+
+@end
+
+#endif // WK_API_ENABLED
+

Copied: branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h (from rev 233976, branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.h) (0 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h	                        (rev 0)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+@protocol ParserYieldTokenTestRunner <NSObject>
+- (void)didFinishDocumentLoad;
+- (void)didFinishLoad;
+@end
+
+@protocol ParserYieldTokenTestBundle <NSObject>
+- (void)takeDocumentParserTokenAfterCommittingLoad;
+- (void)releaseDocumentParserToken;
+@end

Added: branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm (0 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm	                        (rev 0)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm	2018-07-19 05:40:13 UTC (rev 233977)
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#import "ParserYieldTokenTests.h"
+
+#if WK_API_ENABLED
+
+#import "PlatformUtilities.h"
+#import "TestURLSchemeHandler.h"
+#import "TestWKWebView.h"
+#import "WKWebViewConfigurationExtras.h"
+#import <WebKit/WKWebViewPrivate.h>
+#import <WebKit/_WKRemoteObjectInterface.h>
+#import <WebKit/_WKRemoteObjectRegistry.h>
+#import <wtf/BlockPtr.h>
+#import <wtf/Seconds.h>
+
+@interface ParserYieldTokenTestWebView : TestWKWebView <ParserYieldTokenTestRunner>
+@property (nonatomic, readonly) BOOL finishedDocumentLoad;
+@property (nonatomic, readonly) BOOL finishedLoad;
+@end
+
+@implementation ParserYieldTokenTestWebView {
+    RetainPtr<id <ParserYieldTokenTestBundle>> _bundle;
+    RetainPtr<TestURLSchemeHandler> _schemeHandler;
+}
+
++ (RetainPtr<ParserYieldTokenTestWebView>)webView
+{
+    auto schemeHandler = adoptNS([[TestURLSchemeHandler alloc] init]);
+    auto *configuration = [WKWebViewConfiguration _test_configurationWithTestPlugInClassName:@"ParserYieldTokenPlugIn"];
+    [configuration setURLSchemeHandler:schemeHandler.get() forURLScheme:@"custom"];
+    auto webView = adoptNS([[ParserYieldTokenTestWebView alloc] initWithFrame:CGRectMake(0, 0, 200, 200) configuration:configuration]);
+    [[webView _remoteObjectRegistry] registerExportedObject:webView.get() interface:[_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(ParserYieldTokenTestRunner)]];
+    webView->_bundle = [[webView _remoteObjectRegistry] remoteObjectProxyWithInterface:[_WKRemoteObjectInterface remoteObjectInterfaceWithProtocol:@protocol(ParserYieldTokenTestBundle)]];
+    webView->_schemeHandler = WTFMove(schemeHandler);
+    return webView;
+}
+
+- (id <ParserYieldTokenTestBundle>)bundle
+{
+    return _bundle.get();
+}
+
+- (TestURLSchemeHandler *)schemeHandler
+{
+    return _schemeHandler.get();
+}
+
+- (void)didFinishDocumentLoad
+{
+    _finishedDocumentLoad = YES;
+}
+
+- (void)didFinishLoad
+{
+    _finishedLoad = YES;
+}
+
+@end
+
+static void waitForDelay(Seconds delay)
+{
+    __block bool done = false;
+    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, delay.nanoseconds()), dispatch_get_main_queue(), ^{
+        done = true;
+    });
+    TestWebKitAPI::Util::run(&done);
+}
+
+TEST(ParserYieldTokenTests, PreventDocumentLoadByTakingParserYieldToken)
+{
+    auto webView = [ParserYieldTokenTestWebView webView];
+    [[webView bundle] takeDocumentParserTokenAfterCommittingLoad];
+    [webView loadTestPageNamed:@"simple"];
+
+    // Give the web view a chance to load the page. In the case where the token fails to yield document parsing, it's very likely that
+    // the document will finish loading, and we'll fail the test expectations below. In the unlikely event where page load may take
+    // longer than 1 second, this test should still pass.
+    waitForDelay(1_s);
+    EXPECT_FALSE([webView finishedDocumentLoad]);
+    EXPECT_FALSE([webView finishedLoad]);
+
+    // Now, allow document parsing to continue, and wait for the page to finish loading.
+    [[webView bundle] releaseDocumentParserToken];
+
+    while (![webView finishedLoad] || ![webView finishedDocumentLoad])
+        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+}
+
+TEST(ParserYieldTokenTests, TakeMultipleParserYieldTokens)
+{
+    auto webView = [ParserYieldTokenTestWebView webView];
+    [[webView bundle] takeDocumentParserTokenAfterCommittingLoad];
+    [webView loadTestPageNamed:@"simple"];
+
+    waitForDelay(0.5_s);
+    EXPECT_FALSE([webView finishedDocumentLoad]);
+    EXPECT_FALSE([webView finishedLoad]);
+
+    [[webView bundle] takeDocumentParserTokenAfterCommittingLoad];
+    [[webView bundle] releaseDocumentParserToken];
+
+    waitForDelay(0.5_s);
+    EXPECT_FALSE([webView finishedDocumentLoad]);
+    EXPECT_FALSE([webView finishedLoad]);
+
+    [[webView bundle] releaseDocumentParserToken];
+
+    while (![webView finishedLoad] || ![webView finishedDocumentLoad])
+        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+}
+
+TEST(ParserYieldTokenTests, DeferredScriptExecutesBeforeDocumentLoadWhenTakingParserYieldToken)
+{
+    auto webView = [ParserYieldTokenTestWebView webView];
+
+    [[webView bundle] takeDocumentParserTokenAfterCommittingLoad];
+    [webView loadTestPageNamed:@"text-with-deferred-script"];
+
+    waitForDelay(0.5_s);
+    EXPECT_FALSE([webView finishedDocumentLoad]);
+    EXPECT_FALSE([webView finishedLoad]);
+
+    [[webView bundle] releaseDocumentParserToken];
+
+    while (![webView finishedLoad] || ![webView finishedDocumentLoad])
+        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+
+    // Verify that synchronous script is executed before deferred script and deferred script is run before document load.
+    NSArray<NSString *> *eventMessages = [webView objectByEvaluatingJavaScript:@"window.eventMessages"];
+    EXPECT_EQ(eventMessages.count, 8U);
+    EXPECT_WK_STREQ("Running sync", eventMessages[0]);
+    EXPECT_WK_STREQ("Loaded script: sync", eventMessages[1]);
+    EXPECT_WK_STREQ("Running defer-before", eventMessages[2]);
+    EXPECT_WK_STREQ("Loaded script: defer-before", eventMessages[3]);
+    EXPECT_WK_STREQ("Running defer-after", eventMessages[4]);
+    EXPECT_WK_STREQ("Loaded script: defer-after", eventMessages[5]);
+    EXPECT_WK_STREQ("Document finished loading", eventMessages[6]);
+    EXPECT_WK_STREQ("Finished loading", eventMessages[7]);
+}
+
+TEST(ParserYieldTokenTests, AsyncScriptRunsWhenFetched)
+{
+    auto webView = [ParserYieldTokenTestWebView webView];
+    [webView schemeHandler].startURLSchemeTaskHandler = [] (WKWebView *, id <WKURLSchemeTask> task) {
+        auto script = retainPtr(@"window.eventMessages.push('Running async script.');");
+        auto response = adoptNS([[NSURLResponse alloc] initWithURL:task.request.URL MIMEType:@"text/_javascript_" expectedContentLength:[script length] textEncodingName:nil]);
+        dispatch_async(dispatch_get_main_queue(), [task = retainPtr(task), response = WTFMove(response), script = WTFMove(script)] {
+            [task didReceiveResponse:response.get()];
+            [task didReceiveData:[script dataUsingEncoding:NSUTF8StringEncoding]];
+            [task didFinish];
+        });
+    };
+
+    [[webView bundle] takeDocumentParserTokenAfterCommittingLoad];
+
+    NSURL *pageURL = [[NSBundle mainBundle] URLForResource:@"text-with-async-script" withExtension:@"html" subdirectory:@"TestWebKitAPI.resources"];
+    [webView loadHTMLString:[NSString stringWithContentsOfURL:pageURL encoding:NSUTF8StringEncoding error:nil] baseURL:[NSURL URLWithString:@"custom://"]];
+
+    waitForDelay(0.5_s);
+    EXPECT_FALSE([webView finishedDocumentLoad]);
+    EXPECT_FALSE([webView finishedLoad]);
+
+    [[webView bundle] releaseDocumentParserToken];
+
+    while (![webView finishedLoad] || ![webView finishedDocumentLoad])
+        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantPast]];
+
+    NSArray<NSString *> *eventMessages = [webView objectByEvaluatingJavaScript:@"window.eventMessages"];
+    EXPECT_EQ(eventMessages.count, 4U);
+    EXPECT_WK_STREQ("Before requesting async script.", eventMessages[0]);
+    EXPECT_WK_STREQ("After requesting async script.", eventMessages[1]);
+    EXPECT_WK_STREQ("Running async script.", eventMessages[2]);
+    EXPECT_WK_STREQ("Finished requesting async script.", eventMessages[3]);
+}
+
+#endif // WK_API_ENABLED

Copied: branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h (from rev 233976, branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.h) (0 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h	                        (rev 0)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h	2018-07-19 05:40:13 UTC (rev 233977)
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#import <WebKit/WebKit.h>
+
+#if WK_API_ENABLED
+
+@interface TestURLSchemeHandler : NSObject <WKURLSchemeHandler>
+
+@property (nonatomic, copy) void (^startURLSchemeTaskHandler)(WKWebView *, id <WKURLSchemeTask>);
+@property (nonatomic, copy) void (^stopURLSchemeTaskHandler)(WKWebView *, id <WKURLSchemeTask>);
+
+@end
+
+#endif // WK_API_ENABLED

Copied: branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm (from rev 233976, branches/safari-606-branch/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.h) (0 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm	                        (rev 0)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm	2018-07-19 05:40:13 UTC (rev 233977)
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2018 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TestURLSchemeHandler.h"
+
+#import <wtf/BlockPtr.h>
+
+#if WK_API_ENABLED
+
+@implementation TestURLSchemeHandler {
+    BlockPtr<void(WKWebView *, id <WKURLSchemeTask>)> _startURLSchemeTaskHandler;
+    BlockPtr<void(WKWebView *, id <WKURLSchemeTask>)> _stopURLSchemeTaskHandler;
+}
+
+- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
+{
+    if (_startURLSchemeTaskHandler)
+        _startURLSchemeTaskHandler(webView, urlSchemeTask);
+}
+
+- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
+{
+    if (_stopURLSchemeTaskHandler)
+        _stopURLSchemeTaskHandler(webView, urlSchemeTask);
+}
+
+- (void)setStartURLSchemeTaskHandler:(void (^)(WKWebView *, id <WKURLSchemeTask>))block
+{
+    _startURLSchemeTaskHandler = makeBlockPtr(block);
+}
+
+- (void (^)(WKWebView *, id <WKURLSchemeTask>))startURLSchemeTaskHandler
+{
+    return _startURLSchemeTaskHandler.get();
+}
+
+- (void)setStopURLSchemeTaskHandler:(void (^)(WKWebView *, id <WKURLSchemeTask>))block
+{
+    _startURLSchemeTaskHandler = makeBlockPtr(block);
+}
+
+- (void (^)(WKWebView *, id <WKURLSchemeTask>))stopURLSchemeTaskHandler
+{
+    return _stopURLSchemeTaskHandler.get();
+}
+
+@end
+
+#endif // WK_API_ENABLED

Added: branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html (0 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html	                        (rev 0)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html	2018-07-19 05:40:13 UTC (rev 233977)
@@ -0,0 +1,20 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <script>
+        eventMessages = [];
+    </script>
+</head>
+<body>
+    <script src="" async></script>
+    <script>
+        eventMessages.push("Before requesting async script.");
+        fetch("async.js").then(response => eventMessages.push("Finished requesting async script."));
+        eventMessages.push("After requesting async script.");
+    </script>
+    <p>Lorem ipsum dolor sit amet, <a href="" adipiscing elit</a>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <a href="" id eu nisl nunc mi ipsum faucibus vitae.</a> Sed tempus urna et pharetra pharetra massa massa. Vitae tortor condimentum lacinia quis vel eros donec ac. <a href="" velit sed ullamcorper morbi</a> tincidunt ornare massa eget. Sit amet cursus sit amet dictum. Id eu nisl nunc mi ipsum faucibus vitae aliquet nec. Suscipit tellus mauris a diam maecenas sed. Consequat nisl vel pretium lectus quam id leo. <a href="" et malesuada fames ac turpis egestas integer.</a> Quam lacus suspendisse faucibus interdum posuere lorem ipsum. Sem integer vitae justo eget magna fermentum iaculis. A condimentum vitae sapien pellentesque habitant morbi tristique. Variu
 s duis at consectetur lorem. Ipsum faucibus vitae aliquet nec ullamcorper sit.</p>
+    <p>Sed faucibus <a href="" in eu mi bibendum</a>. Donec enim diam vulputate ut pharetra sit amet aliquam. Consequat id porta nibh venenatis cras sed felis eget velit. At lectus urna duis convallis convallis tellus id interdum velit. Id consectetur purus ut faucibus pulvinar elementum integer enim. Ipsum dolor sit amet consectetur adipiscing elit ut aliquam. At tellus at urna condimentum mattis. Faucibus pulvinar elementum integer enim. At elementum eu facilisis sed odio morbi. Fames ac turpis egestas integer eget aliquet. Consequat interdum varius sit amet mattis vulputate enim nulla. Lectus sit amet est placerat in egestas. Dolor sit amet consectetur adipiscing elit pellentesque habitant morbi. Urna et pharetra pharetra massa massa ultricies mi.</p>
+    <p>Sed lectus vestibulum mattis ullamcorper velit sed ullamcorper. <a href="" lacus suspendisse</a> faucibus interdum posuere lorem. Sagittis vitae et leo duis ut diam. Turpis massa sed elementum tempus. Aliquam sem fringilla ut morbi. <a href="" est ullamcorper</a> eget nulla facilisi etiam dignissim. Id velit ut tortor pretium. Bibendum at varius vel pharetra vel turpis nunc. Sit amet aliquam id diam maecenas. Lobortis feugiat vivamus at augue <a href="" arcu dictum</a> varius duis. Libero justo laoreet sit amet. Egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam.</p>
+</body>
+</html>

Added: branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html (0 => 233977)


--- branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html	                        (rev 0)
+++ branches/safari-606-branch/Tools/TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html	2018-07-19 05:40:13 UTC (rev 233977)
@@ -0,0 +1,26 @@
+<!DOCTYPE html>
+<html>
+<head>
+    <meta name="viewport" content="width=device-width, initial-scale=1">
+    <script>
+        eventMessages = []
+
+        function scriptLoaded(script)
+        {
+            eventMessages.push(`Loaded script: ${script.id}`);
+        }
+    </script>
+</head>
+<body>
+    <script>
+        document.addEventListener("DOMContentLoaded", () => eventMessages.push("Document finished loading"));
+        addEventListener("load", () => eventMessages.push("Finished loading"));
+    </script>
+    <script id="defer-before" _onload_="scriptLoaded(this)" defer src="" defer-before')"></script>
+    <script id="sync" _onload_="scriptLoaded(this)" src="" sync')"></script>
+    <script id="defer-after" _onload_="scriptLoaded(this)" defer src="" defer-after')"></script>
+    <p>Lorem ipsum dolor sit amet, <a href="" adipiscing elit</a>, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. <a href="" id eu nisl nunc mi ipsum faucibus vitae.</a> Sed tempus urna et pharetra pharetra massa massa. Vitae tortor condimentum lacinia quis vel eros donec ac. <a href="" velit sed ullamcorper morbi</a> tincidunt ornare massa eget. Sit amet cursus sit amet dictum. Id eu nisl nunc mi ipsum faucibus vitae aliquet nec. Suscipit tellus mauris a diam maecenas sed. Consequat nisl vel pretium lectus quam id leo. <a href="" et malesuada fames ac turpis egestas integer.</a> Quam lacus suspendisse faucibus interdum posuere lorem ipsum. Sem integer vitae justo eget magna fermentum iaculis. A condimentum vitae sapien pellentesque habitant morbi tristique. Variu
 s duis at consectetur lorem. Ipsum faucibus vitae aliquet nec ullamcorper sit.</p>
+    <p>Sed faucibus <a href="" in eu mi bibendum</a>. Donec enim diam vulputate ut pharetra sit amet aliquam. <img src="" Consequat id porta nibh venenatis cras sed felis eget velit. At lectus urna duis convallis convallis tellus id interdum velit. Id consectetur purus ut faucibus pulvinar elementum integer enim. Ipsum dolor sit amet consectetur adipiscing elit ut aliquam. At tellus at urna condimentum mattis. Faucibus pulvinar elementum integer enim. At elementum eu facilisis sed odio morbi. Fames ac turpis egestas integer eget aliquet. Consequat interdum varius sit amet mattis vulputate enim nulla. Lectus sit amet est placerat in egestas. Dolor sit amet consectetur adipiscing elit pellentesque habitant morbi. Urna et pharetra pharetra massa massa ultricies mi.</p>
+    <p>Sed lectus vestibulum mattis ullamcorper velit sed ullamcorper. <a href="" lacus suspendisse</a> faucibus interdum posuere lorem. Sagittis vitae et leo duis ut diam. Turpis massa sed elementum tempus. Aliquam sem fringilla ut morbi. <a href="" est ullamcorper</a> eget nulla facilisi etiam dignissim. Id velit ut tortor pretium. Bibendum at varius vel pharetra vel turpis nunc. Sit amet aliquam id diam maecenas. Lobortis feugiat vivamus at augue <a href="" arcu dictum</a> varius duis. Libero justo laoreet sit amet. Egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam.</p>
+</body>
+</html>
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to