📄 htmlparser.cpp
字号:
// Set our strayTableContent boolean if needed, so that the reopened tag also knows // that it is inside a malformed table. m_blockStack->strayTableContent = malformedTableParent != 0; if (m_blockStack->strayTableContent) m_inStrayTableContent++; // Clear our malformed table parent variable. malformedTableParent = 0; // Update |current| manually to point to the new node. setCurrent(newNode.get()); // Advance to the next tag that needs to be reopened. HTMLStackElem* next = elem->next; elem->derefNode(); delete elem; elem = next; }}void HTMLParser::pushBlock(const AtomicString& tagName, int level){ m_blockStack = new HTMLStackElem(tagName, level, m_current, m_didRefCurrent, m_blockStack); m_didRefCurrent = false; if (tagName == pTag) m_hasPElementInScope = InScope; else if (isScopingTag(tagName)) m_hasPElementInScope = NotInScope;}void HTMLParser::popBlock(const AtomicString& tagName, bool reportErrors){ HTMLStackElem* elem = m_blockStack; int maxLevel = 0; while (elem && (elem->tagName != tagName)) { if (maxLevel < elem->level) maxLevel = elem->level; elem = elem->next; } if (!elem) { if (reportErrors) reportError(StrayCloseTagError, &tagName, 0, true); return; } if (maxLevel > elem->level) { // We didn't match because the tag is in a different scope, e.g., // <b><p>Foo</b>. Try to correct the problem. if (!isResidualStyleTag(tagName)) return; return handleResidualStyleCloseTagAcrossBlocks(elem); } bool isAffectedByStyle = isAffectedByResidualStyle(elem->tagName); HTMLStackElem* residualStyleStack = 0; Node* malformedTableParent = 0; elem = m_blockStack; unsigned stackDepth = 1; unsigned redundantStyleCount = 0; while (elem) { if (elem->tagName == tagName) { int strayTable = m_inStrayTableContent; popOneBlock(); elem = 0; // This element was the root of some malformed content just inside an implicit or // explicit <tbody> or <tr>. // If we end up needing to reopen residual style tags, the root of the reopened chain // must also know that it is the root of malformed content inside a <tbody>/<tr>. if (strayTable && (m_inStrayTableContent < strayTable) && residualStyleStack) { Node* curr = m_current; while (curr && !curr->hasTagName(tableTag)) curr = curr->parentNode(); malformedTableParent = curr ? curr->parentNode() : 0; } } else { if (m_currentFormElement && elem->tagName == formTag) // A <form> is being closed prematurely (and this is // malformed HTML). Set an attribute on the form to clear out its // bottom margin. m_currentFormElement->setMalformed(true); // Schedule this tag for reopening // after we complete the close of this entire block. if (isAffectedByStyle && isResidualStyleTag(elem->tagName) && stackDepth++ < cResidualStyleMaxDepth) { // We've overloaded the use of stack elements and are just reusing the // struct with a slightly different meaning to the variables. Instead of chaining // from innermost to outermost, we build up a list of all the tags we need to reopen // from the outermost to the innermost, i.e., residualStyleStack will end up pointing // to the outermost tag we need to reopen. // We also set elem->node to be the actual element that corresponds to the ID stored in // elem->id rather than the node that you should pop to when the element gets pulled off // the stack. if (residualStyleStack && elem->tagName == residualStyleStack->tagName && elem->node->attributes()->mapsEquivalent(residualStyleStack->node->attributes())) redundantStyleCount++; else redundantStyleCount = 0; if (redundantStyleCount < cMaxRedundantTagDepth) moveOneBlockToStack(residualStyleStack); else popOneBlock(); } else popOneBlock(); elem = m_blockStack; } } reopenResidualStyleTags(residualStyleStack, malformedTableParent);}inline HTMLStackElem* HTMLParser::popOneBlockCommon(){ HTMLStackElem* elem = m_blockStack; // Form elements restore their state during the parsing process. // Also, a few elements (<applet>, <object>) need to know when all child elements (<param>s) are available. if (m_current && elem->node != m_current) m_current->finishParsingChildren(); m_blockStack = elem->next; m_current = elem->node; m_didRefCurrent = elem->didRefNode; if (elem->strayTableContent) m_inStrayTableContent--; if (elem->tagName == pTag) m_hasPElementInScope = NotInScope; else if (isScopingTag(elem->tagName)) m_hasPElementInScope = Unknown; return elem;}void HTMLParser::popOneBlock(){ // Store the current node before popOneBlockCommon overwrites it. Node* lastCurrent = m_current; bool didRefLastCurrent = m_didRefCurrent; delete popOneBlockCommon(); if (didRefLastCurrent) lastCurrent->deref();}void HTMLParser::moveOneBlockToStack(HTMLStackElem*& head){ // We'll be using the stack element we're popping, but for the current node. // See the two callers for details. // Store the current node before popOneBlockCommon overwrites it. Node* lastCurrent = m_current; bool didRefLastCurrent = m_didRefCurrent; // Pop the block, but don't deref the current node as popOneBlock does because // we'll be using the pointer in the new stack element. HTMLStackElem* elem = popOneBlockCommon(); // Transfer the current node into the stack element. // No need to deref the old elem->node because popOneBlockCommon transferred // it into the m_current/m_didRefCurrent fields. elem->node = lastCurrent; elem->didRefNode = didRefLastCurrent; elem->next = head; head = elem;}void HTMLParser::checkIfHasPElementInScope(){ m_hasPElementInScope = NotInScope; HTMLStackElem* elem = m_blockStack; while (elem) { const AtomicString& tagName = elem->tagName; if (tagName == pTag) { m_hasPElementInScope = InScope; return; } else if (isScopingTag(tagName)) return; elem = elem->next; }}void HTMLParser::popInlineBlocks(){ while (m_blockStack && isInline(m_current)) popOneBlock();}void HTMLParser::freeBlock(){ while (m_blockStack) popOneBlock();}void HTMLParser::createHead(){ if (m_head || !m_document->documentElement()) return; m_head = new HTMLHeadElement(headTag, m_document); HTMLElement* body = m_document->body(); ExceptionCode ec = 0; m_document->documentElement()->insertBefore(m_head, body, ec); if (ec) m_head = 0; // If the body does not exist yet, then the <head> should be pushed as the current block. if (m_head && !body) { pushBlock(m_head->localName(), m_head->tagPriority()); setCurrent(m_head); }}PassRefPtr<Node> HTMLParser::handleIsindex(Token* t){ RefPtr<Node> n = new HTMLDivElement(divTag, m_document); NamedMappedAttrMap* attrs = t->attrs.get(); RefPtr<HTMLIsIndexElement> isIndex = new HTMLIsIndexElement(isindexTag, m_document, m_currentFormElement.get()); isIndex->setAttributeMap(attrs); isIndex->setAttribute(typeAttr, "khtml_isindex"); String text = searchableIndexIntroduction(); if (attrs) { if (Attribute* a = attrs->getAttributeItem(promptAttr)) text = a->value().string() + " "; t->attrs = 0; } n->addChild(new HTMLHRElement(hrTag, m_document)); n->addChild(new Text(m_document, text)); n->addChild(isIndex.release()); n->addChild(new HTMLHRElement(hrTag, m_document)); return n.release();}void HTMLParser::startBody(){ if (m_inBody) return; m_inBody = true; if (m_isindexElement) { insertNode(m_isindexElement.get(), true /* don't descend into this node */); m_isindexElement = 0; }}void HTMLParser::finished(){ // In the case of a completely empty document, here's the place to create the HTML element. if (m_current && m_current->isDocumentNode() && !m_document->documentElement()) insertNode(new HTMLHtmlElement(htmlTag, m_document)); // This ensures that "current" is not left pointing to a node when the document is destroyed. freeBlock(); setCurrent(0); // Warning, this may delete the tokenizer and parser, so don't try to do anything else after this. if (!m_isParsingFragment) m_document->finishedParsing();}void HTMLParser::reportErrorToConsole(HTMLParserErrorCode errorCode, const AtomicString* tagName1, const AtomicString* tagName2, bool closeTags){ Frame* frame = m_document->frame(); if (!frame) return; HTMLTokenizer* htmlTokenizer = static_cast<HTMLTokenizer*>(m_document->tokenizer()); int lineNumber = htmlTokenizer->lineNumber() + 1; AtomicString tag1; AtomicString tag2; if (tagName1) { if (*tagName1 == "#text") tag1 = "Text"; else if (*tagName1 == "#comment") tag1 = "<!-- comment -->"; else tag1 = (closeTags ? "</" : "<") + *tagName1 + ">"; } if (tagName2) { if (*tagName2 == "#text") tag2 = "Text"; else if (*tagName2 == "#comment") tag2 = "<!-- comment -->"; else tag2 = (closeTags ? "</" : "<") + *tagName2 + ">"; } const char* errorMsg = htmlParserErrorMessageTemplate(errorCode); if (!errorMsg) return; String message; if (htmlTokenizer->processingContentWrittenByScript()) message += htmlParserDocumentWriteMessage(); message += errorMsg; message.replace("%tag1", tag1); message.replace("%tag2", tag2); frame->domWindow()->console()->addMessage(HTMLMessageSource, isWarning(errorCode) ? WarningMessageLevel : ErrorMessageLevel, message, lineNumber, m_document->url().string());}}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -