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