1/* 2 * Copyright (C) 2010 Google, Inc. All Rights Reserved. 3 * Copyright (C) 2011 Apple Inc. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY GOOGLE INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL GOOGLE INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27#include "config.h" 28#include "HTMLTreeBuilder.h" 29 30#include "AtomicHTMLToken.h" 31#include "DocumentFragment.h" 32#include "HTMLDocument.h" 33#include "HTMLDocumentParser.h" 34#include "HTMLFormElement.h" 35#include "HTMLNames.h" 36#include "HTMLParserIdioms.h" 37#include "HTMLStackItem.h" 38#include "HTMLTemplateElement.h" 39#include "HTMLToken.h" 40#include "HTMLTokenizer.h" 41#include "LocalizedStrings.h" 42#include "MathMLNames.h" 43#include "NotImplemented.h" 44#include "SVGNames.h" 45#include "XLinkNames.h" 46#include "XMLNSNames.h" 47#include "XMLNames.h" 48#include <wtf/MainThread.h> 49#include <wtf/unicode/CharacterNames.h> 50 51namespace WebCore { 52 53using namespace HTMLNames; 54 55namespace { 56 57inline bool isHTMLSpaceOrReplacementCharacter(UChar character) 58{ 59 return isHTMLSpace(character) || character == replacementCharacter; 60} 61 62} 63 64static TextPosition uninitializedPositionValue1() 65{ 66 return TextPosition(OrdinalNumber::fromOneBasedInt(-1), OrdinalNumber::first()); 67} 68 69static inline bool isAllWhitespace(const String& string) 70{ 71 return string.isAllSpecialCharacters<isHTMLSpace>(); 72} 73 74static inline bool isAllWhitespaceOrReplacementCharacters(const String& string) 75{ 76 return string.isAllSpecialCharacters<isHTMLSpaceOrReplacementCharacter>(); 77} 78 79static bool isNumberedHeaderTag(const AtomicString& tagName) 80{ 81 return tagName == h1Tag 82 || tagName == h2Tag 83 || tagName == h3Tag 84 || tagName == h4Tag 85 || tagName == h5Tag 86 || tagName == h6Tag; 87} 88 89static bool isCaptionColOrColgroupTag(const AtomicString& tagName) 90{ 91 return tagName == captionTag 92 || tagName == colTag 93 || tagName == colgroupTag; 94} 95 96static bool isTableCellContextTag(const AtomicString& tagName) 97{ 98 return tagName == thTag || tagName == tdTag; 99} 100 101static bool isTableBodyContextTag(const AtomicString& tagName) 102{ 103 return tagName == tbodyTag 104 || tagName == tfootTag 105 || tagName == theadTag; 106} 107 108static bool isNonAnchorNonNobrFormattingTag(const AtomicString& tagName) 109{ 110 return tagName == bTag 111 || tagName == bigTag 112 || tagName == codeTag 113 || tagName == emTag 114 || tagName == fontTag 115 || tagName == iTag 116 || tagName == sTag 117 || tagName == smallTag 118 || tagName == strikeTag 119 || tagName == strongTag 120 || tagName == ttTag 121 || tagName == uTag; 122} 123 124static bool isNonAnchorFormattingTag(const AtomicString& tagName) 125{ 126 return tagName == nobrTag 127 || isNonAnchorNonNobrFormattingTag(tagName); 128} 129 130// http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#formatting 131static bool isFormattingTag(const AtomicString& tagName) 132{ 133 return tagName == aTag || isNonAnchorFormattingTag(tagName); 134} 135 136static HTMLFormElement* closestFormAncestor(Element* element) 137{ 138 ASSERT(isMainThread()); 139 while (element) { 140 if (element->hasTagName(formTag)) 141 return static_cast<HTMLFormElement*>(element); 142 ContainerNode* parent = element->parentNode(); 143 if (!parent || !parent->isElementNode()) 144 return 0; 145 element = toElement(parent); 146 } 147 return 0; 148} 149 150class HTMLTreeBuilder::ExternalCharacterTokenBuffer { 151 WTF_MAKE_NONCOPYABLE(ExternalCharacterTokenBuffer); 152public: 153 explicit ExternalCharacterTokenBuffer(AtomicHTMLToken* token) 154 : m_current(token->characters()) 155 , m_end(m_current + token->charactersLength()) 156 , m_isAll8BitData(token->isAll8BitData()) 157 { 158 ASSERT(!isEmpty()); 159 } 160 161 explicit ExternalCharacterTokenBuffer(const String& string) 162 : m_current(string.characters()) 163 , m_end(m_current + string.length()) 164 , m_isAll8BitData(string.length() && string.is8Bit()) 165 { 166 ASSERT(!isEmpty()); 167 } 168 169 ~ExternalCharacterTokenBuffer() 170 { 171 ASSERT(isEmpty()); 172 } 173 174 bool isEmpty() const { return m_current == m_end; } 175 176 bool isAll8BitData() const { return m_isAll8BitData; } 177 178 void skipAtMostOneLeadingNewline() 179 { 180 ASSERT(!isEmpty()); 181 if (*m_current == '\n') 182 ++m_current; 183 } 184 185 void skipLeadingWhitespace() 186 { 187 skipLeading<isHTMLSpace>(); 188 } 189 190 String takeLeadingWhitespace() 191 { 192 return takeLeading<isHTMLSpace>(); 193 } 194 195 void skipLeadingNonWhitespace() 196 { 197 skipLeading<isNotHTMLSpace>(); 198 } 199 200 String takeRemaining() 201 { 202 ASSERT(!isEmpty()); 203 const UChar* start = m_current; 204 m_current = m_end; 205 size_t length = m_current - start; 206 207 if (isAll8BitData()) 208 return String::make8BitFrom16BitSource(start, length); 209 210 return String(start, length); 211 } 212 213 void giveRemainingTo(StringBuilder& recipient) 214 { 215 recipient.append(m_current, m_end - m_current); 216 m_current = m_end; 217 } 218 219 String takeRemainingWhitespace() 220 { 221 ASSERT(!isEmpty()); 222 Vector<UChar> whitespace; 223 do { 224 UChar cc = *m_current++; 225 if (isHTMLSpace(cc)) 226 whitespace.append(cc); 227 } while (m_current < m_end); 228 // Returning the null string when there aren't any whitespace 229 // characters is slightly cleaner semantically because we don't want 230 // to insert a text node (as opposed to inserting an empty text node). 231 if (whitespace.isEmpty()) 232 return String(); 233 return String::adopt(whitespace); 234 } 235 236private: 237 template<bool characterPredicate(UChar)> 238 void skipLeading() 239 { 240 ASSERT(!isEmpty()); 241 while (characterPredicate(*m_current)) { 242 if (++m_current == m_end) 243 return; 244 } 245 } 246 247 template<bool characterPredicate(UChar)> 248 String takeLeading() 249 { 250 ASSERT(!isEmpty()); 251 const UChar* start = m_current; 252 skipLeading<characterPredicate>(); 253 if (start == m_current) 254 return String(); 255 if (isAll8BitData()) 256 return String::make8BitFrom16BitSource(start, m_current - start); 257 return String(start, m_current - start); 258 } 259 260 const UChar* m_current; 261 const UChar* m_end; 262 bool m_isAll8BitData; 263}; 264 265 266HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, HTMLDocument* document, ParserContentPolicy parserContentPolicy, bool, const HTMLParserOptions& options) 267 : m_framesetOk(true) 268#ifndef NDEBUG 269 , m_isAttached(true) 270#endif 271 , m_tree(document, parserContentPolicy, options.maximumDOMTreeDepth) 272 , m_insertionMode(InitialMode) 273 , m_originalInsertionMode(InitialMode) 274 , m_shouldSkipLeadingNewline(false) 275 , m_parser(parser) 276 , m_scriptToProcessStartPosition(uninitializedPositionValue1()) 277 , m_options(options) 278{ 279} 280 281// FIXME: Member variables should be grouped into self-initializing structs to 282// minimize code duplication between these constructors. 283HTMLTreeBuilder::HTMLTreeBuilder(HTMLDocumentParser* parser, DocumentFragment* fragment, Element* contextElement, ParserContentPolicy parserContentPolicy, const HTMLParserOptions& options) 284 : m_framesetOk(true) 285#ifndef NDEBUG 286 , m_isAttached(true) 287#endif 288 , m_fragmentContext(fragment, contextElement) 289 , m_tree(fragment, parserContentPolicy, options.maximumDOMTreeDepth) 290 , m_insertionMode(InitialMode) 291 , m_originalInsertionMode(InitialMode) 292 , m_shouldSkipLeadingNewline(false) 293 , m_parser(parser) 294 , m_scriptToProcessStartPosition(uninitializedPositionValue1()) 295 , m_options(options) 296{ 297 ASSERT(isMainThread()); 298 // FIXME: This assertion will become invalid if <http://webkit.org/b/60316> is fixed. 299 ASSERT(contextElement); 300 if (contextElement) { 301 // Steps 4.2-4.6 of the HTML5 Fragment Case parsing algorithm: 302 // http://www.whatwg.org/specs/web-apps/current-work/multipage/the-end.html#fragment-case 303 // For efficiency, we skip step 4.2 ("Let root be a new html element with no attributes") 304 // and instead use the DocumentFragment as a root node. 305 m_tree.openElements()->pushRootNode(HTMLStackItem::create(fragment, HTMLStackItem::ItemForDocumentFragmentNode)); 306 307#if ENABLE(TEMPLATE_ELEMENT) 308 if (contextElement->hasTagName(templateTag)) 309 m_templateInsertionModes.append(TemplateContentsMode); 310#endif 311 312 resetInsertionModeAppropriately(); 313 m_tree.setForm(closestFormAncestor(contextElement)); 314 } 315} 316 317HTMLTreeBuilder::~HTMLTreeBuilder() 318{ 319} 320 321void HTMLTreeBuilder::detach() 322{ 323#ifndef NDEBUG 324 // This call makes little sense in fragment mode, but for consistency 325 // DocumentParser expects detach() to always be called before it's destroyed. 326 m_isAttached = false; 327#endif 328 // HTMLConstructionSite might be on the callstack when detach() is called 329 // otherwise we'd just call m_tree.clear() here instead. 330 m_tree.detach(); 331} 332 333HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext() 334 : m_fragment(0) 335 , m_contextElement(0) 336{ 337} 338 339HTMLTreeBuilder::FragmentParsingContext::FragmentParsingContext(DocumentFragment* fragment, Element* contextElement) 340 : m_fragment(fragment) 341 , m_contextElement(contextElement) 342{ 343 ASSERT(!fragment->hasChildNodes()); 344} 345 346HTMLTreeBuilder::FragmentParsingContext::~FragmentParsingContext() 347{ 348} 349 350PassRefPtr<Element> HTMLTreeBuilder::takeScriptToProcess(TextPosition& scriptStartPosition) 351{ 352 ASSERT(m_scriptToProcess); 353 // Unpause ourselves, callers may pause us again when processing the script. 354 // The HTML5 spec is written as though scripts are executed inside the tree 355 // builder. We pause the parser to exit the tree builder, and then resume 356 // before running scripts. 357 scriptStartPosition = m_scriptToProcessStartPosition; 358 m_scriptToProcessStartPosition = uninitializedPositionValue1(); 359 return m_scriptToProcess.release(); 360} 361 362void HTMLTreeBuilder::constructTree(AtomicHTMLToken* token) 363{ 364 if (shouldProcessTokenInForeignContent(token)) 365 processTokenInForeignContent(token); 366 else 367 processToken(token); 368 369 if (m_parser->tokenizer()) { 370 bool inForeignContent = !m_tree.isEmpty() 371 && !m_tree.currentStackItem()->isInHTMLNamespace() 372 && !HTMLElementStack::isHTMLIntegrationPoint(m_tree.currentStackItem()) 373 && !HTMLElementStack::isMathMLTextIntegrationPoint(m_tree.currentStackItem()); 374 375 m_parser->tokenizer()->setForceNullCharacterReplacement(m_insertionMode == TextMode || inForeignContent); 376 m_parser->tokenizer()->setShouldAllowCDATA(inForeignContent); 377 } 378 379 m_tree.executeQueuedTasks(); 380 // We might be detached now. 381} 382 383void HTMLTreeBuilder::processToken(AtomicHTMLToken* token) 384{ 385 switch (token->type()) { 386 case HTMLToken::Uninitialized: 387 ASSERT_NOT_REACHED(); 388 break; 389 case HTMLToken::DOCTYPE: 390 m_shouldSkipLeadingNewline = false; 391 processDoctypeToken(token); 392 break; 393 case HTMLToken::StartTag: 394 m_shouldSkipLeadingNewline = false; 395 processStartTag(token); 396 break; 397 case HTMLToken::EndTag: 398 m_shouldSkipLeadingNewline = false; 399 processEndTag(token); 400 break; 401 case HTMLToken::Comment: 402 m_shouldSkipLeadingNewline = false; 403 processComment(token); 404 return; 405 case HTMLToken::Character: 406 processCharacter(token); 407 break; 408 case HTMLToken::EndOfFile: 409 m_shouldSkipLeadingNewline = false; 410 processEndOfFile(token); 411 break; 412 } 413} 414 415void HTMLTreeBuilder::processDoctypeToken(AtomicHTMLToken* token) 416{ 417 ASSERT(token->type() == HTMLToken::DOCTYPE); 418 if (m_insertionMode == InitialMode) { 419 m_tree.insertDoctype(token); 420 setInsertionMode(BeforeHTMLMode); 421 return; 422 } 423 if (m_insertionMode == InTableTextMode) { 424 defaultForInTableText(); 425 processDoctypeToken(token); 426 return; 427 } 428 parseError(token); 429} 430 431void HTMLTreeBuilder::processFakeStartTag(const QualifiedName& tagName, const Vector<Attribute>& attributes) 432{ 433 // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags. 434 AtomicHTMLToken fakeToken(HTMLToken::StartTag, tagName.localName(), attributes); 435 processStartTag(&fakeToken); 436} 437 438void HTMLTreeBuilder::processFakeEndTag(const AtomicString& tagName) 439{ 440 AtomicHTMLToken fakeToken(HTMLToken::EndTag, tagName); 441 processEndTag(&fakeToken); 442} 443 444void HTMLTreeBuilder::processFakeEndTag(const QualifiedName& tagName) 445{ 446 // FIXME: We'll need a fancier conversion than just "localName" for SVG/MathML tags. 447 processFakeEndTag(tagName.localName()); 448} 449 450void HTMLTreeBuilder::processFakeCharacters(const String& characters) 451{ 452 ASSERT(!characters.isEmpty()); 453 ExternalCharacterTokenBuffer buffer(characters); 454 processCharacterBuffer(buffer); 455} 456 457void HTMLTreeBuilder::processFakePEndTagIfPInButtonScope() 458{ 459 if (!m_tree.openElements()->inButtonScope(pTag.localName())) 460 return; 461 AtomicHTMLToken endP(HTMLToken::EndTag, pTag.localName()); 462 processEndTag(&endP); 463} 464 465Vector<Attribute> HTMLTreeBuilder::attributesForIsindexInput(AtomicHTMLToken* token) 466{ 467 Vector<Attribute> attributes = token->attributes(); 468 for (int i = attributes.size() - 1; i >= 0; --i) { 469 const QualifiedName& name = attributes.at(i).name(); 470 if (name.matches(nameAttr) || name.matches(actionAttr) || name.matches(promptAttr)) 471 attributes.remove(i); 472 } 473 474 attributes.append(Attribute(nameAttr, isindexTag.localName())); 475 return attributes; 476} 477 478void HTMLTreeBuilder::processIsindexStartTagForInBody(AtomicHTMLToken* token) 479{ 480 ASSERT(token->type() == HTMLToken::StartTag); 481 ASSERT(token->name() == isindexTag); 482 parseError(token); 483 if (m_tree.form()) 484 return; 485 notImplemented(); // Acknowledge self-closing flag 486 processFakeStartTag(formTag); 487 Attribute* actionAttribute = token->getAttributeItem(actionAttr); 488 if (actionAttribute) 489 m_tree.form()->setAttribute(actionAttr, actionAttribute->value()); 490 processFakeStartTag(hrTag); 491 processFakeStartTag(labelTag); 492 Attribute* promptAttribute = token->getAttributeItem(promptAttr); 493 if (promptAttribute) 494 processFakeCharacters(promptAttribute->value()); 495 else 496 processFakeCharacters(searchableIndexIntroduction()); 497 processFakeStartTag(inputTag, attributesForIsindexInput(token)); 498 notImplemented(); // This second set of characters may be needed by non-english locales. 499 processFakeEndTag(labelTag); 500 processFakeStartTag(hrTag); 501 processFakeEndTag(formTag); 502} 503 504namespace { 505 506bool isLi(const HTMLStackItem* item) 507{ 508 return item->hasTagName(liTag); 509} 510 511bool isDdOrDt(const HTMLStackItem* item) 512{ 513 return item->hasTagName(ddTag) 514 || item->hasTagName(dtTag); 515} 516 517} 518 519template <bool shouldClose(const HTMLStackItem*)> 520void HTMLTreeBuilder::processCloseWhenNestedTag(AtomicHTMLToken* token) 521{ 522 m_framesetOk = false; 523 HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); 524 while (1) { 525 RefPtr<HTMLStackItem> item = nodeRecord->stackItem(); 526 if (shouldClose(item.get())) { 527 ASSERT(item->isElementNode()); 528 processFakeEndTag(item->localName()); 529 break; 530 } 531 if (item->isSpecialNode() && !item->hasTagName(addressTag) && !item->hasTagName(divTag) && !item->hasTagName(pTag)) 532 break; 533 nodeRecord = nodeRecord->next(); 534 } 535 processFakePEndTagIfPInButtonScope(); 536 m_tree.insertHTMLElement(token); 537} 538 539typedef HashMap<AtomicString, QualifiedName> PrefixedNameToQualifiedNameMap; 540 541static void mapLoweredLocalNameToName(PrefixedNameToQualifiedNameMap* map, QualifiedName** names, size_t length) 542{ 543 for (size_t i = 0; i < length; ++i) { 544 const QualifiedName& name = *names[i]; 545 const AtomicString& localName = name.localName(); 546 AtomicString loweredLocalName = localName.lower(); 547 if (loweredLocalName != localName) 548 map->add(loweredLocalName, name); 549 } 550} 551 552static void adjustSVGTagNameCase(AtomicHTMLToken* token) 553{ 554 static PrefixedNameToQualifiedNameMap* caseMap = 0; 555 if (!caseMap) { 556 caseMap = new PrefixedNameToQualifiedNameMap; 557 QualifiedName** svgTags = SVGNames::getSVGTags(); 558 mapLoweredLocalNameToName(caseMap, svgTags, SVGNames::SVGTagsCount); 559 } 560 561 const QualifiedName& casedName = caseMap->get(token->name()); 562 if (casedName.localName().isNull()) 563 return; 564 token->setName(casedName.localName()); 565} 566 567template<QualifiedName** getAttrs(), unsigned length> 568static void adjustAttributes(AtomicHTMLToken* token) 569{ 570 static PrefixedNameToQualifiedNameMap* caseMap = 0; 571 if (!caseMap) { 572 caseMap = new PrefixedNameToQualifiedNameMap; 573 QualifiedName** attrs = getAttrs(); 574 mapLoweredLocalNameToName(caseMap, attrs, length); 575 } 576 577 for (unsigned i = 0; i < token->attributes().size(); ++i) { 578 Attribute& tokenAttribute = token->attributes().at(i); 579 const QualifiedName& casedName = caseMap->get(tokenAttribute.localName()); 580 if (!casedName.localName().isNull()) 581 tokenAttribute.parserSetName(casedName); 582 } 583} 584 585static void adjustSVGAttributes(AtomicHTMLToken* token) 586{ 587 adjustAttributes<SVGNames::getSVGAttrs, SVGNames::SVGAttrsCount>(token); 588} 589 590static void adjustMathMLAttributes(AtomicHTMLToken* token) 591{ 592 adjustAttributes<MathMLNames::getMathMLAttrs, MathMLNames::MathMLAttrsCount>(token); 593} 594 595static void addNamesWithPrefix(PrefixedNameToQualifiedNameMap* map, const AtomicString& prefix, QualifiedName** names, size_t length) 596{ 597 for (size_t i = 0; i < length; ++i) { 598 QualifiedName* name = names[i]; 599 const AtomicString& localName = name->localName(); 600 AtomicString prefixColonLocalName = prefix + ':' + localName; 601 QualifiedName nameWithPrefix(prefix, localName, name->namespaceURI()); 602 map->add(prefixColonLocalName, nameWithPrefix); 603 } 604} 605 606static void adjustForeignAttributes(AtomicHTMLToken* token) 607{ 608 static PrefixedNameToQualifiedNameMap* map = 0; 609 if (!map) { 610 map = new PrefixedNameToQualifiedNameMap; 611 612 QualifiedName** attrs = XLinkNames::getXLinkAttrs(); 613 addNamesWithPrefix(map, xlinkAtom, attrs, XLinkNames::XLinkAttrsCount); 614 615 attrs = XMLNames::getXMLAttrs(); 616 addNamesWithPrefix(map, xmlAtom, attrs, XMLNames::XMLAttrsCount); 617 618 map->add(WTF::xmlnsAtom, XMLNSNames::xmlnsAttr); 619 map->add("xmlns:xlink", QualifiedName(xmlnsAtom, xlinkAtom, XMLNSNames::xmlnsNamespaceURI)); 620 } 621 622 for (unsigned i = 0; i < token->attributes().size(); ++i) { 623 Attribute& tokenAttribute = token->attributes().at(i); 624 const QualifiedName& name = map->get(tokenAttribute.localName()); 625 if (!name.localName().isNull()) 626 tokenAttribute.parserSetName(name); 627 } 628} 629 630void HTMLTreeBuilder::processStartTagForInBody(AtomicHTMLToken* token) 631{ 632 ASSERT(token->type() == HTMLToken::StartTag); 633 if (token->name() == htmlTag) { 634 processHtmlStartTagForInBody(token); 635 return; 636 } 637 if (token->name() == baseTag 638 || token->name() == basefontTag 639 || token->name() == bgsoundTag 640 || token->name() == commandTag 641 || token->name() == linkTag 642 || token->name() == metaTag 643 || token->name() == noframesTag 644 || token->name() == scriptTag 645 || token->name() == styleTag 646 || token->name() == titleTag) { 647 bool didProcess = processStartTagForInHead(token); 648 ASSERT_UNUSED(didProcess, didProcess); 649 return; 650 } 651 if (token->name() == bodyTag) { 652 parseError(token); 653 bool fragmentOrTemplateCase = !m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement(); 654#if ENABLE(TEMPLATE_ELEMENT) 655 fragmentOrTemplateCase = fragmentOrTemplateCase || m_tree.openElements()->hasTemplateInHTMLScope(); 656#endif 657 if (fragmentOrTemplateCase) { 658 ASSERT(isParsingFragmentOrTemplateContents()); 659 return; 660 } 661 m_framesetOk = false; 662 m_tree.insertHTMLBodyStartTagInBody(token); 663 return; 664 } 665 if (token->name() == framesetTag) { 666 parseError(token); 667 if (!m_tree.openElements()->secondElementIsHTMLBodyElement() || m_tree.openElements()->hasOnlyOneElement()) { 668 ASSERT(isParsingFragmentOrTemplateContents()); 669 return; 670 } 671 if (!m_framesetOk) 672 return; 673 m_tree.openElements()->bodyElement()->remove(ASSERT_NO_EXCEPTION); 674 m_tree.openElements()->popUntil(m_tree.openElements()->bodyElement()); 675 m_tree.openElements()->popHTMLBodyElement(); 676 ASSERT(m_tree.openElements()->top() == m_tree.openElements()->htmlElement()); 677 m_tree.insertHTMLElement(token); 678 setInsertionMode(InFramesetMode); 679 return; 680 } 681 if (token->name() == addressTag 682 || token->name() == articleTag 683 || token->name() == asideTag 684 || token->name() == blockquoteTag 685 || token->name() == centerTag 686 || token->name() == detailsTag 687 || token->name() == dirTag 688 || token->name() == divTag 689 || token->name() == dlTag 690 || token->name() == fieldsetTag 691 || token->name() == figcaptionTag 692 || token->name() == figureTag 693 || token->name() == footerTag 694 || token->name() == headerTag 695 || token->name() == hgroupTag 696 || token->name() == mainTag 697 || token->name() == menuTag 698 || token->name() == navTag 699 || token->name() == olTag 700 || token->name() == pTag 701 || token->name() == sectionTag 702 || token->name() == summaryTag 703 || token->name() == ulTag) { 704 processFakePEndTagIfPInButtonScope(); 705 m_tree.insertHTMLElement(token); 706 return; 707 } 708 if (isNumberedHeaderTag(token->name())) { 709 processFakePEndTagIfPInButtonScope(); 710 if (m_tree.currentStackItem()->isNumberedHeaderElement()) { 711 parseError(token); 712 m_tree.openElements()->pop(); 713 } 714 m_tree.insertHTMLElement(token); 715 return; 716 } 717 if (token->name() == preTag || token->name() == listingTag) { 718 processFakePEndTagIfPInButtonScope(); 719 m_tree.insertHTMLElement(token); 720 m_shouldSkipLeadingNewline = true; 721 m_framesetOk = false; 722 return; 723 } 724 if (token->name() == formTag) { 725 if (m_tree.form()) { 726 parseError(token); 727 return; 728 } 729 processFakePEndTagIfPInButtonScope(); 730 m_tree.insertHTMLFormElement(token); 731 return; 732 } 733 if (token->name() == liTag) { 734 processCloseWhenNestedTag<isLi>(token); 735 return; 736 } 737 if (token->name() == ddTag || token->name() == dtTag) { 738 processCloseWhenNestedTag<isDdOrDt>(token); 739 return; 740 } 741 if (token->name() == plaintextTag) { 742 processFakePEndTagIfPInButtonScope(); 743 m_tree.insertHTMLElement(token); 744 if (m_parser->tokenizer()) 745 m_parser->tokenizer()->setState(HTMLTokenizer::PLAINTEXTState); 746 return; 747 } 748 if (token->name() == buttonTag) { 749 if (m_tree.openElements()->inScope(buttonTag)) { 750 parseError(token); 751 processFakeEndTag(buttonTag); 752 processStartTag(token); // FIXME: Could we just fall through here? 753 return; 754 } 755 m_tree.reconstructTheActiveFormattingElements(); 756 m_tree.insertHTMLElement(token); 757 m_framesetOk = false; 758 return; 759 } 760 if (token->name() == aTag) { 761 Element* activeATag = m_tree.activeFormattingElements()->closestElementInScopeWithName(aTag.localName()); 762 if (activeATag) { 763 parseError(token); 764 processFakeEndTag(aTag); 765 m_tree.activeFormattingElements()->remove(activeATag); 766 if (m_tree.openElements()->contains(activeATag)) 767 m_tree.openElements()->remove(activeATag); 768 } 769 m_tree.reconstructTheActiveFormattingElements(); 770 m_tree.insertFormattingElement(token); 771 return; 772 } 773 if (isNonAnchorNonNobrFormattingTag(token->name())) { 774 m_tree.reconstructTheActiveFormattingElements(); 775 m_tree.insertFormattingElement(token); 776 return; 777 } 778 if (token->name() == nobrTag) { 779 m_tree.reconstructTheActiveFormattingElements(); 780 if (m_tree.openElements()->inScope(nobrTag)) { 781 parseError(token); 782 processFakeEndTag(nobrTag); 783 m_tree.reconstructTheActiveFormattingElements(); 784 } 785 m_tree.insertFormattingElement(token); 786 return; 787 } 788 if (token->name() == appletTag 789 || token->name() == embedTag 790 || token->name() == objectTag) { 791 if (!pluginContentIsAllowed(m_tree.parserContentPolicy())) 792 return; 793 } 794 if (token->name() == appletTag 795 || token->name() == marqueeTag 796 || token->name() == objectTag) { 797 m_tree.reconstructTheActiveFormattingElements(); 798 m_tree.insertHTMLElement(token); 799 m_tree.activeFormattingElements()->appendMarker(); 800 m_framesetOk = false; 801 return; 802 } 803 if (token->name() == tableTag) { 804 if (!m_tree.inQuirksMode() && m_tree.openElements()->inButtonScope(pTag)) 805 processFakeEndTag(pTag); 806 m_tree.insertHTMLElement(token); 807 m_framesetOk = false; 808 setInsertionMode(InTableMode); 809 return; 810 } 811 if (token->name() == imageTag) { 812 parseError(token); 813 // Apparently we're not supposed to ask. 814 token->setName(imgTag.localName()); 815 // Note the fall through to the imgTag handling below! 816 } 817 if (token->name() == areaTag 818 || token->name() == brTag 819 || token->name() == embedTag 820 || token->name() == imgTag 821 || token->name() == keygenTag 822 || token->name() == wbrTag) { 823 m_tree.reconstructTheActiveFormattingElements(); 824 m_tree.insertSelfClosingHTMLElement(token); 825 m_framesetOk = false; 826 return; 827 } 828 if (token->name() == inputTag) { 829 Attribute* typeAttribute = token->getAttributeItem(typeAttr); 830 m_tree.reconstructTheActiveFormattingElements(); 831 m_tree.insertSelfClosingHTMLElement(token); 832 if (!typeAttribute || !equalIgnoringCase(typeAttribute->value(), "hidden")) 833 m_framesetOk = false; 834 return; 835 } 836 if (token->name() == paramTag 837 || token->name() == sourceTag 838 || token->name() == trackTag) { 839 m_tree.insertSelfClosingHTMLElement(token); 840 return; 841 } 842 if (token->name() == hrTag) { 843 processFakePEndTagIfPInButtonScope(); 844 m_tree.insertSelfClosingHTMLElement(token); 845 m_framesetOk = false; 846 return; 847 } 848 if (token->name() == isindexTag) { 849 processIsindexStartTagForInBody(token); 850 return; 851 } 852 if (token->name() == textareaTag) { 853 m_tree.insertHTMLElement(token); 854 m_shouldSkipLeadingNewline = true; 855 if (m_parser->tokenizer()) 856 m_parser->tokenizer()->setState(HTMLTokenizer::RCDATAState); 857 m_originalInsertionMode = m_insertionMode; 858 m_framesetOk = false; 859 setInsertionMode(TextMode); 860 return; 861 } 862 if (token->name() == xmpTag) { 863 processFakePEndTagIfPInButtonScope(); 864 m_tree.reconstructTheActiveFormattingElements(); 865 m_framesetOk = false; 866 processGenericRawTextStartTag(token); 867 return; 868 } 869 if (token->name() == iframeTag) { 870 m_framesetOk = false; 871 processGenericRawTextStartTag(token); 872 return; 873 } 874 if (token->name() == noembedTag && m_options.pluginsEnabled) { 875 processGenericRawTextStartTag(token); 876 return; 877 } 878 if (token->name() == noscriptTag && m_options.scriptEnabled) { 879 processGenericRawTextStartTag(token); 880 return; 881 } 882 if (token->name() == selectTag) { 883 m_tree.reconstructTheActiveFormattingElements(); 884 m_tree.insertHTMLElement(token); 885 m_framesetOk = false; 886 if (m_insertionMode == InTableMode 887 || m_insertionMode == InCaptionMode 888 || m_insertionMode == InColumnGroupMode 889 || m_insertionMode == InTableBodyMode 890 || m_insertionMode == InRowMode 891 || m_insertionMode == InCellMode) 892 setInsertionMode(InSelectInTableMode); 893 else 894 setInsertionMode(InSelectMode); 895 return; 896 } 897 if (token->name() == optgroupTag || token->name() == optionTag) { 898 if (m_tree.currentStackItem()->hasTagName(optionTag)) { 899 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); 900 processEndTag(&endOption); 901 } 902 m_tree.reconstructTheActiveFormattingElements(); 903 m_tree.insertHTMLElement(token); 904 return; 905 } 906 if (token->name() == rpTag || token->name() == rtTag) { 907 if (m_tree.openElements()->inScope(rubyTag.localName())) { 908 m_tree.generateImpliedEndTags(); 909 if (!m_tree.currentStackItem()->hasTagName(rubyTag)) 910 parseError(token); 911 } 912 m_tree.insertHTMLElement(token); 913 return; 914 } 915 if (token->name() == MathMLNames::mathTag.localName()) { 916 m_tree.reconstructTheActiveFormattingElements(); 917 adjustMathMLAttributes(token); 918 adjustForeignAttributes(token); 919 m_tree.insertForeignElement(token, MathMLNames::mathmlNamespaceURI); 920 return; 921 } 922 if (token->name() == SVGNames::svgTag.localName()) { 923 m_tree.reconstructTheActiveFormattingElements(); 924 adjustSVGAttributes(token); 925 adjustForeignAttributes(token); 926 m_tree.insertForeignElement(token, SVGNames::svgNamespaceURI); 927 return; 928 } 929 if (isCaptionColOrColgroupTag(token->name()) 930 || token->name() == frameTag 931 || token->name() == headTag 932 || isTableBodyContextTag(token->name()) 933 || isTableCellContextTag(token->name()) 934 || token->name() == trTag) { 935 parseError(token); 936 return; 937 } 938#if ENABLE(TEMPLATE_ELEMENT) 939 if (token->name() == templateTag) { 940 processTemplateStartTag(token); 941 return; 942 } 943#endif 944 m_tree.reconstructTheActiveFormattingElements(); 945 m_tree.insertHTMLElement(token); 946} 947 948#if ENABLE(TEMPLATE_ELEMENT) 949void HTMLTreeBuilder::processTemplateStartTag(AtomicHTMLToken* token) 950{ 951 m_tree.activeFormattingElements()->appendMarker(); 952 m_tree.insertHTMLElement(token); 953 m_templateInsertionModes.append(TemplateContentsMode); 954 setInsertionMode(TemplateContentsMode); 955} 956 957bool HTMLTreeBuilder::processTemplateEndTag(AtomicHTMLToken* token) 958{ 959 ASSERT(token->name() == templateTag.localName()); 960 if (!m_tree.openElements()->hasTemplateInHTMLScope()) { 961 ASSERT(m_templateInsertionModes.isEmpty() || (m_templateInsertionModes.size() == 1 && m_fragmentContext.contextElement()->hasTagName(templateTag))); 962 parseError(token); 963 return false; 964 } 965 m_tree.generateImpliedEndTags(); 966 if (!m_tree.currentStackItem()->hasTagName(templateTag)) 967 parseError(token); 968 m_tree.openElements()->popUntilPopped(templateTag); 969 m_tree.activeFormattingElements()->clearToLastMarker(); 970 m_templateInsertionModes.removeLast(); 971 resetInsertionModeAppropriately(); 972 return true; 973} 974 975bool HTMLTreeBuilder::processEndOfFileForInTemplateContents(AtomicHTMLToken* token) 976{ 977 AtomicHTMLToken endTemplate(HTMLToken::EndTag, templateTag.localName()); 978 if (!processTemplateEndTag(&endTemplate)) 979 return false; 980 981 processEndOfFile(token); 982 return true; 983} 984#endif 985 986bool HTMLTreeBuilder::processColgroupEndTagForInColumnGroup() 987{ 988 bool ignoreFakeEndTag = m_tree.currentIsRootNode(); 989#if ENABLE(TEMPLATE_ELEMENT) 990 ignoreFakeEndTag = ignoreFakeEndTag || m_tree.currentNode()->hasTagName(templateTag); 991#endif 992 993 if (ignoreFakeEndTag) { 994 ASSERT(isParsingFragmentOrTemplateContents()); 995 // FIXME: parse error 996 return false; 997 } 998 m_tree.openElements()->pop(); 999 setInsertionMode(InTableMode); 1000 return true; 1001} 1002 1003// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#close-the-cell 1004void HTMLTreeBuilder::closeTheCell() 1005{ 1006 ASSERT(insertionMode() == InCellMode); 1007 if (m_tree.openElements()->inTableScope(tdTag)) { 1008 ASSERT(!m_tree.openElements()->inTableScope(thTag)); 1009 processFakeEndTag(tdTag); 1010 return; 1011 } 1012 ASSERT(m_tree.openElements()->inTableScope(thTag)); 1013 processFakeEndTag(thTag); 1014 ASSERT(insertionMode() == InRowMode); 1015} 1016 1017void HTMLTreeBuilder::processStartTagForInTable(AtomicHTMLToken* token) 1018{ 1019 ASSERT(token->type() == HTMLToken::StartTag); 1020 if (token->name() == captionTag) { 1021 m_tree.openElements()->popUntilTableScopeMarker(); 1022 m_tree.activeFormattingElements()->appendMarker(); 1023 m_tree.insertHTMLElement(token); 1024 setInsertionMode(InCaptionMode); 1025 return; 1026 } 1027 if (token->name() == colgroupTag) { 1028 m_tree.openElements()->popUntilTableScopeMarker(); 1029 m_tree.insertHTMLElement(token); 1030 setInsertionMode(InColumnGroupMode); 1031 return; 1032 } 1033 if (token->name() == colTag) { 1034 processFakeStartTag(colgroupTag); 1035 ASSERT(InColumnGroupMode); 1036 processStartTag(token); 1037 return; 1038 } 1039 if (isTableBodyContextTag(token->name())) { 1040 m_tree.openElements()->popUntilTableScopeMarker(); 1041 m_tree.insertHTMLElement(token); 1042 setInsertionMode(InTableBodyMode); 1043 return; 1044 } 1045 if (isTableCellContextTag(token->name()) 1046 || token->name() == trTag) { 1047 processFakeStartTag(tbodyTag); 1048 ASSERT(insertionMode() == InTableBodyMode); 1049 processStartTag(token); 1050 return; 1051 } 1052 if (token->name() == tableTag) { 1053 parseError(token); 1054 if (!processTableEndTagForInTable()) { 1055 ASSERT(isParsingFragmentOrTemplateContents()); 1056 return; 1057 } 1058 processStartTag(token); 1059 return; 1060 } 1061 if (token->name() == styleTag || token->name() == scriptTag) { 1062 processStartTagForInHead(token); 1063 return; 1064 } 1065 if (token->name() == inputTag) { 1066 Attribute* typeAttribute = token->getAttributeItem(typeAttr); 1067 if (typeAttribute && equalIgnoringCase(typeAttribute->value(), "hidden")) { 1068 parseError(token); 1069 m_tree.insertSelfClosingHTMLElement(token); 1070 return; 1071 } 1072 // Fall through to "anything else" case. 1073 } 1074 if (token->name() == formTag) { 1075 parseError(token); 1076 if (m_tree.form()) 1077 return; 1078 m_tree.insertHTMLFormElement(token, true); 1079 m_tree.openElements()->pop(); 1080 return; 1081 } 1082#if ENABLE(TEMPLATE_ELEMENT) 1083 if (token->name() == templateTag) { 1084 processTemplateStartTag(token); 1085 return; 1086 } 1087#endif 1088 parseError(token); 1089 HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); 1090 processStartTagForInBody(token); 1091} 1092 1093void HTMLTreeBuilder::processStartTag(AtomicHTMLToken* token) 1094{ 1095 ASSERT(token->type() == HTMLToken::StartTag); 1096 switch (insertionMode()) { 1097 case InitialMode: 1098 ASSERT(insertionMode() == InitialMode); 1099 defaultForInitial(); 1100 // Fall through. 1101 case BeforeHTMLMode: 1102 ASSERT(insertionMode() == BeforeHTMLMode); 1103 if (token->name() == htmlTag) { 1104 m_tree.insertHTMLHtmlStartTagBeforeHTML(token); 1105 setInsertionMode(BeforeHeadMode); 1106 return; 1107 } 1108 defaultForBeforeHTML(); 1109 // Fall through. 1110 case BeforeHeadMode: 1111 ASSERT(insertionMode() == BeforeHeadMode); 1112 if (token->name() == htmlTag) { 1113 processHtmlStartTagForInBody(token); 1114 return; 1115 } 1116 if (token->name() == headTag) { 1117 m_tree.insertHTMLHeadElement(token); 1118 setInsertionMode(InHeadMode); 1119 return; 1120 } 1121 defaultForBeforeHead(); 1122 // Fall through. 1123 case InHeadMode: 1124 ASSERT(insertionMode() == InHeadMode); 1125 if (processStartTagForInHead(token)) 1126 return; 1127 defaultForInHead(); 1128 // Fall through. 1129 case AfterHeadMode: 1130 ASSERT(insertionMode() == AfterHeadMode); 1131 if (token->name() == htmlTag) { 1132 processHtmlStartTagForInBody(token); 1133 return; 1134 } 1135 if (token->name() == bodyTag) { 1136 m_framesetOk = false; 1137 m_tree.insertHTMLBodyElement(token); 1138 setInsertionMode(InBodyMode); 1139 return; 1140 } 1141 if (token->name() == framesetTag) { 1142 m_tree.insertHTMLElement(token); 1143 setInsertionMode(InFramesetMode); 1144 return; 1145 } 1146 if (token->name() == baseTag 1147 || token->name() == basefontTag 1148 || token->name() == bgsoundTag 1149 || token->name() == linkTag 1150 || token->name() == metaTag 1151 || token->name() == noframesTag 1152 || token->name() == scriptTag 1153 || token->name() == styleTag 1154 || token->name() == titleTag) { 1155 parseError(token); 1156 ASSERT(m_tree.head()); 1157 m_tree.openElements()->pushHTMLHeadElement(m_tree.headStackItem()); 1158 processStartTagForInHead(token); 1159 m_tree.openElements()->removeHTMLHeadElement(m_tree.head()); 1160 return; 1161 } 1162 if (token->name() == headTag) { 1163 parseError(token); 1164 return; 1165 } 1166 defaultForAfterHead(); 1167 // Fall through 1168 case InBodyMode: 1169 ASSERT(insertionMode() == InBodyMode); 1170 processStartTagForInBody(token); 1171 break; 1172 case InTableMode: 1173 ASSERT(insertionMode() == InTableMode); 1174 processStartTagForInTable(token); 1175 break; 1176 case InCaptionMode: 1177 ASSERT(insertionMode() == InCaptionMode); 1178 if (isCaptionColOrColgroupTag(token->name()) 1179 || isTableBodyContextTag(token->name()) 1180 || isTableCellContextTag(token->name()) 1181 || token->name() == trTag) { 1182 parseError(token); 1183 if (!processCaptionEndTagForInCaption()) { 1184 ASSERT(isParsingFragment()); 1185 return; 1186 } 1187 processStartTag(token); 1188 return; 1189 } 1190 processStartTagForInBody(token); 1191 break; 1192 case InColumnGroupMode: 1193 ASSERT(insertionMode() == InColumnGroupMode); 1194 if (token->name() == htmlTag) { 1195 processHtmlStartTagForInBody(token); 1196 return; 1197 } 1198 if (token->name() == colTag) { 1199 m_tree.insertSelfClosingHTMLElement(token); 1200 return; 1201 } 1202#if ENABLE(TEMPLATE_ELEMENT) 1203 if (token->name() == templateTag) { 1204 processTemplateStartTag(token); 1205 return; 1206 } 1207#endif 1208 if (!processColgroupEndTagForInColumnGroup()) { 1209 ASSERT(isParsingFragmentOrTemplateContents()); 1210 return; 1211 } 1212 processStartTag(token); 1213 break; 1214 case InTableBodyMode: 1215 ASSERT(insertionMode() == InTableBodyMode); 1216 if (token->name() == trTag) { 1217 m_tree.openElements()->popUntilTableBodyScopeMarker(); // How is there ever anything to pop? 1218 m_tree.insertHTMLElement(token); 1219 setInsertionMode(InRowMode); 1220 return; 1221 } 1222 if (isTableCellContextTag(token->name())) { 1223 parseError(token); 1224 processFakeStartTag(trTag); 1225 ASSERT(insertionMode() == InRowMode); 1226 processStartTag(token); 1227 return; 1228 } 1229 if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name())) { 1230 // FIXME: This is slow. 1231 if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) { 1232 ASSERT(isParsingFragmentOrTemplateContents()); 1233 parseError(token); 1234 return; 1235 } 1236 m_tree.openElements()->popUntilTableBodyScopeMarker(); 1237 ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName())); 1238 processFakeEndTag(m_tree.currentStackItem()->localName()); 1239 processStartTag(token); 1240 return; 1241 } 1242 processStartTagForInTable(token); 1243 break; 1244 case InRowMode: 1245 ASSERT(insertionMode() == InRowMode); 1246 if (isTableCellContextTag(token->name())) { 1247 m_tree.openElements()->popUntilTableRowScopeMarker(); 1248 m_tree.insertHTMLElement(token); 1249 setInsertionMode(InCellMode); 1250 m_tree.activeFormattingElements()->appendMarker(); 1251 return; 1252 } 1253 if (token->name() == trTag 1254 || isCaptionColOrColgroupTag(token->name()) 1255 || isTableBodyContextTag(token->name())) { 1256 if (!processTrEndTagForInRow()) { 1257 ASSERT(isParsingFragmentOrTemplateContents()); 1258 return; 1259 } 1260 ASSERT(insertionMode() == InTableBodyMode); 1261 processStartTag(token); 1262 return; 1263 } 1264 processStartTagForInTable(token); 1265 break; 1266 case InCellMode: 1267 ASSERT(insertionMode() == InCellMode); 1268 if (isCaptionColOrColgroupTag(token->name()) 1269 || isTableCellContextTag(token->name()) 1270 || token->name() == trTag 1271 || isTableBodyContextTag(token->name())) { 1272 // FIXME: This could be more efficient. 1273 if (!m_tree.openElements()->inTableScope(tdTag) && !m_tree.openElements()->inTableScope(thTag)) { 1274 ASSERT(isParsingFragment()); 1275 parseError(token); 1276 return; 1277 } 1278 closeTheCell(); 1279 processStartTag(token); 1280 return; 1281 } 1282 processStartTagForInBody(token); 1283 break; 1284 case AfterBodyMode: 1285 case AfterAfterBodyMode: 1286 ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode); 1287 if (token->name() == htmlTag) { 1288 processHtmlStartTagForInBody(token); 1289 return; 1290 } 1291 setInsertionMode(InBodyMode); 1292 processStartTag(token); 1293 break; 1294 case InHeadNoscriptMode: 1295 ASSERT(insertionMode() == InHeadNoscriptMode); 1296 if (token->name() == htmlTag) { 1297 processHtmlStartTagForInBody(token); 1298 return; 1299 } 1300 if (token->name() == basefontTag 1301 || token->name() == bgsoundTag 1302 || token->name() == linkTag 1303 || token->name() == metaTag 1304 || token->name() == noframesTag 1305 || token->name() == styleTag) { 1306 bool didProcess = processStartTagForInHead(token); 1307 ASSERT_UNUSED(didProcess, didProcess); 1308 return; 1309 } 1310 if (token->name() == htmlTag || token->name() == noscriptTag) { 1311 parseError(token); 1312 return; 1313 } 1314 defaultForInHeadNoscript(); 1315 processToken(token); 1316 break; 1317 case InFramesetMode: 1318 ASSERT(insertionMode() == InFramesetMode); 1319 if (token->name() == htmlTag) { 1320 processHtmlStartTagForInBody(token); 1321 return; 1322 } 1323 if (token->name() == framesetTag) { 1324 m_tree.insertHTMLElement(token); 1325 return; 1326 } 1327 if (token->name() == frameTag) { 1328 m_tree.insertSelfClosingHTMLElement(token); 1329 return; 1330 } 1331 if (token->name() == noframesTag) { 1332 processStartTagForInHead(token); 1333 return; 1334 } 1335#if ENABLE(TEMPLATE_ELEMENT) 1336 if (token->name() == templateTag) { 1337 processTemplateStartTag(token); 1338 return; 1339 } 1340#endif 1341 parseError(token); 1342 break; 1343 case AfterFramesetMode: 1344 case AfterAfterFramesetMode: 1345 ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode); 1346 if (token->name() == htmlTag) { 1347 processHtmlStartTagForInBody(token); 1348 return; 1349 } 1350 if (token->name() == noframesTag) { 1351 processStartTagForInHead(token); 1352 return; 1353 } 1354 parseError(token); 1355 break; 1356 case InSelectInTableMode: 1357 ASSERT(insertionMode() == InSelectInTableMode); 1358 if (token->name() == captionTag 1359 || token->name() == tableTag 1360 || isTableBodyContextTag(token->name()) 1361 || token->name() == trTag 1362 || isTableCellContextTag(token->name())) { 1363 parseError(token); 1364 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); 1365 processEndTag(&endSelect); 1366 processStartTag(token); 1367 return; 1368 } 1369 // Fall through 1370 case InSelectMode: 1371 ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode); 1372 if (token->name() == htmlTag) { 1373 processHtmlStartTagForInBody(token); 1374 return; 1375 } 1376 if (token->name() == optionTag) { 1377 if (m_tree.currentStackItem()->hasTagName(optionTag)) { 1378 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); 1379 processEndTag(&endOption); 1380 } 1381 m_tree.insertHTMLElement(token); 1382 return; 1383 } 1384 if (token->name() == optgroupTag) { 1385 if (m_tree.currentStackItem()->hasTagName(optionTag)) { 1386 AtomicHTMLToken endOption(HTMLToken::EndTag, optionTag.localName()); 1387 processEndTag(&endOption); 1388 } 1389 if (m_tree.currentStackItem()->hasTagName(optgroupTag)) { 1390 AtomicHTMLToken endOptgroup(HTMLToken::EndTag, optgroupTag.localName()); 1391 processEndTag(&endOptgroup); 1392 } 1393 m_tree.insertHTMLElement(token); 1394 return; 1395 } 1396 if (token->name() == selectTag) { 1397 parseError(token); 1398 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); 1399 processEndTag(&endSelect); 1400 return; 1401 } 1402 if (token->name() == inputTag 1403 || token->name() == keygenTag 1404 || token->name() == textareaTag) { 1405 parseError(token); 1406 if (!m_tree.openElements()->inSelectScope(selectTag)) { 1407 ASSERT(isParsingFragment()); 1408 return; 1409 } 1410 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); 1411 processEndTag(&endSelect); 1412 processStartTag(token); 1413 return; 1414 } 1415 if (token->name() == scriptTag) { 1416 bool didProcess = processStartTagForInHead(token); 1417 ASSERT_UNUSED(didProcess, didProcess); 1418 return; 1419 } 1420#if ENABLE(TEMPLATE_ELEMENT) 1421 if (token->name() == templateTag) { 1422 processTemplateStartTag(token); 1423 return; 1424 } 1425#endif 1426 break; 1427 case InTableTextMode: 1428 defaultForInTableText(); 1429 processStartTag(token); 1430 break; 1431 case TextMode: 1432 ASSERT_NOT_REACHED(); 1433 break; 1434 case TemplateContentsMode: 1435#if ENABLE(TEMPLATE_ELEMENT) 1436 if (token->name() == templateTag) { 1437 processTemplateStartTag(token); 1438 return; 1439 } 1440 1441 if (token->name() == linkTag 1442 || token->name() == scriptTag 1443 || token->name() == styleTag 1444 || token->name() == metaTag) { 1445 processStartTagForInHead(token); 1446 return; 1447 } 1448 1449 InsertionMode insertionMode = TemplateContentsMode; 1450 if (token->name() == frameTag) 1451 insertionMode = InFramesetMode; 1452 else if (token->name() == colTag) 1453 insertionMode = InColumnGroupMode; 1454 else if (isCaptionColOrColgroupTag(token->name()) || isTableBodyContextTag(token->name())) 1455 insertionMode = InTableMode; 1456 else if (token->name() == trTag) 1457 insertionMode = InTableBodyMode; 1458 else if (isTableCellContextTag(token->name())) 1459 insertionMode = InRowMode; 1460 else 1461 insertionMode = InBodyMode; 1462 1463 ASSERT(insertionMode != TemplateContentsMode); 1464 ASSERT(m_templateInsertionModes.last() == TemplateContentsMode); 1465 m_templateInsertionModes.last() = insertionMode; 1466 setInsertionMode(insertionMode); 1467 1468 processStartTag(token); 1469#else 1470 ASSERT_NOT_REACHED(); 1471#endif 1472 break; 1473 } 1474} 1475 1476void HTMLTreeBuilder::processHtmlStartTagForInBody(AtomicHTMLToken* token) 1477{ 1478 parseError(token); 1479#if ENABLE(TEMPLATE_ELEMENT) 1480 if (m_tree.openElements()->hasTemplateInHTMLScope()) { 1481 ASSERT(isParsingTemplateContents()); 1482 return; 1483 } 1484#endif 1485 m_tree.insertHTMLHtmlStartTagInBody(token); 1486} 1487 1488bool HTMLTreeBuilder::processBodyEndTagForInBody(AtomicHTMLToken* token) 1489{ 1490 ASSERT(token->type() == HTMLToken::EndTag); 1491 ASSERT(token->name() == bodyTag); 1492 if (!m_tree.openElements()->inScope(bodyTag.localName())) { 1493 parseError(token); 1494 return false; 1495 } 1496 notImplemented(); // Emit a more specific parse error based on stack contents. 1497 setInsertionMode(AfterBodyMode); 1498 return true; 1499} 1500 1501void HTMLTreeBuilder::processAnyOtherEndTagForInBody(AtomicHTMLToken* token) 1502{ 1503 ASSERT(token->type() == HTMLToken::EndTag); 1504 HTMLElementStack::ElementRecord* record = m_tree.openElements()->topRecord(); 1505 while (1) { 1506 RefPtr<HTMLStackItem> item = record->stackItem(); 1507 if (item->matchesHTMLTag(token->name())) { 1508 m_tree.generateImpliedEndTagsWithExclusion(token->name()); 1509 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1510 parseError(token); 1511 m_tree.openElements()->popUntilPopped(item->element()); 1512 return; 1513 } 1514 if (item->isSpecialNode()) { 1515 parseError(token); 1516 return; 1517 } 1518 record = record->next(); 1519 } 1520} 1521 1522// http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody 1523void HTMLTreeBuilder::callTheAdoptionAgency(AtomicHTMLToken* token) 1524{ 1525 // The adoption agency algorithm is N^2. We limit the number of iterations 1526 // to stop from hanging the whole browser. This limit is specified in the 1527 // adoption agency algorithm: 1528 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#parsing-main-inbody 1529 static const int outerIterationLimit = 8; 1530 static const int innerIterationLimit = 3; 1531 1532 // 1, 2, 3 and 16 are covered by the for() loop. 1533 for (int i = 0; i < outerIterationLimit; ++i) { 1534 // 4. 1535 Element* formattingElement = m_tree.activeFormattingElements()->closestElementInScopeWithName(token->name()); 1536 // 4.a 1537 if (!formattingElement) 1538 return processAnyOtherEndTagForInBody(token); 1539 // 4.c 1540 if ((m_tree.openElements()->contains(formattingElement)) && !m_tree.openElements()->inScope(formattingElement)) { 1541 parseError(token); 1542 notImplemented(); // Check the stack of open elements for a more specific parse error. 1543 return; 1544 } 1545 // 4.b 1546 HTMLElementStack::ElementRecord* formattingElementRecord = m_tree.openElements()->find(formattingElement); 1547 if (!formattingElementRecord) { 1548 parseError(token); 1549 m_tree.activeFormattingElements()->remove(formattingElement); 1550 return; 1551 } 1552 // 4.d 1553 if (formattingElement != m_tree.currentElement()) 1554 parseError(token); 1555 // 5. 1556 HTMLElementStack::ElementRecord* furthestBlock = m_tree.openElements()->furthestBlockForFormattingElement(formattingElement); 1557 // 6. 1558 if (!furthestBlock) { 1559 m_tree.openElements()->popUntilPopped(formattingElement); 1560 m_tree.activeFormattingElements()->remove(formattingElement); 1561 return; 1562 } 1563 // 7. 1564 ASSERT(furthestBlock->isAbove(formattingElementRecord)); 1565 RefPtr<HTMLStackItem> commonAncestor = formattingElementRecord->next()->stackItem(); 1566 // 8. 1567 HTMLFormattingElementList::Bookmark bookmark = m_tree.activeFormattingElements()->bookmarkFor(formattingElement); 1568 // 9. 1569 HTMLElementStack::ElementRecord* node = furthestBlock; 1570 HTMLElementStack::ElementRecord* nextNode = node->next(); 1571 HTMLElementStack::ElementRecord* lastNode = furthestBlock; 1572 // 9.1, 9.2, 9.3 and 9.11 are covered by the for() loop. 1573 for (int i = 0; i < innerIterationLimit; ++i) { 1574 // 9.4 1575 node = nextNode; 1576 ASSERT(node); 1577 nextNode = node->next(); // Save node->next() for the next iteration in case node is deleted in 9.5. 1578 // 9.5 1579 if (!m_tree.activeFormattingElements()->contains(node->element())) { 1580 m_tree.openElements()->remove(node->element()); 1581 node = 0; 1582 continue; 1583 } 1584 // 9.6 1585 if (node == formattingElementRecord) 1586 break; 1587 // 9.7 1588 RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(node->stackItem().get()); 1589 1590 HTMLFormattingElementList::Entry* nodeEntry = m_tree.activeFormattingElements()->find(node->element()); 1591 nodeEntry->replaceElement(newItem); 1592 node->replaceElement(newItem.release()); 1593 1594 // 9.8 1595 if (lastNode == furthestBlock) 1596 bookmark.moveToAfter(nodeEntry); 1597 // 9.9 1598 m_tree.reparent(*node, *lastNode); 1599 // 9.10 1600 lastNode = node; 1601 } 1602 // 10. 1603 m_tree.insertAlreadyParsedChild(*commonAncestor, *lastNode); 1604 // 11. 1605 RefPtr<HTMLStackItem> newItem = m_tree.createElementFromSavedToken(formattingElementRecord->stackItem().get()); 1606 // 12. 1607 m_tree.takeAllChildren(*newItem, *furthestBlock); 1608 // 13. 1609 m_tree.reparent(*furthestBlock, *newItem); 1610 // 14. 1611 m_tree.activeFormattingElements()->swapTo(formattingElement, newItem, bookmark); 1612 // 15. 1613 m_tree.openElements()->remove(formattingElement); 1614 m_tree.openElements()->insertAbove(newItem, furthestBlock); 1615 } 1616} 1617 1618void HTMLTreeBuilder::resetInsertionModeAppropriately() 1619{ 1620 // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html#reset-the-insertion-mode-appropriately 1621 bool last = false; 1622 HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); 1623 while (1) { 1624 RefPtr<HTMLStackItem> item = nodeRecord->stackItem(); 1625 if (item->node() == m_tree.openElements()->rootNode()) { 1626 ASSERT(isParsingFragment()); 1627 last = true; 1628 item = HTMLStackItem::create(m_fragmentContext.contextElement(), HTMLStackItem::ItemForContextElement); 1629 } 1630#if ENABLE(TEMPLATE_ELEMENT) 1631 if (item->hasTagName(templateTag)) 1632 return setInsertionMode(m_templateInsertionModes.last()); 1633#endif 1634 if (item->hasTagName(selectTag)) { 1635 return setInsertionMode(InSelectMode); 1636 } 1637 if (item->hasTagName(tdTag) || item->hasTagName(thTag)) 1638 return setInsertionMode(InCellMode); 1639 if (item->hasTagName(trTag)) 1640 return setInsertionMode(InRowMode); 1641 if (item->hasTagName(tbodyTag) || item->hasTagName(theadTag) || item->hasTagName(tfootTag)) 1642 return setInsertionMode(InTableBodyMode); 1643 if (item->hasTagName(captionTag)) 1644 return setInsertionMode(InCaptionMode); 1645 if (item->hasTagName(colgroupTag)) { 1646 return setInsertionMode(InColumnGroupMode); 1647 } 1648 if (item->hasTagName(tableTag)) 1649 return setInsertionMode(InTableMode); 1650 if (item->hasTagName(headTag)) { 1651#if ENABLE(TEMPLATE_ELEMENT) 1652 if (!m_fragmentContext.fragment() || m_fragmentContext.contextElement() != item->node()) 1653 return setInsertionMode(InHeadMode); 1654#endif 1655 return setInsertionMode(InBodyMode); 1656 } 1657 if (item->hasTagName(bodyTag)) 1658 return setInsertionMode(InBodyMode); 1659 if (item->hasTagName(framesetTag)) { 1660 return setInsertionMode(InFramesetMode); 1661 } 1662 if (item->hasTagName(htmlTag)) { 1663 ASSERT(isParsingFragment()); 1664 return setInsertionMode(BeforeHeadMode); 1665 } 1666 if (last) { 1667 ASSERT(isParsingFragment()); 1668 return setInsertionMode(InBodyMode); 1669 } 1670 nodeRecord = nodeRecord->next(); 1671 } 1672} 1673 1674void HTMLTreeBuilder::processEndTagForInTableBody(AtomicHTMLToken* token) 1675{ 1676 ASSERT(token->type() == HTMLToken::EndTag); 1677 if (isTableBodyContextTag(token->name())) { 1678 if (!m_tree.openElements()->inTableScope(token->name())) { 1679 parseError(token); 1680 return; 1681 } 1682 m_tree.openElements()->popUntilTableBodyScopeMarker(); 1683 m_tree.openElements()->pop(); 1684 setInsertionMode(InTableMode); 1685 return; 1686 } 1687 if (token->name() == tableTag) { 1688 // FIXME: This is slow. 1689 if (!m_tree.openElements()->inTableScope(tbodyTag) && !m_tree.openElements()->inTableScope(theadTag) && !m_tree.openElements()->inTableScope(tfootTag)) { 1690 ASSERT(isParsingFragmentOrTemplateContents()); 1691 parseError(token); 1692 return; 1693 } 1694 m_tree.openElements()->popUntilTableBodyScopeMarker(); 1695 ASSERT(isTableBodyContextTag(m_tree.currentStackItem()->localName())); 1696 processFakeEndTag(m_tree.currentStackItem()->localName()); 1697 processEndTag(token); 1698 return; 1699 } 1700 if (token->name() == bodyTag 1701 || isCaptionColOrColgroupTag(token->name()) 1702 || token->name() == htmlTag 1703 || isTableCellContextTag(token->name()) 1704 || token->name() == trTag) { 1705 parseError(token); 1706 return; 1707 } 1708 processEndTagForInTable(token); 1709} 1710 1711void HTMLTreeBuilder::processEndTagForInRow(AtomicHTMLToken* token) 1712{ 1713 ASSERT(token->type() == HTMLToken::EndTag); 1714 if (token->name() == trTag) { 1715 processTrEndTagForInRow(); 1716 return; 1717 } 1718 if (token->name() == tableTag) { 1719 if (!processTrEndTagForInRow()) { 1720 ASSERT(isParsingFragmentOrTemplateContents()); 1721 return; 1722 } 1723 ASSERT(insertionMode() == InTableBodyMode); 1724 processEndTag(token); 1725 return; 1726 } 1727 if (isTableBodyContextTag(token->name())) { 1728 if (!m_tree.openElements()->inTableScope(token->name())) { 1729 parseError(token); 1730 return; 1731 } 1732 processFakeEndTag(trTag); 1733 ASSERT(insertionMode() == InTableBodyMode); 1734 processEndTag(token); 1735 return; 1736 } 1737 if (token->name() == bodyTag 1738 || isCaptionColOrColgroupTag(token->name()) 1739 || token->name() == htmlTag 1740 || isTableCellContextTag(token->name())) { 1741 parseError(token); 1742 return; 1743 } 1744 processEndTagForInTable(token); 1745} 1746 1747void HTMLTreeBuilder::processEndTagForInCell(AtomicHTMLToken* token) 1748{ 1749 ASSERT(token->type() == HTMLToken::EndTag); 1750 if (isTableCellContextTag(token->name())) { 1751 if (!m_tree.openElements()->inTableScope(token->name())) { 1752 parseError(token); 1753 return; 1754 } 1755 m_tree.generateImpliedEndTags(); 1756 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1757 parseError(token); 1758 m_tree.openElements()->popUntilPopped(token->name()); 1759 m_tree.activeFormattingElements()->clearToLastMarker(); 1760 setInsertionMode(InRowMode); 1761 return; 1762 } 1763 if (token->name() == bodyTag 1764 || isCaptionColOrColgroupTag(token->name()) 1765 || token->name() == htmlTag) { 1766 parseError(token); 1767 return; 1768 } 1769 if (token->name() == tableTag 1770 || token->name() == trTag 1771 || isTableBodyContextTag(token->name())) { 1772 if (!m_tree.openElements()->inTableScope(token->name())) { 1773#if ENABLE(TEMPLATE_ELEMENT) 1774 ASSERT(isTableBodyContextTag(token->name()) || m_tree.openElements()->inTableScope(templateTag) || isParsingFragment()); 1775#else 1776 ASSERT(isTableBodyContextTag(token->name()) || isParsingFragment()); 1777#endif 1778 parseError(token); 1779 return; 1780 } 1781 closeTheCell(); 1782 processEndTag(token); 1783 return; 1784 } 1785 processEndTagForInBody(token); 1786} 1787 1788void HTMLTreeBuilder::processEndTagForInBody(AtomicHTMLToken* token) 1789{ 1790 ASSERT(token->type() == HTMLToken::EndTag); 1791 if (token->name() == bodyTag) { 1792 processBodyEndTagForInBody(token); 1793 return; 1794 } 1795 if (token->name() == htmlTag) { 1796 AtomicHTMLToken endBody(HTMLToken::EndTag, bodyTag.localName()); 1797 if (processBodyEndTagForInBody(&endBody)) 1798 processEndTag(token); 1799 return; 1800 } 1801 if (token->name() == addressTag 1802 || token->name() == articleTag 1803 || token->name() == asideTag 1804 || token->name() == blockquoteTag 1805 || token->name() == buttonTag 1806 || token->name() == centerTag 1807 || token->name() == detailsTag 1808 || token->name() == dirTag 1809 || token->name() == divTag 1810 || token->name() == dlTag 1811 || token->name() == fieldsetTag 1812 || token->name() == figcaptionTag 1813 || token->name() == figureTag 1814 || token->name() == footerTag 1815 || token->name() == headerTag 1816 || token->name() == hgroupTag 1817 || token->name() == listingTag 1818 || token->name() == mainTag 1819 || token->name() == menuTag 1820 || token->name() == navTag 1821 || token->name() == olTag 1822 || token->name() == preTag 1823 || token->name() == sectionTag 1824 || token->name() == summaryTag 1825 || token->name() == ulTag) { 1826 if (!m_tree.openElements()->inScope(token->name())) { 1827 parseError(token); 1828 return; 1829 } 1830 m_tree.generateImpliedEndTags(); 1831 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1832 parseError(token); 1833 m_tree.openElements()->popUntilPopped(token->name()); 1834 return; 1835 } 1836 if (token->name() == formTag) { 1837 RefPtr<Element> node = m_tree.takeForm(); 1838 if (!node || !m_tree.openElements()->inScope(node.get())) { 1839 parseError(token); 1840 return; 1841 } 1842 m_tree.generateImpliedEndTags(); 1843 if (m_tree.currentElement() != node.get()) 1844 parseError(token); 1845 m_tree.openElements()->remove(node.get()); 1846 } 1847 if (token->name() == pTag) { 1848 if (!m_tree.openElements()->inButtonScope(token->name())) { 1849 parseError(token); 1850 processFakeStartTag(pTag); 1851 ASSERT(m_tree.openElements()->inScope(token->name())); 1852 processEndTag(token); 1853 return; 1854 } 1855 m_tree.generateImpliedEndTagsWithExclusion(token->name()); 1856 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1857 parseError(token); 1858 m_tree.openElements()->popUntilPopped(token->name()); 1859 return; 1860 } 1861 if (token->name() == liTag) { 1862 if (!m_tree.openElements()->inListItemScope(token->name())) { 1863 parseError(token); 1864 return; 1865 } 1866 m_tree.generateImpliedEndTagsWithExclusion(token->name()); 1867 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1868 parseError(token); 1869 m_tree.openElements()->popUntilPopped(token->name()); 1870 return; 1871 } 1872 if (token->name() == ddTag 1873 || token->name() == dtTag) { 1874 if (!m_tree.openElements()->inScope(token->name())) { 1875 parseError(token); 1876 return; 1877 } 1878 m_tree.generateImpliedEndTagsWithExclusion(token->name()); 1879 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1880 parseError(token); 1881 m_tree.openElements()->popUntilPopped(token->name()); 1882 return; 1883 } 1884 if (isNumberedHeaderTag(token->name())) { 1885 if (!m_tree.openElements()->hasNumberedHeaderElementInScope()) { 1886 parseError(token); 1887 return; 1888 } 1889 m_tree.generateImpliedEndTags(); 1890 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1891 parseError(token); 1892 m_tree.openElements()->popUntilNumberedHeaderElementPopped(); 1893 return; 1894 } 1895 if (isFormattingTag(token->name())) { 1896 callTheAdoptionAgency(token); 1897 return; 1898 } 1899 if (token->name() == appletTag 1900 || token->name() == marqueeTag 1901 || token->name() == objectTag) { 1902 if (!m_tree.openElements()->inScope(token->name())) { 1903 parseError(token); 1904 return; 1905 } 1906 m_tree.generateImpliedEndTags(); 1907 if (!m_tree.currentStackItem()->matchesHTMLTag(token->name())) 1908 parseError(token); 1909 m_tree.openElements()->popUntilPopped(token->name()); 1910 m_tree.activeFormattingElements()->clearToLastMarker(); 1911 return; 1912 } 1913 if (token->name() == brTag) { 1914 parseError(token); 1915 processFakeStartTag(brTag); 1916 return; 1917 } 1918#if ENABLE(TEMPLATE_ELEMENT) 1919 if (token->name() == templateTag) { 1920 processTemplateEndTag(token); 1921 return; 1922 } 1923#endif 1924 processAnyOtherEndTagForInBody(token); 1925} 1926 1927bool HTMLTreeBuilder::processCaptionEndTagForInCaption() 1928{ 1929 if (!m_tree.openElements()->inTableScope(captionTag.localName())) { 1930 ASSERT(isParsingFragment()); 1931 // FIXME: parse error 1932 return false; 1933 } 1934 m_tree.generateImpliedEndTags(); 1935 // FIXME: parse error if (!m_tree.currentStackItem()->hasTagName(captionTag)) 1936 m_tree.openElements()->popUntilPopped(captionTag.localName()); 1937 m_tree.activeFormattingElements()->clearToLastMarker(); 1938 setInsertionMode(InTableMode); 1939 return true; 1940} 1941 1942bool HTMLTreeBuilder::processTrEndTagForInRow() 1943{ 1944 if (!m_tree.openElements()->inTableScope(trTag)) { 1945 ASSERT(isParsingFragmentOrTemplateContents()); 1946 // FIXME: parse error 1947 return false; 1948 } 1949 m_tree.openElements()->popUntilTableRowScopeMarker(); 1950 ASSERT(m_tree.currentStackItem()->hasTagName(trTag)); 1951 m_tree.openElements()->pop(); 1952 setInsertionMode(InTableBodyMode); 1953 return true; 1954} 1955 1956bool HTMLTreeBuilder::processTableEndTagForInTable() 1957{ 1958 if (!m_tree.openElements()->inTableScope(tableTag)) { 1959 ASSERT(isParsingFragmentOrTemplateContents()); 1960 // FIXME: parse error. 1961 return false; 1962 } 1963 m_tree.openElements()->popUntilPopped(tableTag.localName()); 1964 resetInsertionModeAppropriately(); 1965 return true; 1966} 1967 1968void HTMLTreeBuilder::processEndTagForInTable(AtomicHTMLToken* token) 1969{ 1970 ASSERT(token->type() == HTMLToken::EndTag); 1971 if (token->name() == tableTag) { 1972 processTableEndTagForInTable(); 1973 return; 1974 } 1975 if (token->name() == bodyTag 1976 || isCaptionColOrColgroupTag(token->name()) 1977 || token->name() == htmlTag 1978 || isTableBodyContextTag(token->name()) 1979 || isTableCellContextTag(token->name()) 1980 || token->name() == trTag) { 1981 parseError(token); 1982 return; 1983 } 1984 parseError(token); 1985 // Is this redirection necessary here? 1986 HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); 1987 processEndTagForInBody(token); 1988} 1989 1990void HTMLTreeBuilder::processEndTag(AtomicHTMLToken* token) 1991{ 1992 ASSERT(token->type() == HTMLToken::EndTag); 1993 switch (insertionMode()) { 1994 case InitialMode: 1995 ASSERT(insertionMode() == InitialMode); 1996 defaultForInitial(); 1997 // Fall through. 1998 case BeforeHTMLMode: 1999 ASSERT(insertionMode() == BeforeHTMLMode); 2000 if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { 2001 parseError(token); 2002 return; 2003 } 2004 defaultForBeforeHTML(); 2005 // Fall through. 2006 case BeforeHeadMode: 2007 ASSERT(insertionMode() == BeforeHeadMode); 2008 if (token->name() != headTag && token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { 2009 parseError(token); 2010 return; 2011 } 2012 defaultForBeforeHead(); 2013 // Fall through. 2014 case InHeadMode: 2015 ASSERT(insertionMode() == InHeadMode); 2016 // FIXME: This case should be broken out into processEndTagForInHead, 2017 // because other end tag cases now refer to it ("process the token for using the rules of the "in head" insertion mode"). 2018 // but because the logic falls through to AfterHeadMode, that gets a little messy. 2019#if ENABLE(TEMPLATE_ELEMENT) 2020 if (token->name() == templateTag) { 2021 processTemplateEndTag(token); 2022 return; 2023 } 2024#endif 2025 if (token->name() == headTag) { 2026 m_tree.openElements()->popHTMLHeadElement(); 2027 setInsertionMode(AfterHeadMode); 2028 return; 2029 } 2030 if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { 2031 parseError(token); 2032 return; 2033 } 2034 defaultForInHead(); 2035 // Fall through. 2036 case AfterHeadMode: 2037 ASSERT(insertionMode() == AfterHeadMode); 2038 if (token->name() != bodyTag && token->name() != htmlTag && token->name() != brTag) { 2039 parseError(token); 2040 return; 2041 } 2042 defaultForAfterHead(); 2043 // Fall through 2044 case InBodyMode: 2045 ASSERT(insertionMode() == InBodyMode); 2046 processEndTagForInBody(token); 2047 break; 2048 case InTableMode: 2049 ASSERT(insertionMode() == InTableMode); 2050 processEndTagForInTable(token); 2051 break; 2052 case InCaptionMode: 2053 ASSERT(insertionMode() == InCaptionMode); 2054 if (token->name() == captionTag) { 2055 processCaptionEndTagForInCaption(); 2056 return; 2057 } 2058 if (token->name() == tableTag) { 2059 parseError(token); 2060 if (!processCaptionEndTagForInCaption()) { 2061 ASSERT(isParsingFragment()); 2062 return; 2063 } 2064 processEndTag(token); 2065 return; 2066 } 2067 if (token->name() == bodyTag 2068 || token->name() == colTag 2069 || token->name() == colgroupTag 2070 || token->name() == htmlTag 2071 || isTableBodyContextTag(token->name()) 2072 || isTableCellContextTag(token->name()) 2073 || token->name() == trTag) { 2074 parseError(token); 2075 return; 2076 } 2077 processEndTagForInBody(token); 2078 break; 2079 case InColumnGroupMode: 2080 ASSERT(insertionMode() == InColumnGroupMode); 2081 if (token->name() == colgroupTag) { 2082 processColgroupEndTagForInColumnGroup(); 2083 return; 2084 } 2085 if (token->name() == colTag) { 2086 parseError(token); 2087 return; 2088 } 2089#if ENABLE(TEMPLATE_ELEMENT) 2090 if (token->name() == templateTag) { 2091 processTemplateEndTag(token); 2092 return; 2093 } 2094#endif 2095 if (!processColgroupEndTagForInColumnGroup()) { 2096 ASSERT(isParsingFragmentOrTemplateContents()); 2097 return; 2098 } 2099 processEndTag(token); 2100 break; 2101 case InRowMode: 2102 ASSERT(insertionMode() == InRowMode); 2103 processEndTagForInRow(token); 2104 break; 2105 case InCellMode: 2106 ASSERT(insertionMode() == InCellMode); 2107 processEndTagForInCell(token); 2108 break; 2109 case InTableBodyMode: 2110 ASSERT(insertionMode() == InTableBodyMode); 2111 processEndTagForInTableBody(token); 2112 break; 2113 case AfterBodyMode: 2114 ASSERT(insertionMode() == AfterBodyMode); 2115 if (token->name() == htmlTag) { 2116 if (isParsingFragment()) { 2117 parseError(token); 2118 return; 2119 } 2120 setInsertionMode(AfterAfterBodyMode); 2121 return; 2122 } 2123 // Fall through. 2124 case AfterAfterBodyMode: 2125 ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode); 2126 parseError(token); 2127 setInsertionMode(InBodyMode); 2128 processEndTag(token); 2129 break; 2130 case InHeadNoscriptMode: 2131 ASSERT(insertionMode() == InHeadNoscriptMode); 2132 if (token->name() == noscriptTag) { 2133 ASSERT(m_tree.currentStackItem()->hasTagName(noscriptTag)); 2134 m_tree.openElements()->pop(); 2135 ASSERT(m_tree.currentStackItem()->hasTagName(headTag)); 2136 setInsertionMode(InHeadMode); 2137 return; 2138 } 2139 if (token->name() != brTag) { 2140 parseError(token); 2141 return; 2142 } 2143 defaultForInHeadNoscript(); 2144 processToken(token); 2145 break; 2146 case TextMode: 2147 if (token->name() == scriptTag) { 2148 // Pause ourselves so that parsing stops until the script can be processed by the caller. 2149 ASSERT(m_tree.currentStackItem()->hasTagName(scriptTag)); 2150 if (scriptingContentIsAllowed(m_tree.parserContentPolicy())) 2151 m_scriptToProcess = m_tree.currentElement(); 2152 m_tree.openElements()->pop(); 2153 setInsertionMode(m_originalInsertionMode); 2154 2155 if (m_parser->tokenizer()) { 2156 // This token will not have been created by the tokenizer if a 2157 // self-closing script tag was encountered and pre-HTML5 parser 2158 // quirks are enabled. We must set the tokenizer's state to 2159 // DataState explicitly if the tokenizer didn't have a chance to. 2160 ASSERT(m_parser->tokenizer()->state() == HTMLTokenizer::DataState || m_options.usePreHTML5ParserQuirks || m_options.useThreading); 2161 m_parser->tokenizer()->setState(HTMLTokenizer::DataState); 2162 } 2163 return; 2164 } 2165 m_tree.openElements()->pop(); 2166 setInsertionMode(m_originalInsertionMode); 2167 break; 2168 case InFramesetMode: 2169 ASSERT(insertionMode() == InFramesetMode); 2170 if (token->name() == framesetTag) { 2171 bool ignoreFramesetForFragmentParsing = m_tree.currentIsRootNode(); 2172#if ENABLE(TEMPLATE_ELEMENT) 2173 ignoreFramesetForFragmentParsing = ignoreFramesetForFragmentParsing || m_tree.openElements()->hasTemplateInHTMLScope(); 2174#endif 2175 if (ignoreFramesetForFragmentParsing) { 2176 ASSERT(isParsingFragmentOrTemplateContents()); 2177 parseError(token); 2178 return; 2179 } 2180 m_tree.openElements()->pop(); 2181 if (!isParsingFragment() && !m_tree.currentStackItem()->hasTagName(framesetTag)) 2182 setInsertionMode(AfterFramesetMode); 2183 return; 2184 } 2185#if ENABLE(TEMPLATE_ELEMENT) 2186 if (token->name() == templateTag) { 2187 processTemplateEndTag(token); 2188 return; 2189 } 2190#endif 2191 break; 2192 case AfterFramesetMode: 2193 ASSERT(insertionMode() == AfterFramesetMode); 2194 if (token->name() == htmlTag) { 2195 setInsertionMode(AfterAfterFramesetMode); 2196 return; 2197 } 2198 // Fall through. 2199 case AfterAfterFramesetMode: 2200 ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode); 2201 parseError(token); 2202 break; 2203 case InSelectInTableMode: 2204 ASSERT(insertionMode() == InSelectInTableMode); 2205 if (token->name() == captionTag 2206 || token->name() == tableTag 2207 || isTableBodyContextTag(token->name()) 2208 || token->name() == trTag 2209 || isTableCellContextTag(token->name())) { 2210 parseError(token); 2211 if (m_tree.openElements()->inTableScope(token->name())) { 2212 AtomicHTMLToken endSelect(HTMLToken::EndTag, selectTag.localName()); 2213 processEndTag(&endSelect); 2214 processEndTag(token); 2215 } 2216 return; 2217 } 2218 // Fall through. 2219 case InSelectMode: 2220 ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode); 2221 if (token->name() == optgroupTag) { 2222 if (m_tree.currentStackItem()->hasTagName(optionTag) && m_tree.oneBelowTop() && m_tree.oneBelowTop()->hasTagName(optgroupTag)) 2223 processFakeEndTag(optionTag); 2224 if (m_tree.currentStackItem()->hasTagName(optgroupTag)) { 2225 m_tree.openElements()->pop(); 2226 return; 2227 } 2228 parseError(token); 2229 return; 2230 } 2231 if (token->name() == optionTag) { 2232 if (m_tree.currentStackItem()->hasTagName(optionTag)) { 2233 m_tree.openElements()->pop(); 2234 return; 2235 } 2236 parseError(token); 2237 return; 2238 } 2239 if (token->name() == selectTag) { 2240 if (!m_tree.openElements()->inSelectScope(token->name())) { 2241 ASSERT(isParsingFragment()); 2242 parseError(token); 2243 return; 2244 } 2245 m_tree.openElements()->popUntilPopped(selectTag.localName()); 2246 resetInsertionModeAppropriately(); 2247 return; 2248 } 2249#if ENABLE(TEMPLATE_ELEMENT) 2250 if (token->name() == templateTag) { 2251 processTemplateEndTag(token); 2252 return; 2253 } 2254#endif 2255 break; 2256 case InTableTextMode: 2257 defaultForInTableText(); 2258 processEndTag(token); 2259 break; 2260 case TemplateContentsMode: 2261#if ENABLE(TEMPLATE_ELEMENT) 2262 if (token->name() == templateTag) { 2263 processTemplateEndTag(token); 2264 return; 2265 } 2266 2267 break; 2268#else 2269 ASSERT_NOT_REACHED(); 2270#endif 2271 break; 2272 } 2273} 2274 2275void HTMLTreeBuilder::processComment(AtomicHTMLToken* token) 2276{ 2277 ASSERT(token->type() == HTMLToken::Comment); 2278 if (m_insertionMode == InitialMode 2279 || m_insertionMode == BeforeHTMLMode 2280 || m_insertionMode == AfterAfterBodyMode 2281 || m_insertionMode == AfterAfterFramesetMode) { 2282 m_tree.insertCommentOnDocument(token); 2283 return; 2284 } 2285 if (m_insertionMode == AfterBodyMode) { 2286 m_tree.insertCommentOnHTMLHtmlElement(token); 2287 return; 2288 } 2289 if (m_insertionMode == InTableTextMode) { 2290 defaultForInTableText(); 2291 processComment(token); 2292 return; 2293 } 2294 m_tree.insertComment(token); 2295} 2296 2297void HTMLTreeBuilder::processCharacter(AtomicHTMLToken* token) 2298{ 2299 ASSERT(token->type() == HTMLToken::Character); 2300 ExternalCharacterTokenBuffer buffer(token); 2301 processCharacterBuffer(buffer); 2302} 2303 2304void HTMLTreeBuilder::processCharacterBuffer(ExternalCharacterTokenBuffer& buffer) 2305{ 2306ReprocessBuffer: 2307 // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html#parsing-main-inbody 2308 // Note that this logic is different than the generic \r\n collapsing 2309 // handled in the input stream preprocessor. This logic is here as an 2310 // "authoring convenience" so folks can write: 2311 // 2312 // <pre> 2313 // lorem ipsum 2314 // lorem ipsum 2315 // </pre> 2316 // 2317 // without getting an extra newline at the start of their <pre> element. 2318 if (m_shouldSkipLeadingNewline) { 2319 m_shouldSkipLeadingNewline = false; 2320 buffer.skipAtMostOneLeadingNewline(); 2321 if (buffer.isEmpty()) 2322 return; 2323 } 2324 2325 switch (insertionMode()) { 2326 case InitialMode: { 2327 ASSERT(insertionMode() == InitialMode); 2328 buffer.skipLeadingWhitespace(); 2329 if (buffer.isEmpty()) 2330 return; 2331 defaultForInitial(); 2332 // Fall through. 2333 } 2334 case BeforeHTMLMode: { 2335 ASSERT(insertionMode() == BeforeHTMLMode); 2336 buffer.skipLeadingWhitespace(); 2337 if (buffer.isEmpty()) 2338 return; 2339 defaultForBeforeHTML(); 2340 // Fall through. 2341 } 2342 case BeforeHeadMode: { 2343 ASSERT(insertionMode() == BeforeHeadMode); 2344 buffer.skipLeadingWhitespace(); 2345 if (buffer.isEmpty()) 2346 return; 2347 defaultForBeforeHead(); 2348 // Fall through. 2349 } 2350 case InHeadMode: { 2351 ASSERT(insertionMode() == InHeadMode); 2352 String leadingWhitespace = buffer.takeLeadingWhitespace(); 2353 if (!leadingWhitespace.isEmpty()) 2354 m_tree.insertTextNode(leadingWhitespace, AllWhitespace); 2355 if (buffer.isEmpty()) 2356 return; 2357 defaultForInHead(); 2358 // Fall through. 2359 } 2360 case AfterHeadMode: { 2361 ASSERT(insertionMode() == AfterHeadMode); 2362 String leadingWhitespace = buffer.takeLeadingWhitespace(); 2363 if (!leadingWhitespace.isEmpty()) 2364 m_tree.insertTextNode(leadingWhitespace, AllWhitespace); 2365 if (buffer.isEmpty()) 2366 return; 2367 defaultForAfterHead(); 2368 // Fall through. 2369 } 2370 case InBodyMode: 2371 case InCaptionMode: 2372 case TemplateContentsMode: 2373 case InCellMode: { 2374#if ENABLE(TEMPLATE_ELEMENT) 2375 ASSERT(insertionMode() == InBodyMode || insertionMode() == InCaptionMode || insertionMode() == InCellMode || insertionMode() == TemplateContentsMode); 2376#else 2377 ASSERT(insertionMode() != TemplateContentsMode); 2378 ASSERT(insertionMode() == InBodyMode || insertionMode() == InCaptionMode || insertionMode() == InCellMode); 2379#endif 2380 processCharacterBufferForInBody(buffer); 2381 break; 2382 } 2383 case InTableMode: 2384 case InTableBodyMode: 2385 case InRowMode: { 2386 ASSERT(insertionMode() == InTableMode || insertionMode() == InTableBodyMode || insertionMode() == InRowMode); 2387 ASSERT(m_pendingTableCharacters.isEmpty()); 2388 if (m_tree.currentStackItem()->isElementNode() 2389 && (m_tree.currentStackItem()->hasTagName(HTMLNames::tableTag) 2390 || m_tree.currentStackItem()->hasTagName(HTMLNames::tbodyTag) 2391 || m_tree.currentStackItem()->hasTagName(HTMLNames::tfootTag) 2392 || m_tree.currentStackItem()->hasTagName(HTMLNames::theadTag) 2393 || m_tree.currentStackItem()->hasTagName(HTMLNames::trTag))) { 2394 m_originalInsertionMode = m_insertionMode; 2395 setInsertionMode(InTableTextMode); 2396 // Note that we fall through to the InTableTextMode case below. 2397 } else { 2398 HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); 2399 processCharacterBufferForInBody(buffer); 2400 break; 2401 } 2402 // Fall through. 2403 } 2404 case InTableTextMode: { 2405 buffer.giveRemainingTo(m_pendingTableCharacters); 2406 break; 2407 } 2408 case InColumnGroupMode: { 2409 ASSERT(insertionMode() == InColumnGroupMode); 2410 String leadingWhitespace = buffer.takeLeadingWhitespace(); 2411 if (!leadingWhitespace.isEmpty()) 2412 m_tree.insertTextNode(leadingWhitespace, AllWhitespace); 2413 if (buffer.isEmpty()) 2414 return; 2415 if (!processColgroupEndTagForInColumnGroup()) { 2416 ASSERT(isParsingFragmentOrTemplateContents()); 2417 // The spec tells us to drop these characters on the floor. 2418 buffer.skipLeadingNonWhitespace(); 2419 if (buffer.isEmpty()) 2420 return; 2421 } 2422 goto ReprocessBuffer; 2423 } 2424 case AfterBodyMode: 2425 case AfterAfterBodyMode: { 2426 ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode); 2427 // FIXME: parse error 2428 setInsertionMode(InBodyMode); 2429 goto ReprocessBuffer; 2430 break; 2431 } 2432 case TextMode: { 2433 ASSERT(insertionMode() == TextMode); 2434 m_tree.insertTextNode(buffer.takeRemaining()); 2435 break; 2436 } 2437 case InHeadNoscriptMode: { 2438 ASSERT(insertionMode() == InHeadNoscriptMode); 2439 String leadingWhitespace = buffer.takeLeadingWhitespace(); 2440 if (!leadingWhitespace.isEmpty()) 2441 m_tree.insertTextNode(leadingWhitespace, AllWhitespace); 2442 if (buffer.isEmpty()) 2443 return; 2444 defaultForInHeadNoscript(); 2445 goto ReprocessBuffer; 2446 break; 2447 } 2448 case InFramesetMode: 2449 case AfterFramesetMode: { 2450 ASSERT(insertionMode() == InFramesetMode || insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode); 2451 String leadingWhitespace = buffer.takeRemainingWhitespace(); 2452 if (!leadingWhitespace.isEmpty()) 2453 m_tree.insertTextNode(leadingWhitespace, AllWhitespace); 2454 // FIXME: We should generate a parse error if we skipped over any 2455 // non-whitespace characters. 2456 break; 2457 } 2458 case InSelectInTableMode: 2459 case InSelectMode: { 2460 ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode); 2461 m_tree.insertTextNode(buffer.takeRemaining()); 2462 break; 2463 } 2464 case AfterAfterFramesetMode: { 2465 String leadingWhitespace = buffer.takeRemainingWhitespace(); 2466 if (!leadingWhitespace.isEmpty()) { 2467 m_tree.reconstructTheActiveFormattingElements(); 2468 m_tree.insertTextNode(leadingWhitespace, AllWhitespace); 2469 } 2470 // FIXME: We should generate a parse error if we skipped over any 2471 // non-whitespace characters. 2472 break; 2473 } 2474 } 2475} 2476 2477void HTMLTreeBuilder::processCharacterBufferForInBody(ExternalCharacterTokenBuffer& buffer) 2478{ 2479 m_tree.reconstructTheActiveFormattingElements(); 2480 String characters = buffer.takeRemaining(); 2481 m_tree.insertTextNode(characters); 2482 if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters)) 2483 m_framesetOk = false; 2484} 2485 2486void HTMLTreeBuilder::processEndOfFile(AtomicHTMLToken* token) 2487{ 2488 ASSERT(token->type() == HTMLToken::EndOfFile); 2489 switch (insertionMode()) { 2490 case InitialMode: 2491 ASSERT(insertionMode() == InitialMode); 2492 defaultForInitial(); 2493 // Fall through. 2494 case BeforeHTMLMode: 2495 ASSERT(insertionMode() == BeforeHTMLMode); 2496 defaultForBeforeHTML(); 2497 // Fall through. 2498 case BeforeHeadMode: 2499 ASSERT(insertionMode() == BeforeHeadMode); 2500 defaultForBeforeHead(); 2501 // Fall through. 2502 case InHeadMode: 2503 ASSERT(insertionMode() == InHeadMode); 2504 defaultForInHead(); 2505 // Fall through. 2506 case AfterHeadMode: 2507 ASSERT(insertionMode() == AfterHeadMode); 2508 defaultForAfterHead(); 2509 // Fall through 2510 case InBodyMode: 2511 case InCellMode: 2512 case InCaptionMode: 2513 case InRowMode: 2514#if ENABLE(TEMPLATE_ELEMENT) 2515 ASSERT(insertionMode() == InBodyMode || insertionMode() == InCellMode || insertionMode() == InCaptionMode || insertionMode() == InRowMode || insertionMode() == TemplateContentsMode); 2516#else 2517 ASSERT(insertionMode() != TemplateContentsMode); 2518 ASSERT(insertionMode() == InBodyMode || insertionMode() == InCellMode || insertionMode() == InCaptionMode || insertionMode() == InRowMode); 2519#endif 2520 notImplemented(); // Emit parse error based on what elements are still open. 2521#if ENABLE(TEMPLATE_ELEMENT) 2522 if (!m_templateInsertionModes.isEmpty()) 2523 if (processEndOfFileForInTemplateContents(token)) 2524 return; 2525#endif 2526 break; 2527 case AfterBodyMode: 2528 case AfterAfterBodyMode: 2529 ASSERT(insertionMode() == AfterBodyMode || insertionMode() == AfterAfterBodyMode); 2530 break; 2531 case InHeadNoscriptMode: 2532 ASSERT(insertionMode() == InHeadNoscriptMode); 2533 defaultForInHeadNoscript(); 2534 processEndOfFile(token); 2535 return; 2536 case AfterFramesetMode: 2537 case AfterAfterFramesetMode: 2538 ASSERT(insertionMode() == AfterFramesetMode || insertionMode() == AfterAfterFramesetMode); 2539 break; 2540 case InColumnGroupMode: 2541 if (m_tree.currentIsRootNode()) { 2542 ASSERT(isParsingFragment()); 2543 return; // FIXME: Should we break here instead of returning? 2544 } 2545#if ENABLE(TEMPLATE_ELEMENT) 2546 ASSERT(m_tree.currentNode()->hasTagName(colgroupTag) || m_tree.currentNode()->hasTagName(templateTag)); 2547#else 2548 ASSERT(m_tree.currentNode()->hasTagName(colgroupTag)); 2549#endif 2550 processColgroupEndTagForInColumnGroup(); 2551 // Fall through 2552 case InFramesetMode: 2553 case InTableMode: 2554 case InTableBodyMode: 2555 case InSelectInTableMode: 2556 case InSelectMode: 2557 ASSERT(insertionMode() == InSelectMode || insertionMode() == InSelectInTableMode || insertionMode() == InTableMode || insertionMode() == InFramesetMode || insertionMode() == InTableBodyMode || insertionMode() == InColumnGroupMode); 2558 if (m_tree.currentNode() != m_tree.openElements()->rootNode()) 2559 parseError(token); 2560 2561#if ENABLE(TEMPLATE_ELEMENT) 2562 if (!m_templateInsertionModes.isEmpty()) 2563 if (processEndOfFileForInTemplateContents(token)) 2564 return; 2565#endif 2566 break; 2567 case InTableTextMode: 2568 defaultForInTableText(); 2569 processEndOfFile(token); 2570 return; 2571 case TextMode: 2572 parseError(token); 2573 if (m_tree.currentStackItem()->hasTagName(scriptTag)) 2574 notImplemented(); // mark the script element as "already started". 2575 m_tree.openElements()->pop(); 2576 ASSERT(m_originalInsertionMode != TextMode); 2577 setInsertionMode(m_originalInsertionMode); 2578 processEndOfFile(token); 2579 return; 2580 case TemplateContentsMode: 2581#if ENABLE(TEMPLATE_ELEMENT) 2582 if (processEndOfFileForInTemplateContents(token)) 2583 return; 2584 break; 2585#else 2586 ASSERT_NOT_REACHED(); 2587#endif 2588 } 2589 ASSERT(m_tree.currentNode()); 2590 m_tree.openElements()->popAll(); 2591} 2592 2593void HTMLTreeBuilder::defaultForInitial() 2594{ 2595 notImplemented(); 2596 m_tree.setDefaultCompatibilityMode(); 2597 // FIXME: parse error 2598 setInsertionMode(BeforeHTMLMode); 2599} 2600 2601void HTMLTreeBuilder::defaultForBeforeHTML() 2602{ 2603 AtomicHTMLToken startHTML(HTMLToken::StartTag, htmlTag.localName()); 2604 m_tree.insertHTMLHtmlStartTagBeforeHTML(&startHTML); 2605 setInsertionMode(BeforeHeadMode); 2606} 2607 2608void HTMLTreeBuilder::defaultForBeforeHead() 2609{ 2610 AtomicHTMLToken startHead(HTMLToken::StartTag, headTag.localName()); 2611 processStartTag(&startHead); 2612} 2613 2614void HTMLTreeBuilder::defaultForInHead() 2615{ 2616 AtomicHTMLToken endHead(HTMLToken::EndTag, headTag.localName()); 2617 processEndTag(&endHead); 2618} 2619 2620void HTMLTreeBuilder::defaultForInHeadNoscript() 2621{ 2622 AtomicHTMLToken endNoscript(HTMLToken::EndTag, noscriptTag.localName()); 2623 processEndTag(&endNoscript); 2624} 2625 2626void HTMLTreeBuilder::defaultForAfterHead() 2627{ 2628 AtomicHTMLToken startBody(HTMLToken::StartTag, bodyTag.localName()); 2629 processStartTag(&startBody); 2630 m_framesetOk = true; 2631} 2632 2633void HTMLTreeBuilder::defaultForInTableText() 2634{ 2635 String characters = m_pendingTableCharacters.toString(); 2636 m_pendingTableCharacters.clear(); 2637 if (!isAllWhitespace(characters)) { 2638 // FIXME: parse error 2639 HTMLConstructionSite::RedirectToFosterParentGuard redirecter(m_tree); 2640 m_tree.reconstructTheActiveFormattingElements(); 2641 m_tree.insertTextNode(characters, NotAllWhitespace); 2642 m_framesetOk = false; 2643 setInsertionMode(m_originalInsertionMode); 2644 return; 2645 } 2646 m_tree.insertTextNode(characters); 2647 setInsertionMode(m_originalInsertionMode); 2648} 2649 2650bool HTMLTreeBuilder::processStartTagForInHead(AtomicHTMLToken* token) 2651{ 2652 ASSERT(token->type() == HTMLToken::StartTag); 2653 if (token->name() == htmlTag) { 2654 processHtmlStartTagForInBody(token); 2655 return true; 2656 } 2657 if (token->name() == baseTag 2658 || token->name() == basefontTag 2659 || token->name() == bgsoundTag 2660 || token->name() == commandTag 2661 || token->name() == linkTag 2662 || token->name() == metaTag) { 2663 m_tree.insertSelfClosingHTMLElement(token); 2664 // Note: The custom processing for the <meta> tag is done in HTMLMetaElement::process(). 2665 return true; 2666 } 2667 if (token->name() == titleTag) { 2668 processGenericRCDATAStartTag(token); 2669 return true; 2670 } 2671 if (token->name() == noscriptTag) { 2672 if (m_options.scriptEnabled) { 2673 processGenericRawTextStartTag(token); 2674 return true; 2675 } 2676 m_tree.insertHTMLElement(token); 2677 setInsertionMode(InHeadNoscriptMode); 2678 return true; 2679 } 2680 if (token->name() == noframesTag || token->name() == styleTag) { 2681 processGenericRawTextStartTag(token); 2682 return true; 2683 } 2684 if (token->name() == scriptTag) { 2685 processScriptStartTag(token); 2686 if (m_options.usePreHTML5ParserQuirks && token->selfClosing()) 2687 processFakeEndTag(scriptTag); 2688 return true; 2689 } 2690#if ENABLE(TEMPLATE_ELEMENT) 2691 if (token->name() == templateTag) { 2692 processTemplateStartTag(token); 2693 return true; 2694 } 2695#endif 2696 if (token->name() == headTag) { 2697 parseError(token); 2698 return true; 2699 } 2700 return false; 2701} 2702 2703void HTMLTreeBuilder::processGenericRCDATAStartTag(AtomicHTMLToken* token) 2704{ 2705 ASSERT(token->type() == HTMLToken::StartTag); 2706 m_tree.insertHTMLElement(token); 2707 if (m_parser->tokenizer()) 2708 m_parser->tokenizer()->setState(HTMLTokenizer::RCDATAState); 2709 m_originalInsertionMode = m_insertionMode; 2710 setInsertionMode(TextMode); 2711} 2712 2713void HTMLTreeBuilder::processGenericRawTextStartTag(AtomicHTMLToken* token) 2714{ 2715 ASSERT(token->type() == HTMLToken::StartTag); 2716 m_tree.insertHTMLElement(token); 2717 if (m_parser->tokenizer()) 2718 m_parser->tokenizer()->setState(HTMLTokenizer::RAWTEXTState); 2719 m_originalInsertionMode = m_insertionMode; 2720 setInsertionMode(TextMode); 2721} 2722 2723void HTMLTreeBuilder::processScriptStartTag(AtomicHTMLToken* token) 2724{ 2725 ASSERT(token->type() == HTMLToken::StartTag); 2726 m_tree.insertScriptElement(token); 2727 if (m_parser->tokenizer()) 2728 m_parser->tokenizer()->setState(HTMLTokenizer::ScriptDataState); 2729 m_originalInsertionMode = m_insertionMode; 2730 2731 TextPosition position = m_parser->textPosition(); 2732 2733 m_scriptToProcessStartPosition = position; 2734 2735 setInsertionMode(TextMode); 2736} 2737 2738// http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html#tree-construction 2739bool HTMLTreeBuilder::shouldProcessTokenInForeignContent(AtomicHTMLToken* token) 2740{ 2741 if (m_tree.isEmpty()) 2742 return false; 2743 HTMLStackItem* item = m_tree.currentStackItem(); 2744 if (item->isInHTMLNamespace()) 2745 return false; 2746 if (HTMLElementStack::isMathMLTextIntegrationPoint(item)) { 2747 if (token->type() == HTMLToken::StartTag 2748 && token->name() != MathMLNames::mglyphTag 2749 && token->name() != MathMLNames::malignmarkTag) 2750 return false; 2751 if (token->type() == HTMLToken::Character) 2752 return false; 2753 } 2754 if (item->hasTagName(MathMLNames::annotation_xmlTag) 2755 && token->type() == HTMLToken::StartTag 2756 && token->name() == SVGNames::svgTag) 2757 return false; 2758 if (HTMLElementStack::isHTMLIntegrationPoint(item)) { 2759 if (token->type() == HTMLToken::StartTag) 2760 return false; 2761 if (token->type() == HTMLToken::Character) 2762 return false; 2763 } 2764 if (token->type() == HTMLToken::EndOfFile) 2765 return false; 2766 return true; 2767} 2768 2769void HTMLTreeBuilder::processTokenInForeignContent(AtomicHTMLToken* token) 2770{ 2771 switch (token->type()) { 2772 case HTMLToken::Uninitialized: 2773 ASSERT_NOT_REACHED(); 2774 break; 2775 case HTMLToken::DOCTYPE: 2776 parseError(token); 2777 break; 2778 case HTMLToken::StartTag: { 2779 if (token->name() == bTag 2780 || token->name() == bigTag 2781 || token->name() == blockquoteTag 2782 || token->name() == bodyTag 2783 || token->name() == brTag 2784 || token->name() == centerTag 2785 || token->name() == codeTag 2786 || token->name() == ddTag 2787 || token->name() == divTag 2788 || token->name() == dlTag 2789 || token->name() == dtTag 2790 || token->name() == emTag 2791 || token->name() == embedTag 2792 || isNumberedHeaderTag(token->name()) 2793 || token->name() == headTag 2794 || token->name() == hrTag 2795 || token->name() == iTag 2796 || token->name() == imgTag 2797 || token->name() == liTag 2798 || token->name() == listingTag 2799 || token->name() == menuTag 2800 || token->name() == metaTag 2801 || token->name() == nobrTag 2802 || token->name() == olTag 2803 || token->name() == pTag 2804 || token->name() == preTag 2805 || token->name() == rubyTag 2806 || token->name() == sTag 2807 || token->name() == smallTag 2808 || token->name() == spanTag 2809 || token->name() == strongTag 2810 || token->name() == strikeTag 2811 || token->name() == subTag 2812 || token->name() == supTag 2813 || token->name() == tableTag 2814 || token->name() == ttTag 2815 || token->name() == uTag 2816 || token->name() == ulTag 2817 || token->name() == varTag 2818 || (token->name() == fontTag && (token->getAttributeItem(colorAttr) || token->getAttributeItem(faceAttr) || token->getAttributeItem(sizeAttr)))) { 2819 parseError(token); 2820 m_tree.openElements()->popUntilForeignContentScopeMarker(); 2821 processStartTag(token); 2822 return; 2823 } 2824 const AtomicString& currentNamespace = m_tree.currentStackItem()->namespaceURI(); 2825 if (currentNamespace == MathMLNames::mathmlNamespaceURI) 2826 adjustMathMLAttributes(token); 2827 if (currentNamespace == SVGNames::svgNamespaceURI) { 2828 adjustSVGTagNameCase(token); 2829 adjustSVGAttributes(token); 2830 } 2831 adjustForeignAttributes(token); 2832 m_tree.insertForeignElement(token, currentNamespace); 2833 break; 2834 } 2835 case HTMLToken::EndTag: { 2836 if (m_tree.currentStackItem()->namespaceURI() == SVGNames::svgNamespaceURI) 2837 adjustSVGTagNameCase(token); 2838 2839 if (token->name() == SVGNames::scriptTag && m_tree.currentStackItem()->hasTagName(SVGNames::scriptTag)) { 2840 if (scriptingContentIsAllowed(m_tree.parserContentPolicy())) 2841 m_scriptToProcess = m_tree.currentElement(); 2842 m_tree.openElements()->pop(); 2843 return; 2844 } 2845 if (!m_tree.currentStackItem()->isInHTMLNamespace()) { 2846 // FIXME: This code just wants an Element* iterator, instead of an ElementRecord* 2847 HTMLElementStack::ElementRecord* nodeRecord = m_tree.openElements()->topRecord(); 2848 if (!nodeRecord->stackItem()->hasLocalName(token->name())) 2849 parseError(token); 2850 while (1) { 2851 if (nodeRecord->stackItem()->hasLocalName(token->name())) { 2852 m_tree.openElements()->popUntilPopped(nodeRecord->element()); 2853 return; 2854 } 2855 nodeRecord = nodeRecord->next(); 2856 2857 if (nodeRecord->stackItem()->isInHTMLNamespace()) 2858 break; 2859 } 2860 } 2861 // Otherwise, process the token according to the rules given in the section corresponding to the current insertion mode in HTML content. 2862 processEndTag(token); 2863 break; 2864 } 2865 case HTMLToken::Comment: 2866 m_tree.insertComment(token); 2867 return; 2868 case HTMLToken::Character: { 2869 String characters = String(token->characters(), token->charactersLength()); 2870 m_tree.insertTextNode(characters); 2871 if (m_framesetOk && !isAllWhitespaceOrReplacementCharacters(characters)) 2872 m_framesetOk = false; 2873 break; 2874 } 2875 case HTMLToken::EndOfFile: 2876 ASSERT_NOT_REACHED(); 2877 break; 2878 } 2879} 2880 2881void HTMLTreeBuilder::finished() 2882{ 2883 if (isParsingFragment()) 2884 return; 2885 2886#if ENABLE(TEMPLATE_ELEMENT) 2887 ASSERT(m_templateInsertionModes.isEmpty()); 2888#endif 2889 2890 ASSERT(m_isAttached); 2891 // Warning, this may detach the parser. Do not do anything else after this. 2892 m_tree.finishedParsing(); 2893} 2894 2895void HTMLTreeBuilder::parseError(AtomicHTMLToken*) 2896{ 2897} 2898 2899} 2900