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 |