1/*
2 * Copyright (C) 2005, 2006, 2007, 2013 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#include "config.h"
27#include "EditCommand.h"
28
29#include "AXObjectCache.h"
30#include "CompositeEditCommand.h"
31#include "Document.h"
32#include "Editing.h"
33#include "Editor.h"
34#include "Element.h"
35#include "Frame.h"
36#include "HTMLInputElement.h"
37#include "HTMLTextAreaElement.h"
38#include "NodeTraversal.h"
39
40namespace WebCore {
41
42String inputTypeNameForEditingAction(EditAction action)
43{
44 switch (action) {
45 case EditAction::Justify:
46 return "formatJustifyFull"_s;
47 case EditAction::AlignLeft:
48 return "formatJustifyLeft"_s;
49 case EditAction::AlignRight:
50 return "formatJustifyRight"_s;
51 case EditAction::Center:
52 return "formatJustifyCenter"_s;
53 case EditAction::Subscript:
54 return "formatSubscript"_s;
55 case EditAction::Superscript:
56 return "formatSuperscript"_s;
57 case EditAction::Underline:
58 return "formatUnderline"_s;
59 case EditAction::SetColor:
60 return "formatFontColor"_s;
61 case EditAction::DeleteByDrag:
62 return "deleteByDrag"_s;
63 case EditAction::Cut:
64 return "deleteByCut"_s;
65 case EditAction::Bold:
66 return "formatBold"_s;
67 case EditAction::Italics:
68 return "formatItalic"_s;
69 case EditAction::Paste:
70 return "insertFromPaste"_s;
71 case EditAction::Delete:
72 case EditAction::TypingDeleteSelection:
73 return "deleteContent"_s;
74 case EditAction::TypingDeleteBackward:
75 return "deleteContentBackward"_s;
76 case EditAction::TypingDeleteForward:
77 return "deleteContentForward"_s;
78 case EditAction::TypingDeleteWordBackward:
79 return "deleteWordBackward"_s;
80 case EditAction::TypingDeleteWordForward:
81 return "deleteWordForward"_s;
82 case EditAction::TypingDeleteLineBackward:
83 return "deleteHardLineBackward"_s;
84 case EditAction::TypingDeleteLineForward:
85 return "deleteHardLineForward"_s;
86 case EditAction::TypingDeletePendingComposition:
87 return "deleteCompositionText"_s;
88 case EditAction::TypingDeleteFinalComposition:
89 return "deleteByComposition"_s;
90 case EditAction::Insert:
91 case EditAction::TypingInsertText:
92 return "insertText"_s;
93 case EditAction::InsertReplacement:
94 return "insertReplacementText"_s;
95 case EditAction::InsertFromDrop:
96 return "insertFromDrop"_s;
97 case EditAction::TypingInsertLineBreak:
98 return "insertLineBreak"_s;
99 case EditAction::TypingInsertParagraph:
100 return "insertParagraph"_s;
101 case EditAction::InsertOrderedList:
102 return "insertOrderedList"_s;
103 case EditAction::InsertUnorderedList:
104 return "insertUnorderedList"_s;
105 case EditAction::TypingInsertPendingComposition:
106 return "insertCompositionText"_s;
107 case EditAction::TypingInsertFinalComposition:
108 return "insertFromComposition"_s;
109 case EditAction::Indent:
110 return "formatIndent"_s;
111 case EditAction::Outdent:
112 return "formatOutdent"_s;
113 case EditAction::SetInlineWritingDirection:
114 return "formatSetInlineTextDirection"_s;
115 case EditAction::SetBlockWritingDirection:
116 return "formatSetBlockTextDirection"_s;
117 default:
118 return emptyString();
119 }
120}
121
122EditCommand::EditCommand(Document& document, EditAction editingAction)
123 : m_document(document)
124 , m_editingAction(editingAction)
125{
126 ASSERT(document.frame());
127 setStartingSelection(m_document->frame()->selection().selection());
128 setEndingSelection(m_startingSelection);
129}
130
131EditCommand::EditCommand(Document& document, const VisibleSelection& startingSelection, const VisibleSelection& endingSelection)
132 : m_document(document)
133{
134 ASSERT(document.frame());
135 setStartingSelection(startingSelection);
136 setEndingSelection(endingSelection);
137}
138
139EditCommand::~EditCommand() = default;
140
141Frame& EditCommand::frame()
142{
143 ASSERT(document().frame());
144 return *document().frame();
145}
146
147const Frame& EditCommand::frame() const
148{
149 ASSERT(document().frame());
150 return *document().frame();
151}
152
153EditAction EditCommand::editingAction() const
154{
155 return m_editingAction;
156}
157
158static inline EditCommandComposition* compositionIfPossible(EditCommand* command)
159{
160 if (!command->isCompositeEditCommand())
161 return 0;
162 return toCompositeEditCommand(command)->composition();
163}
164
165bool EditCommand::isEditingTextAreaOrTextInput() const
166{
167 auto* frame = m_document->frame();
168 if (!frame)
169 return false;
170
171 auto* container = frame->selection().selection().start().containerNode();
172 if (!container)
173 return false;
174
175 auto* ancestor = container->shadowHost();
176 if (!ancestor)
177 return false;
178
179 return is<HTMLTextAreaElement>(*ancestor) || (is<HTMLInputElement>(*ancestor) && downcast<HTMLInputElement>(*ancestor).isText());
180}
181
182void EditCommand::setStartingSelection(const VisibleSelection& s)
183{
184 for (EditCommand* cmd = this; ; cmd = cmd->m_parent) {
185 if (auto* composition = compositionIfPossible(cmd))
186 composition->setStartingSelection(s);
187 cmd->m_startingSelection = s;
188 if (!cmd->m_parent || cmd->m_parent->isFirstCommand(cmd))
189 break;
190 }
191}
192
193void EditCommand::setEndingSelection(const VisibleSelection &s)
194{
195 for (EditCommand* cmd = this; cmd; cmd = cmd->m_parent) {
196 if (auto* composition = compositionIfPossible(cmd))
197 composition->setEndingSelection(s);
198 cmd->m_endingSelection = s;
199 }
200}
201
202void EditCommand::setParent(CompositeEditCommand* parent)
203{
204 ASSERT((parent && !m_parent) || (!parent && m_parent));
205 m_parent = parent;
206 if (parent) {
207 m_startingSelection = parent->m_endingSelection;
208 m_endingSelection = parent->m_endingSelection;
209 }
210}
211
212void EditCommand::postTextStateChangeNotification(AXTextEditType type, const String& text)
213{
214 if (!AXObjectCache::accessibilityEnabled())
215 return;
216 postTextStateChangeNotification(type, text, frame().selection().selection().start());
217}
218
219void EditCommand::postTextStateChangeNotification(AXTextEditType type, const String& text, const VisiblePosition& position)
220{
221 if (!AXObjectCache::accessibilityEnabled())
222 return;
223 if (!text.length())
224 return;
225 auto* cache = document().existingAXObjectCache();
226 if (!cache)
227 return;
228 auto* node = highestEditableRoot(position.deepEquivalent(), HasEditableAXRole);
229 cache->postTextStateChangeNotification(node, type, text, position);
230}
231
232SimpleEditCommand::SimpleEditCommand(Document& document, EditAction editingAction)
233 : EditCommand(document, editingAction)
234{
235}
236
237void SimpleEditCommand::doReapply()
238{
239 doApply();
240}
241
242#ifndef NDEBUG
243void SimpleEditCommand::addNodeAndDescendants(Node* startNode, HashSet<Node*>& nodes)
244{
245 for (Node* node = startNode; node; node = NodeTraversal::next(*node, startNode))
246 nodes.add(node);
247}
248#endif
249
250} // namespace WebCore
251