Changeset 233891 in webkit


Ignore:
Timestamp:
Jul 17, 2018 11:23:36 AM (6 years ago)
Author:
Wenson Hsieh
Message:

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.
Location:
trunk
Files:
4 added
15 edited
3 copied

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r233886 r233891  
     12018-07-17  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Add an SPI hook to allow clients to yield document parsing and script execution
     4        https://bugs.webkit.org/show_bug.cgi?id=187682
     5        <rdar://problem/42207453>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        Using a single web process for both the Reader page and original web page on watchOS has multiple benefits,
     10        including: (1) allowing the user to bail out of Reader and view the original web page without having to load it
     11        again, and (2) improving the bringup time of the Reader page, since subresources are already cached in process
     12        and we don't eat the additional cost of a web process launch if prewarming fails.
     13
     14        However, this has some drawbacks as well, one of which is that main thread work being done on behalf of the
     15        original page may contend with work being done to load and render the Reader page. This is especially bad when
     16        the page is in the middle of executing heavy script after Safari has already detected that the Reader version of
     17        the page is available, but before it has finished loading the Reader page. The result is that script on the
     18        original page may block the first paint of the Reader page (on New York Times articles, this often leads to an
     19        apparent page load time of 25-35 seconds before the user sees anything besides a blank screen).
     20
     21        To mitigate this, we introduce a way for injected bundle clients to yield parsing and async script execution on
     22        a document. This capability is surfaced in the form of an opaque token which clients may request from a
     23        WKDOMDocument. Construction of the token causes the document to begin yielding and defer execution of previously
     24        scheduled scripts, only if there were no active tokens on the document already. Similarly, destruction of all
     25        active tokens on the document causes it to stop yielding and resume execution of scripts if needed.
     26
     27        Tests:  ParserYieldTokenTests.PreventDocumentLoadByTakingParserYieldToken
     28                ParserYieldTokenTests.TakeMultipleParserYieldTokens
     29                ParserYieldTokenTests.DeferredScriptExecutesBeforeDocumentLoadWhenTakingParserYieldToken
     30                ParserYieldTokenTests.AsyncScriptRunsWhenFetched
     31
     32        * dom/Document.cpp:
     33        (WebCore::Document::implicitOpen):
     34
     35        If the parser yield token was taken before the document's parser was created, tell the parser's scheduler to
     36        start yielding immediately after creation.
     37
     38        (WebCore::DocumentParserYieldToken::DocumentParserYieldToken):
     39        (WebCore::DocumentParserYieldToken::~DocumentParserYieldToken):
     40        * dom/Document.h:
     41
     42        Introduce a parser yield count to Document; as long as this count is greater than 0, we consider the Document to
     43        have active yield tokens. When constructing or destroying a ParserYieldToken, we increment and decrement the
     44        parser yield count (respectively).
     45
     46        (WebCore::Document::createParserYieldToken):
     47        (WebCore::Document::hasActiveParserYieldToken const):
     48        * dom/DocumentParser.h:
     49        (WebCore::DocumentParser::didBeginYieldingParser):
     50        (WebCore::DocumentParser::didEndYieldingParser):
     51
     52        Hooks for Document to tell its parser that we've started or finished yielding. This updates a flag on the
     53        parser's scheduler which is consulted when we determine whether to yield before a pumping token or executing
     54        script.
     55
     56        * dom/ScriptRunner.cpp:
     57        (WebCore::ScriptRunner::resume):
     58        (WebCore::ScriptRunner::notifyFinished):
     59        * dom/ScriptRunner.h:
     60        (WebCore::ScriptRunner::didBeginYieldingParser):
     61        (WebCore::ScriptRunner::didEndYieldingParser):
     62
     63        Hooks for Document to tell its ScriptRunner that we've started or finished yielding. These wrap calls to suspend
     64        and resume.
     65
     66        * html/parser/HTMLDocumentParser.cpp:
     67        (WebCore::HTMLDocumentParser::didBeginYieldingParser):
     68        (WebCore::HTMLDocumentParser::didEndYieldingParser):
     69
     70        Plumb to didBegin/didEnd calls to the HTMLParserScheduler.
     71
     72        * html/parser/HTMLDocumentParser.h:
     73        * html/parser/HTMLParserScheduler.cpp:
     74        (WebCore::HTMLParserScheduler::shouldYieldBeforeExecutingScript):
     75        * html/parser/HTMLParserScheduler.h:
     76        (WebCore::HTMLParserScheduler::shouldYieldBeforeToken):
     77
     78        Consult a flag when determining whether to yield. This flag is set to true only while the document has an active
     79        parser yield token.
     80
     81        (WebCore::HTMLParserScheduler::isScheduledForResume const):
     82
     83        Consider the parser scheduler to be scheduled for resume if there are active tokens. Without this change, we
     84        incorrectly consider the document to be finished loading when we have yield tokens, since it appears that the
     85        parser is no longer scheduled to pump its tokenizer.
     86
     87        (WebCore::HTMLParserScheduler::didBeginYieldingParser):
     88        (WebCore::HTMLParserScheduler::didEndYieldingParser):
     89
     90        When the Document begins yielding due to the documet having active tokens or ends yielding after the document
     91        loses all of its yield tokens, update a flag on the parser scheduler. After we finish yielding, additionally
     92        reschedule the parser if needed to ensure that we continue parsing the document; without this additional change
     93        to resume, we'll never get the document load or load events after relinquishing the yield token.
     94
    1952018-07-17  Dirk Schulze  <krit@webkit.org>
    296
  • trunk/Source/WebCore/dom/Document.cpp

    r233865 r233891  
    26872687    cancelParsing();
    26882688    m_parser = createParser();
     2689
     2690    if (hasActiveParserYieldToken())
     2691        m_parser->didBeginYieldingParser();
     2692
    26892693    setParsing(true);
    26902694    setReadyState(Loading);
     
    69026906}
    69036907
     6908DocumentParserYieldToken::DocumentParserYieldToken(Document& document)
     6909    : m_document(makeWeakPtr(document))
     6910{
     6911    if (++document.m_parserYieldTokenCount != 1)
     6912        return;
     6913
     6914    document.scriptRunner()->didBeginYieldingParser();
     6915    if (auto* parser = document.parser())
     6916        parser->didBeginYieldingParser();
     6917}
     6918
     6919DocumentParserYieldToken::~DocumentParserYieldToken()
     6920{
     6921    if (!m_document)
     6922        return;
     6923
     6924    ASSERT(m_document->m_parserYieldTokenCount);
     6925    if (--m_document->m_parserYieldTokenCount)
     6926        return;
     6927
     6928    m_document->scriptRunner()->didEndYieldingParser();
     6929    if (auto* parser = m_document->parser())
     6930        parser->didEndYieldingParser();
     6931}
     6932
    69046933static RenderElement* nearestCommonHoverAncestor(RenderElement* obj1, RenderElement* obj2)
    69056934{
  • trunk/Source/WebCore/dom/Document.h

    r233794 r233891  
    318318>;
    319319
     320class DocumentParserYieldToken {
     321public:
     322    WEBCORE_EXPORT DocumentParserYieldToken(Document&);
     323    WEBCORE_EXPORT ~DocumentParserYieldToken();
     324
     325private:
     326    WeakPtr<Document> m_document;
     327};
     328
    320329class Document
    321330    : public ContainerNode
     
    12671276    void decrementActiveParserCount();
    12681277
     1278    std::unique_ptr<DocumentParserYieldToken> createParserYieldToken()
     1279    {
     1280        return std::make_unique<DocumentParserYieldToken>(*this);
     1281    }
     1282
     1283    bool hasActiveParserYieldToken() const { return m_parserYieldTokenCount; }
     1284
    12691285    DocumentSharedObjectPool* sharedObjectPool() { return m_sharedObjectPool.get(); }
    12701286
     
    14611477
    14621478private:
     1479    friend class DocumentParserYieldToken;
    14631480    friend class Node;
    14641481    friend class IgnoreDestructiveWriteCountIncrementer;
     
    15781595    Ref<CachedResourceLoader> m_cachedResourceLoader;
    15791596    RefPtr<DocumentParser> m_parser;
     1597
     1598    unsigned m_parserYieldTokenCount { 0 };
    15801599
    15811600    // Document URLs.
  • trunk/Source/WebCore/dom/DocumentParser.h

    r210216 r233891  
    9797    virtual void resumeScheduledTasks();
    9898
     99    virtual void didBeginYieldingParser() { }
     100    virtual void didEndYieldingParser() { }
     101
    99102protected:
    100103    explicit DocumentParser(Document&);
  • trunk/Source/WebCore/dom/ScriptRunner.cpp

    r215160 r233891  
    8383void ScriptRunner::resume()
    8484{
    85     if (hasPendingScripts())
     85    if (hasPendingScripts() && !m_document.hasActiveParserYieldToken())
    8686        m_timer.startOneShot(0_s);
    8787}
     
    9696    }
    9797    pendingScript.clearClient();
    98     m_timer.startOneShot(0_s);
     98
     99    if (!m_document.hasActiveParserYieldToken())
     100        m_timer.startOneShot(0_s);
    99101}
    100102
  • trunk/Source/WebCore/dom/ScriptRunner.h

    r210319 r233891  
    5151    void notifyScriptReady(ScriptElement*, ExecutionType);
    5252
     53    void didBeginYieldingParser() { suspend(); }
     54    void didEndYieldingParser() { resume(); }
     55
    5356private:
    5457    void timerFired();
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.cpp

    r233572 r233891  
    149149}
    150150
     151void HTMLDocumentParser::didBeginYieldingParser()
     152{
     153    m_parserScheduler->didBeginYieldingParser();
     154}
     155
     156void HTMLDocumentParser::didEndYieldingParser()
     157{
     158    m_parserScheduler->didEndYieldingParser();
     159}
     160
    151161bool HTMLDocumentParser::isParsingFragment() const
    152162{
  • trunk/Source/WebCore/html/parser/HTMLDocumentParser.h

    r212614 r233891  
    122122    bool shouldDelayEnd() const;
    123123
     124    void didBeginYieldingParser() final;
     125    void didEndYieldingParser() final;
     126
    124127    HTMLParserOptions m_options;
    125128    HTMLInputStream m_input;
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.cpp

    r229174 r233891  
    112112    bool needsFirstPaint = document->view() && !document->view()->hasEverPainted();
    113113    session.didSeeScript = true;
     114
     115    if (UNLIKELY(m_documentHasActiveParserYieldTokens))
     116        return true;
     117
    114118    return needsFirstPaint && document->isLayoutTimerActive();
    115119}
  • trunk/Source/WebCore/html/parser/HTMLParserScheduler.h

    r229209 r233891  
    7070            return true;
    7171#endif
     72        if (UNLIKELY(m_documentHasActiveParserYieldTokens))
     73            return true;
     74
    7275        if (UNLIKELY(session.processedTokens > numberOfTokensBeforeCheckingForYield || session.didSeeScript))
    7376            return checkForYield(session);
     
    7982
    8083    void scheduleForResume();
    81     bool isScheduledForResume() const { return m_isSuspendedWithActiveTimer || m_continueNextChunkTimer.isActive(); }
     84    bool isScheduledForResume() const { return m_isSuspendedWithActiveTimer || m_continueNextChunkTimer.isActive() || m_documentHasActiveParserYieldTokens; }
    8285
    8386    void suspend();
    8487    void resume();
     88
     89    void didBeginYieldingParser()
     90    {
     91        ASSERT(!m_documentHasActiveParserYieldTokens);
     92        m_documentHasActiveParserYieldTokens = true;
     93    }
     94
     95    void didEndYieldingParser()
     96    {
     97        ASSERT(m_documentHasActiveParserYieldTokens);
     98        m_documentHasActiveParserYieldTokens = false;
     99
     100        if (!isScheduledForResume())
     101            scheduleForResume();
     102    }
    85103
    86104private:
     
    113131    bool m_suspended;
    114132#endif
     133    bool m_documentHasActiveParserYieldTokens { false };
    115134};
    116135
  • trunk/Source/WebKit/ChangeLog

    r233888 r233891  
     12018-07-17  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Add an SPI hook to allow clients to yield document parsing and script execution
     4        https://bugs.webkit.org/show_bug.cgi?id=187682
     5        <rdar://problem/42207453>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        Add hooks to WKDOMDocument to create and return an internal WKDOMDocumentParserYieldToken object, whose lifetime
     10        is tied to a document parser yield token. See WebCore ChangeLog for more detail.
     11
     12        * WebProcess/InjectedBundle/API/mac/WKDOMDocument.h:
     13        * WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm:
     14        (-[WKDOMDocumentParserYieldToken initWithDocument:]):
     15        (-[WKDOMDocument parserYieldToken]):
     16
    1172018-07-17  John Wilander  <wilander@apple.com>
    218
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.h

    r230121 r233891  
    4343@property(readonly) WKDOMElement *body;
    4444
     45- (id)parserYieldToken WK_API_AVAILABLE(macosx(WK_MAC_TBA), ios(WK_IOS_TBA));
     46
    4547@end
    4648
  • trunk/Source/WebKit/WebProcess/InjectedBundle/API/mac/WKDOMDocument.mm

    r226467 r233891  
    3636#import <WebCore/markup.h>
    3737
     38@interface WKDOMDocumentParserYieldToken : NSObject
     39
     40@end
     41
     42@implementation WKDOMDocumentParserYieldToken {
     43    std::unique_ptr<WebCore::DocumentParserYieldToken> _token;
     44}
     45
     46- (instancetype)initWithDocument:(WebCore::Document&)document
     47{
     48    if (self = [super init])
     49        _token = document.createParserYieldToken();
     50    return self;
     51}
     52
     53@end
     54
    3855@implementation WKDOMDocument
    3956
     
    6784}
    6885
     86- (id)parserYieldToken
     87{
     88    return [[[WKDOMDocumentParserYieldToken alloc] initWithDocument:downcast<WebCore::Document>(*_impl)] autorelease];
     89}
     90
    6991@end
    7092
  • trunk/Tools/ChangeLog

    r233890 r233891  
     12018-07-17  Wenson Hsieh  <wenson_hsieh@apple.com>
     2
     3        Add an SPI hook to allow clients to yield document parsing and script execution
     4        https://bugs.webkit.org/show_bug.cgi?id=187682
     5        <rdar://problem/42207453>
     6
     7        Reviewed by Ryosuke Niwa.
     8
     9        Add a few tests to exercise the new document yield token SPI, verifying that clients can use the SPI to defer
     10        document load, and that doing so doesn't cause deferred `script` to execute in the wrong order (i.e. before
     11        synchronous script, or after "DOMContentLoaded").
     12
     13        * TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj:
     14        * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenPlugIn.mm: Added.
     15        (-[ParserYieldTokenPlugIn takeDocumentParserTokenAfterCommittingLoad]):
     16        (-[ParserYieldTokenPlugIn releaseDocumentParserToken]):
     17        (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didCommitLoadForFrame:]):
     18        (-[ParserYieldTokenPlugIn webProcessPlugIn:didCreateBrowserContextController:]):
     19        (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishDocumentLoadForFrame:]):
     20        (-[ParserYieldTokenPlugIn webProcessPlugInBrowserContextController:didFinishLoadForFrame:]):
     21
     22        Add an injected bundle object that knows how to take and release multiple document parser yield tokens.
     23
     24        * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h: Added.
     25        * TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.mm: Added.
     26        (+[ParserYieldTokenTestWebView webView]):
     27        (-[ParserYieldTokenTestWebView bundle]):
     28        (-[ParserYieldTokenTestWebView schemeHandler]):
     29        (-[ParserYieldTokenTestWebView didFinishDocumentLoad]):
     30        (-[ParserYieldTokenTestWebView didFinishLoad]):
     31        (waitForDelay):
     32        (TEST):
     33        * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h: Added.
     34        * TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm: Added.
     35        (-[TestURLSchemeHandler webView:startURLSchemeTask:]):
     36        (-[TestURLSchemeHandler webView:stopURLSchemeTask:]):
     37        (-[TestURLSchemeHandler setStartURLSchemeTaskHandler:]):
     38        (-[TestURLSchemeHandler startURLSchemeTaskHandler]):
     39        (-[TestURLSchemeHandler setStopURLSchemeTaskHandler:]):
     40        (-[TestURLSchemeHandler stopURLSchemeTaskHandler]):
     41
     42        Add a new test helper class to handle custom schemes via a block-based API.
     43
     44        * TestWebKitAPI/Tests/WebKitCocoa/text-with-async-script.html: Added.
     45
     46        New test HTML page that contains a deferred script element, a synchronous script element, another deferred
     47        script element, and then some text, images, and links.
     48
     49        * TestWebKitAPI/Tests/WebKitCocoa/text-with-deferred-script.html: Added.
     50
    1512018-07-17  Truitt Savell  <tsavell@apple.com>
    252
  • trunk/Tools/TestWebKitAPI/TestWebKitAPI.xcodeproj/project.pbxproj

    r233798 r233891  
    782782                F43E3BC120DADBC500A4E7ED /* fixed-nav-bar.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F43E3BC020DADB8000A4E7ED /* fixed-nav-bar.html */; };
    783783                F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */; };
     784                F44C79FF20F9E8710014478C /* ParserYieldTokenTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44C79FE20F9E8710014478C /* ParserYieldTokenTests.mm */; };
     785                F44C7A0020F9EEBF0014478C /* ParserYieldTokenPlugIn.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */; };
     786                F44C7A0520FAAE3C0014478C /* text-with-deferred-script.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F44C7A0420FAAE320014478C /* text-with-deferred-script.html */; };
    784787                F44D06451F395C26001A0E29 /* editor-state-test-harness.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F44D06441F395C0D001A0E29 /* editor-state-test-harness.html */; };
    785788                F44D06471F39627A001A0E29 /* EditorStateTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F44D06461F395C4D001A0E29 /* EditorStateTests.mm */; };
     
    812815                F4C2AB221DD6D95E00E06D5B /* enormous-video-with-sound.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */; };
    813816                F4C8797F2059D8D3009CD00B /* ScrollViewInsetTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4C8797E2059D8D3009CD00B /* ScrollViewInsetTests.mm */; };
     817                F4CD74C620FDACFA00DE3794 /* text-with-async-script.html in Copy Resources */ = {isa = PBXBuildFile; fileRef = F4CD74C520FDACF500DE3794 /* text-with-async-script.html */; };
     818                F4CD74C920FDB49600DE3794 /* TestURLSchemeHandler.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4CD74C820FDB49600DE3794 /* TestURLSchemeHandler.mm */; };
    814819                F4D4F3B61E4E2BCB00BB2767 /* DataInteractionSimulator.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4D4F3B41E4E2BCB00BB2767 /* DataInteractionSimulator.mm */; };
    815820                F4D4F3B91E4E36E400BB2767 /* DataInteractionTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4D4F3B71E4E36E400BB2767 /* DataInteractionTests.mm */; };
     
    899904                        dstSubfolderSpec = 7;
    900905                        files = (
    901                                 46AE5A3720F9066D00E0873E /* SimpleServiceWorkerRegistrations-3.sqlite3 in Copy Resources */,
    902906                                1A9E52C913E65EF4006917F5 /* 18-characters.html in Copy Resources */,
    903907                                379028B914FAC24C007E6B43 /* acceptsFirstMouse.html in Copy Resources */,
     
    11261130                                51E5C7021919C3B200D8B3E1 /* simple2.html in Copy Resources */,
    11271131                                51E5C7031919C3B200D8B3E1 /* simple3.html in Copy Resources */,
     1132                                46AE5A3720F9066D00E0873E /* SimpleServiceWorkerRegistrations-3.sqlite3 in Copy Resources */,
    11281133                                F4F405BD1D4C0D1C007A9707 /* skinny-autoplaying-video-with-audio.html in Copy Resources */,
    11291134                                C01A23F21266156700C9ED55 /* spacebar-scrolling.html in Copy Resources */,
     
    11391144                                7AE9E5091AE5AE8B00CF874B /* test.pdf in Copy Resources */,
    11401145                                2E9896151D8F093800739892 /* text-and-password-inputs.html in Copy Resources */,
     1146                                F4CD74C620FDACFA00DE3794 /* text-with-async-script.html in Copy Resources */,
     1147                                F44C7A0520FAAE3C0014478C /* text-with-deferred-script.html in Copy Resources */,
    11411148                                F41AB9AA1EF4696B0083FA08 /* textarea-to-input.html in Copy Resources */,
    11421149                                F4451C761EB8FD890020C5DA /* two-paragraph-contenteditable.html in Copy Resources */,
     
    19771984                F43E3BC020DADB8000A4E7ED /* fixed-nav-bar.html */ = {isa = PBXFileReference; lastKnownFileType = text.html; path = "fixed-nav-bar.html"; sourceTree = "<group>"; };
    19781985                F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "two-paragraph-contenteditable.html"; sourceTree = "<group>"; };
     1986                F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ParserYieldTokenPlugIn.mm; sourceTree = "<group>"; };
     1987                F44C79FD20F9E8710014478C /* ParserYieldTokenTests.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ParserYieldTokenTests.h; sourceTree = "<group>"; };
     1988                F44C79FE20F9E8710014478C /* ParserYieldTokenTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ParserYieldTokenTests.mm; sourceTree = "<group>"; };
     1989                F44C7A0420FAAE320014478C /* text-with-deferred-script.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "text-with-deferred-script.html"; sourceTree = "<group>"; };
    19791990                F44D06441F395C0D001A0E29 /* editor-state-test-harness.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "editor-state-test-harness.html"; sourceTree = "<group>"; };
    19801991                F44D06461F395C4D001A0E29 /* EditorStateTests.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = EditorStateTests.mm; sourceTree = "<group>"; };
     
    20112022                F4C2AB211DD6D94100E06D5B /* enormous-video-with-sound.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "enormous-video-with-sound.html"; sourceTree = "<group>"; };
    20122023                F4C8797E2059D8D3009CD00B /* ScrollViewInsetTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = ScrollViewInsetTests.mm; sourceTree = "<group>"; };
     2024                F4CD74C520FDACF500DE3794 /* text-with-async-script.html */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.html; path = "text-with-async-script.html"; sourceTree = "<group>"; };
     2025                F4CD74C720FDB49600DE3794 /* TestURLSchemeHandler.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestURLSchemeHandler.h; sourceTree = "<group>"; };
     2026                F4CD74C820FDB49600DE3794 /* TestURLSchemeHandler.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = TestURLSchemeHandler.mm; sourceTree = "<group>"; };
    20132027                F4D4F3B41E4E2BCB00BB2767 /* DataInteractionSimulator.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = DataInteractionSimulator.mm; sourceTree = "<group>"; };
    20142028                F4D4F3B51E4E2BCB00BB2767 /* DataInteractionSimulator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DataInteractionSimulator.h; sourceTree = "<group>"; };
     
    22752289                                CEA6CF2219CCF5BD0064F5A7 /* OpenAndCloseWindow.mm */,
    22762290                                CEBCA12E1E3A660100C73293 /* OverrideContentSecurityPolicy.mm */,
     2291                                F44C79FB20F9E50C0014478C /* ParserYieldTokenPlugIn.mm */,
     2292                                F44C79FD20F9E8710014478C /* ParserYieldTokenTests.h */,
     2293                                F44C79FE20F9E8710014478C /* ParserYieldTokenTests.mm */,
    22772294                                9BCB7C2620130600003E7C0C /* PasteHTML.mm */,
    22782295                                9BDCCD851F7D0B0700009A18 /* PasteImage.mm */,
     
    23032320                                515BE1701D428BD100DD7C68 /* StoreBlobThenDelete.mm */,
    23042321                                1C734B5220788C4800F430EA /* SystemColors.mm */,
     2322                                F4CD74C720FDB49600DE3794 /* TestURLSchemeHandler.h */,
     2323                                F4CD74C820FDB49600DE3794 /* TestURLSchemeHandler.mm */,
    23052324                                5CB40B4D1F4B98BE007DC7B9 /* UIDelegate.mm */,
    23062325                                7CC3E1FA197E234100BE6252 /* UserContentController.mm */,
     
    26442663                                9BD6D39E1F7B201E00BD4962 /* sunset-in-cupertino-600px.jpg */,
    26452664                                2E9896141D8F092B00739892 /* text-and-password-inputs.html */,
     2665                                F4CD74C520FDACF500DE3794 /* text-with-async-script.html */,
     2666                                F44C7A0420FAAE320014478C /* text-with-deferred-script.html */,
    26462667                                F41AB9951EF4692C0083FA08 /* textarea-to-input.html */,
    26472668                                F4451C751EB8FD7C0020C5DA /* two-paragraph-contenteditable.html */,
     
    37603781                                7CCE7F091A411AE600447C4C /* ParentFrame.cpp in Sources */,
    37613782                                7C83E0511D0A641800FEBCF3 /* ParsedContentRange.cpp in Sources */,
     3783                                F44C79FF20F9E8710014478C /* ParserYieldTokenTests.mm in Sources */,
    37623784                                7CCE7F0A1A411AE600447C4C /* PasteboardNotifications.mm in Sources */,
    37633785                                9BCB7C2820130600003E7C0C /* PasteHTML.mm in Sources */,
     
    38433865                                A14FC5901B8AE36F00D107EB /* TestProtocol.mm in Sources */,
    38443866                                7CCE7EAE1A411A3400447C4C /* TestsController.cpp in Sources */,
     3867                                F4CD74C920FDB49600DE3794 /* TestURLSchemeHandler.mm in Sources */,
    38453868                                2EFF06D41D8AEDBB0004BB30 /* TestWKWebView.mm in Sources */,
    38463869                                F4517B672054C49500C26721 /* TestWKWebViewController.mm in Sources */,
     
    39673990                                5CB5B3C21FFC55CF00C27BB0 /* FrameHandleSerialization.mm in Sources */,
    39683991                                79C5D431209D768300F1E7CA /* InjectedBundleNodeHandleIsTextField.mm in Sources */,
     3992                                F44C7A0020F9EEBF0014478C /* ParserYieldTokenPlugIn.mm in Sources */,
    39693993                                A13EBBAB1B87434600097110 /* PlatformUtilitiesCocoa.mm in Sources */,
    39703994                                1A4F81CF1BDFFD53004E672E /* RemoteObjectRegistryPlugIn.mm in Sources */,
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/ParserYieldTokenTests.h

    r233890 r233891  
    11/*
    2  * Copyright (C) 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #import <WebKit/WKFoundation.h>
     26#pragma once
    2727
    28 #if WK_API_ENABLED
    29 
    30 #import <WebKit/WKDOMNode.h>
    31 
    32 @class WKDOMElement;
    33 @class WKDOMText;
    34 
    35 WK_CLASS_AVAILABLE(macosx(10.10), ios(8.0))
    36 @interface WKDOMDocument : WKDOMNode
    37 
    38 - (WKDOMElement *)createElement:(NSString *)tagName;
    39 - (WKDOMText *)createTextNode:(NSString *)data;
    40 - (WKDOMNode *)createDocumentFragmentWithMarkupString:(NSString *)markupString baseURL:(NSURL *)baseURL WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
    41 - (WKDOMNode *)createDocumentFragmentWithText:(NSString *)text WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
    42 
    43 @property(readonly) WKDOMElement *body;
    44 
     28@protocol ParserYieldTokenTestRunner <NSObject>
     29- (void)didFinishDocumentLoad;
     30- (void)didFinishLoad;
    4531@end
    4632
    47 #endif // WK_API_ENABLED
     33@protocol ParserYieldTokenTestBundle <NSObject>
     34- (void)takeDocumentParserTokenAfterCommittingLoad;
     35- (void)releaseDocumentParserToken;
     36@end
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.h

    r233890 r233891  
    11/*
    2  * Copyright (C) 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #import <WebKit/WKFoundation.h>
     26#pragma once
     27
     28#import <WebKit/WebKit.h>
    2729
    2830#if WK_API_ENABLED
    2931
    30 #import <WebKit/WKDOMNode.h>
     32@interface TestURLSchemeHandler : NSObject <WKURLSchemeHandler>
    3133
    32 @class WKDOMElement;
    33 @class WKDOMText;
    34 
    35 WK_CLASS_AVAILABLE(macosx(10.10), ios(8.0))
    36 @interface WKDOMDocument : WKDOMNode
    37 
    38 - (WKDOMElement *)createElement:(NSString *)tagName;
    39 - (WKDOMText *)createTextNode:(NSString *)data;
    40 - (WKDOMNode *)createDocumentFragmentWithMarkupString:(NSString *)markupString baseURL:(NSURL *)baseURL WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
    41 - (WKDOMNode *)createDocumentFragmentWithText:(NSString *)text WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
    42 
    43 @property(readonly) WKDOMElement *body;
     34@property (nonatomic, copy) void (^startURLSchemeTaskHandler)(WKWebView *, id <WKURLSchemeTask>);
     35@property (nonatomic, copy) void (^stopURLSchemeTaskHandler)(WKWebView *, id <WKURLSchemeTask>);
    4436
    4537@end
  • trunk/Tools/TestWebKitAPI/Tests/WebKitCocoa/TestURLSchemeHandler.mm

    r233890 r233891  
    11/*
    2  * Copyright (C) 2012 Apple Inc. All rights reserved.
     2 * Copyright (C) 2018 Apple Inc. All rights reserved.
    33 *
    44 * Redistribution and use in source and binary forms, with or without
     
    2424 */
    2525
    26 #import <WebKit/WKFoundation.h>
     26#include "config.h"
     27#include "TestURLSchemeHandler.h"
     28
     29#import <wtf/BlockPtr.h>
    2730
    2831#if WK_API_ENABLED
    2932
    30 #import <WebKit/WKDOMNode.h>
     33@implementation TestURLSchemeHandler {
     34    BlockPtr<void(WKWebView *, id <WKURLSchemeTask>)> _startURLSchemeTaskHandler;
     35    BlockPtr<void(WKWebView *, id <WKURLSchemeTask>)> _stopURLSchemeTaskHandler;
     36}
    3137
    32 @class WKDOMElement;
    33 @class WKDOMText;
     38- (void)webView:(WKWebView *)webView startURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
     39{
     40    if (_startURLSchemeTaskHandler)
     41        _startURLSchemeTaskHandler(webView, urlSchemeTask);
     42}
    3443
    35 WK_CLASS_AVAILABLE(macosx(10.10), ios(8.0))
    36 @interface WKDOMDocument : WKDOMNode
     44- (void)webView:(WKWebView *)webView stopURLSchemeTask:(id <WKURLSchemeTask>)urlSchemeTask
     45{
     46    if (_stopURLSchemeTaskHandler)
     47        _stopURLSchemeTaskHandler(webView, urlSchemeTask);
     48}
    3749
    38 - (WKDOMElement *)createElement:(NSString *)tagName;
    39 - (WKDOMText *)createTextNode:(NSString *)data;
    40 - (WKDOMNode *)createDocumentFragmentWithMarkupString:(NSString *)markupString baseURL:(NSURL *)baseURL WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
    41 - (WKDOMNode *)createDocumentFragmentWithText:(NSString *)text WK_API_AVAILABLE(macosx(10.13.4), ios(11.3));
     50- (void)setStartURLSchemeTaskHandler:(void (^)(WKWebView *, id <WKURLSchemeTask>))block
     51{
     52    _startURLSchemeTaskHandler = makeBlockPtr(block);
     53}
    4254
    43 @property(readonly) WKDOMElement *body;
     55- (void (^)(WKWebView *, id <WKURLSchemeTask>))startURLSchemeTaskHandler
     56{
     57    return _startURLSchemeTaskHandler.get();
     58}
     59
     60- (void)setStopURLSchemeTaskHandler:(void (^)(WKWebView *, id <WKURLSchemeTask>))block
     61{
     62    _startURLSchemeTaskHandler = makeBlockPtr(block);
     63}
     64
     65- (void (^)(WKWebView *, id <WKURLSchemeTask>))stopURLSchemeTaskHandler
     66{
     67    return _stopURLSchemeTaskHandler.get();
     68}
    4469
    4570@end
Note: See TracChangeset for help on using the changeset viewer.