Commit e95b53db authored by darin@apple.com's avatar darin@apple.com

2008-12-23 Darin Adler <darin@apple.com>

        Reviewed by John Sullivan.

        - improve robustness of undo/redo in HTML editing to fix the following bugs
          <https://bugs.webkit.org/show_bug.cgi?id=19703> Crash in WebCore::InsertNodeBeforeCommand::doUnapply()
          <rdar://problem/4059423> DOM operations performed on editable HTML can cause a crash later during Undo

        Major categories of improvements:

            1) Added null checks.
            2) Eliminated type casts without corresponding type checks.
            3) Avoided possible infinite loops by building up lists of nodes to operate on
               before starting to make DOM changes.
            4) Use more RefPtr.

        No test at this time, but test cases should follow in separate patches.

        * WebCore.xcodeproj/project.pbxproj: Set the role of CSSPropertyNames.h to Private so it
        can be used in other Private headers, specifically editing ones.

        * css/CSSStyleSelector.cpp:
        (WebCore::CSSStyleSelector::locateCousinList): Adopt parentElement.
        (WebCore::CSSStyleSelector::locateSharedStyle): Ditto.
        (WebCore::CSSStyleSelector::SelectorChecker::checkOneSelector): Ditto.

        * dom/Element.cpp: (WebCore::Element::cloneElement): Added.
        * dom/Element.h: Added cloneElement and an implementation of parentElement.
        * dom/Node.h: Moved parentElement from here to Element.h and changed its
        implementation so it will return 0 when the parent is not an element
        (document, document fragment, etc.).

        * editing/AppendNodeCommand.cpp:
        (WebCore::AppendNodeCommand::AppendNodeCommand): Made parent be an Element.
        Moved assertions from doApply in here.
        (WebCore::AppendNodeCommand::doApply): Simplified to just a single unchecked
        appendChild call.
        (WebCore::AppendNodeCommand::doUnapply): Simplified to just a single remove call.
        * editing/AppendNodeCommand.h: Updated.

        * editing/ApplyStyleCommand.cpp:
        (WebCore::createStyleSpanElement): Eliminate casting by creating an element in a more
        direct way with new instead of createElementNS.
        (WebCore::ApplyStyleCommand::ApplyStyleCommand): Use PassRefPtr.
        (WebCore::ApplyStyleCommand::removeCSSStyle): Use CSSPropertyID.
        (WebCore::ApplyStyleCommand::addInlineStyleIfNeeded): Use cloneElement.
        * editing/ApplyStyleCommand.h:

        * editing/BreakBlockquoteCommand.cpp:
        (WebCore::BreakBlockquoteCommand::doApply): Use Element* and cloneElement.

        * editing/CompositeEditCommand.cpp:
        (WebCore::CompositeEditCommand::applyStyledElement): Use PassRefPtr and unsigned.
        (WebCore::CompositeEditCommand::removeStyledElement): Ditto.
        (WebCore::CompositeEditCommand::insertNodeBefore): Ditto.
        (WebCore::CompositeEditCommand::insertNodeAfter): Ditto.
        (WebCore::CompositeEditCommand::insertNodeAt): Ditto.
        (WebCore::CompositeEditCommand::appendNode): Ditto.
        (WebCore::CompositeEditCommand::removeChildrenInRange): Ditto. Also use a vector to
        make the list of children in case removing them has side effects.
        (WebCore::CompositeEditCommand::removeNode): Ditto.
        (WebCore::CompositeEditCommand::removeNodePreservingChildren): Ditto.
        (WebCore::CompositeEditCommand::removeNodeAndPruneAncestors): Ditto.
        (WebCore::CompositeEditCommand::splitTextNode): Ditto.
        (WebCore::CompositeEditCommand::splitElement): Ditto.
        (WebCore::CompositeEditCommand::mergeIdenticalElements): Ditto.
        (WebCore::CompositeEditCommand::wrapContentsInDummySpan): Ditto.
        (WebCore::CompositeEditCommand::splitTextNodeContainingElement): Ditto.
        (WebCore::CompositeEditCommand::joinTextNodes): Ditto.
        (WebCore::CompositeEditCommand::inputText): Ditto.
        (WebCore::CompositeEditCommand::insertTextIntoNode): Ditto.
        (WebCore::CompositeEditCommand::deleteTextFromNode): Ditto.
        (WebCore::CompositeEditCommand::replaceTextInNode): Ditto.
        (WebCore::CompositeEditCommand::insertNodeAtTabSpanPosition): Ditto.
        (WebCore::CompositeEditCommand::removeCSSProperty): Ditto.
        (WebCore::CompositeEditCommand::removeNodeAttribute): Ditto. Implement by calling
        setNodeAttribute instead of with its own SimpleEditCommand.
        (WebCore::CompositeEditCommand::setNodeAttribute): Ditto.
        (WebCore::CompositeEditCommand::deleteInsignificantText): Ditto.
        (WebCore::CompositeEditCommand::appendBlockPlaceholder): Ditto.
        (WebCore::CompositeEditCommand::addBlockPlaceholderIfNeeded): Ditto.
        (WebCore::CompositeEditCommand::insertNewDefaultParagraphElementAt): Ditto. Don't
        bother using an undoable operation to put the break element into the paragraph
        element because there's no need to split them and redo this when doing undo/redo.
        (WebCore::CompositeEditCommand::moveParagraphs): Ditto.
        (WebCore::CompositeEditCommand::breakOutOfEmptyListItem): Ditto.
        * editing/CompositeEditCommand.h: Ditto.

        * editing/DeleteFromTextNodeCommand.cpp:
        (WebCore::DeleteFromTextNodeCommand::DeleteFromTextNodeCommand): Use unsigned.
        (WebCore::DeleteFromTextNodeCommand::doApply): Eliminated inappropriate assertions.
        (WebCore::DeleteFromTextNodeCommand::doUnapply): Ditto.
        * editing/DeleteFromTextNodeCommand.h:

        * editing/DeleteSelectionCommand.cpp:
        (WebCore::DeleteSelectionCommand::removeNode): Use PassRefPtr.
        (WebCore::DeleteSelectionCommand::deleteTextFromNode): Ditto.
        * editing/DeleteSelectionCommand.h:

        * editing/FormatBlockCommand.cpp:
        (WebCore::FormatBlockCommand::FormatBlockCommand): Use AtomicString.
        (WebCore::FormatBlockCommand::doApply): Use Element.
        * editing/FormatBlockCommand.h:

        * editing/IndentOutdentCommand.cpp:
        (WebCore::createIndentBlockquoteElement): Use new to create the element
        instead of calling a function so we have a more specific type.
        (WebCore::IndentOutdentCommand::prepareBlockquoteLevelForInsertion):
        Use RefPtr and Element.
        (WebCore::IndentOutdentCommand::indentRegion): Ditto.
        (WebCore::IndentOutdentCommand::outdentParagraph): Ditto.
        * editing/IndentOutdentCommand.h:

        * editing/InsertIntoTextNodeCommand.cpp:
        (WebCore::InsertIntoTextNodeCommand::InsertIntoTextNodeCommand):
        Use unsigned. Added an assertion.
        (WebCore::InsertIntoTextNodeCommand::doApply): Eliminated inappropriate assertions.
        (WebCore::InsertIntoTextNodeCommand::doUnapply): Ditto.
        * editing/InsertIntoTextNodeCommand.h:

        * editing/InsertLineBreakCommand.cpp:
        (WebCore::InsertLineBreakCommand::insertNodeAfterPosition): Use Element.
        (WebCore::InsertLineBreakCommand::insertNodeBeforePosition): Ditto.

        * editing/InsertListCommand.cpp:
        (WebCore::InsertListCommand::doApply): Use Element.

        * editing/InsertNodeBeforeCommand.cpp:
        (WebCore::InsertNodeBeforeCommand::InsertNodeBeforeCommand): Moved assertions
        here from doApply.
        (WebCore::InsertNodeBeforeCommand::doApply): Eliminated inappropriate assertions.
        Added a null check.
        (WebCore::InsertNodeBeforeCommand::doUnapply): Simplified to just a single remove call.

        * editing/InsertParagraphSeparatorCommand.cpp:
        (WebCore::InsertParagraphSeparatorCommand::doApply): Use Element and cloneElement.

        * editing/JoinTextNodesCommand.cpp:
        (WebCore::JoinTextNodesCommand::doApply): Eliminated inappropriate assertions.
        Added some runtime checks. Don't store anything in m_offset.
        (WebCore::JoinTextNodesCommand::doUnapply): Ditto.
        * editing/JoinTextNodesCommand.h:

        * editing/MergeIdenticalElementsCommand.cpp:
        (WebCore::MergeIdenticalElementsCommand::MergeIdenticalElementsCommand): Moved
        an assertion here from doApply.
        (WebCore::MergeIdenticalElementsCommand::doApply): Eliminated inappropriate assertions.
        Added a null check. Changed implementation to use remove to avoid null parent issue.
        Use a vector of nodes to avoid possible infinite loop if mutation happens while iterating.
        (WebCore::MergeIdenticalElementsCommand::doUnapply): Ditto.

        * editing/ModifySelectionListLevel.cpp:
        (WebCore::ModifySelectionListLevelCommand::appendSiblingNodeRange): Use Element*.
        (WebCore::IncreaseSelectionListLevelCommand::doApply): Ditto.
        * editing/ModifySelectionListLevel.h:

        * editing/RemoveCSSPropertyCommand.cpp:
        (WebCore::RemoveCSSPropertyCommand::RemoveCSSPropertyCommand): Use PassRefPtr and
        CSSPropertyID. Also renamed m_decl to m_style.
        (WebCore::RemoveCSSPropertyCommand::doApply): Eliminated inappropriate assertions.
        (WebCore::RemoveCSSPropertyCommand::doUnapply): Ditto.

        * editing/RemoveNodeAttributeCommand.cpp: Removed contents of this file. To be deleted.
        Use SetNodeAttributeCommand instead.
        * editing/RemoveNodeAttributeCommand.h: Ditto.

        * editing/RemoveNodeCommand.cpp:
        (WebCore::RemoveNodeCommand::RemoveNodeCommand): Moved assertions here from doApply.
        Don't initialize m_refChild here; rather do it in doApply.
        (WebCore::RemoveNodeCommand::doApply): Eliminated inappropriate assertions. Added
        checks and streamlined implementation.
        (WebCore::RemoveNodeCommand::doUnapply): Ditto.
        * editing/RemoveNodeCommand.h:

        * editing/RemoveNodePreservingChildrenCommand.cpp:
        (WebCore::RemoveNodePreservingChildrenCommand::doApply): Use a vector.

        * editing/ReplaceSelectionCommand.cpp:
        (WebCore::ReplacementFragment::insertFragmentForTestRendering): Removed now-unneeded cast.

        * editing/SetNodeAttributeCommand.cpp:
        (WebCore::SetNodeAttributeCommand::SetNodeAttributeCommand): Use AtomicString.
        Removed assertion that prevents us from using this to remove an attribute.
        (WebCore::SetNodeAttributeCommand::doApply): Eliminated inappropriate assertions.
        (WebCore::SetNodeAttributeCommand::doUnapply): Ditto.
        * editing/SetNodeAttributeCommand.h:

        * editing/SplitElementCommand.cpp:
        (WebCore::SplitElementCommand::SplitElementCommand): Moved assertion here from doApply.
        (WebCore::SplitElementCommand::doApply): Check some more invariants and use a vector
        to avoid possible infinite loops.
        (WebCore::SplitElementCommand::doUnapply): Ditto.

        * editing/SplitTextNodeCommand.cpp:
        (WebCore::SplitTextNodeCommand::SplitTextNodeCommand): Moved assertions and comment
        here from doApply.
        (WebCore::SplitTextNodeCommand::doApply): Check for null and failures when applying.
        (WebCore::SplitTextNodeCommand::doUnapply): Ditto.

        * editing/SplitTextNodeContainingElementCommand.cpp:
        (WebCore::SplitTextNodeContainingElementCommand::doApply): Use Element.

        * editing/WrapContentsInDummySpanCommand.cpp:
        (WebCore::WrapContentsInDummySpanCommand::doApply): Check for null and ignore failures.
        Don't reuse the dummy span. Simplified logic.
        (WebCore::WrapContentsInDummySpanCommand::doUnapply): Ditto.

        * editing/htmlediting.cpp:
        (WebCore::isBlock): Make sure this returns true only for elements.
        (WebCore::enclosingBlock): Return an Element*.
        (WebCore::enclosingTableCell): Ditto.
        (WebCore::enclosingList): Return an HTMLElement*.
        (WebCore::outermostEnclosingList): Return an HTMLElement*.
        (WebCore::createDefaultParagraphElement): Return an HTMLElement*.
        (WebCore::createBreakElement): Return an HTMLElement*.
        (WebCore::createOrderedListElement): Return an HTMLElement*.
        (WebCore::createUnorderedListElement): Return an HTMLElement*.
        (WebCore::createListItemElement): Return an HTMLElement*.
        (WebCore::createHTMLElement): Return an HTMLElement*.
        * editing/htmlediting.h:

        * editing/markup.cpp:
        (WebCore::createFragmentFromText): Use createBreakElement and use Element*.

        * page/MouseEventWithHitTestResults.cpp:
        (WebCore::MouseEventWithHitTestResults::targetNode): Use parentElement.



