Skip to content
Permalink
Browse files
2010-09-06 Tony Gentilcore <tonyg@chromium.org>
        Reviewed by Adam Barth.

        Implement HTML5 definition of document.readyState
        https://bugs.webkit.org/show_bug.cgi?id=45119

        * fast/dom/Document/readystate-expected.txt: Added.
        * fast/dom/Document/readystate.html: Added. Reads readyState inline script, external script, deferred script, DOMContentLoaded, onload, and dynamic post-onload script.
2010-09-06  Tony Gentilcore  <tonyg@chromium.org>

        Reviewed by Adam Barth.

        Implement HTML5 definition of document.readyState
        https://bugs.webkit.org/show_bug.cgi?id=45119

        The legacy behavior was "loading" -> "loaded" -> "complete". The new
        HTML5 behavior is "loading" -> "interactive" -> "complete". There is
        some potential for this to cause compat problems if for instance a
        page expects readyState to be "loaded" during the DOMContentLoaded event.

        Test: fast/dom/Document/readystate.html

        * dom/Document.cpp:
        (WebCore::Document::Document): Initial value is Complete because according to http://www.whatwg.org/specs/web-apps/current-work/#dom-document-readystate,
        when a Document is created the initial value is "complete" unless it has a parser associated with it, in which case it is "loading".
        So the ctor starts it Complete, and when the parser is created it is flipped to Loading.
        (WebCore::Document::readyState):
        (WebCore::Document::setReadyState):
        (WebCore::Document::implicitOpen):
        (WebCore::Document::finishedParsing): Ensure that XML and HTML parser have transition to Stopping state.
        * dom/Document.h:
        * dom/DocumentParser.cpp:
        (WebCore::DocumentParser::prepareToStopParsing): Previously this was being called when parsing had stopped.
        It is better to ensure it is only called while parsing.
        * dom/XMLDocumentParser.cpp:
        (WebCore::XMLDocumentParser::end): Transition to stopping before calling document finishedParsiong().
        * html/parser/HTMLDocumentParser.cpp:
        (WebCore::HTMLDocumentParser::prepareToStopParsing): Set state to interactive before running deferred scripts.
        This method is also called when parsing fragments, so we need to ensure it isn't done in that case.
        (WebCore::HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd): Added. Break out this part s that notifyFinished doesn't go through
        the additional steps of pumping tokenizer, setting the state, etc.
        (WebCore::HTMLDocumentParser::notifyFinished): Now that prepareToStopParsing is split up, we must protect. It also makes sense to add a couple of ASSERTs.
        * loader/FrameLoader.cpp:
        (WebCore::FrameLoader::stopLoading): It looks like an aborted load should never transition to "complete" according the HTML5. I've left the legacy behavior for now though.
        (WebCore::FrameLoader::checkCompleted): The FrameLoader now sets the state on the Document instead of the Document polling the FrameLoader.

Canonical link: https://commits.webkit.org/57599@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@66841 268f45cc-cd09-0410-ab3c-d52691b4dbfc
  • Loading branch information
tonygentilcore committed Sep 6, 2010
1 parent 0ef9fdd commit fc85d2516e3c358d128a2c4ac181703ca5eba1b9
Showing 11 changed files with 154 additions and 21 deletions.
@@ -1,3 +1,13 @@
2010-09-06 Tony Gentilcore <tonyg@chromium.org>

Reviewed by Adam Barth.

Implement HTML5 definition of document.readyState
https://bugs.webkit.org/show_bug.cgi?id=45119

* fast/dom/Document/readystate-expected.txt: Added.
* fast/dom/Document/readystate.html: Added. Reads readyState inline script, external script, deferred script, DOMContentLoaded, onload, and dynamic post-onload script.

2010-09-06 Shane Stephens <shanestephens@google.com>

Reviewed by Dimitri Glazkov.
@@ -0,0 +1,11 @@
Tests that the document's readyState is set properly at various phases during load.
PASS document.readyState is "loading"
PASS document.readyState is "loading"
PASS document.readyState is "interactive"
PASS document.readyState is "interactive"
PASS document.readyState is "complete"
PASS document.readyState is "complete"
PASS successfullyParsed is true

TEST COMPLETE

@@ -0,0 +1,30 @@
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<link rel="stylesheet" href="../../js/resources/js-test-style.css">
<script src="../../js/resources/js-test-pre.js"></script>
</head>
<body onload="shouldBeEqualToString('document.readyState', 'complete');">
Tests that the document's readyState is set properly at various phases during load.
<div id="console"></div>
<script defer src="data:text/javascript,shouldBeEqualToString('document.readyState', 'interactive');"></script>
<script src="data:text/javascript,shouldBeEqualToString('document.readyState', 'loading');"></script>
<script>
var jsTestIsAsync = true;

shouldBeEqualToString("document.readyState", "loading");

