Commit f1856470 authored by jpfau@apple.com's avatar jpfau@apple.com

New XML parser: scripting support

https://bugs.webkit.org/show_bug.cgi?id=66406

Reviewed by Adam Barth.

* xml/parser/NewXMLDocumentParser.cpp:
(WebCore::NewXMLDocumentParser::NewXMLDocumentParser):
(WebCore::NewXMLDocumentParser::resumeParsing):
(WebCore::NewXMLDocumentParser::processScript):
(WebCore::NewXMLDocumentParser::append): Add support for pausing the parsing
(WebCore::NewXMLDocumentParser::finish): Add support for pausing the parsing
(WebCore::NewXMLDocumentParser::notifyFinished):
* xml/parser/NewXMLDocumentParser.h:
(WebCore::NewXMLDocumentParser::pauseParsing):
* xml/parser/XMLTreeBuilder.cpp: Add a shared function between self-closing and end tags
(WebCore::XMLTreeBuilder::closeElement): Registers scripts and pops the stack
(WebCore::XMLTreeBuilder::processStartTag):
(WebCore::XMLTreeBuilder::processEndTag):
* xml/parser/XMLTreeBuilder.h:


git-svn-id: svn://svn.chromium.org/blink/trunk@93380 bbb929c8-8fbe-4397-9dbb-9b2b20218538
parent 1196fdfc
2011-08-18 Jeffrey Pfau <jpfau@apple.com>
New XML parser: scripting support
https://bugs.webkit.org/show_bug.cgi?id=66406
Reviewed by Adam Barth.
* xml/parser/NewXMLDocumentParser.cpp:
(WebCore::NewXMLDocumentParser::NewXMLDocumentParser):
(WebCore::NewXMLDocumentParser::resumeParsing):
(WebCore::NewXMLDocumentParser::processScript):
(WebCore::NewXMLDocumentParser::append): Add support for pausing the parsing
(WebCore::NewXMLDocumentParser::finish): Add support for pausing the parsing
(WebCore::NewXMLDocumentParser::notifyFinished):
* xml/parser/NewXMLDocumentParser.h:
(WebCore::NewXMLDocumentParser::pauseParsing):
* xml/parser/XMLTreeBuilder.cpp: Add a shared function between self-closing and end tags
(WebCore::XMLTreeBuilder::closeElement): Registers scripts and pops the stack
(WebCore::XMLTreeBuilder::processStartTag):
(WebCore::XMLTreeBuilder::processEndTag):
* xml/parser/XMLTreeBuilder.h:
2011-08-18 Mark Hahnenberg <mhahnenberg@apple.com> 2011-08-18 Mark Hahnenberg <mhahnenberg@apple.com>
Move allocation in constructors into separate constructorBody() methods Move allocation in constructors into separate constructorBody() methods
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#include "NewXMLDocumentParser.h" #include "NewXMLDocumentParser.h"
#include "DocumentFragment.h" #include "DocumentFragment.h"
#include "ScriptElement.h"
#include "ScriptSourceCode.h"
#include "SegmentedString.h" #include "SegmentedString.h"
#include "XMLTreeBuilder.h" #include "XMLTreeBuilder.h"
...@@ -35,7 +37,10 @@ namespace WebCore { ...@@ -35,7 +37,10 @@ namespace WebCore {
NewXMLDocumentParser::NewXMLDocumentParser(Document* document) NewXMLDocumentParser::NewXMLDocumentParser(Document* document)
: ScriptableDocumentParser(document) : ScriptableDocumentParser(document)
, m_tokenizer(XMLTokenizer::create()) , m_tokenizer(XMLTokenizer::create())
, m_parserPaused(false)
, m_finishWasCalled(false) , m_finishWasCalled(false)
, m_pendingScript(0)
, m_scriptElement(0)
, m_treeBuilder(XMLTreeBuilder::create(this, document)) , m_treeBuilder(XMLTreeBuilder::create(this, document))
{ {
} }
...@@ -43,7 +48,10 @@ NewXMLDocumentParser::NewXMLDocumentParser(Document* document) ...@@ -43,7 +48,10 @@ NewXMLDocumentParser::NewXMLDocumentParser(Document* document)
NewXMLDocumentParser::NewXMLDocumentParser(DocumentFragment* fragment, Element* parent, FragmentScriptingPermission) NewXMLDocumentParser::NewXMLDocumentParser(DocumentFragment* fragment, Element* parent, FragmentScriptingPermission)
: ScriptableDocumentParser(fragment->document()) : ScriptableDocumentParser(fragment->document())
, m_tokenizer(XMLTokenizer::create()) , m_tokenizer(XMLTokenizer::create())
, m_parserPaused(false)
, m_finishWasCalled(false) , m_finishWasCalled(false)
, m_pendingScript(0)
, m_scriptElement(0)
, m_treeBuilder(XMLTreeBuilder::create(this, fragment, parent)) , m_treeBuilder(XMLTreeBuilder::create(this, fragment, parent))
{ {
} }
...@@ -67,6 +75,30 @@ NewXMLDocumentParser::~NewXMLDocumentParser() ...@@ -67,6 +75,30 @@ NewXMLDocumentParser::~NewXMLDocumentParser()
{ {
} }
void NewXMLDocumentParser::resumeParsing()
{
m_parserPaused = false;
append(m_input);
}
void NewXMLDocumentParser::processScript(ScriptElement* scriptElement)
{
if (scriptElement->prepareScript(TextPosition1(), ScriptElement::AllowLegacyTypeInTypeAttribute)) {
if (scriptElement->readyToBeParserExecuted())
scriptElement->executeScript(ScriptSourceCode(scriptElement->scriptContent(), document()->url(), TextPosition1()));
else if (scriptElement->willBeParserExecuted()) {
m_pendingScript = scriptElement->cachedScript();
m_scriptElement = scriptElement->element();
m_pendingScript->addClient(this);
// m_pendingScript will be 0 if script was already loaded and addClient() executed it.
if (m_pendingScript)
pauseParsing();
} else
m_scriptElement = 0;
}
}
TextPosition0 NewXMLDocumentParser::textPosition() const TextPosition0 NewXMLDocumentParser::textPosition() const
{ {
return TextPosition0(WTF::ZeroBasedNumber::fromZeroBasedInt(0), return TextPosition0(WTF::ZeroBasedNumber::fromZeroBasedInt(0),
...@@ -85,9 +117,9 @@ void NewXMLDocumentParser::insert(const SegmentedString&) ...@@ -85,9 +117,9 @@ void NewXMLDocumentParser::insert(const SegmentedString&)
void NewXMLDocumentParser::append(const SegmentedString& string) void NewXMLDocumentParser::append(const SegmentedString& string)
{ {
SegmentedString input = string; m_input = string;
while (!input.isEmpty()) { while (!m_input.isEmpty() && isParsing() && !m_parserPaused) {
if (!m_tokenizer->nextToken(input, m_token)) if (!m_tokenizer->nextToken(m_input, m_token))
continue; continue;
#ifndef NDEBUG #ifndef NDEBUG
...@@ -97,7 +129,7 @@ void NewXMLDocumentParser::append(const SegmentedString& string) ...@@ -97,7 +129,7 @@ void NewXMLDocumentParser::append(const SegmentedString& string)
AtomicXMLToken token(m_token); AtomicXMLToken token(m_token);
m_treeBuilder->processToken(token); m_treeBuilder->processToken(token);
if (m_token.type() == XMLTokenTypes::EndOfFile || !isParsing()) if (m_token.type() == XMLTokenTypes::EndOfFile)
break; break;
m_token.clear(); m_token.clear();
...@@ -108,8 +140,11 @@ void NewXMLDocumentParser::append(const SegmentedString& string) ...@@ -108,8 +140,11 @@ void NewXMLDocumentParser::append(const SegmentedString& string)
void NewXMLDocumentParser::finish() void NewXMLDocumentParser::finish()
{ {
ASSERT(!m_finishWasCalled); ASSERT(!m_finishWasCalled);
m_finishWasCalled = true;
if (m_parserPaused)
return;
m_finishWasCalled = true;
if (isParsing()) if (isParsing())
prepareToStopParsing(); prepareToStopParsing();
document()->setReadyState(Document::Interactive); document()->setReadyState(Document::Interactive);
...@@ -140,4 +175,36 @@ void NewXMLDocumentParser::executeScriptsWaitingForStylesheets() ...@@ -140,4 +175,36 @@ void NewXMLDocumentParser::executeScriptsWaitingForStylesheets()
{ {
} }
void NewXMLDocumentParser::notifyFinished(CachedResource* unusedResource)
{
ASSERT_UNUSED(unusedResource, unusedResource == m_pendingScript);
ASSERT(m_pendingScript->accessCount() > 0);
ScriptSourceCode sourceCode(m_pendingScript.get());
bool errorOccurred = m_pendingScript->errorOccurred();
bool wasCanceled = m_pendingScript->wasCanceled();
m_pendingScript->removeClient(this);
m_pendingScript = 0;
RefPtr<Element> element = m_scriptElement;
ScriptElement* scriptElement = toScriptElement(m_scriptElement.get());
m_scriptElement = 0;
ASSERT(scriptElement);
// JavaScript can detach this parser, make sure it's kept alive even if detached.
RefPtr<NewXMLDocumentParser> protect(this);
if (errorOccurred)
scriptElement->dispatchErrorEvent();
else if (!wasCanceled) {
scriptElement->executeScript(sourceCode);
scriptElement->dispatchLoadEvent();
}
if (!isDetached() && m_parserPaused)
resumeParsing();
}
} }
...@@ -27,6 +27,8 @@ ...@@ -27,6 +27,8 @@
#define NewXMLDocumentParser_h #define NewXMLDocumentParser_h
#include "CachedResourceClient.h" #include "CachedResourceClient.h"
#include "CachedResourceHandle.h"
#include "CachedScript.h"
#include "ScriptableDocumentParser.h" #include "ScriptableDocumentParser.h"
#include "XMLToken.h" #include "XMLToken.h"
#include "XMLTokenizer.h" #include "XMLTokenizer.h"
...@@ -35,11 +37,12 @@ ...@@ -35,11 +37,12 @@
namespace WebCore { namespace WebCore {
class Document;
class ContainerNode; class ContainerNode;
class Document;
class ScriptElement;
class XMLTreeBuilder; class XMLTreeBuilder;
class NewXMLDocumentParser : public ScriptableDocumentParser { class NewXMLDocumentParser : public ScriptableDocumentParser, public CachedResourceClient {
WTF_MAKE_FAST_ALLOCATED; WTF_MAKE_FAST_ALLOCATED;
public: public:
static PassRefPtr<NewXMLDocumentParser> create(Document* document) static PassRefPtr<NewXMLDocumentParser> create(Document* document)
...@@ -54,6 +57,10 @@ public: ...@@ -54,6 +57,10 @@ public:
static bool parseDocumentFragment(const String&, DocumentFragment*, Element* parent = 0, FragmentScriptingPermission = FragmentScriptingAllowed); static bool parseDocumentFragment(const String&, DocumentFragment*, Element* parent = 0, FragmentScriptingPermission = FragmentScriptingAllowed);
void pauseParsing() { m_parserPaused = true; }
void resumeParsing();
void processScript(ScriptElement*);
virtual TextPosition0 textPosition() const; virtual TextPosition0 textPosition() const;
virtual int lineNumber() const; virtual int lineNumber() const;
...@@ -64,6 +71,9 @@ public: ...@@ -64,6 +71,9 @@ public:
virtual bool isExecutingScript() const; virtual bool isExecutingScript() const;
virtual void executeScriptsWaitingForStylesheets(); virtual void executeScriptsWaitingForStylesheets();
// CachedResourceClient
virtual void notifyFinished(CachedResource*);
protected: protected:
virtual void insert(const SegmentedString&); virtual void insert(const SegmentedString&);
virtual void append(const SegmentedString&); virtual void append(const SegmentedString&);
...@@ -74,11 +84,16 @@ private: ...@@ -74,11 +84,16 @@ private:
NewXMLDocumentParser(DocumentFragment*, Element* parent, FragmentScriptingPermission); NewXMLDocumentParser(DocumentFragment*, Element* parent, FragmentScriptingPermission);
virtual ~NewXMLDocumentParser(); virtual ~NewXMLDocumentParser();
SegmentedString m_input;
OwnPtr<XMLTokenizer> m_tokenizer; OwnPtr<XMLTokenizer> m_tokenizer;
XMLToken m_token; XMLToken m_token;
bool m_parserPaused;
bool m_finishWasCalled; bool m_finishWasCalled;
CachedResourceHandle<CachedScript> m_pendingScript;
RefPtr<Element> m_scriptElement;
OwnPtr<XMLTreeBuilder> m_treeBuilder; OwnPtr<XMLTreeBuilder> m_treeBuilder;
}; };
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "config.h" #include "config.h"
#include "XMLTreeBuilder.h" #include "XMLTreeBuilder.h"
#include "CachedScript.h"
#include "CDATASection.h" #include "CDATASection.h"
#include "Comment.h" #include "Comment.h"
#include "Document.h" #include "Document.h"
...@@ -35,6 +36,8 @@ ...@@ -35,6 +36,8 @@
#include "HTMLEntitySearch.h" #include "HTMLEntitySearch.h"
#include "NewXMLDocumentParser.h" #include "NewXMLDocumentParser.h"
#include "ProcessingInstruction.h" #include "ProcessingInstruction.h"
#include "ScriptElement.h"
#include "ScriptSourceCode.h"
#include "XMLNSNames.h" #include "XMLNSNames.h"
#include "XMLNames.h" #include "XMLNames.h"
...@@ -143,6 +146,17 @@ void XMLTreeBuilder::popCurrentNode() ...@@ -143,6 +146,17 @@ void XMLTreeBuilder::popCurrentNode()
m_currentNodeStack.removeLast(); m_currentNodeStack.removeLast();
} }
void XMLTreeBuilder::closeElement(PassRefPtr<Element> element)
{
element->finishParsingChildren();
ScriptElement* scriptElement = toScriptElement(element.get());
if (scriptElement)
m_parser->processScript(scriptElement);
popCurrentNode();
}
void XMLTreeBuilder::processProcessingInstruction(const AtomicXMLToken& token) void XMLTreeBuilder::processProcessingInstruction(const AtomicXMLToken& token)
{ {
if (!failOnText()) if (!failOnText())
...@@ -230,10 +244,8 @@ void XMLTreeBuilder::processStartTag(const AtomicXMLToken& token) ...@@ -230,10 +244,8 @@ void XMLTreeBuilder::processStartTag(const AtomicXMLToken& token)
if (isFirstElement && m_document->frame()) if (isFirstElement && m_document->frame())
m_document->frame()->loader()->dispatchDocumentElementAvailable(); m_document->frame()->loader()->dispatchDocumentElementAvailable();
if (token.selfClosing()) { if (token.selfClosing())
popCurrentNode(); closeElement(newElement);
newElement->finishParsingChildren();
}
} }
void XMLTreeBuilder::processEndTag(const AtomicXMLToken& token) void XMLTreeBuilder::processEndTag(const AtomicXMLToken& token)
...@@ -245,8 +257,7 @@ void XMLTreeBuilder::processEndTag(const AtomicXMLToken& token) ...@@ -245,8 +257,7 @@ void XMLTreeBuilder::processEndTag(const AtomicXMLToken& token)
if (!node->hasTagName(QualifiedName(token.prefix(), token.name(), m_currentNodeStack.last().namespaceForPrefix(token.prefix(), m_currentNodeStack.last().namespaceURI())))) if (!node->hasTagName(QualifiedName(token.prefix(), token.name(), m_currentNodeStack.last().namespaceForPrefix(token.prefix(), m_currentNodeStack.last().namespaceURI()))))
m_parser->stopParsing(); m_parser->stopParsing();
popCurrentNode(); closeElement(toElement(node.get()));
node->finishParsingChildren();
} }
void XMLTreeBuilder::processCharacter(const AtomicXMLToken& token) void XMLTreeBuilder::processCharacter(const AtomicXMLToken& token)
......
...@@ -81,6 +81,7 @@ private: ...@@ -81,6 +81,7 @@ private:
void pushCurrentNode(const NodeStackItem&); void pushCurrentNode(const NodeStackItem&);
void popCurrentNode(); void popCurrentNode();
void closeElement(PassRefPtr<Element>);
void processProcessingInstruction(const AtomicXMLToken&); void processProcessingInstruction(const AtomicXMLToken&);
void processXMLDeclaration(const AtomicXMLToken&); void processXMLDeclaration(const AtomicXMLToken&);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment