15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/*
25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009, 2012 Apple Inc. All rights reserved.
35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2009, 2010 Google Inc. All rights reserved.
45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without
65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions
75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met:
85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright
95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer.
105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright
115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    notice, this list of conditions and the following disclaimer in the
125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *    documentation and/or other materials provided with the distribution.
135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) *
145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */
265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h"
2853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/MarkupAccumulator.h"
2953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)
305d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/HTMLNames.h"
315d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/XLinkNames.h"
325d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/XMLNSNames.h"
335d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/XMLNames.h"
3453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/CDATASection.h"
3553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Comment.h"
365d92fedcae5e801a8b224de090094f2d9df0b54aTorne (Richard Coles)#include "core/dom/Document.h"
3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/DocumentFragment.h"
3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/DocumentType.h"
3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/ProcessingInstruction.h"
4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/Editor.h"
4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLElement.h"
4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLTemplateElement.h"
4351b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "platform/weborigin/KURL.h"
44521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#include "wtf/unicode/CharacterNames.h"
455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
46c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)namespace blink {
475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace HTMLNames;
495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)struct EntityDescription {
5109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    UChar entity;
5209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    const CString& reference;
5309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    EntityMask mask;
5409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)};
5509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
5609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)template <typename CharType>
5709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)static inline void appendCharactersReplacingEntitiesInternal(StringBuilder& result, CharType* text, unsigned length, const EntityDescription entityMaps[], unsigned entityMapsCount, EntityMask entityMask)
5809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles){
5909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    unsigned positionAfterLastEntity = 0;
6009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    for (unsigned i = 0; i < length; ++i) {
6109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        for (unsigned entityIndex = 0; entityIndex < entityMapsCount; ++entityIndex) {
6209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            if (text[i] == entityMaps[entityIndex].entity && entityMaps[entityIndex].mask & entityMask) {
6309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                result.append(text + positionAfterLastEntity, i - positionAfterLastEntity);
6409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                const CString& replacement = entityMaps[entityIndex].reference;
6509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                result.append(replacement.data(), replacement.length());
6609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                positionAfterLastEntity = i + 1;
6709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)                break;
6809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            }
6909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
7009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
7109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    result.append(text + positionAfterLastEntity, length - positionAfterLastEntity);
7209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)}
7309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::appendCharactersReplacingEntities(StringBuilder& result, const String& source, unsigned offset, unsigned length, EntityMask entityMask)
755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
7609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    DEFINE_STATIC_LOCAL(const CString, ampReference, ("&amp;"));
7709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    DEFINE_STATIC_LOCAL(const CString, ltReference, ("&lt;"));
7809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    DEFINE_STATIC_LOCAL(const CString, gtReference, ("&gt;"));
7909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    DEFINE_STATIC_LOCAL(const CString, quotReference, ("&quot;"));
8009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    DEFINE_STATIC_LOCAL(const CString, nbspReference, ("&nbsp;"));
815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    static const EntityDescription entityMaps[] = {
835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        { '&', ampReference, EntityAmp },
845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        { '<', ltReference, EntityLt },
855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        { '>', gtReference, EntityGt },
865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        { '"', quotReference, EntityQuot },
875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        { noBreakSpace, nbspReference, EntityNbsp },
885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    };
895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!(offset + length))
915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    ASSERT(offset + length <= source.length());
9409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (source.is8Bit())
9509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendCharactersReplacingEntitiesInternal(result, source.characters8() + offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask);
9609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    else
9709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendCharactersReplacingEntitiesInternal(result, source.characters16() + offset, length, entityMaps, WTF_ARRAY_LENGTH(entityMaps), entityMask);
985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
100f6b7aed3f7ce69aca0d7a032d144cbd088b04393Torne (Richard Coles)MarkupAccumulator::MarkupAccumulator(WillBeHeapVector<RawPtrWillBeMember<Node> >* nodes, EAbsoluteURLs resolveUrlsMethod, const Range* range, SerializationType serializationType)
1015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    : m_nodes(nodes)
1025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_range(range)
1035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    , m_resolveURLsMethod(resolveUrlsMethod)
104d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    , m_serializationType(serializationType)
1055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)MarkupAccumulator::~MarkupAccumulator()
1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
11209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)String MarkupAccumulator::serializeNodes(Node& targetNode, EChildrenOnly childrenOnly, Vector<QualifiedName>* tagNamesToSkip)
1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
114d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    Namespaces* namespaces = 0;
115d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    Namespaces namespaceHash;
116d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (!serializeAsHTMLDocument(targetNode)) {
117d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        // Add pre-bound namespaces for XML fragments.
1186f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        namespaceHash.set(xmlAtom, XMLNames::xmlNamespaceURI);
119d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        namespaces = &namespaceHash;
120d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    }
121d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
122d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    serializeNodesWithNamespaces(targetNode, childrenOnly, namespaces, tagNamesToSkip);
1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return m_markup.toString();
1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
12609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::serializeNodesWithNamespaces(Node& targetNode, EChildrenOnly childrenOnly, const Namespaces* namespaces, Vector<QualifiedName>* tagNamesToSkip)
1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
128c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (tagNamesToSkip && targetNode.isElementNode()) {
1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        for (size_t i = 0; i < tagNamesToSkip->size(); ++i) {
130c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            if (toElement(targetNode).hasTagName(tagNamesToSkip->at(i)))
1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                return;
1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    Namespaces namespaceHash;
1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (namespaces)
1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        namespaceHash = *namespaces;
1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!childrenOnly)
1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        appendStartTag(targetNode, &namespaceHash);
1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
142d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (!(serializeAsHTMLDocument(targetNode) && elementCannotHaveEndTag(targetNode))) {
143d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        Node* current = isHTMLTemplateElement(targetNode) ? toHTMLTemplateElement(targetNode).content()->firstChild() : targetNode.firstChild();
144926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        for ( ; current; current = current->nextSibling())
14509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            serializeNodesWithNamespaces(*current, IncludeNode, &namespaceHash, tagNamesToSkip);
1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
148c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (!childrenOnly && targetNode.isElementNode())
149c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        appendEndTag(toElement(targetNode));
1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
15209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)String MarkupAccumulator::resolveURLIfNeeded(const Element& element, const String& urlString) const
1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    switch (m_resolveURLsMethod) {
1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case ResolveAllURLs:
15609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        return element.document().completeURL(urlString).string();
1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case ResolveNonLocalURLs:
15909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!element.document().url().isLocalFile())
16009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            return element.document().completeURL(urlString).string();
1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case DoNotResolveURLs:
1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
1655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return urlString;
1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::appendString(const String& string)
1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    m_markup.append(string);
1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
17409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendStartTag(Node& node, Namespaces* namespaces)
1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    appendStartMarkup(m_markup, node, namespaces);
1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (m_nodes)
17809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        m_nodes->append(&node);
1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
181c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void MarkupAccumulator::appendEndTag(const Element& element)
1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
183c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    appendEndMarkup(m_markup, element);
1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)size_t MarkupAccumulator::totalLength(const Vector<String>& strings)
1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    size_t length = 0;
1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    for (size_t i = 0; i < strings.size(); ++i)
1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        length += strings[i].length();
1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return length;
1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::concatenateMarkup(StringBuilder& result)
1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(m_markup);
1975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
1985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::appendAttributeValue(StringBuilder& result, const String& attribute, bool documentIsHTML)
2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    appendCharactersReplacingEntities(result, attribute, 0, attribute.length(),
2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        documentIsHTML ? EntityMaskInHTMLAttributeValue : EntityMaskInAttributeValue);
2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
20509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendCustomAttributes(StringBuilder&, const Element&, Namespaces*)
2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
20909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendQuotedURLAttributeValue(StringBuilder& result, const Element& element, const Attribute& attribute)
2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
21109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    ASSERT(element.isURLAttribute(attribute));
2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const String resolvedURLString = resolveURLIfNeeded(element, attribute.value());
2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    UChar quoteChar = '"';
2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    String strippedURLString = resolvedURLString.stripWhiteSpace();
2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (protocolIsJavaScript(strippedURLString)) {
2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        // minimal escaping for javascript urls
2175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (strippedURLString.contains('"')) {
2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            if (strippedURLString.contains('\''))
2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                strippedURLString.replaceWithLiteral('"', "&quot;");
2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            else
2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                quoteChar = '\'';
2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(quoteChar);
2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(strippedURLString);
2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(quoteChar);
2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: This does not fully match other browsers. Firefox percent-escapes non-ASCII characters for innerHTML.
2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(quoteChar);
2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    appendAttributeValue(result, resolvedURLString, false);
2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(quoteChar);
2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
235d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)bool MarkupAccumulator::shouldAddNamespaceElement(const Element& element, Namespaces& namespaces)
2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Don't add namespace attribute if it is already defined for this elem.
23809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    const AtomicString& prefix = element.prefix();
239d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (prefix.isEmpty()) {
240d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        if (element.hasAttribute(xmlnsAtom)) {
2416f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            namespaces.set(emptyAtom, element.namespaceURI());
242d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)            return false;
243d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        }
244d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return true;
245d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    }
2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2476f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    return !element.hasAttribute(WTF::xmlnsWithColon + prefix);
2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2506f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdochbool MarkupAccumulator::shouldAddNamespaceAttribute(const Attribute& attribute, const Element& element)
2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2526f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    // xmlns and xmlns:prefix attributes should be handled by another branch in appendAttribute.
2536f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    ASSERT(attribute.namespaceURI() != XMLNSNames::xmlnsNamespaceURI);
2545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2556f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    // Attributes are in the null namespace by default.
2566f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    if (!attribute.namespaceURI())
2575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2596f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    // Attributes without a prefix will need one generated for them, and an xmlns attribute for that prefix.
2606f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    if (!attribute.prefix())
2616f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        return true;
2626f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch
2636f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    return !element.hasAttribute(WTF::xmlnsWithColon + attribute.prefix());
2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::appendNamespace(StringBuilder& result, const AtomicString& prefix, const AtomicString& namespaceURI, Namespaces& namespaces)
2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (namespaceURI.isEmpty())
2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
2705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2716f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    const AtomicString& lookupKey = (!prefix) ? emptyAtom : prefix;
2726f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    AtomicString foundURI = namespaces.get(lookupKey);
2736f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch    if (foundURI != namespaceURI) {
2746f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        namespaces.set(lookupKey, namespaceURI);
2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(' ');
2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(xmlnsAtom.string());
2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        if (!prefix.isEmpty()) {
2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.append(':');
2795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.append(prefix);
2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
28209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        result.appendLiteral("=\"");
2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        appendAttributeValue(result, namespaceURI, false);
2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append('"');
2855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
28809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)EntityMask MarkupAccumulator::entityMaskForText(const Text& text) const
2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
290d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (!serializeAsHTMLDocument(text))
29151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)        return EntityMaskInPCDATA;
29251b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)
2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    const QualifiedName* parentName = 0;
29409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (text.parentElement())
29509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        parentName = &(text.parentElement())->tagQName();
2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (parentName && (*parentName == scriptTag || *parentName == styleTag || *parentName == xmpTag))
2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return EntityMaskInCDATA;
29951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)    return EntityMaskInHTMLPCDATA;
3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
30209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendText(StringBuilder& result, Text& text)
3035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
30409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    const String& str = text.data();
30509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    unsigned length = str.length();
30609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    unsigned start = 0;
30709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)
30809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (m_range) {
30909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (text == m_range->endContainer())
31009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            length = m_range->endOffset();
31109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (text == m_range->startContainer()) {
31209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            start = m_range->startOffset();
31309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            length -= start;
31409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        }
31509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    }
31609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    appendCharactersReplacingEntities(result, str, start, length, entityMaskForText(text));
3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::appendComment(StringBuilder& result, const String& comment)
3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: Comment content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "-->".
3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.appendLiteral("<!--");
3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(comment);
3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.appendLiteral("-->");
3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
32709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendXMLDeclaration(StringBuilder& result, const Document& document)
3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
32909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (!document.hasXMLDeclaration())
3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.appendLiteral("<?xml version=\"");
33309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    result.append(document.xmlVersion());
33409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    const String& encoding = document.xmlEncoding();
3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (!encoding.isEmpty()) {
3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.appendLiteral("\" encoding=\"");
3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(encoding);
3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
33909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (document.xmlStandaloneStatus() != Document::StandaloneUnspecified) {
3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.appendLiteral("\" standalone=\"");
34109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (document.xmlStandalone())
3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.appendLiteral("yes");
3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        else
3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.appendLiteral("no");
3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.appendLiteral("\"?>");
3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
35009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendDocumentType(StringBuilder& result, const DocumentType& n)
3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
35209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (n.name().isEmpty())
3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.appendLiteral("<!DOCTYPE ");
35609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    result.append(n.name());
35709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (!n.publicId().isEmpty()) {
3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.appendLiteral(" PUBLIC \"");
35909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        result.append(n.publicId());
3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append('"');
36109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (!n.systemId().isEmpty()) {
36209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            result.appendLiteral(" \"");
36309380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)            result.append(n.systemId());
3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.append('"');
3655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
36609380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    } else if (!n.systemId().isEmpty()) {
3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.appendLiteral(" SYSTEM \"");
36809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        result.append(n.systemId());
3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append('"');
3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append('>');
3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::appendProcessingInstruction(StringBuilder& result, const String& target, const String& data)
3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: PI data is not escaped, but XMLSerializer (and possibly other callers) this should raise an exception if it includes "?>".
37709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    result.appendLiteral("<?");
3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(target);
3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(' ');
3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(data);
38109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    result.appendLiteral("?>");
3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
38409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendElement(StringBuilder& result, Element& element, Namespaces* namespaces)
3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    appendOpenTag(result, element, namespaces);
3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
388c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    AttributeCollection attributes = element.attributes();
389e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    AttributeCollection::iterator end = attributes.end();
390e38fbeeb576b5094e34e038ab88d9d6a5c5c2214Torne (Richard Coles)    for (AttributeCollection::iterator it = attributes.begin(); it != end; ++it)
391c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        appendAttribute(result, element, *it, namespaces);
3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // Give an opportunity to subclasses to add their own attributes.
3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    appendCustomAttributes(result, element, namespaces);
3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    appendCloseTag(result, element);
3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
39909380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendOpenTag(StringBuilder& result, const Element& element, Namespaces* namespaces)
4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append('<');
402c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    result.append(element.tagQName().toString());
403d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (!serializeAsHTMLDocument(element) && namespaces && shouldAddNamespaceElement(element, *namespaces))
40409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendNamespace(result, element.prefix(), element.namespaceURI(), *namespaces);
4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
40709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendCloseTag(StringBuilder& result, const Element& element)
4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    if (shouldSelfClose(element)) {
41009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        if (element.isHTMLElement())
4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)            result.append(' '); // XHTML 1.0 <-> HTML compatibility.
4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append('/');
4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append('>');
4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline bool attributeIsInSerializedNamespace(const Attribute& attribute)
4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return attribute.namespaceURI() == XMLNames::xmlNamespaceURI
4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        || attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI
4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        || attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI;
4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
42409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendAttribute(StringBuilder& result, const Element& element, const Attribute& attribute, Namespaces* namespaces)
4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
426d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    bool documentIsHTML = serializeAsHTMLDocument(element);
4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
428d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    QualifiedName prefixedName = attribute.name();
429d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (documentIsHTML && !attributeIsInSerializedNamespace(attribute)) {
4306f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        result.append(' ');
4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(attribute.name().localName());
432d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    } else {
433c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        if (attribute.namespaceURI() == XMLNSNames::xmlnsNamespaceURI) {
4346f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            if (!attribute.prefix() && attribute.localName() != xmlnsAtom)
4355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)                prefixedName.setPrefix(xmlnsAtom);
4366f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            if (namespaces) { // Account for the namespace attribute we're about to append.
4376f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch                const AtomicString& lookupKey = (!attribute.prefix()) ? emptyAtom : attribute.localName();
4386f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch                namespaces->set(lookupKey, attribute.value());
4396f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            }
440c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        } else if (attribute.namespaceURI() == XMLNames::xmlNamespaceURI) {
441c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            if (!attribute.prefix())
442c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                prefixedName.setPrefix(xmlAtom);
443c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)        } else {
444c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            if (attribute.namespaceURI() == XLinkNames::xlinkNamespaceURI) {
445c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                if (!attribute.prefix())
446c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                    prefixedName.setPrefix(xlinkAtom);
447c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            }
448c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)
449c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)            if (namespaces && shouldAddNamespaceAttribute(attribute, element)) {
450c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                if (!prefixedName.prefix()) {
451c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                    // This behavior is in process of being standardized. See crbug.com/248044 and https://www.w3.org/Bugs/Public/show_bug.cgi?id=24208
452c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                    String prefixPrefix("ns", 2);
453c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                    for (unsigned i = attribute.namespaceURI().impl()->existingHash(); ; ++i) {
454c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                        AtomicString newPrefix(String(prefixPrefix + String::number(i)));
455c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                        AtomicString foundURI = namespaces->get(newPrefix);
456c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                        if (foundURI == attribute.namespaceURI() || foundURI == nullAtom) {
457c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                            // We already generated a prefix for this namespace.
458c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                            prefixedName.setPrefix(newPrefix);
459c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                            break;
460c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                        }
4616f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch                    }
4626f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch                }
463c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                ASSERT(prefixedName.prefix());
464c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)                appendNamespace(result, prefixedName.prefix(), attribute.namespaceURI(), *namespaces);
4656f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch            }
4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        }
4676f543c786fc42989f552b4daa774ca5ff32fa697Ben Murdoch        result.append(' ');
4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append(prefixedName.toString());
4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append('=');
4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
473d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (element.isURLAttribute(attribute)) {
4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        appendQuotedURLAttributeValue(result, element, attribute);
475d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    } else {
4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append('"');
4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        appendAttributeValue(result, attribute.value(), documentIsHTML);
4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        result.append('"');
4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void MarkupAccumulator::appendCDATASection(StringBuilder& result, const String& section)
4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: CDATA content is not escaped, but XMLSerializer (and possibly other callers) should raise an exception if it includes "]]>".
4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.appendLiteral("<![CDATA[");
4865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append(section);
4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.appendLiteral("]]>");
4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
49009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)void MarkupAccumulator::appendStartMarkup(StringBuilder& result, Node& node, Namespaces* namespaces)
4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
49209380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    switch (node.nodeType()) {
4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::TEXT_NODE:
49409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendText(result, toText(node));
4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::COMMENT_NODE:
49709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendComment(result, toComment(node).data());
4985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::DOCUMENT_NODE:
500926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)        appendXMLDeclaration(result, toDocument(node));
5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::DOCUMENT_FRAGMENT_NODE:
5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::DOCUMENT_TYPE_NODE:
5058abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)        appendDocumentType(result, toDocumentType(node));
5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::PROCESSING_INSTRUCTION_NODE:
50809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendProcessingInstruction(result, toProcessingInstruction(node).target(), toProcessingInstruction(node).data());
5095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::ELEMENT_NODE:
51109380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendElement(result, toElement(node), namespaces);
5125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::CDATA_SECTION_NODE:
51409380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)        appendCDATASection(result, toCDATASection(node).data());
5155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    case Node::ATTRIBUTE_NODE:
5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        ASSERT_NOT_REACHED();
5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        break;
5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    }
5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// Rules of self-closure
5235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// 1. No elements in HTML documents use the self-closing syntax.
5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// 2. Elements w/ children never self-close because they use a separate end tag.
5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// 3. HTML elements which do not have a "forbidden" end tag will close with a separate end tag.
5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// 4. Other elements self-close.
527c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)bool MarkupAccumulator::shouldSelfClose(const Element& element)
5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
529c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (serializeAsHTMLDocument(element))
5305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
531c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (element.hasChildren())
5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
533c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (element.isHTMLElement() && !elementCannotHaveEndTag(element))
5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    return true;
5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
53809380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)bool MarkupAccumulator::elementCannotHaveEndTag(const Node& node)
5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
54009380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    if (!node.isHTMLElement())
5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return false;
5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
5435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // FIXME: ieForbidsInsertHTML may not be the right function to call here
5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // ieForbidsInsertHTML is used to disallow setting innerHTML/outerHTML
5455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // or createContextualFragment.  It does not necessarily align with
5465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    // which elements should be serialized w/o end tags.
54709380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    return toHTMLElement(node).ieForbidsInsertHTML();
5485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
550c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)void MarkupAccumulator::appendEndMarkup(StringBuilder& result, const Element& element)
5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){
552c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    if (shouldSelfClose(element) || (!element.hasChildren() && elementCannotHaveEndTag(element)))
5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)        return;
5545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
55509380295ba73501a205346becac22c6978e4671dTorne (Richard Coles)    result.appendLiteral("</");
556c1847b1379d12d0e05df27436bf19a9b1bf12deaTorne (Richard Coles)    result.append(element.tagQName().toString());
5575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)    result.append('>');
5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
5595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)
560d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)bool MarkupAccumulator::serializeAsHTMLDocument(const Node& node) const
561d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles){
562d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    if (m_serializationType == ForcedXML)
563d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)        return false;
564d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)    return node.document().isHTMLDocument();
565d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)}
566d5428f32f5d1719f774f62e19147104ca245a3abTorne (Richard Coles)
5675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}
568