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