Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(280)

Side by Side Diff: Source/core/editing/MarkupFormatter.cpp

Issue 1148633010: Refactoring: Separate MarkupAccumulator into MarkupFormatter and MarkupAccumulator (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: rebase Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/core/editing/MarkupFormatter.h ('k') | Source/core/editing/StyledMarkupAccumulator.cpp » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * 13 *
14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 14 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 15 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 16 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 17 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 18 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 19 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */ 25 */
26 26
27 #include "config.h" 27 #include "config.h"
28 #include "core/editing/MarkupAccumulator.h" 28 #include "core/editing/MarkupFormatter.h"
29 29
30 #include "core/HTMLNames.h" 30 #include "core/HTMLNames.h"
31 #include "core/XLinkNames.h" 31 #include "core/XLinkNames.h"
32 #include "core/XMLNSNames.h" 32 #include "core/XMLNSNames.h"
33 #include "core/XMLNames.h" 33 #include "core/XMLNames.h"
34 #include "core/dom/CDATASection.h" 34 #include "core/dom/CDATASection.h"
35 #include "core/dom/Comment.h" 35 #include "core/dom/Comment.h"
36 #include "core/dom/Document.h" 36 #include "core/dom/Document.h"
37 #include "core/dom/DocumentFragment.h" 37 #include "core/dom/DocumentFragment.h"
38 #include "core/dom/DocumentType.h" 38 #include "core/dom/DocumentType.h"
(...skipping 25 matching lines...) Expand all
64 const CString& replacement = entityMaps[entityIndex].reference; 64 const CString& replacement = entityMaps[entityIndex].reference;
65 result.append(replacement.data(), replacement.length()); 65 result.append(replacement.data(), replacement.length());
66 positionAfterLastEntity = i + 1; 66 positionAfterLastEntity = i + 1;
67 break; 67 break;
68 } 68 }
69 } 69 }
70 } 70 }
71 result.append(text + positionAfterLastEntity, length - positionAfterLastEnti ty); 71 result.append(text + positionAfterLastEntity, length - positionAfterLastEnti ty);
72 } 72 }
73 73
74 void MarkupAccumulator::appendCharactersReplacingEntities(StringBuilder& result, const String& source, unsigned offset, unsigned length, EntityMask entityMask) 74 void MarkupFormatter::appendCharactersReplacingEntities(StringBuilder& result, c onst String& source, unsigned offset, unsigned length, EntityMask entityMask)
75 { 75 {
76 DEFINE_STATIC_LOCAL(const CString, ampReference, ("&")); 76 DEFINE_STATIC_LOCAL(const CString, ampReference, ("&"));
77 DEFINE_STATIC_LOCAL(const CString, ltReference, ("<")); 77 DEFINE_STATIC_LOCAL(const CString, ltReference, ("<"));
78 DEFINE_STATIC_LOCAL(const CString, gtReference, (">")); 78 DEFINE_STATIC_LOCAL(const CString, gtReference, (">"));
79 DEFINE_STATIC_LOCAL(const CString, quotReference, (""")); 79 DEFINE_STATIC_LOCAL(const CString, quotReference, ("""));
80 DEFINE_STATIC_LOCAL(const CString, nbspReference, (" ")); 80 DEFINE_STATIC_LOCAL(const CString, nbspReference, (" "));
81 81
82 static const EntityDescription entityMaps[] = { 82 static const EntityDescription entityMaps[] = {
83 { '&', ampReference, EntityAmp }, 83 { '&', ampReference, EntityAmp },
84 { '<', ltReference, EntityLt }, 84 { '<', ltReference, EntityLt },
85 { '>', gtReference, EntityGt }, 85 { '>', gtReference, EntityGt },
86 { '"', quotReference, EntityQuot }, 86 { '"', quotReference, EntityQuot },
87 { noBreakSpaceCharacter, nbspReference, EntityNbsp }, 87 { noBreakSpaceCharacter, nbspReference, EntityNbsp },
88 }; 88 };
89 89
90 if (!(offset + length)) 90 if (!(offset + length))
91 return; 91 return;
92 92
93 ASSERT(offset + length <= source.length()); 93 ASSERT(offset + length <= source.length());
94 if (source.is8Bit()) 94 if (source.is8Bit())
95 appendCharactersReplacingEntitiesInternal(result, source.characters8() + offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask); 95 appendCharactersReplacingEntitiesInternal(result, source.characters8() + offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask);
96 else 96 else
97 appendCharactersReplacingEntitiesInternal(result, source.characters16() + offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask); 97 appendCharactersReplacingEntitiesInternal(result, source.characters16() + offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask);
98 } 98 }
99 99
100 size_t MarkupAccumulator::totalLength(const Vector<String>& strings) 100 size_t MarkupFormatter::totalLength(const Vector<String>& strings)
101 { 101 {
102 size_t length = 0; 102 size_t length = 0;
103 for (const auto& string : strings) 103 for (const auto& string : strings)
104 length += string.length(); 104 length += string.length();
105 return length; 105 return length;
106 } 106 }
107 107
108 MarkupAccumulator::MarkupAccumulator(EAbsoluteURLs resolveUrlsMethod, Serializat ionType serializationType) 108 MarkupFormatter::MarkupFormatter(EAbsoluteURLs resolveUrlsMethod, SerializationT ype serializationType)
109 : m_resolveURLsMethod(resolveUrlsMethod) 109 : m_resolveURLsMethod(resolveUrlsMethod)
110 , m_serializationType(serializationType) 110 , m_serializationType(serializationType)
111 { 111 {
112 } 112 }
113 113
114 MarkupAccumulator::~MarkupAccumulator() 114 MarkupFormatter::~MarkupFormatter()
115 { 115 {
116 } 116 }
117 117
118 String MarkupAccumulator::resolveURLIfNeeded(const Element& element, const Strin g& urlString) const 118 String MarkupFormatter::resolveURLIfNeeded(const Element& element, const String& urlString) const
119 { 119 {
120 switch (m_resolveURLsMethod) { 120 switch (m_resolveURLsMethod) {
121 case ResolveAllURLs: 121 case ResolveAllURLs:
122 return element.document().completeURL(urlString).string(); 122 return element.document().completeURL(urlString).string();
123 123
124 case ResolveNonLocalURLs: 124 case ResolveNonLocalURLs:
125 if (!element.document().url().isLocalFile()) 125 if (!element.document().url().isLocalFile())
126 return element.document().completeURL(urlString).string(); 126 return element.document().completeURL(urlString).string();
127 break; 127 break;
128 128
129 case DoNotResolveURLs: 129 case DoNotResolveURLs:
130 break; 130 break;
131 } 131 }
132 return urlString; 132 return urlString;
133 } 133 }
134 134
135 void MarkupAccumulator::appendString(const String& string)
136 {
137 m_markup.append(string);
138 }
139
140 void MarkupAccumulator::appendStartTag(Node& node, Namespaces* namespaces)
141 {
142 appendStartMarkup(m_markup, node, namespaces);
143 }
144
145 void MarkupAccumulator::appendEndTag(const Element& element)
146 {
147 appendEndMarkup(m_markup, element);
148 }
149
150 void MarkupAccumulator::appendStartMarkup(StringBuilder& result, Node& node, Nam espaces* namespaces)
151 {
152 switch (node.nodeType()) {
153 case Node::TEXT_NODE:
154 appendText(result, toText(node));
155 break;
156 case Node::COMMENT_NODE:
157 appendComment(result, toComment(node).data());
158 break;
159 case Node::DOCUMENT_NODE:
160 appendXMLDeclaration(result, toDocument(node));
161 break;
162 case Node::DOCUMENT_FRAGMENT_NODE:
163 break;
164 case Node::DOCUMENT_TYPE_NODE:
165 appendDocumentType(result, toDocumentType(node));
166 break;
167 case Node::PROCESSING_INSTRUCTION_NODE:
168 appendProcessingInstruction(result, toProcessingInstruction(node).target (), toProcessingInstruction(node).data());
169 break;
170 case Node::ELEMENT_NODE:
171 appendElement(result, toElement(node), namespaces);
172 break;
173 case Node::CDATA_SECTION_NODE:
174 appendCDATASection(result, toCDATASection(node).data());
175 break;
176 case Node::ATTRIBUTE_NODE:
177 ASSERT_NOT_REACHED();
178 break;
179 }
180 }
181
182 static bool elementCannotHaveEndTag(const Node& node) 135 static bool elementCannotHaveEndTag(const Node& node)
183 { 136 {
184 if (!node.isHTMLElement()) 137 if (!node.isHTMLElement())
185 return false; 138 return false;
186 139
187 // FIXME: ieForbidsInsertHTML may not be the right function to call here 140 // FIXME: ieForbidsInsertHTML may not be the right function to call here
188 // ieForbidsInsertHTML is used to disallow setting innerHTML/outerHTML 141 // ieForbidsInsertHTML is used to disallow setting innerHTML/outerHTML
189 // or createContextualFragment. It does not necessarily align with 142 // or createContextualFragment. It does not necessarily align with
190 // which elements should be serialized w/o end tags. 143 // which elements should be serialized w/o end tags.
191 return toHTMLElement(node).ieForbidsInsertHTML(); 144 return toHTMLElement(node).ieForbidsInsertHTML();
192 } 145 }
193 146
194 void MarkupAccumulator::appendEndMarkup(StringBuilder& result, const Element& el ement) 147 void MarkupFormatter::appendEndMarkup(StringBuilder& result, const Element& elem ent)
195 { 148 {
196 if (shouldSelfClose(element) || (!element.hasChildren() && elementCannotHave EndTag(element))) 149 if (shouldSelfClose(element) || (!element.hasChildren() && elementCannotHave EndTag(element)))
197 return; 150 return;
198 151
199 result.appendLiteral("</"); 152 result.appendLiteral("</");
200 result.append(element.tagQName().toString()); 153 result.append(element.tagQName().toString());
201 result.append('>'); 154 result.append('>');
202 } 155 }
203 156
204 void MarkupAccumulator::concatenateMarkup(StringBuilder& result) const 157 void MarkupFormatter::appendAttributeValue(StringBuilder& result, const String& attribute, bool documentIsHTML)
205 {
206 result.append(m_markup);
207 }
208
209 void MarkupAccumulator::appendAttributeValue(StringBuilder& result, const String & attribute, bool documentIsHTML)
210 { 158 {
211 appendCharactersReplacingEntities(result, attribute, 0, attribute.length(), 159 appendCharactersReplacingEntities(result, attribute, 0, attribute.length(),
212 documentIsHTML ? EntityMaskInHTMLAttributeValue : EntityMaskInAttributeV alue); 160 documentIsHTML ? EntityMaskInHTMLAttributeValue : EntityMaskInAttributeV alue);
213 } 161 }
214 162
215 void MarkupAccumulator::appendCustomAttributes(StringBuilder&, const Element&, N amespaces*) 163 void MarkupFormatter::appendQuotedURLAttributeValue(StringBuilder& result, const Element& element, const Attribute& attribute)
216 {
217 }
218
219 void MarkupAccumulator::appendQuotedURLAttributeValue(StringBuilder& result, con st Element& element, const Attribute& attribute)
220 { 164 {
221 ASSERT(element.isURLAttribute(attribute)); 165 ASSERT(element.isURLAttribute(attribute));
222 const String resolvedURLString = resolveURLIfNeeded(element, attribute.value ()); 166 const String resolvedURLString = resolveURLIfNeeded(element, attribute.value ());
223 UChar quoteChar = '"'; 167 UChar quoteChar = '"';
224 String strippedURLString = resolvedURLString.stripWhiteSpace(); 168 String strippedURLString = resolvedURLString.stripWhiteSpace();
225 if (protocolIsJavaScript(strippedURLString)) { 169 if (protocolIsJavaScript(strippedURLString)) {
226 // minimal escaping for javascript urls 170 // minimal escaping for javascript urls
227 if (strippedURLString.contains('&')) 171 if (strippedURLString.contains('&'))
228 strippedURLString.replaceWithLiteral('&', "&amp;"); 172 strippedURLString.replaceWithLiteral('&', "&amp;");
229 173
230 if (strippedURLString.contains('"')) { 174 if (strippedURLString.contains('"')) {
231 if (strippedURLString.contains('\'')) 175 if (strippedURLString.contains('\''))
232 strippedURLString.replaceWithLiteral('"', "&quot;"); 176 strippedURLString.replaceWithLiteral('"', "&quot;");
233 else 177 else
234 quoteChar = '\''; 178 quoteChar = '\'';
235 } 179 }
236 result.append(quoteChar); 180 result.append(quoteChar);
237 result.append(strippedURLString); 181 result.append(strippedURLString);
238 result.append(quoteChar); 182 result.append(quoteChar);
239 return; 183 return;
240 } 184 }
241 185
242 // FIXME: This does not fully match other browsers. Firefox percent-escapes non-ASCII characters for innerHTML. 186 // FIXME: This does not fully match other browsers. Firefox percent-escapes non-ASCII characters for innerHTML.
243 result.append(quoteChar); 187 result.append(quoteChar);
244 appendAttributeValue(result, resolvedURLString, false); 188 appendAttributeValue(result, resolvedURLString, false);
245 result.append(quoteChar); 189 result.append(quoteChar);
246 } 190 }
247 191
248 void MarkupAccumulator::appendNamespace(StringBuilder& result, const AtomicStrin g& prefix, const AtomicString& namespaceURI, Namespaces& namespaces) 192 void MarkupFormatter::appendNamespace(StringBuilder& result, const AtomicString& prefix, const AtomicString& namespaceURI, Namespaces& namespaces)
249 { 193 {
250 if (namespaceURI.isEmpty()) 194 if (namespaceURI.isEmpty())
251 return; 195 return;
252 196
253 const AtomicString& lookupKey = (!prefix) ? emptyAtom : prefix; 197 const AtomicString& lookupKey = (!prefix) ? emptyAtom : prefix;
254 AtomicString foundURI = namespaces.get(lookupKey); 198 AtomicString foundURI = namespaces.get(lookupKey);
255 if (foundURI != namespaceURI) { 199 if (foundURI != namespaceURI) {
256 namespaces.set(lookupKey, namespaceURI); 200 namespaces.set(lookupKey, namespaceURI);
257 result.append(' '); 201 result.append(' ');
258 result.append(xmlnsAtom.string()); 202 result.append(xmlnsAtom.string());
259 if (!prefix.isEmpty()) { 203 if (!prefix.isEmpty()) {
260 result.append(':'); 204 result.append(':');
261 result.append(prefix); 205 result.append(prefix);
262 } 206 }
263 207
264 result.appendLiteral("=\""); 208 result.appendLiteral("=\"");
265 appendAttributeValue(result, namespaceURI, false); 209 appendAttributeValue(result, namespaceURI, false);
266 result.append('"'); 210 result.append('"');
267 } 211 }
268 } 212 }
269 213
270 void MarkupAccumulator::appendText(StringBuilder& result, Text& text) 214 void MarkupFormatter::appendText(StringBuilder& result, Text& text)
271 { 215 {
272 const String& str = text.data(); 216 const String& str = text.data();
273 appendCharactersReplacingEntities(result, str, 0, str.length(), entityMaskFo rText(text)); 217 appendCharactersReplacingEntities(result, str, 0, str.length(), entityMaskFo rText(text));
274 } 218 }
275 219
276 void MarkupAccumulator::appendComment(StringBuilder& result, const String& comme nt) 220 void MarkupFormatter::appendComment(StringBuilder& result, const String& comment )
277 { 221 {
278 // FIXME: Comment content is not escaped, but XMLSerializer (and possibly ot her callers) should raise an exception if it includes "-->". 222 // FIXME: Comment content is not escaped, but XMLSerializer (and possibly ot her callers) should raise an exception if it includes "-->".
279 result.appendLiteral("<!--"); 223 result.appendLiteral("<!--");
280 result.append(comment); 224 result.append(comment);
281 result.appendLiteral("-->"); 225 result.appendLiteral("-->");
282 } 226 }
283 227
284 void MarkupAccumulator::appendXMLDeclaration(StringBuilder& result, const Docume nt& document) 228 void MarkupFormatter::appendXMLDeclaration(StringBuilder& result, const Document & document)
285 { 229 {
286 if (!document.hasXMLDeclaration()) 230 if (!document.hasXMLDeclaration())
287 return; 231 return;
288 232
289 result.appendLiteral("<?xml version=\""); 233 result.appendLiteral("<?xml version=\"");
290 result.append(document.xmlVersion()); 234 result.append(document.xmlVersion());
291 const String& encoding = document.xmlEncoding(); 235 const String& encoding = document.xmlEncoding();
292 if (!encoding.isEmpty()) { 236 if (!encoding.isEmpty()) {
293 result.appendLiteral("\" encoding=\""); 237 result.appendLiteral("\" encoding=\"");
294 result.append(encoding); 238 result.append(encoding);
295 } 239 }
296 if (document.xmlStandaloneStatus() != Document::StandaloneUnspecified) { 240 if (document.xmlStandaloneStatus() != Document::StandaloneUnspecified) {
297 result.appendLiteral("\" standalone=\""); 241 result.appendLiteral("\" standalone=\"");
298 if (document.xmlStandalone()) 242 if (document.xmlStandalone())
299 result.appendLiteral("yes"); 243 result.appendLiteral("yes");
300 else 244 else
301 result.appendLiteral("no"); 245 result.appendLiteral("no");
302 } 246 }
303 247
304 result.appendLiteral("\"?>"); 248 result.appendLiteral("\"?>");
305 } 249 }
306 250
307 void MarkupAccumulator::appendDocumentType(StringBuilder& result, const Document Type& n) 251 void MarkupFormatter::appendDocumentType(StringBuilder& result, const DocumentTy pe& n)
308 { 252 {
309 if (n.name().isEmpty()) 253 if (n.name().isEmpty())
310 return; 254 return;
311 255
312 result.appendLiteral("<!DOCTYPE "); 256 result.appendLiteral("<!DOCTYPE ");
313 result.append(n.name()); 257 result.append(n.name());
314 if (!n.publicId().isEmpty()) { 258 if (!n.publicId().isEmpty()) {
315 result.appendLiteral(" PUBLIC \""); 259 result.appendLiteral(" PUBLIC \"");
316 result.append(n.publicId()); 260 result.append(n.publicId());
317 result.append('"'); 261 result.append('"');
318 if (!n.systemId().isEmpty()) { 262 if (!n.systemId().isEmpty()) {
319 result.appendLiteral(" \""); 263 result.appendLiteral(" \"");
320 result.append(n.systemId()); 264 result.append(n.systemId());
321 result.append('"'); 265 result.append('"');
322 } 266 }
323 } else if (!n.systemId().isEmpty()) { 267 } else if (!n.systemId().isEmpty()) {
324 result.appendLiteral(" SYSTEM \""); 268 result.appendLiteral(" SYSTEM \"");
325 result.append(n.systemId()); 269 result.append(n.systemId());
326 result.append('"'); 270 result.append('"');
327 } 271 }
328 result.append('>'); 272 result.append('>');
329 } 273 }
330 274
331 void MarkupAccumulator::appendProcessingInstruction(StringBuilder& result, const String& target, const String& data) 275 void MarkupFormatter::appendProcessingInstruction(StringBuilder& result, const S tring& target, const String& data)
332 { 276 {
333 // FIXME: PI data is not escaped, but XMLSerializer (and possibly other call ers) this should raise an exception if it includes "?>". 277 // FIXME: PI data is not escaped, but XMLSerializer (and possibly other call ers) this should raise an exception if it includes "?>".
334 result.appendLiteral("<?"); 278 result.appendLiteral("<?");
335 result.append(target); 279 result.append(target);
336 result.append(' '); 280 result.append(' ');
337 result.append(data); 281 result.append(data);
338 result.appendLiteral("?>"); 282 result.appendLiteral("?>");
339 } 283 }
340 284
341 bool MarkupAccumulator::shouldIgnoreAttribute(const Attribute& attribute) 285 void MarkupFormatter::appendOpenTag(StringBuilder& result, const Element& elemen t, Namespaces* namespaces)
342 {
343 return false;
344 }
345
346 void MarkupAccumulator::appendElement(StringBuilder& result, Element& element, N amespaces* namespaces)
347 {
348 appendOpenTag(result, element, namespaces);
349
350 AttributeCollection attributes = element.attributes();
351 for (const auto& attribute : attributes) {
352 if (!shouldIgnoreAttribute(attribute))
353 appendAttribute(result, element, attribute, namespaces);
354 }
355
356 // Give an opportunity to subclasses to add their own attributes.
357 appendCustomAttributes(result, element, namespaces);
358
359 appendCloseTag(result, element);
360 }
361
362 void MarkupAccumulator::appendOpenTag(StringBuilder& result, const Element& elem ent, Namespaces* namespaces)
363 { 286 {
364 result.append('<'); 287 result.append('<');
365 result.append(element.tagQName().toString()); 288 result.append(element.tagQName().toString());
366 if (!serializeAsHTMLDocument(element) && namespaces && shouldAddNamespaceEle ment(element, *namespaces)) 289 if (!serializeAsHTMLDocument(element) && namespaces && shouldAddNamespaceEle ment(element, *namespaces))
367 appendNamespace(result, element.prefix(), element.namespaceURI(), *names paces); 290 appendNamespace(result, element.prefix(), element.namespaceURI(), *names paces);
368 } 291 }
369 292
370 void MarkupAccumulator::appendCloseTag(StringBuilder& result, const Element& ele ment) 293 void MarkupFormatter::appendCloseTag(StringBuilder& result, const Element& eleme nt)
371 { 294 {
372 if (shouldSelfClose(element)) { 295 if (shouldSelfClose(element)) {
373 if (element.isHTMLElement()) 296 if (element.isHTMLElement())
374 result.append(' '); // XHTML 1.0 <-> HTML compatibility. 297 result.append(' '); // XHTML 1.0 <-> HTML compatibility.
375 result.append('/'); 298 result.append('/');
376 } 299 }
377 result.append('>'); 300 result.append('>');
378 } 301 }
379 302
380 static inline bool attributeIsInSerializedNamespace(const Attribute& attribute) 303 static inline bool attributeIsInSerializedNamespace(const Attribute& attribute)
381 { 304 {
382 return attribute.namespaceURI() == XMLNames::xmlNamespaceURI 305 return attribute.namespaceURI() == XMLNames::xmlNamespaceURI
383 || attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI 306 || attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI
384 || attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI; 307 || attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI;
385 } 308 }
386 309
387 void MarkupAccumulator::appendAttribute(StringBuilder& result, const Element& el ement, const Attribute& attribute, Namespaces* namespaces) 310 void MarkupFormatter::appendAttribute(StringBuilder& result, const Element& elem ent, const Attribute& attribute, Namespaces* namespaces)
388 { 311 {
389 bool documentIsHTML = serializeAsHTMLDocument(element); 312 bool documentIsHTML = serializeAsHTMLDocument(element);
390 313
391 QualifiedName prefixedName = attribute.name(); 314 QualifiedName prefixedName = attribute.name();
392 if (documentIsHTML && !attributeIsInSerializedNamespace(attribute)) { 315 if (documentIsHTML && !attributeIsInSerializedNamespace(attribute)) {
393 result.append(' '); 316 result.append(' ');
394 result.append(attribute.name().localName()); 317 result.append(attribute.name().localName());
395 } else { 318 } else {
396 if (attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI) { 319 if (attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI) {
397 if (!attribute.prefix() && attribute.localName() != xmlnsAtom) 320 if (!attribute.prefix() && attribute.localName() != xmlnsAtom)
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
435 358
436 if (element.isURLAttribute(attribute)) { 359 if (element.isURLAttribute(attribute)) {
437 appendQuotedURLAttributeValue(result, element, attribute); 360 appendQuotedURLAttributeValue(result, element, attribute);
438 } else { 361 } else {
439 result.append('"'); 362 result.append('"');
440 appendAttributeValue(result, attribute.value(), documentIsHTML); 363 appendAttributeValue(result, attribute.value(), documentIsHTML);
441 result.append('"'); 364 result.append('"');
442 } 365 }
443 } 366 }
444 367
445 void MarkupAccumulator::appendCDATASection(StringBuilder& result, const String& section) 368 void MarkupFormatter::appendCDATASection(StringBuilder& result, const String& se ction)
446 { 369 {
447 // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly othe r callers) should raise an exception if it includes "]]>". 370 // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly othe r callers) should raise an exception if it includes "]]>".
448 result.appendLiteral("<![CDATA["); 371 result.appendLiteral("<![CDATA[");
449 result.append(section); 372 result.append(section);
450 result.appendLiteral("]]>"); 373 result.appendLiteral("]]>");
451 } 374 }
452 375
453 bool MarkupAccumulator::shouldAddNamespaceElement(const Element& element, Namesp aces& namespaces) const 376 bool MarkupFormatter::shouldAddNamespaceElement(const Element& element, Namespac es& namespaces) const
454 { 377 {
455 // Don't add namespace attribute if it is already defined for this elem. 378 // Don't add namespace attribute if it is already defined for this elem.
456 const AtomicString& prefix = element.prefix(); 379 const AtomicString& prefix = element.prefix();
457 if (prefix.isEmpty()) { 380 if (prefix.isEmpty()) {
458 if (element.hasAttribute(xmlnsAtom)) { 381 if (element.hasAttribute(xmlnsAtom)) {
459 namespaces.set(emptyAtom, element.namespaceURI()); 382 namespaces.set(emptyAtom, element.namespaceURI());
460 return false; 383 return false;
461 } 384 }
462 return true; 385 return true;
463 } 386 }
464 387
465 return !element.hasAttribute(WTF::xmlnsWithColon + prefix); 388 return !element.hasAttribute(WTF::xmlnsWithColon + prefix);
466 } 389 }
467 390
468 bool MarkupAccumulator::shouldAddNamespaceAttribute(const Attribute& attribute, const Element& element) const 391 bool MarkupFormatter::shouldAddNamespaceAttribute(const Attribute& attribute, co nst Element& element) const
469 { 392 {
470 // xmlns and xmlns:prefix attributes should be handled by another branch in appendAttribute. 393 // xmlns and xmlns:prefix attributes should be handled by another branch in appendAttribute.
471 ASSERT(attribute.namespaceURI() != XMLNSNames::xmlnsNamespaceURI); 394 ASSERT(attribute.namespaceURI() != XMLNSNames::xmlnsNamespaceURI);
472 395
473 // Attributes are in the null namespace by default. 396 // Attributes are in the null namespace by default.
474 if (!attribute.namespaceURI()) 397 if (!attribute.namespaceURI())
475 return false; 398 return false;
476 399
477 // Attributes without a prefix will need one generated for them, and an xmln s attribute for that prefix. 400 // Attributes without a prefix will need one generated for them, and an xmln s attribute for that prefix.
478 if (!attribute.prefix()) 401 if (!attribute.prefix())
479 return true; 402 return true;
480 403
481 return !element.hasAttribute(WTF::xmlnsWithColon + attribute.prefix()); 404 return !element.hasAttribute(WTF::xmlnsWithColon + attribute.prefix());
482 } 405 }
483 406
484 EntityMask MarkupAccumulator::entityMaskForText(const Text& text) const 407 EntityMask MarkupFormatter::entityMaskForText(const Text& text) const
485 { 408 {
486 if (!serializeAsHTMLDocument(text)) 409 if (!serializeAsHTMLDocument(text))
487 return EntityMaskInPCDATA; 410 return EntityMaskInPCDATA;
488 411
489 // TODO(hajimehoshi): We need to switch EditingStrategy. 412 // TODO(hajimehoshi): We need to switch EditingStrategy.
490 const QualifiedName* parentName = nullptr; 413 const QualifiedName* parentName = nullptr;
491 if (text.parentElement()) 414 if (text.parentElement())
492 parentName = &(text.parentElement())->tagQName(); 415 parentName = &(text.parentElement())->tagQName();
493 416
494 if (parentName && (*parentName == scriptTag || *parentName == styleTag || *p arentName == xmpTag)) 417 if (parentName && (*parentName == scriptTag || *parentName == styleTag || *p arentName == xmpTag))
495 return EntityMaskInCDATA; 418 return EntityMaskInCDATA;
496 return EntityMaskInHTMLPCDATA; 419 return EntityMaskInHTMLPCDATA;
497 } 420 }
498 421
499 // Rules of self-closure 422 // Rules of self-closure
500 // 1. No elements in HTML documents use the self-closing syntax. 423 // 1. No elements in HTML documents use the self-closing syntax.
501 // 2. Elements w/ children never self-close because they use a separate end tag. 424 // 2. Elements w/ children never self-close because they use a separate end tag.
502 // 3. HTML elements which do not have a "forbidden" end tag will close with a se parate end tag. 425 // 3. HTML elements which do not have a "forbidden" end tag will close with a se parate end tag.
503 // 4. Other elements self-close. 426 // 4. Other elements self-close.
504 bool MarkupAccumulator::shouldSelfClose(const Element& element) const 427 bool MarkupFormatter::shouldSelfClose(const Element& element) const
505 { 428 {
506 if (serializeAsHTMLDocument(element)) 429 if (serializeAsHTMLDocument(element))
507 return false; 430 return false;
508 if (element.hasChildren()) 431 if (element.hasChildren())
509 return false; 432 return false;
510 if (element.isHTMLElement() && !elementCannotHaveEndTag(element)) 433 if (element.isHTMLElement() && !elementCannotHaveEndTag(element))
511 return false; 434 return false;
512 return true; 435 return true;
513 } 436 }
514 437
515 bool MarkupAccumulator::serializeAsHTMLDocument(const Node& node) const 438 bool MarkupFormatter::serializeAsHTMLDocument(const Node& node) const
516 { 439 {
517 if (m_serializationType == SerializationType::ForcedXML) 440 if (m_serializationType == SerializationType::ForcedXML)
518 return false; 441 return false;
519 return node.document().isHTMLDocument(); 442 return node.document().isHTMLDocument();
520 } 443 }
521 444
522 template<typename Strategy>
523 static void serializeNodesWithNamespaces(MarkupAccumulator& accumulator, Node& t argetNode, EChildrenOnly childrenOnly, const Namespaces* namespaces)
524 {
525 Namespaces namespaceHash;
526 if (namespaces)
527 namespaceHash = *namespaces;
528
529 if (!childrenOnly)
530 accumulator.appendStartTag(targetNode, &namespaceHash);
531
532 if (!(accumulator.serializeAsHTMLDocument(targetNode) && elementCannotHaveEn dTag(targetNode))) {
533 Node* current = isHTMLTemplateElement(targetNode) ? Strategy::firstChild (*toHTMLTemplateElement(targetNode).content()) : Strategy::firstChild(targetNode );
534 for ( ; current; current = Strategy::nextSibling(*current))
535 serializeNodesWithNamespaces<Strategy>(accumulator, *current, Includ eNode, &namespaceHash);
536 }
537
538 if (!childrenOnly && targetNode.isElementNode())
539 accumulator.appendEndTag(toElement(targetNode));
540 } 445 }
541
542 template<typename Strategy>
543 String serializeNodes(MarkupAccumulator& accumulator, Node& targetNode, EChildre nOnly childrenOnly)
544 {
545 Namespaces* namespaces = nullptr;
546 Namespaces namespaceHash;
547 if (!accumulator.serializeAsHTMLDocument(targetNode)) {
548 // Add pre-bound namespaces for XML fragments.
549 namespaceHash.set(xmlAtom, XMLNames::xmlNamespaceURI);
550 namespaces = &namespaceHash;
551 }
552
553 serializeNodesWithNamespaces<Strategy>(accumulator, targetNode, childrenOnly , namespaces);
554 return accumulator.toString();
555 }
556
557 template String serializeNodes<EditingStrategy>(MarkupAccumulator&, Node&, EChil drenOnly);
558
559 }
OLDNEW
« no previous file with comments | « Source/core/editing/MarkupFormatter.h ('k') | Source/core/editing/StyledMarkupAccumulator.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698