document.addEventListener("DOMContentLoaded", function() {
shouldBeEqualToString("document.readyState", "interactive");

var el = document.createElement('script');
el.src = "data:text/javascript,shouldBeEqualToString('document.readyState', 'complete');";
el.onload = function() { finishJSTest(); }
document.getElementsByTagName('head')[0].appendChild(el);
}, false);

var successfullyParsed = true;
</script>
<script src="../../js/resources/js-test-post.js"></script>
</body>
</html>
@@ -1,3 +1,41 @@
2010-09-06 Tony Gentilcore <tonyg@chromium.org>

Reviewed by Adam Barth.

Implement HTML5 definition of document.readyState
https://bugs.webkit.org/show_bug.cgi?id=45119

The legacy behavior was "loading" -> "loaded" -> "complete". The new
HTML5 behavior is "loading" -> "interactive" -> "complete". There is
some potential for this to cause compat problems if for instance a
page expects readyState to be "loaded" during the DOMContentLoaded event.

Test: fast/dom/Document/readystate.html

* dom/Document.cpp:
(WebCore::Document::Document): Initial value is Complete because according to http://www.whatwg.org/specs/web-apps/current-work/#dom-document-readystate,
when a Document is created the initial value is "complete" unless it has a parser associated with it, in which case it is "loading".
So the ctor starts it Complete, and when the parser is created it is flipped to Loading.
(WebCore::Document::readyState):
(WebCore::Document::setReadyState):
(WebCore::Document::implicitOpen):
(WebCore::Document::finishedParsing): Ensure that XML and HTML parser have transition to Stopping state.
* dom/Document.h:
* dom/DocumentParser.cpp:
(WebCore::DocumentParser::prepareToStopParsing): Previously this was being called when parsing had stopped.
It is better to ensure it is only called while parsing.
* dom/XMLDocumentParser.cpp:
(WebCore::XMLDocumentParser::end): Transition to stopping before calling document finishedParsiong().
* html/parser/HTMLDocumentParser.cpp:
(WebCore::HTMLDocumentParser::prepareToStopParsing): Set state to interactive before running deferred scripts.
This method is also called when parsing fragments, so we need to ensure it isn't done in that case.
(WebCore::HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd): Added. Break out this part s that notifyFinished doesn't go through
the additional steps of pumping tokenizer, setting the state, etc.
(WebCore::HTMLDocumentParser::notifyFinished): Now that prepareToStopParsing is split up, we must protect. It also makes sense to add a couple of ASSERTs.
* loader/FrameLoader.cpp:
(WebCore::FrameLoader::stopLoading): It looks like an aborted load should never transition to "complete" according the HTML5. I've left the legacy behavior for now though.
(WebCore::FrameLoader::checkCompleted): The FrameLoader now sets the state on the Document instead of the Document polling the FrameLoader.

2010-09-06 Anton Muhin <antonm@chromium.org>

Reviewed by Adam Barth.
@@ -357,6 +357,7 @@ Document::Document(Frame* frame, const KURL& url, bool isXHTML, bool isHTML)
, m_compatibilityModeLocked(false)
, m_domTreeVersion(0)
, m_styleSheets(StyleSheetList::create(this))
, m_readyState(Complete)
, m_styleRecalcTimer(this, &Document::styleRecalcTimerFired)
, m_pendingStyleRecalcShouldForce(false)
, m_frameElementsShouldIgnoreScrolling(false)
@@ -952,18 +953,29 @@ Element* Document::getElementById(const AtomicString& elementId) const

