| OLD | NEW |
| 1 /* | 1 /* |
| 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights
reserved. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights
reserved. |
| 3 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. | 3 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. |
| 4 * | 4 * |
| 5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
| 6 * modification, are permitted provided that the following conditions | 6 * modification, are permitted provided that the following conditions |
| 7 * are met: | 7 * are met: |
| 8 * 1. Redistributions of source code must retain the above copyright | 8 * 1. Redistributions of source code must retain the above copyright |
| 9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
| 10 * 2. Redistributions in binary form must reproduce the above copyright | 10 * 2. Redistributions in binary form must reproduce the above copyright |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 89 if (!(offset + length)) | 89 if (!(offset + length)) |
| 90 return; | 90 return; |
| 91 | 91 |
| 92 ASSERT(offset + length <= source.length()); | 92 ASSERT(offset + length <= source.length()); |
| 93 if (source.is8Bit()) | 93 if (source.is8Bit()) |
| 94 appendCharactersReplacingEntitiesInternal(result, source.characters8() +
offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask); | 94 appendCharactersReplacingEntitiesInternal(result, source.characters8() +
offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask); |
| 95 else | 95 else |
| 96 appendCharactersReplacingEntitiesInternal(result, source.characters16()
+ offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask); | 96 appendCharactersReplacingEntitiesInternal(result, source.characters16()
+ offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask); |
| 97 } | 97 } |
| 98 | 98 |
| 99 MarkupAccumulator::MarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs resolve
UrlsMethod, const Range* range) | 99 MarkupAccumulator::MarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs resolve
UrlsMethod, const Range* range, SerializationType serializationType) |
| 100 : m_nodes(nodes) | 100 : m_nodes(nodes) |
| 101 , m_range(range) | 101 , m_range(range) |
| 102 , m_resolveURLsMethod(resolveUrlsMethod) | 102 , m_resolveURLsMethod(resolveUrlsMethod) |
| 103 , m_serializationType(serializationType) |
| 103 { | 104 { |
| 104 } | 105 } |
| 105 | 106 |
| 106 MarkupAccumulator::~MarkupAccumulator() | 107 MarkupAccumulator::~MarkupAccumulator() |
| 107 { | 108 { |
| 108 } | 109 } |
| 109 | 110 |
| 110 String MarkupAccumulator::serializeNodes(Node& targetNode, EChildrenOnly childre
nOnly, Vector<QualifiedName>* tagNamesToSkip) | 111 String MarkupAccumulator::serializeNodes(Node& targetNode, EChildrenOnly childre
nOnly, Vector<QualifiedName>* tagNamesToSkip) |
| 111 { | 112 { |
| 112 Namespaces* namespaces = 0; | 113 Namespaces* namespaces = 0; |
| 113 Namespaces namespaceHash; | 114 Namespaces namespaceHash; |
| 114 if (!targetNode.document().isHTMLDocument()) { | 115 if (!serializeAsHTMLDocument(targetNode)) { |
| 115 // Add pre-bound namespaces for XML fragments. | 116 // Add pre-bound namespaces for XML fragments. |
| 116 namespaceHash.set(xmlAtom.impl(), XMLNames::xmlNamespaceURI.impl()); | 117 namespaceHash.set(xmlAtom.impl(), XMLNames::xmlNamespaceURI.impl()); |
| 117 namespaces = &namespaceHash; | 118 namespaces = &namespaceHash; |
| 118 } | 119 } |
| 119 | 120 |
| 120 serializeNodesWithNamespaces(targetNode, childrenOnly, namespaces, tagNamesT
oSkip); | 121 serializeNodesWithNamespaces(targetNode, childrenOnly, namespaces, tagNamesT
oSkip); |
| 121 return m_markup.toString(); | 122 return m_markup.toString(); |
| 122 } | 123 } |
| 123 | 124 |
| 124 void MarkupAccumulator::serializeNodesWithNamespaces(Node& targetNode, EChildren
Only childrenOnly, const Namespaces* namespaces, Vector<QualifiedName>* tagNames
ToSkip) | 125 void MarkupAccumulator::serializeNodesWithNamespaces(Node& targetNode, EChildren
Only childrenOnly, const Namespaces* namespaces, Vector<QualifiedName>* tagNames
ToSkip) |
| 125 { | 126 { |
| 126 if (tagNamesToSkip) { | 127 if (tagNamesToSkip) { |
| 127 for (size_t i = 0; i < tagNamesToSkip->size(); ++i) { | 128 for (size_t i = 0; i < tagNamesToSkip->size(); ++i) { |
| 128 if (targetNode.hasTagName(tagNamesToSkip->at(i))) | 129 if (targetNode.hasTagName(tagNamesToSkip->at(i))) |
| 129 return; | 130 return; |
| 130 } | 131 } |
| 131 } | 132 } |
| 132 | 133 |
| 133 Namespaces namespaceHash; | 134 Namespaces namespaceHash; |
| 134 if (namespaces) | 135 if (namespaces) |
| 135 namespaceHash = *namespaces; | 136 namespaceHash = *namespaces; |
| 136 | 137 |
| 137 if (!childrenOnly) | 138 if (!childrenOnly) |
| 138 appendStartTag(targetNode, &namespaceHash); | 139 appendStartTag(targetNode, &namespaceHash); |
| 139 | 140 |
| 140 if (!(targetNode.document().isHTMLDocument() && elementCannotHaveEndTag(targ
etNode))) { | 141 if (!(serializeAsHTMLDocument(targetNode) && elementCannotHaveEndTag(targetN
ode))) { |
| 141 Node* current = targetNode.hasTagName(templateTag) ? toHTMLTemplateEleme
nt(targetNode).content()->firstChild() : targetNode.firstChild(); | 142 Node* current = targetNode.hasTagName(templateTag) ? toHTMLTemplateEleme
nt(targetNode).content()->firstChild() : targetNode.firstChild(); |
| 142 for ( ; current; current = current->nextSibling()) | 143 for ( ; current; current = current->nextSibling()) |
| 143 serializeNodesWithNamespaces(*current, IncludeNode, &namespaceHash,
tagNamesToSkip); | 144 serializeNodesWithNamespaces(*current, IncludeNode, &namespaceHash,
tagNamesToSkip); |
| 144 } | 145 } |
| 145 | 146 |
| 146 if (!childrenOnly) | 147 if (!childrenOnly) |
| 147 appendEndTag(targetNode); | 148 appendEndTag(targetNode); |
| 148 } | 149 } |
| 149 | 150 |
| 150 String MarkupAccumulator::resolveURLIfNeeded(const Element& element, const Strin
g& urlString) const | 151 String MarkupAccumulator::resolveURLIfNeeded(const Element& element, const Strin
g& urlString) const |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 281 } | 282 } |
| 282 | 283 |
| 283 result.appendLiteral("=\""); | 284 result.appendLiteral("=\""); |
| 284 appendAttributeValue(result, namespaceURI, false); | 285 appendAttributeValue(result, namespaceURI, false); |
| 285 result.append('"'); | 286 result.append('"'); |
| 286 } | 287 } |
| 287 } | 288 } |
| 288 | 289 |
| 289 EntityMask MarkupAccumulator::entityMaskForText(const Text& text) const | 290 EntityMask MarkupAccumulator::entityMaskForText(const Text& text) const |
| 290 { | 291 { |
| 291 if (!text.document().isHTMLDocument()) | 292 if (!serializeAsHTMLDocument(text)) |
| 292 return EntityMaskInPCDATA; | 293 return EntityMaskInPCDATA; |
| 293 | 294 |
| 294 const QualifiedName* parentName = 0; | 295 const QualifiedName* parentName = 0; |
| 295 if (text.parentElement()) | 296 if (text.parentElement()) |
| 296 parentName = &(text.parentElement())->tagQName(); | 297 parentName = &(text.parentElement())->tagQName(); |
| 297 | 298 |
| 298 if (parentName && (*parentName == scriptTag || *parentName == styleTag || *p
arentName == xmpTag)) | 299 if (parentName && (*parentName == scriptTag || *parentName == styleTag || *p
arentName == xmpTag)) |
| 299 return EntityMaskInCDATA; | 300 return EntityMaskInCDATA; |
| 300 return EntityMaskInHTMLPCDATA; | 301 return EntityMaskInHTMLPCDATA; |
| 301 } | 302 } |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 405 | 406 |
| 406 static String nodeNamePreservingCase(const Element& element) | 407 static String nodeNamePreservingCase(const Element& element) |
| 407 { | 408 { |
| 408 return element.tagQName().toString(); | 409 return element.tagQName().toString(); |
| 409 } | 410 } |
| 410 | 411 |
| 411 void MarkupAccumulator::appendOpenTag(StringBuilder& result, const Element& elem
ent, Namespaces* namespaces) | 412 void MarkupAccumulator::appendOpenTag(StringBuilder& result, const Element& elem
ent, Namespaces* namespaces) |
| 412 { | 413 { |
| 413 result.append('<'); | 414 result.append('<'); |
| 414 result.append(nodeNamePreservingCase(element)); | 415 result.append(nodeNamePreservingCase(element)); |
| 415 if (!element.document().isHTMLDocument() && namespaces && shouldAddNamespace
Element(element, *namespaces)) | 416 if (!serializeAsHTMLDocument(element) && namespaces && shouldAddNamespaceEle
ment(element, *namespaces)) |
| 416 appendNamespace(result, element.prefix(), element.namespaceURI(), *names
paces); | 417 appendNamespace(result, element.prefix(), element.namespaceURI(), *names
paces); |
| 417 } | 418 } |
| 418 | 419 |
| 419 void MarkupAccumulator::appendCloseTag(StringBuilder& result, const Element& ele
ment) | 420 void MarkupAccumulator::appendCloseTag(StringBuilder& result, const Element& ele
ment) |
| 420 { | 421 { |
| 421 if (shouldSelfClose(element)) { | 422 if (shouldSelfClose(element)) { |
| 422 if (element.isHTMLElement()) | 423 if (element.isHTMLElement()) |
| 423 result.append(' '); // XHTML 1.0 <-> HTML compatibility. | 424 result.append(' '); // XHTML 1.0 <-> HTML compatibility. |
| 424 result.append('/'); | 425 result.append('/'); |
| 425 } | 426 } |
| 426 result.append('>'); | 427 result.append('>'); |
| 427 } | 428 } |
| 428 | 429 |
| 429 static inline bool attributeIsInSerializedNamespace(const Attribute& attribute) | 430 static inline bool attributeIsInSerializedNamespace(const Attribute& attribute) |
| 430 { | 431 { |
| 431 return attribute.namespaceURI() == XMLNames::xmlNamespaceURI | 432 return attribute.namespaceURI() == XMLNames::xmlNamespaceURI |
| 432 || attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI | 433 || attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI |
| 433 || attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI; | 434 || attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI; |
| 434 } | 435 } |
| 435 | 436 |
| 436 void MarkupAccumulator::appendAttribute(StringBuilder& result, const Element& el
ement, const Attribute& attribute, Namespaces* namespaces) | 437 void MarkupAccumulator::appendAttribute(StringBuilder& result, const Element& el
ement, const Attribute& attribute, Namespaces* namespaces) |
| 437 { | 438 { |
| 438 bool documentIsHTML = element.document().isHTMLDocument(); | 439 bool documentIsHTML = serializeAsHTMLDocument(element); |
| 439 | 440 |
| 440 result.append(' '); | 441 result.append(' '); |
| 441 | 442 |
| 442 QualifiedName prefixedName = attribute.name(); | 443 QualifiedName prefixedName = attribute.name(); |
| 443 if (documentIsHTML && !attributeIsInSerializedNamespace(attribute)) { | 444 if (documentIsHTML && !attributeIsInSerializedNamespace(attribute)) { |
| 444 result.append(attribute.name().localName()); | 445 result.append(attribute.name().localName()); |
| 445 } else { | 446 } else { |
| 446 if (attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI) { | 447 if (attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI) { |
| 447 if (!attribute.prefix()) | 448 if (!attribute.prefix()) |
| 448 prefixedName.setPrefix(xlinkAtom); | 449 prefixedName.setPrefix(xlinkAtom); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 510 } | 511 } |
| 511 } | 512 } |
| 512 | 513 |
| 513 // Rules of self-closure | 514 // Rules of self-closure |
| 514 // 1. No elements in HTML documents use the self-closing syntax. | 515 // 1. No elements in HTML documents use the self-closing syntax. |
| 515 // 2. Elements w/ children never self-close because they use a separate end tag. | 516 // 2. Elements w/ children never self-close because they use a separate end tag. |
| 516 // 3. HTML elements which do not have a "forbidden" end tag will close with a se
parate end tag. | 517 // 3. HTML elements which do not have a "forbidden" end tag will close with a se
parate end tag. |
| 517 // 4. Other elements self-close. | 518 // 4. Other elements self-close. |
| 518 bool MarkupAccumulator::shouldSelfClose(const Node& node) | 519 bool MarkupAccumulator::shouldSelfClose(const Node& node) |
| 519 { | 520 { |
| 520 if (node.document().isHTMLDocument()) | 521 if (serializeAsHTMLDocument(node)) |
| 521 return false; | 522 return false; |
| 522 if (node.hasChildren()) | 523 if (node.hasChildren()) |
| 523 return false; | 524 return false; |
| 524 if (node.isHTMLElement() && !elementCannotHaveEndTag(node)) | 525 if (node.isHTMLElement() && !elementCannotHaveEndTag(node)) |
| 525 return false; | 526 return false; |
| 526 return true; | 527 return true; |
| 527 } | 528 } |
| 528 | 529 |
| 529 bool MarkupAccumulator::elementCannotHaveEndTag(const Node& node) | 530 bool MarkupAccumulator::elementCannotHaveEndTag(const Node& node) |
| 530 { | 531 { |
| (...skipping 10 matching lines...) Expand all Loading... |
| 541 void MarkupAccumulator::appendEndMarkup(StringBuilder& result, const Node& node) | 542 void MarkupAccumulator::appendEndMarkup(StringBuilder& result, const Node& node) |
| 542 { | 543 { |
| 543 if (!node.isElementNode() || shouldSelfClose(node) || (!node.hasChildren() &
& elementCannotHaveEndTag(node))) | 544 if (!node.isElementNode() || shouldSelfClose(node) || (!node.hasChildren() &
& elementCannotHaveEndTag(node))) |
| 544 return; | 545 return; |
| 545 | 546 |
| 546 result.appendLiteral("</"); | 547 result.appendLiteral("</"); |
| 547 result.append(nodeNamePreservingCase(toElement(node))); | 548 result.append(nodeNamePreservingCase(toElement(node))); |
| 548 result.append('>'); | 549 result.append('>'); |
| 549 } | 550 } |
| 550 | 551 |
| 552 bool MarkupAccumulator::serializeAsHTMLDocument(const Node& node) const |
| 553 { |
| 554 if (m_serializationType == ForcedXML) |
| 555 return false; |
| 556 return node.document().isHTMLDocument(); |
| 551 } | 557 } |
| 558 |
| 559 } |
| OLD | NEW |