diff options
Diffstat (limited to 'Source/WebCore/html/parser/HTMLTreeBuilder.cpp')
-rw-r--r-- | Source/WebCore/html/parser/HTMLTreeBuilder.cpp | 133 |
1 files changed, 63 insertions, 70 deletions
diff --git a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp index d2931ac..8f9e3e1 100644 --- a/Source/WebCore/html/parser/HTMLTreeBuilder.cpp +++ b/Source/WebCore/html/parser/HTMLTreeBuilder.cpp @@ -1,5 +1,6 @@ /* * Copyright (C) 2010 Google, Inc. All Rights Reserved. + * Copyright (C) 2011 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -122,6 +123,8 @@ bool isSpecialNode(Node* node) || node->hasTagName(SVGNames::descTag) || node->hasTagName(SVGNames::titleTag)) return true; + if (node->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) + return true; if (node->namespaceURI() != xhtmlNamespaceURI) return false; const AtomicString& tagName = node->localName(); @@ -375,7 +378,9 @@ HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, DocumentFragment* f if (contextElement) { // Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm: // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case - processFakeStartTag(htmlTag); + // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes") + // and instead use the DocumentFragment as a root node. + m_tree.openElements()->pushRootNode(fragment); resetInsertionModeAppropriately(); m_tree.setForm(closestFormAncestor(contextElement)); } @@ -410,19 +415,6 @@ HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment ASSERT(!fragment->hasChildNodes()); } -void HTMLTreeBuilder::FragmentParsingContext::finished() -{ - if (!m_contextElement) - return; - - // The HTML5 spec says to return the children of the fragment's document - // element when there is a context element (10.4.7). - RefPtr<ContainerNode> documentElement = firstElementChild(m_fragment); - m_fragment->removeChildren(); - ASSERT(documentElement); - m_fragment->takeAllChildrenFrom(documentElement.get()); -} - HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext() { } @@ -453,7 +445,7 @@ void HTMLTreeBuilder::constructTreeFromAtomicToken(AtomicHTMLToken& token) // the U+0000 characters into replacement characters has compatibility // problems. m_parser->tokenizer()->setForceNullCharacterReplacement(m_insertionMode == TextMode || m_insertionMode == InForeignContentMode); - m_parser->tokenizer()->setShouldAllowCDATA(m_insertionMode == InForeignContentMode && m_tree.currentElement()->namespaceURI() != xhtmlNamespaceURI); + m_parser->tokenizer()->setShouldAllowCDATA(m_insertionMode == InForeignContentMode && m_tree.currentNode()->namespaceURI() != xhtmlNamespaceURI); } void HTMLTreeBuilder::processToken(AtomicHTMLToken& token) @@ -574,12 +566,12 @@ void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken& token) namespace { -bool isLi(const Element* element) +bool isLi(const ContainerNode* element) { return element->hasTagName(liTag); } -bool isDdOrDt(const Element* element) +bool isDdOrDt(const ContainerNode* element) { return element->hasTagName(ddTag) || element->hasTagName(dtTag); @@ -587,15 +579,16 @@ bool isDdOrDt(const Element* element) } -template <bool shouldClose(const Element*)> +template <bool shouldClose(const ContainerNode*)> void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken& token) { m_framesetOk = false; HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); while (1) { - Element* node = nodeRecord->element(); + ContainerNode* node = nodeRecord->node(); if (shouldClose(node)) { - processFakeEndTag(node->tagQName()); + ASSERT(node->isElementNode()); + processFakeEndTag(toElement(node)->tagQName()); break; } if (isSpecialNode(node) && !node->hasTagName(addressTag) && !node->hasTagName(divTag) && !node->hasTagName(pTag)) @@ -786,7 +779,7 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token) } if (isNumberedHeaderTag(token.name())) { processFakePEndTagIfPInButtonScope(); - if (isNumberedHeaderTag(m_tree.currentElement()->localName())) { + if (isNumberedHeaderTag(m_tree.currentNode()->localName())) { parseError(token); m_tree.openElements()->pop(); } @@ -978,7 +971,7 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token) if (token.name() == rpTag || token.name() == rtTag) { if (m_tree.openElements()->inScope(rubyTag.localName())) { m_tree.generateImpliedEndTags(); - if (!m_tree.currentElement()->hasTagName(rubyTag)) { + if (!m_tree.currentNode()->hasTagName(rubyTag)) { parseError(token); m_tree.openElements()->popUntil(rubyTag.localName()); } @@ -1019,7 +1012,7 @@ void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken& token) bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup() { - if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) { + if (m_tree.currentNode() == m_tree.openElements()->rootNode()) { ASSERT(isParsingFragment()); // FIXME: parse error return false; @@ -1115,7 +1108,7 @@ void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken& token) namespace { -bool shouldProcessForeignContentUsingInBodyInsertionMode(AtomicHTMLToken& token, Element* currentElement) +bool shouldProcessForeignContentUsingInBodyInsertionMode(AtomicHTMLToken& token, ContainerNode* currentElement) { ASSERT(token.type() == HTMLToken::StartTag); if (currentElement->hasTagName(MathMLNames::miTag) @@ -1409,7 +1402,7 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) return; } if (token.name() == optionTag) { - if (m_tree.currentElement()->hasTagName(optionTag)) { + if (m_tree.currentNode()->hasTagName(optionTag)) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); processEndTag(endOption); } @@ -1417,11 +1410,11 @@ void HTMLTreeBuilder::processStartTag(AtomicHTMLToken& token) return; } if (token.name() == optgroupTag) { - if (m_tree.currentElement()->hasTagName(optionTag)) { + if (m_tree.currentNode()->hasTagName(optionTag)) { AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); processEndTag(endOption); } - if (m_tree.currentElement()->hasTagName(optgroupTag)) { + if (m_tree.currentNode()->hasTagName(optgroupTag)) { AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName()); processEndTag(endOptgroup); } @@ -1543,20 +1536,24 @@ void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken& token) ASSERT(token.type() == HTMLToken::EndTag); HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord(); while (1) { - Element* node = record->element(); + ContainerNode* node = record->node(); if (node->hasLocalName(token.name())) { m_tree.generateImpliedEndTags(); - if (!m_tree.currentElement()->hasLocalName(token.name())) { + // FIXME: The ElementRecord pointed to by record might be deleted by + // the preceding call. Perhaps we should hold a RefPtr so that it + // stays alive for the duration of record's scope. + record = 0; + if (!m_tree.currentNode()->hasLocalName(token.name())) { parseError(token); // FIXME: This is either a bug in the spec, or a bug in our // implementation. Filed a bug with HTML5: // http://www.w3.org/Bugs/Public/show_bug.cgi?id=10080 // We might have already popped the node for the token in // generateImpliedEndTags, just abort. - if (!m_tree.openElements()->contains(node)) + if (!m_tree.openElements()->contains(toElement(node))) return; } - m_tree.openElements()->popUntilPopped(node); + m_tree.openElements()->popUntilPopped(toElement(node)); return; } if (isSpecialNode(node)) { @@ -1616,7 +1613,7 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token) } // 4. ASSERT(furthestBlock->isAbove(formattingElementRecord)); - Element* commonAncestor = formattingElementRecord->next()->element(); + ContainerNode* commonAncestor = formattingElementRecord->next()->node(); // 5. HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement); // 6. @@ -1668,7 +1665,9 @@ void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken& token) m_tree.fosterParent(lastNode->element()); else { commonAncestor->parserAddChild(lastNode->element()); - if (lastNode->element()->parentElement()->attached() && !lastNode->element()->attached()) + ASSERT(lastNode->node()->isElementNode()); + ASSERT(lastNode->element()->parentNode()); + if (lastNode->element()->parentNode()->attached() && !lastNode->element()->attached()) lastNode->element()->lazyAttach(); } // 8 @@ -1700,8 +1699,8 @@ void HTMLTreeBuilder::resetInsertionModeAppropriately() bool last = false; HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); while (1) { - Element* node = nodeRecord->element(); - if (node == m_tree.openElements()->bottom()) { + ContainerNode* node = nodeRecord->node(); + if (node == m_tree.openElements()->rootNode()) { ASSERT(isParsingFragment()); last = true; node = m_fragmentContext.contextElement(); @@ -1831,7 +1830,7 @@ void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken& token) return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentElement()->hasLocalName(token.name())) + if (!m_tree.currentNode()->hasLocalName(token.name())) parseError(token); m_tree.openElements()->popUntilPopped(token.name()); m_tree.activeFormattingElements()->clearToLastMarker(); @@ -1901,7 +1900,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentElement()->hasLocalName(token.name())) + if (!m_tree.currentNode()->hasLocalName(token.name())) parseError(token); m_tree.openElements()->popUntilPopped(token.name()); return; @@ -1926,7 +1925,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) return; } m_tree.generateImpliedEndTagsWithExclusion(token.name()); - if (!m_tree.currentElement()->hasLocalName(token.name())) + if (!m_tree.currentNode()->hasLocalName(token.name())) parseError(token); m_tree.openElements()->popUntilPopped(token.name()); return; @@ -1937,7 +1936,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) return; } m_tree.generateImpliedEndTagsWithExclusion(token.name()); - if (!m_tree.currentElement()->hasLocalName(token.name())) + if (!m_tree.currentNode()->hasLocalName(token.name())) parseError(token); m_tree.openElements()->popUntilPopped(token.name()); return; @@ -1949,7 +1948,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) return; } m_tree.generateImpliedEndTagsWithExclusion(token.name()); - if (!m_tree.currentElement()->hasLocalName(token.name())) + if (!m_tree.currentNode()->hasLocalName(token.name())) parseError(token); m_tree.openElements()->popUntilPopped(token.name()); return; @@ -1960,7 +1959,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentElement()->hasLocalName(token.name())) + if (!m_tree.currentNode()->hasLocalName(token.name())) parseError(token); m_tree.openElements()->popUntilNumberedHeaderElementPopped(); return; @@ -1977,7 +1976,7 @@ void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken& token) return; } m_tree.generateImpliedEndTags(); - if (!m_tree.currentElement()->hasLocalName(token.name())) + if (!m_tree.currentNode()->hasLocalName(token.name())) parseError(token); m_tree.openElements()->popUntilPopped(token.name()); m_tree.activeFormattingElements()->clearToLastMarker(); @@ -2221,7 +2220,7 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) case InFramesetMode: ASSERT(insertionMode() == InFramesetMode); if (token.name() == framesetTag) { - if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) { + if (m_tree.currentNode() == m_tree.openElements()->rootNode()) { parseError(token); return; } @@ -2261,9 +2260,9 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) case InSelectMode: ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode); if (token.name() == optgroupTag) { - if (m_tree.currentElement()->hasTagName(optionTag) && m_tree.oneBelowTop()->hasTagName(optgroupTag)) + if (m_tree.currentNode()->hasTagName(optionTag) && m_tree.oneBelowTop()->hasTagName(optgroupTag)) processFakeEndTag(optionTag); - if (m_tree.currentElement()->hasTagName(optgroupTag)) { + if (m_tree.currentNode()->hasTagName(optgroupTag)) { m_tree.openElements()->pop(); return; } @@ -2271,7 +2270,7 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) return; } if (token.name() == optionTag) { - if (m_tree.currentElement()->hasTagName(optionTag)) { + if (m_tree.currentNode()->hasTagName(optionTag)) { m_tree.openElements()->pop(); return; } @@ -2294,23 +2293,29 @@ void HTMLTreeBuilder::processEndTag(AtomicHTMLToken& token) processEndTag(token); break; case InForeignContentMode: - if (token.name() == SVGNames::scriptTag && m_tree.currentElement()->hasTagName(SVGNames::scriptTag)) { + if (token.name() == SVGNames::scriptTag && m_tree.currentNode()->hasTagName(SVGNames::scriptTag)) { notImplemented(); return; } - if (m_tree.currentElement()->namespaceURI() != xhtmlNamespaceURI) { + if (m_tree.currentNode()->namespaceURI() != xhtmlNamespaceURI) { // FIXME: This code just wants an Element* iterator, instead of an ElementRecord* HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); - if (!nodeRecord->element()->hasLocalName(token.name())) + if (!nodeRecord->node()->hasLocalName(token.name())) parseError(token); while (1) { - if (nodeRecord->element()->hasLocalName(token.name())) { + if (nodeRecord->node()->hasLocalName(token.name())) { m_tree.openElements()->popUntilPopped(nodeRecord->element()); resetForeignInsertionMode(); return; } nodeRecord = nodeRecord->next(); - if (nodeRecord->element()->namespaceURI() == xhtmlNamespaceURI) + + if (nodeRecord->node()->nodeType() == Node::DOCUMENT_FRAGMENT_NODE) { + ASSERT(isParsingFragment()); + break; + } + + if (nodeRecord->node()->namespaceURI() == xhtmlNamespaceURI) break; } } @@ -2609,11 +2614,11 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) case InSelectInTableMode: case InSelectMode: ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode); - if (m_tree.currentElement() != m_tree.openElements()->htmlElement()) + if (m_tree.currentNode() != m_tree.openElements()->rootNode()) parseError(token); break; case InColumnGroupMode: - if (m_tree.currentElement() == m_tree.openElements()->htmlElement()) { + if (m_tree.currentNode() == m_tree.openElements()->rootNode()) { ASSERT(isParsingFragment()); return; // FIXME: Should we break here instead of returning? } @@ -2634,7 +2639,7 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) return; case TextMode: parseError(token); - if (m_tree.currentElement()->hasTagName(scriptTag)) + if (m_tree.currentNode()->hasTagName(scriptTag)) notImplemented(); // mark the script element as "already started". m_tree.openElements()->pop(); setInsertionMode(m_originalInsertionMode); @@ -2642,7 +2647,7 @@ void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken& token) processEndOfFile(token); return; } - ASSERT(m_tree.openElements()->top()); + ASSERT(m_tree.currentNode()); m_tree.openElements()->popAll(); } @@ -2794,28 +2799,16 @@ void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken& token) void HTMLTreeBuilder::finished() { - ASSERT(m_document); - if (isParsingFragment()) { - m_fragmentContext.finished(); + if (isParsingFragment()) return; - } - + + ASSERT(m_document); // Warning, this may detach the parser. Do not do anything else after this. m_document->finishedParsing(); } void HTMLTreeBuilder::parseError(AtomicHTMLToken&) { - DEFINE_STATIC_LOCAL(String, parseErrorMessage, ("HTML parse error (recovered gracefully)")); - - if (!m_reportErrors) - return; - - DOMWindow* domWindow = m_document->domWindow(); - if (!domWindow) - return; - - domWindow->console()->addMessage(HTMLMessageSource, LogMessageType, WarningMessageLevel, parseErrorMessage, m_parser->lineNumber(), m_document->url().string()); } bool HTMLTreeBuilder::scriptEnabled(Frame* frame) |