1a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch/*
2a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
4a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *
5a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * Redistribution and use in source and binary forms, with or without
6a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * modification, are permitted provided that the following conditions
7a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * are met:
8a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 1. Redistributions of source code must retain the above copyright
9a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *    notice, this list of conditions and the following disclaimer.
10a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * 2. Redistributions in binary form must reproduce the above copyright
11a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *    notice, this list of conditions and the following disclaimer in the
12a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *    documentation and/or other materials provided with the distribution.
13a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch *
14a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
15a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
16a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
17a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
18a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
19a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
20a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch */
26a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
27a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "config.h"
28a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "MarkupAccumulator.h"
29a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
30a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "CDATASection.h"
31a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "Comment.h"
32a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "DocumentFragment.h"
33a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "DocumentType.h"
34a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "Editor.h"
35a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "HTMLElement.h"
36a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "HTMLNames.h"
37a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "KURL.h"
38a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "ProcessingInstruction.h"
39a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch#include "XMLNSNames.h"
402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block#include <wtf/unicode/CharacterNames.h>
41a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
42a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochnamespace WebCore {
43a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
44a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochusing namespace HTMLNames;
45a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
46a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid appendCharactersReplacingEntities(Vector<UChar>& out, const UChar* content, size_t length, EntityMask entityMask)
47a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
48a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    DEFINE_STATIC_LOCAL(const String, ampReference, ("&amp;"));
49a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    DEFINE_STATIC_LOCAL(const String, ltReference, ("&lt;"));
50a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    DEFINE_STATIC_LOCAL(const String, gtReference, ("&gt;"));
51a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    DEFINE_STATIC_LOCAL(const String, quotReference, ("&quot;"));
52a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    DEFINE_STATIC_LOCAL(const String, nbspReference, ("&nbsp;"));
53a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
54a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    static const EntityDescription entityMaps[] = {
55a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        { '&', ampReference, EntityAmp },
56a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        { '<', ltReference, EntityLt },
57a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        { '>', gtReference, EntityGt },
58a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        { '"', quotReference, EntityQuot },
59a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        { noBreakSpace, nbspReference, EntityNbsp },
60a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    };
61a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
62a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    size_t positionAfterLastEntity = 0;
634576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang    for (size_t i = 0; i < length; ++i) {
644576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        for (size_t m = 0; m < WTF_ARRAY_LENGTH(entityMaps); ++m) {
65a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (content[i] == entityMaps[m].entity && entityMaps[m].mask & entityMask) {
66a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                out.append(content + positionAfterLastEntity, i - positionAfterLastEntity);
67a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                append(out, entityMaps[m].reference);
68a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                positionAfterLastEntity = i + 1;
69a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                break;
70a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            }
71a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
72a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
73a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    out.append(content + positionAfterLastEntity, length - positionAfterLastEntity);
74a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
75a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
76a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochMarkupAccumulator::MarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, const Range* range)
77a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    : m_nodes(nodes)
78a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_range(range)
79a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    , m_shouldResolveURLs(shouldResolveURLs)
80a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
81a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
82a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
83a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochMarkupAccumulator::~MarkupAccumulator()
84a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
85a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
86a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
87a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochString MarkupAccumulator::serializeNodes(Node* node, Node* nodeToSkip, EChildrenOnly childrenOnly)
88a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
89a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    Vector<UChar> out;
90a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    serializeNodesWithNamespaces(node, nodeToSkip, childrenOnly, 0);
91a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    out.reserveInitialCapacity(length());
92a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    concatenateMarkup(out);
93a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return String::adopt(out);
94a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
95a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
96a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::serializeNodesWithNamespaces(Node* node, Node* nodeToSkip, EChildrenOnly childrenOnly, const Namespaces* namespaces)
97a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
98a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (node == nodeToSkip)
99a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
100a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
101a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    Namespaces namespaceHash;
102a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (namespaces)
103a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        namespaceHash = *namespaces;
104a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
105a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!childrenOnly)
106a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendStartTag(node, &namespaceHash);
107a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
108a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!(node->document()->isHTMLDocument() && elementCannotHaveEndTag(node))) {
109a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        for (Node* current = node->firstChild(); current; current = current->nextSibling())
110a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            serializeNodesWithNamespaces(current, nodeToSkip, IncludeNode, &namespaceHash);
111a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
112a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
113a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!childrenOnly)
114a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendEndTag(node);
115a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
116a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
117a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendString(const String& string)
118a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
119a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    m_succeedingMarkup.append(string);
120a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
121a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
122a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendStartTag(Node* node, Namespaces* namespaces)
123a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
124a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    Vector<UChar> markup;
125a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendStartMarkup(markup, node, namespaces);
126a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendString(String::adopt(markup));
127a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (m_nodes)
128a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        m_nodes->append(node);
129a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
130a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
131a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendEndTag(Node* node)
132a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
133a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    Vector<UChar> markup;
134a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendEndMarkup(markup, node);
135a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendString(String::adopt(markup));
136a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
137a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
138a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochsize_t MarkupAccumulator::totalLength(const Vector<String>& strings)
139a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    size_t length = 0;
141a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    for (size_t i = 0; i < strings.size(); ++i)
142a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        length += strings[i].length();
143a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return length;
144a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
145a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
146a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// FIXME: This is a very inefficient way of accumulating the markup.
147a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// We're converting results of appendStartMarkup and appendEndMarkup from Vector<UChar> to String
148a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// and then back to Vector<UChar> and again to String here.
149a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::concatenateMarkup(Vector<UChar>& out)
150a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
151a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    for (size_t i = 0; i < m_succeedingMarkup.size(); ++i)
152a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(out, m_succeedingMarkup[i]);
153a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
154a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
155a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendAttributeValue(Vector<UChar>& result, const String& attribute, bool documentIsHTML)
156a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
157a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendCharactersReplacingEntities(result, attribute.characters(), attribute.length(),
158a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        documentIsHTML ? EntityMaskInHTMLAttributeValue : EntityMaskInAttributeValue);
159a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
160a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
161a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendQuotedURLAttributeValue(Vector<UChar>& result, const String& urlString)
162a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
163a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    UChar quoteChar = '\"';
164a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    String strippedURLString = urlString.stripWhiteSpace();
165a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (protocolIsJavaScript(strippedURLString)) {
166a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // minimal escaping for javascript urls
167a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (strippedURLString.contains('"')) {
168a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            if (strippedURLString.contains('\''))
169a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                strippedURLString.replace('\"', "&quot;");
170a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            else
171a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch                quoteChar = '\'';
172a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
173a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        result.append(quoteChar);
174a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, strippedURLString);
175a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        result.append(quoteChar);
176a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
177a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
178a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
179a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // FIXME: This does not fully match other browsers. Firefox percent-escapes non-ASCII characters for innerHTML.
180a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    result.append(quoteChar);
181a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendAttributeValue(result, urlString, false);
182a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    result.append(quoteChar);
183a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
184a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
185a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendNodeValue(Vector<UChar>& out, const Node* node, const Range* range, EntityMask entityMask)
186a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
187a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    String str = node->nodeValue();
188a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const UChar* characters = str.characters();
189a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    size_t length = str.length();
190a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
191a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (range) {
192a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        ExceptionCode ec;
193a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (node == range->endContainer(ec))
194a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            length = range->endOffset(ec);
195a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (node == range->startContainer(ec)) {
196a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            size_t start = range->startOffset(ec);
197a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            characters += start;
198a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            length -= start;
199a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
200a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
201a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
202a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendCharactersReplacingEntities(out, characters, length, entityMask);
203a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
204a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
205a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochbool MarkupAccumulator::shouldAddNamespaceElement(const Element* element)
206a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
207a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Don't add namespace attribute if it is already defined for this elem.
208a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const AtomicString& prefix = element->prefix();
209a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    AtomicString attr = !prefix.isEmpty() ? "xmlns:" + prefix : "xmlns";
210a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return !element->hasAttribute(attr);
211a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
212a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
213a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochbool MarkupAccumulator::shouldAddNamespaceAttribute(const Attribute& attribute, Namespaces& namespaces)
214a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
215a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    namespaces.checkConsistency();
216a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
217a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Don't add namespace attributes twice
218a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (attribute.name() == XMLNSNames::xmlnsAttr) {
219a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        namespaces.set(emptyAtom.impl(), attribute.value().impl());
220a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
221a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
222a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
223a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    QualifiedName xmlnsPrefixAttr(xmlnsAtom, attribute.localName(), XMLNSNames::xmlnsNamespaceURI);
224a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (attribute.name() == xmlnsPrefixAttr) {
225a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        namespaces.set(attribute.localName().impl(), attribute.value().impl());
226a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
227a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
228a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
229a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return true;
230a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
231a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
232a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendNamespace(Vector<UChar>& result, const AtomicString& prefix, const AtomicString& namespaceURI, Namespaces& namespaces)
233a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
234a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    namespaces.checkConsistency();
235a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (namespaceURI.isEmpty())
236a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
237a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
238a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // Use emptyAtoms's impl() for both null and empty strings since the HashMap can't handle 0 as a key
239a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    AtomicStringImpl* pre = prefix.isEmpty() ? emptyAtom.impl() : prefix.impl();
240a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    AtomicStringImpl* foundNS = namespaces.get(pre);
241a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (foundNS != namespaceURI.impl()) {
242a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        namespaces.set(pre, namespaceURI.impl());
243a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        result.append(' ');
244a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, xmlnsAtom.string());
245a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!prefix.isEmpty()) {
246a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            result.append(':');
247a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            append(result, prefix);
248a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
249a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
250a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        result.append('=');
251a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        result.append('"');
252a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendAttributeValue(result, namespaceURI, false);
253a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        result.append('"');
254a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
255a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
256a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
257a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochEntityMask MarkupAccumulator::entityMaskForText(Text* text) const
258a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
259a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    const QualifiedName* parentName = 0;
260a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (text->parentElement())
261a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        parentName = &static_cast<Element*>(text->parentElement())->tagQName();
262a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
263a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (parentName && (*parentName == scriptTag || *parentName == styleTag || *parentName == xmpTag))
264a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return EntityMaskInCDATA;
265a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
266a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return text->document()->isHTMLDocument() ? EntityMaskInHTMLPCDATA : EntityMaskInPCDATA;
267a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
268a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
269a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendText(Vector<UChar>& out, Text* text)
270a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
271a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendNodeValue(out, text, m_range, entityMaskForText(text));
272a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
273a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
274a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendComment(Vector<UChar>& out, const String& comment)
275a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
276a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // FIXME: Comment content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "-->".
277a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, "<!--");
278a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, comment);
279a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, "-->");
280a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
281a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
282a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendDocumentType(Vector<UChar>& result, const DocumentType* n)
283a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
284a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (n->name().isEmpty())
285a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
286a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
287a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(result, "<!DOCTYPE ");
288a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(result, n->name());
289a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!n->publicId().isEmpty()) {
290a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, " PUBLIC \"");
291a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, n->publicId());
292a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, "\"");
293a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (!n->systemId().isEmpty()) {
294a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            append(result, " \"");
295a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            append(result, n->systemId());
296a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            append(result, "\"");
297a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        }
298a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    } else if (!n->systemId().isEmpty()) {
299a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, " SYSTEM \"");
300a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, n->systemId());
301a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, "\"");
302a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
303a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!n->internalSubset().isEmpty()) {
304a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, " [");
305a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, n->internalSubset());
306a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(result, "]");
307a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
308a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(result, ">");
309a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
310a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
311a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendProcessingInstruction(Vector<UChar>& out, const String& target, const String& data)
312a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
313a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // FIXME: PI data is not escaped, but XMLSerializer (and possibly other callers) this should raise an exception if it includes "?>".
314a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, "<?");
315a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, target);
316a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, " ");
317a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, data);
318a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, "?>");
319a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
320a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
321a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendElement(Vector<UChar>& out, Element* element, Namespaces* namespaces)
322a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
323a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendOpenTag(out, element, namespaces);
324a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
325a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    NamedNodeMap* attributes = element->attributes();
326a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    unsigned length = attributes->length();
327a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    for (unsigned int i = 0; i < length; i++)
328a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendAttribute(out, element, *attributes->attributeItem(i), namespaces);
329a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
330a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    appendCloseTag(out, element);
331a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
332a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
333a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendOpenTag(Vector<UChar>& out, Element* element, Namespaces* namespaces)
334a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
335a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    out.append('<');
336a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, element->nodeNamePreservingCase());
337a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!element->document()->isHTMLDocument() && namespaces && shouldAddNamespaceElement(element))
338a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendNamespace(out, element->prefix(), element->namespaceURI(), *namespaces);
339a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
340a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
341a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendCloseTag(Vector<UChar>& out, Element* element)
342a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
343a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (shouldSelfClose(element)) {
344a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (element->isHTMLElement())
345a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            out.append(' '); // XHTML 1.0 <-> HTML compatibility.
346a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        out.append('/');
347a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
348a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    out.append('>');
349a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
350a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
351a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendAttribute(Vector<UChar>& out, Element* element, const Attribute& attribute, Namespaces* namespaces)
352a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
353a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    bool documentIsHTML = element->document()->isHTMLDocument();
354a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
355a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    out.append(' ');
356a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
357a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (documentIsHTML)
358a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(out, attribute.name().localName());
359a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    else
360a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        append(out, attribute.name().toString());
361a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
362a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    out.append('=');
363a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
364a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (element->isURLAttribute(const_cast<Attribute*>(&attribute))) {
365a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // We don't want to complete file:/// URLs because it may contain sensitive information
366a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        // about the user's system.
367a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        if (shouldResolveURLs() && !element->document()->url().isLocalFile())
368a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            appendQuotedURLAttributeValue(out, element->document()->completeURL(attribute.value()).string());
369a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        else
370a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch            appendQuotedURLAttributeValue(out, attribute.value());
371a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    } else {
372a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        out.append('\"');
373a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendAttributeValue(out, attribute.value(), documentIsHTML);
374a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        out.append('\"');
375a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
376a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
377a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!documentIsHTML && namespaces && shouldAddNamespaceAttribute(attribute, *namespaces))
378a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendNamespace(out, attribute.prefix(), attribute.namespaceURI(), *namespaces);
379a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
380a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
381a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendCDATASection(Vector<UChar>& out, const String& section)
382a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
383a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "]]>".
384a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, "<![CDATA[");
385a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, section);
386a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(out, "]]>");
387a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
388a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
389a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendStartMarkup(Vector<UChar>& result, const Node* node, Namespaces* namespaces)
390a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
391a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (namespaces)
392a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        namespaces->checkConsistency();
393a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
394a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    switch (node->nodeType()) {
395a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::TEXT_NODE:
396a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendText(result, static_cast<Text*>(const_cast<Node*>(node)));
397a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
398a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::COMMENT_NODE:
399a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendComment(result, static_cast<const Comment*>(node)->data());
400a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
401a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::DOCUMENT_NODE:
402a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::DOCUMENT_FRAGMENT_NODE:
403a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
404a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::DOCUMENT_TYPE_NODE:
405a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendDocumentType(result, static_cast<const DocumentType*>(node));
406a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
407a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::PROCESSING_INSTRUCTION_NODE:
408a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendProcessingInstruction(result, static_cast<const ProcessingInstruction*>(node)->target(), static_cast<const ProcessingInstruction*>(node)->data());
409a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
410a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::ELEMENT_NODE:
411a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendElement(result, static_cast<Element*>(const_cast<Node*>(node)), namespaces);
412a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
413a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::CDATA_SECTION_NODE:
414a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        appendCDATASection(result, static_cast<const CDATASection*>(node)->data());
415a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
416a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::ATTRIBUTE_NODE:
417a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::ENTITY_NODE:
418a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::ENTITY_REFERENCE_NODE:
419a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::NOTATION_NODE:
420a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    case Node::XPATH_NAMESPACE_NODE:
421a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        ASSERT_NOT_REACHED();
422a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        break;
423a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    }
424a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
425a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
426a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// Rules of self-closure
427a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// 1. No elements in HTML documents use the self-closing syntax.
428a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// 2. Elements w/ children never self-close because they use a separate end tag.
429a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// 3. HTML elements which do not have a "forbidden" end tag will close with a separate end tag.
430a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch// 4. Other elements self-close.
431a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochbool MarkupAccumulator::shouldSelfClose(const Node* node)
432a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
433a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (node->document()->isHTMLDocument())
434a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
435a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (node->hasChildNodes())
436a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
437a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (node->isHTMLElement() && !elementCannotHaveEndTag(node))
438a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
439a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return true;
440a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
441a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
442a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochbool MarkupAccumulator::elementCannotHaveEndTag(const Node* node)
443a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
444a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!node->isHTMLElement())
445a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return false;
446a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
447a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // FIXME: ieForbidsInsertHTML may not be the right function to call here
448a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // ieForbidsInsertHTML is used to disallow setting innerHTML/outerHTML
449a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // or createContextualFragment.  It does not necessarily align with
450a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    // which elements should be serialized w/o end tags.
451a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    return static_cast<const HTMLElement*>(node)->ieForbidsInsertHTML();
452a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
453a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
454a94275402997c11dd2e778633dacf4b7e630a35dBen Murdochvoid MarkupAccumulator::appendEndMarkup(Vector<UChar>& result, const Node* node)
455a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
456a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    if (!node->isElementNode() || shouldSelfClose(node) || (!node->hasChildNodes() && elementCannotHaveEndTag(node)))
457a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch        return;
458a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
459a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    result.append('<');
460a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    result.append('/');
461a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    append(result, static_cast<const Element*>(node)->nodeNamePreservingCase());
462a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch    result.append('>');
463a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
464a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
465a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
466