String Document::readyState() const
{
if (Frame* f = frame()) {
if (f->loader()->isComplete())
return "complete";
if (parsing())
return "loading";
return "loaded";
// FIXME: What does "interactive" mean?
// FIXME: Missing support for "uninitialized".
DEFINE_STATIC_LOCAL(const String, loading, ("loading"));
DEFINE_STATIC_LOCAL(const String, interactive, ("interactive"));
DEFINE_STATIC_LOCAL(const String, complete, ("complete"));

switch (m_readyState) {
case Loading:
return loading;
case Interactive:
return interactive;
case Complete:
return complete;
}

ASSERT_NOT_REACHED();
return String();
}

void Document::setReadyState(ReadyState readyState)
{
// FIXME: Fire the readystatechange event on this Document.
m_readyState = readyState;
}

String Document::encoding() const
{
if (TextResourceDecoder* d = decoder())
@@ -1869,6 +1881,7 @@ void Document::implicitOpen()

m_parser = createParser();
setParsing(true);
setReadyState(Loading);

ScriptableDocumentParser* parser = scriptableDocumentParser();
if (m_frame && parser)
@@ -4103,6 +4116,8 @@ CollectionCache* Document::nameCollectionInfo(CollectionType type, const AtomicS

void Document::finishedParsing()
{
ASSERT(!scriptableDocumentParser() || !m_parser->isParsing());
ASSERT(!scriptableDocumentParser() || m_readyState != Loading);
setParsing(false);
dispatchEvent(Event::create(eventNames().DOMContentLoadedEvent, true, false));

@@ -582,7 +582,13 @@ class Document : public ContainerNode, public ScriptExecutionContext {
bool inQuirksMode() const { return m_compatibilityMode == QuirksMode; }
bool inLimitedQuirksMode() const { return m_compatibilityMode == LimitedQuirksMode; }
bool inNoQuirksMode() const { return m_compatibilityMode == NoQuirksMode; }


enum ReadyState {
Loading,
Interactive,
Complete
};
void setReadyState(ReadyState);
void setParsing(bool);
bool parsing() const { return m_bParsing; }
int minimumLayoutDelay();
@@ -1154,6 +1160,7 @@ class Document : public ContainerNode, public ScriptExecutionContext {

bool m_loadingSheet;
bool m_visuallyOrdered;
ReadyState m_readyState;
bool m_bParsing;

Timer<Document> m_styleRecalcTimer;
@@ -52,8 +52,8 @@ void DocumentParser::startParsing()

void DocumentParser::prepareToStopParsing()
{
if (m_state == ParsingState)
m_state = StoppingState;
ASSERT(m_state == ParsingState);
m_state = StoppingState;
}

void DocumentParser::stopParsing()
@@ -234,6 +234,9 @@ void XMLDocumentParser::end()
document()->styleSelectorChanged(RecalcStyleImmediately);
}

if (isParsing())
prepareToStopParsing();
document()->setReadyState(Document::Interactive);
clearCurrentNodeStack();
document()->finishedParsing();
}
@@ -152,16 +152,20 @@ void HTMLDocumentParser::prepareToStopParsing()
// but we need to ensure it isn't deleted yet.
RefPtr<HTMLDocumentParser> protect(this);

// FIXME: Set the current document readiness to "interactive".

// NOTE: This pump should only ever emit buffered character tokens,
// so ForceSynchronous vs. AllowYield should be meaningless.
pumpTokenizerIfPossible(ForceSynchronous);

if (isStopped())
return;

DocumentParser::prepareToStopParsing();
if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing())
return;
end();

// We will not have a scriptRunner when parsing a DocumentFragment.
if (m_scriptRunner)
document()->setReadyState(Document::Interactive);

attemptToRunDeferredScriptsAndEnd();
}

bool HTMLDocumentParser::processingData() const
@@ -353,6 +357,15 @@ void HTMLDocumentParser::end()
m_treeBuilder->finished();
}

void HTMLDocumentParser::attemptToRunDeferredScriptsAndEnd()
{
ASSERT(isStopping());
ASSERT(!hasInsertionPoint());
if (m_scriptRunner && !m_scriptRunner->executeScriptsWaitingForParsing())
return;
end();
}

void HTMLDocumentParser::attemptToEnd()
{
// finish() indicates we will not receive any more data. If we are waiting on
@@ -460,17 +473,17 @@ bool HTMLDocumentParser::shouldLoadExternalScriptFromSrc(const AtomicString& src

void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
{
if (isStopping()) {
prepareToStopParsing();
return;
}

// pumpTokenizer can cause this parser to be detached from the Document,
// but we need to ensure it isn't deleted yet.
RefPtr<HTMLDocumentParser> protect(this);

ASSERT(m_scriptRunner);
ASSERT(!inScriptExecution());
if (isStopping()) {
attemptToRunDeferredScriptsAndEnd();
return;
}

ASSERT(m_treeBuilder->isPaused());
// Note: We only ever wait on one script at a time, so we always know this
// is the one we were waiting on and can un-pause the tree builder.
@@ -114,6 +114,7 @@ class HTMLDocumentParser : public ScriptableDocumentParser, HTMLScriptRunnerHos
void begin();
void attemptToEnd();
void endIfDelayed();
void attemptToRunDeferredScriptsAndEnd();
void end();

bool isScheduledForResume() const;
@@ -425,6 +425,10 @@ void FrameLoader::stopLoading(UnloadEventPolicy unloadEventPolicy, DatabasePolic
m_workingURL = KURL();

if (Document* doc = m_frame->document()) {
// FIXME: HTML5 doesn't tell us to set the state to complete when aborting, but we do anyway to match legacy behavior.
// http://www.w3.org/Bugs/Public/show_bug.cgi?id=10537
doc->setReadyState(Document::Complete);

if (DocLoader* docLoader = doc->docLoader())
cache()->loader()->cancelRequests(docLoader);

@@ -838,6 +842,7 @@ void FrameLoader::checkCompleted()

// OK, completed.
m_isComplete = true;
m_frame->document()->setReadyState(Document::Complete);

RefPtr<Frame> protect(m_frame);
checkCallImplicitClose(); // if we didn't do it before

0 comments on commit fc85d25

Please sign in to comment.