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