📄 markup.cpp
字号:
// Don't add namespace attribute if it is already defined for this elem. const AtomicString& prefix = elem->prefix(); AtomicString attr = !prefix.isEmpty() ? "xmlns:" + prefix : "xmlns"; return !elem->hasAttribute(attr);}static bool shouldAddNamespaceAttr(const Attribute* attr, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces){ // Don't add namespace attributes twice DEFINE_STATIC_LOCAL(const AtomicString, xmlnsURI, ("http://www.w3.org/2000/xmlns/")); DEFINE_STATIC_LOCAL(const QualifiedName, xmlnsAttr, (nullAtom, "xmlns", xmlnsURI)); if (attr->name() == xmlnsAttr) { namespaces.set(emptyAtom.impl(), attr->value().impl()); return false; } QualifiedName xmlnsPrefixAttr("xmlns", attr->localName(), xmlnsURI); if (attr->name() == xmlnsPrefixAttr) { namespaces.set(attr->localName().impl(), attr->value().impl()); return false; } return true;}static void appendNamespace(Vector<UChar>& result, const AtomicString& prefix, const AtomicString& ns, HashMap<AtomicStringImpl*, AtomicStringImpl*>& namespaces){ if (ns.isEmpty()) return; // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key AtomicStringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl(); AtomicStringImpl* foundNS = namespaces.get(pre); if (foundNS != ns.impl()) { namespaces.set(pre, ns.impl()); DEFINE_STATIC_LOCAL(const String, xmlns, ("xmlns")); result.append(' '); append(result, xmlns); if (!prefix.isEmpty()) { result.append(':'); append(result, prefix); } result.append('='); result.append('"'); appendAttributeValue(result, ns, false); result.append('"'); }}static void appendDocumentType(Vector<UChar>& result, const DocumentType* n){ if (n->name().isEmpty()) return; append(result, "<!DOCTYPE "); append(result, n->name()); if (!n->publicId().isEmpty()) { append(result, " PUBLIC \""); append(result, n->publicId()); append(result, "\""); if (!n->systemId().isEmpty()) { append(result, " \""); append(result, n->systemId()); append(result, "\""); } } else if (!n->systemId().isEmpty()) { append(result, " SYSTEM \""); append(result, n->systemId()); append(result, "\""); } if (!n->internalSubset().isEmpty()) { append(result, " ["); append(result, n->internalSubset()); append(result, "]"); } append(result, ">");}static void appendStartMarkup(Vector<UChar>& result, const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0){ bool documentIsHTML = node->document()->isHTMLDocument(); switch (node->nodeType()) { case Node::TEXT_NODE: { if (Node* parent = node->parentNode()) { if (parent->hasTagName(scriptTag) || parent->hasTagName(styleTag) || parent->hasTagName(textareaTag) || parent->hasTagName(xmpTag)) { appendUCharRange(result, ucharRange(node, range)); break; } } if (!annotate) { appendEscapedContent(result, ucharRange(node, range), documentIsHTML); break; } bool useRenderedText = !enclosingNodeWithTag(Position(const_cast<Node*>(node), 0), selectTag); String markup = escapeContentText(useRenderedText ? renderedText(node, range) : stringValueForRange(node, range), false); if (annotate) markup = convertHTMLTextToInterchangeFormat(markup, static_cast<const Text*>(node)); append(result, markup); break; } case Node::COMMENT_NODE: // FIXME: Comment content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "-->". append(result, "<!--"); append(result, static_cast<const Comment*>(node)->nodeValue()); append(result, "-->"); break; case Node::DOCUMENT_NODE: case Node::DOCUMENT_FRAGMENT_NODE: break; case Node::DOCUMENT_TYPE_NODE: appendDocumentType(result, static_cast<const DocumentType*>(node)); break; case Node::PROCESSING_INSTRUCTION_NODE: { // FIXME: PI data is not escaped, but XMLSerializer (and possibly other callers) this should raise an exception if it includes "?>". const ProcessingInstruction* n = static_cast<const ProcessingInstruction*>(node); append(result, "<?"); append(result, n->target()); append(result, " "); append(result, n->data()); append(result, "?>"); break; } case Node::ELEMENT_NODE: { result.append('<'); const Element* el = static_cast<const Element*>(node); bool convert = convertBlocksToInlines & isBlock(const_cast<Node*>(node)); append(result, el->nodeNamePreservingCase()); NamedAttrMap *attrs = el->attributes(); unsigned length = attrs->length(); if (!documentIsHTML && namespaces && shouldAddNamespaceElem(el)) appendNamespace(result, el->prefix(), el->namespaceURI(), *namespaces); for (unsigned int i = 0; i < length; i++) { Attribute *attr = attrs->attributeItem(i); // We'll handle the style attribute separately, below. if (attr->name() == styleAttr && el->isHTMLElement() && (annotate || convert)) continue; result.append(' '); if (documentIsHTML) append(result, attr->name().localName()); else append(result, attr->name().toString()); result.append('='); if (el->isURLAttribute(attr)) appendQuotedURLAttributeValue(result, attr->value()); else { result.append('\"'); appendAttributeValue(result, attr->value(), documentIsHTML); result.append('\"'); } if (!documentIsHTML && namespaces && shouldAddNamespaceAttr(attr, *namespaces)) appendNamespace(result, attr->prefix(), attr->namespaceURI(), *namespaces); } if (el->isHTMLElement() && (annotate || convert)) { Element* element = const_cast<Element*>(el); RefPtr<CSSMutableStyleDeclaration> style = static_cast<HTMLElement*>(element)->getInlineStyleDecl()->copy(); if (annotate) { RefPtr<CSSMutableStyleDeclaration> styleFromMatchedRules = styleFromMatchedRulesForElement(const_cast<Element*>(el)); // Styles from the inline style declaration, held in the variable "style", take precedence // over those from matched rules. styleFromMatchedRules->merge(style.get()); style = styleFromMatchedRules; RefPtr<CSSComputedStyleDeclaration> computedStyleForElement = computedStyle(element); RefPtr<CSSMutableStyleDeclaration> fromComputedStyle = CSSMutableStyleDeclaration::create(); { CSSMutableStyleDeclaration::const_iterator end = style->end(); for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) { const CSSProperty& property = *it; CSSValue* value = property.value(); // The property value, if it's a percentage, may not reflect the actual computed value. // For example: style="height: 1%; overflow: visible;" in quirksmode // FIXME: There are others like this, see <rdar://problem/5195123> Slashdot copy/paste fidelity problem if (value->cssValueType() == CSSValue::CSS_PRIMITIVE_VALUE) if (static_cast<CSSPrimitiveValue*>(value)->primitiveType() == CSSPrimitiveValue::CSS_PERCENTAGE) if (RefPtr<CSSValue> computedPropertyValue = computedStyleForElement->getPropertyCSSValue(property.id())) fromComputedStyle->addParsedProperty(CSSProperty(property.id(), computedPropertyValue)); } } style->merge(fromComputedStyle.get()); } if (convert) style->setProperty(CSSPropertyDisplay, CSSValueInline, true); if (style->length() > 0) { DEFINE_STATIC_LOCAL(const String, stylePrefix, (" style=\"")); append(result, stylePrefix); appendAttributeValue(result, style->cssText(), documentIsHTML); result.append('\"'); } } if (shouldSelfClose(el)) { if (el->isHTMLElement()) result.append(' '); // XHTML 1.0 <-> HTML compatibility. result.append('/'); } result.append('>'); break; } case Node::CDATA_SECTION_NODE: { // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "]]>". const CDATASection* n = static_cast<const CDATASection*>(node); append(result, "<![CDATA["); append(result, n->data()); append(result, "]]>"); break; } case Node::ATTRIBUTE_NODE: case Node::ENTITY_NODE: case Node::ENTITY_REFERENCE_NODE: case Node::NOTATION_NODE: case Node::XPATH_NAMESPACE_NODE: ASSERT_NOT_REACHED(); break; }}static String getStartMarkup(const Node *node, const Range *range, EAnnotateForInterchange annotate, bool convertBlocksToInlines = false, HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0){ Vector<UChar> result; appendStartMarkup(result, node, range, annotate, convertBlocksToInlines, namespaces); return String::adopt(result);}static inline bool doesHTMLForbidEndTag(const Node *node){ if (node->isHTMLElement()) { const HTMLElement* htmlElt = static_cast<const HTMLElement*>(node); return (htmlElt->endTagRequirement() == TagStatusForbidden); } return false;}// Rules of self-closure// 1. No elements in HTML documents use the self-closing syntax.// 2. Elements w/ children never self-close because they use a separate end tag.// 3. HTML elements which do not have a "forbidden" end tag will close with a separate end tag.// 4. Other elements self-close.static inline bool shouldSelfClose(const Node *node){ if (node->document()->isHTMLDocument()) return false; if (node->hasChildNodes()) return false; if (node->isHTMLElement() && !doesHTMLForbidEndTag(node)) return false; return true;}static void appendEndMarkup(Vector<UChar>& result, const Node* node){ if (!node->isElementNode() || shouldSelfClose(node) || (!node->hasChildNodes() && doesHTMLForbidEndTag(node))) return; result.append('<'); result.append('/'); append(result, static_cast<const Element*>(node)->nodeNamePreservingCase()); result.append('>');}static String getEndMarkup(const Node *node){ Vector<UChar> result; appendEndMarkup(result, node); return String::adopt(result);}static void appendMarkup(Vector<UChar>& result, Node* startNode, bool onlyIncludeChildren, Vector<Node*>* nodes, const HashMap<AtomicStringImpl*, AtomicStringImpl*>* namespaces = 0){ HashMap<AtomicStringImpl*, AtomicStringImpl*> namespaceHash; if (namespaces) namespaceHash = *namespaces; if (!onlyIncludeChildren) { if (nodes) nodes->append(startNode); appendStartMarkup(result,startNode, 0, DoNotAnnotateForInterchange, false, &namespaceHash); } // print children if (!(startNode->document()->isHTMLDocument() && doesHTMLForbidEndTag(startNode))) for (Node* current = startNode->firstChild(); current; current = current->nextSibling()) appendMarkup(result, current, false, nodes, &namespaceHash); // Print my ending tag if (!onlyIncludeChildren) appendEndMarkup(result, startNode);}static void completeURLs(Node* node, const String& baseURL){ Vector<AttributeChange> changes; KURL parsedBaseURL(baseURL); Node* end = node->traverseNextSibling(); for (Node* n = node; n != end; n = n->traverseNextNode()) { if (n->isElementNode()) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -