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