1/*
2 * Copyright (C) 2005, 2006, 2008 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "AXObjectCache.h"
29#include "EditCommand.h"
30#include "CSSPropertyNames.h"
31#include "UndoStep.h"
32#include <wtf/Vector.h>
33
34namespace WebCore {
35
36class EditingStyle;
37class DataTransfer;
38class HTMLElement;
39class StaticRange;
40class StyledElement;
41class Text;
42
43class AccessibilityUndoReplacedText {
44public:
45 AccessibilityUndoReplacedText() { }
46 void configureRangeDeletedByReapplyWithStartingSelection(const VisibleSelection&);
47 void configureRangeDeletedByReapplyWithEndingSelection(const VisibleSelection&);
48 void setRangeDeletedByUnapply(const VisiblePositionIndexRange&);
49
50 void captureTextForUnapply();
51 void captureTextForReapply();
52
53 void postTextStateChangeNotificationForUnapply(AXObjectCache*);
54 void postTextStateChangeNotificationForReapply(AXObjectCache*);
55
56private:
57 int indexForVisiblePosition(const VisiblePosition&, RefPtr<ContainerNode>&) const;
58 String textDeletedByUnapply();
59 String textDeletedByReapply();
60
61 String m_replacedText;
62 VisiblePositionIndexRange m_rangeDeletedByUnapply;
63 VisiblePositionIndexRange m_rangeDeletedByReapply;
64};
65
66class EditCommandComposition : public UndoStep {
67public:
68 static Ref<EditCommandComposition> create(Document&, const VisibleSelection& startingSelection, const VisibleSelection& endingSelection, EditAction);
69
70 void unapply() override;
71 void reapply() override;
72 EditAction editingAction() const override { return m_editAction; }
73 void append(SimpleEditCommand*);
74 bool wasCreateLinkCommand() const { return m_editAction == EditAction::CreateLink; }
75
76 const VisibleSelection& startingSelection() const { return m_startingSelection; }
77 const VisibleSelection& endingSelection() const { return m_endingSelection; }
78 void setStartingSelection(const VisibleSelection&);
79 void setEndingSelection(const VisibleSelection&);
80 Element* startingRootEditableElement() const { return m_startingRootEditableElement.get(); }
81 Element* endingRootEditableElement() const { return m_endingRootEditableElement.get(); }
82 void setRangeDeletedByUnapply(const VisiblePositionIndexRange&);
83
84#ifndef NDEBUG
85 virtual void getNodesInCommand(HashSet<Node*>&);
86#endif
87
88private:
89 EditCommandComposition(Document&, const VisibleSelection& startingSelection, const VisibleSelection& endingSelection, EditAction);
90
91 String label() const final;
92 void didRemoveFromUndoManager() final { }
93
94 RefPtr<Document> m_document;
95 VisibleSelection m_startingSelection;
96 VisibleSelection m_endingSelection;
97 Vector<RefPtr<SimpleEditCommand>> m_commands;
98 RefPtr<Element> m_startingRootEditableElement;
99 RefPtr<Element> m_endingRootEditableElement;
100 AccessibilityUndoReplacedText m_replacedText;
101 EditAction m_editAction;
102};
103
104class CompositeEditCommand : public EditCommand {
105public:
106 virtual ~CompositeEditCommand();
107
108 void apply();
109 bool isFirstCommand(EditCommand* command) { return !m_commands.isEmpty() && m_commands.first() == command; }
110 EditCommandComposition* composition() const;
111 EditCommandComposition& ensureComposition();
112
113 virtual bool isCreateLinkCommand() const;
114 virtual bool isTypingCommand() const;
115 virtual bool isDictationCommand() const { return false; }
116 virtual bool preservesTypingStyle() const;
117 virtual bool shouldRetainAutocorrectionIndicator() const;
118 virtual void setShouldRetainAutocorrectionIndicator(bool);
119 virtual bool shouldStopCaretBlinking() const { return false; }
120 virtual String inputEventTypeName() const;
121 virtual String inputEventData() const { return { }; }
122 virtual bool isBeforeInputEventCancelable() const { return true; }
123 virtual bool shouldDispatchInputEvents() const { return true; }
124 Vector<RefPtr<StaticRange>> targetRangesForBindings() const;
125 virtual RefPtr<DataTransfer> inputEventDataTransfer() const;
126
127protected:
128 explicit CompositeEditCommand(Document&, EditAction = EditAction::Unspecified);
129
130 // If willApplyCommand returns false, we won't proceed with applying the command.
131 virtual bool willApplyCommand();
132 virtual void didApplyCommand();
133
134 virtual Vector<RefPtr<StaticRange>> targetRanges() const;
135
136 //
137 // sugary-sweet convenience functions to help create and apply edit commands in composite commands
138 //
139 void appendNode(Ref<Node>&&, Ref<ContainerNode>&& parent);
140 void applyCommandToComposite(Ref<EditCommand>&&);
141 void applyCommandToComposite(Ref<CompositeEditCommand>&&, const VisibleSelection&);
142 void applyStyle(const EditingStyle*, EditAction = EditAction::ChangeAttributes);
143 void applyStyle(const EditingStyle*, const Position& start, const Position& end, EditAction = EditAction::ChangeAttributes);
144 void applyStyledElement(Ref<Element>&&);
145 void removeStyledElement(Ref<Element>&&);
146 void deleteSelection(bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = true, bool sanitizeMarkup = true);
147 void deleteSelection(const VisibleSelection&, bool smartDelete = false, bool mergeBlocksAfterDelete = true, bool replace = false, bool expandForSpecialElements = true, bool sanitizeMarkup = true);
148 virtual void deleteTextFromNode(Text&, unsigned offset, unsigned count);
149 void inputText(const String&, bool selectInsertedText = false);
150 bool isRemovableBlock(const Node*);
151 void insertNodeAfter(Ref<Node>&&, Node& refChild);
152 void insertNodeAt(Ref<Node>&&, const Position&);
153 void insertNodeAtTabSpanPosition(Ref<Node>&&, const Position&);
154 void insertNodeBefore(Ref<Node>&&, Node& refChild, ShouldAssumeContentIsAlwaysEditable = DoNotAssumeContentIsAlwaysEditable);
155 void insertParagraphSeparatorAtPosition(const Position&, bool useDefaultParagraphElement = false, bool pasteBlockqutoeIntoUnquotedArea = false);
156 void insertParagraphSeparator(bool useDefaultParagraphElement = false, bool pasteBlockqutoeIntoUnquotedArea = false);
157 void insertLineBreak();
158 void insertTextIntoNode(Text&, unsigned offset, const String& text);
159 void mergeIdenticalElements(Element&, Element&);
160 void rebalanceWhitespace();
161 void rebalanceWhitespaceAt(const Position&);
162 void rebalanceWhitespaceOnTextSubstring(Text&, int startOffset, int endOffset);
163 void prepareWhitespaceAtPositionForSplit(Position&);
164 bool canRebalance(const Position&) const;
165 bool shouldRebalanceLeadingWhitespaceFor(const String&) const;
166 void removeNodeAttribute(Element&, const QualifiedName& attribute);
167 void removeChildrenInRange(Node&, unsigned from, unsigned to);
168 virtual void removeNode(Node&, ShouldAssumeContentIsAlwaysEditable = DoNotAssumeContentIsAlwaysEditable);
169 HTMLElement* replaceElementWithSpanPreservingChildrenAndAttributes(HTMLElement&);
170 void removeNodePreservingChildren(Node&, ShouldAssumeContentIsAlwaysEditable = DoNotAssumeContentIsAlwaysEditable);
171 void removeNodeAndPruneAncestors(Node&);
172 void moveRemainingSiblingsToNewParent(Node*, Node* pastLastNodeToMove, Element& newParent);
173 void updatePositionForNodeRemovalPreservingChildren(Position&, Node&);
174 void prune(Node*);
175 void replaceTextInNode(Text&, unsigned offset, unsigned count, const String& replacementText);
176 Position replaceSelectedTextInNode(const String&);
177 void replaceTextInNodePreservingMarkers(Text&, unsigned offset, unsigned count, const String& replacementText);
178 Position positionOutsideTabSpan(const Position&);
179 void setNodeAttribute(Element&, const QualifiedName& attribute, const AtomString& value);
180 void splitElement(Element&, Node& atChild);
181 void splitTextNode(Text&, unsigned offset);
182 void splitTextNodeContainingElement(Text&, unsigned offset);
183 void wrapContentsInDummySpan(Element&);
184
185 void deleteInsignificantText(Text&, unsigned start, unsigned end);
186 void deleteInsignificantText(const Position& start, const Position& end);
187 void deleteInsignificantTextDownstream(const Position&);
188
189 Ref<Element> appendBlockPlaceholder(Ref<Element>&&);
190 RefPtr<Node> insertBlockPlaceholder(const Position&);
191 RefPtr<Node> addBlockPlaceholderIfNeeded(Element*);
192 void removePlaceholderAt(const Position&);
193
194 Ref<HTMLElement> insertNewDefaultParagraphElementAt(const Position&);
195
196 RefPtr<Node> moveParagraphContentsToNewBlockIfNecessary(const Position&);
197
198 void pushAnchorElementDown(Element&);
199
200 void moveParagraph(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false, bool preserveStyle = true);
201 void moveParagraphs(const VisiblePosition&, const VisiblePosition&, const VisiblePosition&, bool preserveSelection = false, bool preserveStyle = true);
202 void moveParagraphWithClones(const VisiblePosition& startOfParagraphToMove, const VisiblePosition& endOfParagraphToMove, Element* blockElement, Node* outerNode);
203 void cloneParagraphUnderNewElement(const Position& start, const Position& end, Node* outerNode, Element* blockElement);
204 void cleanupAfterDeletion(VisiblePosition destination = VisiblePosition());
205
206 Optional<VisibleSelection> shouldBreakOutOfEmptyListItem() const;
207 bool breakOutOfEmptyListItem();
208 bool breakOutOfEmptyMailBlockquotedParagraph();
209
210 Position positionAvoidingSpecialElementBoundary(const Position&);
211
212 RefPtr<Node> splitTreeToNode(Node&, Node&, bool splitAncestor = false);
213
214 Vector<RefPtr<EditCommand>> m_commands;
215
216private:
217 bool isCompositeEditCommand() const override { return true; }
218
219 RefPtr<EditCommandComposition> m_composition;
220};
221
222inline CompositeEditCommand* toCompositeEditCommand(EditCommand* command)
223{
224 ASSERT(command);
225 ASSERT_WITH_SECURITY_IMPLICATION(command->isCompositeEditCommand());
226 return static_cast<CompositeEditCommand*>(command);
227}
228
229} // namespace WebCore
230