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 | |
34 | namespace WebCore { |
35 | |
36 | class EditingStyle; |
37 | class DataTransfer; |
38 | class HTMLElement; |
39 | class StaticRange; |
40 | class StyledElement; |
41 | class Text; |
42 | |
43 | class AccessibilityUndoReplacedText { |
44 | public: |
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 | |
56 | private: |
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 | |
66 | class EditCommandComposition : public UndoStep { |
67 | public: |
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 | |
88 | private: |
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 | |
104 | class CompositeEditCommand : public EditCommand { |
105 | public: |
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 | |
127 | protected: |
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 AtomicString& 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 | |
216 | private: |
217 | bool isCompositeEditCommand() const override { return true; } |
218 | |
219 | RefPtr<EditCommandComposition> m_composition; |
220 | }; |
221 | |
222 | inline 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 | |