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