git-svn-id: http://svn.webkit.org/repository/webkit/trunk@39456 268f45cc-cd09-0410-ab3c-d52691b4dbfc
parent 3ca73cb1
This diff is collapsed.
......@@ -799,7 +799,7 @@
6550B6A6099DF0270090D781 /* Text.h in Headers */ = {isa = PBXBuildFile; fileRef = 6550B69C099DF0270090D781 /* Text.h */; settings = {ATTRIBUTES = (Private, ); }; };
65653F2D0D9727D200CA9723 /* SVGAltGlyphElement.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65653F2A0D9727D200CA9723 /* SVGAltGlyphElement.cpp */; };
65653F2E0D9727D200CA9723 /* SVGAltGlyphElement.h in Headers */ = {isa = PBXBuildFile; fileRef = 65653F2B0D9727D200CA9723 /* SVGAltGlyphElement.h */; };
656580F409D12B20000E61D7 /* CSSPropertyNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 656580EF09D12B20000E61D7 /* CSSPropertyNames.h */; };
656580F409D12B20000E61D7 /* CSSPropertyNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 656580EF09D12B20000E61D7 /* CSSPropertyNames.h */; settings = {ATTRIBUTES = (Private, ); }; };
6565815109D13043000E61D7 /* CSSValueKeywords.h in Headers */ = {isa = PBXBuildFile; fileRef = 6565814809D13043000E61D7 /* CSSValueKeywords.h */; };
656581B209D14EE6000E61D7 /* UserAgentStyleSheets.h in Headers */ = {isa = PBXBuildFile; fileRef = 656581AE09D14EE6000E61D7 /* UserAgentStyleSheets.h */; };
656581FE09D1508D000E61D7 /* SVGElementFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 656581E709D1508D000E61D7 /* SVGElementFactory.h */; };
This diff is collapsed.
......@@ -99,6 +99,11 @@ PassRefPtr<Node> Element::cloneNode(bool deep)
return clone.release();
}
PassRefPtr<Element> Element::cloneElement()
{
return static_pointer_cast<Element>(cloneNode(false));
}
void Element::removeAttribute(const QualifiedName& name, ExceptionCode& ec)
{
if (namedAttrMap) {
......
......@@ -116,6 +116,8 @@ public:
virtual void removedFromDocument();
virtual void childrenChanged(bool changedByParser = false, Node* beforeChange = 0, Node* afterChange = 0, int childCountDelta = 0);
PassRefPtr<Element> cloneElement();
void normalizeAttributes();
virtual bool isInputTypeHidden() const { return false; }
......@@ -237,6 +239,12 @@ inline NamedAttrMap* Node::attributes() const
return isElementNode() ? static_cast<const Element*>(this)->attributes() : 0;
}
inline Element* Node::parentElement() const
{
Node* parent = parentNode();
return parent && parent->isElementNode() ? static_cast<Element*>(parent) : 0;
}
} //namespace
#endif
......@@ -108,7 +108,7 @@ public:
virtual void setNodeValue(const String&, ExceptionCode&);
virtual NodeType nodeType() const = 0;
Node* parentNode() const { return parent(); }
Node* parentElement() const { return parent(); } // IE extension
Element* parentElement() const;
Node* previousSibling() const { return m_previous; }
Node* nextSibling() const { return m_next; }
virtual PassRefPtr<NodeList> childNodes();
......
......@@ -25,39 +25,33 @@
#include "config.h"
#include "AppendNodeCommand.h"
#include "htmlediting.h"
namespace WebCore {
AppendNodeCommand::AppendNodeCommand(PassRefPtr<Node> parentNode, PassRefPtr<Node> childToAppend)
: SimpleEditCommand(parentNode->document()), m_parentNode(parentNode), m_childToAppend(childToAppend)
AppendNodeCommand::AppendNodeCommand(PassRefPtr<Element> parent, PassRefPtr<Node> node)
: SimpleEditCommand(parent->document())
, m_parent(parent)
, m_node(node)
{
ASSERT(m_childToAppend);
ASSERT(m_parentNode);
ASSERT(m_parent);
ASSERT(m_node);
ASSERT(!m_node->parent());
ASSERT(enclosingNodeOfType(Position(m_parent.get(), 0), isContentEditable) || !m_parent->attached());
}
void AppendNodeCommand::doApply()
{
ASSERT(m_childToAppend);
ASSERT(m_parentNode);
// If the child to append is already in a tree, appending it will remove it from it's old location
// in an non-undoable way. We might eventually find it useful to do an undoable remove in this case.
ASSERT(!m_childToAppend->parent());
ASSERT(enclosingNodeOfType(Position(m_parentNode.get(), 0), &isContentEditable) || !m_parentNode->attached());
ExceptionCode ec = 0;
m_parentNode->appendChild(m_childToAppend.get(), ec);
ASSERT(ec == 0);
ExceptionCode ec;
m_parent->appendChild(m_node.get(), ec);
}
void AppendNodeCommand::doUnapply()
{
ASSERT(m_childToAppend);
ASSERT(m_parentNode);
ExceptionCode ec = 0;
m_parentNode->removeChild(m_childToAppend.get(), ec);
ASSERT(ec == 0);
ExceptionCode ec;
m_node->remove(ec);
}
} // namespace WebCore
......@@ -32,19 +32,19 @@ namespace WebCore {
class AppendNodeCommand : public SimpleEditCommand {
public:
static PassRefPtr<AppendNodeCommand> create(PassRefPtr<Node> parentNode, PassRefPtr<Node> childToAppend)
static PassRefPtr<AppendNodeCommand> create(PassRefPtr<Element> parent, PassRefPtr<Node> node)
{
return adoptRef(new AppendNodeCommand(parentNode, childToAppend));
return adoptRef(new AppendNodeCommand(parent, node));
}
private:
AppendNodeCommand(PassRefPtr<Node> parentNode, PassRefPtr<Node> childToAppend);
AppendNodeCommand(PassRefPtr<Element> parent, PassRefPtr<Node> node);
virtual void doApply();
virtual void doUnapply();
RefPtr<Node> m_parentNode;
RefPtr<Node> m_childToAppend;
RefPtr<Element> m_parent;
RefPtr<Node> m_node;
};
} // namespace WebCore
......
......@@ -274,11 +274,9 @@ static PassRefPtr<Element> createFontElement(Document* document)
PassRefPtr<HTMLElement> createStyleSpanElement(Document* document)
{
ExceptionCode ec = 0;
RefPtr<Element> styleElement = document->createElementNS(xhtmlNamespaceURI, "span", ec);
ASSERT(ec == 0);
RefPtr<HTMLElement> styleElement = new HTMLElement(spanTag, document);
styleElement->setAttribute(classAttr, styleSpanClassString());
return static_pointer_cast<HTMLElement>(styleElement.release());
return styleElement.release();
}
ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* style, EditAction editingAction, EPropertyLevel propertyLevel)
......@@ -307,7 +305,7 @@ ApplyStyleCommand::ApplyStyleCommand(Document* document, CSSStyleDeclaration* st
{
}
ApplyStyleCommand::ApplyStyleCommand(Element* element, bool removeOnly, EditAction editingAction)
ApplyStyleCommand::ApplyStyleCommand(PassRefPtr<Element> element, bool removeOnly, EditAction editingAction)
: CompositeEditCommand(element->document())
, m_style(CSSMutableStyleDeclaration::create())
, m_editingAction(editingAction)
......@@ -995,7 +993,7 @@ void ApplyStyleCommand::removeCSSStyle(CSSMutableStyleDeclaration *style, HTMLEl
CSSMutableStyleDeclaration::const_iterator end = style->end();
for (CSSMutableStyleDeclaration::const_iterator it = style->begin(); it != end; ++it) {
int propertyID = (*it).id();
CSSPropertyID propertyID = static_cast<CSSPropertyID>((*it).id());
RefPtr<CSSValue> value = decl->getPropertyCSSValue(propertyID);
if (value && (propertyID != CSSPropertyWhiteSpace || !isTabSpanNode(elem))) {
removeCSSProperty(decl, propertyID);
......@@ -1553,7 +1551,7 @@ void ApplyStyleCommand::addInlineStyleIfNeeded(CSSMutableStyleDeclaration *style
}
if (m_styledInlineElement) {
RefPtr<Element> clonedElement = static_pointer_cast<Element>(m_styledInlineElement->cloneNode(false));
RefPtr<Element> clonedElement = m_styledInlineElement->cloneElement();
insertNodeBefore(clonedElement.get(), startNode);
surroundNodeRangeWithElement(startNode, endNode, clonedElement.get());
}
......
......@@ -46,7 +46,7 @@ public:
{
return adoptRef(new ApplyStyleCommand(document, style, start, end, action, level));
}
static PassRefPtr<ApplyStyleCommand> create(Element* element, bool removeOnly = false, EditAction action = EditActionChangeAttributes)
static PassRefPtr<ApplyStyleCommand> create(PassRefPtr<Element> element, bool removeOnly = false, EditAction action = EditActionChangeAttributes)
{
return adoptRef(new ApplyStyleCommand(element, removeOnly, action));
}
......@@ -54,7 +54,7 @@ public:
private:
ApplyStyleCommand(Document*, CSSStyleDeclaration*, EditAction, EPropertyLevel);
ApplyStyleCommand(Document*, CSSStyleDeclaration*, const Position& start, const Position& end, EditAction, EPropertyLevel);
ApplyStyleCommand(Element*, bool removeOnly, EditAction);
ApplyStyleCommand(PassRefPtr<Element>, bool removeOnly, EditAction);
virtual void doApply();
virtual EditAction editingAction() const;
......
......@@ -59,10 +59,10 @@ void BreakBlockquoteCommand::doApply()
// startNode is the first node that we need to move to the new blockquote.
Node* startNode = pos.node();
// Find the top-most blockquote from the start.
Node* topBlockquote = 0;
Element* topBlockquote = 0;
for (Node *node = startNode->parentNode(); node; node = node->parentNode()) {
if (isMailBlockquote(node))
topBlockquote = node;
topBlockquote = static_cast<Element*>(node);
}
if (!topBlockquote || !topBlockquote->parentNode())
return;
......@@ -102,21 +102,21 @@ void BreakBlockquoteCommand::doApply()
}
// Build up list of ancestors in between the start node and the top blockquote.
Vector<Node*> ancestors;
for (Node* node = startNode->parentNode(); node != topBlockquote; node = node->parentNode())
Vector<Element*> ancestors;
for (Element* node = startNode->parentElement(); node && node != topBlockquote; node = node->parentElement())
ancestors.append(node);
// Insert a clone of the top blockquote after the break.
RefPtr<Node> clonedBlockquote = topBlockquote->cloneNode(false);
RefPtr<Element> clonedBlockquote = topBlockquote->cloneElement();
insertNodeAfter(clonedBlockquote.get(), breakNode.get());
// Clone startNode's ancestors into the cloned blockquote.
// On exiting this loop, clonedAncestor is the lowest ancestor
// that was cloned (i.e. the clone of either ancestors.last()
// or clonedBlockquote if ancestors is empty).
RefPtr<Node> clonedAncestor = clonedBlockquote;
RefPtr<Element> clonedAncestor = clonedBlockquote;
for (size_t i = ancestors.size(); i != 0; --i) {
RefPtr<Node> clonedChild = ancestors[i - 1]->cloneNode(false); // shallow clone
RefPtr<Element> clonedChild = ancestors[i - 1]->cloneElement(); // shallow clone
// Preserve list item numbering in cloned lists.
if (clonedChild->isElementNode() && clonedChild->hasTagName(olTag)) {
Node* listChildNode = i > 1 ? ancestors[i - 2] : startNode;
......@@ -149,11 +149,11 @@ void BreakBlockquoteCommand::doApply()
// Throughout this loop, clonedParent is the clone of ancestor's parent.
// This is so we can clone ancestor's siblings and place the clones
// into the clone corresponding to the ancestor's parent.
Node* ancestor;
Node* clonedParent;
for (ancestor = ancestors.first(), clonedParent = clonedAncestor->parentNode();
Element* ancestor;
Element* clonedParent;
for (ancestor = ancestors.first(), clonedParent = clonedAncestor->parentElement();
ancestor && ancestor != topBlockquote;
ancestor = ancestor->parentNode(), clonedParent = clonedParent->parentNode()) {
ancestor = ancestor->parentElement(), clonedParent = clonedParent->parentElement()) {
moveNode = ancestor->nextSibling();
while (moveNode) {
Node *next = moveNode->nextSibling();
......
This diff is collapsed.
......@@ -27,6 +27,7 @@
#define CompositeEditCommand_h
#include "EditCommand.h"
#include "CSSPropertyNames.h"
#include <wtf/Vector.h>
namespace WebCore {
......@@ -44,50 +45,50 @@ protected:
//
// sugary-sweet convenience functions to help create and apply edit commands in composite commands
//
void appendNode(Node* appendChild, Node* parentNode);
void appendNode(PassRefPtr<Node>, PassRefPtr<Element> parent);
void applyCommandToComposite(PassRefPtr<EditCommand>);
void applyStyle(CSSStyleDeclaration*, EditAction = EditActionChangeAttributes);
void applyStyle(CSSStyleDeclaration*, const Position& start, const Position& end, EditAction = EditActionChangeAttributes);
void applyStyledElement(Element*);
void removeStyledElement(Element*);
void applyStyledElement(PassRefPtr<Element>);
void removeStyledElement(PassRefPtr<Element>);
void deleteSelection(bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = true);
void deleteSelection(const Selection&, bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = true);
virtual void deleteTextFromNode(Text* node, int offset, int count);
virtual void deleteTextFromNode(PassRefPtr<Text>, unsigned offset, unsigned count);
void inputText(const String&, bool selectInsertedText = false);
void insertNodeAfter(Node* insertChild, Node* refChild);
void insertNodeAt(Node* insertChild, const Position&);
void insertNodeBefore(Node* insertChild, Node* refChild);
void insertNodeAfter(PassRefPtr<Node>, PassRefPtr<Node> refChild);
void insertNodeAt(PassRefPtr<Node>, const Position&);
void insertNodeAtTabSpanPosition(PassRefPtr<Node>, const Position&);
void insertNodeBefore(PassRefPtr<Node>, PassRefPtr<Node> refChild);
void insertParagraphSeparator(bool useDefaultParagraphElement = false);
void insertLineBreak();
void insertTextIntoNode(Text* node, int offset, const String& text);
void joinTextNodes(Text*, Text*);
void insertTextIntoNode(PassRefPtr<Text>, unsigned offset, const String& text);
void joinTextNodes(PassRefPtr<Text>, PassRefPtr<Text>);
void mergeIdenticalElements(PassRefPtr<Element>, PassRefPtr<Element>);
void rebalanceWhitespace();
void rebalanceWhitespaceAt(const Position&);
void prepareWhitespaceAtPositionForSplit(Position& position);
void removeCSSProperty(CSSStyleDeclaration*, int property);
void removeNodeAttribute(Element*, const QualifiedName& attribute);
void removeChildrenInRange(Node*, int from, int to);
virtual void removeNode(Node*);
void removeNodePreservingChildren(Node*);
void removeNodeAndPruneAncestors(Node*);
void prepareWhitespaceAtPositionForSplit(Position&);
void removeCSSProperty(PassRefPtr<CSSMutableStyleDeclaration>, CSSPropertyID);
void removeNodeAttribute(PassRefPtr<Element>, const QualifiedName& attribute);
void removeChildrenInRange(PassRefPtr<Node>, unsigned from, unsigned to);
virtual void removeNode(PassRefPtr<Node>);
void removeNodePreservingChildren(PassRefPtr<Node>);
void removeNodeAndPruneAncestors(PassRefPtr<Node>);
void prune(PassRefPtr<Node>);
void replaceTextInNode(Text* node, int offset, int count, const String& replacementText);
void replaceTextInNode(PassRefPtr<Text>, unsigned offset, unsigned count, const String& replacementText);
Position positionOutsideTabSpan(const Position&);
void insertNodeAtTabSpanPosition(Node*, const Position&);
void setNodeAttribute(Element*, const QualifiedName& attribute, const String& value);
void splitTextNode(Text*, int offset);
void splitElement(Element*, Node* atChild);
void mergeIdenticalElements(Element*, Element*);
void wrapContentsInDummySpan(Element*);
void splitTextNodeContainingElement(Text*, int offset);
void setNodeAttribute(PassRefPtr<Element>, const QualifiedName& attribute, const AtomicString& value);
void splitElement(PassRefPtr<Element>, PassRefPtr<Node> atChild);
void splitTextNode(PassRefPtr<Text>, unsigned offset);
void splitTextNodeContainingElement(PassRefPtr<Text>, unsigned offset);
void wrapContentsInDummySpan(PassRefPtr<Element>);
void deleteInsignificantText(Text*, int start, int end);
void deleteInsignificantText(PassRefPtr<Text>, unsigned start, unsigned end);
void deleteInsignificantText(const Position& start, const Position& end);
void deleteInsignificantTextDownstream(const Position&);
PassRefPtr<Node> appendBlockPlaceholder(Node*);
PassRefPtr<Node> appendBlockPlaceholder(PassRefPtr<Element>);
PassRefPtr<Node> insertBlockPlaceholder(const Position&);
PassRefPtr<Node> addBlockPlaceholderIfNeeded(Node*);
PassRefPtr<Node> addBlockPlaceholderIfNeeded(Element*);
void removePlaceholderAt(const VisiblePosition&);
PassRefPtr<Node> insertNewDefaultParagraphElementAt(const Position&);
......
......@@ -30,13 +30,15 @@
namespace WebCore {
DeleteFromTextNodeCommand::DeleteFromTextNodeCommand(PassRefPtr<Text> node, int offset, int count)
: SimpleEditCommand(node->document()), m_node(node), m_offset(offset), m_count(count)
DeleteFromTextNodeCommand::DeleteFromTextNodeCommand(PassRefPtr<Text> node, unsigned offset, unsigned count)
: SimpleEditCommand(node->document())
, m_node(node)
, m_offset(offset)
, m_count(count)
{
ASSERT(m_node);
ASSERT(m_offset >= 0);
ASSERT(m_offset < (int)m_node->length());
ASSERT(m_count >= 0);
ASSERT(m_offset <= m_node->length());
ASSERT(m_offset + m_count <= m_node->length());
}
void DeleteFromTextNodeCommand::doApply()
......@@ -45,20 +47,18 @@ void DeleteFromTextNodeCommand::doApply()
ExceptionCode ec = 0;
m_text = m_node->substringData(m_offset, m_count, ec);
ASSERT(ec == 0);
if (ec)
return;
m_node->deleteData(m_offset, m_count, ec);
ASSERT(ec == 0);
}
void DeleteFromTextNodeCommand::doUnapply()
{
ASSERT(m_node);
ASSERT(!m_text.isEmpty());
ExceptionCode ec = 0;
ExceptionCode ec;
m_node->insertData(m_offset, m_text, ec);
ASSERT(ec == 0);
}
} // namespace WebCore
......@@ -34,20 +34,20 @@ class Text;
class DeleteFromTextNodeCommand : public SimpleEditCommand {
public:
static PassRefPtr<DeleteFromTextNodeCommand> create(PassRefPtr<Text> node, int offset, int count)
static PassRefPtr<DeleteFromTextNodeCommand> create(PassRefPtr<Text> node, unsigned offset, unsigned count)
{
return adoptRef(new DeleteFromTextNodeCommand(node, offset, count));
}
private:
DeleteFromTextNodeCommand(PassRefPtr<Text>, int offset, int count);
DeleteFromTextNodeCommand(PassRefPtr<Text>, unsigned offset, unsigned count);
virtual void doApply();
virtual void doUnapply();
RefPtr<Text> m_node;
int m_offset;
int m_count;
unsigned m_offset;
unsigned m_count;
String m_text;
};
......
......@@ -317,7 +317,7 @@ static void updatePositionForNodeRemoval(Node* node, Position& position)
position = positionBeforeNode(node);
}
void DeleteSelectionCommand::removeNode(Node *node)
void DeleteSelectionCommand::removeNode(PassRefPtr<Node> node)
{
if (!node)
return;
......@@ -344,12 +344,12 @@ void DeleteSelectionCommand::removeNode(Node *node)
}
}
if (isTableStructureNode(node) || node == node->rootEditableElement()) {
if (isTableStructureNode(node.get()) || node == node->rootEditableElement()) {
// Do not remove an element of table structure; remove its contents.
// Likewise for the root editable element.
Node *child = node->firstChild();
Node* child = node->firstChild();
while (child) {
Node *remove = child;
Node* remove = child;
child = child->nextSibling();
removeNode(remove);
}
......@@ -368,9 +368,9 @@ void DeleteSelectionCommand::removeNode(Node *node)
m_needPlaceholder = true;
// FIXME: Update the endpoints of the range being deleted.
updatePositionForNodeRemoval(node, m_endingPosition);
updatePositionForNodeRemoval(node, m_leadingWhitespace);
updatePositionForNodeRemoval(node, m_trailingWhitespace);
updatePositionForNodeRemoval(node.get(), m_endingPosition);
updatePositionForNodeRemoval(node.get(), m_leadingWhitespace);
updatePositionForNodeRemoval(node.get(), m_trailingWhitespace);
CompositeEditCommand::removeNode(node);
}
......@@ -386,12 +386,12 @@ void updatePositionForTextRemoval(Node* node, int offset, int count, Position& p
}
}
void DeleteSelectionCommand::deleteTextFromNode(Text *node, int offset, int count)
void DeleteSelectionCommand::deleteTextFromNode(PassRefPtr<Text> node, unsigned offset, unsigned count)
{
// FIXME: Update the endpoints of the range being deleted.
updatePositionForTextRemoval(node, offset, count, m_endingPosition);
updatePositionForTextRemoval(node, offset, count, m_leadingWhitespace);
updatePositionForTextRemoval(node, offset, count, m_trailingWhitespace);
updatePositionForTextRemoval(node.get(), offset, count, m_endingPosition);
updatePositionForTextRemoval(node.get(), offset, count, m_leadingWhitespace);
updatePositionForTextRemoval(node.get(), offset, count, m_trailingWhitespace);
CompositeEditCommand::deleteTextFromNode(node, offset, count);
}
......
......@@ -62,8 +62,8 @@ private:
void calculateEndingPosition();
void calculateTypingStyleAfterDelete();
void clearTransientState();
virtual void removeNode(Node*);
virtual void deleteTextFromNode(Text*, int, int);
virtual void removeNode(PassRefPtr<Node>);
virtual void deleteTextFromNode(PassRefPtr<Text>, unsigned, unsigned);
bool m_hasSelectionToDelete;
bool m_smartDelete;
......
......@@ -36,7 +36,7 @@ namespace WebCore {
using namespace HTMLNames;
FormatBlockCommand::FormatBlockCommand(Document* document, const String& tagName)
FormatBlockCommand::FormatBlockCommand(Document* document, const AtomicString& tagName)
: CompositeEditCommand(document), m_tagName(tagName)
{
}
......@@ -107,21 +107,21 @@ void FormatBlockCommand::doApply()
VisiblePosition paragraphEnd = endOfParagraph(endingSelection().visibleStart());
VisiblePosition blockStart = startOfBlock(endingSelection().visibleStart());
VisiblePosition blockEnd = endOfBlock(endingSelection().visibleStart());
RefPtr<Node> blockNode = createElement(document(), m_tagName);
RefPtr<Node> placeholder = createBreakElement(document());
RefPtr<Element> blockNode = createHTMLElement(document(), m_tagName);
RefPtr<Element> placeholder = createBreakElement(document());
Node* root = endingSelection().start().node()->rootEditableElement();
if (validBlockTag(refNode->nodeName().lower()) &&
paragraphStart == blockStart && paragraphEnd == blockEnd &&
refNode != root && !root->isDescendantOf(refNode))
// Already in a valid block tag that only contains the current paragraph, so we can swap with the new tag
insertNodeBefore(blockNode.get(), refNode);
insertNodeBefore(blockNode, refNode);
else {
// Avoid inserting inside inline elements that surround paragraphStart with upstream().
// This is only to avoid creating bloated markup.
insertNodeAt(blockNode.get(), paragraphStart.deepEquivalent().upstream());
insertNodeAt(blockNode, paragraphStart.deepEquivalent().upstream());
}
appendNode(placeholder.get(), blockNode.get());
appendNode(placeholder, blockNode);
VisiblePosition destination(Position(placeholder.get(), 0));
if (paragraphStart == paragraphEnd && !lineBreakExistsAtPosition(paragraphStart)) {
......
......@@ -32,19 +32,19 @@ namespace WebCore {
class FormatBlockCommand : public CompositeEditCommand {
public:
static PassRefPtr<FormatBlockCommand> create(Document* document, const String& tagName)
static PassRefPtr<FormatBlockCommand> create(Document* document, const AtomicString& tagName)
{
return adoptRef(new FormatBlockCommand(document, tagName));
}
private:
FormatBlockCommand(Document*, const String& tagName);
FormatBlockCommand(Document*, const AtomicString& tagName);
virtual void doApply();
virtual EditAction editingAction() const { return EditActionFormatBlock; }
bool modifyRange();
String m_tagName;
AtomicString m_tagName;
};
} // namespace WebCore
......
This diff is collapsed.
......@@ -49,7 +49,7 @@ private:
void indentRegion();
void outdentRegion();
void outdentParagraph();
Node* prepareBlockquoteLevelForInsertion(VisiblePosition&, Node**);
PassRefPtr<Element> prepareBlockquoteLevelForInsertion(VisiblePosition&, RefPtr<Element>&);
EIndentType m_typeOfAction;
int m_marginInPixels;
......
......@@ -30,29 +30,27 @@
namespace WebCore {
InsertIntoTextNodeCommand::InsertIntoTextNodeCommand(PassRefPtr<Text> node, int offset, const String& text)
InsertIntoTextNodeCommand::InsertIntoTextNodeCommand(PassRefPtr<Text> node, unsigned offset, const String& text)
: SimpleEditCommand(node->document())
, m_node(node)
, m_offset(offset)
, m_text(text)
{
ASSERT(m_node);
ASSERT(offset >= 0);
ASSERT(!text.isEmpty());
ASSERT(m_offset <= m_node->length());
ASSERT(!m_text.isEmpty());
}
void InsertIntoTextNodeCommand::doApply()
{
ExceptionCode ec = 0;
ExceptionCode ec;
m_node->insertData(m_offset, m_text, ec);
ASSERT(ec == 0);
}
void InsertIntoTextNodeCommand::doUnapply()
{
ExceptionCode ec = 0;
ExceptionCode ec;
m_node->deleteData(m_offset, m_text.length(), ec);
ASSERT(ec == 0);
}
} // namespace WebCore
......@@ -34,19 +34,19 @@ class Text;
class InsertIntoTextNodeCommand : public SimpleEditCommand {
public:
static PassRefPtr<InsertIntoTextNodeCommand> create(PassRefPtr<Text> node, int offset, const String& text)
static PassRefPtr<InsertIntoTextNodeCommand> create(PassRefPtr<Text> node, unsigned offset, const String& text)
{
return adoptRef(new InsertIntoTextNodeCommand(node, offset, text));
}
private:
InsertIntoTextNodeCommand(PassRefPtr<Text> node, int offset, const String& text);
InsertIntoTextNodeCommand(PassRefPtr<Text> node, unsigned offset, const String& text);
virtual void doApply();
virtual void doUnapply();
RefPtr<Text> m_node;
int m_offset;
unsigned m_offset;
String m_text;
};
......
<
......@@ -51,24 +51,24 @@ bool InsertLineBreakCommand::preservesTypingStyle() const
return true;
}
void InsertLineBreakCommand::insertNodeAfterPosition(Node *node, const Position &pos)
void InsertLineBreakCommand::insertNodeAfterPosition(Node* node, const Position& pos)
{
// Insert the BR after the caret position. In the case the