blob: cce5a79dd4e53506dd7d3ce7454f5f782628c39d [file] [log] [blame]
mjs84e724c2005-05-24 07:21:47 +00001/*
bfulgham@apple.com1f2e42b2019-05-28 21:02:38 +00002 * Copyright (C) 2005-2019 Apple Inc. All rights reserved.
mjs84e724c2005-05-24 07:21:47 +00003 *
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 *
mjs@apple.com92047332014-03-15 04:08:27 +000013 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
mjs84e724c2005-05-24 07:21:47 +000014 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
mjs@apple.com92047332014-03-15 04:08:27 +000016 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
mjs84e724c2005-05-24 07:21:47 +000017 * 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
mjsb64c50a2005-10-03 21:13:12 +000026#include "config.h"
darina68e0432006-02-14 21:40:54 +000027#include "TypingCommand.h"
mjs84e724c2005-05-24 07:21:47 +000028
d_russell@apple.com07f85592016-04-04 23:17:59 +000029#include "AXObjectCache.h"
darina68e0432006-02-14 21:40:54 +000030#include "BreakBlockquoteCommand.h"
wenson_hsieh@apple.comadff4e02016-10-31 15:12:00 +000031#include "DataTransfer.h"
lweintraub6d377802006-07-07 19:33:28 +000032#include "DeleteSelectionCommand.h"
jer.noble@apple.com117db592021-10-13 05:54:46 +000033#include "DocumentInlines.h"
commit-queue@webkit.org02ea7a22017-03-03 06:35:25 +000034#include "Editing.h"
ggaren57aa2fe2006-10-31 01:01:01 +000035#include "Editor.h"
eseidel40eb1b92006-03-25 22:20:36 +000036#include "Element.h"
darina68e0432006-02-14 21:40:54 +000037#include "Frame.h"
darin@apple.com15708b12014-03-16 16:38:58 +000038#include "HTMLElement.h"
mitz@apple.com3d9a5082009-04-30 03:03:29 +000039#include "HTMLNames.h"
darina68e0432006-02-14 21:40:54 +000040#include "InsertLineBreakCommand.h"
41#include "InsertParagraphSeparatorCommand.h"
42#include "InsertTextCommand.h"
simon.fraser@apple.com906b0862016-08-28 00:36:05 +000043#include "Logging.h"
wenson_hsieh@apple.comadff4e02016-10-31 15:12:00 +000044#include "MarkupAccumulator.h"
darin@apple.com15708b12014-03-16 16:38:58 +000045#include "MathMLElement.h"
aperez@igalia.comfa121a62020-08-03 16:42:33 +000046#include "Range.h"
antti@apple.comc3cbb6b2013-09-20 08:59:25 +000047#include "RenderElement.h"
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +000048#include "StaticRange.h"
darin@apple.com51e2d462014-03-03 02:30:37 +000049#include "TextIterator.h"
tkent@chromium.org8c35c122013-03-06 13:00:14 +000050#include "VisibleUnits.h"
mjs84e724c2005-05-24 07:21:47 +000051
darina68e0432006-02-14 21:40:54 +000052namespace WebCore {
mjs84e724c2005-05-24 07:21:47 +000053
mitz@apple.com3d9a5082009-04-30 03:03:29 +000054using namespace HTMLNames;
55
jpu@apple.comdfd2ce62012-04-16 03:05:06 +000056class TypingCommandLineOperation
commit-queue@webkit.orgb887b8c2011-03-17 06:31:00 +000057{
jpu@apple.comdfd2ce62012-04-16 03:05:06 +000058public:
59 TypingCommandLineOperation(TypingCommand* typingCommand, bool selectInsertedText, const String& text)
60 : m_typingCommand(typingCommand)
61 , m_selectInsertedText(selectInsertedText)
62 , m_text(text)
63 { }
64
65 void operator()(size_t lineOffset, size_t lineLength, bool isLastLine) const
66 {
67 if (isLastLine) {
68 if (!lineOffset || lineLength > 0)
69 m_typingCommand->insertTextRunWithoutNewlines(m_text.substring(lineOffset, lineLength), m_selectInsertedText);
70 } else {
71 if (lineLength > 0)
72 m_typingCommand->insertTextRunWithoutNewlines(m_text.substring(lineOffset, lineLength), false);
73 m_typingCommand->insertParagraphSeparator();
74 }
75 }
76
77private:
78 TypingCommand* m_typingCommand;
79 bool m_selectInsertedText;
80 const String& m_text;
81};
commit-queue@webkit.orgb887b8c2011-03-17 06:31:00 +000082
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +000083static inline EditAction editActionForTypingCommand(TypingCommand::ETypingCommand command, TextGranularity granularity, TypingCommand::TextCompositionType compositionType, bool isAutocompletion)
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +000084{
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +000085 if (compositionType == TypingCommand::TextCompositionPending) {
86 if (command == TypingCommand::InsertText)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +000087 return EditAction::TypingInsertPendingComposition;
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +000088 if (command == TypingCommand::DeleteSelection)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +000089 return EditAction::TypingDeletePendingComposition;
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +000090 ASSERT_NOT_REACHED();
91 }
92
93 if (compositionType == TypingCommand::TextCompositionFinal) {
94 if (command == TypingCommand::InsertText)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +000095 return EditAction::TypingInsertFinalComposition;
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +000096 if (command == TypingCommand::DeleteSelection)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +000097 return EditAction::TypingDeleteFinalComposition;
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +000098 ASSERT_NOT_REACHED();
99 }
100
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000101 switch (command) {
102 case TypingCommand::DeleteSelection:
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000103 return EditAction::TypingDeleteSelection;
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000104 case TypingCommand::DeleteKey: {
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000105 if (granularity == TextGranularity::WordGranularity)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000106 return EditAction::TypingDeleteWordBackward;
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000107 if (granularity == TextGranularity::LineBoundary)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000108 return EditAction::TypingDeleteLineBackward;
109 return EditAction::TypingDeleteBackward;
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000110 }
111 case TypingCommand::ForwardDeleteKey:
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000112 if (granularity == TextGranularity::WordGranularity)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000113 return EditAction::TypingDeleteWordForward;
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000114 if (granularity == TextGranularity::LineBoundary)
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000115 return EditAction::TypingDeleteLineForward;
116 return EditAction::TypingDeleteForward;
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000117 case TypingCommand::InsertText:
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000118 return isAutocompletion ? EditAction::InsertReplacement : EditAction::TypingInsertText;
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000119 case TypingCommand::InsertLineBreak:
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000120 return EditAction::TypingInsertLineBreak;
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000121 case TypingCommand::InsertParagraphSeparator:
122 case TypingCommand::InsertParagraphSeparatorInQuotedContent:
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000123 return EditAction::TypingInsertParagraph;
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000124 default:
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000125 return EditAction::Unspecified;
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000126 }
127}
128
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000129static inline bool editActionIsDeleteByTyping(EditAction action)
130{
131 switch (action) {
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000132 case EditAction::TypingDeleteSelection:
133 case EditAction::TypingDeleteBackward:
134 case EditAction::TypingDeleteWordBackward:
135 case EditAction::TypingDeleteLineBackward:
136 case EditAction::TypingDeleteForward:
137 case EditAction::TypingDeleteWordForward:
138 case EditAction::TypingDeleteLineForward:
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000139 return true;
140 default:
141 return false;
142 }
143}
144
akling@apple.comd455eb62013-09-01 05:30:31 +0000145TypingCommand::TypingCommand(Document& document, ETypingCommand commandType, const String &textToInsert, Options options, TextGranularity granularity, TextCompositionType compositionType)
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000146 : TextInsertionBaseCommand(document, editActionForTypingCommand(commandType, granularity, compositionType, options & IsAutocompletion))
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000147 , m_commandType(commandType)
148 , m_textToInsert(textToInsert)
wenson_hsieh@apple.com3747aa52016-10-10 18:30:03 +0000149 , m_currentTextToInsert(textToInsert)
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000150 , m_openForMoreTyping(true)
151 , m_selectInsertedText(options & SelectInsertedText)
commit-queue@webkit.org6aedb682011-04-08 03:59:34 +0000152 , m_smartDelete(options & SmartDelete)
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000153 , m_granularity(granularity)
154 , m_compositionType(compositionType)
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000155 , m_shouldAddToKillRing(options & AddsToKillRing)
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000156 , m_isAutocompletion(options & IsAutocompletion)
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000157 , m_openedByBackwardDelete(false)
158 , m_shouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator)
commit-queue@webkit.org6aedb682011-04-08 03:59:34 +0000159 , m_shouldPreventSpellChecking(options & PreventSpellChecking)
mjs84e724c2005-05-24 07:21:47 +0000160{
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000161 m_currentTypingEditAction = editingAction();
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000162 updatePreservesTypingStyle(m_commandType);
mjs84e724c2005-05-24 07:21:47 +0000163}
164
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000165void TypingCommand::deleteSelection(Document& document, Options options, TextCompositionType compositionType)
justingee38ac82007-10-25 00:58:54 +0000166{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000167 if (!document.selection().isRange())
justingee38ac82007-10-25 00:58:54 +0000168 return;
rniwa@webkit.org166a086c2011-12-07 09:03:51 +0000169
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000170 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000171 lastTypingCommand->setIsAutocompletion(options & IsAutocompletion);
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000172 lastTypingCommand->setCompositionType(compositionType);
commit-queue@webkit.org6aedb682011-04-08 03:59:34 +0000173 lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
174 lastTypingCommand->deleteSelection(options & SmartDelete);
justingee38ac82007-10-25 00:58:54 +0000175 return;
176 }
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000177
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000178 TypingCommand::create(document, DeleteSelection, emptyString(), options, compositionType)->apply();
justingee38ac82007-10-25 00:58:54 +0000179}
180
akling@apple.com62b19a82013-10-05 03:34:51 +0000181void TypingCommand::deleteKeyPressed(Document& document, Options options, TextGranularity granularity)
mjs84e724c2005-05-24 07:21:47 +0000182{
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000183 if (granularity == TextGranularity::CharacterGranularity) {
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000184 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
185 updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand.get(), document);
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000186 lastTypingCommand->setIsAutocompletion(options & IsAutocompletion);
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000187 lastTypingCommand->setCompositionType(TextCompositionNone);
rniwa@webkit.org166a086c2011-12-07 09:03:51 +0000188 lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000189 lastTypingCommand->deleteKeyPressed(granularity, options & AddsToKillRing);
rniwa@webkit.org166a086c2011-12-07 09:03:51 +0000190 return;
191 }
mjs84e724c2005-05-24 07:21:47 +0000192 }
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000193
cdumez@apple.com327d6c62016-07-16 04:51:45 +0000194 TypingCommand::create(document, DeleteKey, emptyString(), options, granularity)->apply();
mjs84e724c2005-05-24 07:21:47 +0000195}
196
akling@apple.com62b19a82013-10-05 03:34:51 +0000197void TypingCommand::forwardDeleteKeyPressed(Document& document, Options options, TextGranularity granularity)
mjs84e724c2005-05-24 07:21:47 +0000198{
justing4a536cf2007-08-17 00:29:36 +0000199 // FIXME: Forward delete in TextEdit appears to open and close a new typing command.
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000200 if (granularity == TextGranularity::CharacterGranularity) {
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000201 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
202 updateSelectionIfDifferentFromCurrentSelection(lastTypingCommand.get(), document);
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000203 lastTypingCommand->setIsAutocompletion(options & IsAutocompletion);
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000204 lastTypingCommand->setCompositionType(TextCompositionNone);
rniwa@webkit.org166a086c2011-12-07 09:03:51 +0000205 lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000206 lastTypingCommand->forwardDeleteKeyPressed(granularity, options & AddsToKillRing);
rniwa@webkit.org166a086c2011-12-07 09:03:51 +0000207 return;
208 }
mjs84e724c2005-05-24 07:21:47 +0000209 }
harrison78e65832006-02-14 03:29:43 +0000210
cdumez@apple.com327d6c62016-07-16 04:51:45 +0000211 TypingCommand::create(document, ForwardDeleteKey, emptyString(), options, granularity)->apply();
mjs84e724c2005-05-24 07:21:47 +0000212}
213
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000214void TypingCommand::updateSelectionIfDifferentFromCurrentSelection(TypingCommand* typingCommand, Document& document)
rniwa@webkit.org54a246d2010-12-03 19:26:22 +0000215{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000216 VisibleSelection currentSelection = document.selection().selection();
rniwa@webkit.org54a246d2010-12-03 19:26:22 +0000217 if (currentSelection == typingCommand->endingSelection())
218 return;
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000219
rniwa@webkit.org54a246d2010-12-03 19:26:22 +0000220 typingCommand->setStartingSelection(currentSelection);
221 typingCommand->setEndingSelection(currentSelection);
222}
rniwa@webkit.org54a246d2010-12-03 19:26:22 +0000223
akling@apple.com62b19a82013-10-05 03:34:51 +0000224void TypingCommand::insertText(Document& document, const String& text, Options options, TextCompositionType composition)
mjs84e724c2005-05-24 07:21:47 +0000225{
commit-queue@webkit.org08abac62010-10-28 23:45:26 +0000226 if (!text.isEmpty())
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000227 document.editor().updateMarkersForWordsAffectedByEditing(isSpaceOrNewline(text[0]));
morrita@google.com4e40c8b2011-04-08 21:21:44 +0000228
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000229 insertText(document, text, document.selection().selection(), options, composition);
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000230}
231
rniwa@webkit.org78bbc942011-05-05 18:14:43 +0000232// FIXME: We shouldn't need to take selectionForInsertion. It should be identical to FrameSelection's current selection.
akling@apple.com62b19a82013-10-05 03:34:51 +0000233void TypingCommand::insertText(Document& document, const String& text, const VisibleSelection& selectionForInsertion, Options options, TextCompositionType compositionType)
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000234{
simon.fraser@apple.com906b0862016-08-28 00:36:05 +0000235 LOG(Editing, "TypingCommand::insertText (text %s)", text.utf8().data());
236
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000237 VisibleSelection currentSelection = document.selection().selection();
jpu@apple.comdfd2ce62012-04-16 03:05:06 +0000238
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000239 String newText = dispatchBeforeTextInsertedEvent(text, selectionForInsertion, compositionType == TextCompositionPending);
adele1abf9592006-03-06 05:52:31 +0000240
adele6ef54cf72007-01-31 22:55:56 +0000241 // Set the starting and ending selection appropriately if we are using a selection
242 // that is different from the current selection. In the future, we should change EditCommand
243 // to deal with custom selections in a general way that can be used by all of the commands.
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000244 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
rniwa@webkit.org54a246d2010-12-03 19:26:22 +0000245 if (lastTypingCommand->endingSelection() != selectionForInsertion) {
adele6ef54cf72007-01-31 22:55:56 +0000246 lastTypingCommand->setStartingSelection(selectionForInsertion);
247 lastTypingCommand->setEndingSelection(selectionForInsertion);
darind4408fc2007-04-24 17:37:50 +0000248 }
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000249
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000250 lastTypingCommand->setIsAutocompletion(options & IsAutocompletion);
morrita@google.com6a3e4252011-01-24 06:53:34 +0000251 lastTypingCommand->setCompositionType(compositionType);
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000252 lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
commit-queue@webkit.org6aedb682011-04-08 03:59:34 +0000253 lastTypingCommand->setShouldPreventSpellChecking(options & PreventSpellChecking);
d_russell@apple.com07f85592016-04-04 23:17:59 +0000254 lastTypingCommand->insertTextAndNotifyAccessibility(newText, options & SelectInsertedText);
harrison78e65832006-02-14 03:29:43 +0000255 return;
mjs84e724c2005-05-24 07:21:47 +0000256 }
harrison78e65832006-02-14 03:29:43 +0000257
yusukesuzuki@slowstart.orgae5a8bd2018-12-22 06:37:39 +0000258 auto cmd = TypingCommand::create(document, InsertText, newText, options, compositionType);
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000259 applyTextInsertionCommand(document.frame(), cmd.get(), selectionForInsertion, currentSelection);
mjs84e724c2005-05-24 07:21:47 +0000260}
261
akling@apple.com62b19a82013-10-05 03:34:51 +0000262void TypingCommand::insertLineBreak(Document& document, Options options)
mjs84e724c2005-05-24 07:21:47 +0000263{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000264 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000265 lastTypingCommand->setIsAutocompletion(options & IsAutocompletion);
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000266 lastTypingCommand->setCompositionType(TextCompositionNone);
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000267 lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
d_russell@apple.com07f85592016-04-04 23:17:59 +0000268 lastTypingCommand->insertLineBreakAndNotifyAccessibility();
harrison78e65832006-02-14 03:29:43 +0000269 return;
mjs84e724c2005-05-24 07:21:47 +0000270 }
harrison78e65832006-02-14 03:29:43 +0000271
cdumez@apple.com2fecce72017-05-05 05:09:56 +0000272 TypingCommand::create(document, InsertLineBreak, emptyString(), options)->apply();
mjs84e724c2005-05-24 07:21:47 +0000273}
274
akling@apple.com62b19a82013-10-05 03:34:51 +0000275void TypingCommand::insertParagraphSeparatorInQuotedContent(Document& document)
mjs84e724c2005-05-24 07:21:47 +0000276{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000277 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000278 lastTypingCommand->setIsAutocompletion(false);
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000279 lastTypingCommand->setCompositionType(TextCompositionNone);
d_russell@apple.com07f85592016-04-04 23:17:59 +0000280 lastTypingCommand->insertParagraphSeparatorInQuotedContentAndNotifyAccessibility();
harrison78e65832006-02-14 03:29:43 +0000281 return;
mjs84e724c2005-05-24 07:21:47 +0000282 }
harrison78e65832006-02-14 03:29:43 +0000283
cdumez@apple.com2fecce72017-05-05 05:09:56 +0000284 TypingCommand::create(document, InsertParagraphSeparatorInQuotedContent)->apply();
mjs84e724c2005-05-24 07:21:47 +0000285}
286
akling@apple.com62b19a82013-10-05 03:34:51 +0000287void TypingCommand::insertParagraphSeparator(Document& document, Options options)
mjs84e724c2005-05-24 07:21:47 +0000288{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000289 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000290 lastTypingCommand->setIsAutocompletion(options & IsAutocompletion);
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000291 lastTypingCommand->setCompositionType(TextCompositionNone);
commit-queue@webkit.org5396fd92011-03-01 20:31:40 +0000292 lastTypingCommand->setShouldRetainAutocorrectionIndicator(options & RetainAutocorrectionIndicator);
d_russell@apple.com07f85592016-04-04 23:17:59 +0000293 lastTypingCommand->insertParagraphSeparatorAndNotifyAccessibility();
harrison78e65832006-02-14 03:29:43 +0000294 return;
mjs84e724c2005-05-24 07:21:47 +0000295 }
harrison78e65832006-02-14 03:29:43 +0000296
cdumez@apple.com2fecce72017-05-05 05:09:56 +0000297 TypingCommand::create(document, InsertParagraphSeparator, emptyString(), options)->apply();
mjs84e724c2005-05-24 07:21:47 +0000298}
299
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000300RefPtr<TypingCommand> TypingCommand::lastTypingCommandIfStillOpenForTyping(Document& document)
mjs84e724c2005-05-24 07:21:47 +0000301{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000302 RefPtr<CompositeEditCommand> lastEditCommand = document.editor().lastEditCommand();
rniwa@webkit.org6c2ef9d2012-01-19 21:41:08 +0000303 if (!lastEditCommand || !lastEditCommand->isTypingCommand() || !static_cast<TypingCommand*>(lastEditCommand.get())->isOpenForMoreTyping())
gyuyoung.kim@webkit.org842c7862016-03-23 14:05:54 +0000304 return nullptr;
rniwa@webkit.org166a086c2011-12-07 09:03:51 +0000305
rniwa@webkit.org6c2ef9d2012-01-19 21:41:08 +0000306 return static_cast<TypingCommand*>(lastEditCommand.get());
mjs84e724c2005-05-24 07:21:47 +0000307}
308
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000309bool TypingCommand::shouldDeferWillApplyCommandUntilAddingTypingCommand() const
310{
311 return !m_isHandlingInitialTypingCommand || editActionIsDeleteByTyping(editingAction());
312}
313
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000314void TypingCommand::closeTyping(Document& document)
mjs84e724c2005-05-24 07:21:47 +0000315{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000316 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document))
rniwa@webkit.org166a086c2011-12-07 09:03:51 +0000317 lastTypingCommand->closeTyping();
mjs84e724c2005-05-24 07:21:47 +0000318}
319
ap@apple.com1e8475922018-10-18 21:38:50 +0000320#if PLATFORM(IOS_FAMILY)
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000321void TypingCommand::ensureLastEditCommandHasCurrentSelectionIfOpenForMoreTyping(Document& document, const VisibleSelection& newSelection)
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000322{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000323 if (RefPtr<TypingCommand> lastTypingCommand = lastTypingCommandIfStillOpenForTyping(document)) {
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000324 lastTypingCommand->setEndingSelection(newSelection);
325 lastTypingCommand->setEndingSelectionOnLastInsertCommand(newSelection);
326 }
327}
328#endif
329
d_russell@apple.com07f85592016-04-04 23:17:59 +0000330void TypingCommand::postTextStateChangeNotificationForDeletion(const VisibleSelection& selection)
331{
332 if (!AXObjectCache::accessibilityEnabled())
333 return;
334 postTextStateChangeNotification(AXTextEditTypeDelete, AccessibilityObject::stringForVisiblePositionRange(selection), selection.start());
335 VisiblePositionIndexRange range;
darin@apple.com2e2bfd72020-07-29 16:36:40 +0000336 range.startIndex.value = indexForVisiblePosition(selection.visibleStart(), range.startIndex.scope);
337 range.endIndex.value = indexForVisiblePosition(selection.visibleEnd(), range.endIndex.scope);
d_russell@apple.comd60eb242016-05-13 19:34:48 +0000338 composition()->setRangeDeletedByUnapply(range);
d_russell@apple.com07f85592016-04-04 23:17:59 +0000339}
340
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000341bool TypingCommand::willApplyCommand()
342{
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000343 if (shouldDeferWillApplyCommandUntilAddingTypingCommand()) {
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000344 // The TypingCommand will handle the willApplyCommand logic separately in TypingCommand::willAddTypingToOpenCommand.
345 return true;
346 }
347
348 return CompositeEditCommand::willApplyCommand();
349}
350
mjs84e724c2005-05-24 07:21:47 +0000351void TypingCommand::doApply()
352{
rniwa@webkit.org0a8ef822016-06-08 19:19:22 +0000353 if (endingSelection().isNoneOrOrphaned())
mjs84e724c2005-05-24 07:21:47 +0000354 return;
rniwa@webkit.org0a8ef822016-06-08 19:19:22 +0000355
justing4a536cf2007-08-17 00:29:36 +0000356 if (m_commandType == DeleteKey)
357 if (m_commands.isEmpty())
358 m_openedByBackwardDelete = true;
mjs84e724c2005-05-24 07:21:47 +0000359
360 switch (m_commandType) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000361 case DeleteSelection:
362 deleteSelection(m_smartDelete);
363 return;
364 case DeleteKey:
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000365 deleteKeyPressed(m_granularity, m_shouldAddToKillRing);
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000366 return;
367 case ForwardDeleteKey:
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000368 forwardDeleteKeyPressed(m_granularity, m_shouldAddToKillRing);
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000369 return;
370 case InsertLineBreak:
d_russell@apple.com07f85592016-04-04 23:17:59 +0000371 insertLineBreakAndNotifyAccessibility();
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000372 return;
373 case InsertParagraphSeparator:
d_russell@apple.com07f85592016-04-04 23:17:59 +0000374 insertParagraphSeparatorAndNotifyAccessibility();
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000375 return;
376 case InsertParagraphSeparatorInQuotedContent:
d_russell@apple.com07f85592016-04-04 23:17:59 +0000377 insertParagraphSeparatorInQuotedContentAndNotifyAccessibility();
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000378 return;
379 case InsertText:
d_russell@apple.com07f85592016-04-04 23:17:59 +0000380 insertTextAndNotifyAccessibility(m_textToInsert, m_selectInsertedText);
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000381 return;
mjs84e724c2005-05-24 07:21:47 +0000382 }
383
384 ASSERT_NOT_REACHED();
385}
386
cdumez@apple.comb5c30b72022-05-02 00:17:50 +0000387AtomString TypingCommand::inputEventTypeName() const
wenson_hsieh@apple.com4bb2f7a2016-10-10 03:11:20 +0000388{
389 return inputTypeNameForEditingAction(m_currentTypingEditAction);
390}
391
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000392bool TypingCommand::isBeforeInputEventCancelable() const
393{
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000394 return m_currentTypingEditAction != EditAction::TypingInsertPendingComposition && m_currentTypingEditAction != EditAction::TypingDeletePendingComposition;
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000395}
396
wenson_hsieh@apple.com3747aa52016-10-10 18:30:03 +0000397String TypingCommand::inputEventData() const
398{
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000399 switch (m_currentTypingEditAction) {
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000400 case EditAction::TypingInsertText:
401 case EditAction::TypingInsertPendingComposition:
402 case EditAction::TypingInsertFinalComposition:
wenson_hsieh@apple.com3747aa52016-10-10 18:30:03 +0000403 return m_currentTextToInsert;
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000404 case EditAction::InsertReplacement:
wenson_hsieh@apple.comadff4e02016-10-31 15:12:00 +0000405 return isEditingTextAreaOrTextInput() ? m_currentTextToInsert : String();
wenson_hsieh@apple.com8ee483a2016-10-21 23:06:05 +0000406 default:
407 return CompositeEditCommand::inputEventData();
408 }
wenson_hsieh@apple.com3747aa52016-10-10 18:30:03 +0000409}
410
wenson_hsieh@apple.comadff4e02016-10-31 15:12:00 +0000411RefPtr<DataTransfer> TypingCommand::inputEventDataTransfer() const
412{
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000413 if (m_currentTypingEditAction != EditAction::InsertReplacement || isEditingTextAreaOrTextInput())
wenson_hsieh@apple.comadff4e02016-10-31 15:12:00 +0000414 return nullptr;
415
416 StringBuilder htmlText;
417 MarkupAccumulator::appendCharactersReplacingEntities(htmlText, m_currentTextToInsert, 0, m_currentTextToInsert.length(), EntityMaskInHTMLPCDATA);
cdumez@apple.comc6e9e742019-09-18 22:30:39 +0000418 return DataTransfer::createForInputEvent(m_currentTextToInsert, htmlText.toString());
wenson_hsieh@apple.comadff4e02016-10-31 15:12:00 +0000419}
420
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000421void TypingCommand::didApplyCommand()
422{
423 // TypingCommands handle applied editing separately (see TypingCommand::typingAddedToOpenCommand).
424 m_isHandlingInitialTypingCommand = false;
425}
426
commit-queue@webkit.org57662912010-09-29 00:14:17 +0000427void TypingCommand::markMisspellingsAfterTyping(ETypingCommand commandType)
mjs84e724c2005-05-24 07:21:47 +0000428{
mitz@apple.com630ef442014-02-19 08:12:24 +0000429#if PLATFORM(MAC)
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000430 if (!document().editor().isContinuousSpellCheckingEnabled()
431 && !document().editor().isAutomaticQuoteSubstitutionEnabled()
432 && !document().editor().isAutomaticLinkDetectionEnabled()
433 && !document().editor().isAutomaticDashSubstitutionEnabled()
434 && !document().editor().isAutomaticTextReplacementEnabled())
andersca@apple.comb4170922013-05-15 19:47:47 +0000435 return;
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000436 if (document().editor().isHandlingAcceptedCandidate())
bdakin@apple.comd84d6cb2016-02-04 00:01:46 +0000437 return;
justin.garcia@apple.com2ac9a812009-04-30 01:35:07 +0000438#else
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000439 if (!document().editor().isContinuousSpellCheckingEnabled())
justin.garcia@apple.com64125512008-02-20 17:48:44 +0000440 return;
justin.garcia@apple.com2ac9a812009-04-30 01:35:07 +0000441#endif
mjs84e724c2005-05-24 07:21:47 +0000442 // Take a look at the selection that results after typing and determine whether we need to spellcheck.
443 // Since the word containing the current selection is never marked, this does a check to
444 // see if typing made a new word that is not in the current selection. Basically, you
445 // get this by being at the end of a word and typing a space.
darin9aa45a42006-01-15 23:32:02 +0000446 VisiblePosition start(endingSelection().start(), endingSelection().affinity());
mjs84e724c2005-05-24 07:21:47 +0000447 VisiblePosition previous = start.previous();
448 if (previous.isNotNull()) {
ap@apple.com1e8475922018-10-18 21:38:50 +0000449#if !PLATFORM(IOS_FAMILY)
mjs84e724c2005-05-24 07:21:47 +0000450 VisiblePosition p1 = startOfWord(previous, LeftWordIfOnBoundary);
451 VisiblePosition p2 = startOfWord(start, LeftWordIfOnBoundary);
commit-queue@webkit.org76bec612011-04-11 20:56:32 +0000452 if (p1 != p2) {
darin@apple.com5d3decc2020-08-01 15:50:36 +0000453 auto range = makeSimpleRange(p1, p2);
commit-queue@webkit.org76bec612011-04-11 20:56:32 +0000454 String strippedPreviousWord;
455 if (range && (commandType == TypingCommand::InsertText || commandType == TypingCommand::InsertLineBreak || commandType == TypingCommand::InsertParagraphSeparator || commandType == TypingCommand::InsertParagraphSeparatorInQuotedContent))
darin@apple.com1b30f742020-04-02 18:57:15 +0000456 strippedPreviousWord = plainText(*range).stripWhiteSpace();
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000457 document().editor().markMisspellingsAfterTypingToWord(p1, endingSelection(), !strippedPreviousWord.isEmpty());
commit-queue@webkit.org76bec612011-04-11 20:56:32 +0000458 } else if (commandType == TypingCommand::InsertText)
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000459 document().editor().startAlternativeTextUITimer();
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000460#else
461 UNUSED_PARAM(commandType);
ap@apple.com1e8475922018-10-18 21:38:50 +0000462 // If this bug gets fixed, this PLATFORM(IOS_FAMILY) code could be removed:
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000463 // <rdar://problem/7259611> Word boundary code on iPhone gives different results than desktop
464 EWordSide startWordSide = LeftWordIfOnBoundary;
465 UChar32 c = previous.characterAfter();
466 // FIXME: VisiblePosition::characterAfter() and characterBefore() do not emit newlines the same
467 // way as TextIterator, so we do an isEndOfParagraph check here.
darin@apple.com5917cb12017-11-23 17:32:42 +0000468 if (isSpaceOrNewline(c) || c == noBreakSpace || isEndOfParagraph(previous)) {
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000469 startWordSide = RightWordIfOnBoundary;
470 }
471 VisiblePosition p1 = startOfWord(previous, startWordSide);
472 VisiblePosition p2 = startOfWord(start, startWordSide);
473 if (p1 != p2)
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000474 document().editor().markMisspellingsAfterTypingToWord(p1, endingSelection(), false);
ap@apple.com1e8475922018-10-18 21:38:50 +0000475#endif // !PLATFORM(IOS_FAMILY)
mjs84e724c2005-05-24 07:21:47 +0000476 }
477}
478
darin@apple.coma4ddc782021-05-30 16:11:40 +0000479bool TypingCommand::willAddTypingToOpenCommand(ETypingCommand commandType, TextGranularity granularity, const String& text, const std::optional<SimpleRange>& range)
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000480{
wenson_hsieh@apple.com3747aa52016-10-10 18:30:03 +0000481 m_currentTextToInsert = text;
wenson_hsieh@apple.coma76d4f9c2016-10-29 01:06:13 +0000482 m_currentTypingEditAction = editActionForTypingCommand(commandType, granularity, m_compositionType, m_isAutocompletion);
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000483
484 if (!shouldDeferWillApplyCommandUntilAddingTypingCommand())
485 return true;
486
487 if (!range || isEditingTextAreaOrTextInput())
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000488 return document().editor().willApplyEditing(*this, CompositeEditCommand::targetRangesForBindings());
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000489
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000490 return document().editor().willApplyEditing(*this, { 1, StaticRange::create(*range) });
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000491}
492
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000493void TypingCommand::typingAddedToOpenCommand(ETypingCommand commandTypeForAddedTyping)
mjs84e724c2005-05-24 07:21:47 +0000494{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000495 RefPtr<Frame> protector(document().frame());
morrita@google.com7b933de2012-02-03 11:39:51 +0000496
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000497 updatePreservesTypingStyle(commandTypeForAddedTyping);
commit-queue@webkit.org57662912010-09-29 00:14:17 +0000498
mitz@apple.com28c9d4a2014-02-08 22:26:50 +0000499#if PLATFORM(COCOA)
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000500 document().editor().appliedEditing(*this);
adele@apple.comf4cbf342009-04-27 23:14:33 +0000501 // Since the spellchecking code may also perform corrections and other replacements, it should happen after the typing changes.
commit-queue@webkit.org6aedb682011-04-08 03:59:34 +0000502 if (!m_shouldPreventSpellChecking)
503 markMisspellingsAfterTyping(commandTypeForAddedTyping);
bdakin@apple.comf2a17a72009-05-08 23:40:39 +0000504#else
505 // The old spellchecking code requires that checking be done first, to prevent issues like that in 6864072, where <doesn't> is marked as misspelled.
commit-queue@webkit.org57662912010-09-29 00:14:17 +0000506 markMisspellingsAfterTyping(commandTypeForAddedTyping);
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000507 document().editor().appliedEditing(*this);
bdakin@apple.comf2a17a72009-05-08 23:40:39 +0000508#endif
mjs84e724c2005-05-24 07:21:47 +0000509}
510
darinb9481ed2006-03-20 02:57:59 +0000511void TypingCommand::insertText(const String &text, bool selectInsertedText)
mjs84e724c2005-05-24 07:21:47 +0000512{
513 // FIXME: Need to implement selectInsertedText for cases where more than one insert is involved.
514 // This requires support from insertTextRunWithoutNewlines and insertParagraphSeparator for extending
515 // an existing selection; at the moment they can either put the caret after what's inserted or
516 // select what's inserted, but there's no way to "extend selection" to include both an old selection
517 // that ends just before where we want to insert text and the newly inserted text.
jpu@apple.comdfd2ce62012-04-16 03:05:06 +0000518 TypingCommandLineOperation operation(this, selectInsertedText, text);
519 forEachLineInString(text, operation);
mjs84e724c2005-05-24 07:21:47 +0000520}
521
d_russell@apple.com07f85592016-04-04 23:17:59 +0000522void TypingCommand::insertTextAndNotifyAccessibility(const String &text, bool selectInsertedText)
523{
simon.fraser@apple.com906b0862016-08-28 00:36:05 +0000524 LOG(Editing, "TypingCommand %p insertTextAndNotifyAccessibility (text %s, selectInsertedText %d)", this, text.utf8().data(), selectInsertedText);
525
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000526 AccessibilityReplacedText replacedText(document().selection().selection());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000527 insertText(text, selectInsertedText);
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000528 replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, text, document().selection().selection());
d_russell@apple.comd60eb242016-05-13 19:34:48 +0000529 composition()->setRangeDeletedByUnapply(replacedText.replacedRange());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000530}
531
darinb9481ed2006-03-20 02:57:59 +0000532void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool selectInsertedText)
mjs84e724c2005-05-24 07:21:47 +0000533{
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000534 if (!willAddTypingToOpenCommand(InsertText, TextGranularity::CharacterGranularity, text))
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000535 return;
536
cdumez@apple.com8f91d5b2017-05-01 18:08:07 +0000537 auto command = InsertTextCommand::create(document(), text, selectInsertedText,
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000538 m_compositionType == TextCompositionNone ? InsertTextCommand::RebalanceLeadingAndTrailingWhitespaces : InsertTextCommand::RebalanceAllWhitespaces, EditAction::TypingInsertText);
rniwa@webkit.org1a364302011-07-13 17:55:20 +0000539
cdumez@apple.com8f91d5b2017-05-01 18:08:07 +0000540 applyCommandToComposite(WTFMove(command), endingSelection());
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000541 typingAddedToOpenCommand(InsertText);
mjs84e724c2005-05-24 07:21:47 +0000542}
543
544void TypingCommand::insertLineBreak()
545{
jpu@apple.comdfd2ce62012-04-16 03:05:06 +0000546 if (!canAppendNewLineFeedToSelection(endingSelection()))
commit-queue@webkit.orgb887b8c2011-03-17 06:31:00 +0000547 return;
548
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000549 if (!willAddTypingToOpenCommand(InsertLineBreak, TextGranularity::LineGranularity))
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000550 return;
551
darin@apple.com48ac3c42008-06-14 08:46:51 +0000552 applyCommandToComposite(InsertLineBreakCommand::create(document()));
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000553 typingAddedToOpenCommand(InsertLineBreak);
mjs84e724c2005-05-24 07:21:47 +0000554}
555
d_russell@apple.com07f85592016-04-04 23:17:59 +0000556void TypingCommand::insertLineBreakAndNotifyAccessibility()
557{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000558 AccessibilityReplacedText replacedText(document().selection().selection());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000559 insertLineBreak();
cdumez@apple.comec2f5082022-03-28 21:20:09 +0000560 replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, "\n"_s, document().selection().selection());
d_russell@apple.comd60eb242016-05-13 19:34:48 +0000561 composition()->setRangeDeletedByUnapply(replacedText.replacedRange());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000562}
563
mjs84e724c2005-05-24 07:21:47 +0000564void TypingCommand::insertParagraphSeparator()
565{
jpu@apple.comdfd2ce62012-04-16 03:05:06 +0000566 if (!canAppendNewLineFeedToSelection(endingSelection()))
commit-queue@webkit.orgb887b8c2011-03-17 06:31:00 +0000567 return;
568
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000569 if (!willAddTypingToOpenCommand(InsertParagraphSeparator, TextGranularity::ParagraphGranularity))
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000570 return;
571
wenson_hsieh@apple.comea091012018-09-07 03:04:53 +0000572 applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), false, false, EditAction::TypingInsertParagraph));
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000573 typingAddedToOpenCommand(InsertParagraphSeparator);
mjs84e724c2005-05-24 07:21:47 +0000574}
575
d_russell@apple.com07f85592016-04-04 23:17:59 +0000576void TypingCommand::insertParagraphSeparatorAndNotifyAccessibility()
577{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000578 AccessibilityReplacedText replacedText(document().selection().selection());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000579 insertParagraphSeparator();
cdumez@apple.comec2f5082022-03-28 21:20:09 +0000580 replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, "\n"_s, document().selection().selection());
d_russell@apple.comd60eb242016-05-13 19:34:48 +0000581 composition()->setRangeDeletedByUnapply(replacedText.replacedRange());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000582}
583
mjs84e724c2005-05-24 07:21:47 +0000584void TypingCommand::insertParagraphSeparatorInQuotedContent()
585{
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000586 if (!willAddTypingToOpenCommand(InsertParagraphSeparatorInQuotedContent, TextGranularity::ParagraphGranularity))
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000587 return;
588
adele@apple.com65426e32009-04-12 05:49:44 +0000589 // If the selection starts inside a table, just insert the paragraph separator normally
590 // Breaking the blockquote would also break apart the table, which is unecessary when inserting a newline
591 if (enclosingNodeOfType(endingSelection().start(), &isTableStructureNode)) {
592 insertParagraphSeparator();
593 return;
594 }
595
darin@apple.com48ac3c42008-06-14 08:46:51 +0000596 applyCommandToComposite(BreakBlockquoteCommand::create(document()));
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000597 typingAddedToOpenCommand(InsertParagraphSeparatorInQuotedContent);
mjs84e724c2005-05-24 07:21:47 +0000598}
599
d_russell@apple.com07f85592016-04-04 23:17:59 +0000600void TypingCommand::insertParagraphSeparatorInQuotedContentAndNotifyAccessibility()
601{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000602 AccessibilityReplacedText replacedText(document().selection().selection());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000603 insertParagraphSeparatorInQuotedContent();
cdumez@apple.comec2f5082022-03-28 21:20:09 +0000604 replacedText.postTextStateChangeNotification(document().existingAXObjectCache(), AXTextEditTypeTyping, "\n"_s, document().selection().selection());
d_russell@apple.comd60eb242016-05-13 19:34:48 +0000605 composition()->setRangeDeletedByUnapply(replacedText.replacedRange());
d_russell@apple.com07f85592016-04-04 23:17:59 +0000606}
607
mitz@apple.com3d9a5082009-04-30 03:03:29 +0000608bool TypingCommand::makeEditableRootEmpty()
609{
610 Element* root = endingSelection().rootEditableElement();
eae@chromium.org480a4422011-03-29 12:10:05 +0000611 if (!root || !root->firstChild())
mitz@apple.com3d9a5082009-04-30 03:03:29 +0000612 return false;
613
614 if (root->firstChild() == root->lastChild() && root->firstElementChild() && root->firstElementChild()->hasTagName(brTag)) {
615 // If there is a single child and it could be a placeholder, leave it alone.
hyatt@apple.com7caec522013-09-09 18:37:33 +0000616 if (root->renderer() && root->renderer()->isRenderBlockFlow())
mitz@apple.com3d9a5082009-04-30 03:03:29 +0000617 return false;
618 }
619
620 while (Node* child = root->firstChild())
cdumez@apple.com2fecce72017-05-05 05:09:56 +0000621 removeNode(*child);
mitz@apple.com3d9a5082009-04-30 03:03:29 +0000622
623 addBlockPlaceholderIfNeeded(root);
darin@apple.comc8d8b552020-09-03 21:38:50 +0000624 setEndingSelection(VisibleSelection(firstPositionInNode(root), Affinity::Downstream, endingSelection().isDirectional()));
mitz@apple.com3d9a5082009-04-30 03:03:29 +0000625
626 return true;
627}
628
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000629void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool shouldAddToKillRing)
mjs84e724c2005-05-24 07:21:47 +0000630{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000631 RefPtr<Frame> protector(document().frame());
morrita@google.com7b933de2012-02-03 11:39:51 +0000632
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000633 document().editor().updateMarkersForWordsAffectedByEditing(false);
morrita@google.com4e40c8b2011-04-08 21:21:44 +0000634
eric@webkit.org87ea95c2009-02-09 21:43:24 +0000635 VisibleSelection selectionToDelete;
636 VisibleSelection selectionAfterUndo;
darin@apple.comc8d8b552020-09-03 21:38:50 +0000637 bool expandForSpecialElements = false;
commit-queue@webkit.org08abac62010-10-28 23:45:26 +0000638
darin@apple.comc8d8b552020-09-03 21:38:50 +0000639 ASSERT(endingSelection().isCaretOrRange());
640
641 if (endingSelection().isRange()) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000642 selectionToDelete = endingSelection();
643 selectionAfterUndo = selectionToDelete;
darin@apple.comc8d8b552020-09-03 21:38:50 +0000644 expandForSpecialElements = true;
645 } else {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000646 // After breaking out of an empty mail blockquote, we still want continue with the deletion
647 // so actual content will get deleted, and not just the quote style.
648 if (breakOutOfEmptyMailBlockquotedParagraph())
649 typingAddedToOpenCommand(DeleteKey);
darind4408fc2007-04-24 17:37:50 +0000650
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000651 m_smartDelete = false;
enrica@apple.combde8a9a2009-12-15 01:14:35 +0000652
rniwa@webkit.org78bbc942011-05-05 18:14:43 +0000653 FrameSelection selection;
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000654 selection.setSelection(endingSelection());
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000655 selection.modify(FrameSelection::AlterationExtend, SelectionDirection::Backward, granularity);
656 if (shouldAddToKillRing && selection.isCaret() && granularity != TextGranularity::CharacterGranularity)
657 selection.modify(FrameSelection::AlterationExtend, SelectionDirection::Backward, TextGranularity::CharacterGranularity);
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000658
jfernandez@igalia.com4bb32e82017-08-08 12:22:33 +0000659 const VisiblePosition& visibleStart = endingSelection().visibleStart();
660 const VisiblePosition& previousPosition = visibleStart.previous(CannotCrossEditingBoundary);
661 Node* enclosingTableCell = enclosingNodeOfType(visibleStart.deepEquivalent(), &isTableCell);
662 const Node* enclosingTableCellForPreviousPosition = enclosingNodeOfType(previousPosition.deepEquivalent(), &isTableCell);
663 if (previousPosition.isNull() || enclosingTableCell != enclosingTableCellForPreviousPosition) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000664 // When the caret is at the start of the editable area in an empty list item, break out of the list item.
commit-queue@webkit.orgff9eed32021-08-31 08:39:52 +0000665 if (auto deleteListSelection = shouldBreakOutOfEmptyListItem(); !deleteListSelection.isNone()) {
666 if (willAddTypingToOpenCommand(DeleteKey, granularity, { }, deleteListSelection.firstRange())) {
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000667 breakOutOfEmptyListItem();
668 typingAddedToOpenCommand(DeleteKey);
669 }
lweintraub6d377802006-07-07 19:33:28 +0000670 return;
671 }
jfernandez@igalia.com4bb32e82017-08-08 12:22:33 +0000672 }
673 if (previousPosition.isNull()) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000674 // When there are no visible positions in the editing root, delete its entire contents.
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000675 // FIXME: Dispatch a `beforeinput` event here and bail if preventDefault() was invoked.
jfernandez@igalia.com4bb32e82017-08-08 12:22:33 +0000676 if (visibleStart.next(CannotCrossEditingBoundary).isNull() && makeEditableRootEmpty()) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000677 typingAddedToOpenCommand(DeleteKey);
678 return;
ap@webkit.orgee2987b2008-12-10 12:49:56 +0000679 }
mjs84e724c2005-05-24 07:21:47 +0000680 }
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000681
commit-queue@webkit.org66c34e42013-03-15 04:25:27 +0000682 // If we have a caret selection at the beginning of a cell, we have nothing to do.
commit-queue@webkit.org66c34e42013-03-15 04:25:27 +0000683 if (enclosingTableCell && visibleStart == firstPositionInNode(enclosingTableCell))
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000684 return;
685
686 // If the caret is at the start of a paragraph after a table, move content into the last table cell.
rniwa@webkit.orgea702ba2011-03-10 21:15:45 +0000687 if (isStartOfParagraph(visibleStart) && isFirstPositionAfterTable(visibleStart.previous(CannotCrossEditingBoundary))) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000688 // Unless the caret is just before a table. We don't want to move a table into the last table cell.
689 if (isLastPositionBeforeTable(visibleStart))
690 return;
691 // Extend the selection backward into the last cell, then deletion will handle the move.
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000692 selection.modify(FrameSelection::AlterationExtend, SelectionDirection::Backward, granularity);
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000693 // If the caret is just after a table, select the table and don't delete anything.
694 } else if (Node* table = isFirstPositionAfterTable(visibleStart)) {
darin@apple.comc8d8b552020-09-03 21:38:50 +0000695 setEndingSelection(VisibleSelection(positionBeforeNode(table), endingSelection().start(), Affinity::Downstream, endingSelection().isDirectional()));
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000696 typingAddedToOpenCommand(DeleteKey);
697 return;
698 }
699
700 selectionToDelete = selection.selection();
701
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000702 if (granularity == TextGranularity::CharacterGranularity && selectionToDelete.end().containerNode() == selectionToDelete.start().containerNode()
rniwa@webkit.org5b6a7522011-04-20 01:18:03 +0000703 && selectionToDelete.end().computeOffsetInContainerNode() - selectionToDelete.start().computeOffsetInContainerNode() > 1) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000704 // If there are multiple Unicode code points to be deleted, adjust the range to match platform conventions.
705 selectionToDelete.setWithoutValidation(selectionToDelete.end(), selectionToDelete.end().previous(BackwardDeletion));
706 }
707
708 if (!startingSelection().isRange() || selectionToDelete.base() != startingSelection().start())
709 selectionAfterUndo = selectionToDelete;
710 else
711 // It's a little tricky to compute what the starting selection would have been in the original document.
712 // We can't let the VisibleSelection class's validation kick in or it'll adjust for us based on
713 // the current state of the document and we'll get the wrong result.
714 selectionAfterUndo.setWithoutValidation(startingSelection().end(), selectionToDelete.extent());
mjs84e724c2005-05-24 07:21:47 +0000715 }
716
justin.garcia@apple.com313f2152009-03-06 01:25:40 +0000717 ASSERT(!selectionToDelete.isNone());
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000718 if (selectionToDelete.isNone()) {
ap@apple.com1e8475922018-10-18 21:38:50 +0000719#if PLATFORM(IOS_FAMILY)
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000720 // Workaround for this bug:
721 // <rdar://problem/4653755> UIKit text widgets should use WebKit editing API to manipulate text
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000722 setEndingSelection(document().selection().selection());
723 closeTyping(document());
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000724#endif
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000725 return;
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000726 }
darin@apple.comc8d8b552020-09-03 21:38:50 +0000727
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000728 if (selectionToDelete.isCaret() || !document().selection().shouldDeleteSelection(selectionToDelete))
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000729 return;
darin@apple.comc8d8b552020-09-03 21:38:50 +0000730
darin@apple.com5d3decc2020-08-01 15:50:36 +0000731 if (!willAddTypingToOpenCommand(DeleteKey, granularity, { }, selectionToDelete.firstRange()))
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000732 return;
733
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000734 if (shouldAddToKillRing)
darin@apple.comf91ef172020-08-03 00:47:52 +0000735 document().editor().addRangeToKillRing(*selectionToDelete.toNormalizedRange(), Editor::KillRingInsertionMode::PrependText);
d_russell@apple.com07f85592016-04-04 23:17:59 +0000736
737 // Post the accessibility notification before actually deleting the content while selectionToDelete is still valid
738 postTextStateChangeNotificationForDeletion(selectionToDelete);
739
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000740 // Make undo select everything that has been deleted, unless an undo will undo more than just this deletion.
741 // FIXME: This behaves like TextEdit except for the case where you open with text insertion and then delete
742 // more text than you insert. In that case all of the text that was around originally should be selected.
743 if (m_openedByBackwardDelete)
744 setStartingSelection(selectionAfterUndo);
jfernandez@igalia.com736db5b2018-07-17 08:48:49 +0000745 CompositeEditCommand::deleteSelection(selectionToDelete, m_smartDelete, /* mergeBlocksAfterDelete*/ true, /* replace*/ false, expandForSpecialElements, /*sanitizeMarkup*/ true);
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000746 setSmartDelete(false);
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000747 typingAddedToOpenCommand(DeleteKey);
mjs84e724c2005-05-24 07:21:47 +0000748}
749
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000750void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool shouldAddToKillRing)
mjs84e724c2005-05-24 07:21:47 +0000751{
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000752 RefPtr<Frame> protector(document().frame());
morrita@google.com7b933de2012-02-03 11:39:51 +0000753
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000754 document().editor().updateMarkersForWordsAffectedByEditing(false);
morrita@google.com4e40c8b2011-04-08 21:21:44 +0000755
eric@webkit.org87ea95c2009-02-09 21:43:24 +0000756 VisibleSelection selectionToDelete;
757 VisibleSelection selectionAfterUndo;
darin@apple.comc8d8b552020-09-03 21:38:50 +0000758 bool expandForSpecialElements = false;
darind4408fc2007-04-24 17:37:50 +0000759
darin@apple.comc8d8b552020-09-03 21:38:50 +0000760 ASSERT(endingSelection().isCaretOrRange());
761
762 if (endingSelection().isRange()) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000763 selectionToDelete = endingSelection();
764 selectionAfterUndo = selectionToDelete;
darin@apple.comc8d8b552020-09-03 21:38:50 +0000765 expandForSpecialElements = true;
766 } else {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000767 m_smartDelete = false;
darind4408fc2007-04-24 17:37:50 +0000768
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000769 // Handle delete at beginning-of-block case.
770 // Do nothing in the case that the caret is at the start of a
771 // root editable element or at the start of a document.
rniwa@webkit.org78bbc942011-05-05 18:14:43 +0000772 FrameSelection selection;
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000773 selection.setSelection(endingSelection());
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000774 selection.modify(FrameSelection::AlterationExtend, SelectionDirection::Forward, granularity);
shihchieh_lee@apple.comda81f1e2020-04-15 21:57:22 +0000775 if (selection.isNone())
776 return;
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000777 if (shouldAddToKillRing && selection.isCaret() && granularity != TextGranularity::CharacterGranularity)
778 selection.modify(FrameSelection::AlterationExtend, SelectionDirection::Forward, TextGranularity::CharacterGranularity);
harrison5eb15992006-12-20 15:40:34 +0000779
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000780 Position downstreamEnd = endingSelection().end().downstream();
781 VisiblePosition visibleEnd = endingSelection().visibleEnd();
commit-queue@webkit.org66c34e42013-03-15 04:25:27 +0000782 Node* enclosingTableCell = enclosingNodeOfType(visibleEnd.deepEquivalent(), &isTableCell);
783 if (enclosingTableCell && visibleEnd == lastPositionInNode(enclosingTableCell))
commit-queue@webkit.orgb38d5132012-07-30 05:22:58 +0000784 return;
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000785 if (visibleEnd == endOfParagraph(visibleEnd))
rniwa@webkit.orgea702ba2011-03-10 21:15:45 +0000786 downstreamEnd = visibleEnd.next(CannotCrossEditingBoundary).deepEquivalent().downstream();
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000787 // When deleting tables: Select the table first, then perform the deletion
rniwa@webkit.org5b6a7522011-04-20 01:18:03 +0000788 if (downstreamEnd.containerNode() && downstreamEnd.containerNode()->renderer() && downstreamEnd.containerNode()->renderer()->isTable()
darin@apple.comd385be42016-05-14 20:09:50 +0000789 && downstreamEnd.computeOffsetInContainerNode() <= caretMinOffset(*downstreamEnd.containerNode())) {
darin@apple.comc8d8b552020-09-03 21:38:50 +0000790 setEndingSelection(VisibleSelection(endingSelection().end(), positionAfterNode(downstreamEnd.containerNode()), Affinity::Downstream, endingSelection().isDirectional()));
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000791 typingAddedToOpenCommand(ForwardDeleteKey);
792 return;
mjs84e724c2005-05-24 07:21:47 +0000793 }
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000794
795 // deleting to end of paragraph when at end of paragraph needs to merge the next paragraph (if any)
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000796 if (granularity == TextGranularity::ParagraphBoundary && selection.selection().isCaret() && isEndOfParagraph(selection.selection().visibleEnd()))
797 selection.modify(FrameSelection::AlterationExtend, SelectionDirection::Forward, TextGranularity::CharacterGranularity);
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000798
799 selectionToDelete = selection.selection();
800 if (!startingSelection().isRange() || selectionToDelete.base() != startingSelection().start())
801 selectionAfterUndo = selectionToDelete;
802 else {
803 // It's a little tricky to compute what the starting selection would have been in the original document.
804 // We can't let the VisibleSelection class's validation kick in or it'll adjust for us based on
805 // the current state of the document and we'll get the wrong result.
806 Position extent = startingSelection().end();
rniwa@webkit.org5b6a7522011-04-20 01:18:03 +0000807 if (extent.containerNode() != selectionToDelete.end().containerNode())
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000808 extent = selectionToDelete.extent();
809 else {
810 int extraCharacters;
rniwa@webkit.org5b6a7522011-04-20 01:18:03 +0000811 if (selectionToDelete.start().containerNode() == selectionToDelete.end().containerNode())
812 extraCharacters = selectionToDelete.end().computeOffsetInContainerNode() - selectionToDelete.start().computeOffsetInContainerNode();
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000813 else
rniwa@webkit.org5b6a7522011-04-20 01:18:03 +0000814 extraCharacters = selectionToDelete.end().computeOffsetInContainerNode();
815 extent = Position(extent.containerNode(), extent.computeOffsetInContainerNode() + extraCharacters, Position::PositionIsOffsetInAnchor);
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000816 }
817 selectionAfterUndo.setWithoutValidation(startingSelection().start(), extent);
818 }
mjs84e724c2005-05-24 07:21:47 +0000819 }
820
justin.garcia@apple.com313f2152009-03-06 01:25:40 +0000821 ASSERT(!selectionToDelete.isNone());
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000822 if (selectionToDelete.isNone()) {
ap@apple.com1e8475922018-10-18 21:38:50 +0000823#if PLATFORM(IOS_FAMILY)
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000824 // Workaround for this bug:
825 // <rdar://problem/4653755> UIKit text widgets should use WebKit editing API to manipulate text
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000826 setEndingSelection(document().selection().selection());
827 closeTyping(document());
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000828#endif
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000829 return;
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000830 }
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000831
shihchieh_lee@apple.com501b37c2020-04-28 16:36:38 +0000832 if (selectionToDelete.isCaret() || !document().selection().shouldDeleteSelection(selectionToDelete))
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000833 return;
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000834
darin@apple.com5d3decc2020-08-01 15:50:36 +0000835 if (!willAddTypingToOpenCommand(ForwardDeleteKey, granularity, { }, selectionToDelete.firstRange()))
wenson_hsieh@apple.com6ed4b152016-10-21 15:51:28 +0000836 return;
837
d_russell@apple.com07f85592016-04-04 23:17:59 +0000838 // Post the accessibility notification before actually deleting the content while selectionToDelete is still valid
839 postTextStateChangeNotificationForDeletion(selectionToDelete);
840
bburg@apple.comf4fb5bb2015-11-19 19:29:59 +0000841 if (shouldAddToKillRing)
darin@apple.comf91ef172020-08-03 00:47:52 +0000842 document().editor().addRangeToKillRing(*selectionToDelete.toNormalizedRange(), Editor::KillRingInsertionMode::AppendText);
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000843 // make undo select what was deleted
844 setStartingSelection(selectionAfterUndo);
jfernandez@igalia.com736db5b2018-07-17 08:48:49 +0000845 CompositeEditCommand::deleteSelection(selectionToDelete, m_smartDelete, /* mergeBlocksAfterDelete*/ true, /* replace*/ false, expandForSpecialElements, /*sanitizeMarkup*/ true);
justin.garcia@apple.com0e8bd792009-03-06 01:00:29 +0000846 setSmartDelete(false);
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000847 typingAddedToOpenCommand(ForwardDeleteKey);
mjs84e724c2005-05-24 07:21:47 +0000848}
849
justingee38ac82007-10-25 00:58:54 +0000850void TypingCommand::deleteSelection(bool smartDelete)
851{
commit-queue@webkit.org2dd35882020-05-16 03:45:59 +0000852 if (!willAddTypingToOpenCommand(DeleteSelection, TextGranularity::CharacterGranularity))
wenson_hsieh@apple.com2bebcde2016-10-07 23:47:18 +0000853 return;
854
justingee38ac82007-10-25 00:58:54 +0000855 CompositeEditCommand::deleteSelection(smartDelete);
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000856 typingAddedToOpenCommand(DeleteSelection);
justingee38ac82007-10-25 00:58:54 +0000857}
858
ap@apple.com1e8475922018-10-18 21:38:50 +0000859#if PLATFORM(IOS_FAMILY)
dbates@webkit.orgf435ee12014-01-10 17:06:52 +0000860class FriendlyEditCommand : public EditCommand {
861public:
862 void setEndingSelection(const VisibleSelection& selection)
863 {
864 EditCommand::setEndingSelection(selection);
865 }
866};
867
868void TypingCommand::setEndingSelectionOnLastInsertCommand(const VisibleSelection& selection)
869{
870 if (!m_commands.isEmpty()) {
871 EditCommand* lastCommand = m_commands.last().get();
872 if (lastCommand->isInsertTextCommand())
873 static_cast<FriendlyEditCommand*>(lastCommand)->setEndingSelection(selection);
874 }
875}
876#endif
877
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000878void TypingCommand::updatePreservesTypingStyle(ETypingCommand commandType)
mjs84e724c2005-05-24 07:21:47 +0000879{
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000880 switch (commandType) {
eric@webkit.orgb0988e22010-05-31 00:51:55 +0000881 case DeleteSelection:
882 case DeleteKey:
883 case ForwardDeleteKey:
884 case InsertParagraphSeparator:
885 case InsertLineBreak:
886 m_preservesTypingStyle = true;
887 return;
888 case InsertParagraphSeparatorInQuotedContent:
889 case InsertText:
890 m_preservesTypingStyle = false;
891 return;
mjs84e724c2005-05-24 07:21:47 +0000892 }
893 ASSERT_NOT_REACHED();
adele@apple.com03d6c3a2009-06-26 16:53:24 +0000894 m_preservesTypingStyle = false;
mjs84e724c2005-05-24 07:21:47 +0000895}
896
897bool TypingCommand::isTypingCommand() const
898{
899 return true;
900}
901
darinb9481ed2006-03-20 02:57:59 +0000902} // namespace WebCore