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 |
| 3 * reserved. |
3 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. | 4 * Copyright (C) 2009, 2010 Google Inc. All rights reserved. |
4 * | 5 * |
5 * Redistribution and use in source and binary forms, with or without | 6 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions | 7 * modification, are permitted provided that the following conditions |
7 * are met: | 8 * are met: |
8 * 1. Redistributions of source code must retain the above copyright | 9 * 1. Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
10 * 2. Redistributions in binary form must reproduce the above copyright | 11 * 2. Redistributions in binary form must reproduce the above copyright |
11 * notice, this list of conditions and the following disclaimer in the | 12 * notice, this list of conditions and the following disclaimer in the |
12 * documentation and/or other materials provided with the distribution. | 13 * documentation and/or other materials provided with the distribution. |
(...skipping 214 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
227 strippedURLString.replace('"', """); | 228 strippedURLString.replace('"', """); |
228 else | 229 else |
229 quoteChar = '\''; | 230 quoteChar = '\''; |
230 } | 231 } |
231 result.append(quoteChar); | 232 result.append(quoteChar); |
232 result.append(strippedURLString); | 233 result.append(strippedURLString); |
233 result.append(quoteChar); | 234 result.append(quoteChar); |
234 return; | 235 return; |
235 } | 236 } |
236 | 237 |
237 // FIXME: This does not fully match other browsers. Firefox percent-escapes no
n-ASCII characters for innerHTML. | 238 // FIXME: This does not fully match other browsers. Firefox percent-escapes |
| 239 // non-ASCII characters for innerHTML. |
238 result.append(quoteChar); | 240 result.append(quoteChar); |
239 appendAttributeValue(result, resolvedURLString, false); | 241 appendAttributeValue(result, resolvedURLString, false); |
240 result.append(quoteChar); | 242 result.append(quoteChar); |
241 } | 243 } |
242 | 244 |
243 void MarkupFormatter::appendNamespace(StringBuilder& result, | 245 void MarkupFormatter::appendNamespace(StringBuilder& result, |
244 const AtomicString& prefix, | 246 const AtomicString& prefix, |
245 const AtomicString& namespaceURI, | 247 const AtomicString& namespaceURI, |
246 Namespaces& namespaces) { | 248 Namespaces& namespaces) { |
247 if (namespaceURI.isEmpty()) | 249 if (namespaceURI.isEmpty()) |
(...skipping 17 matching lines...) Expand all Loading... |
265 } | 267 } |
266 | 268 |
267 void MarkupFormatter::appendText(StringBuilder& result, Text& text) { | 269 void MarkupFormatter::appendText(StringBuilder& result, Text& text) { |
268 const String& str = text.data(); | 270 const String& str = text.data(); |
269 appendCharactersReplacingEntities(result, str, 0, str.length(), | 271 appendCharactersReplacingEntities(result, str, 0, str.length(), |
270 entityMaskForText(text)); | 272 entityMaskForText(text)); |
271 } | 273 } |
272 | 274 |
273 void MarkupFormatter::appendComment(StringBuilder& result, | 275 void MarkupFormatter::appendComment(StringBuilder& result, |
274 const String& comment) { | 276 const String& comment) { |
275 // FIXME: Comment content is not escaped, but XMLSerializer (and possibly othe
r callers) should raise an exception if it includes "-->". | 277 // FIXME: Comment content is not escaped, but XMLSerializer (and possibly |
| 278 // other callers) should raise an exception if it includes "-->". |
276 result.append("<!--"); | 279 result.append("<!--"); |
277 result.append(comment); | 280 result.append(comment); |
278 result.append("-->"); | 281 result.append("-->"); |
279 } | 282 } |
280 | 283 |
281 void MarkupFormatter::appendXMLDeclaration(StringBuilder& result, | 284 void MarkupFormatter::appendXMLDeclaration(StringBuilder& result, |
282 const Document& document) { | 285 const Document& document) { |
283 if (!document.hasXMLDeclaration()) | 286 if (!document.hasXMLDeclaration()) |
284 return; | 287 return; |
285 | 288 |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
321 result.append(" SYSTEM \""); | 324 result.append(" SYSTEM \""); |
322 result.append(n.systemId()); | 325 result.append(n.systemId()); |
323 result.append('"'); | 326 result.append('"'); |
324 } | 327 } |
325 result.append('>'); | 328 result.append('>'); |
326 } | 329 } |
327 | 330 |
328 void MarkupFormatter::appendProcessingInstruction(StringBuilder& result, | 331 void MarkupFormatter::appendProcessingInstruction(StringBuilder& result, |
329 const String& target, | 332 const String& target, |
330 const String& data) { | 333 const String& data) { |
331 // FIXME: PI data is not escaped, but XMLSerializer (and possibly other caller
s) this should raise an exception if it includes "?>". | 334 // FIXME: PI data is not escaped, but XMLSerializer (and possibly other |
| 335 // callers) this should raise an exception if it includes "?>". |
332 result.append("<?"); | 336 result.append("<?"); |
333 result.append(target); | 337 result.append(target); |
334 result.append(' '); | 338 result.append(' '); |
335 result.append(data); | 339 result.append(data); |
336 result.append("?>"); | 340 result.append("?>"); |
337 } | 341 } |
338 | 342 |
339 void MarkupFormatter::appendOpenTag(StringBuilder& result, | 343 void MarkupFormatter::appendOpenTag(StringBuilder& result, |
340 const Element& element, | 344 const Element& element, |
341 Namespaces* namespaces) { | 345 Namespaces* namespaces) { |
(...skipping 29 matching lines...) Expand all Loading... |
371 bool documentIsHTML = serializeAsHTMLDocument(element); | 375 bool documentIsHTML = serializeAsHTMLDocument(element); |
372 | 376 |
373 QualifiedName prefixedName = attribute.name(); | 377 QualifiedName prefixedName = attribute.name(); |
374 if (documentIsHTML && !attributeIsInSerializedNamespace(attribute)) { | 378 if (documentIsHTML && !attributeIsInSerializedNamespace(attribute)) { |
375 result.append(' '); | 379 result.append(' '); |
376 result.append(attribute.name().localName()); | 380 result.append(attribute.name().localName()); |
377 } else { | 381 } else { |
378 if (attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI) { | 382 if (attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI) { |
379 if (!attribute.prefix() && attribute.localName() != xmlnsAtom) | 383 if (!attribute.prefix() && attribute.localName() != xmlnsAtom) |
380 prefixedName.setPrefix(xmlnsAtom); | 384 prefixedName.setPrefix(xmlnsAtom); |
381 if (namespaces) { // Account for the namespace attribute we're about to a
ppend. | 385 // Account for the namespace attribute we're about to append. |
| 386 if (namespaces) { |
382 const AtomicString& lookupKey = | 387 const AtomicString& lookupKey = |
383 (!attribute.prefix()) ? emptyAtom : attribute.localName(); | 388 (!attribute.prefix()) ? emptyAtom : attribute.localName(); |
384 namespaces->set(lookupKey, attribute.value()); | 389 namespaces->set(lookupKey, attribute.value()); |
385 } | 390 } |
386 } else if (attribute.namespaceURI() == XMLNames::xmlNamespaceURI) { | 391 } else if (attribute.namespaceURI() == XMLNames::xmlNamespaceURI) { |
387 if (!attribute.prefix()) | 392 if (!attribute.prefix()) |
388 prefixedName.setPrefix(xmlAtom); | 393 prefixedName.setPrefix(xmlAtom); |
389 } else { | 394 } else { |
390 if (attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI) { | 395 if (attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI) { |
391 if (!attribute.prefix()) | 396 if (!attribute.prefix()) |
392 prefixedName.setPrefix(xlinkAtom); | 397 prefixedName.setPrefix(xlinkAtom); |
393 } | 398 } |
394 | 399 |
395 if (namespaces && shouldAddNamespaceAttribute(attribute, element)) { | 400 if (namespaces && shouldAddNamespaceAttribute(attribute, element)) { |
396 if (!prefixedName.prefix()) { | 401 if (!prefixedName.prefix()) { |
397 // This behavior is in process of being standardized. See crbug.com/24
8044 and https://www.w3.org/Bugs/Public/show_bug.cgi?id=24208 | 402 // This behavior is in process of being standardized. See |
| 403 // crbug.com/248044 and |
| 404 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=24208 |
398 String prefixPrefix("ns", 2); | 405 String prefixPrefix("ns", 2); |
399 for (unsigned i = attribute.namespaceURI().impl()->existingHash();; | 406 for (unsigned i = attribute.namespaceURI().impl()->existingHash();; |
400 ++i) { | 407 ++i) { |
401 AtomicString newPrefix(String(prefixPrefix + String::number(i))); | 408 AtomicString newPrefix(String(prefixPrefix + String::number(i))); |
402 AtomicString foundURI = namespaces->get(newPrefix); | 409 AtomicString foundURI = namespaces->get(newPrefix); |
403 if (foundURI == attribute.namespaceURI() || foundURI == nullAtom) { | 410 if (foundURI == attribute.namespaceURI() || foundURI == nullAtom) { |
404 // We already generated a prefix for this namespace. | 411 // We already generated a prefix for this namespace. |
405 prefixedName.setPrefix(newPrefix); | 412 prefixedName.setPrefix(newPrefix); |
406 break; | 413 break; |
407 } | 414 } |
(...skipping 14 matching lines...) Expand all Loading... |
422 appendQuotedURLAttributeValue(result, element, attribute); | 429 appendQuotedURLAttributeValue(result, element, attribute); |
423 } else { | 430 } else { |
424 result.append('"'); | 431 result.append('"'); |
425 appendAttributeValue(result, attribute.value(), documentIsHTML); | 432 appendAttributeValue(result, attribute.value(), documentIsHTML); |
426 result.append('"'); | 433 result.append('"'); |
427 } | 434 } |
428 } | 435 } |
429 | 436 |
430 void MarkupFormatter::appendCDATASection(StringBuilder& result, | 437 void MarkupFormatter::appendCDATASection(StringBuilder& result, |
431 const String& section) { | 438 const String& section) { |
432 // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other
callers) should raise an exception if it includes "]]>". | 439 // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other |
| 440 // callers) should raise an exception if it includes "]]>". |
433 result.append("<![CDATA["); | 441 result.append("<![CDATA["); |
434 result.append(section); | 442 result.append(section); |
435 result.append("]]>"); | 443 result.append("]]>"); |
436 } | 444 } |
437 | 445 |
438 bool MarkupFormatter::shouldAddNamespaceElement(const Element& element, | 446 bool MarkupFormatter::shouldAddNamespaceElement(const Element& element, |
439 Namespaces& namespaces) const { | 447 Namespaces& namespaces) const { |
440 // Don't add namespace attribute if it is already defined for this elem. | 448 // Don't add namespace attribute if it is already defined for this elem. |
441 const AtomicString& prefix = element.prefix(); | 449 const AtomicString& prefix = element.prefix(); |
442 if (prefix.isEmpty()) { | 450 if (prefix.isEmpty()) { |
443 if (element.hasAttribute(xmlnsAtom)) { | 451 if (element.hasAttribute(xmlnsAtom)) { |
444 namespaces.set(emptyAtom, element.namespaceURI()); | 452 namespaces.set(emptyAtom, element.namespaceURI()); |
445 return false; | 453 return false; |
446 } | 454 } |
447 return true; | 455 return true; |
448 } | 456 } |
449 | 457 |
450 return !element.hasAttribute(WTF::xmlnsWithColon + prefix); | 458 return !element.hasAttribute(WTF::xmlnsWithColon + prefix); |
451 } | 459 } |
452 | 460 |
453 bool MarkupFormatter::shouldAddNamespaceAttribute( | 461 bool MarkupFormatter::shouldAddNamespaceAttribute( |
454 const Attribute& attribute, | 462 const Attribute& attribute, |
455 const Element& element) const { | 463 const Element& element) const { |
456 // xmlns and xmlns:prefix attributes should be handled by another branch in ap
pendAttribute. | 464 // xmlns and xmlns:prefix attributes should be handled by another branch in |
| 465 // appendAttribute. |
457 DCHECK_NE(attribute.namespaceURI(), XMLNSNames::xmlnsNamespaceURI); | 466 DCHECK_NE(attribute.namespaceURI(), XMLNSNames::xmlnsNamespaceURI); |
458 | 467 |
459 // Attributes are in the null namespace by default. | 468 // Attributes are in the null namespace by default. |
460 if (!attribute.namespaceURI()) | 469 if (!attribute.namespaceURI()) |
461 return false; | 470 return false; |
462 | 471 |
463 // Attributes without a prefix will need one generated for them, and an xmlns
attribute for that prefix. | 472 // Attributes without a prefix will need one generated for them, and an xmlns |
| 473 // attribute for that prefix. |
464 if (!attribute.prefix()) | 474 if (!attribute.prefix()) |
465 return true; | 475 return true; |
466 | 476 |
467 return !element.hasAttribute(WTF::xmlnsWithColon + attribute.prefix()); | 477 return !element.hasAttribute(WTF::xmlnsWithColon + attribute.prefix()); |
468 } | 478 } |
469 | 479 |
470 EntityMask MarkupFormatter::entityMaskForText(const Text& text) const { | 480 EntityMask MarkupFormatter::entityMaskForText(const Text& text) const { |
471 if (!serializeAsHTMLDocument(text)) | 481 if (!serializeAsHTMLDocument(text)) |
472 return EntityMaskInPCDATA; | 482 return EntityMaskInPCDATA; |
473 | 483 |
474 // TODO(hajimehoshi): We need to switch EditingStrategy. | 484 // TODO(hajimehoshi): We need to switch EditingStrategy. |
475 const QualifiedName* parentName = nullptr; | 485 const QualifiedName* parentName = nullptr; |
476 if (text.parentElement()) | 486 if (text.parentElement()) |
477 parentName = &(text.parentElement())->tagQName(); | 487 parentName = &(text.parentElement())->tagQName(); |
478 | 488 |
479 if (parentName && (*parentName == scriptTag || *parentName == styleTag || | 489 if (parentName && (*parentName == scriptTag || *parentName == styleTag || |
480 *parentName == xmpTag)) | 490 *parentName == xmpTag)) |
481 return EntityMaskInCDATA; | 491 return EntityMaskInCDATA; |
482 return EntityMaskInHTMLPCDATA; | 492 return EntityMaskInHTMLPCDATA; |
483 } | 493 } |
484 | 494 |
485 // Rules of self-closure | 495 // Rules of self-closure |
486 // 1. No elements in HTML documents use the self-closing syntax. | 496 // 1. No elements in HTML documents use the self-closing syntax. |
487 // 2. Elements w/ children never self-close because they use a separate end tag. | 497 // 2. Elements w/ children never self-close because they use a separate end tag. |
488 // 3. HTML elements which do not have a "forbidden" end tag will close with a se
parate end tag. | 498 // 3. HTML elements which do not have a "forbidden" end tag will close with a |
| 499 // separate end tag. |
489 // 4. Other elements self-close. | 500 // 4. Other elements self-close. |
490 bool MarkupFormatter::shouldSelfClose(const Element& element) const { | 501 bool MarkupFormatter::shouldSelfClose(const Element& element) const { |
491 if (serializeAsHTMLDocument(element)) | 502 if (serializeAsHTMLDocument(element)) |
492 return false; | 503 return false; |
493 if (element.hasChildren()) | 504 if (element.hasChildren()) |
494 return false; | 505 return false; |
495 if (element.isHTMLElement() && !elementCannotHaveEndTag(element)) | 506 if (element.isHTMLElement() && !elementCannotHaveEndTag(element)) |
496 return false; | 507 return false; |
497 return true; | 508 return true; |
498 } | 509 } |
499 | 510 |
500 bool MarkupFormatter::serializeAsHTMLDocument(const Node& node) const { | 511 bool MarkupFormatter::serializeAsHTMLDocument(const Node& node) const { |
501 if (m_serializationType == SerializationType::ForcedXML) | 512 if (m_serializationType == SerializationType::ForcedXML) |
502 return false; | 513 return false; |
503 return node.document().isHTMLDocument(); | 514 return node.document().isHTMLDocument(); |
504 } | 515 } |
505 | 516 |
506 } // namespace blink | 517 } // namespace blink |
OLD | NEW |