| Index: Source/core/html/HTMLImport.cpp
|
| diff --git a/Source/core/html/HTMLImport.cpp b/Source/core/html/HTMLImport.cpp
|
| index abc6da56420b4719149bc322d4037536783c9481..fe07e0f196dde5d27b0d9e88bfa8b9c47aae34d9 100644
|
| --- a/Source/core/html/HTMLImport.cpp
|
| +++ b/Source/core/html/HTMLImport.cpp
|
| @@ -32,6 +32,7 @@
|
| #include "core/html/HTMLImport.h"
|
|
|
| #include "core/dom/Document.h"
|
| +#include "core/html/HTMLImportStateResolver.h"
|
|
|
| namespace WebCore {
|
|
|
| @@ -52,161 +53,102 @@ HTMLImportsController* HTMLImport::controller()
|
|
|
| void HTMLImport::appendChild(HTMLImport* child)
|
| {
|
| - if (isBlockedFromRunningScript())
|
| - child->blockFromRunningScript();
|
| TreeNode<HTMLImport>::appendChild(child);
|
| +
|
| + // This prevents HTML parser from going beyond the
|
| + // blockage line before the precise state is computed by recalcState().
|
| if (child->isCreatedByParser())
|
| - blockPredecessorsOf(child);
|
| -}
|
| + forceBlock();
|
|
|
| -bool HTMLImport::isBlockedFromCreatingDocument() const
|
| -{
|
| - if (hasLoader())
|
| - return false;
|
| - return previous() && previous()->isBlockingFollowersFromCreatingDocument();
|
| + stateWillChange();
|
| }
|
|
|
| -bool HTMLImport::isBlockedFromRunningScriptByPredecessors() const
|
| +void HTMLImport::stateDidChange()
|
| {
|
| - HTMLImport* parent = this->parent();
|
| - if (!parent)
|
| - return false;
|
| -
|
| - for (HTMLImport* sibling = parent->firstChild(); sibling; sibling = sibling->next()) {
|
| - if (sibling == this)
|
| - break;
|
| - if (sibling->isBlockingFollowersFromRunningScript())
|
| - return true;
|
| + if (!isStateBlockedFromRunningScript()) {
|
| + if (Document* document = this->document())
|
| + document->didLoadAllImports();
|
| }
|
| -
|
| - return false;
|
| -}
|
| -
|
| -void HTMLImport::waitLoaderOrChildren()
|
| -{
|
| - if (WaitingLoaderOrChildren < m_state)
|
| - m_state = WaitingLoaderOrChildren;
|
| }
|
|
|
| -void HTMLImport::blockFromRunningScript()
|
| +void HTMLImport::recalcState()
|
| {
|
| - if (BlockedFromRunningScript < m_state)
|
| - m_state = BlockedFromRunningScript;
|
| + ASSERT(!isStateCacheValid());
|
| + m_cachedState = HTMLImportStateResolver(this).resolve();
|
| }
|
|
|
| -void HTMLImport::becomeReady()
|
| +void HTMLImport::forceBlock()
|
| {
|
| - if (!isBlocked())
|
| - return;
|
| - m_state = Ready;
|
| - didBecomeReady();
|
| + ASSERT(m_cachedState != Ready);
|
| + m_cachedState = BlockedFromCreatingDocument;
|
| }
|
|
|
| -void HTMLImport::unblockFromRunningScript()
|
| +void HTMLImport::stateWillChange()
|
| {
|
| - if (!isBlockedFromRunningScript())
|
| - return;
|
| - m_state = WaitingLoaderOrChildren;
|
| - didUnblockFromRunningScript();
|
| + root()->scheduleRecalcState();
|
| }
|
|
|
| -void HTMLImport::didUnblockFromRunningScript()
|
| +void HTMLImport::recalcTreeState(HTMLImport* root)
|
| {
|
| - ASSERT(!isBlockedFromCreatingDocument());
|
| - ASSERT(!isBlockedFromRunningScript());
|
| - if (Document* document = this->document())
|
| - document->didLoadAllImports();
|
| -}
|
| + ASSERT(root == root->root());
|
|
|
| -void HTMLImport::didBecomeReady()
|
| -{
|
| - ASSERT(isDone());
|
| -}
|
| + HashMap<HTMLImport*, State> snapshot;
|
| + Vector<HTMLImport*> updated;
|
|
|
| -void HTMLImport::didUnblockFromCreatingDocument()
|
| -{
|
| - ASSERT(!isBlockedFromCreatingDocument());
|
| -}
|
| + for (HTMLImport* i = root; i; i = traverseNext(i)) {
|
| + snapshot.add(i, i->state());
|
| + i->invalidateCachedState();
|
| + }
|
|
|
| -void HTMLImport::loaderWasResolved()
|
| -{
|
| - unblockFromRunningScript();
|
| -}
|
| + // The post-visit DFS order matters here because
|
| + // HTMLImportStateResolver in recalcState() Depends on
|
| + // |m_cachedState| of its children and precedents of ancestors.
|
| + // Accidental cycle dependency of state computation is prevented
|
| + // by invalidateCachedState() and isStateCacheValid() check.
|
| + for (HTMLImport* i = traverseFirstPostOrder(root); i; i = traverseNextPostOrder(i)) {
|
| + i->recalcState();
|
| +
|
| + State newState = i->state();
|
| + State oldState = snapshot.get(i);
|
| + // Once the state reaches Ready, it shouldn't go back.
|
| + ASSERT(oldState != Ready || oldState <= newState);
|
| + if (newState != oldState)
|
| + updated.append(i);
|
| + }
|
|
|
| -void HTMLImport::loaderDidFinish()
|
| -{
|
| - if (m_state == WaitingLoaderOrChildren)
|
| - becomeReady();
|
| - root()->blockerGone();
|
| + for (size_t i = 0; i < updated.size(); ++i)
|
| + updated[i]->stateDidChange();
|
| }
|
|
|
| -inline bool HTMLImport::isBlockingFollowersFromRunningScript() const
|
| +bool HTMLImport::isMaster(Document* document)
|
| {
|
| - if (!isCreatedByParser())
|
| - return false;
|
| - if (isBlockedFromRunningScript())
|
| + if (!document->import())
|
| return true;
|
| - // Blocking here can result dead lock if the node doesn't own loader and has shared loader.
|
| - // Because the shared loader can point its ascendant and forms a cycle.
|
| - if (!ownsLoader())
|
| - return false;
|
| - return !isDone();
|
| -}
|
| -
|
| -inline bool HTMLImport::isBlockingFollowersFromCreatingDocument() const
|
| -{
|
| - return !isDone();
|
| -}
|
| -
|
| -bool HTMLImport::unblock(HTMLImport* import)
|
| -{
|
| - ASSERT(!import->isBlockedFromRunningScriptByPredecessors());
|
| -
|
| - if (import->isBlockedFromCreatingDocument())
|
| - return false;
|
| - import->didUnblockFromCreatingDocument();
|
| -
|
| - for (HTMLImport* child = import->firstChild(); child; child = child->next()) {
|
| - if (!unblock(child))
|
| - return false;
|
| - }
|
| -
|
| - import->unblockFromRunningScript();
|
| - if (import->isDone())
|
| - import->becomeReady();
|
| -
|
| - return !import->isBlockingFollowersFromRunningScript();
|
| + return (document->import()->master() == document);
|
| }
|
|
|
| -void HTMLImport::block(HTMLImport* import)
|
| +#if !defined(NDEBUG)
|
| +void HTMLImport::show()
|
| {
|
| - for (HTMLImport* child = import; child; child = traverseNext(child, import))
|
| - child->blockFromRunningScript();
|
| + root()->showTree(this, 0);
|
| }
|
|
|
| -void HTMLImport::blockPredecessorsOf(HTMLImport* child)
|
| +void HTMLImport::showTree(HTMLImport* highlight, unsigned depth)
|
| {
|
| - ASSERT(child->parent() == this);
|
| -
|
| - for (HTMLImport* sibling = lastChild(); sibling; sibling = sibling->previous()) {
|
| - if (sibling == child)
|
| - break;
|
| - HTMLImport::block(sibling);
|
| - }
|
| + for (unsigned i = 0; i < depth*4; ++i)
|
| + fprintf(stderr, " ");
|
|
|
| - this->blockFromRunningScript();
|
| -
|
| - if (HTMLImport* parent = this->parent()) {
|
| - if (isCreatedByParser())
|
| - parent->blockPredecessorsOf(this);
|
| - }
|
| + fprintf(stderr, "%s", this == highlight ? "*" : " ");
|
| + showThis();
|
| + fprintf(stderr, "\n");
|
| + for (HTMLImport* child = firstChild(); child; child = child->next())
|
| + child->showTree(highlight, depth + 1);
|
| }
|
|
|
| -bool HTMLImport::isMaster(Document* document)
|
| +void HTMLImport::showThis()
|
| {
|
| - if (!document->import())
|
| - return true;
|
| - return (document->import()->master() == document);
|
| + fprintf(stderr, "%p state=%d", this, m_cachedState);
|
| }
|
| +#endif
|
|
|
| } // namespace WebCore
|
|
|