📄 htmlparser.cpp
字号:
// let's be stupid and just try to insert it. // this should work if the document is well-formed Node* newNode = m_current->addChild(n); if (!newNode) return handleError(n, flat, localName, tagPriority); // Try to handle the error. // don't push elements without end tags (e.g., <img>) on the stack bool parentAttached = m_current->attached(); if (tagPriority > 0 && !flat) { if (newNode == m_current) { // This case should only be hit when a demoted <form> is placed inside a table. ASSERT(localName == formTag); reportError(FormInsideTablePartError, &m_current->localName()); } else { // The pushBlock function transfers ownership of current to the block stack // so we're guaranteed that m_didRefCurrent is false. The code below is an // optimized version of setCurrent that takes advantage of that fact and also // assumes that newNode is neither 0 nor a pointer to the document. pushBlock(localName, tagPriority); newNode->beginParsingChildren(); ASSERT(!m_didRefCurrent); newNode->ref(); m_current = newNode; m_didRefCurrent = true; } if (parentAttached && !n->attached() && !m_isParsingFragment) n->attach(); } else { if (parentAttached && !n->attached() && !m_isParsingFragment) n->attach(); n->finishParsingChildren(); } if (localName == htmlTag && m_document->frame()) m_document->frame()->loader()->dispatchDocumentElementAvailable(); return true;}bool HTMLParser::handleError(Node* n, bool flat, const AtomicString& localName, int tagPriority){ // Error handling code. This is just ad hoc handling of specific parent/child combinations. HTMLElement* e; bool handled = false; // 1. Check out the element's tag name to decide how to deal with errors. if (n->isHTMLElement()) { HTMLElement* h = static_cast<HTMLElement*>(n); if (h->hasLocalName(trTag) || h->hasLocalName(thTag) || h->hasLocalName(tdTag)) { if (m_inStrayTableContent && !isTableRelated(m_current)) { reportError(MisplacedTablePartError, &localName, &m_current->localName()); // pop out to the nearest enclosing table-related tag. while (m_blockStack && !isTableRelated(m_current)) popOneBlock(); return insertNode(n); } } else if (h->hasLocalName(headTag)) { if (!m_current->isDocumentNode() && !m_current->hasTagName(htmlTag)) { reportError(MisplacedHeadError); return false; } } else if (h->hasLocalName(metaTag) || h->hasLocalName(linkTag) || h->hasLocalName(baseTag)) { bool createdHead = false; if (!m_head) { createHead(); createdHead = true; } if (m_head) { if (!createdHead) reportError(MisplacedHeadContentError, &localName, &m_current->localName()); if (m_head->addChild(n)) { if (!n->attached() && !m_isParsingFragment) n->attach(); return true; } else return false; } } else if (h->hasLocalName(htmlTag)) { if (!m_current->isDocumentNode() ) { if (m_document->documentElement() && m_document->documentElement()->hasTagName(htmlTag)) { reportError(RedundantHTMLBodyError, &localName); // we have another <HTML> element.... apply attributes to existing one // make sure we don't overwrite already existing attributes NamedAttrMap* map = static_cast<Element*>(n)->attributes(true); Element* existingHTML = static_cast<Element*>(m_document->documentElement()); NamedAttrMap* bmap = existingHTML->attributes(false); for (unsigned l = 0; map && l < map->length(); ++l) { Attribute* it = map->attributeItem(l); if (!bmap->getAttributeItem(it->name())) existingHTML->setAttribute(it->name(), it->value()); } } return false; } } else if (h->hasLocalName(titleTag) || h->hasLocalName(styleTag)) { bool createdHead = false; if (!m_head) { createHead(); createdHead = true; } if (m_head) { Node* newNode = m_head->addChild(n); if (!newNode) { setSkipMode(h->tagQName()); return false; } if (!createdHead) reportError(MisplacedHeadContentError, &localName, &m_current->localName()); pushBlock(localName, tagPriority); newNode->beginParsingChildren(); setCurrent(newNode); if (!n->attached() && !m_isParsingFragment) n->attach(); return true; } if (m_inBody) { setSkipMode(h->tagQName()); return false; } } else if (h->hasLocalName(bodyTag)) { if (m_inBody && m_document->body()) { // we have another <BODY> element.... apply attributes to existing one // make sure we don't overwrite already existing attributes // some sites use <body bgcolor=rightcolor>...<body bgcolor=wrongcolor> reportError(RedundantHTMLBodyError, &localName); NamedAttrMap* map = static_cast<Element*>(n)->attributes(true); Element* existingBody = m_document->body(); NamedAttrMap* bmap = existingBody->attributes(false); for (unsigned l = 0; map && l < map->length(); ++l) { Attribute* it = map->attributeItem(l); if (!bmap->getAttributeItem(it->name())) existingBody->setAttribute(it->name(), it->value()); } return false; } else if (!m_current->isDocumentNode()) return false; } else if (h->hasLocalName(areaTag)) { if (m_currentMapElement) { reportError(MisplacedAreaError, &m_current->localName()); m_currentMapElement->addChild(n); if (!n->attached() && !m_isParsingFragment) n->attach(); handled = true; return true; } return false; } else if (h->hasLocalName(colgroupTag) || h->hasLocalName(captionTag)) { if (isTableRelated(m_current)) { while (m_blockStack && isTablePart(m_current)) popOneBlock(); return insertNode(n); } } } else if (n->isCommentNode() && !m_head) return false; // 2. Next we examine our currently active element to do some further error handling. if (m_current->isHTMLElement()) { HTMLElement* h = static_cast<HTMLElement*>(m_current); const AtomicString& currentTagName = h->localName(); if (h->hasLocalName(htmlTag)) { HTMLElement* elt = n->isHTMLElement() ? static_cast<HTMLElement*>(n) : 0; if (elt && (elt->hasLocalName(scriptTag) || elt->hasLocalName(styleTag) || elt->hasLocalName(metaTag) || elt->hasLocalName(linkTag) || elt->hasLocalName(objectTag) || elt->hasLocalName(embedTag) || elt->hasLocalName(titleTag) || elt->hasLocalName(isindexTag) || elt->hasLocalName(baseTag))) { if (!m_head) { m_head = new HTMLHeadElement(headTag, m_document); e = m_head; insertNode(e); handled = true; } } else { if (n->isTextNode()) { Text* t = static_cast<Text*>(n); if (t->containsOnlyWhitespace()) return false; } if (!m_haveFrameSet) { e = new HTMLBodyElement(bodyTag, m_document); startBody(); insertNode(e); handled = true; } else reportError(MisplacedFramesetContentError, &localName); } } else if (h->hasLocalName(headTag)) { if (n->hasTagName(htmlTag)) return false; else { // This means the body starts here... if (!m_haveFrameSet) { popBlock(currentTagName); e = new HTMLBodyElement(bodyTag, m_document); startBody(); insertNode(e); handled = true; } else reportError(MisplacedFramesetContentError, &localName); } } else if (h->hasLocalName(addressTag) || h->hasLocalName(fontTag) || h->hasLocalName(styleTag) || h->hasLocalName(titleTag)) { reportError(MisplacedContentRetryError, &localName, ¤tTagName); popBlock(currentTagName); handled = true; } else if (h->hasLocalName(captionTag)) { // Illegal content in a caption. Close the caption and try again. reportError(MisplacedCaptionContentError, &localName); popBlock(currentTagName); if (isTablePart(n)) return insertNode(n, flat); } else if (h->hasLocalName(tableTag) || h->hasLocalName(trTag) || isTableSection(h)) { if (n->hasTagName(tableTag)) { reportError(MisplacedTableError, ¤tTagName); if (m_isParsingFragment && !h->hasLocalName(tableTag)) // fragment may contain table parts without <table> ancestor, pop them one by one popBlock(h->localName()); popBlock(localName); // end the table handled = true; // ...and start a new one } else { ExceptionCode ec = 0; Node* node = m_current; Node* parent = node->parentNode(); // A script may have removed the current node's parent from the DOM // http://bugs.webkit.org/show_bug.cgi?id=7137 // FIXME: we should do real recovery here and re-parent with the correct node. if (!parent) return false; Node* grandparent = parent->parentNode(); if (n->isTextNode() || (h->hasLocalName(trTag) && isTableSection(parent) && grandparent && grandparent->hasTagName(tableTag)) || ((!n->hasTagName(tdTag) && !n->hasTagName(thTag) && !n->hasTagName(formTag) && !n->hasTagName(scriptTag)) && isTableSection(node) && parent->hasTagName(tableTag))) { node = (node->hasTagName(tableTag)) ? node : ((node->hasTagName(trTag)) ? grandparent : parent); // This can happen with fragments if (!node) return false; Node* parent = node->parentNode(); if (!parent) return false; parent->insertBefore(n, node, ec); if (!ec) { reportError(StrayTableContentError, &localName, ¤tTagName); if (n->isHTMLElement() && tagPriority > 0 && !flat && static_cast<HTMLElement*>(n)->endTagRequirement() != TagStatusForbidden) { pushBlock(localName, tagPriority); n->beginParsingChildren(); setCurrent(n); m_inStrayTableContent++; m_blockStack->strayTableContent = true; } return true; } } if (!ec) { if (m_current->hasTagName(trTag)) { reportError(TablePartRequiredError, &localName, &tdTag.localName()); e = new HTMLTableCellElement(tdTag, m_document); } else if (m_current->hasTagName(tableTag)) { // Don't report an error in this case, since making a <tbody> happens all the time when you have <table><tr>, // and it isn't really a parse error per se. e = new HTMLTableSectionElement(tbodyTag, m_document); } else { reportError(TablePartRequiredError, &localName, &trTag.localName()); e = new HTMLTableRowElement(trTag, m_document); } insertNode(e); handled = true; } } } else if (h->hasLocalName(objectTag)) { reportError(MisplacedContentRetryError, &localName, ¤tTagName); popBlock(objectTag); handled = true; } else if (h->hasLocalName(pTag) || isHeaderTag(currentTagName)) { if (!isInline(n)) { popBlock(currentTagName); handled = true; } } else if (h->hasLocalName(optionTag) || h->hasLocalName(optgroupTag)) { if (localName == optgroupTag) { popBlock(currentTagName); handled = true; } else if (localName == selectTag) { // IE treats a nested select as </select>. Let's do the same popBlock(localName); } } else if (h->hasLocalName(selectTag)) { if (localName == inputTag || localName == textareaTag) { reportError(MisplacedContentRetryError, &localName, ¤tTagName); popBlock(currentTagName); handled = true; } } else if (h->hasLocalName(colgroupTag)) { popBlock(currentTagName); handled = true; } else if (!h->hasLocalName(bodyTag)) { if (isInline(m_current)) { popInlineBlocks(); handled = true; } } } else if (m_current->isDocumentNode()) { if (n->isTextNode()) { Text* t = static_cast<Text*>(n); if (t->containsOnlyWhitespace()) return false; } if (!m_document->documentElement()) { e = new HTMLHtmlElement(htmlTag, m_document);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -