summaryrefslogtreecommitdiffstats
path: root/Source/WebCore/html/parser
diff options
context:
space:
mode:
Diffstat (limited to 'Source/WebCore/html/parser')
-rw-r--r--Source/WebCore/html/parser/CSSPreloadScanner.cpp39
-rw-r--r--Source/WebCore/html/parser/CSSPreloadScanner.h3
-rw-r--r--Source/WebCore/html/parser/HTMLDocumentParser.cpp31
-rw-r--r--Source/WebCore/html/parser/HTMLDocumentParser.h2
-rw-r--r--Source/WebCore/html/parser/HTMLParserScheduler.h14
-rw-r--r--Source/WebCore/html/parser/HTMLScriptRunner.cpp5
-rw-r--r--Source/WebCore/html/parser/HTMLScriptRunnerHost.h4
7 files changed, 78 insertions, 20 deletions
diff --git a/Source/WebCore/html/parser/CSSPreloadScanner.cpp b/Source/WebCore/html/parser/CSSPreloadScanner.cpp
index 23364f9..3c23b9f 100644
--- a/Source/WebCore/html/parser/CSSPreloadScanner.cpp
+++ b/Source/WebCore/html/parser/CSSPreloadScanner.cpp
@@ -54,7 +54,7 @@ void CSSPreloadScanner::scan(const HTMLToken& token, bool scanningBody)
m_scanningBody = scanningBody;
const HTMLToken::DataVector& characters = token.characters();
- for (HTMLToken::DataVector::const_iterator iter = characters.begin(); iter != characters.end(); ++iter)
+ for (HTMLToken::DataVector::const_iterator iter = characters.begin(); iter != characters.end() && m_state != DoneParsingImportRules; ++iter)
tokenize(*iter);
}
@@ -64,10 +64,14 @@ inline void CSSPreloadScanner::tokenize(UChar c)
// Searching for other types of resources is probably low payoff.
switch (m_state) {
case Initial:
+ if (isHTMLSpace(c))
+ break;
if (c == '@')
m_state = RuleStart;
else if (c == '/')
m_state = MaybeComment;
+ else
+ m_state = DoneParsingImportRules;
break;
case MaybeComment:
if (c == '*')
@@ -80,10 +84,10 @@ inline void CSSPreloadScanner::tokenize(UChar c)
m_state = MaybeCommentEnd;
break;
case MaybeCommentEnd:
+ if (c == '*')
+ break;
if (c == '/')
m_state = Initial;
- else if (c == '*')
- ;
else
m_state = Comment;
break;
@@ -106,9 +110,11 @@ inline void CSSPreloadScanner::tokenize(UChar c)
break;
case AfterRule:
if (isHTMLSpace(c))
- ;
- else if (c == ';')
+ break;
+ if (c == ';')
m_state = Initial;
+ else if (c == '{')
+ m_state = DoneParsingImportRules;
else {
m_state = RuleValue;
m_ruleValue.append(c);
@@ -117,23 +123,26 @@ inline void CSSPreloadScanner::tokenize(UChar c)
case RuleValue:
if (isHTMLSpace(c))
m_state = AfterRuleValue;
- else if (c == ';') {
+ else if (c == ';')
emitRule();
- m_state = Initial;
- } else
+ else
m_ruleValue.append(c);
break;
case AfterRuleValue:
if (isHTMLSpace(c))
- ;
- else if (c == ';') {
+ break;
+ if (c == ';')
emitRule();
- m_state = Initial;
- } else {
+ else if (c == '{')
+ m_state = DoneParsingImportRules;
+ else {
// FIXME: media rules
m_state = Initial;
}
break;
+ case DoneParsingImportRules:
+ ASSERT_NOT_REACHED();
+ break;
}
}
@@ -187,7 +196,11 @@ void CSSPreloadScanner::emitRule()
String value = parseCSSStringOrURL(m_ruleValue.data(), m_ruleValue.size());
if (!value.isEmpty())
m_document->cachedResourceLoader()->preload(CachedResource::CSSStyleSheet, value, String(), m_scanningBody);
- }
+ m_state = Initial;
+ } else if (equalIgnoringCase("charset", m_rule.data(), m_rule.size()))
+ m_state = Initial;
+ else
+ m_state = DoneParsingImportRules;
m_rule.clear();
m_ruleValue.clear();
}
diff --git a/Source/WebCore/html/parser/CSSPreloadScanner.h b/Source/WebCore/html/parser/CSSPreloadScanner.h
index fae95a1..e45fa2d 100644
--- a/Source/WebCore/html/parser/CSSPreloadScanner.h
+++ b/Source/WebCore/html/parser/CSSPreloadScanner.h
@@ -53,7 +53,8 @@ private:
Rule,
AfterRule,
RuleValue,
- AfterRuleValue
+ AfterRuleValue,
+ DoneParsingImportRules,
};
inline void tokenize(UChar c);
diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.cpp b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
index 88db3c2..7519699 100644
--- a/Source/WebCore/html/parser/HTMLDocumentParser.cpp
+++ b/Source/WebCore/html/parser/HTMLDocumentParser.cpp
@@ -40,7 +40,6 @@
#include "InspectorInstrumentation.h"
#include "NestingLevelIncrementer.h"
#include "Settings.h"
-#include <wtf/CurrentTime.h>
#ifdef ANDROID_INSTRUMENT
#include "TimeCounter.h"
@@ -331,6 +330,14 @@ void HTMLDocumentParser::insert(const SegmentedString& source)
excludedLineNumberSource.setExcludeLineNumbers();
m_input.insertAtCurrentInsertionPoint(excludedLineNumberSource);
pumpTokenizerIfPossible(ForceSynchronous);
+
+ if (isWaitingForScripts()) {
+ // Check the document.write() output with a separate preload scanner as
+ // the main scanner can't deal with insertions.
+ HTMLPreloadScanner preloadScanner(document());
+ preloadScanner.appendToEnd(source);
+ preloadScanner.scan();
+ }
endIfDelayed();
}
@@ -344,9 +351,19 @@ void HTMLDocumentParser::append(const SegmentedString& source)
// but we need to ensure it isn't deleted yet.
RefPtr<HTMLDocumentParser> protect(this);
+ if (m_preloadScanner) {
+ if (m_input.current().isEmpty() && !isWaitingForScripts()) {
+ // We have parsed until the end of the current input and so are now moving ahead of the preload scanner.
+ // Clear the scanner so we know to scan starting from the current input point if we block again.
+ m_preloadScanner.clear();
+ } else {
+ m_preloadScanner->appendToEnd(source);
+ if (isWaitingForScripts())
+ m_preloadScanner->scan();
+ }
+ }
+
m_input.appendToEnd(source);
- if (m_preloadScanner)
- m_preloadScanner->appendToEnd(source);
if (inPumpSession()) {
// We've gotten data off the network in a nested write.
@@ -473,7 +490,6 @@ void HTMLDocumentParser::resumeParsingAfterScriptExecution()
ASSERT(!inScriptExecution());
ASSERT(!m_treeBuilder->isPaused());
- m_preloadScanner.clear();
pumpTokenizerIfPossible(AllowYield);
endIfDelayed();
}
@@ -491,6 +507,13 @@ void HTMLDocumentParser::stopWatchingForLoad(CachedResource* cachedScript)
{
cachedScript->removeClient(this);
}
+
+void HTMLDocumentParser::appendCurrentInputStreamToPreloadScannerAndScan()
+{
+ ASSERT(m_preloadScanner);
+ m_preloadScanner->appendToEnd(m_input.current());
+ m_preloadScanner->scan();
+}
void HTMLDocumentParser::notifyFinished(CachedResource* cachedResource)
{
diff --git a/Source/WebCore/html/parser/HTMLDocumentParser.h b/Source/WebCore/html/parser/HTMLDocumentParser.h
index a016cf3..d482a3d 100644
--- a/Source/WebCore/html/parser/HTMLDocumentParser.h
+++ b/Source/WebCore/html/parser/HTMLDocumentParser.h
@@ -109,6 +109,8 @@ private:
virtual void watchForLoad(CachedResource*);
virtual void stopWatchingForLoad(CachedResource*);
virtual HTMLInputStream& inputStream() { return m_input; }
+ virtual bool hasPreloadScanner() const { return m_preloadScanner.get(); }
+ virtual void appendCurrentInputStreamToPreloadScannerAndScan();
// CachedResourceClient
virtual void notifyFinished(CachedResource*);
diff --git a/Source/WebCore/html/parser/HTMLParserScheduler.h b/Source/WebCore/html/parser/HTMLParserScheduler.h
index 730b52b..b0e2e85 100644
--- a/Source/WebCore/html/parser/HTMLParserScheduler.h
+++ b/Source/WebCore/html/parser/HTMLParserScheduler.h
@@ -26,6 +26,8 @@
#ifndef HTMLParserScheduler_h
#define HTMLParserScheduler_h
+#include <limits.h>
+
#include "NestingLevelIncrementer.h"
#include "Timer.h"
#include <wtf/CurrentTime.h>
@@ -39,8 +41,11 @@ class PumpSession : public NestingLevelIncrementer {
public:
PumpSession(unsigned& nestingLevel)
: NestingLevelIncrementer(nestingLevel)
- , processedTokens(0)
- , startTime(currentTime())
+ // Setting processedTokens to INT_MAX causes us to check for yields
+ // after any token during any parse where yielding is allowed.
+ // At that time we'll initialize startTime.
+ , processedTokens(INT_MAX)
+ , startTime(0)
, needsYield(false)
{
}
@@ -63,6 +68,11 @@ public:
void checkForYieldBeforeToken(PumpSession& session)
{
if (session.processedTokens > m_parserChunkSize) {
+ // currentTime() can be expensive. By delaying, we avoided calling
+ // currentTime() when constructing non-yielding PumpSessions.
+ if (!session.startTime)
+ session.startTime = currentTime();
+
session.processedTokens = 0;
double elapsedTime = currentTime() - session.startTime;
if (elapsedTime > m_parserTimeLimit)
diff --git a/Source/WebCore/html/parser/HTMLScriptRunner.cpp b/Source/WebCore/html/parser/HTMLScriptRunner.cpp
index 99fff5e..7312334 100644
--- a/Source/WebCore/html/parser/HTMLScriptRunner.cpp
+++ b/Source/WebCore/html/parser/HTMLScriptRunner.cpp
@@ -169,12 +169,17 @@ bool HTMLScriptRunner::execute(PassRefPtr<Element> scriptElement, const TextPosi
ASSERT(scriptElement);
// FIXME: If scripting is disabled, always just return true;
+ bool hadPreloadScanner = m_host->hasPreloadScanner();
+
// Try to execute the script given to us.
runScript(scriptElement.get(), scriptStartPosition);
if (haveParsingBlockingScript()) {
if (m_scriptNestingLevel)
return false; // Block the parser. Unwind to the outermost HTMLScriptRunner::execute before continuing parsing.
+ // If preload scanner got created, it is missing the source after the current insertion point. Append it and scan.
+ if (!hadPreloadScanner && m_host->hasPreloadScanner())
+ m_host->appendCurrentInputStreamToPreloadScannerAndScan();
if (!executeParsingBlockingScripts())
return false; // We still have a parsing blocking script, block the parser.
}
diff --git a/Source/WebCore/html/parser/HTMLScriptRunnerHost.h b/Source/WebCore/html/parser/HTMLScriptRunnerHost.h
index 454bc6f..1f22896 100644
--- a/Source/WebCore/html/parser/HTMLScriptRunnerHost.h
+++ b/Source/WebCore/html/parser/HTMLScriptRunnerHost.h
@@ -45,6 +45,10 @@ public:
virtual void stopWatchingForLoad(CachedResource*) = 0;
virtual HTMLInputStream& inputStream() = 0;
+
+ virtual bool hasPreloadScanner() const = 0;
+ virtual void appendCurrentInputStreamToPreloadScannerAndScan() = 0;
+
};
}