1 /*
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies)
4 * Copyright (C) 2009 Igalia S.L.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
16 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
18 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
19 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
20 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
22 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
23 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
25 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 #include "third_party/blink/renderer/core/editing/commands/editor_command.h"
29
30 #include "third_party/blink/public/platform/platform.h"
31 #include "third_party/blink/renderer/core/css/css_property_names.h"
32 #include "third_party/blink/renderer/core/css/css_property_value_set.h"
33 #include "third_party/blink/renderer/core/css_value_keywords.h"
34 #include "third_party/blink/renderer/core/dom/events/event.h"
35 #include "third_party/blink/renderer/core/dom/tag_collection.h"
36 #include "third_party/blink/renderer/core/editing/commands/clipboard_commands.h"
37 #include "third_party/blink/renderer/core/editing/commands/create_link_command.h"
38 #include "third_party/blink/renderer/core/editing/commands/editing_command_type.h"
39 #include "third_party/blink/renderer/core/editing/commands/editing_commands_utilities.h"
40 #include "third_party/blink/renderer/core/editing/commands/editor_command_names.h"
41 #include "third_party/blink/renderer/core/editing/commands/format_block_command.h"
42 #include "third_party/blink/renderer/core/editing/commands/indent_outdent_command.h"
43 #include "third_party/blink/renderer/core/editing/commands/insert_commands.h"
44 #include "third_party/blink/renderer/core/editing/commands/move_commands.h"
45 #include "third_party/blink/renderer/core/editing/commands/remove_format_command.h"
46 #include "third_party/blink/renderer/core/editing/commands/style_commands.h"
47 #include "third_party/blink/renderer/core/editing/commands/typing_command.h"
48 #include "third_party/blink/renderer/core/editing/commands/unlink_command.h"
49 #include "third_party/blink/renderer/core/editing/editing_tri_state.h"
50 #include "third_party/blink/renderer/core/editing/editing_utilities.h"
51 #include "third_party/blink/renderer/core/editing/editor.h"
52 #include "third_party/blink/renderer/core/editing/ephemeral_range.h"
53 #include "third_party/blink/renderer/core/editing/frame_selection.h"
54 #include "third_party/blink/renderer/core/editing/iterators/text_iterator.h"
55 #include "third_party/blink/renderer/core/editing/kill_ring.h"
56 #include "third_party/blink/renderer/core/editing/selection_modifier.h"
57 #include "third_party/blink/renderer/core/editing/selection_template.h"
58 #include "third_party/blink/renderer/core/editing/set_selection_options.h"
59 #include "third_party/blink/renderer/core/editing/spellcheck/spell_checker.h"
60 #include "third_party/blink/renderer/core/editing/visible_position.h"
61 #include "third_party/blink/renderer/core/frame/local_frame.h"
62 #include "third_party/blink/renderer/core/frame/local_frame_view.h"
63 #include "third_party/blink/renderer/core/frame/settings.h"
64 #include "third_party/blink/renderer/core/html/html_br_element.h"
65 #include "third_party/blink/renderer/core/html_names.h"
66 #include "third_party/blink/renderer/core/input/event_handler.h"
67 #include "third_party/blink/renderer/core/page/chrome_client.h"
68 #include "third_party/blink/renderer/core/page/page.h"
69 #include "third_party/blink/renderer/core/scroll/scrollbar.h"
70 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
71 #include "third_party/blink/renderer/platform/heap/heap.h"
72 #include "third_party/blink/renderer/platform/instrumentation/histogram.h"
73 #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
74 #include "third_party/blink/renderer/platform/wtf/text/atomic_string.h"
75
76 #include <iterator>
77
78 namespace blink {
79
80 namespace {
81
82 struct CommandNameEntry {
83 const char* name;
84 EditingCommandType type;
85 };
86
87 const CommandNameEntry kCommandNameEntries[] = {
88 #define V(name) {#name, EditingCommandType::k##name},
89 FOR_EACH_BLINK_EDITING_COMMAND_NAME(V)
90 #undef V
91 };
92 // Handles all commands except EditingCommandType::Invalid.
93 static_assert(
94 base::size(kCommandNameEntries) + 1 ==
95 static_cast<size_t>(EditingCommandType::kNumberOfCommandTypes),
96 "must handle all valid EditingCommandType");
97
EditingCommandTypeFromCommandName(const String & command_name)98 EditingCommandType EditingCommandTypeFromCommandName(
99 const String& command_name) {
100 const CommandNameEntry* result = std::lower_bound(
101 std::begin(kCommandNameEntries), std::end(kCommandNameEntries),
102 command_name, [](const CommandNameEntry& entry, const String& needle) {
103 return CodeUnitCompareIgnoringASCIICase(needle, entry.name) > 0;
104 });
105 if (result != std::end(kCommandNameEntries) &&
106 CodeUnitCompareIgnoringASCIICase(command_name, result->name) == 0)
107 return result->type;
108 return EditingCommandType::kInvalid;
109 }
110
111 // |frame| is only used for |InsertNewline| due to how |executeInsertNewline()|
112 // works.
InputTypeFromCommandType(EditingCommandType command_type,LocalFrame & frame)113 InputEvent::InputType InputTypeFromCommandType(EditingCommandType command_type,
114 LocalFrame& frame) {
115 // We only handle InputType on spec for 'beforeinput'.
116 // http://w3c.github.io/editing/input-events.html
117 using CommandType = EditingCommandType;
118 using InputType = InputEvent::InputType;
119
120 // |executeInsertNewline()| could do two things but we have no other ways to
121 // predict.
122 if (command_type == CommandType::kInsertNewline)
123 return frame.GetEditor().CanEditRichly() ? InputType::kInsertParagraph
124 : InputType::kInsertLineBreak;
125
126 switch (command_type) {
127 // Insertion.
128 case CommandType::kInsertBacktab:
129 case CommandType::kInsertText:
130 return InputType::kInsertText;
131 case CommandType::kInsertLineBreak:
132 return InputType::kInsertLineBreak;
133 case CommandType::kInsertParagraph:
134 case CommandType::kInsertNewlineInQuotedContent:
135 return InputType::kInsertParagraph;
136 case CommandType::kInsertHorizontalRule:
137 return InputType::kInsertHorizontalRule;
138 case CommandType::kInsertOrderedList:
139 return InputType::kInsertOrderedList;
140 case CommandType::kInsertUnorderedList:
141 return InputType::kInsertUnorderedList;
142
143 // Deletion.
144 case CommandType::kDelete:
145 case CommandType::kDeleteBackward:
146 case CommandType::kDeleteBackwardByDecomposingPreviousCharacter:
147 return InputType::kDeleteContentBackward;
148 case CommandType::kDeleteForward:
149 return InputType::kDeleteContentForward;
150 case CommandType::kDeleteToBeginningOfLine:
151 return InputType::kDeleteSoftLineBackward;
152 case CommandType::kDeleteToEndOfLine:
153 return InputType::kDeleteSoftLineForward;
154 case CommandType::kDeleteWordBackward:
155 return InputType::kDeleteWordBackward;
156 case CommandType::kDeleteWordForward:
157 return InputType::kDeleteWordForward;
158 case CommandType::kDeleteToBeginningOfParagraph:
159 return InputType::kDeleteHardLineBackward;
160 case CommandType::kDeleteToEndOfParagraph:
161 return InputType::kDeleteHardLineForward;
162 // TODO(editing-dev): Find appreciate InputType for following commands.
163 case CommandType::kDeleteToMark:
164 return InputType::kNone;
165
166 // Command.
167 case CommandType::kUndo:
168 return InputType::kHistoryUndo;
169 case CommandType::kRedo:
170 return InputType::kHistoryRedo;
171 // Cut and Paste will be handled in |Editor::dispatchCPPEvent()|.
172
173 // Styling.
174 case CommandType::kBold:
175 case CommandType::kToggleBold:
176 return InputType::kFormatBold;
177 case CommandType::kItalic:
178 case CommandType::kToggleItalic:
179 return InputType::kFormatItalic;
180 case CommandType::kUnderline:
181 case CommandType::kToggleUnderline:
182 return InputType::kFormatUnderline;
183 case CommandType::kStrikethrough:
184 return InputType::kFormatStrikeThrough;
185 case CommandType::kSuperscript:
186 return InputType::kFormatSuperscript;
187 case CommandType::kSubscript:
188 return InputType::kFormatSubscript;
189 default:
190 return InputType::kNone;
191 }
192 }
193
RangesFromCurrentSelectionOrExtendCaret(const LocalFrame & frame,SelectionModifyDirection direction,TextGranularity granularity)194 StaticRangeVector* RangesFromCurrentSelectionOrExtendCaret(
195 const LocalFrame& frame,
196 SelectionModifyDirection direction,
197 TextGranularity granularity) {
198 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
199 SelectionModifier selection_modifier(
200 frame, frame.Selection().GetSelectionInDOMTree());
201 selection_modifier.SetSelectionIsDirectional(
202 frame.Selection().IsDirectional());
203 if (selection_modifier.Selection().IsCaret())
204 selection_modifier.Modify(SelectionModifyAlteration::kExtend, direction,
205 granularity);
206 StaticRangeVector* ranges = MakeGarbageCollected<StaticRangeVector>();
207 // We only supports single selections.
208 if (selection_modifier.Selection().IsNone())
209 return ranges;
210 ranges->push_back(StaticRange::Create(
211 FirstEphemeralRangeOf(selection_modifier.Selection())));
212 return ranges;
213 }
214
ComputeRangeForTranspose(LocalFrame & frame)215 EphemeralRange ComputeRangeForTranspose(LocalFrame& frame) {
216 const VisibleSelection& selection =
217 frame.Selection().ComputeVisibleSelectionInDOMTree();
218 if (!selection.IsCaret())
219 return EphemeralRange();
220
221 // Make a selection that goes back one character and forward two characters.
222 const VisiblePosition& caret = selection.VisibleStart();
223 const VisiblePosition& next =
224 IsEndOfParagraph(caret) ? caret : NextPositionOf(caret);
225 const VisiblePosition& previous = PreviousPositionOf(next);
226 if (next.DeepEquivalent() == previous.DeepEquivalent())
227 return EphemeralRange();
228 const VisiblePosition& previous_of_previous = PreviousPositionOf(previous);
229 if (!InSameParagraph(next, previous_of_previous))
230 return EphemeralRange();
231 return MakeRange(previous_of_previous, next);
232 }
233
234 } // anonymous namespace
235
236 class EditorInternalCommand {
237 STACK_ALLOCATED();
238
239 public:
240 EditingCommandType command_type;
241 bool (*execute)(LocalFrame&, Event*, EditorCommandSource, const String&);
242 bool (*is_supported_from_dom)(LocalFrame*);
243 bool (*is_enabled)(LocalFrame&, Event*, EditorCommandSource);
244 EditingTriState (*state)(LocalFrame&, Event*);
245 String (*value)(const EditorInternalCommand&, LocalFrame&, Event*);
246 bool is_text_insertion;
247 bool (*can_execute)(LocalFrame&, EditorCommandSource);
248 };
249
250 static const bool kNotTextInsertion = false;
251 static const bool kIsTextInsertion = true;
252
ExecuteApplyParagraphStyle(LocalFrame & frame,EditorCommandSource source,InputEvent::InputType input_type,CSSPropertyID property_id,const String & property_value)253 static bool ExecuteApplyParagraphStyle(LocalFrame& frame,
254 EditorCommandSource source,
255 InputEvent::InputType input_type,
256 CSSPropertyID property_id,
257 const String& property_value) {
258 auto* style =
259 MakeGarbageCollected<MutableCSSPropertyValueSet>(kHTMLQuirksMode);
260 style->SetProperty(property_id, property_value, /* important */ false,
261 frame.GetDocument()->GetSecureContextMode());
262 // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a
263 // good reason for that?
264 switch (source) {
265 case EditorCommandSource::kMenuOrKeyBinding:
266 frame.GetEditor().ApplyParagraphStyleToSelection(style, input_type);
267 return true;
268 case EditorCommandSource::kDOM:
269 frame.GetEditor().ApplyParagraphStyle(style, input_type);
270 return true;
271 }
272 NOTREACHED();
273 return false;
274 }
275
ExpandSelectionToGranularity(LocalFrame & frame,TextGranularity granularity)276 bool ExpandSelectionToGranularity(LocalFrame& frame,
277 TextGranularity granularity) {
278 const VisibleSelection& selection = CreateVisibleSelectionWithGranularity(
279 SelectionInDOMTree::Builder()
280 .SetBaseAndExtent(
281 frame.Selection().ComputeVisibleSelectionInDOMTree().Base(),
282 frame.Selection().ComputeVisibleSelectionInDOMTree().Extent())
283 .Build(),
284 granularity);
285 const EphemeralRange new_range = selection.ToNormalizedEphemeralRange();
286 if (new_range.IsNull())
287 return false;
288 if (new_range.IsCollapsed())
289 return false;
290 frame.Selection().SetSelection(
291 SelectionInDOMTree::Builder().SetBaseAndExtent(new_range).Build(),
292 SetSelectionOptions::Builder().SetShouldCloseTyping(true).Build());
293 return true;
294 }
295
HasChildTags(Element & element,const QualifiedName & tag_name)296 static bool HasChildTags(Element& element, const QualifiedName& tag_name) {
297 return !element.getElementsByTagName(tag_name.LocalName())->IsEmpty();
298 }
299
SelectionListState(const FrameSelection & selection,const QualifiedName & tag_name)300 static EditingTriState SelectionListState(const FrameSelection& selection,
301 const QualifiedName& tag_name) {
302 if (selection.ComputeVisibleSelectionInDOMTreeDeprecated().IsCaret()) {
303 if (EnclosingElementWithTag(
304 selection.ComputeVisibleSelectionInDOMTreeDeprecated().Start(),
305 tag_name))
306 return EditingTriState::kTrue;
307 } else if (selection.ComputeVisibleSelectionInDOMTreeDeprecated().IsRange()) {
308 Element* start_element = EnclosingElementWithTag(
309 selection.ComputeVisibleSelectionInDOMTreeDeprecated().Start(),
310 tag_name);
311 Element* end_element = EnclosingElementWithTag(
312 selection.ComputeVisibleSelectionInDOMTreeDeprecated().End(), tag_name);
313
314 if (start_element && end_element && start_element == end_element) {
315 // If the selected list has the different type of list as child, return
316 // |FalseTriState|.
317 // See http://crbug.com/385374
318 if (HasChildTags(*start_element, tag_name.Matches(html_names::kUlTag)
319 ? html_names::kOlTag
320 : html_names::kUlTag))
321 return EditingTriState::kFalse;
322 return EditingTriState::kTrue;
323 }
324 }
325
326 return EditingTriState::kFalse;
327 }
328
UnionEphemeralRanges(const EphemeralRange & range1,const EphemeralRange & range2)329 static EphemeralRange UnionEphemeralRanges(const EphemeralRange& range1,
330 const EphemeralRange& range2) {
331 const Position start_position =
332 range1.StartPosition().CompareTo(range2.StartPosition()) <= 0
333 ? range1.StartPosition()
334 : range2.StartPosition();
335 const Position end_position =
336 range1.EndPosition().CompareTo(range2.EndPosition()) <= 0
337 ? range1.EndPosition()
338 : range2.EndPosition();
339 return EphemeralRange(start_position, end_position);
340 }
341
342 // Execute command functions
343
CanSmartCopyOrDelete(LocalFrame & frame)344 static bool CanSmartCopyOrDelete(LocalFrame& frame) {
345 return frame.GetEditor().SmartInsertDeleteEnabled() &&
346 frame.Selection().Granularity() == TextGranularity::kWord;
347 }
348
ExecuteCreateLink(LocalFrame & frame,Event *,EditorCommandSource,const String & value)349 static bool ExecuteCreateLink(LocalFrame& frame,
350 Event*,
351 EditorCommandSource,
352 const String& value) {
353 if (value.IsEmpty())
354 return false;
355 DCHECK(frame.GetDocument());
356 return MakeGarbageCollected<CreateLinkCommand>(*frame.GetDocument(), value)
357 ->Apply();
358 }
359
ExecuteDefaultParagraphSeparator(LocalFrame & frame,Event *,EditorCommandSource,const String & value)360 static bool ExecuteDefaultParagraphSeparator(LocalFrame& frame,
361 Event*,
362 EditorCommandSource,
363 const String& value) {
364 if (EqualIgnoringASCIICase(value, "div")) {
365 frame.GetEditor().SetDefaultParagraphSeparator(
366 EditorParagraphSeparator::kIsDiv);
367 return true;
368 }
369 if (EqualIgnoringASCIICase(value, "p")) {
370 frame.GetEditor().SetDefaultParagraphSeparator(
371 EditorParagraphSeparator::kIsP);
372 }
373 return true;
374 }
375
PerformDelete(LocalFrame & frame)376 static void PerformDelete(LocalFrame& frame) {
377 if (!frame.GetEditor().CanDelete())
378 return;
379
380 // TODO(editing-dev): The use of UpdateStyleAndLayout
381 // needs to be audited. See http://crbug.com/590369 for more details.
382 // |SelectedRange| requires clean layout for visible selection normalization.
383 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
384
385 frame.GetEditor().AddToKillRing(frame.GetEditor().SelectedRange());
386 // TODO(editing-dev): |Editor::performDelete()| has no direction.
387 // https://github.com/w3c/editing/issues/130
388 frame.GetEditor().DeleteSelectionWithSmartDelete(
389 CanSmartCopyOrDelete(frame) ? DeleteMode::kSmart : DeleteMode::kSimple,
390 InputEvent::InputType::kDeleteContentBackward);
391
392 // clear the "start new kill ring sequence" setting, because it was set to
393 // true when the selection was updated by deleting the range
394 frame.GetEditor().SetStartNewKillRingSequence(false);
395 }
396
ExecuteDelete(LocalFrame & frame,Event *,EditorCommandSource source,const String &)397 static bool ExecuteDelete(LocalFrame& frame,
398 Event*,
399 EditorCommandSource source,
400 const String&) {
401 switch (source) {
402 case EditorCommandSource::kMenuOrKeyBinding: {
403 // Doesn't modify the text if the current selection isn't a range.
404 PerformDelete(frame);
405 return true;
406 }
407 case EditorCommandSource::kDOM:
408 // If the current selection is a caret, delete the preceding character. IE
409 // performs forwardDelete, but we currently side with Firefox. Doesn't
410 // scroll to make the selection visible, or modify the kill ring (this
411 // time, siding with IE, not Firefox).
412 DCHECK(frame.GetDocument());
413 TypingCommand::DeleteKeyPressed(
414 *frame.GetDocument(),
415 frame.Selection().Granularity() == TextGranularity::kWord
416 ? TypingCommand::kSmartDelete
417 : 0);
418 return true;
419 }
420 NOTREACHED();
421 return false;
422 }
423
DeleteWithDirection(LocalFrame & frame,DeleteDirection direction,TextGranularity granularity,bool kill_ring,bool is_typing_action)424 static bool DeleteWithDirection(LocalFrame& frame,
425 DeleteDirection direction,
426 TextGranularity granularity,
427 bool kill_ring,
428 bool is_typing_action) {
429 Editor& editor = frame.GetEditor();
430 if (!editor.CanEdit())
431 return false;
432
433 EditingState editing_state;
434 if (frame.Selection()
435 .ComputeVisibleSelectionInDOMTreeDeprecated()
436 .IsRange()) {
437 if (is_typing_action) {
438 DCHECK(frame.GetDocument());
439 TypingCommand::DeleteKeyPressed(
440 *frame.GetDocument(),
441 CanSmartCopyOrDelete(frame) ? TypingCommand::kSmartDelete : 0,
442 granularity);
443 editor.RevealSelectionAfterEditingOperation();
444 } else {
445 if (kill_ring)
446 editor.AddToKillRing(editor.SelectedRange());
447 editor.DeleteSelectionWithSmartDelete(
448 CanSmartCopyOrDelete(frame) ? DeleteMode::kSmart
449 : DeleteMode::kSimple,
450 DeletionInputTypeFromTextGranularity(direction, granularity));
451 // Implicitly calls revealSelectionAfterEditingOperation().
452 }
453 } else {
454 TypingCommand::Options options = 0;
455 if (CanSmartCopyOrDelete(frame))
456 options |= TypingCommand::kSmartDelete;
457 if (kill_ring)
458 options |= TypingCommand::kKillRing;
459 switch (direction) {
460 case DeleteDirection::kForward:
461 DCHECK(frame.GetDocument());
462 TypingCommand::ForwardDeleteKeyPressed(
463 *frame.GetDocument(), &editing_state, options, granularity);
464 if (editing_state.IsAborted())
465 return false;
466 break;
467 case DeleteDirection::kBackward:
468 DCHECK(frame.GetDocument());
469 TypingCommand::DeleteKeyPressed(*frame.GetDocument(), options,
470 granularity);
471 break;
472 }
473 editor.RevealSelectionAfterEditingOperation();
474 }
475
476 // FIXME: We should to move this down into deleteKeyPressed.
477 // clear the "start new kill ring sequence" setting, because it was set to
478 // true when the selection was updated by deleting the range
479 if (kill_ring)
480 editor.SetStartNewKillRingSequence(false);
481
482 return true;
483 }
484
ExecuteDeleteBackward(LocalFrame & frame,Event *,EditorCommandSource,const String &)485 static bool ExecuteDeleteBackward(LocalFrame& frame,
486 Event*,
487 EditorCommandSource,
488 const String&) {
489 DeleteWithDirection(frame, DeleteDirection::kBackward,
490 TextGranularity::kCharacter, false, true);
491 return true;
492 }
493
ExecuteDeleteBackwardByDecomposingPreviousCharacter(LocalFrame & frame,Event *,EditorCommandSource,const String &)494 static bool ExecuteDeleteBackwardByDecomposingPreviousCharacter(
495 LocalFrame& frame,
496 Event*,
497 EditorCommandSource,
498 const String&) {
499 DLOG(ERROR) << "DeleteBackwardByDecomposingPreviousCharacter is not "
500 "implemented, doing DeleteBackward instead";
501 DeleteWithDirection(frame, DeleteDirection::kBackward,
502 TextGranularity::kCharacter, false, true);
503 return true;
504 }
505
ExecuteDeleteForward(LocalFrame & frame,Event *,EditorCommandSource,const String &)506 static bool ExecuteDeleteForward(LocalFrame& frame,
507 Event*,
508 EditorCommandSource,
509 const String&) {
510 DeleteWithDirection(frame, DeleteDirection::kForward,
511 TextGranularity::kCharacter, false, true);
512 return true;
513 }
514
ExecuteDeleteToBeginningOfLine(LocalFrame & frame,Event *,EditorCommandSource,const String &)515 static bool ExecuteDeleteToBeginningOfLine(LocalFrame& frame,
516 Event*,
517 EditorCommandSource,
518 const String&) {
519 DeleteWithDirection(frame, DeleteDirection::kBackward,
520 TextGranularity::kLineBoundary, true, false);
521 return true;
522 }
523
ExecuteDeleteToBeginningOfParagraph(LocalFrame & frame,Event *,EditorCommandSource,const String &)524 static bool ExecuteDeleteToBeginningOfParagraph(LocalFrame& frame,
525 Event*,
526 EditorCommandSource,
527 const String&) {
528 DeleteWithDirection(frame, DeleteDirection::kBackward,
529 TextGranularity::kParagraphBoundary, true, false);
530 return true;
531 }
532
ExecuteDeleteToEndOfLine(LocalFrame & frame,Event *,EditorCommandSource,const String &)533 static bool ExecuteDeleteToEndOfLine(LocalFrame& frame,
534 Event*,
535 EditorCommandSource,
536 const String&) {
537 // Despite its name, this command should delete the newline at the end of a
538 // paragraph if you are at the end of a paragraph (like
539 // DeleteToEndOfParagraph).
540 DeleteWithDirection(frame, DeleteDirection::kForward,
541 TextGranularity::kLineBoundary, true, false);
542 return true;
543 }
544
ExecuteDeleteToEndOfParagraph(LocalFrame & frame,Event *,EditorCommandSource,const String &)545 static bool ExecuteDeleteToEndOfParagraph(LocalFrame& frame,
546 Event*,
547 EditorCommandSource,
548 const String&) {
549 // Despite its name, this command should delete the newline at the end of
550 // a paragraph if you are at the end of a paragraph.
551 DeleteWithDirection(frame, DeleteDirection::kForward,
552 TextGranularity::kParagraphBoundary, true, false);
553 return true;
554 }
555
ExecuteDeleteToMark(LocalFrame & frame,Event *,EditorCommandSource,const String &)556 static bool ExecuteDeleteToMark(LocalFrame& frame,
557 Event*,
558 EditorCommandSource,
559 const String&) {
560 const EphemeralRange mark =
561 frame.GetEditor().Mark().ToNormalizedEphemeralRange();
562 if (mark.IsNotNull()) {
563 frame.Selection().SetSelection(
564 SelectionInDOMTree::Builder()
565 .SetBaseAndExtent(
566 UnionEphemeralRanges(mark, frame.GetEditor().SelectedRange()))
567 .Build(),
568 SetSelectionOptions::Builder().SetShouldCloseTyping(true).Build());
569 }
570 PerformDelete(frame);
571
572 // TODO(editing-dev): The use of UpdateStyleAndLayout
573 // needs to be audited. See http://crbug.com/590369 for more details.
574 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
575 frame.GetEditor().SetMark();
576 return true;
577 }
578
ExecuteDeleteWordBackward(LocalFrame & frame,Event *,EditorCommandSource,const String &)579 static bool ExecuteDeleteWordBackward(LocalFrame& frame,
580 Event*,
581 EditorCommandSource,
582 const String&) {
583 DeleteWithDirection(frame, DeleteDirection::kBackward, TextGranularity::kWord,
584 true, false);
585 return true;
586 }
587
ExecuteDeleteWordForward(LocalFrame & frame,Event *,EditorCommandSource,const String &)588 static bool ExecuteDeleteWordForward(LocalFrame& frame,
589 Event*,
590 EditorCommandSource,
591 const String&) {
592 DeleteWithDirection(frame, DeleteDirection::kForward, TextGranularity::kWord,
593 true, false);
594 return true;
595 }
596
ExecuteFindString(LocalFrame & frame,Event *,EditorCommandSource,const String & value)597 static bool ExecuteFindString(LocalFrame& frame,
598 Event*,
599 EditorCommandSource,
600 const String& value) {
601 return Editor::FindString(frame, value, kCaseInsensitive | kWrapAround);
602 }
603
ExecuteFormatBlock(LocalFrame & frame,Event *,EditorCommandSource,const String & value)604 static bool ExecuteFormatBlock(LocalFrame& frame,
605 Event*,
606 EditorCommandSource,
607 const String& value) {
608 String tag_name = value.DeprecatedLower();
609 if (tag_name[0] == '<' && tag_name[tag_name.length() - 1] == '>')
610 tag_name = tag_name.Substring(1, tag_name.length() - 2);
611
612 AtomicString local_name, prefix;
613 if (!Document::ParseQualifiedName(AtomicString(tag_name), prefix, local_name,
614 IGNORE_EXCEPTION_FOR_TESTING))
615 return false;
616 QualifiedName qualified_tag_name(prefix, local_name,
617 html_names::xhtmlNamespaceURI);
618
619 DCHECK(frame.GetDocument());
620 auto* command = MakeGarbageCollected<FormatBlockCommand>(*frame.GetDocument(),
621 qualified_tag_name);
622 command->Apply();
623 return command->DidApply();
624 }
625
ExecuteForwardDelete(LocalFrame & frame,Event *,EditorCommandSource source,const String &)626 static bool ExecuteForwardDelete(LocalFrame& frame,
627 Event*,
628 EditorCommandSource source,
629 const String&) {
630 EditingState editing_state;
631 switch (source) {
632 case EditorCommandSource::kMenuOrKeyBinding:
633 DeleteWithDirection(frame, DeleteDirection::kForward,
634 TextGranularity::kCharacter, false, true);
635 return true;
636 case EditorCommandSource::kDOM:
637 // Doesn't scroll to make the selection visible, or modify the kill ring.
638 // ForwardDelete is not implemented in IE or Firefox, so this behavior is
639 // only needed for backward compatibility with ourselves, and for
640 // consistency with Delete.
641 DCHECK(frame.GetDocument());
642 TypingCommand::ForwardDeleteKeyPressed(*frame.GetDocument(),
643 &editing_state);
644 if (editing_state.IsAborted())
645 return false;
646 return true;
647 }
648 NOTREACHED();
649 return false;
650 }
651
ExecuteIgnoreSpelling(LocalFrame & frame,Event *,EditorCommandSource,const String &)652 static bool ExecuteIgnoreSpelling(LocalFrame& frame,
653 Event*,
654 EditorCommandSource,
655 const String&) {
656 frame.GetSpellChecker().IgnoreSpelling();
657 return true;
658 }
659
ExecuteIndent(LocalFrame & frame,Event *,EditorCommandSource,const String &)660 static bool ExecuteIndent(LocalFrame& frame,
661 Event*,
662 EditorCommandSource,
663 const String&) {
664 DCHECK(frame.GetDocument());
665 return MakeGarbageCollected<IndentOutdentCommand>(
666 *frame.GetDocument(), IndentOutdentCommand::kIndent)
667 ->Apply();
668 }
669
ExecuteJustifyCenter(LocalFrame & frame,Event *,EditorCommandSource source,const String &)670 static bool ExecuteJustifyCenter(LocalFrame& frame,
671 Event*,
672 EditorCommandSource source,
673 const String&) {
674 return ExecuteApplyParagraphStyle(frame, source,
675 InputEvent::InputType::kFormatJustifyCenter,
676 CSSPropertyID::kTextAlign, "center");
677 }
678
ExecuteJustifyFull(LocalFrame & frame,Event *,EditorCommandSource source,const String &)679 static bool ExecuteJustifyFull(LocalFrame& frame,
680 Event*,
681 EditorCommandSource source,
682 const String&) {
683 return ExecuteApplyParagraphStyle(frame, source,
684 InputEvent::InputType::kFormatJustifyFull,
685 CSSPropertyID::kTextAlign, "justify");
686 }
687
ExecuteJustifyLeft(LocalFrame & frame,Event *,EditorCommandSource source,const String &)688 static bool ExecuteJustifyLeft(LocalFrame& frame,
689 Event*,
690 EditorCommandSource source,
691 const String&) {
692 return ExecuteApplyParagraphStyle(frame, source,
693 InputEvent::InputType::kFormatJustifyLeft,
694 CSSPropertyID::kTextAlign, "left");
695 }
696
ExecuteJustifyRight(LocalFrame & frame,Event *,EditorCommandSource source,const String &)697 static bool ExecuteJustifyRight(LocalFrame& frame,
698 Event*,
699 EditorCommandSource source,
700 const String&) {
701 return ExecuteApplyParagraphStyle(frame, source,
702 InputEvent::InputType::kFormatJustifyRight,
703 CSSPropertyID::kTextAlign, "right");
704 }
705
ExecuteOutdent(LocalFrame & frame,Event *,EditorCommandSource,const String &)706 static bool ExecuteOutdent(LocalFrame& frame,
707 Event*,
708 EditorCommandSource,
709 const String&) {
710 DCHECK(frame.GetDocument());
711 return MakeGarbageCollected<IndentOutdentCommand>(
712 *frame.GetDocument(), IndentOutdentCommand::kOutdent)
713 ->Apply();
714 }
715
ExecuteToggleOverwrite(LocalFrame & frame,Event *,EditorCommandSource,const String &)716 static bool ExecuteToggleOverwrite(LocalFrame& frame,
717 Event*,
718 EditorCommandSource,
719 const String&) {
720 frame.GetEditor().ToggleOverwriteModeEnabled();
721 return true;
722 }
723
ExecutePrint(LocalFrame & frame,Event *,EditorCommandSource,const String &)724 static bool ExecutePrint(LocalFrame& frame,
725 Event*,
726 EditorCommandSource,
727 const String&) {
728 Page* page = frame.GetPage();
729 if (!page)
730 return false;
731 return page->GetChromeClient().Print(&frame);
732 }
733
ExecuteRedo(LocalFrame & frame,Event *,EditorCommandSource,const String &)734 static bool ExecuteRedo(LocalFrame& frame,
735 Event*,
736 EditorCommandSource,
737 const String&) {
738 frame.GetEditor().Redo();
739 return true;
740 }
741
ExecuteRemoveFormat(LocalFrame & frame,Event *,EditorCommandSource,const String &)742 static bool ExecuteRemoveFormat(LocalFrame& frame,
743 Event*,
744 EditorCommandSource,
745 const String&) {
746 DCHECK(frame.GetDocument());
747 MakeGarbageCollected<RemoveFormatCommand>(*frame.GetDocument())->Apply();
748
749 return true;
750 }
751
ExecuteScrollPageBackward(LocalFrame & frame,Event *,EditorCommandSource,const String &)752 static bool ExecuteScrollPageBackward(LocalFrame& frame,
753 Event*,
754 EditorCommandSource,
755 const String&) {
756 return frame.GetEventHandler().BubblingScroll(
757 mojom::blink::ScrollDirection::kScrollBlockDirectionBackward,
758 ScrollGranularity::kScrollByPage);
759 }
760
ExecuteScrollPageForward(LocalFrame & frame,Event *,EditorCommandSource,const String &)761 static bool ExecuteScrollPageForward(LocalFrame& frame,
762 Event*,
763 EditorCommandSource,
764 const String&) {
765 return frame.GetEventHandler().BubblingScroll(
766 mojom::blink::ScrollDirection::kScrollBlockDirectionForward,
767 ScrollGranularity::kScrollByPage);
768 }
769
ExecuteScrollLineUp(LocalFrame & frame,Event *,EditorCommandSource,const String &)770 static bool ExecuteScrollLineUp(LocalFrame& frame,
771 Event*,
772 EditorCommandSource,
773 const String&) {
774 return frame.GetEventHandler().BubblingScroll(
775 mojom::blink::ScrollDirection::kScrollUpIgnoringWritingMode,
776 ScrollGranularity::kScrollByLine);
777 }
778
ExecuteScrollLineDown(LocalFrame & frame,Event *,EditorCommandSource,const String &)779 static bool ExecuteScrollLineDown(LocalFrame& frame,
780 Event*,
781 EditorCommandSource,
782 const String&) {
783 return frame.GetEventHandler().BubblingScroll(
784 mojom::blink::ScrollDirection::kScrollDownIgnoringWritingMode,
785 ScrollGranularity::kScrollByLine);
786 }
787
ExecuteScrollToBeginningOfDocument(LocalFrame & frame,Event *,EditorCommandSource,const String &)788 static bool ExecuteScrollToBeginningOfDocument(LocalFrame& frame,
789 Event*,
790 EditorCommandSource,
791 const String&) {
792 return frame.GetEventHandler().BubblingScroll(
793 mojom::blink::ScrollDirection::kScrollBlockDirectionBackward,
794 ScrollGranularity::kScrollByDocument);
795 }
796
ExecuteScrollToEndOfDocument(LocalFrame & frame,Event *,EditorCommandSource,const String &)797 static bool ExecuteScrollToEndOfDocument(LocalFrame& frame,
798 Event*,
799 EditorCommandSource,
800 const String&) {
801 return frame.GetEventHandler().BubblingScroll(
802 mojom::blink::ScrollDirection::kScrollBlockDirectionForward,
803 ScrollGranularity::kScrollByDocument);
804 }
805
ExecuteSelectAll(LocalFrame & frame,Event *,EditorCommandSource source,const String &)806 static bool ExecuteSelectAll(LocalFrame& frame,
807 Event*,
808 EditorCommandSource source,
809 const String&) {
810 const SetSelectionBy set_selection_by =
811 source == EditorCommandSource::kMenuOrKeyBinding
812 ? SetSelectionBy::kUser
813 : SetSelectionBy::kSystem;
814 frame.Selection().SelectAll(set_selection_by);
815 return true;
816 }
817
ExecuteSelectLine(LocalFrame & frame,Event *,EditorCommandSource,const String &)818 static bool ExecuteSelectLine(LocalFrame& frame,
819 Event*,
820 EditorCommandSource,
821 const String&) {
822 return ExpandSelectionToGranularity(frame, TextGranularity::kLine);
823 }
824
ExecuteSelectParagraph(LocalFrame & frame,Event *,EditorCommandSource,const String &)825 static bool ExecuteSelectParagraph(LocalFrame& frame,
826 Event*,
827 EditorCommandSource,
828 const String&) {
829 return ExpandSelectionToGranularity(frame, TextGranularity::kParagraph);
830 }
831
ExecuteSelectSentence(LocalFrame & frame,Event *,EditorCommandSource,const String &)832 static bool ExecuteSelectSentence(LocalFrame& frame,
833 Event*,
834 EditorCommandSource,
835 const String&) {
836 return ExpandSelectionToGranularity(frame, TextGranularity::kSentence);
837 }
838
ExecuteSelectToMark(LocalFrame & frame,Event *,EditorCommandSource,const String &)839 static bool ExecuteSelectToMark(LocalFrame& frame,
840 Event*,
841 EditorCommandSource,
842 const String&) {
843 const EphemeralRange mark =
844 frame.GetEditor().Mark().ToNormalizedEphemeralRange();
845 EphemeralRange selection = frame.GetEditor().SelectedRange();
846 if (mark.IsNull() || selection.IsNull())
847 return false;
848 frame.Selection().SetSelection(
849 SelectionInDOMTree::Builder()
850 .SetBaseAndExtent(UnionEphemeralRanges(mark, selection))
851 .Build(),
852 SetSelectionOptions::Builder().SetShouldCloseTyping(true).Build());
853 return true;
854 }
855
ExecuteSelectWord(LocalFrame & frame,Event *,EditorCommandSource,const String &)856 static bool ExecuteSelectWord(LocalFrame& frame,
857 Event*,
858 EditorCommandSource,
859 const String&) {
860 return ExpandSelectionToGranularity(frame, TextGranularity::kWord);
861 }
862
ExecuteSetMark(LocalFrame & frame,Event *,EditorCommandSource,const String &)863 static bool ExecuteSetMark(LocalFrame& frame,
864 Event*,
865 EditorCommandSource,
866 const String&) {
867 frame.GetEditor().SetMark();
868 return true;
869 }
870
ExecuteSwapWithMark(LocalFrame & frame,Event *,EditorCommandSource,const String &)871 static bool ExecuteSwapWithMark(LocalFrame& frame,
872 Event*,
873 EditorCommandSource,
874 const String&) {
875 const VisibleSelection mark(frame.GetEditor().Mark());
876 const VisibleSelection& selection =
877 frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated();
878 const bool mark_is_directional = frame.GetEditor().MarkIsDirectional();
879 if (mark.IsNone() || selection.IsNone())
880 return false;
881
882 frame.GetEditor().SetMark();
883 frame.Selection().SetSelection(mark.AsSelection(),
884 SetSelectionOptions::Builder()
885 .SetIsDirectional(mark_is_directional)
886 .Build());
887 return true;
888 }
889
ExecuteTranspose(LocalFrame & frame,Event *,EditorCommandSource,const String &)890 static bool ExecuteTranspose(LocalFrame& frame,
891 Event*,
892 EditorCommandSource,
893 const String&) {
894 Editor& editor = frame.GetEditor();
895 if (!editor.CanEdit())
896 return false;
897
898 Document* const document = frame.GetDocument();
899
900 // TODO(editing-dev): The use of UpdateStyleAndLayout
901 // needs to be audited. See http://crbug.com/590369 for more details.
902 document->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
903
904 const EphemeralRange& range = ComputeRangeForTranspose(frame);
905 if (range.IsNull())
906 return false;
907
908 // Transpose the two characters.
909 const String& text = PlainText(range);
910 if (text.length() != 2)
911 return false;
912 const String& transposed = text.Right(1) + text.Left(1);
913
914 if (DispatchBeforeInputInsertText(EventTargetNodeForDocument(document),
915 transposed,
916 InputEvent::InputType::kInsertTranspose,
917 MakeGarbageCollected<StaticRangeVector>(
918 1, StaticRange::Create(range))) !=
919 DispatchEventResult::kNotCanceled)
920 return false;
921
922 // 'beforeinput' event handler may destroy document->
923 if (frame.GetDocument() != document)
924 return false;
925
926 // TODO(editing-dev): The use of UpdateStyleAndLayout
927 // needs to be audited. See http://crbug.com/590369 for more details.
928 document->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
929
930 // 'beforeinput' event handler may change selection, we need to re-calculate
931 // range.
932 const EphemeralRange& new_range = ComputeRangeForTranspose(frame);
933 if (new_range.IsNull())
934 return false;
935
936 const String& new_text = PlainText(new_range);
937 if (new_text.length() != 2)
938 return false;
939 const String& new_transposed = new_text.Right(1) + new_text.Left(1);
940
941 const SelectionInDOMTree& new_selection =
942 SelectionInDOMTree::Builder().SetBaseAndExtent(new_range).Build();
943
944 // Select the two characters.
945 if (CreateVisibleSelection(new_selection) !=
946 frame.Selection().ComputeVisibleSelectionInDOMTree())
947 frame.Selection().SetSelectionAndEndTyping(new_selection);
948
949 // Insert the transposed characters.
950 editor.ReplaceSelectionWithText(new_transposed, false, false,
951 InputEvent::InputType::kInsertTranspose);
952 return true;
953 }
954
ExecuteUndo(LocalFrame & frame,Event *,EditorCommandSource,const String &)955 static bool ExecuteUndo(LocalFrame& frame,
956 Event*,
957 EditorCommandSource,
958 const String&) {
959 frame.GetEditor().Undo();
960 return true;
961 }
962
ExecuteUnlink(LocalFrame & frame,Event *,EditorCommandSource,const String &)963 static bool ExecuteUnlink(LocalFrame& frame,
964 Event*,
965 EditorCommandSource,
966 const String&) {
967 DCHECK(frame.GetDocument());
968 return MakeGarbageCollected<UnlinkCommand>(*frame.GetDocument())->Apply();
969 }
970
ExecuteUnselect(LocalFrame & frame,Event *,EditorCommandSource,const String &)971 static bool ExecuteUnselect(LocalFrame& frame,
972 Event*,
973 EditorCommandSource,
974 const String&) {
975 frame.Selection().Clear();
976 return true;
977 }
978
ExecuteYank(LocalFrame & frame,Event *,EditorCommandSource,const String &)979 static bool ExecuteYank(LocalFrame& frame,
980 Event*,
981 EditorCommandSource,
982 const String&) {
983 const String& yank_string = frame.GetEditor().GetKillRing().Yank();
984 if (DispatchBeforeInputInsertText(
985 EventTargetNodeForDocument(frame.GetDocument()), yank_string,
986 InputEvent::InputType::kInsertFromYank) !=
987 DispatchEventResult::kNotCanceled)
988 return true;
989
990 // 'beforeinput' event handler may destroy document.
991 if (frame.GetDocument()->GetFrame() != &frame)
992 return false;
993
994 // TODO(editing-dev): The use of UpdateStyleAndLayout
995 // needs to be audited. see http://crbug.com/590369 for more details.
996 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
997
998 frame.GetEditor().InsertTextWithoutSendingTextEvent(
999 yank_string, false, nullptr, InputEvent::InputType::kInsertFromYank);
1000 frame.GetEditor().GetKillRing().SetToYankedState();
1001 return true;
1002 }
1003
ExecuteYankAndSelect(LocalFrame & frame,Event *,EditorCommandSource,const String &)1004 static bool ExecuteYankAndSelect(LocalFrame& frame,
1005 Event*,
1006 EditorCommandSource,
1007 const String&) {
1008 const String& yank_string = frame.GetEditor().GetKillRing().Yank();
1009 if (DispatchBeforeInputInsertText(
1010 EventTargetNodeForDocument(frame.GetDocument()), yank_string,
1011 InputEvent::InputType::kInsertFromYank) !=
1012 DispatchEventResult::kNotCanceled)
1013 return true;
1014
1015 // 'beforeinput' event handler may destroy document.
1016 if (frame.GetDocument()->GetFrame() != &frame)
1017 return false;
1018
1019 // TODO(editing-dev): The use of UpdateStyleAndLayout
1020 // needs to be audited. see http://crbug.com/590369 for more details.
1021 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1022
1023 frame.GetEditor().InsertTextWithoutSendingTextEvent(
1024 frame.GetEditor().GetKillRing().Yank(), true, nullptr,
1025 InputEvent::InputType::kInsertFromYank);
1026 frame.GetEditor().GetKillRing().SetToYankedState();
1027 return true;
1028 }
1029
1030 // Supported functions
1031
Supported(LocalFrame *)1032 static bool Supported(LocalFrame*) {
1033 return true;
1034 }
1035
SupportedFromMenuOrKeyBinding(LocalFrame *)1036 static bool SupportedFromMenuOrKeyBinding(LocalFrame*) {
1037 return false;
1038 }
1039
1040 // Enabled functions
1041
Enabled(LocalFrame &,Event *,EditorCommandSource)1042 static bool Enabled(LocalFrame&, Event*, EditorCommandSource) {
1043 return true;
1044 }
1045
EnabledVisibleSelection(LocalFrame & frame,Event * event,EditorCommandSource source)1046 static bool EnabledVisibleSelection(LocalFrame& frame,
1047 Event* event,
1048 EditorCommandSource source) {
1049 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1050
1051 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1052 !frame.Selection().SelectionHasFocus())
1053 return false;
1054
1055 // The term "visible" here includes a caret in editable text, a range in any
1056 // text, or a caret in non-editable text when caret browsing is enabled.
1057 const VisibleSelection& selection =
1058 CreateVisibleSelection(frame.GetEditor().SelectionForCommand(event));
1059 return (selection.IsCaret() &&
1060 (selection.IsContentEditable() || frame.IsCaretBrowsingEnabled())) ||
1061 selection.IsRange();
1062 }
1063
EnabledVisibleSelectionAndMark(LocalFrame & frame,Event * event,EditorCommandSource source)1064 static bool EnabledVisibleSelectionAndMark(LocalFrame& frame,
1065 Event* event,
1066 EditorCommandSource source) {
1067 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1068
1069 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1070 !frame.Selection().SelectionHasFocus())
1071 return false;
1072
1073 const VisibleSelection& selection =
1074 CreateVisibleSelection(frame.GetEditor().SelectionForCommand(event));
1075 return ((selection.IsCaret() &&
1076 (selection.IsContentEditable() || frame.IsCaretBrowsingEnabled())) ||
1077 selection.IsRange()) &&
1078 !frame.GetEditor().Mark().IsNone();
1079 }
1080
EnableCaretInEditableText(LocalFrame & frame,Event * event,EditorCommandSource source)1081 static bool EnableCaretInEditableText(LocalFrame& frame,
1082 Event* event,
1083 EditorCommandSource source) {
1084 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1085
1086 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1087 !frame.Selection().SelectionHasFocus())
1088 return false;
1089 const VisibleSelection& selection =
1090 CreateVisibleSelection(frame.GetEditor().SelectionForCommand(event));
1091 return selection.IsCaret() && selection.IsContentEditable();
1092 }
1093
EnabledInEditableText(LocalFrame & frame,Event * event,EditorCommandSource source)1094 static bool EnabledInEditableText(LocalFrame& frame,
1095 Event* event,
1096 EditorCommandSource source) {
1097 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1098 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1099 !frame.Selection().SelectionHasFocus())
1100 return false;
1101 const SelectionInDOMTree selection =
1102 frame.GetEditor().SelectionForCommand(event);
1103 return RootEditableElementOf(
1104 CreateVisiblePosition(selection.Base()).DeepEquivalent());
1105 }
1106
EnabledInEditableTextOrCaretBrowsing(LocalFrame & frame,Event * event,EditorCommandSource source)1107 static bool EnabledInEditableTextOrCaretBrowsing(LocalFrame& frame,
1108 Event* event,
1109 EditorCommandSource source) {
1110 return frame.IsCaretBrowsingEnabled() ||
1111 EnabledInEditableText(frame, event, source);
1112 }
1113
EnabledDelete(LocalFrame & frame,Event * event,EditorCommandSource source)1114 static bool EnabledDelete(LocalFrame& frame,
1115 Event* event,
1116 EditorCommandSource source) {
1117 switch (source) {
1118 case EditorCommandSource::kMenuOrKeyBinding:
1119 return frame.Selection().SelectionHasFocus() &&
1120 frame.GetEditor().CanDelete();
1121 case EditorCommandSource::kDOM:
1122 // "Delete" from DOM is like delete/backspace keypress, affects selected
1123 // range if non-empty, otherwise removes a character
1124 return EnabledInEditableText(frame, event, source);
1125 }
1126 NOTREACHED();
1127 return false;
1128 }
1129
EnabledInRichlyEditableText(LocalFrame & frame,Event *,EditorCommandSource source)1130 static bool EnabledInRichlyEditableText(LocalFrame& frame,
1131 Event*,
1132 EditorCommandSource source) {
1133 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1134 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1135 !frame.Selection().SelectionHasFocus())
1136 return false;
1137 const VisibleSelection& selection =
1138 frame.Selection().ComputeVisibleSelectionInDOMTree();
1139 return !selection.IsNone() && IsRichlyEditablePosition(selection.Base()) &&
1140 selection.RootEditableElement();
1141 }
1142
EnabledRangeInEditableText(LocalFrame & frame,Event *,EditorCommandSource source)1143 static bool EnabledRangeInEditableText(LocalFrame& frame,
1144 Event*,
1145 EditorCommandSource source) {
1146 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1147 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1148 !frame.Selection().SelectionHasFocus())
1149 return false;
1150 return frame.Selection()
1151 .ComputeVisibleSelectionInDOMTreeDeprecated()
1152 .IsRange() &&
1153 frame.Selection()
1154 .ComputeVisibleSelectionInDOMTreeDeprecated()
1155 .IsContentEditable();
1156 }
1157
EnabledRangeInRichlyEditableText(LocalFrame & frame,Event *,EditorCommandSource source)1158 static bool EnabledRangeInRichlyEditableText(LocalFrame& frame,
1159 Event*,
1160 EditorCommandSource source) {
1161 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1162 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1163 !frame.Selection().SelectionHasFocus())
1164 return false;
1165 const VisibleSelection& selection =
1166 frame.Selection().ComputeVisibleSelectionInDOMTree();
1167 return selection.IsRange() && IsRichlyEditablePosition(selection.Base());
1168 }
1169
EnabledRedo(LocalFrame & frame,Event *,EditorCommandSource)1170 static bool EnabledRedo(LocalFrame& frame, Event*, EditorCommandSource) {
1171 return frame.GetEditor().CanRedo();
1172 }
1173
EnabledUndo(LocalFrame & frame,Event *,EditorCommandSource)1174 static bool EnabledUndo(LocalFrame& frame, Event*, EditorCommandSource) {
1175 return frame.GetEditor().CanUndo();
1176 }
1177
EnabledUnselect(LocalFrame & frame,Event * event,EditorCommandSource)1178 static bool EnabledUnselect(LocalFrame& frame,
1179 Event* event,
1180 EditorCommandSource) {
1181 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1182
1183 // The term "visible" here includes a caret in editable text or a range in any
1184 // text.
1185 const VisibleSelection& selection =
1186 CreateVisibleSelection(frame.GetEditor().SelectionForCommand(event));
1187 return (selection.IsCaret() && selection.IsContentEditable()) ||
1188 selection.IsRange();
1189 }
1190
EnabledSelectAll(LocalFrame & frame,Event *,EditorCommandSource source)1191 static bool EnabledSelectAll(LocalFrame& frame,
1192 Event*,
1193 EditorCommandSource source) {
1194 // TODO(editing-dev): The use of UpdateStyleAndLayout
1195 // needs to be audited. See http://crbug.com/590369 for more details.
1196 frame.GetDocument()->UpdateStyleAndLayout(DocumentUpdateReason::kEditing);
1197 const VisibleSelection& selection =
1198 frame.Selection().ComputeVisibleSelectionInDOMTree();
1199 if (selection.IsNone())
1200 return true;
1201 // Hidden selection appears as no selection to users, in which case user-
1202 // triggered SelectAll should be enabled and act as if there is no selection.
1203 if (source == EditorCommandSource::kMenuOrKeyBinding &&
1204 frame.Selection().IsHidden())
1205 return true;
1206 if (Node* root = HighestEditableRoot(selection.Start())) {
1207 if (!root->hasChildren())
1208 return false;
1209
1210 // When the editable contains a BR only, it appears as an empty line, in
1211 // which case allowing select-all confuses users.
1212 if (root->firstChild() == root->lastChild() &&
1213 IsA<HTMLBRElement>(root->firstChild()))
1214 return false;
1215
1216 // TODO(amaralp): Return false if already fully selected.
1217 }
1218 // TODO(amaralp): Address user-select handling.
1219 return true;
1220 }
1221
1222 // State functions
1223
StateNone(LocalFrame &,Event *)1224 static EditingTriState StateNone(LocalFrame&, Event*) {
1225 return EditingTriState::kFalse;
1226 }
1227
StateOrderedList(LocalFrame & frame,Event *)1228 EditingTriState StateOrderedList(LocalFrame& frame, Event*) {
1229 return SelectionListState(frame.Selection(), html_names::kOlTag);
1230 }
1231
StateUnorderedList(LocalFrame & frame,Event *)1232 static EditingTriState StateUnorderedList(LocalFrame& frame, Event*) {
1233 return SelectionListState(frame.Selection(), html_names::kUlTag);
1234 }
1235
StateJustifyCenter(LocalFrame & frame,Event *)1236 static EditingTriState StateJustifyCenter(LocalFrame& frame, Event*) {
1237 return StyleCommands::StateStyle(frame, CSSPropertyID::kTextAlign, "center");
1238 }
1239
StateJustifyFull(LocalFrame & frame,Event *)1240 static EditingTriState StateJustifyFull(LocalFrame& frame, Event*) {
1241 return StyleCommands::StateStyle(frame, CSSPropertyID::kTextAlign, "justify");
1242 }
1243
StateJustifyLeft(LocalFrame & frame,Event *)1244 static EditingTriState StateJustifyLeft(LocalFrame& frame, Event*) {
1245 return StyleCommands::StateStyle(frame, CSSPropertyID::kTextAlign, "left");
1246 }
1247
StateJustifyRight(LocalFrame & frame,Event *)1248 static EditingTriState StateJustifyRight(LocalFrame& frame, Event*) {
1249 return StyleCommands::StateStyle(frame, CSSPropertyID::kTextAlign, "right");
1250 }
1251
1252 // Value functions
1253
ValueStateOrNull(const EditorInternalCommand & self,LocalFrame & frame,Event * triggering_event)1254 static String ValueStateOrNull(const EditorInternalCommand& self,
1255 LocalFrame& frame,
1256 Event* triggering_event) {
1257 if (self.state == StateNone)
1258 return String();
1259 return self.state(frame, triggering_event) == EditingTriState::kTrue
1260 ? "true"
1261 : "false";
1262 }
1263
1264 // The command has no value.
1265 // https://w3c.github.io/editing/execCommand.html#querycommandvalue()
1266 // > ... or has no value, return the empty string.
ValueEmpty(const EditorInternalCommand &,LocalFrame &,Event *)1267 static String ValueEmpty(const EditorInternalCommand&, LocalFrame&, Event*) {
1268 return g_empty_string;
1269 }
1270
ValueDefaultParagraphSeparator(const EditorInternalCommand &,LocalFrame & frame,Event *)1271 static String ValueDefaultParagraphSeparator(const EditorInternalCommand&,
1272 LocalFrame& frame,
1273 Event*) {
1274 switch (frame.GetEditor().DefaultParagraphSeparator()) {
1275 case EditorParagraphSeparator::kIsDiv:
1276 return html_names::kDivTag.LocalName();
1277 case EditorParagraphSeparator::kIsP:
1278 return html_names::kPTag.LocalName();
1279 }
1280
1281 NOTREACHED();
1282 return String();
1283 }
1284
ValueFormatBlock(const EditorInternalCommand &,LocalFrame & frame,Event *)1285 static String ValueFormatBlock(const EditorInternalCommand&,
1286 LocalFrame& frame,
1287 Event*) {
1288 const VisibleSelection& selection =
1289 frame.Selection().ComputeVisibleSelectionInDOMTreeDeprecated();
1290 if (selection.IsNone() || !selection.IsValidFor(*(frame.GetDocument())) ||
1291 !selection.IsContentEditable())
1292 return "";
1293 Element* format_block_element =
1294 FormatBlockCommand::ElementForFormatBlockCommand(
1295 FirstEphemeralRangeOf(selection));
1296 if (!format_block_element)
1297 return "";
1298 return format_block_element->localName();
1299 }
1300
1301 // CanExectue functions
1302
CanNotExecuteWhenDisabled(LocalFrame &,EditorCommandSource)1303 static bool CanNotExecuteWhenDisabled(LocalFrame&, EditorCommandSource) {
1304 return false;
1305 }
1306
1307 // Map of functions
1308
InternalCommand(const String & command_name)1309 static const EditorInternalCommand* InternalCommand(
1310 const String& command_name) {
1311 static const EditorInternalCommand kEditorCommands[] = {
1312 // Lists all commands in blink::EditingCommandType.
1313 // Must be ordered by |commandType| for index lookup.
1314 // Covered by unit tests in editing_command_test.cc
1315 {EditingCommandType::kAlignJustified, ExecuteJustifyFull,
1316 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText, StateNone,
1317 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1318 {EditingCommandType::kAlignLeft, ExecuteJustifyLeft,
1319 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText, StateNone,
1320 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1321 {EditingCommandType::kAlignRight, ExecuteJustifyRight,
1322 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText, StateNone,
1323 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1324 {EditingCommandType::kBackColor, StyleCommands::ExecuteBackColor,
1325 Supported, EnabledInRichlyEditableText, StateNone,
1326 StyleCommands::ValueBackColor, kNotTextInsertion,
1327 CanNotExecuteWhenDisabled},
1328 // FIXME: remove BackwardDelete when Safari for Windows stops using it.
1329 {EditingCommandType::kBackwardDelete, ExecuteDeleteBackward,
1330 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1331 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1332 {EditingCommandType::kBold, StyleCommands::ExecuteToggleBold, Supported,
1333 EnabledInRichlyEditableText, StyleCommands::StateBold, ValueStateOrNull,
1334 kNotTextInsertion, CanNotExecuteWhenDisabled},
1335 {EditingCommandType::kCopy, ClipboardCommands::ExecuteCopy, Supported,
1336 ClipboardCommands::EnabledCopy, StateNone, ValueStateOrNull,
1337 kNotTextInsertion, ClipboardCommands::CanWriteClipboard},
1338 {EditingCommandType::kCreateLink, ExecuteCreateLink, Supported,
1339 EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1340 kNotTextInsertion, CanNotExecuteWhenDisabled},
1341 {EditingCommandType::kCut, ClipboardCommands::ExecuteCut, Supported,
1342 ClipboardCommands::EnabledCut, StateNone, ValueStateOrNull,
1343 kNotTextInsertion, ClipboardCommands::CanWriteClipboard},
1344 {EditingCommandType::kDefaultParagraphSeparator,
1345 ExecuteDefaultParagraphSeparator, Supported, Enabled, StateNone,
1346 ValueDefaultParagraphSeparator, kNotTextInsertion,
1347 CanNotExecuteWhenDisabled},
1348 {EditingCommandType::kDelete, ExecuteDelete, Supported, EnabledDelete,
1349 StateNone, ValueStateOrNull, kNotTextInsertion,
1350 CanNotExecuteWhenDisabled},
1351 {EditingCommandType::kDeleteBackward, ExecuteDeleteBackward,
1352 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1353 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1354 {EditingCommandType::kDeleteBackwardByDecomposingPreviousCharacter,
1355 ExecuteDeleteBackwardByDecomposingPreviousCharacter,
1356 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1357 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1358 {EditingCommandType::kDeleteForward, ExecuteDeleteForward,
1359 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1360 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1361 {EditingCommandType::kDeleteToBeginningOfLine,
1362 ExecuteDeleteToBeginningOfLine, SupportedFromMenuOrKeyBinding,
1363 EnabledInEditableText, StateNone, ValueStateOrNull, kNotTextInsertion,
1364 CanNotExecuteWhenDisabled},
1365 {EditingCommandType::kDeleteToBeginningOfParagraph,
1366 ExecuteDeleteToBeginningOfParagraph, SupportedFromMenuOrKeyBinding,
1367 EnabledInEditableText, StateNone, ValueStateOrNull, kNotTextInsertion,
1368 CanNotExecuteWhenDisabled},
1369 {EditingCommandType::kDeleteToEndOfLine, ExecuteDeleteToEndOfLine,
1370 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1371 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1372 {EditingCommandType::kDeleteToEndOfParagraph,
1373 ExecuteDeleteToEndOfParagraph, SupportedFromMenuOrKeyBinding,
1374 EnabledInEditableText, StateNone, ValueStateOrNull, kNotTextInsertion,
1375 CanNotExecuteWhenDisabled},
1376 {EditingCommandType::kDeleteToMark, ExecuteDeleteToMark,
1377 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1378 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1379 {EditingCommandType::kDeleteWordBackward, ExecuteDeleteWordBackward,
1380 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1381 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1382 {EditingCommandType::kDeleteWordForward, ExecuteDeleteWordForward,
1383 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1384 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1385 {EditingCommandType::kFindString, ExecuteFindString, Supported, Enabled,
1386 StateNone, ValueStateOrNull, kNotTextInsertion,
1387 CanNotExecuteWhenDisabled},
1388 {EditingCommandType::kFontName, StyleCommands::ExecuteFontName, Supported,
1389 EnabledInRichlyEditableText, StateNone, StyleCommands::ValueFontName,
1390 kNotTextInsertion, CanNotExecuteWhenDisabled},
1391 {EditingCommandType::kFontSize, StyleCommands::ExecuteFontSize, Supported,
1392 EnabledInRichlyEditableText, StateNone, StyleCommands::ValueFontSize,
1393 kNotTextInsertion, CanNotExecuteWhenDisabled},
1394 {EditingCommandType::kFontSizeDelta, StyleCommands::ExecuteFontSizeDelta,
1395 Supported, EnabledInRichlyEditableText, StateNone,
1396 StyleCommands::ValueFontSizeDelta, kNotTextInsertion,
1397 CanNotExecuteWhenDisabled},
1398 {EditingCommandType::kForeColor, StyleCommands::ExecuteForeColor,
1399 Supported, EnabledInRichlyEditableText, StateNone,
1400 StyleCommands::ValueForeColor, kNotTextInsertion,
1401 CanNotExecuteWhenDisabled},
1402 {EditingCommandType::kFormatBlock, ExecuteFormatBlock, Supported,
1403 EnabledInRichlyEditableText, StateNone, ValueFormatBlock,
1404 kNotTextInsertion, CanNotExecuteWhenDisabled},
1405 {EditingCommandType::kForwardDelete, ExecuteForwardDelete, Supported,
1406 EnabledInEditableText, StateNone, ValueStateOrNull, kNotTextInsertion,
1407 CanNotExecuteWhenDisabled},
1408 {EditingCommandType::kHiliteColor, StyleCommands::ExecuteBackColor,
1409 Supported, EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1410 kNotTextInsertion, CanNotExecuteWhenDisabled},
1411 {EditingCommandType::kIgnoreSpelling, ExecuteIgnoreSpelling,
1412 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1413 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1414 {EditingCommandType::kIndent, ExecuteIndent, Supported,
1415 EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1416 kNotTextInsertion, CanNotExecuteWhenDisabled},
1417 {EditingCommandType::kInsertBacktab, InsertCommands::ExecuteInsertBacktab,
1418 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1419 ValueStateOrNull, kIsTextInsertion, CanNotExecuteWhenDisabled},
1420 {EditingCommandType::kInsertHTML, InsertCommands::ExecuteInsertHTML,
1421 Supported, EnabledInEditableText, StateNone, ValueStateOrNull,
1422 kNotTextInsertion, CanNotExecuteWhenDisabled},
1423 {EditingCommandType::kInsertHorizontalRule,
1424 InsertCommands::ExecuteInsertHorizontalRule, Supported,
1425 EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1426 kNotTextInsertion, CanNotExecuteWhenDisabled},
1427 {EditingCommandType::kInsertImage, InsertCommands::ExecuteInsertImage,
1428 Supported, EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1429 kNotTextInsertion, CanNotExecuteWhenDisabled},
1430 {EditingCommandType::kInsertLineBreak,
1431 InsertCommands::ExecuteInsertLineBreak, Supported, EnabledInEditableText,
1432 StateNone, ValueStateOrNull, kIsTextInsertion,
1433 CanNotExecuteWhenDisabled},
1434 {EditingCommandType::kInsertNewline, InsertCommands::ExecuteInsertNewline,
1435 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1436 ValueStateOrNull, kIsTextInsertion, CanNotExecuteWhenDisabled},
1437 {EditingCommandType::kInsertNewlineInQuotedContent,
1438 InsertCommands::ExecuteInsertNewlineInQuotedContent, Supported,
1439 EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1440 kNotTextInsertion, CanNotExecuteWhenDisabled},
1441 {EditingCommandType::kInsertOrderedList,
1442 InsertCommands::ExecuteInsertOrderedList, Supported,
1443 EnabledInRichlyEditableText, StateOrderedList, ValueStateOrNull,
1444 kNotTextInsertion, CanNotExecuteWhenDisabled},
1445 {EditingCommandType::kInsertParagraph,
1446 InsertCommands::ExecuteInsertParagraph, Supported, EnabledInEditableText,
1447 StateNone, ValueStateOrNull, kNotTextInsertion,
1448 CanNotExecuteWhenDisabled},
1449 {EditingCommandType::kInsertTab, InsertCommands::ExecuteInsertTab,
1450 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1451 ValueStateOrNull, kIsTextInsertion, CanNotExecuteWhenDisabled},
1452 {EditingCommandType::kInsertText, InsertCommands::ExecuteInsertText,
1453 Supported, EnabledInEditableText, StateNone, ValueStateOrNull,
1454 kIsTextInsertion, CanNotExecuteWhenDisabled},
1455 {EditingCommandType::kInsertUnorderedList,
1456 InsertCommands::ExecuteInsertUnorderedList, Supported,
1457 EnabledInRichlyEditableText, StateUnorderedList, ValueStateOrNull,
1458 kNotTextInsertion, CanNotExecuteWhenDisabled},
1459 {EditingCommandType::kItalic, StyleCommands::ExecuteToggleItalic,
1460 Supported, EnabledInRichlyEditableText, StyleCommands::StateItalic,
1461 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1462 {EditingCommandType::kJustifyCenter, ExecuteJustifyCenter, Supported,
1463 EnabledInRichlyEditableText, StateJustifyCenter, ValueStateOrNull,
1464 kNotTextInsertion, CanNotExecuteWhenDisabled},
1465 {EditingCommandType::kJustifyFull, ExecuteJustifyFull, Supported,
1466 EnabledInRichlyEditableText, StateJustifyFull, ValueStateOrNull,
1467 kNotTextInsertion, CanNotExecuteWhenDisabled},
1468 {EditingCommandType::kJustifyLeft, ExecuteJustifyLeft, Supported,
1469 EnabledInRichlyEditableText, StateJustifyLeft, ValueStateOrNull,
1470 kNotTextInsertion, CanNotExecuteWhenDisabled},
1471 {EditingCommandType::kJustifyNone, ExecuteJustifyLeft, Supported,
1472 EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1473 kNotTextInsertion, CanNotExecuteWhenDisabled},
1474 {EditingCommandType::kJustifyRight, ExecuteJustifyRight, Supported,
1475 EnabledInRichlyEditableText, StateJustifyRight, ValueStateOrNull,
1476 kNotTextInsertion, CanNotExecuteWhenDisabled},
1477 {EditingCommandType::kMakeTextWritingDirectionLeftToRight,
1478 StyleCommands::ExecuteMakeTextWritingDirectionLeftToRight,
1479 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText,
1480 StyleCommands::StateTextWritingDirectionLeftToRight, ValueStateOrNull,
1481 kNotTextInsertion, CanNotExecuteWhenDisabled},
1482 {EditingCommandType::kMakeTextWritingDirectionNatural,
1483 StyleCommands::ExecuteMakeTextWritingDirectionNatural,
1484 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText,
1485 StyleCommands::StateTextWritingDirectionNatural, ValueStateOrNull,
1486 kNotTextInsertion, CanNotExecuteWhenDisabled},
1487 {EditingCommandType::kMakeTextWritingDirectionRightToLeft,
1488 StyleCommands::ExecuteMakeTextWritingDirectionRightToLeft,
1489 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText,
1490 StyleCommands::StateTextWritingDirectionRightToLeft, ValueStateOrNull,
1491 kNotTextInsertion, CanNotExecuteWhenDisabled},
1492 {EditingCommandType::kMoveBackward, MoveCommands::ExecuteMoveBackward,
1493 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1494 StateNone, ValueStateOrNull, kNotTextInsertion,
1495 CanNotExecuteWhenDisabled},
1496 {EditingCommandType::kMoveBackwardAndModifySelection,
1497 MoveCommands::ExecuteMoveBackwardAndModifySelection,
1498 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1499 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1500 {EditingCommandType::kMoveDown, MoveCommands::ExecuteMoveDown,
1501 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1502 StateNone, ValueStateOrNull, kNotTextInsertion,
1503 CanNotExecuteWhenDisabled},
1504 {EditingCommandType::kMoveDownAndModifySelection,
1505 MoveCommands::ExecuteMoveDownAndModifySelection,
1506 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1507 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1508 {EditingCommandType::kMoveForward, MoveCommands::ExecuteMoveForward,
1509 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1510 StateNone, ValueStateOrNull, kNotTextInsertion,
1511 CanNotExecuteWhenDisabled},
1512 {EditingCommandType::kMoveForwardAndModifySelection,
1513 MoveCommands::ExecuteMoveForwardAndModifySelection,
1514 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1515 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1516 {EditingCommandType::kMoveLeft, MoveCommands::ExecuteMoveLeft,
1517 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1518 StateNone, ValueStateOrNull, kNotTextInsertion,
1519 CanNotExecuteWhenDisabled},
1520 {EditingCommandType::kMoveLeftAndModifySelection,
1521 MoveCommands::ExecuteMoveLeftAndModifySelection,
1522 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1523 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1524 {EditingCommandType::kMovePageDown, MoveCommands::ExecuteMovePageDown,
1525 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1526 StateNone, ValueStateOrNull, kNotTextInsertion,
1527 CanNotExecuteWhenDisabled},
1528 {EditingCommandType::kMovePageDownAndModifySelection,
1529 MoveCommands::ExecuteMovePageDownAndModifySelection,
1530 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1531 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1532 {EditingCommandType::kMovePageUp, MoveCommands::ExecuteMovePageUp,
1533 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1534 StateNone, ValueStateOrNull, kNotTextInsertion,
1535 CanNotExecuteWhenDisabled},
1536 {EditingCommandType::kMovePageUpAndModifySelection,
1537 MoveCommands::ExecuteMovePageUpAndModifySelection,
1538 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1539 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1540 {EditingCommandType::kMoveParagraphBackward,
1541 MoveCommands::ExecuteMoveParagraphBackward,
1542 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1543 StateNone, ValueStateOrNull, kNotTextInsertion,
1544 CanNotExecuteWhenDisabled},
1545 {EditingCommandType::kMoveParagraphBackwardAndModifySelection,
1546 MoveCommands::ExecuteMoveParagraphBackwardAndModifySelection,
1547 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1548 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1549 {EditingCommandType::kMoveParagraphForward,
1550 MoveCommands::ExecuteMoveParagraphForward, SupportedFromMenuOrKeyBinding,
1551 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1552 kNotTextInsertion, CanNotExecuteWhenDisabled},
1553 {EditingCommandType::kMoveParagraphForwardAndModifySelection,
1554 MoveCommands::ExecuteMoveParagraphForwardAndModifySelection,
1555 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1556 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1557 {EditingCommandType::kMoveRight, MoveCommands::ExecuteMoveRight,
1558 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1559 StateNone, ValueStateOrNull, kNotTextInsertion,
1560 CanNotExecuteWhenDisabled},
1561 {EditingCommandType::kMoveRightAndModifySelection,
1562 MoveCommands::ExecuteMoveRightAndModifySelection,
1563 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1564 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1565 {EditingCommandType::kMoveToBeginningOfDocument,
1566 MoveCommands::ExecuteMoveToBeginningOfDocument,
1567 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1568 StateNone, ValueStateOrNull, kNotTextInsertion,
1569 CanNotExecuteWhenDisabled},
1570 {EditingCommandType::kMoveToBeginningOfDocumentAndModifySelection,
1571 MoveCommands::ExecuteMoveToBeginningOfDocumentAndModifySelection,
1572 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1573 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1574 {EditingCommandType::kMoveToBeginningOfLine,
1575 MoveCommands::ExecuteMoveToBeginningOfLine,
1576 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1577 StateNone, ValueStateOrNull, kNotTextInsertion,
1578 CanNotExecuteWhenDisabled},
1579 {EditingCommandType::kMoveToBeginningOfLineAndModifySelection,
1580 MoveCommands::ExecuteMoveToBeginningOfLineAndModifySelection,
1581 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1582 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1583 {EditingCommandType::kMoveToBeginningOfParagraph,
1584 MoveCommands::ExecuteMoveToBeginningOfParagraph,
1585 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1586 StateNone, ValueStateOrNull, kNotTextInsertion,
1587 CanNotExecuteWhenDisabled},
1588 {EditingCommandType::kMoveToBeginningOfParagraphAndModifySelection,
1589 MoveCommands::ExecuteMoveToBeginningOfParagraphAndModifySelection,
1590 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1591 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1592 {EditingCommandType::kMoveToBeginningOfSentence,
1593 MoveCommands::ExecuteMoveToBeginningOfSentence,
1594 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1595 StateNone, ValueStateOrNull, kNotTextInsertion,
1596 CanNotExecuteWhenDisabled},
1597 {EditingCommandType::kMoveToBeginningOfSentenceAndModifySelection,
1598 MoveCommands::ExecuteMoveToBeginningOfSentenceAndModifySelection,
1599 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1600 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1601 {EditingCommandType::kMoveToEndOfDocument,
1602 MoveCommands::ExecuteMoveToEndOfDocument, SupportedFromMenuOrKeyBinding,
1603 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1604 kNotTextInsertion, CanNotExecuteWhenDisabled},
1605 {EditingCommandType::kMoveToEndOfDocumentAndModifySelection,
1606 MoveCommands::ExecuteMoveToEndOfDocumentAndModifySelection,
1607 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1608 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1609 {EditingCommandType::kMoveToEndOfLine,
1610 MoveCommands::ExecuteMoveToEndOfLine, SupportedFromMenuOrKeyBinding,
1611 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1612 kNotTextInsertion, CanNotExecuteWhenDisabled},
1613 {EditingCommandType::kMoveToEndOfLineAndModifySelection,
1614 MoveCommands::ExecuteMoveToEndOfLineAndModifySelection,
1615 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1616 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1617 {EditingCommandType::kMoveToEndOfParagraph,
1618 MoveCommands::ExecuteMoveToEndOfParagraph, SupportedFromMenuOrKeyBinding,
1619 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1620 kNotTextInsertion, CanNotExecuteWhenDisabled},
1621 {EditingCommandType::kMoveToEndOfParagraphAndModifySelection,
1622 MoveCommands::ExecuteMoveToEndOfParagraphAndModifySelection,
1623 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1624 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1625 {EditingCommandType::kMoveToEndOfSentence,
1626 MoveCommands::ExecuteMoveToEndOfSentence, SupportedFromMenuOrKeyBinding,
1627 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1628 kNotTextInsertion, CanNotExecuteWhenDisabled},
1629 {EditingCommandType::kMoveToEndOfSentenceAndModifySelection,
1630 MoveCommands::ExecuteMoveToEndOfSentenceAndModifySelection,
1631 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1632 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1633 {EditingCommandType::kMoveToLeftEndOfLine,
1634 MoveCommands::ExecuteMoveToLeftEndOfLine, SupportedFromMenuOrKeyBinding,
1635 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1636 kNotTextInsertion, CanNotExecuteWhenDisabled},
1637 {EditingCommandType::kMoveToLeftEndOfLineAndModifySelection,
1638 MoveCommands::ExecuteMoveToLeftEndOfLineAndModifySelection,
1639 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1640 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1641 {EditingCommandType::kMoveToRightEndOfLine,
1642 MoveCommands::ExecuteMoveToRightEndOfLine, SupportedFromMenuOrKeyBinding,
1643 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1644 kNotTextInsertion, CanNotExecuteWhenDisabled},
1645 {EditingCommandType::kMoveToRightEndOfLineAndModifySelection,
1646 MoveCommands::ExecuteMoveToRightEndOfLineAndModifySelection,
1647 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1648 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1649 {EditingCommandType::kMoveUp, MoveCommands::ExecuteMoveUp,
1650 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1651 StateNone, ValueStateOrNull, kNotTextInsertion,
1652 CanNotExecuteWhenDisabled},
1653 {EditingCommandType::kMoveUpAndModifySelection,
1654 MoveCommands::ExecuteMoveUpAndModifySelection,
1655 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1656 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1657 {EditingCommandType::kMoveWordBackward,
1658 MoveCommands::ExecuteMoveWordBackward, SupportedFromMenuOrKeyBinding,
1659 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1660 kNotTextInsertion, CanNotExecuteWhenDisabled},
1661 {EditingCommandType::kMoveWordBackwardAndModifySelection,
1662 MoveCommands::ExecuteMoveWordBackwardAndModifySelection,
1663 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1664 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1665 {EditingCommandType::kMoveWordForward,
1666 MoveCommands::ExecuteMoveWordForward, SupportedFromMenuOrKeyBinding,
1667 EnabledInEditableTextOrCaretBrowsing, StateNone, ValueStateOrNull,
1668 kNotTextInsertion, CanNotExecuteWhenDisabled},
1669 {EditingCommandType::kMoveWordForwardAndModifySelection,
1670 MoveCommands::ExecuteMoveWordForwardAndModifySelection,
1671 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1672 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1673 {EditingCommandType::kMoveWordLeft, MoveCommands::ExecuteMoveWordLeft,
1674 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1675 StateNone, ValueStateOrNull, kNotTextInsertion,
1676 CanNotExecuteWhenDisabled},
1677 {EditingCommandType::kMoveWordLeftAndModifySelection,
1678 MoveCommands::ExecuteMoveWordLeftAndModifySelection,
1679 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1680 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1681 {EditingCommandType::kMoveWordRight, MoveCommands::ExecuteMoveWordRight,
1682 SupportedFromMenuOrKeyBinding, EnabledInEditableTextOrCaretBrowsing,
1683 StateNone, ValueStateOrNull, kNotTextInsertion,
1684 CanNotExecuteWhenDisabled},
1685 {EditingCommandType::kMoveWordRightAndModifySelection,
1686 MoveCommands::ExecuteMoveWordRightAndModifySelection,
1687 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1688 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1689 {EditingCommandType::kOutdent, ExecuteOutdent, Supported,
1690 EnabledInRichlyEditableText, StateNone, ValueStateOrNull,
1691 kNotTextInsertion, CanNotExecuteWhenDisabled},
1692 {EditingCommandType::kOverWrite, ExecuteToggleOverwrite,
1693 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText, StateNone,
1694 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1695 {EditingCommandType::kPaste, ClipboardCommands::ExecutePaste,
1696 ClipboardCommands::PasteSupported, ClipboardCommands::EnabledPaste,
1697 StateNone, ValueStateOrNull, kNotTextInsertion,
1698 ClipboardCommands::CanReadClipboard},
1699 {EditingCommandType::kPasteAndMatchStyle,
1700 ClipboardCommands::ExecutePasteAndMatchStyle, Supported,
1701 ClipboardCommands::EnabledPaste, StateNone, ValueStateOrNull,
1702 kNotTextInsertion, ClipboardCommands::CanReadClipboard},
1703 {EditingCommandType::kPasteGlobalSelection,
1704 ClipboardCommands::ExecutePasteGlobalSelection,
1705 SupportedFromMenuOrKeyBinding, ClipboardCommands::EnabledPaste,
1706 StateNone, ValueStateOrNull, kNotTextInsertion,
1707 ClipboardCommands::CanReadClipboard},
1708 {EditingCommandType::kPrint, ExecutePrint, Supported, Enabled, StateNone,
1709 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1710 {EditingCommandType::kRedo, ExecuteRedo, Supported, EnabledRedo,
1711 StateNone, ValueStateOrNull, kNotTextInsertion,
1712 CanNotExecuteWhenDisabled},
1713 {EditingCommandType::kRemoveFormat, ExecuteRemoveFormat, Supported,
1714 EnabledRangeInEditableText, StateNone, ValueStateOrNull,
1715 kNotTextInsertion, CanNotExecuteWhenDisabled},
1716 {EditingCommandType::kScrollPageBackward, ExecuteScrollPageBackward,
1717 SupportedFromMenuOrKeyBinding, Enabled, StateNone, ValueStateOrNull,
1718 kNotTextInsertion, CanNotExecuteWhenDisabled},
1719 {EditingCommandType::kScrollPageForward, ExecuteScrollPageForward,
1720 SupportedFromMenuOrKeyBinding, Enabled, StateNone, ValueStateOrNull,
1721 kNotTextInsertion, CanNotExecuteWhenDisabled},
1722 {EditingCommandType::kScrollLineUp, ExecuteScrollLineUp,
1723 SupportedFromMenuOrKeyBinding, Enabled, StateNone, ValueStateOrNull,
1724 kNotTextInsertion, CanNotExecuteWhenDisabled},
1725 {EditingCommandType::kScrollLineDown, ExecuteScrollLineDown,
1726 SupportedFromMenuOrKeyBinding, Enabled, StateNone, ValueStateOrNull,
1727 kNotTextInsertion, CanNotExecuteWhenDisabled},
1728 {EditingCommandType::kScrollToBeginningOfDocument,
1729 ExecuteScrollToBeginningOfDocument, SupportedFromMenuOrKeyBinding,
1730 Enabled, StateNone, ValueStateOrNull, kNotTextInsertion,
1731 CanNotExecuteWhenDisabled},
1732 {EditingCommandType::kScrollToEndOfDocument, ExecuteScrollToEndOfDocument,
1733 SupportedFromMenuOrKeyBinding, Enabled, StateNone, ValueStateOrNull,
1734 kNotTextInsertion, CanNotExecuteWhenDisabled},
1735 {EditingCommandType::kSelectAll, ExecuteSelectAll, Supported,
1736 EnabledSelectAll, StateNone, ValueStateOrNull, kNotTextInsertion,
1737 CanNotExecuteWhenDisabled},
1738 {EditingCommandType::kSelectLine, ExecuteSelectLine,
1739 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1740 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1741 {EditingCommandType::kSelectParagraph, ExecuteSelectParagraph,
1742 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1743 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1744 {EditingCommandType::kSelectSentence, ExecuteSelectSentence,
1745 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1746 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1747 {EditingCommandType::kSelectToMark, ExecuteSelectToMark,
1748 SupportedFromMenuOrKeyBinding, EnabledVisibleSelectionAndMark, StateNone,
1749 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1750 {EditingCommandType::kSelectWord, ExecuteSelectWord,
1751 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1752 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1753 {EditingCommandType::kSetMark, ExecuteSetMark,
1754 SupportedFromMenuOrKeyBinding, EnabledVisibleSelection, StateNone,
1755 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1756 {EditingCommandType::kStrikethrough, StyleCommands::ExecuteStrikethrough,
1757 Supported, EnabledInRichlyEditableText,
1758 StyleCommands::StateStrikethrough, ValueStateOrNull, kNotTextInsertion,
1759 CanNotExecuteWhenDisabled},
1760 {EditingCommandType::kStyleWithCSS, StyleCommands::ExecuteStyleWithCSS,
1761 Supported, Enabled, StyleCommands::StateStyleWithCSS, ValueEmpty,
1762 kNotTextInsertion, CanNotExecuteWhenDisabled},
1763 {EditingCommandType::kSubscript, StyleCommands::ExecuteSubscript,
1764 Supported, EnabledInRichlyEditableText, StyleCommands::StateSubscript,
1765 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1766 {EditingCommandType::kSuperscript, StyleCommands::ExecuteSuperscript,
1767 Supported, EnabledInRichlyEditableText, StyleCommands::StateSuperscript,
1768 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1769 {EditingCommandType::kSwapWithMark, ExecuteSwapWithMark,
1770 SupportedFromMenuOrKeyBinding, EnabledVisibleSelectionAndMark, StateNone,
1771 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1772 {EditingCommandType::kToggleBold, StyleCommands::ExecuteToggleBold,
1773 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText,
1774 StyleCommands::StateBold, ValueStateOrNull, kNotTextInsertion,
1775 CanNotExecuteWhenDisabled},
1776 {EditingCommandType::kToggleItalic, StyleCommands::ExecuteToggleItalic,
1777 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText,
1778 StyleCommands::StateItalic, ValueStateOrNull, kNotTextInsertion,
1779 CanNotExecuteWhenDisabled},
1780 {EditingCommandType::kToggleUnderline, StyleCommands::ExecuteUnderline,
1781 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText,
1782 StyleCommands::StateUnderline, ValueStateOrNull, kNotTextInsertion,
1783 CanNotExecuteWhenDisabled},
1784 {EditingCommandType::kTranspose, ExecuteTranspose, Supported,
1785 EnableCaretInEditableText, StateNone, ValueStateOrNull,
1786 kNotTextInsertion, CanNotExecuteWhenDisabled},
1787 {EditingCommandType::kUnderline, StyleCommands::ExecuteUnderline,
1788 Supported, EnabledInRichlyEditableText, StyleCommands::StateUnderline,
1789 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1790 {EditingCommandType::kUndo, ExecuteUndo, Supported, EnabledUndo,
1791 StateNone, ValueStateOrNull, kNotTextInsertion,
1792 CanNotExecuteWhenDisabled},
1793 {EditingCommandType::kUnlink, ExecuteUnlink, Supported,
1794 EnabledRangeInRichlyEditableText, StateNone, ValueStateOrNull,
1795 kNotTextInsertion, CanNotExecuteWhenDisabled},
1796 {EditingCommandType::kUnscript, StyleCommands::ExecuteUnscript,
1797 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText, StateNone,
1798 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1799 {EditingCommandType::kUnselect, ExecuteUnselect, Supported,
1800 EnabledUnselect, StateNone, ValueStateOrNull, kNotTextInsertion,
1801 CanNotExecuteWhenDisabled},
1802 {EditingCommandType::kUseCSS, StyleCommands::ExecuteUseCSS, Supported,
1803 Enabled, StateNone, ValueStateOrNull, kNotTextInsertion,
1804 CanNotExecuteWhenDisabled},
1805 {EditingCommandType::kYank, ExecuteYank, SupportedFromMenuOrKeyBinding,
1806 EnabledInEditableText, StateNone, ValueStateOrNull, kNotTextInsertion,
1807 CanNotExecuteWhenDisabled},
1808 {EditingCommandType::kYankAndSelect, ExecuteYankAndSelect,
1809 SupportedFromMenuOrKeyBinding, EnabledInEditableText, StateNone,
1810 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1811 {EditingCommandType::kAlignCenter, ExecuteJustifyCenter,
1812 SupportedFromMenuOrKeyBinding, EnabledInRichlyEditableText, StateNone,
1813 ValueStateOrNull, kNotTextInsertion, CanNotExecuteWhenDisabled},
1814 };
1815 // Handles all commands except EditingCommandType::Invalid.
1816 static_assert(
1817 base::size(kEditorCommands) + 1 ==
1818 static_cast<size_t>(EditingCommandType::kNumberOfCommandTypes),
1819 "must handle all valid EditingCommandType");
1820
1821 EditingCommandType command_type =
1822 EditingCommandTypeFromCommandName(command_name);
1823 if (command_type == EditingCommandType::kInvalid)
1824 return nullptr;
1825
1826 int command_index = static_cast<int>(command_type) - 1;
1827 DCHECK(command_index >= 0 &&
1828 command_index < static_cast<int>(base::size(kEditorCommands)));
1829 return &kEditorCommands[command_index];
1830 }
1831
CreateCommand(const String & command_name) const1832 EditorCommand Editor::CreateCommand(const String& command_name) const {
1833 return EditorCommand(InternalCommand(command_name),
1834 EditorCommandSource::kMenuOrKeyBinding, frame_);
1835 }
1836
CreateCommand(const String & command_name,EditorCommandSource source) const1837 EditorCommand Editor::CreateCommand(const String& command_name,
1838 EditorCommandSource source) const {
1839 return EditorCommand(InternalCommand(command_name), source, frame_);
1840 }
1841
ExecuteCommand(const String & command_name)1842 bool Editor::ExecuteCommand(const String& command_name) {
1843 // Specially handling commands that Editor::execCommand does not directly
1844 // support.
1845 DCHECK(GetFrame().GetDocument()->IsActive());
1846 if (command_name == "DeleteToEndOfParagraph") {
1847 if (!DeleteWithDirection(GetFrame(), DeleteDirection::kForward,
1848 TextGranularity::kParagraphBoundary, true,
1849 false)) {
1850 DeleteWithDirection(GetFrame(), DeleteDirection::kForward,
1851 TextGranularity::kCharacter, true, false);
1852 }
1853 return true;
1854 }
1855 if (command_name == "DeleteBackward")
1856 return CreateCommand(AtomicString("BackwardDelete")).Execute();
1857 if (command_name == "DeleteForward")
1858 return CreateCommand(AtomicString("ForwardDelete")).Execute();
1859 if (command_name == "AdvanceToNextMisspelling") {
1860 // TODO(editing-dev): Use of UpdateStyleAndLayout
1861 // needs to be audited. see http://crbug.com/590369 for more details.
1862 GetFrame().GetDocument()->UpdateStyleAndLayout(
1863 DocumentUpdateReason::kEditing);
1864
1865 // We need to pass false here or else the currently selected word will never
1866 // be skipped.
1867 GetSpellChecker().AdvanceToNextMisspelling(false);
1868 return true;
1869 }
1870 if (command_name == "ToggleSpellPanel") {
1871 // TODO(editing-dev): Use of UpdateStyleAndLayout
1872 // needs to be audited.
1873 // see http://crbug.com/590369 for more details.
1874 GetFrame().GetDocument()->UpdateStyleAndLayout(
1875 DocumentUpdateReason::kEditing);
1876
1877 GetSpellChecker().ShowSpellingGuessPanel();
1878 return true;
1879 }
1880 return CreateCommand(command_name).Execute();
1881 }
1882
ExecuteCommand(const String & command_name,const String & value)1883 bool Editor::ExecuteCommand(const String& command_name, const String& value) {
1884 // moveToBeginningOfDocument and moveToEndfDocument are only handled by WebKit
1885 // for editable nodes.
1886 DCHECK(GetFrame().GetDocument()->IsActive());
1887 if (!CanEdit() && command_name == "moveToBeginningOfDocument") {
1888 return GetFrame().GetEventHandler().BubblingScroll(
1889 mojom::blink::ScrollDirection::kScrollUpIgnoringWritingMode,
1890 ScrollGranularity::kScrollByDocument);
1891 }
1892
1893 if (!CanEdit() && command_name == "moveToEndOfDocument") {
1894 return GetFrame().GetEventHandler().BubblingScroll(
1895 mojom::blink::ScrollDirection::kScrollDownIgnoringWritingMode,
1896 ScrollGranularity::kScrollByDocument);
1897 }
1898
1899 if (command_name == "ToggleSpellPanel") {
1900 // TODO(editing-dev): Use of UpdateStyleAndLayout
1901 // needs to be audited. see http://crbug.com/590369 for more details.
1902 GetFrame().GetDocument()->UpdateStyleAndLayout(
1903 DocumentUpdateReason::kEditing);
1904
1905 GetSpellChecker().ShowSpellingGuessPanel();
1906 return true;
1907 }
1908
1909 return CreateCommand(command_name).Execute(value);
1910 }
1911
IsCommandEnabled(const String & command_name) const1912 bool Editor::IsCommandEnabled(const String& command_name) const {
1913 return CreateCommand(command_name).IsEnabled();
1914 }
1915
EditorCommand()1916 EditorCommand::EditorCommand()
1917 : command_(nullptr),
1918 source_(EditorCommandSource::kMenuOrKeyBinding),
1919 frame_(nullptr) {}
1920
EditorCommand(const EditorInternalCommand * command,EditorCommandSource source,LocalFrame * frame)1921 EditorCommand::EditorCommand(const EditorInternalCommand* command,
1922 EditorCommandSource source,
1923 LocalFrame* frame)
1924 : command_(command), source_(source), frame_(command ? frame : nullptr) {
1925 // Use separate assertions so we can tell which bad thing happened.
1926 if (!command)
1927 DCHECK(!frame_);
1928 else
1929 DCHECK(frame_);
1930 }
1931
GetFrame() const1932 LocalFrame& EditorCommand::GetFrame() const {
1933 DCHECK(frame_);
1934 return *frame_;
1935 }
1936
Execute(const String & parameter,Event * triggering_event) const1937 bool EditorCommand::Execute(const String& parameter,
1938 Event* triggering_event) const {
1939 if (!CanExecute(triggering_event))
1940 return false;
1941
1942 if (source_ == EditorCommandSource::kMenuOrKeyBinding) {
1943 InputEvent::InputType input_type =
1944 InputTypeFromCommandType(command_->command_type, *frame_);
1945 if (input_type != InputEvent::InputType::kNone) {
1946 if (DispatchBeforeInputEditorCommand(
1947 EventTargetNodeForDocument(frame_->GetDocument()), input_type,
1948 GetTargetRanges()) != DispatchEventResult::kNotCanceled)
1949 return true;
1950 // 'beforeinput' event handler may destroy target frame.
1951 if (frame_->GetDocument()->GetFrame() != frame_)
1952 return false;
1953 }
1954 }
1955
1956 GetFrame().GetDocument()->UpdateStyleAndLayout(
1957 DocumentUpdateReason::kEditing);
1958 DEFINE_STATIC_LOCAL(SparseHistogram, command_histogram,
1959 ("WebCore.Editing.Commands"));
1960 command_histogram.Sample(static_cast<int>(command_->command_type));
1961 return command_->execute(*frame_, triggering_event, source_, parameter);
1962 }
1963
Execute(Event * triggering_event) const1964 bool EditorCommand::Execute(Event* triggering_event) const {
1965 return Execute(String(), triggering_event);
1966 }
1967
CanExecute(Event * triggering_event) const1968 bool EditorCommand::CanExecute(Event* triggering_event) const {
1969 if (IsEnabled(triggering_event))
1970 return true;
1971 return IsSupported() && frame_ && command_->can_execute(*frame_, source_);
1972 }
1973
IsSupported() const1974 bool EditorCommand::IsSupported() const {
1975 if (!command_)
1976 return false;
1977 switch (source_) {
1978 case EditorCommandSource::kMenuOrKeyBinding:
1979 return true;
1980 case EditorCommandSource::kDOM:
1981 return command_->is_supported_from_dom(frame_);
1982 }
1983 NOTREACHED();
1984 return false;
1985 }
1986
IsEnabled(Event * triggering_event) const1987 bool EditorCommand::IsEnabled(Event* triggering_event) const {
1988 if (!IsSupported() || !frame_)
1989 return false;
1990 return command_->is_enabled(*frame_, triggering_event, source_);
1991 }
1992
GetState(Event * triggering_event) const1993 EditingTriState EditorCommand::GetState(Event* triggering_event) const {
1994 if (!IsSupported() || !frame_)
1995 return EditingTriState::kFalse;
1996 return command_->state(*frame_, triggering_event);
1997 }
1998
Value(Event * triggering_event) const1999 String EditorCommand::Value(Event* triggering_event) const {
2000 if (!IsSupported() || !frame_)
2001 return String();
2002 return command_->value(*command_, *frame_, triggering_event);
2003 }
2004
IsTextInsertion() const2005 bool EditorCommand::IsTextInsertion() const {
2006 return command_ && command_->is_text_insertion;
2007 }
2008
IdForHistogram() const2009 int EditorCommand::IdForHistogram() const {
2010 return IsSupported() ? static_cast<int>(command_->command_type) : 0;
2011 }
2012
GetTargetRanges() const2013 const StaticRangeVector* EditorCommand::GetTargetRanges() const {
2014 const Node* target = EventTargetNodeForDocument(frame_->GetDocument());
2015 if (!IsSupported() || !frame_ || !target || !HasRichlyEditableStyle(*target))
2016 return nullptr;
2017
2018 switch (command_->command_type) {
2019 case EditingCommandType::kDelete:
2020 case EditingCommandType::kDeleteBackward:
2021 return RangesFromCurrentSelectionOrExtendCaret(
2022 *frame_, SelectionModifyDirection::kBackward,
2023 TextGranularity::kCharacter);
2024 case EditingCommandType::kDeleteForward:
2025 return RangesFromCurrentSelectionOrExtendCaret(
2026 *frame_, SelectionModifyDirection::kForward,
2027 TextGranularity::kCharacter);
2028 case EditingCommandType::kDeleteToBeginningOfLine:
2029 return RangesFromCurrentSelectionOrExtendCaret(
2030 *frame_, SelectionModifyDirection::kBackward, TextGranularity::kLine);
2031 case EditingCommandType::kDeleteToBeginningOfParagraph:
2032 return RangesFromCurrentSelectionOrExtendCaret(
2033 *frame_, SelectionModifyDirection::kBackward,
2034 TextGranularity::kParagraph);
2035 case EditingCommandType::kDeleteToEndOfLine:
2036 return RangesFromCurrentSelectionOrExtendCaret(
2037 *frame_, SelectionModifyDirection::kForward, TextGranularity::kLine);
2038 case EditingCommandType::kDeleteToEndOfParagraph:
2039 return RangesFromCurrentSelectionOrExtendCaret(
2040 *frame_, SelectionModifyDirection::kForward,
2041 TextGranularity::kParagraph);
2042 case EditingCommandType::kDeleteWordBackward:
2043 return RangesFromCurrentSelectionOrExtendCaret(
2044 *frame_, SelectionModifyDirection::kBackward, TextGranularity::kWord);
2045 case EditingCommandType::kDeleteWordForward:
2046 return RangesFromCurrentSelectionOrExtendCaret(
2047 *frame_, SelectionModifyDirection::kForward, TextGranularity::kWord);
2048 default:
2049 return TargetRangesForInputEvent(*target);
2050 }
2051 }
2052
2053 } // namespace blink
2054