15c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)/* 25c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. 35c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2008, 2009, 2010, 2011 Google Inc. All rights reserved. 45c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2011 Igalia S.L. 55c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Copyright (C) 2011 Motorola Mobility. All rights reserved. 65c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 75c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * Redistribution and use in source and binary forms, with or without 85c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * modification, are permitted provided that the following conditions 95c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * are met: 105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 1. Redistributions of source code must retain the above copyright 115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer. 125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 2. Redistributions in binary form must reproduce the above copyright 135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * notice, this list of conditions and the following disclaimer in the 145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * documentation and/or other materials provided with the distribution. 155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * 165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 2602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) */ 285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "config.h" 3053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/markup.h" 315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "CSSPropertyNames.h" 335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "CSSValueKeywords.h" 345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)#include "HTMLNames.h" 35df95704c49daea886ddad70775bda23618d6274dBen Murdoch#include "bindings/v8/ExceptionState.h" 3653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/CSSPrimitiveValue.h" 3753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/CSSValue.h" 3853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/css/StylePropertySet.h" 3953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/CDATASection.h" 4053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/ChildListMutationScope.h" 4153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/ContextFeatures.h" 4253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/DocumentFragment.h" 43e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles)#include "core/dom/ElementTraversal.h" 4453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/ExceptionCode.h" 4553e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/NodeTraversal.h" 4653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/dom/Range.h" 4753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/Editor.h" 4853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/MarkupAccumulator.h" 4953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/TextIterator.h" 5053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/VisibleSelection.h" 5153e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/VisibleUnits.h" 5253e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/editing/htmlediting.h" 5353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLBodyElement.h" 5453e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLElement.h" 55e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "core/html/HTMLHtmlElement.h" 56e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch#include "core/html/HTMLTableElement.h" 5753e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/html/HTMLTextFormControlElement.h" 581e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles)#include "core/frame/Frame.h" 5953e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)#include "core/rendering/RenderObject.h" 6051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)#include "platform/weborigin/KURL.h" 61521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#include "wtf/StdLibExtras.h" 62521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles)#include "wtf/text/StringBuilder.h" 635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace std; 655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)namespace WebCore { 675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)using namespace HTMLNames; 695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool propertyMissingOrEqualToNone(StylePropertySet*, CSSPropertyID); 715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class AttributeChange { 735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)public: 745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AttributeChange() 755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : m_name(nullAtom, nullAtom, nullAtom) 765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) AttributeChange(PassRefPtr<Element> element, const QualifiedName& name, const String& value) 805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : m_element(element), m_name(name), m_value(value) 815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) void apply() 855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 86a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) m_element->setAttribute(m_name, AtomicString(m_value)); 875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)private: 905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Element> m_element; 915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) QualifiedName m_name; 925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String m_value; 935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)static void completeURLs(DocumentFragment& fragment, const String& baseURL) 965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Vector<AttributeChange> changes; 985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) KURL parsedBaseURL(ParsedURLString, baseURL); 1005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) for (Element* element = ElementTraversal::firstWithin(fragment); element; element = ElementTraversal::next(*element, &fragment)) { 102926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!element->hasAttributes()) 103926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) continue; 104926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) unsigned length = element->attributeCount(); 105926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) for (unsigned i = 0; i < length; i++) { 106926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) const Attribute* attribute = element->attributeItem(i); 107926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (element->isURLAttribute(*attribute) && !attribute->value().isEmpty()) 108926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) changes.append(AttributeChange(element, attribute->name(), KURL(parsedBaseURL, attribute->value()).string())); 1095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numChanges = changes.size(); 1135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < numChanges; ++i) 1145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) changes[i].apply(); 1155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 11602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 1175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)class StyledMarkupAccumulator : public MarkupAccumulator { 1185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)public: 1195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) enum RangeFullySelectsNode { DoesFullySelectNode, DoesNotFullySelectNode }; 1205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs, EAnnotateForInterchange, const Range*, Node* highestNodeToBeSerialized = 0); 1225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* serializeNodes(Node* startNode, Node* pastEnd); 1235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) virtual void appendString(const String& s) { return MarkupAccumulator::appendString(s); } 1245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) void wrapWithNode(Node*, bool convertBlocksToInlines = false, RangeFullySelectsNode = DoesFullySelectNode); 1255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) void wrapWithStyleNode(StylePropertySet*, Document*, bool isBlock = false); 1265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String takeResults(); 1275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)private: 1295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) void appendStyleNodeOpenTag(StringBuilder&, StylePropertySet*, Document*, bool isBlock = false); 1305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const String& styleNodeCloseTag(bool isBlock = false); 1315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) virtual void appendText(StringBuilder& out, Text*); 1325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String renderedText(const Node*, const Range*); 1335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String stringValueForRange(const Node*, const Range*); 1345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) void appendElement(StringBuilder& out, Element*, bool addDisplayInline, RangeFullySelectsNode); 1355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) void appendElement(StringBuilder& out, Element* element, Namespaces*) { appendElement(out, element, false, DoesFullySelectNode); } 1365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) enum NodeTraversalMode { EmitString, DoNotEmitString }; 1385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode); 1395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool shouldAnnotate() { return m_shouldAnnotate == AnnotateForInterchange; } 1415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool shouldApplyWrappingStyle(Node* node) const 1425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) { 1435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode() == node->parentNode() 1445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) && m_wrappingStyle && m_wrappingStyle->style(); 1455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 1465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Vector<String> m_reversedPrecedingMarkup; 1485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const EAnnotateForInterchange m_shouldAnnotate; 1495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* m_highestNodeToBeSerialized; 1505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<EditingStyle> m_wrappingStyle; 1515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)}; 1525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)inline StyledMarkupAccumulator::StyledMarkupAccumulator(Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, EAnnotateForInterchange shouldAnnotate, 1545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const Range* range, Node* highestNodeToBeSerialized) 1555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) : MarkupAccumulator(nodes, shouldResolveURLs, range) 1565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_shouldAnnotate(shouldAnnotate) 1575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) , m_highestNodeToBeSerialized(highestNodeToBeSerialized) 1585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void StyledMarkupAccumulator::wrapWithNode(Node* node, bool convertBlocksToInlines, RangeFullySelectsNode rangeFullySelectsNode) 1625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringBuilder markup; 1645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (node->isElementNode()) 165926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) appendElement(markup, toElement(node), convertBlocksToInlines && isBlock(const_cast<Node*>(node)), rangeFullySelectsNode); 1665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 1675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendStartMarkup(markup, node, 0); 1685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_reversedPrecedingMarkup.append(markup.toString()); 1695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendEndTag(node); 1705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_nodes) 1715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_nodes->append(node); 1725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void StyledMarkupAccumulator::wrapWithStyleNode(StylePropertySet* style, Document* document, bool isBlock) 1755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringBuilder openTag; 1775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendStyleNodeOpenTag(openTag, style, document, isBlock); 1785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_reversedPrecedingMarkup.append(openTag.toString()); 1795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendString(styleNodeCloseTag(isBlock)); 1805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void StyledMarkupAccumulator::appendStyleNodeOpenTag(StringBuilder& out, StylePropertySet* style, Document* document, bool isBlock) 1835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // wrappingStyleForSerialization should have removed -webkit-text-decorations-in-effect 1855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(propertyMissingOrEqualToNone(style, CSSPropertyWebkitTextDecorationsInEffect)); 1865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (isBlock) 1875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.appendLiteral("<div style=\""); 1885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 1895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.appendLiteral("<span style=\""); 1905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendAttributeValue(out, style->asText(), document->isHTMLDocument()); 1915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.append('\"'); 1925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.append('>'); 1935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)const String& StyledMarkupAccumulator::styleNodeCloseTag(bool isBlock) 1965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1973c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch DEFINE_STATIC_LOCAL(const String, divClose, ("</div>")); 1983c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch DEFINE_STATIC_LOCAL(const String, styleSpanClose, ("</span>")); 1995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return isBlock ? divClose : styleSpanClose; 2005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String StyledMarkupAccumulator::takeResults() 2035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringBuilder result; 2055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) result.reserveCapacity(totalLength(m_reversedPrecedingMarkup) + length()); 2065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = m_reversedPrecedingMarkup.size(); i > 0; --i) 2085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) result.append(m_reversedPrecedingMarkup[i - 1]); 2095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) concatenateMarkup(result); 2115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We remove '\0' characters because they are not visibly rendered to the user. 2135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return result.toString().replace(0, ""); 2145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void StyledMarkupAccumulator::appendText(StringBuilder& out, Text* text) 21702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch{ 2185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const bool parentIsTextarea = text->parentElement() && text->parentElement()->tagQName() == textareaTag; 2195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const bool wrappingSpan = shouldApplyWrappingStyle(text) && !parentIsTextarea; 2205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (wrappingSpan) { 2215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<EditingStyle> wrappingStyle = m_wrappingStyle->copy(); 2225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: <rdar://problem/5371536> Style rules that match pasted content can change it's appearance 2235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Make sure spans are inline style in paste side e.g. span { display: block }. 2245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wrappingStyle->forceInline(); 2255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: Should this be included in forceInline? 2265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wrappingStyle->style()->setProperty(CSSPropertyFloat, CSSValueNone); 2275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2288abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) appendStyleNodeOpenTag(out, wrappingStyle->style(), &text->document()); 2295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!shouldAnnotate() || parentIsTextarea) 2325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) MarkupAccumulator::appendText(out, text); 2335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else { 2345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const bool useRenderedText = !enclosingNodeWithTag(firstPositionInNode(text), selectTag); 2355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String content = useRenderedText ? renderedText(text, m_range) : stringValueForRange(text, m_range); 2365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringBuilder buffer; 2375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendCharactersReplacingEntities(buffer, content, 0, content.length(), EntityMaskInPCDATA); 2385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.append(convertHTMLTextToInterchangeFormat(buffer.toString(), text)); 2395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (wrappingSpan) 2425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.append(styleNodeCloseTag()); 2435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 24402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 2455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String StyledMarkupAccumulator::renderedText(const Node* node, const Range* range) 2465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!node->isTextNode()) 2485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return String(); 2495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2508abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) const Text* textNode = toText(node); 2515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned startOffset = 0; 2525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) unsigned endOffset = textNode->length(); 2535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 254926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (range && node == range->startContainer()) 255926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) startOffset = range->startOffset(); 256926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (range && node == range->endContainer()) 257926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) endOffset = range->endOffset(); 2585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Position start = createLegacyEditingPosition(const_cast<Node*>(node), startOffset); 2605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Position end = createLegacyEditingPosition(const_cast<Node*>(node), endOffset); 2615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return plainText(Range::create(node->document(), start, end).get()); 2625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String StyledMarkupAccumulator::stringValueForRange(const Node* node, const Range* range) 2655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!range) 2675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return node->nodeValue(); 2685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String str = node->nodeValue(); 270926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (node == range->endContainer()) 271926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) str.truncate(range->endOffset()); 272926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (node == range->startContainer()) 273926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) str.remove(0, range->startOffset()); 2745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return str; 2755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 2765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)void StyledMarkupAccumulator::appendElement(StringBuilder& out, Element* element, bool addDisplayInline, RangeFullySelectsNode rangeFullySelectsNode) 2785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 2798abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) const bool documentIsHTML = element->document().isHTMLDocument(); 2805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendOpenTag(out, element, 0); 2815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const unsigned length = element->hasAttributes() ? element->attributeCount() : 0; 2835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const bool shouldAnnotateOrForceInline = element->isHTMLElement() && (shouldAnnotate() || addDisplayInline); 2845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const bool shouldOverrideStyleAttr = shouldAnnotateOrForceInline || shouldApplyWrappingStyle(element); 285926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) for (unsigned i = 0; i < length; ++i) { 2865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const Attribute* attribute = element->attributeItem(i); 2875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We'll handle the style attribute separately, below. 2885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (attribute->name() == styleAttr && shouldOverrideStyleAttr) 2895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 2905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendAttribute(out, element, *attribute, 0); 2915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 2925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldOverrideStyleAttr) { 2945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<EditingStyle> newInlineStyle; 2955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 2965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldApplyWrappingStyle(element)) { 2975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) newInlineStyle = m_wrappingStyle->copy(); 2985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) newInlineStyle->removePropertiesInElementDefaultStyle(element); 2995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) newInlineStyle->removeStyleConflictingWithStyleOfNode(element); 3005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else 3015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) newInlineStyle = EditingStyle::create(); 3025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 303591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch if (element->isStyledElement() && element->inlineStyle()) 304591b958dee2cf159d33a0b931e6231072eaf38d5Ben Murdoch newInlineStyle->overrideWithStyle(element->inlineStyle()); 3055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldAnnotateOrForceInline) { 3075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldAnnotate()) 3085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) newInlineStyle->mergeStyleFromRulesForSerialization(toHTMLElement(element)); 3095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (addDisplayInline) 3115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) newInlineStyle->forceInline(); 3125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If the node is not fully selected by the range, then we don't want to keep styles that affect its relationship to the nodes around it 3145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // only the ones that affect it and the nodes within it. 3155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (rangeFullySelectsNode == DoesNotFullySelectNode && newInlineStyle->style()) 3165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) newInlineStyle->style()->removeProperty(CSSPropertyFloat); 3175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!newInlineStyle->isEmpty()) { 3205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.appendLiteral(" style=\""); 3215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendAttributeValue(out, newInlineStyle->style()->asText(), documentIsHTML); 3225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) out.append('\"'); 3235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendCloseTag(out, element); 3275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Node* StyledMarkupAccumulator::serializeNodes(Node* startNode, Node* pastEnd) 3305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!m_highestNodeToBeSerialized) { 3325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* lastClosed = traverseNodesForSerialization(startNode, pastEnd, DoNotEmitString); 3335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_highestNodeToBeSerialized = lastClosed; 3345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (m_highestNodeToBeSerialized && m_highestNodeToBeSerialized->parentNode()) 3375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) m_wrappingStyle = EditingStyle::wrappingStyleForSerialization(m_highestNodeToBeSerialized->parentNode(), shouldAnnotate()); 3385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return traverseNodesForSerialization(startNode, pastEnd, EmitString); 3405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 3415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)Node* StyledMarkupAccumulator::traverseNodesForSerialization(Node* startNode, Node* pastEnd, NodeTraversalMode traversalMode) 3435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 3445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const bool shouldEmit = traversalMode == EmitString; 3455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Vector<Node*> ancestorsToClose; 3465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* next; 3475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* lastClosed = 0; 3485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (Node* n = startNode; n != pastEnd; n = next) { 3495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // According to <rdar://problem/5730668>, it is possible for n to blow 3505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // past pastEnd and become null here. This shouldn't be possible. 3515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // This null check will prevent crashes (but create too much markup) 3525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // and the ASSERT will hopefully lead us to understanding the problem. 3535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(n); 3545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!n) 3555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 35602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 35751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) next = NodeTraversal::next(*n); 3585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool openedTag = false; 3595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (isBlock(n) && canHaveChildrenForEditing(n) && next == pastEnd) 3615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Don't write out empty block containers that aren't fully selected. 3625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 3635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!n->renderer() && !enclosingNodeWithTag(firstPositionInOrBeforeNode(n), selectTag)) { 36551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) next = NodeTraversal::nextSkippingChildren(*n); 3665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Don't skip over pastEnd. 3675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (pastEnd && pastEnd->isDescendantOf(n)) 3685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) next = pastEnd; 3695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 3705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Add the node to the markup if we're not skipping the descendants 3715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldEmit) 3725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendStartTag(n); 3735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If node has no children, close the tag now. 3755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!n->childNodeCount()) { 3765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldEmit) 3775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendEndTag(n); 3785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) lastClosed = n; 3795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 3805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) openedTag = true; 3815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ancestorsToClose.append(n); 3825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 3855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If we didn't insert open tag and there's no more siblings or we're at the end of the traversal, take care of ancestors. 3865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: What happens if we just inserted open tag and reached the end? 3875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!openedTag && (!n->nextSibling() || next == pastEnd)) { 3885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Close up the ancestors. 3895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) while (!ancestorsToClose.isEmpty()) { 3905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* ancestor = ancestorsToClose.last(); 3915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (next != pastEnd && next->isDescendantOf(ancestor)) 3925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 3935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Not at the end of the range, close ancestors up to sibling of next node. 3945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldEmit) 3955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) appendEndTag(ancestor); 3965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) lastClosed = ancestor; 3975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ancestorsToClose.removeLast(); 3985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 3995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Surround the currently accumulated markup with markup for ancestors we never opened as we leave the subtree(s) rooted at those ancestors. 4015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ContainerNode* nextParent = next ? next->parentNode() : 0; 4025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (next != pastEnd && n != nextParent) { 4035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* lastAncestorClosedOrSelf = n->isDescendantOf(lastClosed) ? lastClosed : n; 4045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (ContainerNode* parent = lastAncestorClosedOrSelf->parentNode(); parent && parent != nextParent; parent = parent->parentNode()) { 4055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // All ancestors that aren't in the ancestorsToClose list should either be a) unrendered: 4065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!parent->renderer()) 4075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 4085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // or b) ancestors that we never encountered during a pre-order traversal starting at startNode: 4095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(startNode->isDescendantOf(parent)); 4105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldEmit) 4115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) wrapWithNode(parent); 4125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) lastClosed = parent; 4135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return lastClosed; 4195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool isHTMLBlockElement(const Node* node) 4225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return node->hasTagName(tdTag) 4245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) || node->hasTagName(thTag) 4255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) || isNonTableCellHTMLBlockElement(node); 4265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static Node* ancestorToRetainStructureAndAppearanceForBlock(Node* commonAncestorBlock) 4295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!commonAncestorBlock) 4315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 4325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (commonAncestorBlock->hasTagName(tbodyTag) || commonAncestorBlock->hasTagName(trTag)) { 4345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ContainerNode* table = commonAncestorBlock->parentNode(); 435e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch while (table && !isHTMLTableElement(table)) 4365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) table = table->parentNode(); 4375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return table; 4395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 4405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (isNonTableCellHTMLBlockElement(commonAncestorBlock)) 4425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return commonAncestorBlock; 4435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 4455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline Node* ancestorToRetainStructureAndAppearance(Node* commonAncestor) 4485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return ancestorToRetainStructureAndAppearanceForBlock(enclosingBlock(commonAncestor)); 4505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline Node* ancestorToRetainStructureAndAppearanceWithNoRenderer(Node* commonAncestor) 4535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* commonAncestorBlock = enclosingNodeOfType(firstPositionInOrBeforeNode(commonAncestor), isHTMLBlockElement); 4555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return ancestorToRetainStructureAndAppearanceForBlock(commonAncestorBlock); 4565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool propertyMissingOrEqualToNone(StylePropertySet* style, CSSPropertyID propertyID) 4595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!style) 4615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 4625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<CSSValue> value = style->getPropertyCSSValue(propertyID); 4635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!value) 4645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 4655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!value->isPrimitiveValue()) 4665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 4673c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch return toCSSPrimitiveValue(value.get())->getValueID() == CSSValueNone; 4685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool needInterchangeNewlineAfter(const VisiblePosition& v) 4715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) VisiblePosition next = v.next(); 4735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* upstreamNode = next.deepEquivalent().upstream().deprecatedNode(); 4745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* downstreamNode = v.deepEquivalent().downstream().deprecatedNode(); 4755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Add an interchange newline if a paragraph break is selected and a br won't already be added to the markup to represent it. 4765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return isEndOfParagraph(v) && isStartOfParagraph(next) && !(upstreamNode->hasTagName(brTag) && upstreamNode == downstreamNode); 4775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static PassRefPtr<EditingStyle> styleFromMatchedRulesAndInlineDecl(const Node* node) 4805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!node->isHTMLElement()) 4825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 4835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: Having to const_cast here is ugly, but it is quite a bit of work to untangle 4855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // the non-const-ness of styleFromMatchedRulesForElement. 4868abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) HTMLElement* element = const_cast<HTMLElement*>(toHTMLElement(node)); 4875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<EditingStyle> style = EditingStyle::create(element->inlineStyle()); 4885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) style->mergeStyleFromRules(element); 4895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return style.release(); 4905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 4925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool isElementPresentational(const Node* node) 4935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 4945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return node->hasTagName(uTag) || node->hasTagName(sTag) || node->hasTagName(strikeTag) 4955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) || node->hasTagName(iTag) || node->hasTagName(emTag) || node->hasTagName(bTag) || node->hasTagName(strongTag); 4965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 4975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 49853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)static Node* highestAncestorToWrapMarkup(const Range* range, EAnnotateForInterchange shouldAnnotate, Node* constrainingAncestor) 4995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 5001fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch Node* commonAncestor = range->commonAncestorContainer(IGNORE_EXCEPTION); 5015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(commonAncestor); 5025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* specialCommonAncestor = 0; 5035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldAnnotate == AnnotateForInterchange) { 50402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch // Include ancestors that aren't completely inside the range but are required to retain 5055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // the structure and appearance of the copied markup. 5065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) specialCommonAncestor = ancestorToRetainStructureAndAppearance(commonAncestor); 5075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 508926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (Node* parentListNode = enclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isListItem)) { 509926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (WebCore::areRangesEqual(VisibleSelection::selectionFromContentsOfNode(parentListNode).toNormalizedRange().get(), range)) { 510926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) specialCommonAncestor = parentListNode->parentNode(); 511926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) while (specialCommonAncestor && !isListElement(specialCommonAncestor)) 512926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) specialCommonAncestor = specialCommonAncestor->parentNode(); 513926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 514926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) } 515926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 5165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Retain the Mail quote level by including all ancestor mail block quotes. 5175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (Node* highestMailBlockquote = highestEnclosingNodeOfType(firstPositionInOrBeforeNode(range->firstNode()), isMailBlockquote, CanCrossEditingBoundary)) 5185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) specialCommonAncestor = highestMailBlockquote; 5195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* checkAncestor = specialCommonAncestor ? specialCommonAncestor : commonAncestor; 5225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (checkAncestor->renderer()) { 52353e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) Node* newSpecialCommonAncestor = highestEnclosingNodeOfType(firstPositionInNode(checkAncestor), &isElementPresentational, CanCrossEditingBoundary, constrainingAncestor); 5245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (newSpecialCommonAncestor) 5255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) specialCommonAncestor = newSpecialCommonAncestor; 5265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If a single tab is selected, commonAncestor will be a text node inside a tab span. 5295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // If two or more tabs are selected, commonAncestor will be the tab span. 53002772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch // In either case, if there is a specialCommonAncestor already, it will necessarily be above 5315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // any tab span that needs to be included. 5325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!specialCommonAncestor && isTabSpanTextNode(commonAncestor)) 5335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) specialCommonAncestor = commonAncestor->parentNode(); 5345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!specialCommonAncestor && isTabSpanNode(commonAncestor)) 5355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) specialCommonAncestor = commonAncestor; 5365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (Node *enclosingAnchor = enclosingNodeWithTag(firstPositionInNode(specialCommonAncestor ? specialCommonAncestor : commonAncestor), aTag)) 5385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) specialCommonAncestor = enclosingAnchor; 5395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return specialCommonAncestor; 5415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 5425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 54302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch// FIXME: Shouldn't we omit style info when annotate == DoNotAnnotateForInterchange? 5445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)// FIXME: At least, annotation and style info should probably not be included in range.markupString() 5458abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)static String createMarkupInternal(Document& document, const Range* range, const Range* updatedRange, Vector<Node*>* nodes, 54653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs, Node* constrainingAncestor) 5475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 548926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) ASSERT(range); 549926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) ASSERT(updatedRange); 5503c9e4aeaee9f9b0a9a814da07bcb33319c7ea363Ben Murdoch DEFINE_STATIC_LOCAL(const String, interchangeNewlineString, ("<br class=\"" AppleInterchangeNewline "\">")); 5515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5521fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch bool collapsed = updatedRange->collapsed(ASSERT_NO_EXCEPTION); 5535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (collapsed) 554926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return emptyString(); 5551fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch Node* commonAncestor = updatedRange->commonAncestorContainer(ASSERT_NO_EXCEPTION); 5565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!commonAncestor) 557926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return emptyString(); 5585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5598abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) document.updateLayoutIgnorePendingStylesheets(); 5605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* body = enclosingNodeWithTag(firstPositionInNode(commonAncestor), bodyTag); 5625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* fullySelectedRoot = 0; 5635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: Do this for all fully selected blocks, not just the body. 5645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (body && areRangesEqual(VisibleSelection::selectionFromContentsOfNode(body).toNormalizedRange().get(), range)) 5655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fullySelectedRoot = body; 56653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) Node* specialCommonAncestor = highestAncestorToWrapMarkup(updatedRange, shouldAnnotate, constrainingAncestor); 567926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) StyledMarkupAccumulator accumulator(nodes, shouldResolveURLs, shouldAnnotate, updatedRange, specialCommonAncestor); 5685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* pastEnd = updatedRange->pastLastNode(); 5695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* startNode = updatedRange->firstNode(); 5715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) VisiblePosition visibleStart(updatedRange->startPosition(), VP_DEFAULT_AFFINITY); 5725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) VisiblePosition visibleEnd(updatedRange->endPosition(), VP_DEFAULT_AFFINITY); 5735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleStart)) { 574926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (visibleStart == visibleEnd.previous()) 5755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return interchangeNewlineString; 5765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) accumulator.appendString(interchangeNewlineString); 5785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) startNode = visibleStart.next().deepEquivalent().deprecatedNode(); 5795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5801fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch if (pastEnd && Range::compareBoundaryPoints(startNode, 0, pastEnd, 0, ASSERT_NO_EXCEPTION) >= 0) 5815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return interchangeNewlineString; 5825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 5835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* lastClosed = accumulator.serializeNodes(startNode, pastEnd); 5855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (specialCommonAncestor && lastClosed) { 5875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Also include all of the ancestors of lastClosed up to this special ancestor. 5885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (ContainerNode* ancestor = lastClosed->parentNode(); ancestor; ancestor = ancestor->parentNode()) { 5895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (ancestor == fullySelectedRoot && !convertBlocksToInlines) { 5905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<EditingStyle> fullySelectedRootStyle = styleFromMatchedRulesAndInlineDecl(fullySelectedRoot); 5915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Bring the background attribute over, but not as an attribute because a background attribute on a div 5935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // appears to have no effect. 5945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if ((!fullySelectedRootStyle || !fullySelectedRootStyle->style() || !fullySelectedRootStyle->style()->getPropertyCSSValue(CSSPropertyBackgroundImage)) 595926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) && toElement(fullySelectedRoot)->hasAttribute(backgroundAttr)) 596926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) fullySelectedRootStyle->style()->setProperty(CSSPropertyBackgroundImage, "url('" + toElement(fullySelectedRoot)->getAttribute(backgroundAttr) + "')"); 5975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 5985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (fullySelectedRootStyle->style()) { 5995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Reset the CSS properties to avoid an assertion error in addStyleMarkup(). 6005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // This assertion is caused at least when we select all text of a <body> element whose 6015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // 'text-decoration' property is "inherit", and copy it. 6025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyTextDecoration)) 6035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fullySelectedRootStyle->style()->setProperty(CSSPropertyTextDecoration, CSSValueNone); 6045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!propertyMissingOrEqualToNone(fullySelectedRootStyle->style(), CSSPropertyWebkitTextDecorationsInEffect)) 6055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fullySelectedRootStyle->style()->setProperty(CSSPropertyWebkitTextDecorationsInEffect, CSSValueNone); 6068abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) accumulator.wrapWithStyleNode(fullySelectedRootStyle->style(), &document, true); 6075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 6095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Since this node and all the other ancestors are not in the selection we want to set RangeFullySelectsNode to DoesNotFullySelectNode 6105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // so that styles that affect the exterior of the node are not included. 6115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) accumulator.wrapWithNode(ancestor, convertBlocksToInlines, StyledMarkupAccumulator::DoesNotFullySelectNode); 6125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (nodes) 6145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) nodes->append(ancestor); 61502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 6165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) lastClosed = ancestor; 61702772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 6185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (ancestor == specialCommonAncestor) 6195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 6205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: The interchange newline should be placed in the block that it's in, not after all of the content, unconditionally. 6245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (shouldAnnotate == AnnotateForInterchange && needInterchangeNewlineAfter(visibleEnd.previous())) 6255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) accumulator.appendString(interchangeNewlineString); 6265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return accumulator.takeResults(); 6285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 63053e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles)String createMarkup(const Range* range, Vector<Node*>* nodes, EAnnotateForInterchange shouldAnnotate, bool convertBlocksToInlines, EAbsoluteURLs shouldResolveURLs, Node* constrainingAncestor) 631926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles){ 632926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!range) 633926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) return emptyString(); 634926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 6358abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) Document& document = range->ownerDocument(); 636926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) const Range* updatedRange = range; 637926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 63853e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) return createMarkupInternal(document, range, updatedRange, nodes, shouldAnnotate, convertBlocksToInlines, shouldResolveURLs, constrainingAncestor); 639926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles)} 640926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 6418abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)PassRefPtr<DocumentFragment> createFragmentFromMarkup(Document& document, const String& markup, const String& baseURL, ParserContentPolicy parserContentPolicy) 6425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We use a fake body element here to trick the HTML parser to using the InBody insertion mode. 6445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(document); 6455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<DocumentFragment> fragment = DocumentFragment::create(document); 646926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 647926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) fragment->parseHTML(markup, fakeBody.get(), parserContentPolicy); 6485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6498abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if (!baseURL.isEmpty() && baseURL != blankURL() && baseURL != document.baseURL()) 65051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) completeURLs(*fragment, baseURL); 6515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 6535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static const char fragmentMarkerTag[] = "webkit-fragment-marker"; 6565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static bool findNodesSurroundingContext(Document* document, RefPtr<Node>& nodeBeforeContext, RefPtr<Node>& nodeAfterContext) 6585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 65951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) for (Node* node = document->firstChild(); node; node = NodeTraversal::next(*node)) { 6608abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if (node->nodeType() == Node::COMMENT_NODE && toCharacterData(node)->data() == fragmentMarkerTag) { 6615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!nodeBeforeContext) 6625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) nodeBeforeContext = node; 6635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else { 6645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) nodeAfterContext = node; 6655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 6665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 6705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void trimFragment(DocumentFragment* fragment, Node* nodeBeforeContext, Node* nodeAfterContext) 6735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Node> next; 6755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (RefPtr<Node> node = fragment->firstChild(); node; node = next) { 6765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (nodeBeforeContext->isDescendantOf(node.get())) { 67751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) next = NodeTraversal::next(*node); 6785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) continue; 6795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 68051b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) next = NodeTraversal::nextSkippingChildren(*node); 6815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(!node->contains(nodeAfterContext)); 6821fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION); 6835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (nodeBeforeContext == node) 6845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) break; 6855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(nodeAfterContext->parentNode()); 6885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (RefPtr<Node> node = nodeAfterContext; node; node = next) { 68951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) next = NodeTraversal::nextSkippingChildren(*node); 6901fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch node->parentNode()->removeChild(node.get(), ASSERT_NO_EXCEPTION); 6915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 6925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 6935c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6948abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)PassRefPtr<DocumentFragment> createFragmentFromMarkupWithContext(Document& document, const String& markup, unsigned fragmentStart, unsigned fragmentEnd, 695926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) const String& baseURL, ParserContentPolicy parserContentPolicy) 6965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 6975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: Need to handle the case where the markup already contains these markers. 6985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 6995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringBuilder taggedMarkup; 7005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) taggedMarkup.append(markup.left(fragmentStart)); 7015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) MarkupAccumulator::appendComment(taggedMarkup, fragmentMarkerTag); 7025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) taggedMarkup.append(markup.substring(fragmentStart, fragmentEnd - fragmentStart)); 7035c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) MarkupAccumulator::appendComment(taggedMarkup, fragmentMarkerTag); 7045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) taggedMarkup.append(markup.substring(fragmentEnd)); 7055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 706926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) RefPtr<DocumentFragment> taggedFragment = createFragmentFromMarkup(document, taggedMarkup.toString(), baseURL, parserContentPolicy); 707e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch RefPtr<Document> taggedDocument = Document::create(); 7088abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) taggedDocument->setContextFeatures(document.contextFeatures()); 7091e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) 7101e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) // FIXME: It's not clear what this code is trying to do. It puts nodes as direct children of a 7111e202183a5dc46166763171984b285173f8585e5Torne (Richard Coles) // Document that are not normally allowed by using the parser machinery. 71219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) taggedDocument->parserTakeAllChildrenFrom(*taggedFragment); 7135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Node> nodeBeforeContext; 7155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Node> nodeAfterContext; 7165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!findNodesSurroundingContext(taggedDocument.get(), nodeBeforeContext, nodeAfterContext)) 7175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 7185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7198abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) RefPtr<Range> range = Range::create(*taggedDocument.get(), 7205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) positionAfterNode(nodeBeforeContext.get()).parentAnchoredEquivalent(), 7215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) positionBeforeNode(nodeAfterContext.get()).parentAnchoredEquivalent()); 7225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7231fad5ca6c42d689812b66fc493992aa6d747a6fbBen Murdoch Node* commonAncestor = range->commonAncestorContainer(ASSERT_NO_EXCEPTION); 7245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* specialCommonAncestor = ancestorToRetainStructureAndAppearanceWithNoRenderer(commonAncestor); 7255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // When there's a special common ancestor outside of the fragment, we must include it as well to 7275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // preserve the structure and appearance of the fragment. For example, if the fragment contains 7285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // TD, we need to include the enclosing TABLE tag as well. 7295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<DocumentFragment> fragment = DocumentFragment::create(document); 730926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (specialCommonAncestor) 731e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) fragment->appendChild(specialCommonAncestor); 732926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) else 73319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) fragment->parserTakeAllChildrenFrom(toContainerNode(*commonAncestor)); 7345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) trimFragment(fragment.get(), nodeBeforeContext.get(), nodeAfterContext.get()); 7365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment; 7385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String createMarkup(const Node* node, EChildrenOnly childrenOnly, Vector<Node*>* nodes, EAbsoluteURLs shouldResolveURLs, Vector<QualifiedName>* tagNamesToSkip) 7415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!node) 7435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return ""; 7445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) MarkupAccumulator accumulator(nodes, shouldResolveURLs); 74653e740f4a82e17f3ae59772501622dc354e42336Torne (Richard Coles) return accumulator.serializeNodes(const_cast<Node*>(node), childrenOnly, tagNamesToSkip); 7475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static void fillContainerFromString(ContainerNode* paragraph, const String& string) 7505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 7518abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) Document& document = paragraph->document(); 7525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (string.isEmpty()) { 754e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) paragraph->appendChild(createBlockPlaceholderElement(document)); 7555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 7565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 75806f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) ASSERT(string.find('\n') == kNotFound); 7595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Vector<String> tabList; 7615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) string.split('\t', true, tabList); 7625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String tabText = emptyString(); 7635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool first = true; 7645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numEntries = tabList.size(); 7655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < numEntries; ++i) { 7665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const String& s = tabList[i]; 7675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // append the non-tab textual part 7695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!s.isEmpty()) { 7705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!tabText.isEmpty()) { 771e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) paragraph->appendChild(createTabSpanElement(document, tabText)); 7725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) tabText = emptyString(); 7735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7748abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) RefPtr<Node> textNode = document.createTextNode(stringWithRebalancedWhitespace(s, first, i + 1 == numEntries)); 775e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) paragraph->appendChild(textNode.release()); 7765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // there is a tab after every entry, except the last entry 7795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // (if the last character is a tab, the list gets an extra empty entry) 7805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (i + 1 != numEntries) 7815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) tabText.append('\t'); 782926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) else if (!tabText.isEmpty()) 783e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) paragraph->appendChild(createTabSpanElement(document, tabText)); 784926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) 7855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) first = false; 7865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 7875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 7895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)bool isPlainTextMarkup(Node *node) 7905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 791926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) if (!node->isElementNode() || !node->hasTagName(divTag) || toElement(node)->hasAttributes()) 7925c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return false; 79302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 7945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (node->childNodeCount() == 1 && (node->firstChild()->isTextNode() || (node->firstChild()->firstChild()))) 7955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return true; 79602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 7975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return (node->childNodeCount() == 2 && isTabSpanTextNode(node->firstChild()->firstChild()) && node->firstChild()->nextSibling()->isTextNode()); 7985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 7995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 80023e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdochstatic bool shouldPreserveNewline(const Range& range) 80123e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch{ 80223e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch if (Node* node = range.firstNode()) { 80323e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch if (RenderObject* renderer = node->renderer()) 80423e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch return renderer->style()->preserveNewline(); 80523e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch } 80623e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch 80723e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch if (Node* node = range.startPosition().anchorNode()) { 80823e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch if (RenderObject* renderer = node->renderer()) 80923e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch return renderer->style()->preserveNewline(); 81023e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch } 81123e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch 81223e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch return false; 81323e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch} 81423e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch 8155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassRefPtr<DocumentFragment> createFragmentFromText(Range* context, const String& text) 8165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 8175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!context) 8185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 8195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8208abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) Document& document = context->ownerDocument(); 8218abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) RefPtr<DocumentFragment> fragment = document.createDocumentFragment(); 82202772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 8235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (text.isEmpty()) 8245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 8255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String string = text; 8275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) string.replace("\r\n", "\n"); 8285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) string.replace('\r', '\n'); 8295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 83023e46e0f045bc1935a09565578b448d36cfc5b8cBen Murdoch if (shouldPreserveNewline(*context)) { 8318abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) fragment->appendChild(document.createTextNode(string)); 8325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (string.endsWith('\n')) { 8335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Element> element = createBreakElement(document); 83402772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch element->setAttribute(classAttr, AppleInterchangeNewline); 835e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) fragment->appendChild(element.release()); 8365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 8385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // A string with no newlines gets added inline, rather than being put into a paragraph. 84106f816c7c76bc45a15e452ade8a34e8af077693eTorne (Richard Coles) if (string.find('\n') == kNotFound) { 8425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fillContainerFromString(fragment.get(), string); 8435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 8445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8455c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Break string into paragraphs. Extra line breaks turn into empty paragraphs. 8475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* blockNode = enclosingBlock(context->firstNode()); 848926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) Element* block = toElement(blockNode); 8495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool useClonesOfEnclosingBlock = blockNode 8505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) && blockNode->isElementNode() 8515c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) && !block->hasTagName(bodyTag) 852e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch && !isHTMLHtmlElement(block) 8535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) && block != editableRootForPosition(context->startPosition()); 8545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool useLineBreak = enclosingTextFormControl(context->startPosition()); 8555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Vector<String> list; 8575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) string.split('\n', true, list); // true gets us empty strings in the list 8585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t numLines = list.size(); 8595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < numLines; ++i) { 8605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) const String& s = list[i]; 8615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Element> element; 8635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (s.isEmpty() && i + 1 == numLines) { 8645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // For last line, use the "magic BR" rather than a P. 8655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) element = createBreakElement(document); 8665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) element->setAttribute(classAttr, AppleInterchangeNewline); 8675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else if (useLineBreak) { 8685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) element = createBreakElement(document); 8695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fillContainerFromString(fragment.get(), s); 8705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } else { 8715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (useClonesOfEnclosingBlock) 8725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) element = block->cloneElementWithoutChildren(); 8735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) else 8745c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) element = createDefaultParagraphElement(document); 8755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fillContainerFromString(element.get(), s); 8765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 877e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) fragment->appendChild(element.release()); 8785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 8805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 8815c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)PassRefPtr<DocumentFragment> createFragmentFromNodes(Document *document, const Vector<Node*>& nodes) 8835c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 8845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!document) 8855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 8865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<DocumentFragment> fragment = document->createDocumentFragment(); 8885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) size_t size = nodes.size(); 8905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (size_t i = 0; i < size; ++i) { 8918abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) RefPtr<Element> element = createDefaultParagraphElement(*document); 892e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) element->appendChild(nodes[i]); 893e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) fragment->appendChild(element.release()); 8945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 8955c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 8975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 8985c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 8995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String createFullMarkup(const Node* node) 9005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9015c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!node) 9025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return String(); 90302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 9048abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) Frame* frame = node->document().frame(); 9055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!frame) 9065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return String(); 9075c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 90802772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch // FIXME: This is never "for interchange". Is that right? 9095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) String markupString = createMarkup(node, IncludeNode, 0); 9105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node::NodeType nodeType = node->nodeType(); 9115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (nodeType != Node::DOCUMENT_NODE && nodeType != Node::DOCUMENT_TYPE_NODE) 9125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) markupString = frame->documentTypeString() + markupString; 9135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return markupString; 9155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String createFullMarkup(const Range* range) 9185c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9195c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!range) 9205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return String(); 9215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) Node* node = range->startContainer(); 9235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!node) 9245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return String(); 92502772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 9268abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) Frame* frame = node->document().frame(); 9275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!frame) 9285c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return String(); 9295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9305c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: This is always "for interchange". Is that right? See the previous method. 93102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch return frame->documentTypeString() + createMarkup(range, 0, AnnotateForInterchange); 9325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9335c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)String urlToMarkup(const KURL& url, const String& title) 9355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) StringBuilder markup; 9375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) markup.append("<a href=\""); 9385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) markup.append(url.string()); 9395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) markup.append("\">"); 9405c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) MarkupAccumulator::appendCharactersReplacingEntities(markup, title, 0, title.length(), EntityMaskInPCDATA); 9415c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) markup.append("</a>"); 9425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return markup.toString(); 9435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 94551b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)PassRefPtr<DocumentFragment> createFragmentForInnerOuterHTML(const String& markup, Element* contextElement, ParserContentPolicy parserContentPolicy, const char* method, ExceptionState& exceptionState) 9465c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9478abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) Document& document = contextElement->hasTagName(templateTag) ? contextElement->document().ensureTemplateDocument() : contextElement->document(); 9485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<DocumentFragment> fragment = DocumentFragment::create(document); 9495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9508abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) if (document.isHTMLDocument()) { 951926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) fragment->parseHTML(markup, contextElement, parserContentPolicy); 9525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment; 9535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 9545c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 955926b001d589ce2f10facb93dd4b87578ea35a855Torne (Richard Coles) bool wasValid = fragment->parseXML(markup, contextElement, parserContentPolicy); 9565c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!wasValid) { 957a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) exceptionState.throwDOMException(SyntaxError, "The provided markup is invalid XML, and therefore cannot be inserted into an XML document."); 9585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 9595c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 9605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 9615c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9625c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9638abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles)PassRefPtr<DocumentFragment> createFragmentForTransformToFragment(const String& sourceString, const String& sourceMIMEType, Document& outputDoc) 9645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9658abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) RefPtr<DocumentFragment> fragment = outputDoc.createDocumentFragment(); 96602772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 9675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (sourceMIMEType == "text/html") { 9685c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // As far as I can tell, there isn't a spec for how transformToFragment is supposed to work. 9695c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Based on the documentation I can find, it looks like we want to start parsing the fragment in the InBody insertion mode. 9705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // Unfortunately, that's an implementation detail of the parser. 9715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We achieve that effect here by passing in a fake body element as context for the fragment. 9725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<HTMLBodyElement> fakeBody = HTMLBodyElement::create(outputDoc); 9735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fragment->parseHTML(sourceString, fakeBody.get()); 9748abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) } else if (sourceMIMEType == "text/plain") { 9755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) fragment->parserAppendChild(Text::create(outputDoc, sourceString)); 9768abfc5808a4e34d6e03867af8bc440dee641886fTorne (Richard Coles) } else { 9775c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) bool successfulParse = fragment->parseXML(sourceString, 0); 9785c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!successfulParse) 9795c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 9805c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 98102772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 9825c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // FIXME: Do we need to mess with URLs here? 98302772c6a72f1ee0b226341a4f4439970c29fc861Ben Murdoch 9845c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 9855c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9865c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 9875c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)static inline void removeElementPreservingChildren(PassRefPtr<DocumentFragment> fragment, HTMLElement* element) 9885c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 9895c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Node> nextChild; 9905c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (RefPtr<Node> child = element->firstChild(); child; child = nextChild) { 9915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) nextChild = child->nextSibling(); 992e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) element->removeChild(child.get()); 993e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) fragment->insertBefore(child, element); 9945c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 995e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) fragment->removeChild(element); 9965c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 9975c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 99851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)PassRefPtr<DocumentFragment> createContextualFragment(const String& markup, HTMLElement* element, ParserContentPolicy parserContentPolicy, ExceptionState& exceptionState) 9995c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 10005c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) ASSERT(element); 1001f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) if (element->ieForbidsInsertHTML() || element->hasLocalName(colTag) || element->hasLocalName(colgroupTag) || element->hasLocalName(framesetTag) 10025c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) || element->hasLocalName(headTag) || element->hasLocalName(styleTag) || element->hasLocalName(titleTag)) { 1003a854de003a23bf3c7f95ec0f8154ada64092ff5cTorne (Richard Coles) exceptionState.throwDOMException(NotSupportedError, "The range's container is '" + element->localName() + "', which is not supported."); 10045c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 10055c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10065c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 100751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) RefPtr<DocumentFragment> fragment = createFragmentForInnerOuterHTML(markup, element, parserContentPolicy, "createContextualFragment", exceptionState); 10085c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!fragment) 10095c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return 0; 10105c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10115c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // We need to pop <html> and <body> elements and remove <head> to 10125c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // accommodate folks passing complete HTML documents to make the 10135c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) // child of an element. 10145c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10155c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Node> nextNode; 10165c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) for (RefPtr<Node> node = fragment->firstChild(); node; node = nextNode) { 10175c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) nextNode = node->nextSibling(); 1018e69819bd8e388ea4ad1636a19aa6b2eed4952191Ben Murdoch if (isHTMLHtmlElement(node.get()) || node->hasTagName(headTag) || node->hasTagName(bodyTag)) { 1019f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) HTMLElement* element = toHTMLElement(node); 10205c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (Node* firstChild = element->firstChild()) 10215c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) nextNode = firstChild; 10225c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) removeElementPreservingChildren(fragment, element); 10235c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10245c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10255c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return fragment.release(); 10265c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 10275c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 102851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void replaceChildrenWithFragment(ContainerNode* container, PassRefPtr<DocumentFragment> fragment, ExceptionState& exceptionState) 10295c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1030f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) ASSERT(container); 10315c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<ContainerNode> containerNode(container); 10325c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1033f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) ChildListMutationScope mutation(*containerNode); 10345c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10355c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) if (!fragment->firstChild()) { 10365c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) containerNode->removeChildren(); 10375c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 10385c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10395c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1040e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if (containerNode->hasOneTextChild() && fragment->hasOneTextChild()) { 1041521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) toText(containerNode->firstChild())->setData(toText(fragment->firstChild())->data()); 10425c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 10435c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10445c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1045e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if (containerNode->hasOneChild()) { 104651b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) containerNode->replaceChild(fragment, containerNode->firstChild(), exceptionState); 10475c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 10485c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10495c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10505c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) containerNode->removeChildren(); 105151b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) containerNode->appendChild(fragment, exceptionState); 10525c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 10535c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 105451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void replaceChildrenWithText(ContainerNode* container, const String& text, ExceptionState& exceptionState) 10555c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles){ 1056f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) ASSERT(container); 10575c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<ContainerNode> containerNode(container); 10585c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1059f79f16f17ddc4f842d7b7a38603e280e94be826aTorne (Richard Coles) ChildListMutationScope mutation(*containerNode); 10605c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1061e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if (containerNode->hasOneTextChild()) { 1062521d96ec04ace82590870fb04353ec4f82bb150fTorne (Richard Coles) toText(containerNode->firstChild())->setData(text); 10635c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 10645c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10655c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10665c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) RefPtr<Text> textNode = Text::create(containerNode->document(), text); 10675c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 1068e1f1df5f01594c0e62e751e4b46e779b85c2faa5Torne (Richard Coles) if (containerNode->hasOneChild()) { 106951b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) containerNode->replaceChild(textNode.release(), containerNode->firstChild(), exceptionState); 10705c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) return; 10715c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) } 10725c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 10735c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) containerNode->removeChildren(); 107451b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) containerNode->appendChild(textNode.release(), exceptionState); 10755c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 10765c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles) 107751b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles)void mergeWithNextTextNode(PassRefPtr<Node> node, ExceptionState& exceptionState) 107819cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles){ 107919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) ASSERT(node && node->isTextNode()); 108019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) Node* next = node->nextSibling(); 108119cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) if (!next || !next->isTextNode()) 108219cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) return; 108319cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) 108419cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) RefPtr<Text> textNode = toText(node.get()); 108519cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) RefPtr<Text> textNext = toText(next); 108619cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) textNode->appendData(textNext->data()); 108719cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) if (textNext->parentNode()) // Might have been removed by mutation event. 108851b2906e11752df6c18351cf520e30522d3b53a1Torne (Richard Coles) textNext->remove(exceptionState); 108919cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles)} 109019cde67944066db31e633d9e386f2aa9bf9fadb3Torne (Richard Coles) 10915c87bf8b86a7c82ef50fb7a89697d8e02e2553beTorne (Richard Coles)} 1092