diff options
Diffstat (limited to 'chromium/third_party/WebKit/Source/core/html/parser')
48 files changed, 755 insertions, 599 deletions
diff --git a/chromium/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h b/chromium/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h index 2d74f8e1930..63e8c0c86dc 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/AtomicHTMLToken.h @@ -26,6 +26,7 @@ #ifndef AtomicHTMLToken_h #define AtomicHTMLToken_h +#include "HTMLElementLookupTrie.h" #include "core/dom/Attribute.h" #include "core/html/parser/CompactHTMLToken.h" #include "core/html/parser/HTMLToken.h" @@ -124,7 +125,10 @@ public: case HTMLToken::StartTag: case HTMLToken::EndTag: { m_selfClosing = token.selfClosing(); - m_name = AtomicString(token.name()); + if (StringImpl* tagName = lookupHTMLTag(token.name().data(), token.name().size())) + m_name = AtomicString(tagName); + else + m_name = AtomicString(token.name()); initializeAttributes(token.attributes()); break; } @@ -146,10 +150,10 @@ public: ASSERT_NOT_REACHED(); break; case HTMLToken::DOCTYPE: - m_name = token.data().asString(); + m_name = token.data(); m_doctypeData = adoptPtr(new DoctypeData()); m_doctypeData->m_hasPublicIdentifier = true; - append(m_doctypeData->m_publicIdentifier, token.publicIdentifier().asString()); + append(m_doctypeData->m_publicIdentifier, token.publicIdentifier()); m_doctypeData->m_hasSystemIdentifier = true; append(m_doctypeData->m_systemIdentifier, token.systemIdentifier()); m_doctypeData->m_forceQuirks = token.doctypeForcesQuirks(); @@ -159,7 +163,7 @@ public: case HTMLToken::StartTag: m_attributes.reserveInitialCapacity(token.attributes().size()); for (Vector<CompactHTMLToken::Attribute>::const_iterator it = token.attributes().begin(); it != token.attributes().end(); ++it) { - QualifiedName name(nullAtom, it->name.asString(), nullAtom); + QualifiedName name(nullAtom, it->name, nullAtom); // FIXME: This is N^2 for the number of attributes. if (!findAttributeInVector(m_attributes, name)) m_attributes.append(Attribute(name, it->value)); @@ -167,11 +171,11 @@ public: // Fall through! case HTMLToken::EndTag: m_selfClosing = token.selfClosing(); - m_name = token.data().asString(); + m_name = token.data(); break; case HTMLToken::Character: case HTMLToken::Comment: - m_data = token.data().asString(); + m_data = token.data(); break; } } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp b/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp index 6f536082c63..05ccea8e021 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.cpp @@ -31,6 +31,7 @@ namespace WebCore { BackgroundHTMLInputStream::BackgroundHTMLInputStream() : m_firstValidCheckpointIndex(0) , m_firstValidSegmentIndex(0) + , m_totalCheckpointTokenCount(0) { } @@ -45,10 +46,11 @@ void BackgroundHTMLInputStream::close() m_current.close(); } -HTMLInputCheckpoint BackgroundHTMLInputStream::createCheckpoint() +HTMLInputCheckpoint BackgroundHTMLInputStream::createCheckpoint(size_t tokensExtractedSincePreviousCheckpoint) { HTMLInputCheckpoint checkpoint = m_checkpoints.size(); - m_checkpoints.append(Checkpoint(m_current, m_segments.size())); + m_checkpoints.append(Checkpoint(m_current, m_segments.size(), tokensExtractedSincePreviousCheckpoint)); + m_totalCheckpointTokenCount += tokensExtractedSincePreviousCheckpoint; return checkpoint; } @@ -70,6 +72,8 @@ void BackgroundHTMLInputStream::invalidateCheckpointsBefore(HTMLInputCheckpoint for (size_t i = m_firstValidCheckpointIndex; i < newFirstValidCheckpointIndex; ++i) m_checkpoints[i].clear(); m_firstValidCheckpointIndex = newFirstValidCheckpointIndex; + + updateTotalCheckpointTokenCount(); } void BackgroundHTMLInputStream::rewindTo(HTMLInputCheckpoint checkpointIndex, const String& unparsedInput) @@ -99,6 +103,16 @@ void BackgroundHTMLInputStream::rewindTo(HTMLInputCheckpoint checkpointIndex, co m_checkpoints.clear(); m_firstValidCheckpointIndex = 0; m_firstValidSegmentIndex = 0; + + updateTotalCheckpointTokenCount(); +} + +void BackgroundHTMLInputStream::updateTotalCheckpointTokenCount() +{ + m_totalCheckpointTokenCount = 0; + size_t lastCheckpointIndex = m_checkpoints.size(); + for (size_t i = 0; i < lastCheckpointIndex; ++i) + m_totalCheckpointTokenCount += m_checkpoints[i].tokensExtractedSincePreviousCheckpoint; } } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.h b/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.h index 3ffc16cba94..ba12b63e070 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLInputStream.h @@ -26,7 +26,7 @@ #ifndef BackgroundHTMLInputStream_h #define BackgroundHTMLInputStream_h -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" #include "wtf/Vector.h" #include "wtf/text/WTFString.h" @@ -46,23 +46,24 @@ public: // An HTMLInputCheckpoint is valid until the next call to rewindTo, at which // point all outstanding checkpoints are invalidated. - HTMLInputCheckpoint createCheckpoint(); + HTMLInputCheckpoint createCheckpoint(size_t tokensExtractedSincePreviousCheckpoint); void rewindTo(HTMLInputCheckpoint, const String& unparsedInput); void invalidateCheckpointsBefore(HTMLInputCheckpoint); - size_t outstandingCheckpointCount() const { return m_checkpoints.size() - m_firstValidCheckpointIndex; } + size_t totalCheckpointTokenCount() const { return m_totalCheckpointTokenCount; } private: struct Checkpoint { - Checkpoint(const SegmentedString& i, size_t n) : input(i), numberOfSegmentsAlreadyAppended(n) { } + Checkpoint(const SegmentedString& i, size_t n, size_t t) : input(i), numberOfSegmentsAlreadyAppended(n), tokensExtractedSincePreviousCheckpoint(t) { } SegmentedString input; size_t numberOfSegmentsAlreadyAppended; + size_t tokensExtractedSincePreviousCheckpoint; #ifndef NDEBUG bool isNull() const { return input.isEmpty() && !numberOfSegmentsAlreadyAppended; } #endif - void clear() { input.clear(); numberOfSegmentsAlreadyAppended = 0; } + void clear() { input.clear(); numberOfSegmentsAlreadyAppended = 0; tokensExtractedSincePreviousCheckpoint = 0;} }; SegmentedString m_current; @@ -72,6 +73,9 @@ private: // Note: These indicies may === vector.size(), in which case there are no valid checkpoints/segments at this time. size_t m_firstValidCheckpointIndex; size_t m_firstValidSegmentIndex; + size_t m_totalCheckpointTokenCount; + + void updateTotalCheckpointTokenCount(); }; } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp b/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp index 23747edd7eb..b91dafd40b9 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/BackgroundHTMLParser.cpp @@ -28,7 +28,6 @@ #include "core/html/parser/HTMLDocumentParser.h" #include "core/html/parser/HTMLParserThread.h" -#include "core/html/parser/HTMLTokenizer.h" #include "core/html/parser/XSSAuditor.h" #include "wtf/MainThread.h" #include "wtf/text/TextPosition.h" @@ -39,14 +38,14 @@ namespace WebCore { // with a fast CPU, we could end up speculatively tokenizing // the whole document, well ahead of when the main-thread actually needs it. // This is a waste of memory (and potentially time if the speculation fails). -// So we limit our outstanding speculations arbitrarily to 10. +// So we limit our outstanding tokens arbitrarily to 10,000. // Our maximal memory spent speculating will be approximately: -// outstandingCheckpointLimit * pendingTokenLimit * sizeof(CompactToken) +// (outstandingTokenLimit + pendingTokenLimit) * sizeof(CompactToken) // We use a separate low and high water mark to avoid constantly topping // off the main thread's token buffer. -// At time of writing, this is 10 * 1000 * 28 bytes = appox 280kb of memory. +// At time of writing, this is (10000 + 1000) * 28 bytes = ~308kb of memory. // These numbers have not been tuned. -static const size_t outstandingCheckpointLimit = 10; +static const size_t outstandingTokenLimit = 10000; // We limit our chucks to 1000 tokens, to make sure the main // thread is never waiting on the parser thread for tokens. @@ -69,6 +68,12 @@ static void checkThatPreloadsAreSafeToSendToAnotherThread(const PreloadRequestSt ASSERT(preloads[i]->isSafeToSendToAnotherThread()); } +static void checkThatXSSInfosAreSafeToSendToAnotherThread(const XSSInfoStream& infos) +{ + for (size_t i = 0; i < infos.size(); ++i) + ASSERT(infos[i]->isSafeToSendToAnotherThread()); +} + #endif BackgroundHTMLParser::BackgroundHTMLParser(PassRefPtr<WeakReference<BackgroundHTMLParser> > reference, PassOwnPtr<Configuration> config) @@ -139,7 +144,7 @@ void BackgroundHTMLParser::markEndOfFile() void BackgroundHTMLParser::pumpTokenizer() { // No need to start speculating until the main thread has almost caught up. - if (m_input.outstandingCheckpointCount() > outstandingCheckpointLimit) + if (m_input.totalCheckpointTokenCount() > outstandingTokenLimit) return; while (true) { @@ -171,7 +176,7 @@ void BackgroundHTMLParser::pumpTokenizer() if (!m_treeBuilderSimulator.simulate(m_pendingTokens->last(), m_tokenizer.get()) || m_pendingTokens->size() >= pendingTokenLimit) { sendTokensToMainThread(); // If we're far ahead of the main thread, yield for a bit to avoid consuming too much memory. - if (m_input.outstandingCheckpointCount() > outstandingCheckpointLimit) + if (m_input.totalCheckpointTokenCount() > outstandingTokenLimit) break; } } @@ -185,16 +190,17 @@ void BackgroundHTMLParser::sendTokensToMainThread() #ifndef NDEBUG checkThatTokensAreSafeToSendToAnotherThread(m_pendingTokens.get()); checkThatPreloadsAreSafeToSendToAnotherThread(m_pendingPreloads); + checkThatXSSInfosAreSafeToSendToAnotherThread(m_pendingXSSInfos); #endif OwnPtr<HTMLDocumentParser::ParsedChunk> chunk = adoptPtr(new HTMLDocumentParser::ParsedChunk); - chunk->tokens = m_pendingTokens.release(); chunk->preloads.swap(m_pendingPreloads); chunk->xssInfos.swap(m_pendingXSSInfos); chunk->tokenizerState = m_tokenizer->state(); chunk->treeBuilderState = m_treeBuilderSimulator.state(); - chunk->inputCheckpoint = m_input.createCheckpoint(); + chunk->inputCheckpoint = m_input.createCheckpoint(m_pendingTokens->size()); chunk->preloadScannerCheckpoint = m_preloadScanner->createCheckpoint(); + chunk->tokens = m_pendingTokens.release(); callOnMainThread(bind(&HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser, m_parser, chunk.release())); m_pendingTokens = adoptPtr(new CompactHTMLTokenStream); diff --git a/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp b/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp index af3ff09d9cc..b1eea275aaa 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.cpp @@ -29,9 +29,8 @@ #include "core/html/parser/CSSPreloadScanner.h" #include "FetchInitiatorTypeNames.h" -#include "core/html/parser/HTMLIdentifier.h" #include "core/html/parser/HTMLParserIdioms.h" -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" namespace WebCore { @@ -66,16 +65,15 @@ void CSSPreloadScanner::scan(const HTMLToken::DataVector& data, const SegmentedS scanCommon(data.data(), data.data() + data.size(), source, requests); } -void CSSPreloadScanner::scan(const HTMLIdentifier& identifier, const SegmentedString& source, PreloadRequestStream& requests) +void CSSPreloadScanner::scan(const String& tagName, const SegmentedString& source, PreloadRequestStream& requests) { - const StringImpl* data = identifier.asStringImpl(); - if (data->is8Bit()) { - const LChar* begin = data->characters8(); - scanCommon(begin, begin + data->length(), source, requests); + if (tagName.is8Bit()) { + const LChar* begin = tagName.characters8(); + scanCommon(begin, begin + tagName.length(), source, requests); return; } - const UChar* begin = data->characters16(); - scanCommon(begin, begin + data->length(), source, requests); + const UChar* begin = tagName.characters16(); + scanCommon(begin, begin + tagName.length(), source, requests); } inline void CSSPreloadScanner::tokenize(UChar c, const SegmentedString& source) diff --git a/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h b/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h index 07e3b175d0c..7161a27434e 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/CSSPreloadScanner.h @@ -45,7 +45,7 @@ public: void reset(); void scan(const HTMLToken::DataVector&, const SegmentedString&, PreloadRequestStream&); - void scan(const HTMLIdentifier&, const SegmentedString&, PreloadRequestStream&); + void scan(const String&, const SegmentedString&, PreloadRequestStream&); private: enum State { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp b/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp index 11c4f639e21..4a826e839b3 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.cpp @@ -28,13 +28,12 @@ #include "core/dom/QualifiedName.h" #include "core/html/parser/HTMLParserIdioms.h" -#include "core/html/parser/HTMLToken.h" namespace WebCore { struct SameSizeAsCompactHTMLToken { unsigned bitfields; - HTMLIdentifier data; + String data; Vector<Attribute> vector; TextPosition textPosition; }; @@ -52,10 +51,11 @@ CompactHTMLToken::CompactHTMLToken(const HTMLToken* token, const TextPosition& t ASSERT_NOT_REACHED(); break; case HTMLToken::DOCTYPE: { - m_data = HTMLIdentifier(token->name(), Likely8Bit); + m_data = attemptStaticStringCreation(token->name(), Likely8Bit); + // There is only 1 DOCTYPE token per document, so to avoid increasing the // size of CompactHTMLToken, we just use the m_attributes vector. - m_attributes.append(Attribute(HTMLIdentifier(token->publicIdentifier(), Likely8Bit), String(token->systemIdentifier()))); + m_attributes.append(Attribute(attemptStaticStringCreation(token->publicIdentifier(), Likely8Bit), String(token->systemIdentifier()))); m_doctypeForcesQuirks = token->forceQuirks(); break; } @@ -64,7 +64,7 @@ CompactHTMLToken::CompactHTMLToken(const HTMLToken* token, const TextPosition& t case HTMLToken::StartTag: m_attributes.reserveInitialCapacity(token->attributes().size()); for (Vector<HTMLToken::Attribute>::const_iterator it = token->attributes().begin(); it != token->attributes().end(); ++it) - m_attributes.append(Attribute(HTMLIdentifier(it->name, Likely8Bit), StringImpl::create8BitIfPossible(it->value))); + m_attributes.append(Attribute(attemptStaticStringCreation(it->name, Likely8Bit), StringImpl::create8BitIfPossible(it->value))); // Fall through! case HTMLToken::EndTag: m_selfClosing = token->selfClosing(); @@ -72,7 +72,7 @@ CompactHTMLToken::CompactHTMLToken(const HTMLToken* token, const TextPosition& t case HTMLToken::Comment: case HTMLToken::Character: { m_isAll8BitData = token->isAll8BitData(); - m_data = HTMLIdentifier(token->data(), token->isAll8BitData() ? Force8Bit : Force16Bit); + m_data = attemptStaticStringCreation(token->data(), token->isAll8BitData() ? Force8Bit : Force16Bit); break; } default: diff --git a/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.h b/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.h index 89ef4ca6a02..3858e03a094 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/CompactHTMLToken.h @@ -26,7 +26,6 @@ #ifndef CompactHTMLToken_h #define CompactHTMLToken_h -#include "core/html/parser/HTMLIdentifier.h" #include "core/html/parser/HTMLToken.h" #include "wtf/Vector.h" #include "wtf/text/TextPosition.h" @@ -39,13 +38,13 @@ class QualifiedName; class CompactHTMLToken { public: struct Attribute { - Attribute(const HTMLIdentifier& name, const String& value) + Attribute(const String& name, const String& value) : name(name) , value(value) { } - HTMLIdentifier name; + String name; String value; }; @@ -54,7 +53,7 @@ public: bool isSafeToSendToAnotherThread() const; HTMLToken::Type type() const { return static_cast<HTMLToken::Type>(m_type); } - const HTMLIdentifier& data() const { return m_data; } + const String& data() const { return m_data; } bool selfClosing() const { return m_selfClosing; } bool isAll8BitData() const { return m_isAll8BitData; } const Vector<Attribute>& attributes() const { return m_attributes; } @@ -63,7 +62,7 @@ public: // There is only 1 DOCTYPE token per document, so to avoid increasing the // size of CompactHTMLToken, we just use the m_attributes vector. - const HTMLIdentifier& publicIdentifier() const { return m_attributes[0].name; } + const String& publicIdentifier() const { return m_attributes[0].name; } const String& systemIdentifier() const { return m_attributes[0].value; } bool doctypeForcesQuirks() const { return m_doctypeForcesQuirks; } @@ -73,7 +72,7 @@ private: unsigned m_isAll8BitData : 1; unsigned m_doctypeForcesQuirks: 1; - HTMLIdentifier m_data; // "name", "characters", or "data" depending on m_type + String m_data; // "name", "characters", or "data" depending on m_type Vector<Attribute> m_attributes; TextPosition m_textPosition; }; diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp index 169f06711cc..96dc2484b4b 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.cpp @@ -46,8 +46,9 @@ #include "core/html/parser/HTMLToken.h" #include "core/loader/FrameLoader.h" #include "core/loader/FrameLoaderClient.h" -#include "core/page/Frame.h" -#include "core/platform/NotImplemented.h" +#include "core/frame/Frame.h" +#include "platform/NotImplemented.h" +#include "platform/text/TextBreakIterator.h" #include <limits> namespace WebCore { @@ -82,6 +83,11 @@ static bool shouldUseLengthLimit(const ContainerNode* node) && !node->hasTagName(SVGNames::scriptTag); } +static unsigned textLengthLimitForContainer(const ContainerNode* node) +{ + return shouldUseLengthLimit(node) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max(); +} + static inline bool isAllWhitespace(const String& string) { return string.isAllSpecialCharacters<isHTMLSpace<UChar> >(); @@ -93,10 +99,10 @@ static inline void insert(HTMLConstructionSiteTask& task) task.parent = toHTMLTemplateElement(task.parent.get())->content(); if (ContainerNode* parent = task.child->parentNode()) - parent->parserRemoveChild(task.child.get()); + parent->parserRemoveChild(*task.child); if (task.nextChild) - task.parent->parserInsertBefore(task.child.get(), task.nextChild.get()); + task.parent->parserInsertBefore(task.child.get(), *task.nextChild); else task.parent->parserAppendChild(task.child.get()); } @@ -113,12 +119,33 @@ static inline void executeInsertTask(HTMLConstructionSiteTask& task) task.child->finishParsingChildren(); } +static inline void executeInsertTextTask(HTMLConstructionSiteTask& task) +{ + ASSERT(task.operation == HTMLConstructionSiteTask::InsertText); + ASSERT(task.child->isTextNode()); + + // Merge text nodes into previous ones if possible: + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#insert-a-character + Text* newText = toText(task.child.get()); + Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild(); + if (previousChild && previousChild->isTextNode()) { + Text* previousText = toText(previousChild); + unsigned lengthLimit = textLengthLimitForContainer(task.parent.get()); + if (previousText->length() + newText->length() < lengthLimit) { + previousText->parserAppendData(newText->data()); + return; + } + } + + insert(task); +} + static inline void executeReparentTask(HTMLConstructionSiteTask& task) { ASSERT(task.operation == HTMLConstructionSiteTask::Reparent); if (ContainerNode* parent = task.child->parentNode()) - parent->parserRemoveChild(task.child.get()); + parent->parserRemoveChild(*task.child); task.parent->parserAppendChild(task.child); } @@ -134,16 +161,18 @@ static inline void executeTakeAllChildrenTask(HTMLConstructionSiteTask& task) { ASSERT(task.operation == HTMLConstructionSiteTask::TakeAllChildren); - task.parent->takeAllChildrenFrom(task.oldParent()); - // Notice that we don't need to manually attach the moved children - // because takeAllChildrenFrom does that work for us. + task.parent->parserTakeAllChildrenFrom(*task.oldParent()); } -static inline void executeTask(HTMLConstructionSiteTask& task) +void HTMLConstructionSite::executeTask(HTMLConstructionSiteTask& task) { + ASSERT(m_taskQueue.isEmpty()); if (task.operation == HTMLConstructionSiteTask::Insert) return executeInsertTask(task); + if (task.operation == HTMLConstructionSiteTask::InsertText) + return executeInsertTextTask(task); + // All the cases below this point are only used by the adoption agency. if (task.operation == HTMLConstructionSiteTask::InsertAlreadyParsedChild) @@ -158,6 +187,88 @@ static inline void executeTask(HTMLConstructionSiteTask& task) ASSERT_NOT_REACHED(); } +// This is only needed for TextDocuments where we might have text nodes +// approaching the default length limit (~64k) and we don't want to +// break a text node in the middle of a combining character. +static unsigned findBreakIndexBetween(const StringBuilder& string, unsigned currentPosition, unsigned proposedBreakIndex) +{ + ASSERT(currentPosition < proposedBreakIndex); + ASSERT(proposedBreakIndex <= string.length()); + // The end of the string is always a valid break. + if (proposedBreakIndex == string.length()) + return proposedBreakIndex; + + // Latin-1 does not have breakable boundaries. If we ever moved to a differnet 8-bit encoding this could be wrong. + if (string.is8Bit()) + return proposedBreakIndex; + + const UChar* breakSearchCharacters = string.characters16() + currentPosition; + // We need at least two characters look-ahead to account for UTF-16 surrogates, but can't search off the end of the buffer! + unsigned breakSearchLength = std::min(proposedBreakIndex - currentPosition + 2, string.length() - currentPosition); + NonSharedCharacterBreakIterator it(breakSearchCharacters, breakSearchLength); + + if (it.isBreak(proposedBreakIndex - currentPosition)) + return proposedBreakIndex; + + int adjustedBreakIndexInSubstring = it.preceding(proposedBreakIndex - currentPosition); + if (adjustedBreakIndexInSubstring > 0) + return currentPosition + adjustedBreakIndexInSubstring; + // We failed to find a breakable point, let the caller figure out what to do. + return 0; +} + +static String atomizeIfAllWhitespace(const String& string, WhitespaceMode whitespaceMode) +{ + // Strings composed entirely of whitespace are likely to be repeated. + // Turn them into AtomicString so we share a single string for each. + if (whitespaceMode == AllWhitespace || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(string))) + return AtomicString(string).string(); + return string; +} + +void HTMLConstructionSite::flushPendingText() +{ + if (m_pendingText.isEmpty()) + return; + + PendingText pendingText; + // Hold onto the current pending text on the stack so that queueTask doesn't recurse infinitely. + m_pendingText.swap(pendingText); + ASSERT(m_pendingText.isEmpty()); + + // Splitting text nodes into smaller chunks contradicts HTML5 spec, but is necessary + // for performance, see: https://bugs.webkit.org/show_bug.cgi?id=55898 + unsigned lengthLimit = textLengthLimitForContainer(pendingText.parent.get()); + + unsigned currentPosition = 0; + const StringBuilder& string = pendingText.stringBuilder; + while (currentPosition < string.length()) { + unsigned proposedBreakIndex = std::min(currentPosition + lengthLimit, string.length()); + unsigned breakIndex = findBreakIndexBetween(string, currentPosition, proposedBreakIndex); + ASSERT(breakIndex <= string.length()); + String substring = string.substring(currentPosition, breakIndex - currentPosition); + substring = atomizeIfAllWhitespace(substring, pendingText.whitespaceMode); + + HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertText); + task.parent = pendingText.parent; + task.nextChild = pendingText.nextChild; + task.child = Text::create(task.parent->document(), substring); + queueTask(task); + + ASSERT(breakIndex > currentPosition); + ASSERT(breakIndex - currentPosition == substring.length()); + ASSERT(toText(task.child.get())->length() == substring.length()); + currentPosition = breakIndex; + } +} + +void HTMLConstructionSite::queueTask(const HTMLConstructionSiteTask& task) +{ + flushPendingText(); + ASSERT(m_pendingText.isEmpty()); + m_taskQueue.append(task); +} + void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> prpChild, bool selfClosing) { ASSERT(scriptingContentIsAllowed(m_parserContentPolicy) || !prpChild.get()->isElementNode() || !toScriptLoaderIfPossible(toElement(prpChild.get()))); @@ -178,11 +289,13 @@ void HTMLConstructionSite::attachLater(ContainerNode* parent, PassRefPtr<Node> p task.parent = task.parent->parentNode(); ASSERT(task.parent); - m_taskQueue.append(task); + queueTask(task); } void HTMLConstructionSite::executeQueuedTasks() { + // This has no affect on pendingText, and we may have pendingText + // remaining after executing all other queued tasks. const size_t size = m_taskQueue.size(); if (!size) return; @@ -222,10 +335,20 @@ HTMLConstructionSite::HTMLConstructionSite(DocumentFragment* fragment, ParserCon HTMLConstructionSite::~HTMLConstructionSite() { + // Depending on why we're being destroyed it might be OK + // to forget queued tasks, but currently we don't expect to. + ASSERT(m_taskQueue.isEmpty()); + // Currently we assume that text will never be the last token in the + // document and that we'll always queue some additional task to cause it to flush. + ASSERT(m_pendingText.isEmpty()); } void HTMLConstructionSite::detach() { + // FIXME: We'd like to ASSERT here that we're canceling and not just discarding + // text that really should have made it into the DOM earlier, but there + // doesn't seem to be a nice way to do that. + m_pendingText.discard(); m_document = 0; m_attachmentRoot = 0; } @@ -246,7 +369,7 @@ void HTMLConstructionSite::dispatchDocumentElementAvailableIfNeeded() { ASSERT(m_document); if (m_document->frame() && !m_isParsingFragment) - m_document->frame()->loader()->dispatchDocumentElementAvailable(); + m_document->frame()->loader().dispatchDocumentElementAvailable(); } void HTMLConstructionSite::insertHTMLHtmlStartTagBeforeHTML(AtomicHTMLToken* token) @@ -392,8 +515,18 @@ void HTMLConstructionSite::setCompatibilityModeFromDoctype(const String& name, c setCompatibilityMode(Document::NoQuirksMode); } +void HTMLConstructionSite::processEndOfFile() +{ + ASSERT(currentNode()); + flush(); + openElements()->popAll(); +} + void HTMLConstructionSite::finishedParsing() { + // We shouldn't have any queued tasks but we might have pending text which we need to promote to tasks and execute. + ASSERT(m_taskQueue.isEmpty()); + flush(); m_document->finishedParsing(); } @@ -457,7 +590,7 @@ void HTMLConstructionSite::insertHTMLBodyElement(AtomicHTMLToken* token) attachLater(currentNode(), body); m_openElements.pushHTMLBodyElement(HTMLStackItem::create(body.release(), token)); if (Frame* frame = m_document->frame()) - frame->loader()->client()->dispatchWillInsertBody(); + frame->loader().client()->dispatchWillInsertBody(); } void HTMLConstructionSite::insertHTMLFormElement(AtomicHTMLToken* token, bool isDemoted) @@ -506,7 +639,7 @@ void HTMLConstructionSite::insertScriptElement(AtomicHTMLToken* token) // those flags or effects thereof. const bool parserInserted = m_parserContentPolicy != AllowScriptingContentAndDoNotMarkAlreadyStarted; const bool alreadyStarted = m_isParsingFragment && parserInserted; - RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(scriptTag, ownerDocumentForCurrentNode(), parserInserted, alreadyStarted); + RefPtr<HTMLScriptElement> element = HTMLScriptElement::create(ownerDocumentForCurrentNode(), parserInserted, alreadyStarted); setAttributes(element.get(), token, m_parserContentPolicy); if (scriptingContentIsAllowed(m_parserContentPolicy)) attachLater(currentNode(), element); @@ -525,49 +658,24 @@ void HTMLConstructionSite::insertForeignElement(AtomicHTMLToken* token, const At m_openElements.push(HTMLStackItem::create(element.release(), token, namespaceURI)); } -void HTMLConstructionSite::insertTextNode(const String& characters, WhitespaceMode whitespaceMode) +void HTMLConstructionSite::insertTextNode(const String& string, WhitespaceMode whitespaceMode) { - HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Insert); - task.parent = currentNode(); + HTMLConstructionSiteTask dummyTask(HTMLConstructionSiteTask::Insert); + dummyTask.parent = currentNode(); if (shouldFosterParent()) - findFosterSite(task); - - if (task.parent->hasTagName(templateTag)) - task.parent = toHTMLTemplateElement(task.parent.get())->content(); + findFosterSite(dummyTask); - // Strings composed entirely of whitespace are likely to be repeated. - // Turn them into AtomicString so we share a single string for each. - bool shouldUseAtomicString = whitespaceMode == AllWhitespace - || (whitespaceMode == WhitespaceUnknown && isAllWhitespace(characters)); + // FIXME: This probably doesn't need to be done both here and in insert(Task). + if (dummyTask.parent->hasTagName(templateTag)) + dummyTask.parent = toHTMLTemplateElement(dummyTask.parent.get())->content(); - unsigned currentPosition = 0; - unsigned lengthLimit = shouldUseLengthLimit(task.parent.get()) ? Text::defaultLengthLimit : std::numeric_limits<unsigned>::max(); - - // FIXME: Splitting text nodes into smaller chunks contradicts HTML5 spec, but is currently necessary - // for performance, see <https://bugs.webkit.org/show_bug.cgi?id=55898>. - - Node* previousChild = task.nextChild ? task.nextChild->previousSibling() : task.parent->lastChild(); - if (previousChild && previousChild->isTextNode()) { - // FIXME: We're only supposed to append to this text node if it - // was the last text node inserted by the parser. - currentPosition = toCharacterData(previousChild)->parserAppendData(characters, 0, lengthLimit); - } - - while (currentPosition < characters.length()) { - RefPtr<Text> textNode = Text::createWithLengthLimit(task.parent->document(), shouldUseAtomicString ? AtomicString(characters).string() : characters, currentPosition, lengthLimit); - // If we have a whole string of unbreakable characters the above could lead to an infinite loop. Exceeding the length limit is the lesser evil. - if (!textNode->length()) { - String substring = characters.substring(currentPosition); - textNode = Text::create(task.parent->document(), shouldUseAtomicString ? AtomicString(substring).string() : substring); - } - - currentPosition += textNode->length(); - ASSERT(currentPosition <= characters.length()); - task.child = textNode.release(); - - executeTask(task); - } + // Unclear when parent != case occurs. Somehow we insert text into two separate nodes while processing the same Token. + // The nextChild != dummy.nextChild case occurs whenever foster parenting happened and we hit a new text node "<table>a</table>b" + // In either case we have to flush the pending text into the task queue before making more. + if (!m_pendingText.isEmpty() && (m_pendingText.parent != dummyTask.parent || m_pendingText.nextChild != dummyTask.nextChild)) + flushPendingText(); + m_pendingText.append(dummyTask.parent, dummyTask.nextChild, string, whitespaceMode); } void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, HTMLElementStack::ElementRecord* child) @@ -575,7 +683,7 @@ void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent); task.parent = newParent->node(); task.child = child->node(); - m_taskQueue.append(task); + queueTask(task); } void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, HTMLStackItem* child) @@ -583,7 +691,7 @@ void HTMLConstructionSite::reparent(HTMLElementStack::ElementRecord* newParent, HTMLConstructionSiteTask task(HTMLConstructionSiteTask::Reparent); task.parent = newParent->node(); task.child = child->node(); - m_taskQueue.append(task); + queueTask(task); } void HTMLConstructionSite::insertAlreadyParsedChild(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* child) @@ -596,7 +704,7 @@ void HTMLConstructionSite::insertAlreadyParsedChild(HTMLStackItem* newParent, HT HTMLConstructionSiteTask task(HTMLConstructionSiteTask::InsertAlreadyParsedChild); task.parent = newParent->node(); task.child = child->node(); - m_taskQueue.append(task); + queueTask(task); } void HTMLConstructionSite::takeAllChildren(HTMLStackItem* newParent, HTMLElementStack::ElementRecord* oldParent) @@ -604,7 +712,7 @@ void HTMLConstructionSite::takeAllChildren(HTMLStackItem* newParent, HTMLElement HTMLConstructionSiteTask task(HTMLConstructionSiteTask::TakeAllChildren); task.parent = newParent->node(); task.child = oldParent->node(); - m_taskQueue.append(task); + queueTask(task); } PassRefPtr<Element> HTMLConstructionSite::createElement(AtomicHTMLToken* token, const AtomicString& namespaceURI) @@ -624,7 +732,6 @@ inline Document& HTMLConstructionSite::ownerDocumentForCurrentNode() PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* token) { - QualifiedName tagName(nullAtom, token->name(), xhtmlNamespaceURI); Document& document = ownerDocumentForCurrentNode(); // Only associate the element with the current form if we're creating the new element // in a document with a browsing context (rather than in <template> contents). @@ -632,7 +739,7 @@ PassRefPtr<Element> HTMLConstructionSite::createHTMLElement(AtomicHTMLToken* tok // FIXME: This can't use HTMLConstructionSite::createElement because we // have to pass the current form element. We should rework form association // to occur after construction to allow better code sharing here. - RefPtr<Element> element = HTMLElementFactory::createHTMLElement(tagName, &document, form, true); + RefPtr<Element> element = HTMLElementFactory::createHTMLElement(token->name(), document, form, true); setAttributes(element.get(), token, m_parserContentPolicy); ASSERT(element->isHTMLElement()); return element.release(); @@ -746,8 +853,7 @@ void HTMLConstructionSite::fosterParent(PassRefPtr<Node> node) findFosterSite(task); task.child = node; ASSERT(task.parent); - - m_taskQueue.append(task); + queueTask(task); } } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h index ba03ce72d34..d4d812eb109 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLConstructionSite.h @@ -34,13 +34,15 @@ #include "wtf/PassRefPtr.h" #include "wtf/RefPtr.h" #include "wtf/Vector.h" +#include "wtf/text/StringBuilder.h" namespace WebCore { struct HTMLConstructionSiteTask { enum Operation { Insert, - InsertAlreadyParsedChild, + InsertText, // Handles possible merging of text nodes. + InsertAlreadyParsedChild, // Insert w/o calling begin/end parsing. Reparent, TakeAllChildren, }; @@ -74,10 +76,12 @@ template<> struct VectorTraits<WebCore::HTMLConstructionSiteTask> : SimpleClassV namespace WebCore { +// Note: These are intentionally ordered so that when we concatonate +// strings and whitespaces the resulting whitespace is ws = min(ws1, ws2). enum WhitespaceMode { - AllWhitespace, + WhitespaceUnknown, NotAllWhitespace, - WhitespaceUnknown + AllWhitespace, }; class AtomicHTMLToken; @@ -93,9 +97,31 @@ public: ~HTMLConstructionSite(); void detach(); + + // executeQueuedTasks empties the queue but does not flush pending text. + // NOTE: Possible reentrancy via JavaScript execution. void executeQueuedTasks(); + // flushPendingText turns pending text into queued Text insertions, but does not execute them. + void flushPendingText(); + + // Called before every token in HTMLTreeBuilder::processToken, thus inlined: + void flush() + { + if (!hasPendingTasks()) + return; + flushPendingText(); + executeQueuedTasks(); // NOTE: Possible reentrancy via JavaScript execution. + ASSERT(!hasPendingTasks()); + } + + bool hasPendingTasks() + { + return !m_pendingText.isEmpty() || !m_taskQueue.isEmpty(); + } + void setDefaultCompatibilityMode(); + void processEndOfFile(); void finishedParsing(); void insertDoctype(AtomicHTMLToken*); @@ -195,6 +221,9 @@ private: void mergeAttributesFromTokenIntoElement(AtomicHTMLToken*, Element*); void dispatchDocumentElementAvailableIfNeeded(); + void executeTask(HTMLConstructionSiteTask&); + void queueTask(const HTMLConstructionSiteTask&); + Document* m_document; // This is the root ContainerNode to which the parser attaches all newly @@ -209,6 +238,53 @@ private: TaskQueue m_taskQueue; + struct PendingText { + PendingText() + : whitespaceMode(WhitespaceUnknown) + { + } + + void append(PassRefPtr<ContainerNode> newParent, PassRefPtr<Node> newNextChild, const String& newString, WhitespaceMode newWhitespaceMode) + { + ASSERT(!parent || parent == newParent); + parent = newParent; + ASSERT(!nextChild || nextChild == newNextChild); + nextChild = newNextChild; + stringBuilder.append(newString); + whitespaceMode = std::min(whitespaceMode, newWhitespaceMode); + } + + void swap(PendingText& other) + { + std::swap(whitespaceMode, other.whitespaceMode); + parent.swap(other.parent); + nextChild.swap(other.nextChild); + stringBuilder.swap(other.stringBuilder); + } + + void discard() + { + PendingText discardedText; + swap(discardedText); + } + + bool isEmpty() + { + // When the stringbuilder is empty, the parent and whitespace should also be "empty". + ASSERT(stringBuilder.isEmpty() == !parent); + ASSERT(!stringBuilder.isEmpty() || !nextChild); + ASSERT(!stringBuilder.isEmpty() || (whitespaceMode == WhitespaceUnknown)); + return stringBuilder.isEmpty(); + } + + RefPtr<ContainerNode> parent; + RefPtr<Node> nextChild; + StringBuilder stringBuilder; + WhitespaceMode whitespaceMode; + }; + + PendingText m_pendingText; + ParserContentPolicy m_parserContentPolicy; bool m_isParsingFragment; diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp index e377ee67132..2008ae5f0e1 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.cpp @@ -32,17 +32,13 @@ #include "core/html/HTMLDocument.h" #include "core/html/parser/AtomicHTMLToken.h" #include "core/html/parser/BackgroundHTMLParser.h" -#include "core/html/parser/CompactHTMLToken.h" -#include "core/html/parser/HTMLIdentifier.h" #include "core/html/parser/HTMLParserScheduler.h" #include "core/html/parser/HTMLParserThread.h" -#include "core/html/parser/HTMLPreloadScanner.h" #include "core/html/parser/HTMLScriptRunner.h" -#include "core/html/parser/HTMLTokenizer.h" #include "core/html/parser/HTMLTreeBuilder.h" #include "core/inspector/InspectorInstrumentation.h" -#include "core/page/Frame.h" -#include "core/platform/chromium/TraceEvent.h" +#include "core/frame/Frame.h" +#include "platform/TraceEvent.h" #include "wtf/Functional.h" namespace WebCore { @@ -288,7 +284,7 @@ bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& ses // parser to stop parsing cleanly. The problem is we're not // perpared to do that at every point where we run JavaScript. if (!isParsingFragment() - && document()->frame() && document()->frame()->navigationScheduler()->locationChangePending()) + && document()->frame() && document()->frame()->navigationScheduler().locationChangePending()) return false; if (mode == AllowYield) @@ -299,6 +295,8 @@ bool HTMLDocumentParser::canTakeNextToken(SynchronousMode mode, PumpSession& ses void HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> chunk) { + TRACE_EVENT0("webkit", "HTMLDocumentParser::didReceiveParsedChunkFromBackgroundParser"); + // alert(), runModalDialog, and the JavaScript Debugger all run nested event loops // which can cause this method to be re-entered. We detect re-entry using // hasActiveParser(), save the chunk as a speculation, and return. @@ -378,6 +376,8 @@ void HTMLDocumentParser::discardSpeculationsAndResumeFrom(PassOwnPtr<ParsedChunk void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk> popChunk) { + TRACE_EVENT0("webkit", "HTMLDocumentParser::processParsedChunkFromBackgroundParser"); + ASSERT_WITH_SECURITY_IMPLICATION(!document()->activeParserCount()); ASSERT(!isParsingFragment()); ASSERT(!isWaitingForScripts()); @@ -407,7 +407,7 @@ void HTMLDocumentParser::processParsedChunkFromBackgroundParser(PassOwnPtr<Parse ASSERT(!isWaitingForScripts()); if (!isParsingFragment() - && document()->frame() && document()->frame()->navigationScheduler()->locationChangePending()) { + && document()->frame() && document()->frame()->navigationScheduler().locationChangePending()) { // To match main-thread parser behavior (which never checks locationChangePending on the EOF path) // we peek to see if this chunk has an EOF and process it anyway. @@ -553,6 +553,12 @@ void HTMLDocumentParser::pumpTokenizer(SynchronousMode mode) if (isStopped()) return; + // There should only be PendingText left since the tree-builder always flushes + // the task queue before returning. In case that ever changes, crash. + if (mode == ForceSynchronous) + m_treeBuilder->flush(); + RELEASE_ASSERT(!isStopped()); + if (session.needsYield) m_parserScheduler->scheduleForResume(); @@ -614,6 +620,8 @@ void HTMLDocumentParser::insert(const SegmentedString& source) if (isStopped()) return; + TRACE_EVENT0("webkit", "HTMLDocumentParser::insert"); + // 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); @@ -649,8 +657,6 @@ void HTMLDocumentParser::startBackgroundParser() ASSERT(!m_haveBackgroundParser); m_haveBackgroundParser = true; - HTMLIdentifier::init(); - RefPtr<WeakReference<BackgroundHTMLParser> > reference = WeakReference<BackgroundHTMLParser>::createUnbound(); m_backgroundParser = WeakPtr<BackgroundHTMLParser>(reference); diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h index 4b3be11a9a8..40779561ad3 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLDocumentParser.h @@ -29,6 +29,7 @@ #include "core/dom/ParserContentPolicy.h" #include "core/dom/ScriptableDocumentParser.h" #include "core/fetch/ResourceClient.h" +#include "core/frame/UseCounter.h" #include "core/html/parser/BackgroundHTMLInputStream.h" #include "core/html/parser/CompactHTMLToken.h" #include "core/html/parser/HTMLInputStream.h" @@ -41,7 +42,7 @@ #include "core/html/parser/HTMLTreeBuilderSimulator.h" #include "core/html/parser/XSSAuditor.h" #include "core/html/parser/XSSAuditorDelegate.h" -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" #include "wtf/Deque.h" #include "wtf/OwnPtr.h" #include "wtf/WeakPtr.h" @@ -96,6 +97,8 @@ public: }; void didReceiveParsedChunkFromBackgroundParser(PassOwnPtr<ParsedChunk>); + UseCounter* useCounter() { return UseCounter::getFrom(contextForParsingSession()); } + protected: virtual void insert(const SegmentedString&) OVERRIDE; virtual void append(PassRefPtr<StringImpl>) OVERRIDE; diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLElementStack.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLElementStack.cpp index 1a8227c9fdc..9adfdf1612c 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLElementStack.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLElementStack.cpp @@ -34,7 +34,6 @@ #include "core/html/HTMLHtmlElement.h" #include "core/html/HTMLOptGroupElement.h" #include "core/html/HTMLTableElement.h" -#include "wtf/PassOwnPtr.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.h index 12499c76c93..ed5d7e6652e 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLEntityParser.h @@ -27,7 +27,7 @@ #ifndef HTMLEntityParser_h #define HTMLEntityParser_h -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLIdentifier.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLIdentifier.cpp deleted file mode 100644 index d12ea6a955c..00000000000 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLIdentifier.cpp +++ /dev/null @@ -1,125 +0,0 @@ -/* - * Copyright (C) 2013 Google, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "core/html/parser/HTMLIdentifier.h" - -#include "HTMLNames.h" -#include "wtf/HashMap.h" -#include "wtf/MainThread.h" -#include "wtf/text/StringHash.h" - -namespace WebCore { - -using namespace HTMLNames; - -typedef HashMap<unsigned, StringImpl*, AlreadyHashed> IdentifierTable; - -unsigned HTMLIdentifier::maxNameLength = 0; - -static IdentifierTable& identifierTable() -{ - DEFINE_STATIC_LOCAL(IdentifierTable, table, ()); - ASSERT(isMainThread() || !table.isEmpty()); - return table; -} - -#ifndef NDEBUG -bool HTMLIdentifier::isKnown(const StringImpl* string) -{ - const IdentifierTable& table = identifierTable(); - return table.contains(string->hash()); -} -#endif - -StringImpl* HTMLIdentifier::findIfKnown(const UChar* characters, unsigned length) -{ - // We don't need to try hashing if we know the string is too long. - if (length > maxNameLength) - return 0; - // computeHashAndMaskTop8Bits is the function StringImpl::hash() uses. - unsigned hash = StringHasher::computeHashAndMaskTop8Bits(characters, length); - const IdentifierTable& table = identifierTable(); - ASSERT(!table.isEmpty()); - - IdentifierTable::const_iterator it = table.find(hash); - if (it == table.end()) - return 0; - // It's possible to have hash collisions between arbitrary strings and - // known identifiers (e.g. "bvvfg" collides with "script"). - // However ASSERTs in addNames() guard against there ever being collisions - // between known identifiers. - if (!equal(it->value, characters, length)) - return 0; - return it->value; -} - -const unsigned kHTMLNamesIndexOffset = 0; -const unsigned kHTMLAttrsIndexOffset = 1000; -COMPILE_ASSERT(kHTMLAttrsIndexOffset > HTMLTagsCount, kHTMLAttrsIndexOffset_should_be_larger_than_HTMLTagsCount); - -const String& HTMLIdentifier::asString() const -{ - ASSERT(isMainThread()); - return m_string; -} - -const StringImpl* HTMLIdentifier::asStringImpl() const -{ - return m_string.impl(); -} - -void HTMLIdentifier::addNames(QualifiedName** names, unsigned namesCount, unsigned indexOffset) -{ - IdentifierTable& table = identifierTable(); - for (unsigned i = 0; i < namesCount; ++i) { - StringImpl* name = names[i]->localName().impl(); - unsigned hash = name->hash(); - IdentifierTable::AddResult addResult = table.add(hash, name); - maxNameLength = std::max(maxNameLength, name->length()); - // Ensure we're using the same hashing algorithm to get and set. - ASSERT_UNUSED(addResult, !addResult.isNewEntry || HTMLIdentifier::findIfKnown(String(name).charactersWithNullTermination().data(), name->length()) == name); - // We expect some hash collisions, but only for identical strings. - // Since all of these names are AtomicStrings pointers should be equal. - // Note: If you hit this ASSERT, then we had a hash collision among - // HTMLNames strings, and we need to re-design how we use this hash! - ASSERT_UNUSED(addResult, !addResult.isNewEntry || name == addResult.iterator->value); - } -} - -void HTMLIdentifier::init() -{ - ASSERT(isMainThread()); // Not technically necessary, but this is our current expected usage. - static bool isInitialized = false; - if (isInitialized) - return; - isInitialized = true; - - // FIXME: We should atomize small whitespace (\n, \n\n, etc.) - addNames(getHTMLTags(), HTMLTagsCount, kHTMLNamesIndexOffset); - addNames(getHTMLAttrs(), HTMLAttrsCount, kHTMLAttrsIndexOffset); -} - -} diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLIdentifier.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLIdentifier.h deleted file mode 100644 index 1aec5f7d7d7..00000000000 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLIdentifier.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (C) 2013 Google, Inc. All Rights Reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR - * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY - * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef HTMLIdentifier_h -#define HTMLIdentifier_h - -#include "wtf/text/WTFString.h" - -namespace WebCore { - -class QualifiedName; - -enum CharacterWidth { - Likely8Bit, - Force8Bit, - Force16Bit -}; - -class HTMLIdentifier { -public: - HTMLIdentifier() { } - - template<size_t inlineCapacity> - HTMLIdentifier(const Vector<UChar, inlineCapacity>& vector, CharacterWidth width) - : m_string(findIfKnown(vector.data(), vector.size())) - { - if (m_string.impl()) - return; - if (width == Likely8Bit) - m_string = StringImpl::create8BitIfPossible(vector); - else if (width == Force8Bit) - m_string = String::make8BitFrom16BitSource(vector); - else - m_string = String(vector); - } - - // asString should only be used on the main thread. - const String& asString() const; - // asStringImpl() is safe to call from any thread. - const StringImpl* asStringImpl() const; - - static void init(); - - bool isSafeToSendToAnotherThread() const { return m_string.isSafeToSendToAnotherThread(); } - -#ifndef NDEBUG - static bool isKnown(const StringImpl*); -#endif - -private: - static unsigned maxNameLength; - static StringImpl* findIfKnown(const UChar* characters, unsigned length); - static void addNames(QualifiedName** names, unsigned namesCount, unsigned indexOffset); - - String m_string; -}; - -} - -#endif diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLInputStream.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLInputStream.h index c7acd97d9ef..a121b131f12 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLInputStream.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLInputStream.h @@ -27,7 +27,7 @@ #define HTMLInputStream_h #include "core/html/parser/InputStreamPreprocessor.h" -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp index 7f3c34d8905..038c8a1e5fb 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.cpp @@ -30,7 +30,6 @@ #include "core/html/parser/HTMLParserIdioms.h" #include "core/html/parser/HTMLParserOptions.h" #include "core/html/parser/HTMLTokenizer.h" -#include "wtf/text/TextCodec.h" #include "wtf/text/TextEncodingRegistry.h" #include "wtf/text/WTFString.h" diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.h index 5ee8862ccd9..3393fca40d2 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLMetaCharsetParser.h @@ -27,7 +27,7 @@ #define HTMLMetaCharsetParser_h #include "core/html/parser/HTMLToken.h" -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" #include "wtf/Noncopyable.h" #include "wtf/text/TextCodec.h" #include "wtf/text/TextEncoding.h" diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp index 493627c1417..f538c54cc5b 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.cpp @@ -26,12 +26,10 @@ #include "core/html/parser/HTMLParserIdioms.h" #include <limits> -#include "core/dom/QualifiedName.h" -#include "core/html/parser/HTMLIdentifier.h" -#include "core/platform/Decimal.h" #include "wtf/MathExtras.h" #include "wtf/text/AtomicString.h" #include "wtf/text/StringBuilder.h" +#include "wtf/text/StringHash.h" namespace WebCore { @@ -115,11 +113,6 @@ Decimal parseToDecimalForNumberType(const String& string, const Decimal& fallbac return value.isZero() ? Decimal(0) : value; } -Decimal parseToDecimalForNumberType(const String& string) -{ - return parseToDecimalForNumberType(string, Decimal::nan()); -} - double parseToDoubleForNumberType(const String& string, double fallbackValue) { // See HTML5 2.5.4.3 `Real numbers.' @@ -147,11 +140,6 @@ double parseToDoubleForNumberType(const String& string, double fallbackValue) return value ? value : 0; } -double parseToDoubleForNumberType(const String& string) -{ - return parseToDoubleForNumberType(string, std::numeric_limits<double>::quiet_NaN()); -} - template <typename CharacterType> static bool parseHTMLIntegerInternal(const CharacterType* position, const CharacterType* end, int& value) { @@ -291,9 +279,31 @@ bool threadSafeMatch(const QualifiedName& a, const QualifiedName& b) return threadSafeEqual(a.localName().impl(), b.localName().impl()); } -bool threadSafeMatch(const HTMLIdentifier& localName, const QualifiedName& qName) +bool threadSafeMatch(const String& localName, const QualifiedName& qName) +{ + return threadSafeEqual(localName.impl(), qName.localName().impl()); +} + +StringImpl* findStringIfStatic(const UChar* characters, unsigned length) { - return threadSafeEqual(localName.asStringImpl(), qName.localName().impl()); + // We don't need to try hashing if we know the string is too long. + if (length > StringImpl::highestStaticStringLength()) + return 0; + // computeHashAndMaskTop8Bits is the function StringImpl::hash() uses. + unsigned hash = StringHasher::computeHashAndMaskTop8Bits(characters, length); + const WTF::StaticStringsTable& table = StringImpl::allStaticStrings(); + ASSERT(!table.isEmpty()); + + WTF::StaticStringsTable::const_iterator it = table.find(hash); + if (it == table.end()) + return 0; + // It's possible to have hash collisions between arbitrary strings and + // known identifiers (e.g. "bvvfg" collides with "script"). + // However ASSERTs in StringImpl::createStatic guard against there ever being collisions + // between static strings. + if (!equal(it->value, characters, length)) + return 0; + return it->value; } } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h index 5c3e9df9e84..16fd3eebe3c 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserIdioms.h @@ -26,14 +26,12 @@ #define HTMLParserIdioms_h #include "core/dom/QualifiedName.h" -#include "core/html/parser/HTMLIdentifier.h" +#include "platform/Decimal.h" #include "wtf/Forward.h" #include "wtf/text/WTFString.h" namespace WebCore { -class Decimal; - // Space characters as defined by the HTML specification. bool isHTMLSpace(UChar); bool isHTMLLineBreak(UChar); @@ -54,10 +52,8 @@ String serializeForNumberType(double); // Convert the specified string to a decimal/double. If the conversion fails, the return value is fallback value or NaN if not specified. // Leading or trailing illegal characters cause failure, as does passing an empty string. // The double* parameter may be 0 to check if the string can be parsed without getting the result. -Decimal parseToDecimalForNumberType(const String&); -Decimal parseToDecimalForNumberType(const String&, const Decimal& fallbackValue); -double parseToDoubleForNumberType(const String&); -double parseToDoubleForNumberType(const String&, double fallbackValue); +Decimal parseToDecimalForNumberType(const String&, const Decimal& fallbackValue = Decimal::nan()); +double parseToDoubleForNumberType(const String&, double fallbackValue = std::numeric_limits<double>::quiet_NaN()); // http://www.whatwg.org/specs/web-apps/current-work/#rules-for-parsing-integers bool parseHTMLInteger(const String&, int&); @@ -101,15 +97,31 @@ inline bool isNotHTMLSpace(CharType character) } bool threadSafeMatch(const QualifiedName&, const QualifiedName&); -bool threadSafeMatch(const HTMLIdentifier&, const QualifiedName&); -inline bool threadSafeHTMLNamesMatch(const HTMLIdentifier& tagName, const QualifiedName& qName) +bool threadSafeMatch(const String&, const QualifiedName&); + +StringImpl* findStringIfStatic(const UChar* characters, unsigned length); + +enum CharacterWidth { + Likely8Bit, + Force8Bit, + Force16Bit +}; + +template<size_t inlineCapacity> +static String attemptStaticStringCreation(const Vector<UChar, inlineCapacity>& vector, CharacterWidth width) { - // When the QualifiedName is known to HTMLIdentifier, - // all we have to do is a pointer compare. - ASSERT(HTMLIdentifier::isKnown(qName.localName().impl())); - return tagName.asStringImpl() == qName.localName().impl(); + String string(findStringIfStatic(vector.data(), vector.size())); + if (string.impl()) + return string; + if (width == Likely8Bit) + string = StringImpl::create8BitIfPossible(vector); + else if (width == Force8Bit) + string = String::make8BitFrom16BitSource(vector); + else + string = String(vector); + + return string; } } - #endif diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserOptions.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserOptions.cpp index 3ed04906ffe..98ceb68461d 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserOptions.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserOptions.cpp @@ -29,16 +29,16 @@ #include "bindings/v8/ScriptController.h" #include "core/dom/Document.h" #include "core/loader/FrameLoader.h" -#include "core/page/Frame.h" -#include "core/page/Settings.h" +#include "core/frame/Frame.h" +#include "core/frame/Settings.h" namespace WebCore { HTMLParserOptions::HTMLParserOptions(Document* document) { Frame* frame = document ? document->frame() : 0; - scriptEnabled = frame && frame->script()->canExecuteScripts(NotAboutToExecuteScript); - pluginsEnabled = frame && frame->loader()->allowPlugins(NotAboutToInstantiatePlugin); + scriptEnabled = frame && frame->script().canExecuteScripts(NotAboutToExecuteScript); + pluginsEnabled = frame && frame->loader().allowPlugins(NotAboutToInstantiatePlugin); Settings* settings = document ? document->settings() : 0; // We force the main-thread parser for about:blank, javascript: and data: urls for compatibility diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp index b5b38896df4..c74628479df 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.cpp @@ -28,7 +28,7 @@ #include "core/dom/Document.h" #include "core/html/parser/HTMLDocumentParser.h" -#include "core/page/FrameView.h" +#include "core/frame/FrameView.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h index 01624b7940f..e8bfe493085 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserScheduler.h @@ -27,7 +27,7 @@ #define HTMLParserScheduler_h #include "core/html/parser/NestingLevelIncrementer.h" -#include "core/platform/Timer.h" +#include "platform/Timer.h" #include "wtf/CurrentTime.h" #include "wtf/PassOwnPtr.h" #include "wtf/RefPtr.h" diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.cpp index 0ddc0587687..5a0e30c3e67 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.cpp @@ -31,14 +31,14 @@ #include "config.h" #include "core/html/parser/HTMLParserThread.h" -#include "core/platform/Task.h" -#include "wtf/PassOwnPtr.h" +#include "platform/Task.h" #include "public/platform/Platform.h" +#include "wtf/PassOwnPtr.h" namespace WebCore { HTMLParserThread::HTMLParserThread() - : m_thread(adoptPtr(WebKit::Platform::current()->createThread("HTMLParserThread"))) + : m_thread(adoptPtr(blink::Platform::current()->createThread("HTMLParserThread"))) { } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.h index 9e687de451a..e0b85f9399c 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLParserThread.h @@ -46,7 +46,7 @@ private: HTMLParserThread(); ~HTMLParserThread(); - OwnPtr<WebKit::WebThread> m_thread; + OwnPtr<blink::WebThread> m_thread; }; } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp index e4a3abb3089..0d1e0645ad7 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.cpp @@ -29,13 +29,13 @@ #include "core/html/parser/HTMLPreloadScanner.h" #include "HTMLNames.h" +#include "InputTypeNames.h" #include "RuntimeEnabledFeatures.h" #include "core/html/LinkRelAttribute.h" -#include "core/html/forms/InputTypeNames.h" #include "core/html/parser/HTMLParserIdioms.h" #include "core/html/parser/HTMLSrcsetParser.h" #include "core/html/parser/HTMLTokenizer.h" -#include "core/platform/chromium/TraceEvent.h" +#include "platform/TraceEvent.h" #include "wtf/MainThread.h" namespace WebCore { @@ -47,17 +47,17 @@ static bool match(const StringImpl* impl, const QualifiedName& qName) return impl == qName.localName().impl(); } -static bool match(const HTMLIdentifier& name, const QualifiedName& qName) -{ - return match(name.asStringImpl(), qName); -} - static bool match(const AtomicString& name, const QualifiedName& qName) { ASSERT(isMainThread()); return qName.localName() == name; } +static bool match(const String& name, const QualifiedName& qName) +{ + return threadSafeMatch(name, qName); +} + static const StringImpl* tagImplFor(const HTMLToken::DataVector& data) { AtomicString tagName(data); @@ -67,9 +67,9 @@ static const StringImpl* tagImplFor(const HTMLToken::DataVector& data) return 0; } -static const StringImpl* tagImplFor(const HTMLIdentifier& tagName) +static const StringImpl* tagImplFor(const String& tagName) { - const StringImpl* result = tagName.asStringImpl(); + const StringImpl* result = tagName.impl(); if (result->isStatic()) return result; return 0; @@ -98,6 +98,8 @@ public: , m_inputIsImage(false) , m_deviceScaleFactor(deviceScaleFactor) , m_encounteredImgSrc(false) + , m_isCORSEnabled(false) + , m_allowCredentials(DoNotAllowStoredCredentials) { if (!match(m_tagImpl, imgTag) && !match(m_tagImpl, inputTag) @@ -139,7 +141,8 @@ public: TRACE_EVENT_INSTANT1("net", "PreloadRequest", "url", m_urlToLoad.ascii()); TextPosition position = TextPosition(source.currentLine(), source.currentColumn()); OwnPtr<PreloadRequest> request = PreloadRequest::create(initiatorFor(m_tagImpl), position, m_urlToLoad, predictedBaseURL, resourceType(), m_mediaAttribute); - request->setCrossOriginModeAllowsCookies(crossOriginModeAllowsCookies()); + if (isCORSEnabled()) + request->setCrossOriginEnabled(allowCredentials()); request->setCharset(charset()); return request.release(); } @@ -154,14 +157,14 @@ private: if (match(m_tagImpl, scriptTag)) { if (match(attributeName, srcAttr)) setUrlToLoad(attributeValue, DisallowURLReplacement); - else if (match(attributeName, crossoriginAttr) && !attributeValue.isNull()) - m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue); + else if (match(attributeName, crossoriginAttr)) + setCrossOriginAllowed(attributeValue); } else if (match(m_tagImpl, imgTag)) { if (match(attributeName, srcAttr) && !m_encounteredImgSrc) { m_encounteredImgSrc = true; setUrlToLoad(bestFitSourceForImageAttributes(m_deviceScaleFactor, attributeValue, m_srcsetImageCandidate), AllowURLReplacement); - } else if (match(attributeName, crossoriginAttr) && !attributeValue.isNull()) { - m_crossOriginMode = stripLeadingAndTrailingHTMLSpaces(attributeValue); + } else if (match(attributeName, crossoriginAttr)) { + setCrossOriginAllowed(attributeValue); } else if (RuntimeEnabledFeatures::srcsetEnabled() && match(attributeName, srcsetAttr) && m_srcsetImageCandidate.isEmpty()) { @@ -179,7 +182,7 @@ private: if (match(attributeName, srcAttr)) setUrlToLoad(attributeValue, DisallowURLReplacement); else if (match(attributeName, typeAttr)) - m_inputIsImage = equalIgnoringCase(attributeValue, InputTypeNames::image()); + m_inputIsImage = equalIgnoringCase(attributeValue, InputTypeNames::image); } } @@ -221,7 +224,7 @@ private: return Resource::Raw; } - bool shouldPreload() + bool shouldPreload() const { if (m_urlToLoad.isEmpty()) return false; @@ -232,21 +235,36 @@ private: return true; } - bool crossOriginModeAllowsCookies() + bool isCORSEnabled() const + { + return m_isCORSEnabled; + } + + StoredCredentials allowCredentials() const + { + return m_allowCredentials; + } + + void setCrossOriginAllowed(const String& corsSetting) { - return m_crossOriginMode.isNull() || equalIgnoringCase(m_crossOriginMode, "use-credentials"); + m_isCORSEnabled = true; + if (!corsSetting.isNull() && equalIgnoringCase(stripLeadingAndTrailingHTMLSpaces(corsSetting), "use-credentials")) + m_allowCredentials = AllowStoredCredentials; + else + m_allowCredentials = DoNotAllowStoredCredentials; } const StringImpl* m_tagImpl; String m_urlToLoad; ImageCandidate m_srcsetImageCandidate; String m_charset; - String m_crossOriginMode; bool m_linkIsStyleSheet; String m_mediaAttribute; bool m_inputIsImage; float m_deviceScaleFactor; bool m_encounteredImgSrc; + bool m_isCORSEnabled; + StoredCredentials m_allowCredentials; }; TokenPreloadScanner::TokenPreloadScanner(const KURL& documentURL, float deviceScaleFactor) diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.h index 50366d18f7f..956d30b3d28 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLPreloadScanner.h @@ -30,7 +30,7 @@ #include "core/html/parser/CSSPreloadScanner.h" #include "core/html/parser/CompactHTMLToken.h" #include "core/html/parser/HTMLToken.h" -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" #include "wtf/Vector.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.cpp index 1d5317c4775..08e70a6a278 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.cpp @@ -32,8 +32,8 @@ #include "core/html/HTMLImport.h" #include "core/css/MediaList.h" #include "core/css/MediaQueryEvaluator.h" -#include "core/platform/HistogramSupport.h" #include "core/rendering/RenderObject.h" +#include "public/platform/Platform.h" namespace WebCore { @@ -59,9 +59,8 @@ FetchRequest PreloadRequest::resourceRequest(Document* document) initiatorInfo.position = m_initiatorPosition; FetchRequest request(ResourceRequest(completeURL(document)), initiatorInfo); - // FIXME: It's possible CORS should work for other request types? - if (m_resourceType == Resource::Script) - request.mutableResourceRequest().setAllowCookies(m_crossOriginModeAllowsCookies); + if (m_isCORSEnabled) + request.setCrossOriginAccessControl(document->securityOrigin(), m_allowCredentials); return request; } @@ -93,7 +92,7 @@ void HTMLResourcePreloader::preload(PassOwnPtr<PreloadRequest> preload) return; FetchRequest request = preload->resourceRequest(m_document); - HistogramSupport::histogramCustomCounts("WebCore.PreloadDelayMs", static_cast<int>(1000 * (monotonicallyIncreasingTime() - preload->discoveryTime())), 0, 2000, 20); + blink::Platform::current()->histogramCustomCounts("WebCore.PreloadDelayMs", static_cast<int>(1000 * (monotonicallyIncreasingTime() - preload->discoveryTime())), 0, 2000, 20); loadingDocument->fetcher()->preload(preload->resourceType(), request, preload->charset()); } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.h index 75c620d86a8..48686b6ca73 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLResourcePreloader.h @@ -53,7 +53,12 @@ public: const String& media() const { return m_mediaAttribute; } double discoveryTime() const { return m_discoveryTime; } void setCharset(const String& charset) { m_charset = charset.isolatedCopy(); } - void setCrossOriginModeAllowsCookies(bool allowsCookies) { m_crossOriginModeAllowsCookies = allowsCookies; } + void setCrossOriginEnabled(StoredCredentials allowCredentials) + { + m_isCORSEnabled = true; + m_allowCredentials = allowCredentials; + } + Resource::Type resourceType() const { return m_resourceType; } private: @@ -64,7 +69,8 @@ private: , m_baseURL(baseURL.copy()) , m_resourceType(resourceType) , m_mediaAttribute(mediaAttribute.isolatedCopy()) - , m_crossOriginModeAllowsCookies(false) + , m_isCORSEnabled(false) + , m_allowCredentials(DoNotAllowStoredCredentials) , m_discoveryTime(monotonicallyIncreasingTime()) { } @@ -78,7 +84,8 @@ private: String m_charset; Resource::Type m_resourceType; String m_mediaAttribute; - bool m_crossOriginModeAllowsCookies; + bool m_isCORSEnabled; + StoredCredentials m_allowCredentials; double m_discoveryTime; }; @@ -89,18 +96,14 @@ class HTMLResourcePreloader { public: explicit HTMLResourcePreloader(Document* document) : m_document(document) - , m_weakFactory(this) { } void takeAndPreload(PreloadRequestStream&); void preload(PassOwnPtr<PreloadRequest>); - WeakPtr<HTMLResourcePreloader> createWeakPtr() { return m_weakFactory.createWeakPtr(); } - private: Document* m_document; - WeakPtrFactory<HTMLResourcePreloader> m_weakFactory; }; } diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp index f03d204314d..1cb6555c243 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLScriptRunner.cpp @@ -28,7 +28,7 @@ #include "bindings/v8/ScriptSourceCode.h" #include "core/dom/Element.h" -#include "core/dom/Event.h" +#include "core/events/Event.h" #include "core/dom/IgnoreDestructiveWriteCountIncrementer.h" #include "core/dom/Microtask.h" #include "core/dom/ScriptLoader.h" @@ -36,8 +36,8 @@ #include "core/html/parser/HTMLInputStream.h" #include "core/html/parser/HTMLScriptRunnerHost.h" #include "core/html/parser/NestingLevelIncrementer.h" -#include "core/page/Frame.h" -#include "core/platform/NotImplemented.h" +#include "core/frame/Frame.h" +#include "platform/NotImplemented.h" namespace WebCore { @@ -81,7 +81,7 @@ static KURL documentURLForScriptExecution(Document* document) inline PassRefPtr<Event> createScriptLoadEvent() { - return Event::create(eventNames().loadEvent); + return Event::create(EventTypeNames::load); } ScriptSourceCode HTMLScriptRunner::sourceFromPendingScript(const PendingScript& script, bool& errorOccurred) const @@ -137,8 +137,8 @@ void HTMLScriptRunner::executePendingScriptAndDispatchEvent(PendingScript& pendi scriptLoader->dispatchErrorEvent(); else { ASSERT(isExecutingScript()); - scriptLoader->executeScript(sourceCode); - element->dispatchEvent(createScriptLoadEvent()); + if (scriptLoader->executePotentiallyCrossOriginScript(sourceCode)) + element->dispatchEvent(createScriptLoadEvent()); } } ASSERT(!isExecutingScript()); diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.cpp index ef802ba4ee7..af729fa4dc8 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.cpp @@ -58,14 +58,17 @@ void HTMLSourceTracker::end(SegmentedString& currentInput, HTMLTokenizer* tokeni String HTMLSourceTracker::sourceForToken(const HTMLToken& token) { - if (token.type() == HTMLToken::EndOfFile) - return String(); // Hides the null character we use to mark the end of file. - if (!m_cachedSourceForToken.isEmpty()) return m_cachedSourceForToken; - ASSERT(!token.startIndex()); - size_t length = static_cast<size_t>(token.endIndex() - token.startIndex()); + size_t length; + if (token.type() == HTMLToken::EndOfFile) { + // Consume the remainder of the input, omitting the null character we use to mark the end of the file. + length = m_previousSource.length() + m_currentSource.length() - 1; + } else { + ASSERT(!token.startIndex()); + length = static_cast<size_t>(token.endIndex() - token.startIndex()); + } StringBuilder source; source.reserveCapacity(length); diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.h index 63fec2b1bb9..083e6a93bf4 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSourceTracker.h @@ -27,7 +27,7 @@ #define HTMLSourceTracker_h #include "core/html/parser/HTMLToken.h" -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp index 40c95a19643..7002dffab3b 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.cpp @@ -32,7 +32,7 @@ #include "core/html/parser/HTMLSrcsetParser.h" #include "core/html/parser/HTMLParserIdioms.h" -#include "core/platform/ParsingUtilities.h" +#include "platform/ParsingUtilities.h" namespace WebCore { @@ -154,10 +154,13 @@ ImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, const St return pickBestImageCandidate(deviceScaleFactor, imageCandidates); } -String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute) +ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute) { - if (srcsetAttribute.isNull()) - return srcAttribute; + if (srcsetAttribute.isNull()) { + if (srcAttribute.isNull()) + return ImageCandidate(); + return ImageCandidate(srcAttribute, 0, srcAttribute.length(), 1); + } Vector<ImageCandidate> imageCandidates; @@ -166,7 +169,7 @@ String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& sr if (!srcAttribute.isEmpty()) imageCandidates.append(ImageCandidate(srcAttribute, 0, srcAttribute.length(), 1.0)); - return pickBestImageCandidate(deviceScaleFactor, imageCandidates).toString(); + return pickBestImageCandidate(deviceScaleFactor, imageCandidates); } String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, ImageCandidate& srcsetImageCandidate) diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.h index bb53cb893c9..8964ffbcd5f 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLSrcsetParser.h @@ -70,7 +70,7 @@ private: ImageCandidate bestFitSourceForSrcsetAttribute(float deviceScaleFactor, const String& srcsetAttribute); -String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute); +ImageCandidate bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, const String& srcsetAttribute); String bestFitSourceForImageAttributes(float deviceScaleFactor, const String& srcAttribute, ImageCandidate& srcsetImageCandidate); diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp index c78cd592941..ed8c954a64b 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.cpp @@ -30,9 +30,8 @@ #include "HTMLNames.h" #include "core/html/parser/HTMLEntityParser.h" -#include "core/html/parser/HTMLToken.h" #include "core/html/parser/HTMLTreeBuilder.h" -#include "core/platform/NotImplemented.h" +#include "platform/NotImplemented.h" #include "core/xml/parser/MarkupTokenizerInlines.h" #include "wtf/ASCIICType.h" #include "wtf/text/AtomicString.h" diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.h index bbfa0f2f9b2..aa7c059bf78 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTokenizer.h @@ -30,7 +30,7 @@ #include "core/html/parser/HTMLParserOptions.h" #include "core/html/parser/HTMLToken.h" #include "core/html/parser/InputStreamPreprocessor.h" -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp index ac516a20d2e..4196cde09f0 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.cpp @@ -46,8 +46,8 @@ #include "core/html/parser/HTMLStackItem.h" #include "core/html/parser/HTMLToken.h" #include "core/html/parser/HTMLTokenizer.h" -#include "core/platform/LocalizedStrings.h" -#include "core/platform/NotImplemented.h" +#include "platform/NotImplemented.h" +#include "platform/text/PlatformLocale.h" #include "wtf/MainThread.h" #include "wtf/unicode/CharacterNames.h" @@ -340,15 +340,14 @@ void HTMLTreeBuilder::detach() HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext() : m_fragment(0) - , m_contextElement(0) { } HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment* fragment, Element* contextElement) : m_fragment(fragment) - , m_contextElement(contextElement) { ASSERT(!fragment->hasChildNodes()); + m_contextElementStackItem = HTMLStackItem::create(contextElement, HTMLStackItem::ItemForContextElement); } HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext() @@ -358,6 +357,7 @@ HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext() PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition) { ASSERT(m_scriptToProcess); + ASSERT(!m_tree.hasPendingTasks()); // Unpause ourselves, callers may pause us again when processing the script. // The HTML5 spec is written as though scripts are executed inside the tree // builder. We pause the parser to exit the tree builder, and then resume @@ -375,10 +375,13 @@ void HTMLTreeBuilder::constructTree(AtomicHTMLToken* token) processToken(token); if (m_parser->tokenizer()) { - bool inForeignContent = !m_tree.isEmpty() - && !m_tree.currentStackItem()->isInHTMLNamespace() - && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem()) - && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem()); + bool inForeignContent = false; + if (!m_tree.isEmpty()) { + HTMLStackItem* adjustedCurrentNode = adjustedCurrentStackItem(); + inForeignContent = !adjustedCurrentNode->isInHTMLNamespace() + && !HTMLElementStack::isHTMLIntegrationPoint(adjustedCurrentNode) + && !HTMLElementStack::isMathMLTextIntegrationPoint(adjustedCurrentNode); + } m_parser->tokenizer()->setForceNullCharacterReplacement(m_insertionMode == TextMode || inForeignContent); m_parser->tokenizer()->setShouldAllowCDATA(inForeignContent); @@ -390,31 +393,34 @@ void HTMLTreeBuilder::constructTree(AtomicHTMLToken* token) void HTMLTreeBuilder::processToken(AtomicHTMLToken* token) { + if (token->type() == HTMLToken::Character) { + processCharacter(token); + return; + } + + // Any non-character token needs to cause us to flush any pending text immediately. + // NOTE: flush() can cause any queued tasks to execute, possibly re-entering the parser. + m_tree.flush(); + m_shouldSkipLeadingNewline = false; + switch (token->type()) { case HTMLToken::Uninitialized: + case HTMLToken::Character: ASSERT_NOT_REACHED(); break; case HTMLToken::DOCTYPE: - m_shouldSkipLeadingNewline = false; processDoctypeToken(token); break; case HTMLToken::StartTag: - m_shouldSkipLeadingNewline = false; processStartTag(token); break; case HTMLToken::EndTag: - m_shouldSkipLeadingNewline = false; processEndTag(token); break; case HTMLToken::Comment: - m_shouldSkipLeadingNewline = false; processComment(token); - return; - case HTMLToken::Character: - processCharacter(token); break; case HTMLToken::EndOfFile: - m_shouldSkipLeadingNewline = false; processEndOfFile(token); break; } @@ -487,6 +493,10 @@ void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken* token) { ASSERT(token->type() == HTMLToken::StartTag); ASSERT(token->name() == isindexTag); + + if (m_parser->useCounter()) + m_parser->useCounter()->count(UseCounter::IsIndexElement); + parseError(token); if (m_tree.form()) return; @@ -501,7 +511,7 @@ void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken* token) if (promptAttribute) processFakeCharacters(promptAttribute->value()); else - processFakeCharacters(searchableIndexIntroduction()); + processFakeCharacters(Locale::defaultLocale().queryString(blink::WebLocalizedString::SearchableIndexIntroduction)); processFakeStartTag(inputTag, attributesForIsindexInput(token)); notImplemented(); // This second set of characters may be needed by non-english locales. processFakeEndTag(labelTag); @@ -546,7 +556,7 @@ void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken* token) typedef HashMap<AtomicString, QualifiedName> PrefixedNameToQualifiedNameMap; -static void mapLoweredLocalNameToName(PrefixedNameToQualifiedNameMap* map, QualifiedName** names, size_t length) +static void mapLoweredLocalNameToName(PrefixedNameToQualifiedNameMap* map, const QualifiedName* const* names, size_t length) { for (size_t i = 0; i < length; ++i) { const QualifiedName& name = *names[i]; @@ -562,7 +572,7 @@ static void adjustSVGTagNameCase(AtomicHTMLToken* token) static PrefixedNameToQualifiedNameMap* caseMap = 0; if (!caseMap) { caseMap = new PrefixedNameToQualifiedNameMap; - QualifiedName** svgTags = SVGNames::getSVGTags(); + const QualifiedName* const* svgTags = SVGNames::getSVGTags(); mapLoweredLocalNameToName(caseMap, svgTags, SVGNames::SVGTagsCount); } @@ -572,13 +582,13 @@ static void adjustSVGTagNameCase(AtomicHTMLToken* token) token->setName(casedName.localName()); } -template<QualifiedName** getAttrs(), unsigned length> +template<const QualifiedName* const* getAttrs(), unsigned length> static void adjustAttributes(AtomicHTMLToken* token) { static PrefixedNameToQualifiedNameMap* caseMap = 0; if (!caseMap) { caseMap = new PrefixedNameToQualifiedNameMap; - QualifiedName** attrs = getAttrs(); + const QualifiedName* const* attrs = getAttrs(); mapLoweredLocalNameToName(caseMap, attrs, length); } @@ -600,10 +610,10 @@ static void adjustMathMLAttributes(AtomicHTMLToken* token) adjustAttributes<MathMLNames::getMathMLAttrs, MathMLNames::MathMLAttrsCount>(token); } -static void addNamesWithPrefix(PrefixedNameToQualifiedNameMap* map, const AtomicString& prefix, QualifiedName** names, size_t length) +static void addNamesWithPrefix(PrefixedNameToQualifiedNameMap* map, const AtomicString& prefix, const QualifiedName* const* names, size_t length) { for (size_t i = 0; i < length; ++i) { - QualifiedName* name = names[i]; + const QualifiedName* name = names[i]; const AtomicString& localName = name->localName(); AtomicString prefixColonLocalName = prefix + ':' + localName; QualifiedName nameWithPrefix(prefix, localName, name->namespaceURI()); @@ -617,7 +627,7 @@ static void adjustForeignAttributes(AtomicHTMLToken* token) if (!map) { map = new PrefixedNameToQualifiedNameMap; - QualifiedName** attrs = XLinkNames::getXLinkAttrs(); + const QualifiedName* const* attrs = XLinkNames::getXLinkAttrs(); addNamesWithPrefix(map, xlinkAtom, attrs, XLinkNames::XLinkAttrsCount); attrs = XMLNames::getXMLAttrs(); @@ -995,6 +1005,16 @@ bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup() return true; } +// http://www.whatwg.org/specs/web-apps/current-work/#adjusted-current-node +HTMLStackItem* HTMLTreeBuilder::adjustedCurrentStackItem() const +{ + ASSERT(!m_tree.isEmpty()); + if (isParsingFragment() && m_tree.openElements()->hasOnlyOneElement()) + return m_fragmentContext.contextElementStackItem(); + + return m_tree.currentStackItem(); +} + // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell void HTMLTreeBuilder::closeTheCell() { @@ -1144,6 +1164,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token) || token->name() == noframesTag || token->name() == scriptTag || token->name() == styleTag + || token->name() == templateTag || token->name() == titleTag) { parseError(token); ASSERT(m_tree.head()); @@ -1604,13 +1625,21 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately() while (1) { RefPtr<HTMLStackItem> item = nodeRecord->stackItem(); if (item->node() == m_tree.openElements()->rootNode()) { - ASSERT(isParsingFragment()); last = true; - item = HTMLStackItem::create(m_fragmentContext.contextElement(), HTMLStackItem::ItemForContextElement); + if (isParsingFragment()) + item = m_fragmentContext.contextElementStackItem(); } if (item->hasTagName(templateTag)) return setInsertionMode(m_templateInsertionModes.last()); if (item->hasTagName(selectTag)) { + if (!last) { + while (item->node() != m_tree.openElements()->rootNode() && !item->hasTagName(templateTag)) { + nodeRecord = nodeRecord->next(); + item = nodeRecord->stackItem(); + if (isHTMLTableElement(item->node())) + return setInsertionMode(InSelectInTableMode); + } + } return setInsertionMode(InSelectMode); } if (item->hasTagName(tdTag) || item->hasTagName(thTag)) @@ -1637,6 +1666,9 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately() return setInsertionMode(InFramesetMode); } if (isHTMLHtmlElement(item->node())) { + if (m_tree.headStackItem()) + return setInsertionMode(AfterHeadMode); + ASSERT(isParsingFragment()); return setInsertionMode(BeforeHeadMode); } @@ -2514,8 +2546,7 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token) return; break; } - ASSERT(m_tree.currentNode()); - m_tree.openElements()->popAll(); + m_tree.processEndOfFile(); } void HTMLTreeBuilder::defaultForInitial() @@ -2664,10 +2695,11 @@ bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token) { if (m_tree.isEmpty()) return false; - HTMLStackItem* item = m_tree.currentStackItem(); - if (item->isInHTMLNamespace()) + HTMLStackItem* adjustedCurrentNode = adjustedCurrentStackItem(); + + if (adjustedCurrentNode->isInHTMLNamespace()) return false; - if (HTMLElementStack::isMathMLTextIntegrationPoint(item)) { + if (HTMLElementStack::isMathMLTextIntegrationPoint(adjustedCurrentNode)) { if (token->type() == HTMLToken::StartTag && token->name() != MathMLNames::mglyphTag && token->name() != MathMLNames::malignmarkTag) @@ -2675,11 +2707,11 @@ bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token) if (token->type() == HTMLToken::Character) return false; } - if (item->hasTagName(MathMLNames::annotation_xmlTag) + if (adjustedCurrentNode->hasTagName(MathMLNames::annotation_xmlTag) && token->type() == HTMLToken::StartTag && token->name() == SVGNames::svgTag) return false; - if (HTMLElementStack::isHTMLIntegrationPoint(item)) { + if (HTMLElementStack::isHTMLIntegrationPoint(adjustedCurrentNode)) { if (token->type() == HTMLToken::StartTag) return false; if (token->type() == HTMLToken::Character) @@ -2692,6 +2724,17 @@ bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token) void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) { + if (token->type() == HTMLToken::Character) { + const String& characters = token->characters(); + m_tree.insertTextNode(characters); + if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters)) + m_framesetOk = false; + return; + } + + m_tree.flush(); + HTMLStackItem* adjustedCurrentNode = adjustedCurrentStackItem(); + switch (token->type()) { case HTMLToken::Uninitialized: ASSERT_NOT_REACHED(); @@ -2745,7 +2788,7 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) processStartTag(token); return; } - const AtomicString& currentNamespace = m_tree.currentStackItem()->namespaceURI(); + const AtomicString& currentNamespace = adjustedCurrentNode->namespaceURI(); if (currentNamespace == MathMLNames::mathmlNamespaceURI) adjustMathMLAttributes(token); if (currentNamespace == SVGNames::svgNamespaceURI) { @@ -2757,7 +2800,7 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) break; } case HTMLToken::EndTag: { - if (m_tree.currentStackItem()->namespaceURI() == SVGNames::svgNamespaceURI) + if (adjustedCurrentNode->namespaceURI() == SVGNames::svgNamespaceURI) adjustSVGTagNameCase(token); if (token->name() == SVGNames::scriptTag && m_tree.currentStackItem()->hasTagName(SVGNames::scriptTag)) { @@ -2788,14 +2831,8 @@ void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) } case HTMLToken::Comment: m_tree.insertComment(token); - return; - case HTMLToken::Character: { - const String& characters = token->characters(); - m_tree.insertTextNode(characters); - if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters)) - m_framesetOk = false; break; - } + case HTMLToken::Character: case HTMLToken::EndOfFile: ASSERT_NOT_REACHED(); break; @@ -2817,4 +2854,4 @@ void HTMLTreeBuilder::parseError(AtomicHTMLToken*) { } -} +} // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.h b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.h index c434d56220c..60ead95f286 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilder.h @@ -80,6 +80,9 @@ public: // Done, close any open tags, etc. void finished(); + // Synchronously empty any queues, possibly creating more DOM nodes. + void flush() { m_tree.flush(); } + void setShouldSkipLeadingNewline(bool shouldSkip) { m_shouldSkipLeadingNewline = shouldSkip; } private: @@ -166,6 +169,7 @@ private: void defaultForAfterHead(); void defaultForInTableText(); + inline HTMLStackItem* adjustedCurrentStackItem() const; inline bool shouldProcessTokenInForeignContent(AtomicHTMLToken*); void processTokenInForeignContent(AtomicHTMLToken*); @@ -197,11 +201,12 @@ private: ~FragmentParsingContext(); DocumentFragment* fragment() const { return m_fragment; } - Element* contextElement() const { ASSERT(m_fragment); return m_contextElement; } + Element* contextElement() const { ASSERT(m_fragment); return m_contextElementStackItem->element(); } + HTMLStackItem* contextElementStackItem() const { ASSERT(m_fragment); return m_contextElementStackItem.get(); } private: DocumentFragment* m_fragment; - Element* m_contextElement; + RefPtr<HTMLStackItem> m_contextElementStackItem; }; bool m_framesetOk; diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp index 32ccaaf1ae9..37273cbaea0 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLTreeBuilderSimulator.cpp @@ -40,64 +40,64 @@ using namespace HTMLNames; static bool tokenExitsForeignContent(const CompactHTMLToken& token) { // FIXME: This is copied from HTMLTreeBuilder::processTokenInForeignContent and changed to use threadSafeHTMLNamesMatch. - const HTMLIdentifier& tagName = token.data(); - return threadSafeHTMLNamesMatch(tagName, bTag) - || threadSafeHTMLNamesMatch(tagName, bigTag) - || threadSafeHTMLNamesMatch(tagName, blockquoteTag) - || threadSafeHTMLNamesMatch(tagName, bodyTag) - || threadSafeHTMLNamesMatch(tagName, brTag) - || threadSafeHTMLNamesMatch(tagName, centerTag) - || threadSafeHTMLNamesMatch(tagName, codeTag) - || threadSafeHTMLNamesMatch(tagName, ddTag) - || threadSafeHTMLNamesMatch(tagName, divTag) - || threadSafeHTMLNamesMatch(tagName, dlTag) - || threadSafeHTMLNamesMatch(tagName, dtTag) - || threadSafeHTMLNamesMatch(tagName, emTag) - || threadSafeHTMLNamesMatch(tagName, embedTag) - || threadSafeHTMLNamesMatch(tagName, h1Tag) - || threadSafeHTMLNamesMatch(tagName, h2Tag) - || threadSafeHTMLNamesMatch(tagName, h3Tag) - || threadSafeHTMLNamesMatch(tagName, h4Tag) - || threadSafeHTMLNamesMatch(tagName, h5Tag) - || threadSafeHTMLNamesMatch(tagName, h6Tag) - || threadSafeHTMLNamesMatch(tagName, headTag) - || threadSafeHTMLNamesMatch(tagName, hrTag) - || threadSafeHTMLNamesMatch(tagName, iTag) - || threadSafeHTMLNamesMatch(tagName, imgTag) - || threadSafeHTMLNamesMatch(tagName, liTag) - || threadSafeHTMLNamesMatch(tagName, listingTag) - || threadSafeHTMLNamesMatch(tagName, menuTag) - || threadSafeHTMLNamesMatch(tagName, metaTag) - || threadSafeHTMLNamesMatch(tagName, nobrTag) - || threadSafeHTMLNamesMatch(tagName, olTag) - || threadSafeHTMLNamesMatch(tagName, pTag) - || threadSafeHTMLNamesMatch(tagName, preTag) - || threadSafeHTMLNamesMatch(tagName, rubyTag) - || threadSafeHTMLNamesMatch(tagName, sTag) - || threadSafeHTMLNamesMatch(tagName, smallTag) - || threadSafeHTMLNamesMatch(tagName, spanTag) - || threadSafeHTMLNamesMatch(tagName, strongTag) - || threadSafeHTMLNamesMatch(tagName, strikeTag) - || threadSafeHTMLNamesMatch(tagName, subTag) - || threadSafeHTMLNamesMatch(tagName, supTag) - || threadSafeHTMLNamesMatch(tagName, tableTag) - || threadSafeHTMLNamesMatch(tagName, ttTag) - || threadSafeHTMLNamesMatch(tagName, uTag) - || threadSafeHTMLNamesMatch(tagName, ulTag) - || threadSafeHTMLNamesMatch(tagName, varTag) - || (threadSafeHTMLNamesMatch(tagName, fontTag) && (token.getAttributeItem(colorAttr) || token.getAttributeItem(faceAttr) || token.getAttributeItem(sizeAttr))); + const String& tagName = token.data(); + return threadSafeMatch(tagName, bTag) + || threadSafeMatch(tagName, bigTag) + || threadSafeMatch(tagName, blockquoteTag) + || threadSafeMatch(tagName, bodyTag) + || threadSafeMatch(tagName, brTag) + || threadSafeMatch(tagName, centerTag) + || threadSafeMatch(tagName, codeTag) + || threadSafeMatch(tagName, ddTag) + || threadSafeMatch(tagName, divTag) + || threadSafeMatch(tagName, dlTag) + || threadSafeMatch(tagName, dtTag) + || threadSafeMatch(tagName, emTag) + || threadSafeMatch(tagName, embedTag) + || threadSafeMatch(tagName, h1Tag) + || threadSafeMatch(tagName, h2Tag) + || threadSafeMatch(tagName, h3Tag) + || threadSafeMatch(tagName, h4Tag) + || threadSafeMatch(tagName, h5Tag) + || threadSafeMatch(tagName, h6Tag) + || threadSafeMatch(tagName, headTag) + || threadSafeMatch(tagName, hrTag) + || threadSafeMatch(tagName, iTag) + || threadSafeMatch(tagName, imgTag) + || threadSafeMatch(tagName, liTag) + || threadSafeMatch(tagName, listingTag) + || threadSafeMatch(tagName, menuTag) + || threadSafeMatch(tagName, metaTag) + || threadSafeMatch(tagName, nobrTag) + || threadSafeMatch(tagName, olTag) + || threadSafeMatch(tagName, pTag) + || threadSafeMatch(tagName, preTag) + || threadSafeMatch(tagName, rubyTag) + || threadSafeMatch(tagName, sTag) + || threadSafeMatch(tagName, smallTag) + || threadSafeMatch(tagName, spanTag) + || threadSafeMatch(tagName, strongTag) + || threadSafeMatch(tagName, strikeTag) + || threadSafeMatch(tagName, subTag) + || threadSafeMatch(tagName, supTag) + || threadSafeMatch(tagName, tableTag) + || threadSafeMatch(tagName, ttTag) + || threadSafeMatch(tagName, uTag) + || threadSafeMatch(tagName, ulTag) + || threadSafeMatch(tagName, varTag) + || (threadSafeMatch(tagName, fontTag) && (token.getAttributeItem(colorAttr) || token.getAttributeItem(faceAttr) || token.getAttributeItem(sizeAttr))); } static bool tokenExitsSVG(const CompactHTMLToken& token) { // FIXME: It's very fragile that we special case foreignObject here to be case-insensitive. - return equalIgnoringCaseNonNull(token.data().asStringImpl(), SVGNames::foreignObjectTag.localName().impl()); + return equalIgnoringCaseNonNull(token.data().impl(), SVGNames::foreignObjectTag.localName().impl()); } static bool tokenExitsMath(const CompactHTMLToken& token) { // FIXME: This is copied from HTMLElementStack::isMathMLTextIntegrationPoint and changed to use threadSafeMatch. - const HTMLIdentifier& tagName = token.data(); + const String& tagName = token.data(); return threadSafeMatch(tagName, MathMLNames::miTag) || threadSafeMatch(tagName, MathMLNames::moTag) || threadSafeMatch(tagName, MathMLNames::mnTag) @@ -132,7 +132,7 @@ HTMLTreeBuilderSimulator::State HTMLTreeBuilderSimulator::stateFor(HTMLTreeBuild bool HTMLTreeBuilderSimulator::simulate(const CompactHTMLToken& token, HTMLTokenizer* tokenizer) { if (token.type() == HTMLToken::StartTag) { - const HTMLIdentifier& tagName = token.data(); + const String& tagName = token.data(); if (threadSafeMatch(tagName, SVGNames::svgTag)) m_namespaceStack.append(SVG); if (threadSafeMatch(tagName, MathMLNames::mathTag)) @@ -144,30 +144,30 @@ bool HTMLTreeBuilderSimulator::simulate(const CompactHTMLToken& token, HTMLToken m_namespaceStack.append(HTML); if (!inForeignContent()) { // FIXME: This is just a copy of Tokenizer::updateStateFor which uses threadSafeMatches. - if (threadSafeHTMLNamesMatch(tagName, textareaTag) || threadSafeHTMLNamesMatch(tagName, titleTag)) + if (threadSafeMatch(tagName, textareaTag) || threadSafeMatch(tagName, titleTag)) tokenizer->setState(HTMLTokenizer::RCDATAState); - else if (threadSafeHTMLNamesMatch(tagName, plaintextTag)) + else if (threadSafeMatch(tagName, plaintextTag)) tokenizer->setState(HTMLTokenizer::PLAINTEXTState); - else if (threadSafeHTMLNamesMatch(tagName, scriptTag)) + else if (threadSafeMatch(tagName, scriptTag)) tokenizer->setState(HTMLTokenizer::ScriptDataState); - else if (threadSafeHTMLNamesMatch(tagName, styleTag) - || threadSafeHTMLNamesMatch(tagName, iframeTag) - || threadSafeHTMLNamesMatch(tagName, xmpTag) - || (threadSafeHTMLNamesMatch(tagName, noembedTag) && m_options.pluginsEnabled) - || threadSafeHTMLNamesMatch(tagName, noframesTag) - || (threadSafeHTMLNamesMatch(tagName, noscriptTag) && m_options.scriptEnabled)) + else if (threadSafeMatch(tagName, styleTag) + || threadSafeMatch(tagName, iframeTag) + || threadSafeMatch(tagName, xmpTag) + || (threadSafeMatch(tagName, noembedTag) && m_options.pluginsEnabled) + || threadSafeMatch(tagName, noframesTag) + || (threadSafeMatch(tagName, noscriptTag) && m_options.scriptEnabled)) tokenizer->setState(HTMLTokenizer::RAWTEXTState); } } if (token.type() == HTMLToken::EndTag) { - const HTMLIdentifier& tagName = token.data(); + const String& tagName = token.data(); if ((m_namespaceStack.last() == SVG && threadSafeMatch(tagName, SVGNames::svgTag)) || (m_namespaceStack.last() == MathML && threadSafeMatch(tagName, MathMLNames::mathTag)) || (m_namespaceStack.contains(SVG) && m_namespaceStack.last() == HTML && tokenExitsSVG(token)) || (m_namespaceStack.contains(MathML) && m_namespaceStack.last() == HTML && tokenExitsMath(token))) m_namespaceStack.removeLast(); - if (threadSafeHTMLNamesMatch(tagName, scriptTag)) { + if (threadSafeMatch(tagName, scriptTag)) { if (!inForeignContent()) tokenizer->setState(HTMLTokenizer::DataState); return false; diff --git a/chromium/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp b/chromium/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp index de01ee274d1..b46ff5ad2e9 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/HTMLViewSourceParser.cpp @@ -27,7 +27,6 @@ #include "core/html/parser/HTMLViewSourceParser.h" #include "core/dom/DOMImplementation.h" -#include "core/html/HTMLViewSourceDocument.h" #include "core/html/parser/HTMLParserOptions.h" #include "core/html/parser/HTMLToken.h" diff --git a/chromium/third_party/WebKit/Source/core/html/parser/InputStreamPreprocessor.h b/chromium/third_party/WebKit/Source/core/html/parser/InputStreamPreprocessor.h index 842e948138b..a411d52d6a1 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/InputStreamPreprocessor.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/InputStreamPreprocessor.h @@ -28,7 +28,7 @@ #ifndef InputStreamPreprocessor_h #define InputStreamPreprocessor_h -#include "core/platform/text/SegmentedString.h" +#include "platform/text/SegmentedString.h" #include "wtf/Noncopyable.h" namespace WebCore { diff --git a/chromium/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.in b/chromium/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.in new file mode 100644 index 00000000000..45a6e3af507 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/html/parser/MathMLAttributeNames.in @@ -0,0 +1,26 @@ +namespace="MathML" +namespaceURI="http://www.w3.org/1998/Math/MathML" +attrsNullNamespace + +alttext +background +close +color +columnspan +definitionURL +denomalign +encoding +fontfamily +fontsize +fontstyle +fontweight +linethickness +mathbackground +mathcolor +mathsize +mathvariant +numalign +open +rowspan +separators +stretchy diff --git a/chromium/third_party/WebKit/Source/core/html/parser/MathMLTagNames.in b/chromium/third_party/WebKit/Source/core/html/parser/MathMLTagNames.in new file mode 100644 index 00000000000..80d830f4750 --- /dev/null +++ b/chromium/third_party/WebKit/Source/core/html/parser/MathMLTagNames.in @@ -0,0 +1,12 @@ +namespace="MathML" +namespaceURI="http://www.w3.org/1998/Math/MathML" + +math +mi +mn +mo +mtext +ms +mglyph +malignmark +annotation-xml diff --git a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp index bd70813edde..a43fca982b5 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.cpp @@ -32,20 +32,25 @@ #include "XLinkNames.h" #include "core/dom/Document.h" #include "core/fetch/TextResourceDecoder.h" +#include "core/frame/ContentSecurityPolicy.h" +#include "core/frame/Frame.h" #include "core/html/HTMLParamElement.h" #include "core/html/parser/HTMLDocumentParser.h" #include "core/html/parser/HTMLParserIdioms.h" #include "core/html/parser/XSSAuditorDelegate.h" #include "core/loader/DocumentLoader.h" -#include "core/page/ContentSecurityPolicy.h" -#include "core/page/Frame.h" -#include "core/page/Settings.h" -#include "core/platform/JSONValues.h" -#include "core/platform/network/FormData.h" -#include "core/platform/text/DecodeEscapeSequences.h" -#include "weborigin/KURL.h" +#include "core/frame/Settings.h" +#include "platform/JSONValues.h" +#include "platform/network/FormData.h" +#include "platform/text/DecodeEscapeSequences.h" #include "wtf/MainThread.h" -#include "wtf/text/TextEncoding.h" + +namespace { + +// SecurityOrigin::urlWithUniqueSecurityOrigin() can't be used cross-thread, or we'd use it instead. +const char kURLWithUniqueOrigin[] = "data:,"; + +} // namespace namespace WebCore { @@ -170,12 +175,12 @@ static String fullyDecodeString(const String& string, const WTF::TextEncoding& e return workingString; } -static ContentSecurityPolicy::ReflectedXSSDisposition combineXSSProtectionHeaderAndCSP(ContentSecurityPolicy::ReflectedXSSDisposition xssProtection, ContentSecurityPolicy::ReflectedXSSDisposition reflectedXSS) +static ReflectedXSSDisposition combineXSSProtectionHeaderAndCSP(ReflectedXSSDisposition xssProtection, ReflectedXSSDisposition reflectedXSS) { - ContentSecurityPolicy::ReflectedXSSDisposition result = std::max(xssProtection, reflectedXSS); + ReflectedXSSDisposition result = std::max(xssProtection, reflectedXSS); - if (result == ContentSecurityPolicy::ReflectedXSSInvalid || result == ContentSecurityPolicy::FilterReflectedXSS || result == ContentSecurityPolicy::ReflectedXSSUnset) - return ContentSecurityPolicy::FilterReflectedXSS; + if (result == ReflectedXSSInvalid || result == FilterReflectedXSS || result == ReflectedXSSUnset) + return FilterReflectedXSS; return result; } @@ -198,7 +203,7 @@ static bool semicolonSeparatedValueContainsJavaScriptURL(const String& value) XSSAuditor::XSSAuditor() : m_isEnabled(false) - , m_xssProtection(ContentSecurityPolicy::FilterReflectedXSS) + , m_xssProtection(FilterReflectedXSS) , m_didSendValidCSPHeader(false) , m_didSendValidXSSProtectionHeader(false) , m_state(Uninitialized) @@ -214,7 +219,7 @@ void XSSAuditor::initForFragment() { ASSERT(isMainThread()); ASSERT(m_state == Uninitialized); - m_state = Initialized; + m_state = FilteringTokens; // When parsing a fragment, we don't enable the XSS auditor because it's // too much overhead. ASSERT(!m_isEnabled); @@ -226,10 +231,9 @@ void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate) const int suffixTreeDepth = 5; ASSERT(isMainThread()); - if (m_state == Initialized) + if (m_state != Uninitialized) return; - ASSERT(m_state == Uninitialized); - m_state = Initialized; + m_state = FilteringTokens; if (Settings* settings = document->settings()) m_isEnabled = settings->xssAuditorEnabled(); @@ -265,36 +269,36 @@ void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate) m_decodedURL = String(); String httpBodyAsString; - if (DocumentLoader* documentLoader = document->frame()->loader()->documentLoader()) { - DEFINE_STATIC_LOCAL(String, XSSProtectionHeader, ("X-XSS-Protection")); - String headerValue = documentLoader->response().httpHeaderField(XSSProtectionHeader); + if (DocumentLoader* documentLoader = document->frame()->loader().documentLoader()) { + DEFINE_STATIC_LOCAL(const AtomicString, XSSProtectionHeader, ("X-XSS-Protection", AtomicString::ConstructFromLiteral)); + const AtomicString& headerValue = documentLoader->response().httpHeaderField(XSSProtectionHeader); String errorDetails; unsigned errorPosition = 0; String reportURL; KURL xssProtectionReportURL; // Process the X-XSS-Protection header, then mix in the CSP header's value. - ContentSecurityPolicy::ReflectedXSSDisposition xssProtectionHeader = parseXSSProtectionHeader(headerValue, errorDetails, errorPosition, reportURL); - m_didSendValidXSSProtectionHeader = xssProtectionHeader != ContentSecurityPolicy::ReflectedXSSUnset && xssProtectionHeader != ContentSecurityPolicy::ReflectedXSSInvalid; - if ((xssProtectionHeader == ContentSecurityPolicy::FilterReflectedXSS || xssProtectionHeader == ContentSecurityPolicy::BlockReflectedXSS) && !reportURL.isEmpty()) { + ReflectedXSSDisposition xssProtectionHeader = parseXSSProtectionHeader(headerValue, errorDetails, errorPosition, reportURL); + m_didSendValidXSSProtectionHeader = xssProtectionHeader != ReflectedXSSUnset && xssProtectionHeader != ReflectedXSSInvalid; + if ((xssProtectionHeader == FilterReflectedXSS || xssProtectionHeader == BlockReflectedXSS) && !reportURL.isEmpty()) { xssProtectionReportURL = document->completeURL(reportURL); if (MixedContentChecker::isMixedContent(document->securityOrigin(), xssProtectionReportURL)) { errorDetails = "insecure reporting URL for secure page"; - xssProtectionHeader = ContentSecurityPolicy::ReflectedXSSInvalid; + xssProtectionHeader = ReflectedXSSInvalid; xssProtectionReportURL = KURL(); } } - if (xssProtectionHeader == ContentSecurityPolicy::ReflectedXSSInvalid) + if (xssProtectionHeader == ReflectedXSSInvalid) document->addConsoleMessage(SecurityMessageSource, ErrorMessageLevel, "Error parsing header X-XSS-Protection: " + headerValue + ": " + errorDetails + " at character position " + String::format("%u", errorPosition) + ". The default protections will be applied."); - ContentSecurityPolicy::ReflectedXSSDisposition cspHeader = document->contentSecurityPolicy()->reflectedXSSDisposition(); - m_didSendValidCSPHeader = cspHeader != ContentSecurityPolicy::ReflectedXSSUnset && cspHeader != ContentSecurityPolicy::ReflectedXSSInvalid; + ReflectedXSSDisposition cspHeader = document->contentSecurityPolicy()->reflectedXSSDisposition(); + m_didSendValidCSPHeader = cspHeader != ReflectedXSSUnset && cspHeader != ReflectedXSSInvalid; m_xssProtection = combineXSSProtectionHeaderAndCSP(xssProtectionHeader, cspHeader); // FIXME: Combine the two report URLs in some reasonable way. if (auditorDelegate) auditorDelegate->setReportURL(xssProtectionReportURL.copy()); - FormData* httpBody = documentLoader->originalRequest().httpBody(); + FormData* httpBody = documentLoader->request().httpBody(); if (httpBody && !httpBody->isEmpty()) { httpBodyAsString = httpBody->flattenToString(); if (!httpBodyAsString.isEmpty()) { @@ -315,8 +319,8 @@ void XSSAuditor::init(Document* document, XSSAuditorDelegate* auditorDelegate) PassOwnPtr<XSSInfo> XSSAuditor::filterToken(const FilterTokenRequest& request) { - ASSERT(m_state == Initialized); - if (!m_isEnabled || m_xssProtection == ContentSecurityPolicy::AllowReflectedXSS) + ASSERT(m_state != Uninitialized); + if (!m_isEnabled || m_xssProtection == AllowReflectedXSS) return nullptr; bool didBlockScript = false; @@ -330,7 +334,7 @@ PassOwnPtr<XSSInfo> XSSAuditor::filterToken(const FilterTokenRequest& request) } if (didBlockScript) { - bool didBlockEntirePage = (m_xssProtection == ContentSecurityPolicy::BlockReflectedXSS); + bool didBlockEntirePage = (m_xssProtection == BlockReflectedXSS); OwnPtr<XSSInfo> xssInfo = XSSInfo::create(m_documentURL, didBlockEntirePage, m_didSendValidXSSProtectionHeader, m_didSendValidCSPHeader); return xssInfo.release(); } @@ -339,6 +343,7 @@ PassOwnPtr<XSSInfo> XSSAuditor::filterToken(const FilterTokenRequest& request) bool XSSAuditor::filterStartToken(const FilterTokenRequest& request) { + m_state = FilteringTokens; bool didBlockScript = eraseDangerousAttributesIfInjected(request); if (hasName(request.token, scriptTag)) { @@ -372,6 +377,7 @@ bool XSSAuditor::filterStartToken(const FilterTokenRequest& request) void XSSAuditor::filterEndToken(const FilterTokenRequest& request) { ASSERT(m_scriptTagNestingLevel); + m_state = FilteringTokens; if (hasName(request.token, scriptTag)) { m_scriptTagNestingLevel--; ASSERT(request.shouldAllowCDATA || !m_scriptTagNestingLevel); @@ -381,11 +387,19 @@ void XSSAuditor::filterEndToken(const FilterTokenRequest& request) bool XSSAuditor::filterCharacterToken(const FilterTokenRequest& request) { ASSERT(m_scriptTagNestingLevel); - if (m_scriptTagFoundInRequest && isContainedInRequest(decodedSnippetForJavaScript(request))) { + ASSERT(m_state != Uninitialized); + if (m_state == PermittingAdjacentCharacterTokens) + return false; + + if ((m_state == SuppressingAdjacentCharacterTokens) + || (m_scriptTagFoundInRequest && isContainedInRequest(decodedSnippetForJavaScript(request)))) { request.token.eraseCharacters(); request.token.appendToCharacter(' '); // Technically, character tokens can't be empty. + m_state = SuppressingAdjacentCharacterTokens; return true; } + + m_state = PermittingAdjacentCharacterTokens; return false; } @@ -465,11 +479,10 @@ bool XSSAuditor::filterFrameToken(const FilterTokenRequest& request) ASSERT(request.token.type() == HTMLToken::StartTag); ASSERT(hasName(request.token, iframeTag) || hasName(request.token, frameTag)); - bool didBlockScript = false; - if (isContainedInRequest(decodedSnippetForName(request))) { + bool didBlockScript = eraseAttributeIfInjected(request, srcdocAttr, String(), ScriptLikeAttribute); + if (isContainedInRequest(decodedSnippetForName(request))) didBlockScript |= eraseAttributeIfInjected(request, srcAttr, String(), SrcLikeAttribute); - didBlockScript |= eraseAttributeIfInjected(request, srcdocAttr, String(), ScriptLikeAttribute); - } + return didBlockScript; } @@ -494,7 +507,7 @@ bool XSSAuditor::filterFormToken(const FilterTokenRequest& request) ASSERT(request.token.type() == HTMLToken::StartTag); ASSERT(hasName(request.token, formTag)); - return eraseAttributeIfInjected(request, actionAttr, blankURL().string()); + return eraseAttributeIfInjected(request, actionAttr, kURLWithUniqueOrigin); } bool XSSAuditor::filterInputToken(const FilterTokenRequest& request) @@ -502,7 +515,7 @@ bool XSSAuditor::filterInputToken(const FilterTokenRequest& request) ASSERT(request.token.type() == HTMLToken::StartTag); ASSERT(hasName(request.token, inputTag)); - return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute); + return eraseAttributeIfInjected(request, formactionAttr, kURLWithUniqueOrigin, SrcLikeAttribute); } bool XSSAuditor::filterButtonToken(const FilterTokenRequest& request) @@ -510,7 +523,7 @@ bool XSSAuditor::filterButtonToken(const FilterTokenRequest& request) ASSERT(request.token.type() == HTMLToken::StartTag); ASSERT(hasName(request.token, buttonTag)); - return eraseAttributeIfInjected(request, formactionAttr, blankURL().string(), SrcLikeAttribute); + return eraseAttributeIfInjected(request, formactionAttr, kURLWithUniqueOrigin, SrcLikeAttribute); } bool XSSAuditor::eraseDangerousAttributesIfInjected(const FilterTokenRequest& request) diff --git a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.h b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.h index 5249479c630..db2655f4a8a 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditor.h @@ -27,9 +27,9 @@ #define XSSAuditor_h #include "core/html/parser/HTMLToken.h" -#include "core/platform/network/HTTPParsers.h" -#include "core/platform/text/SuffixTree.h" -#include "weborigin/KURL.h" +#include "platform/network/HTTPParsers.h" +#include "platform/text/SuffixTree.h" +#include "platform/weborigin/KURL.h" #include "wtf/PassOwnPtr.h" #include "wtf/text/TextEncoding.h" @@ -69,7 +69,9 @@ private: enum State { Uninitialized, - Initialized + FilteringTokens, + PermittingAdjacentCharacterTokens, + SuppressingAdjacentCharacterTokens }; enum AttributeKind { @@ -107,7 +109,7 @@ private: KURL m_documentURL; bool m_isEnabled; - ContentSecurityPolicy::ReflectedXSSDisposition m_xssProtection; + ReflectedXSSDisposition m_xssProtection; bool m_didSendValidCSPHeader; bool m_didSendValidXSSProtectionHeader; diff --git a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.cpp b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.cpp index a5a4f52b73f..5ea9b66ccf7 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.cpp +++ b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.cpp @@ -27,40 +27,32 @@ #include "core/html/parser/XSSAuditorDelegate.h" #include "core/dom/Document.h" +#include "core/frame/Frame.h" #include "core/loader/DocumentLoader.h" #include "core/loader/FrameLoader.h" #include "core/loader/FrameLoaderClient.h" #include "core/loader/PingLoader.h" -#include "core/page/Frame.h" -#include "core/platform/JSONValues.h" -#include "core/platform/network/FormData.h" -#include "weborigin/SecurityOrigin.h" +#include "platform/JSONValues.h" +#include "platform/network/FormData.h" +#include "platform/weborigin/SecurityOrigin.h" #include "wtf/text/StringBuilder.h" namespace WebCore { -XSSAuditorDelegate::XSSAuditorDelegate(Document* document) - : m_document(document) - , m_didSendNotifications(false) -{ - ASSERT(isMainThread()); - ASSERT(m_document); -} - -static inline String buildConsoleError(const XSSInfo& xssInfo) +String XSSInfo::buildConsoleError() const { StringBuilder message; message.append("The XSS Auditor "); - message.append(xssInfo.m_didBlockEntirePage ? "blocked access to" : "refused to execute a script in"); + message.append(m_didBlockEntirePage ? "blocked access to" : "refused to execute a script in"); message.append(" '"); - message.append(xssInfo.m_originalURL); + message.append(m_originalURL); message.append("' because "); - message.append(xssInfo.m_didBlockEntirePage ? "the source code of a script" : "its source code"); + message.append(m_didBlockEntirePage ? "the source code of a script" : "its source code"); message.append(" was found within the request."); - if (xssInfo.m_didSendCSPHeader) + if (m_didSendCSPHeader) message.append(" The server sent a 'Content-Security-Policy' header requesting this behavior."); - else if (xssInfo.m_didSendXSSProtectionHeader) + else if (m_didSendXSSProtectionHeader) message.append(" The server sent an 'X-XSS-Protection' header requesting this behavior."); else message.append(" The auditor was enabled as the server sent neither an 'X-XSS-Protection' nor 'Content-Security-Policy' header."); @@ -68,14 +60,27 @@ static inline String buildConsoleError(const XSSInfo& xssInfo) return message.toString(); } +bool XSSInfo::isSafeToSendToAnotherThread() const +{ + return m_originalURL.isSafeToSendToAnotherThread(); +} + +XSSAuditorDelegate::XSSAuditorDelegate(Document* document) + : m_document(document) + , m_didSendNotifications(false) +{ + ASSERT(isMainThread()); + ASSERT(m_document); +} + PassRefPtr<FormData> XSSAuditorDelegate::generateViolationReport(const XSSInfo& xssInfo) { ASSERT(isMainThread()); - FrameLoader* frameLoader = m_document->frame()->loader(); + FrameLoader& frameLoader = m_document->frame()->loader(); String httpBody; - if (frameLoader->documentLoader()) { - if (FormData* formData = frameLoader->documentLoader()->originalRequest().httpBody()) + if (frameLoader.documentLoader()) { + if (FormData* formData = frameLoader.documentLoader()->originalRequest().httpBody()) httpBody = formData->flattenToString(); } @@ -93,25 +98,25 @@ void XSSAuditorDelegate::didBlockScript(const XSSInfo& xssInfo) { ASSERT(isMainThread()); - m_document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, buildConsoleError(xssInfo)); + m_document->addConsoleMessage(JSMessageSource, ErrorMessageLevel, xssInfo.buildConsoleError()); // stopAllLoaders can detach the Frame, so protect it. RefPtr<Frame> protect(m_document->frame()); - FrameLoader* frameLoader = m_document->frame()->loader(); + FrameLoader& frameLoader = m_document->frame()->loader(); if (xssInfo.m_didBlockEntirePage) - frameLoader->stopAllLoaders(); + frameLoader.stopAllLoaders(); if (!m_didSendNotifications) { m_didSendNotifications = true; - frameLoader->client()->didDetectXSS(m_document->url(), xssInfo.m_didBlockEntirePage); + frameLoader.client()->didDetectXSS(m_document->url(), xssInfo.m_didBlockEntirePage); if (!m_reportURL.isEmpty()) PingLoader::sendViolationReport(m_document->frame(), m_reportURL, generateViolationReport(xssInfo), PingLoader::XSSAuditorViolationReport); } if (xssInfo.m_didBlockEntirePage) - m_document->frame()->navigationScheduler()->scheduleLocationChange(m_document->securityOrigin(), SecurityOrigin::urlWithUniqueSecurityOrigin(), String()); + m_document->frame()->navigationScheduler().scheduleLocationChange(m_document, SecurityOrigin::urlWithUniqueSecurityOrigin(), String()); } } // namespace WebCore diff --git a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.h b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.h index 5dda5f5b5e2..1fbfb20b01c 100644 --- a/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.h +++ b/chromium/third_party/WebKit/Source/core/html/parser/XSSAuditorDelegate.h @@ -26,7 +26,7 @@ #ifndef XSSAuditorDelegate_h #define XSSAuditorDelegate_h -#include "weborigin/KURL.h" +#include "platform/weborigin/KURL.h" #include "wtf/OwnPtr.h" #include "wtf/PassOwnPtr.h" #include "wtf/Vector.h" @@ -45,6 +45,9 @@ public: return adoptPtr(new XSSInfo(originalURL, didBlockEntirePage, didSendXSSProtectionHeader, didSendCSPHeader)); } + String buildConsoleError() const; + bool isSafeToSendToAnotherThread() const; + String m_originalURL; bool m_didBlockEntirePage; bool m_didSendXSSProtectionHeader; |