ff1ad30b56a687cdda09822c75c339225f3a9328
[WebKit-https.git] / Source / WebCore / editing / EditorCommand.cpp
1 /*
2  * Copyright (C) 2006-2008, 2014, 2016 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 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 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 "config.h"
29 #include "Editor.h"
30
31 #include "CSSComputedStyleDeclaration.h"
32 #include "CSSValueList.h"
33 #include "Chrome.h"
34 #include "CreateLinkCommand.h"
35 #include "DocumentFragment.h"
36 #include "Editing.h"
37 #include "EditorClient.h"
38 #include "Event.h"
39 #include "EventHandler.h"
40 #include "FormatBlockCommand.h"
41 #include "Frame.h"
42 #include "FrameLoader.h"
43 #include "FrameView.h"
44 #include "HTMLFontElement.h"
45 #include "HTMLHRElement.h"
46 #include "HTMLImageElement.h"
47 #include "HTMLNames.h"
48 #include "IndentOutdentCommand.h"
49 #include "InsertListCommand.h"
50 #include "Page.h"
51 #include "Pasteboard.h"
52 #include "RenderBox.h"
53 #include "ReplaceSelectionCommand.h"
54 #include "Scrollbar.h"
55 #include "Settings.h"
56 #include "StyleProperties.h"
57 #include "TypingCommand.h"
58 #include "UnlinkCommand.h"
59 #include "UserGestureIndicator.h"
60 #include "UserTypingGestureIndicator.h"
61 #include "markup.h"
62 #include <pal/system/Sound.h>
63 #include <pal/text/KillRing.h>
64 #include <wtf/text/AtomicString.h>
65
66 namespace WebCore {
67
68 using namespace HTMLNames;
69
70 class EditorInternalCommand {
71 public:
72     bool (*execute)(Frame&, Event*, EditorCommandSource, const String&);
73     bool (*isSupportedFromDOM)(Frame*);
74     bool (*isEnabled)(Frame&, Event*, EditorCommandSource);
75     TriState (*state)(Frame&, Event*);
76     String (*value)(Frame&, Event*);
77     bool isTextInsertion;
78     bool (*allowExecutionWhenDisabled)(Frame&, EditorCommandSource);
79 };
80
81 typedef HashMap<String, const EditorInternalCommand*, ASCIICaseInsensitiveHash> CommandMap;
82
83 static const bool notTextInsertion = false;
84 static const bool isTextInsertion = true;
85
86 // Related to Editor::selectionForCommand.
87 // Certain operations continue to use the target control's selection even if the event handler
88 // already moved the selection outside of the text control.
89 static Frame* targetFrame(Frame& frame, Event* event)
90 {
91     if (!event)
92         return &frame;
93     if (!is<Node>(event->target()))
94         return &frame;
95     return downcast<Node>(*event->target()).document().frame();
96 }
97
98 static bool applyCommandToFrame(Frame& frame, EditorCommandSource source, EditAction action, Ref<EditingStyle>&& style)
99 {
100     // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
101     switch (source) {
102     case CommandFromMenuOrKeyBinding:
103         // Use InvertColor for testing purposes. foreColor and backColor are never triggered with CommandFromMenuOrKeyBinding outside DRT/WTR.
104         frame.editor().applyStyleToSelection(WTFMove(style), action, Editor::ColorFilterMode::InvertColor);
105         return true;
106     case CommandFromDOM:
107     case CommandFromDOMWithUserInterface:
108         frame.editor().applyStyle(WTFMove(style), EditAction::Unspecified, Editor::ColorFilterMode::UseOriginalColor);
109         return true;
110     }
111     ASSERT_NOT_REACHED();
112     return false;
113 }
114
115 static bool isStylePresent(Editor& editor, CSSPropertyID propertyID, const char* onValue)
116 {
117     // Style is considered present when
118     // Mac: present at the beginning of selection
119     // Windows: present throughout the selection
120     if (editor.behavior().shouldToggleStyleBasedOnStartOfSelection())
121         return editor.selectionStartHasStyle(propertyID, onValue);
122     return editor.selectionHasStyle(propertyID, onValue) == TrueTriState;
123 }
124
125 static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
126 {
127     return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
128 }
129
130 static bool executeApplyStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, CSSValueID propertyValue)
131 {
132     return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, propertyValue));
133 }
134
135 static bool executeToggleStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const char* offValue, const char* onValue)
136 {
137     bool styleIsPresent = isStylePresent(frame.editor(), propertyID, onValue);
138     return applyCommandToFrame(frame, source, action, EditingStyle::create(propertyID, styleIsPresent ? offValue : onValue));
139 }
140
141 static bool executeApplyParagraphStyle(Frame& frame, EditorCommandSource source, EditAction action, CSSPropertyID propertyID, const String& propertyValue)
142 {
143     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
144     style->setProperty(propertyID, propertyValue);
145     // FIXME: We don't call shouldApplyStyle when the source is DOM; is there a good reason for that?
146     switch (source) {
147     case CommandFromMenuOrKeyBinding:
148         frame.editor().applyParagraphStyleToSelection(style.get(), action);
149         return true;
150     case CommandFromDOM:
151     case CommandFromDOMWithUserInterface:
152         frame.editor().applyParagraphStyle(style.get());
153         return true;
154     }
155     ASSERT_NOT_REACHED();
156     return false;
157 }
158
159 static bool executeInsertFragment(Frame& frame, Ref<DocumentFragment>&& fragment)
160 {
161     ASSERT(frame.document());
162     ReplaceSelectionCommand::create(*frame.document(), WTFMove(fragment), ReplaceSelectionCommand::PreventNesting, EditAction::Insert)->apply();
163     return true;
164 }
165
166 static bool executeInsertNode(Frame& frame, Ref<Node>&& content)
167 {
168     auto fragment = DocumentFragment::create(*frame.document());
169     if (fragment->appendChild(content).hasException())
170         return false;
171     return executeInsertFragment(frame, WTFMove(fragment));
172 }
173
174 static bool expandSelectionToGranularity(Frame& frame, TextGranularity granularity)
175 {
176     VisibleSelection selection = frame.selection().selection();
177     selection.expandUsingGranularity(granularity);
178     RefPtr<Range> newRange = selection.toNormalizedRange();
179     if (!newRange)
180         return false;
181     if (newRange->collapsed())
182         return false;
183     RefPtr<Range> oldRange = selection.toNormalizedRange();
184     EAffinity affinity = selection.affinity();
185     if (!frame.editor().client()->shouldChangeSelectedRange(oldRange.get(), newRange.get(), affinity, false))
186         return false;
187     frame.selection().setSelectedRange(newRange.get(), affinity, true);
188     return true;
189 }
190
191 static TriState stateStyle(Frame& frame, CSSPropertyID propertyID, const char* desiredValue)
192 {
193     if (frame.editor().behavior().shouldToggleStyleBasedOnStartOfSelection())
194         return frame.editor().selectionStartHasStyle(propertyID, desiredValue) ? TrueTriState : FalseTriState;
195     return frame.editor().selectionHasStyle(propertyID, desiredValue);
196 }
197
198 static String valueStyle(Frame& frame, CSSPropertyID propertyID)
199 {
200     // FIXME: Rather than retrieving the style at the start of the current selection,
201     // we should retrieve the style present throughout the selection for non-Mac platforms.
202     return frame.editor().selectionStartCSSPropertyValue(propertyID);
203 }
204
205 static TriState stateTextWritingDirection(Frame& frame, WritingDirection direction)
206 {
207     bool hasNestedOrMultipleEmbeddings;
208     WritingDirection selectionDirection = EditingStyle::textDirectionForSelection(frame.selection().selection(),
209         frame.selection().typingStyle(), hasNestedOrMultipleEmbeddings);
210     // FXIME: We should be returning MixedTriState when selectionDirection == direction && hasNestedOrMultipleEmbeddings
211     return (selectionDirection == direction && !hasNestedOrMultipleEmbeddings) ? TrueTriState : FalseTriState;
212 }
213
214 static unsigned verticalScrollDistance(Frame& frame)
215 {
216     Element* focusedElement = frame.document()->focusedElement();
217     if (!focusedElement)
218         return 0;
219     auto* renderer = focusedElement->renderer();
220     if (!is<RenderBox>(renderer))
221         return 0;
222     const RenderStyle& style = renderer->style();
223     if (!(style.overflowY() == Overflow::Scroll || style.overflowY() == Overflow::Auto || focusedElement->hasEditableStyle()))
224         return 0;
225     int height = std::min<int>(downcast<RenderBox>(*renderer).clientHeight(), frame.view()->visibleHeight());
226     return static_cast<unsigned>(Scrollbar::pageStep(height));
227 }
228
229 static RefPtr<Range> unionDOMRanges(Range& a, Range& b)
230 {
231     Range& start = a.compareBoundaryPoints(Range::START_TO_START, b).releaseReturnValue() <= 0 ? a : b;
232     Range& end = a.compareBoundaryPoints(Range::END_TO_END, b).releaseReturnValue() <= 0 ? b : a;
233     return Range::create(a.ownerDocument(), &start.startContainer(), start.startOffset(), &end.endContainer(), end.endOffset());
234 }
235
236 // Execute command functions
237
238 static bool executeBackColor(Frame& frame, Event*, EditorCommandSource source, const String& value)
239 {
240     return executeApplyStyle(frame, source, EditAction::SetBackgroundColor, CSSPropertyBackgroundColor, value);
241 }
242
243 static bool executeCopy(Frame& frame, Event*, EditorCommandSource, const String&)
244 {
245     frame.editor().copy();
246     return true;
247 }
248
249 static bool executeCreateLink(Frame& frame, Event*, EditorCommandSource, const String& value)
250 {
251     // FIXME: If userInterface is true, we should display a dialog box to let the user enter a URL.
252     if (value.isEmpty())
253         return false;
254     ASSERT(frame.document());
255     CreateLinkCommand::create(*frame.document(), value)->apply();
256     return true;
257 }
258
259 static bool executeCut(Frame& frame, Event*, EditorCommandSource source, const String&)
260 {
261     if (source == CommandFromMenuOrKeyBinding) {
262         UserTypingGestureIndicator typingGestureIndicator(frame);
263         frame.editor().cut();
264     } else
265         frame.editor().cut();
266     return true;
267 }
268
269 static bool executeClearText(Frame& frame, Event*, EditorCommandSource, const String&)
270 {
271     frame.editor().clearText();
272     return true;
273 }
274
275 static bool executeDefaultParagraphSeparator(Frame& frame, Event*, EditorCommandSource, const String& value)
276 {
277     if (equalLettersIgnoringASCIICase(value, "div"))
278         frame.editor().setDefaultParagraphSeparator(EditorParagraphSeparatorIsDiv);
279     else if (equalLettersIgnoringASCIICase(value, "p"))
280         frame.editor().setDefaultParagraphSeparator(EditorParagraphSeparatorIsP);
281
282     return true;
283 }
284
285 static bool executeDelete(Frame& frame, Event*, EditorCommandSource source, const String&)
286 {
287     switch (source) {
288     case CommandFromMenuOrKeyBinding: {
289         // Doesn't modify the text if the current selection isn't a range.
290         UserTypingGestureIndicator typingGestureIndicator(frame);
291         frame.editor().performDelete();
292         return true;
293     }
294     case CommandFromDOM:
295     case CommandFromDOMWithUserInterface:
296         // If the current selection is a caret, delete the preceding character. IE performs forwardDelete, but we currently side with Firefox.
297         // Doesn't scroll to make the selection visible, or modify the kill ring (this time, siding with IE, not Firefox).
298         TypingCommand::deleteKeyPressed(*frame.document(), frame.selection().granularity() == WordGranularity ? TypingCommand::SmartDelete : 0);
299         return true;
300     }
301     ASSERT_NOT_REACHED();
302     return false;
303 }
304
305 static bool executeDeleteBackward(Frame& frame, Event*, EditorCommandSource, const String&)
306 {
307     frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
308     return true;
309 }
310
311 static bool executeDeleteBackwardByDecomposingPreviousCharacter(Frame& frame, Event*, EditorCommandSource, const String&)
312 {
313     LOG_ERROR("DeleteBackwardByDecomposingPreviousCharacter is not implemented, doing DeleteBackward instead");
314     frame.editor().deleteWithDirection(DirectionBackward, CharacterGranularity, false, true);
315     return true;
316 }
317
318 static bool executeDeleteForward(Frame& frame, Event*, EditorCommandSource, const String&)
319 {
320     frame.editor().deleteWithDirection(DirectionForward, CharacterGranularity, false, true);
321     return true;
322 }
323
324 static bool executeDeleteToBeginningOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
325 {
326     frame.editor().deleteWithDirection(DirectionBackward, LineBoundary, true, false);
327     return true;
328 }
329
330 static bool executeDeleteToBeginningOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
331 {
332     frame.editor().deleteWithDirection(DirectionBackward, ParagraphBoundary, true, false);
333     return true;
334 }
335
336 static bool executeDeleteToEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
337 {
338     // Despite its name, this command should delete the newline at the end of
339     // a paragraph if you are at the end of a paragraph (like DeleteToEndOfParagraph).
340     frame.editor().deleteWithDirection(DirectionForward, LineBoundary, true, false);
341     return true;
342 }
343
344 static bool executeDeleteToEndOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
345 {
346     // Despite its name, this command should delete the newline at the end of
347     // a paragraph if you are at the end of a paragraph.
348     frame.editor().deleteWithDirection(DirectionForward, ParagraphBoundary, true, false);
349     return true;
350 }
351
352 static bool executeDeleteToMark(Frame& frame, Event*, EditorCommandSource, const String&)
353 {
354     RefPtr<Range> mark = frame.editor().mark().toNormalizedRange();
355     FrameSelection& selection = frame.selection();
356     if (mark && frame.editor().selectedRange()) {
357         bool selected = selection.setSelectedRange(unionDOMRanges(*mark, *frame.editor().selectedRange()).get(), DOWNSTREAM, true);
358         ASSERT(selected);
359         if (!selected)
360             return false;
361     }
362     frame.editor().performDelete();
363     frame.editor().setMark(selection.selection());
364     return true;
365 }
366
367 static bool executeDeleteWordBackward(Frame& frame, Event*, EditorCommandSource, const String&)
368 {
369     frame.editor().deleteWithDirection(DirectionBackward, WordGranularity, true, false);
370     return true;
371 }
372
373 static bool executeDeleteWordForward(Frame& frame, Event*, EditorCommandSource, const String&)
374 {
375     frame.editor().deleteWithDirection(DirectionForward, WordGranularity, true, false);
376     return true;
377 }
378
379 static bool executeFindString(Frame& frame, Event*, EditorCommandSource, const String& value)
380 {
381     return frame.editor().findString(value, { CaseInsensitive, WrapAround, DoNotTraverseFlatTree });
382 }
383
384 static bool executeFontName(Frame& frame, Event*, EditorCommandSource source, const String& value)
385 {
386     return executeApplyStyle(frame, source, EditAction::SetFont, CSSPropertyFontFamily, value);
387 }
388
389 static bool executeFontSize(Frame& frame, Event*, EditorCommandSource source, const String& value)
390 {
391     CSSValueID size;
392     if (!HTMLFontElement::cssValueFromFontSizeNumber(value, size))
393         return false;
394     return executeApplyStyle(frame, source, EditAction::ChangeAttributes, CSSPropertyFontSize, size);
395 }
396
397 static bool executeFontSizeDelta(Frame& frame, Event*, EditorCommandSource source, const String& value)
398 {
399     return executeApplyStyle(frame, source, EditAction::ChangeAttributes, CSSPropertyWebkitFontSizeDelta, value);
400 }
401
402 static bool executeForeColor(Frame& frame, Event*, EditorCommandSource source, const String& value)
403 {
404     return executeApplyStyle(frame, source, EditAction::SetColor, CSSPropertyColor, value);
405 }
406
407 static bool executeFormatBlock(Frame& frame, Event*, EditorCommandSource, const String& value)
408 {
409     String tagName = value.convertToASCIILowercase();
410     if (tagName[0] == '<' && tagName[tagName.length() - 1] == '>')
411         tagName = tagName.substring(1, tagName.length() - 2);
412
413     auto qualifiedTagName = Document::parseQualifiedName(xhtmlNamespaceURI, tagName);
414     if (qualifiedTagName.hasException())
415         return false;
416
417     ASSERT(frame.document());
418     auto command = FormatBlockCommand::create(*frame.document(), qualifiedTagName.releaseReturnValue());
419     command->apply();
420     return command->didApply();
421 }
422
423 static bool executeForwardDelete(Frame& frame, Event*, EditorCommandSource source, const String&)
424 {
425     switch (source) {
426     case CommandFromMenuOrKeyBinding:
427         frame.editor().deleteWithDirection(DirectionForward, CharacterGranularity, false, true);
428         return true;
429     case CommandFromDOM:
430     case CommandFromDOMWithUserInterface:
431         // Doesn't scroll to make the selection visible, or modify the kill ring.
432         // ForwardDelete is not implemented in IE or Firefox, so this behavior is only needed for
433         // backward compatibility with ourselves, and for consistency with Delete.
434         TypingCommand::forwardDeleteKeyPressed(*frame.document());
435         return true;
436     }
437     ASSERT_NOT_REACHED();
438     return false;
439 }
440
441 static bool executeIgnoreSpelling(Frame& frame, Event*, EditorCommandSource, const String&)
442 {
443     frame.editor().ignoreSpelling();
444     return true;
445 }
446
447 static bool executeIndent(Frame& frame, Event*, EditorCommandSource, const String&)
448 {
449     ASSERT(frame.document());
450     IndentOutdentCommand::create(*frame.document(), IndentOutdentCommand::Indent)->apply();
451     return true;
452 }
453
454 static bool executeInsertBacktab(Frame& frame, Event* event, EditorCommandSource, const String&)
455 {
456     return targetFrame(frame, event)->eventHandler().handleTextInputEvent("\t"_s, event, TextEventInputBackTab);
457 }
458
459 static bool executeInsertHorizontalRule(Frame& frame, Event*, EditorCommandSource, const String& value)
460 {
461     Ref<HTMLHRElement> rule = HTMLHRElement::create(*frame.document());
462     if (!value.isEmpty())
463         rule->setIdAttribute(value);
464     return executeInsertNode(frame, WTFMove(rule));
465 }
466
467 static bool executeInsertHTML(Frame& frame, Event*, EditorCommandSource, const String& value)
468 {
469     return executeInsertFragment(frame, createFragmentFromMarkup(*frame.document(), value, emptyString()));
470 }
471
472 static bool executeInsertImage(Frame& frame, Event*, EditorCommandSource, const String& value)
473 {
474     // FIXME: If userInterface is true, we should display a dialog box and let the user choose a local image.
475     Ref<HTMLImageElement> image = HTMLImageElement::create(*frame.document());
476     image->setSrc(value);
477     return executeInsertNode(frame, WTFMove(image));
478 }
479
480 static bool executeInsertLineBreak(Frame& frame, Event* event, EditorCommandSource source, const String&)
481 {
482     switch (source) {
483     case CommandFromMenuOrKeyBinding:
484         return targetFrame(frame, event)->eventHandler().handleTextInputEvent("\n"_s, event, TextEventInputLineBreak);
485     case CommandFromDOM:
486     case CommandFromDOMWithUserInterface:
487         // Doesn't scroll to make the selection visible, or modify the kill ring.
488         // InsertLineBreak is not implemented in IE or Firefox, so this behavior is only needed for
489         // backward compatibility with ourselves, and for consistency with other commands.
490         TypingCommand::insertLineBreak(*frame.document(), 0);
491         return true;
492     }
493     ASSERT_NOT_REACHED();
494     return false;
495 }
496
497 static bool executeInsertNewline(Frame& frame, Event* event, EditorCommandSource, const String&)
498 {
499     Frame* targetFrame = WebCore::targetFrame(frame, event);
500     return targetFrame->eventHandler().handleTextInputEvent("\n"_s, event, targetFrame->editor().canEditRichly() ? TextEventInputKeyboard : TextEventInputLineBreak);
501 }
502
503 static bool executeInsertNewlineInQuotedContent(Frame& frame, Event*, EditorCommandSource, const String&)
504 {
505     TypingCommand::insertParagraphSeparatorInQuotedContent(*frame.document());
506     return true;
507 }
508
509 static bool executeInsertOrderedList(Frame& frame, Event*, EditorCommandSource, const String&)
510 {
511     ASSERT(frame.document());
512     InsertListCommand::create(*frame.document(), InsertListCommand::OrderedList)->apply();
513     return true;
514 }
515
516 static bool executeInsertParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
517 {
518     TypingCommand::insertParagraphSeparator(*frame.document(), 0);
519     return true;
520 }
521
522 static bool executeInsertTab(Frame& frame, Event* event, EditorCommandSource, const String&)
523 {
524     return targetFrame(frame, event)->eventHandler().handleTextInputEvent("\t"_s, event);
525 }
526
527 static bool executeInsertText(Frame& frame, Event*, EditorCommandSource, const String& value)
528 {
529     TypingCommand::insertText(*frame.document(), value, 0);
530     return true;
531 }
532
533 static bool executeInsertUnorderedList(Frame& frame, Event*, EditorCommandSource, const String&)
534 {
535     ASSERT(frame.document());
536     InsertListCommand::create(*frame.document(), InsertListCommand::UnorderedList)->apply();
537     return true;
538 }
539
540 static bool executeJustifyCenter(Frame& frame, Event*, EditorCommandSource source, const String&)
541 {
542     return executeApplyParagraphStyle(frame, source, EditAction::Center, CSSPropertyTextAlign, "center"_s);
543 }
544
545 static bool executeJustifyFull(Frame& frame, Event*, EditorCommandSource source, const String&)
546 {
547     return executeApplyParagraphStyle(frame, source, EditAction::Justify, CSSPropertyTextAlign, "justify"_s);
548 }
549
550 static bool executeJustifyLeft(Frame& frame, Event*, EditorCommandSource source, const String&)
551 {
552     return executeApplyParagraphStyle(frame, source, EditAction::AlignLeft, CSSPropertyTextAlign, "left"_s);
553 }
554
555 static bool executeJustifyRight(Frame& frame, Event*, EditorCommandSource source, const String&)
556 {
557     return executeApplyParagraphStyle(frame, source, EditAction::AlignRight, CSSPropertyTextAlign, "right"_s);
558 }
559
560 static bool executeMakeTextWritingDirectionLeftToRight(Frame& frame, Event*, EditorCommandSource, const String&)
561 {
562     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
563     style->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed);
564     style->setProperty(CSSPropertyDirection, CSSValueLtr);
565     frame.editor().applyStyle(style.get(), EditAction::SetWritingDirection);
566     return true;
567 }
568
569 static bool executeMakeTextWritingDirectionNatural(Frame& frame, Event*, EditorCommandSource, const String&)
570 {
571     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
572     style->setProperty(CSSPropertyUnicodeBidi, CSSValueNormal);
573     frame.editor().applyStyle(style.get(), EditAction::SetWritingDirection);
574     return true;
575 }
576
577 static bool executeMakeTextWritingDirectionRightToLeft(Frame& frame, Event*, EditorCommandSource, const String&)
578 {
579     RefPtr<MutableStyleProperties> style = MutableStyleProperties::create();
580     style->setProperty(CSSPropertyUnicodeBidi, CSSValueEmbed);
581     style->setProperty(CSSPropertyDirection, CSSValueRtl);
582     frame.editor().applyStyle(style.get(), EditAction::SetWritingDirection);
583     return true;
584 }
585
586 static bool executeMoveBackward(Frame& frame, Event*, EditorCommandSource, const String&)
587 {
588     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, CharacterGranularity, UserTriggered);
589     return true;
590 }
591
592 static bool executeMoveBackwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
593 {
594     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, CharacterGranularity, UserTriggered);
595     return true;
596 }
597
598 static bool executeMoveDown(Frame& frame, Event*, EditorCommandSource, const String&)
599 {
600     return frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, LineGranularity, UserTriggered);
601 }
602
603 static bool executeMoveDownAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
604 {
605     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, LineGranularity, UserTriggered);
606     return true;
607 }
608
609 static bool executeMoveForward(Frame& frame, Event*, EditorCommandSource, const String&)
610 {
611     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, CharacterGranularity, UserTriggered);
612     return true;
613 }
614
615 static bool executeMoveForwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
616 {
617     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, CharacterGranularity, UserTriggered);
618     return true;
619 }
620
621 static bool executeMoveLeft(Frame& frame, Event*, EditorCommandSource, const String&)
622 {
623     return frame.selection().modify(FrameSelection::AlterationMove, DirectionLeft, CharacterGranularity, UserTriggered);
624 }
625
626 static bool executeMoveLeftAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
627 {
628     frame.selection().modify(FrameSelection::AlterationExtend, DirectionLeft, CharacterGranularity, UserTriggered);
629     return true;
630 }
631
632 static bool executeMovePageDown(Frame& frame, Event*, EditorCommandSource, const String&)
633 {
634     unsigned distance = verticalScrollDistance(frame);
635     if (!distance)
636         return false;
637     return frame.selection().modify(FrameSelection::AlterationMove, distance, FrameSelection::DirectionDown,
638         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
639 }
640
641 static bool executeMovePageDownAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
642 {
643     unsigned distance = verticalScrollDistance(frame);
644     if (!distance)
645         return false;
646     return frame.selection().modify(FrameSelection::AlterationExtend, distance, FrameSelection::DirectionDown,
647         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
648 }
649
650 static bool executeMovePageUp(Frame& frame, Event*, EditorCommandSource, const String&)
651 {
652     unsigned distance = verticalScrollDistance(frame);
653     if (!distance)
654         return false;
655     return frame.selection().modify(FrameSelection::AlterationMove, distance, FrameSelection::DirectionUp,
656         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
657 }
658
659 static bool executeMovePageUpAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
660 {
661     unsigned distance = verticalScrollDistance(frame);
662     if (!distance)
663         return false;
664     return frame.selection().modify(FrameSelection::AlterationExtend, distance, FrameSelection::DirectionUp,
665         UserTriggered, FrameSelection::AlignCursorOnScrollAlways);
666 }
667
668 static bool executeMoveRight(Frame& frame, Event*, EditorCommandSource, const String&)
669 {
670     return frame.selection().modify(FrameSelection::AlterationMove, DirectionRight, CharacterGranularity, UserTriggered);
671 }
672
673 static bool executeMoveRightAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
674 {
675     frame.selection().modify(FrameSelection::AlterationExtend, DirectionRight, CharacterGranularity, UserTriggered);
676     return true;
677 }
678
679 static bool executeMoveToBeginningOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
680 {
681     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, DocumentBoundary, UserTriggered);
682     return true;
683 }
684
685 static bool executeMoveToBeginningOfDocumentAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
686 {
687     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, DocumentBoundary, UserTriggered);
688     return true;
689 }
690
691 static bool executeMoveToBeginningOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
692 {
693     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, LineBoundary, UserTriggered);
694     return true;
695 }
696
697 static bool executeMoveToBeginningOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
698 {
699     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, LineBoundary, UserTriggered);
700     return true;
701 }
702
703 static bool executeMoveToBeginningOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
704 {
705     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, ParagraphBoundary, UserTriggered);
706     return true;
707 }
708
709 static bool executeMoveToBeginningOfParagraphAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
710 {
711     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, ParagraphBoundary, UserTriggered);
712     return true;
713 }
714
715 static bool executeMoveToBeginningOfSentence(Frame& frame, Event*, EditorCommandSource, const String&)
716 {
717     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, SentenceBoundary, UserTriggered);
718     return true;
719 }
720
721 static bool executeMoveToBeginningOfSentenceAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
722 {
723     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, SentenceBoundary, UserTriggered);
724     return true;
725 }
726
727 static bool executeMoveToEndOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
728 {
729     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, DocumentBoundary, UserTriggered);
730     return true;
731 }
732
733 static bool executeMoveToEndOfDocumentAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
734 {
735     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, DocumentBoundary, UserTriggered);
736     return true;
737 }
738
739 static bool executeMoveToEndOfSentence(Frame& frame, Event*, EditorCommandSource, const String&)
740 {
741     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, SentenceBoundary, UserTriggered);
742     return true;
743 }
744
745 static bool executeMoveToEndOfSentenceAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
746 {
747     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, SentenceBoundary, UserTriggered);
748     return true;
749 }
750
751 static bool executeMoveToEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
752 {
753     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, LineBoundary, UserTriggered);
754     return true;
755 }
756
757 static bool executeMoveToEndOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
758 {
759     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, LineBoundary, UserTriggered);
760     return true;
761 }
762
763 static bool executeMoveToEndOfParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
764 {
765     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, ParagraphBoundary, UserTriggered);
766     return true;
767 }
768
769 static bool executeMoveToEndOfParagraphAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
770 {
771     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, ParagraphBoundary, UserTriggered);
772     return true;
773 }
774
775 static bool executeMoveParagraphBackwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
776 {
777     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, ParagraphGranularity, UserTriggered);
778     return true;
779 }
780
781 static bool executeMoveParagraphForwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
782 {
783     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, ParagraphGranularity, UserTriggered);
784     return true;
785 }
786
787 static bool executeMoveUp(Frame& frame, Event*, EditorCommandSource, const String&)
788 {
789     return frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, LineGranularity, UserTriggered);
790 }
791
792 static bool executeMoveUpAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
793 {
794     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, LineGranularity, UserTriggered);
795     return true;
796 }
797
798 static bool executeMoveWordBackward(Frame& frame, Event*, EditorCommandSource, const String&)
799 {
800     frame.selection().modify(FrameSelection::AlterationMove, DirectionBackward, WordGranularity, UserTriggered);
801     return true;
802 }
803
804 static bool executeMoveWordBackwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
805 {
806     frame.selection().modify(FrameSelection::AlterationExtend, DirectionBackward, WordGranularity, UserTriggered);
807     return true;
808 }
809
810 static bool executeMoveWordForward(Frame& frame, Event*, EditorCommandSource, const String&)
811 {
812     frame.selection().modify(FrameSelection::AlterationMove, DirectionForward, WordGranularity, UserTriggered);
813     return true;
814 }
815
816 static bool executeMoveWordForwardAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
817 {
818     frame.selection().modify(FrameSelection::AlterationExtend, DirectionForward, WordGranularity, UserTriggered);
819     return true;
820 }
821
822 static bool executeMoveWordLeft(Frame& frame, Event*, EditorCommandSource, const String&)
823 {
824     frame.selection().modify(FrameSelection::AlterationMove, DirectionLeft, WordGranularity, UserTriggered);
825     return true;
826 }
827
828 static bool executeMoveWordLeftAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
829 {
830     frame.selection().modify(FrameSelection::AlterationExtend, DirectionLeft, WordGranularity, UserTriggered);
831     return true;
832 }
833
834 static bool executeMoveWordRight(Frame& frame, Event*, EditorCommandSource, const String&)
835 {
836     frame.selection().modify(FrameSelection::AlterationMove, DirectionRight, WordGranularity, UserTriggered);
837     return true;
838 }
839
840 static bool executeMoveWordRightAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
841 {
842     frame.selection().modify(FrameSelection::AlterationExtend, DirectionRight, WordGranularity, UserTriggered);
843     return true;
844 }
845
846 static bool executeMoveToLeftEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
847 {
848     frame.selection().modify(FrameSelection::AlterationMove, DirectionLeft, LineBoundary, UserTriggered);
849     return true;
850 }
851
852 static bool executeMoveToLeftEndOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
853 {
854     frame.selection().modify(FrameSelection::AlterationExtend, DirectionLeft, LineBoundary, UserTriggered);
855     return true;
856 }
857
858 static bool executeMoveToRightEndOfLine(Frame& frame, Event*, EditorCommandSource, const String&)
859 {
860     frame.selection().modify(FrameSelection::AlterationMove, DirectionRight, LineBoundary, UserTriggered);
861     return true;
862 }
863
864 static bool executeMoveToRightEndOfLineAndModifySelection(Frame& frame, Event*, EditorCommandSource, const String&)
865 {
866     frame.selection().modify(FrameSelection::AlterationExtend, DirectionRight, LineBoundary, UserTriggered);
867     return true;
868 }
869
870 static bool executeOutdent(Frame& frame, Event*, EditorCommandSource, const String&)
871 {
872     ASSERT(frame.document());
873     IndentOutdentCommand::create(*frame.document(), IndentOutdentCommand::Outdent)->apply();
874     return true;
875 }
876
877 static bool executeToggleOverwrite(Frame& frame, Event*, EditorCommandSource, const String&)
878 {
879     frame.editor().toggleOverwriteModeEnabled();
880     return true;
881 }
882
883 static bool executePaste(Frame& frame, Event*, EditorCommandSource source, const String&)
884 {
885     if (source == CommandFromMenuOrKeyBinding) {
886         UserTypingGestureIndicator typingGestureIndicator(frame);
887         frame.editor().paste();
888     } else
889         frame.editor().paste();
890     return true;
891 }
892
893 #if PLATFORM(GTK)
894
895 static bool executePasteGlobalSelection(Frame& frame, Event*, EditorCommandSource source, const String&)
896 {
897     // FIXME: This check should be in an enable function, not here.
898     if (!frame.editor().client()->supportsGlobalSelection())
899         return false;
900
901     ASSERT_UNUSED(source, source == CommandFromMenuOrKeyBinding);
902     UserTypingGestureIndicator typingGestureIndicator(frame);
903     frame.editor().paste(*Pasteboard::createForGlobalSelection());
904     return true;
905 }
906
907 #endif
908
909 static bool executePasteAndMatchStyle(Frame& frame, Event*, EditorCommandSource source, const String&)
910 {
911     if (source == CommandFromMenuOrKeyBinding) {
912         UserTypingGestureIndicator typingGestureIndicator(frame);
913         frame.editor().pasteAsPlainText();
914     } else
915         frame.editor().pasteAsPlainText();
916     return true;
917 }
918
919 static bool executePasteAsPlainText(Frame& frame, Event*, EditorCommandSource source, const String&)
920 {
921     if (source == CommandFromMenuOrKeyBinding) {
922         UserTypingGestureIndicator typingGestureIndicator(frame);
923         frame.editor().pasteAsPlainText();
924     } else
925         frame.editor().pasteAsPlainText();
926     return true;
927 }
928
929 static bool executePasteAsQuotation(Frame& frame, Event*, EditorCommandSource source, const String&)
930 {
931     if (source == CommandFromMenuOrKeyBinding) {
932         UserTypingGestureIndicator typingGestureIndicator(frame);
933         frame.editor().pasteAsQuotation();
934     } else
935         frame.editor().pasteAsQuotation();
936     return true;
937 }
938
939 static bool executePrint(Frame& frame, Event*, EditorCommandSource, const String&)
940 {
941     Page* page = frame.page();
942     if (!page)
943         return false;
944     return page->chrome().print(frame);
945 }
946
947 static bool executeRedo(Frame& frame, Event*, EditorCommandSource, const String&)
948 {
949     frame.editor().redo();
950     return true;
951 }
952
953 static bool executeRemoveFormat(Frame& frame, Event*, EditorCommandSource, const String&)
954 {
955     frame.editor().removeFormattingAndStyle();
956     return true;
957 }
958
959 static bool executeScrollPageBackward(Frame& frame, Event*, EditorCommandSource, const String&)
960 {
961     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByPage);
962 }
963
964 static bool executeScrollPageForward(Frame& frame, Event*, EditorCommandSource, const String&)
965 {
966     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByPage);
967 }
968
969 static bool executeScrollLineUp(Frame& frame, Event*, EditorCommandSource, const String&)
970 {
971     return frame.eventHandler().scrollRecursively(ScrollUp, ScrollByLine);
972 }
973
974 static bool executeScrollLineDown(Frame& frame, Event*, EditorCommandSource, const String&)
975 {
976     return frame.eventHandler().scrollRecursively(ScrollDown, ScrollByLine);
977 }
978
979 static bool executeScrollToBeginningOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
980 {
981     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionBackward, ScrollByDocument);
982 }
983
984 static bool executeScrollToEndOfDocument(Frame& frame, Event*, EditorCommandSource, const String&)
985 {
986     return frame.eventHandler().logicalScrollRecursively(ScrollBlockDirectionForward, ScrollByDocument);
987 }
988
989 static bool executeSelectAll(Frame& frame, Event*, EditorCommandSource, const String&)
990 {
991     frame.selection().selectAll();
992     return true;
993 }
994
995 static bool executeSelectLine(Frame& frame, Event*, EditorCommandSource, const String&)
996 {
997     return expandSelectionToGranularity(frame, LineGranularity);
998 }
999
1000 static bool executeSelectParagraph(Frame& frame, Event*, EditorCommandSource, const String&)
1001 {
1002     return expandSelectionToGranularity(frame, ParagraphGranularity);
1003 }
1004
1005 static bool executeSelectSentence(Frame& frame, Event*, EditorCommandSource, const String&)
1006 {
1007     return expandSelectionToGranularity(frame, SentenceGranularity);
1008 }
1009
1010 static bool executeSelectToMark(Frame& frame, Event*, EditorCommandSource, const String&)
1011 {
1012     RefPtr<Range> mark = frame.editor().mark().toNormalizedRange();
1013     RefPtr<Range> selection = frame.editor().selectedRange();
1014     if (!mark || !selection) {
1015         PAL::systemBeep();
1016         return false;
1017     }
1018     frame.selection().setSelectedRange(unionDOMRanges(*mark, *selection).get(), DOWNSTREAM, true);
1019     return true;
1020 }
1021
1022 static bool executeSelectWord(Frame& frame, Event*, EditorCommandSource, const String&)
1023 {
1024     return expandSelectionToGranularity(frame, WordGranularity);
1025 }
1026
1027 static bool executeSetMark(Frame& frame, Event*, EditorCommandSource, const String&)
1028 {
1029     frame.editor().setMark(frame.selection().selection());
1030     return true;
1031 }
1032
1033 static TextDecorationChange textDecorationChangeForToggling(Editor& editor, CSSPropertyID propertyID, const char* onValue)
1034 {
1035     return isStylePresent(editor, propertyID, onValue) ? TextDecorationChange::Remove : TextDecorationChange::Add;
1036 }
1037
1038 static bool executeStrikethrough(Frame& frame, Event*, EditorCommandSource source, const String&)
1039 {
1040     Ref<EditingStyle> style = EditingStyle::create();
1041     style->setStrikeThroughChange(textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "line-through"_s));
1042     // FIXME: Needs a new EditAction!
1043     return applyCommandToFrame(frame, source, EditAction::Underline, WTFMove(style));
1044 }
1045
1046 static bool executeStyleWithCSS(Frame& frame, Event*, EditorCommandSource, const String& value)
1047 {
1048     frame.editor().setShouldStyleWithCSS(!equalLettersIgnoringASCIICase(value, "false"));
1049     return true;
1050 }
1051
1052 static bool executeUseCSS(Frame& frame, Event*, EditorCommandSource, const String& value)
1053 {
1054     frame.editor().setShouldStyleWithCSS(equalLettersIgnoringASCIICase(value, "false"));
1055     return true;
1056 }
1057
1058 static bool executeSubscript(Frame& frame, Event*, EditorCommandSource source, const String&)
1059 {
1060     return executeToggleStyle(frame, source, EditAction::Subscript, CSSPropertyVerticalAlign, "baseline"_s, "sub"_s);
1061 }
1062
1063 static bool executeSuperscript(Frame& frame, Event*, EditorCommandSource source, const String&)
1064 {
1065     return executeToggleStyle(frame, source, EditAction::Superscript, CSSPropertyVerticalAlign, "baseline"_s, "super"_s);
1066 }
1067
1068 static bool executeSwapWithMark(Frame& frame, Event*, EditorCommandSource, const String&)
1069 {
1070     Ref<Frame> protector(frame);
1071     const VisibleSelection& mark = frame.editor().mark();
1072     const VisibleSelection& selection = frame.selection().selection();
1073     if (mark.isNone() || selection.isNone()) {
1074         PAL::systemBeep();
1075         return false;
1076     }
1077     frame.selection().setSelection(mark);
1078     frame.editor().setMark(selection);
1079     return true;
1080 }
1081
1082 #if PLATFORM(MAC)
1083 static bool executeTakeFindStringFromSelection(Frame& frame, Event*, EditorCommandSource, const String&)
1084 {
1085     frame.editor().takeFindStringFromSelection();
1086     return true;
1087 }
1088 #endif
1089
1090 static bool executeToggleBold(Frame& frame, Event*, EditorCommandSource source, const String&)
1091 {
1092     return executeToggleStyle(frame, source, EditAction::Bold, CSSPropertyFontWeight, "normal"_s, "bold"_s);
1093 }
1094
1095 static bool executeToggleItalic(Frame& frame, Event*, EditorCommandSource source, const String&)
1096 {
1097     return executeToggleStyle(frame, source, EditAction::Italics, CSSPropertyFontStyle, "normal"_s, "italic"_s);
1098 }
1099
1100 static bool executeTranspose(Frame& frame, Event*, EditorCommandSource, const String&)
1101 {
1102     frame.editor().transpose();
1103     return true;
1104 }
1105
1106 static bool executeUnderline(Frame& frame, Event*, EditorCommandSource source, const String&)
1107 {
1108     Ref<EditingStyle> style = EditingStyle::create();
1109     TextDecorationChange change = textDecorationChangeForToggling(frame.editor(), CSSPropertyWebkitTextDecorationsInEffect, "underline"_s);
1110     style->setUnderlineChange(change);
1111     return applyCommandToFrame(frame, source, EditAction::Underline, WTFMove(style));
1112 }
1113
1114 static bool executeUndo(Frame& frame, Event*, EditorCommandSource, const String&)
1115 {
1116     frame.editor().undo();
1117     return true;
1118 }
1119
1120 static bool executeUnlink(Frame& frame, Event*, EditorCommandSource, const String&)
1121 {
1122     ASSERT(frame.document());
1123     UnlinkCommand::create(*frame.document())->apply();
1124     return true;
1125 }
1126
1127 static bool executeUnscript(Frame& frame, Event*, EditorCommandSource source, const String&)
1128 {
1129     return executeApplyStyle(frame, source, EditAction::Unscript, CSSPropertyVerticalAlign, "baseline"_s);
1130 }
1131
1132 static bool executeUnselect(Frame& frame, Event*, EditorCommandSource, const String&)
1133 {
1134     frame.selection().clear();
1135     return true;
1136 }
1137
1138 static bool executeYank(Frame& frame, Event*, EditorCommandSource, const String&)
1139 {
1140     frame.editor().insertTextWithoutSendingTextEvent(frame.editor().killRing().yank(), false, 0);
1141     frame.editor().killRing().setToYankedState();
1142     return true;
1143 }
1144
1145 static bool executeYankAndSelect(Frame& frame, Event*, EditorCommandSource, const String&)
1146 {
1147     frame.editor().insertTextWithoutSendingTextEvent(frame.editor().killRing().yank(), true, 0);
1148     frame.editor().killRing().setToYankedState();
1149     return true;
1150 }
1151
1152 // Supported functions
1153
1154 static bool supported(Frame*)
1155 {
1156     return true;
1157 }
1158
1159 static bool supportedFromMenuOrKeyBinding(Frame*)
1160 {
1161     return false;
1162 }
1163
1164 static bool defaultValueForSupportedCopyCut(Frame& frame)
1165 {
1166     auto& settings = frame.settings();
1167     if (settings.javaScriptCanAccessClipboard())
1168         return true;
1169     
1170     switch (settings.clipboardAccessPolicy()) {
1171     case ClipboardAccessPolicy::Allow:
1172     case ClipboardAccessPolicy::RequiresUserGesture:
1173         return true;
1174     case ClipboardAccessPolicy::Deny:
1175         return false;
1176     }
1177
1178     ASSERT_NOT_REACHED();
1179     return false;
1180 }
1181
1182 static bool supportedCopyCut(Frame* frame)
1183 {
1184     if (!frame)
1185         return false;
1186
1187     bool defaultValue = defaultValueForSupportedCopyCut(*frame);
1188
1189     EditorClient* client = frame->editor().client();
1190     return client ? client->canCopyCut(frame, defaultValue) : defaultValue;
1191 }
1192
1193 static bool supportedPaste(Frame* frame)
1194 {
1195     if (!frame)
1196         return false;
1197
1198     bool defaultValue = frame->settings().javaScriptCanAccessClipboard() && frame->settings().DOMPasteAllowed();
1199
1200     EditorClient* client = frame->editor().client();
1201     return client ? client->canPaste(frame, defaultValue) : defaultValue;
1202 }
1203
1204 // Enabled functions
1205
1206 static bool enabled(Frame&, Event*, EditorCommandSource)
1207 {
1208     return true;
1209 }
1210
1211 static bool enabledVisibleSelection(Frame& frame, Event* event, EditorCommandSource)
1212 {
1213     // The term "visible" here includes a caret in editable text or a range in any text.
1214     const VisibleSelection& selection = frame.editor().selectionForCommand(event);
1215     return (selection.isCaret() && selection.isContentEditable()) || selection.isRange();
1216 }
1217
1218 static bool caretBrowsingEnabled(Frame& frame)
1219 {
1220     return frame.settings().caretBrowsingEnabled();
1221 }
1222
1223 static EditorCommandSource dummyEditorCommandSource = static_cast<EditorCommandSource>(0);
1224
1225 static bool enabledVisibleSelectionOrCaretBrowsing(Frame& frame, Event* event, EditorCommandSource)
1226 {
1227     // The EditorCommandSource parameter is unused in enabledVisibleSelection, so just pass a dummy variable
1228     return caretBrowsingEnabled(frame) || enabledVisibleSelection(frame, event, dummyEditorCommandSource);
1229 }
1230
1231 static bool enabledVisibleSelectionAndMark(Frame& frame, Event* event, EditorCommandSource)
1232 {
1233     const VisibleSelection& selection = frame.editor().selectionForCommand(event);
1234     return ((selection.isCaret() && selection.isContentEditable()) || selection.isRange())
1235         && frame.editor().mark().isCaretOrRange();
1236 }
1237
1238 static bool enableCaretInEditableText(Frame& frame, Event* event, EditorCommandSource)
1239 {
1240     const VisibleSelection& selection = frame.editor().selectionForCommand(event);
1241     return selection.isCaret() && selection.isContentEditable();
1242 }
1243
1244 static bool allowCopyCutFromDOM(Frame& frame)
1245 {
1246     auto& settings = frame.settings();
1247     if (settings.javaScriptCanAccessClipboard())
1248         return true;
1249     
1250     switch (settings.clipboardAccessPolicy()) {
1251     case ClipboardAccessPolicy::Allow:
1252         return true;
1253     case ClipboardAccessPolicy::Deny:
1254         return false;
1255     case ClipboardAccessPolicy::RequiresUserGesture:
1256         return UserGestureIndicator::processingUserGesture();
1257     }
1258
1259     ASSERT_NOT_REACHED();
1260     return false;
1261 }
1262
1263 static bool enabledCopy(Frame& frame, Event*, EditorCommandSource source)
1264 {
1265     switch (source) {
1266     case CommandFromMenuOrKeyBinding:    
1267         return frame.editor().canDHTMLCopy() || frame.editor().canCopy();
1268     case CommandFromDOM:
1269     case CommandFromDOMWithUserInterface:
1270         return allowCopyCutFromDOM(frame) && (frame.editor().canDHTMLCopy() || frame.editor().canCopy());
1271     }
1272     ASSERT_NOT_REACHED();
1273     return false;
1274 }
1275
1276 static bool enabledCut(Frame& frame, Event*, EditorCommandSource source)
1277 {
1278     switch (source) {
1279     case CommandFromMenuOrKeyBinding:    
1280         return frame.editor().canDHTMLCut() || frame.editor().canCut();
1281     case CommandFromDOM:
1282     case CommandFromDOMWithUserInterface:
1283         return allowCopyCutFromDOM(frame) && (frame.editor().canDHTMLCut() || frame.editor().canCut());
1284     }
1285     ASSERT_NOT_REACHED();
1286     return false;
1287 }
1288
1289 static bool enabledClearText(Frame& frame, Event*, EditorCommandSource)
1290 {
1291     UNUSED_PARAM(frame);
1292     return false;
1293 }
1294
1295 static bool enabledInEditableText(Frame& frame, Event* event, EditorCommandSource)
1296 {
1297     return frame.editor().selectionForCommand(event).rootEditableElement();
1298 }
1299
1300 static bool enabledDelete(Frame& frame, Event* event, EditorCommandSource source)
1301 {
1302     switch (source) {
1303     case CommandFromMenuOrKeyBinding:    
1304         return frame.editor().canDelete();
1305     case CommandFromDOM:
1306     case CommandFromDOMWithUserInterface:
1307         // "Delete" from DOM is like delete/backspace keypress, affects selected range if non-empty,
1308         // otherwise removes a character
1309         return enabledInEditableText(frame, event, source);
1310     }
1311     ASSERT_NOT_REACHED();
1312     return false;
1313 }
1314
1315 static bool enabledInEditableTextOrCaretBrowsing(Frame& frame, Event* event, EditorCommandSource)
1316 {
1317     // The EditorCommandSource parameter is unused in enabledInEditableText, so just pass a dummy variable
1318     return caretBrowsingEnabled(frame) || enabledInEditableText(frame, event, dummyEditorCommandSource);
1319 }
1320
1321 static bool enabledInRichlyEditableText(Frame& frame, Event*, EditorCommandSource)
1322 {
1323     const VisibleSelection& selection = frame.selection().selection();
1324     return selection.isCaretOrRange() && selection.isContentRichlyEditable() && selection.rootEditableElement();
1325 }
1326
1327 static bool enabledPaste(Frame& frame, Event*, EditorCommandSource)
1328 {
1329     return frame.editor().canPaste();
1330 }
1331
1332 static bool enabledRangeInEditableText(Frame& frame, Event*, EditorCommandSource)
1333 {
1334     return frame.selection().isRange() && frame.selection().selection().isContentEditable();
1335 }
1336
1337 static bool enabledRangeInRichlyEditableText(Frame& frame, Event*, EditorCommandSource)
1338 {
1339     return frame.selection().isRange() && frame.selection().selection().isContentRichlyEditable();
1340 }
1341
1342 static bool enabledRedo(Frame& frame, Event*, EditorCommandSource)
1343 {
1344     return frame.editor().canRedo();
1345 }
1346
1347 #if PLATFORM(MAC)
1348 static bool enabledTakeFindStringFromSelection(Frame& frame, Event*, EditorCommandSource)
1349 {
1350     return frame.editor().canCopyExcludingStandaloneImages();
1351 }
1352 #endif
1353
1354 static bool enabledUndo(Frame& frame, Event*, EditorCommandSource)
1355 {
1356     return frame.editor().canUndo();
1357 }
1358
1359 // State functions
1360
1361 static TriState stateNone(Frame&, Event*)
1362 {
1363     return FalseTriState;
1364 }
1365
1366 static TriState stateBold(Frame& frame, Event*)
1367 {
1368     return stateStyle(frame, CSSPropertyFontWeight, "bold"_s);
1369 }
1370
1371 static TriState stateItalic(Frame& frame, Event*)
1372 {
1373     return stateStyle(frame, CSSPropertyFontStyle, "italic"_s);
1374 }
1375
1376 static TriState stateOrderedList(Frame& frame, Event*)
1377 {
1378     return frame.editor().selectionOrderedListState();
1379 }
1380
1381 static TriState stateStrikethrough(Frame& frame, Event*)
1382 {
1383     return stateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, "line-through"_s);
1384 }
1385
1386 static TriState stateStyleWithCSS(Frame& frame, Event*)
1387 {
1388     return frame.editor().shouldStyleWithCSS() ? TrueTriState : FalseTriState;
1389 }
1390
1391 static TriState stateSubscript(Frame& frame, Event*)
1392 {
1393     return stateStyle(frame, CSSPropertyVerticalAlign, "sub"_s);
1394 }
1395
1396 static TriState stateSuperscript(Frame& frame, Event*)
1397 {
1398     return stateStyle(frame, CSSPropertyVerticalAlign, "super"_s);
1399 }
1400
1401 static TriState stateTextWritingDirectionLeftToRight(Frame& frame, Event*)
1402 {
1403     return stateTextWritingDirection(frame, LeftToRightWritingDirection);
1404 }
1405
1406 static TriState stateTextWritingDirectionNatural(Frame& frame, Event*)
1407 {
1408     return stateTextWritingDirection(frame, NaturalWritingDirection);
1409 }
1410
1411 static TriState stateTextWritingDirectionRightToLeft(Frame& frame, Event*)
1412 {
1413     return stateTextWritingDirection(frame, RightToLeftWritingDirection);
1414 }
1415
1416 static TriState stateUnderline(Frame& frame, Event*)
1417 {
1418     return stateStyle(frame, CSSPropertyWebkitTextDecorationsInEffect, "underline"_s);
1419 }
1420
1421 static TriState stateUnorderedList(Frame& frame, Event*)
1422 {
1423     return frame.editor().selectionUnorderedListState();
1424 }
1425
1426 static TriState stateJustifyCenter(Frame& frame, Event*)
1427 {
1428     return stateStyle(frame, CSSPropertyTextAlign, "center"_s);
1429 }
1430
1431 static TriState stateJustifyFull(Frame& frame, Event*)
1432 {
1433     return stateStyle(frame, CSSPropertyTextAlign, "justify"_s);
1434 }
1435
1436 static TriState stateJustifyLeft(Frame& frame, Event*)
1437 {
1438     return stateStyle(frame, CSSPropertyTextAlign, "left"_s);
1439 }
1440
1441 static TriState stateJustifyRight(Frame& frame, Event*)
1442 {
1443     return stateStyle(frame, CSSPropertyTextAlign, "right"_s);
1444 }
1445
1446 // Value functions
1447
1448 static String valueNull(Frame&, Event*)
1449 {
1450     return String();
1451 }
1452
1453 static String valueBackColor(Frame& frame, Event*)
1454 {
1455     return valueStyle(frame, CSSPropertyBackgroundColor);
1456 }
1457
1458 static String valueDefaultParagraphSeparator(Frame& frame, Event*)
1459 {
1460     switch (frame.editor().defaultParagraphSeparator()) {
1461     case EditorParagraphSeparatorIsDiv:
1462         return divTag->localName();
1463     case EditorParagraphSeparatorIsP:
1464         return pTag->localName();
1465     }
1466
1467     ASSERT_NOT_REACHED();
1468     return String();
1469 }
1470
1471 static String valueFontName(Frame& frame, Event*)
1472 {
1473     return valueStyle(frame, CSSPropertyFontFamily);
1474 }
1475
1476 static String valueFontSize(Frame& frame, Event*)
1477 {
1478     return valueStyle(frame, CSSPropertyFontSize);
1479 }
1480
1481 static String valueFontSizeDelta(Frame& frame, Event*)
1482 {
1483     return valueStyle(frame, CSSPropertyWebkitFontSizeDelta);
1484 }
1485
1486 static String valueForeColor(Frame& frame, Event*)
1487 {
1488     return valueStyle(frame, CSSPropertyColor);
1489 }
1490
1491 static String valueFormatBlock(Frame& frame, Event*)
1492 {
1493     const VisibleSelection& selection = frame.selection().selection();
1494     if (selection.isNoneOrOrphaned() || !selection.isContentEditable())
1495         return emptyString();
1496     Element* formatBlockElement = FormatBlockCommand::elementForFormatBlockCommand(selection.firstRange().get());
1497     if (!formatBlockElement)
1498         return emptyString();
1499     return formatBlockElement->localName();
1500 }
1501
1502 // allowExecutionWhenDisabled functions
1503
1504 static bool allowExecutionWhenDisabled(Frame&, EditorCommandSource)
1505 {
1506     return true;
1507 }
1508
1509 static bool doNotAllowExecutionWhenDisabled(Frame&, EditorCommandSource)
1510 {
1511     return false;
1512 }
1513
1514 static bool allowExecutionWhenDisabledCopyCut(Frame&, EditorCommandSource source)
1515 {
1516     switch (source) {
1517     case CommandFromMenuOrKeyBinding:
1518         return true;
1519     case CommandFromDOM:
1520     case CommandFromDOMWithUserInterface:
1521         return false;
1522     }
1523
1524     ASSERT_NOT_REACHED();
1525     return false;
1526 }
1527
1528 static bool allowExecutionWhenDisabledPaste(Frame& frame, EditorCommandSource)
1529 {
1530     if (frame.mainFrame().loader().shouldSuppressTextInputFromEditing())
1531         return false;
1532     return true;
1533 }
1534
1535 // Map of functions
1536
1537 struct CommandEntry {
1538     const char* name;
1539     EditorInternalCommand command;
1540 };
1541
1542 static const CommandMap& createCommandMap()
1543 {
1544     static const CommandEntry commands[] = {
1545         { "AlignCenter", { executeJustifyCenter, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1546         { "AlignJustified", { executeJustifyFull, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1547         { "AlignLeft", { executeJustifyLeft, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1548         { "AlignRight", { executeJustifyRight, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1549         { "BackColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueBackColor, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1550         { "Bold", { executeToggleBold, supported, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1551         { "ClearText", { executeClearText, supported, enabledClearText, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1552         { "Copy", { executeCopy, supportedCopyCut, enabledCopy, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledCopyCut } },
1553         { "CreateLink", { executeCreateLink, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1554         { "Cut", { executeCut, supportedCopyCut, enabledCut, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledCopyCut } },
1555         { "DefaultParagraphSeparator", { executeDefaultParagraphSeparator, supported, enabled, stateNone, valueDefaultParagraphSeparator, notTextInsertion, doNotAllowExecutionWhenDisabled} },
1556         { "Delete", { executeDelete, supported, enabledDelete, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1557         { "DeleteBackward", { executeDeleteBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1558         { "DeleteBackwardByDecomposingPreviousCharacter", { executeDeleteBackwardByDecomposingPreviousCharacter, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1559         { "DeleteForward", { executeDeleteForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1560         { "DeleteToBeginningOfLine", { executeDeleteToBeginningOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1561         { "DeleteToBeginningOfParagraph", { executeDeleteToBeginningOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1562         { "DeleteToEndOfLine", { executeDeleteToEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1563         { "DeleteToEndOfParagraph", { executeDeleteToEndOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1564         { "DeleteToMark", { executeDeleteToMark, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1565         { "DeleteWordBackward", { executeDeleteWordBackward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1566         { "DeleteWordForward", { executeDeleteWordForward, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1567         { "FindString", { executeFindString, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1568         { "FontName", { executeFontName, supported, enabledInEditableText, stateNone, valueFontName, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1569         { "FontSize", { executeFontSize, supported, enabledInEditableText, stateNone, valueFontSize, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1570         { "FontSizeDelta", { executeFontSizeDelta, supported, enabledInEditableText, stateNone, valueFontSizeDelta, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1571         { "ForeColor", { executeForeColor, supported, enabledInRichlyEditableText, stateNone, valueForeColor, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1572         { "FormatBlock", { executeFormatBlock, supported, enabledInRichlyEditableText, stateNone, valueFormatBlock, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1573         { "ForwardDelete", { executeForwardDelete, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1574         { "HiliteColor", { executeBackColor, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1575         { "IgnoreSpelling", { executeIgnoreSpelling, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1576         { "Indent", { executeIndent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1577         { "InsertBacktab", { executeInsertBacktab, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1578         { "InsertHTML", { executeInsertHTML, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1579         { "InsertHorizontalRule", { executeInsertHorizontalRule, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1580         { "InsertImage", { executeInsertImage, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1581         { "InsertLineBreak", { executeInsertLineBreak, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1582         { "InsertNewline", { executeInsertNewline, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },    
1583         { "InsertNewlineInQuotedContent", { executeInsertNewlineInQuotedContent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1584         { "InsertOrderedList", { executeInsertOrderedList, supported, enabledInRichlyEditableText, stateOrderedList, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1585         { "InsertParagraph", { executeInsertParagraph, supported, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1586         { "InsertTab", { executeInsertTab, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1587         { "InsertText", { executeInsertText, supported, enabledInEditableText, stateNone, valueNull, isTextInsertion, doNotAllowExecutionWhenDisabled } },
1588         { "InsertUnorderedList", { executeInsertUnorderedList, supported, enabledInRichlyEditableText, stateUnorderedList, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1589         { "Italic", { executeToggleItalic, supported, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1590         { "JustifyCenter", { executeJustifyCenter, supported, enabledInRichlyEditableText, stateJustifyCenter, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1591         { "JustifyFull", { executeJustifyFull, supported, enabledInRichlyEditableText, stateJustifyFull, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1592         { "JustifyLeft", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateJustifyLeft, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1593         { "JustifyNone", { executeJustifyLeft, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1594         { "JustifyRight", { executeJustifyRight, supported, enabledInRichlyEditableText, stateJustifyRight, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1595         { "MakeTextWritingDirectionLeftToRight", { executeMakeTextWritingDirectionLeftToRight, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateTextWritingDirectionLeftToRight, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1596         { "MakeTextWritingDirectionNatural", { executeMakeTextWritingDirectionNatural, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateTextWritingDirectionNatural, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1597         { "MakeTextWritingDirectionRightToLeft", { executeMakeTextWritingDirectionRightToLeft, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateTextWritingDirectionRightToLeft, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1598         { "MoveBackward", { executeMoveBackward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1599         { "MoveBackwardAndModifySelection", { executeMoveBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1600         { "MoveDown", { executeMoveDown, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1601         { "MoveDownAndModifySelection", { executeMoveDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1602         { "MoveForward", { executeMoveForward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1603         { "MoveForwardAndModifySelection", { executeMoveForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1604         { "MoveLeft", { executeMoveLeft, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1605         { "MoveLeftAndModifySelection", { executeMoveLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1606         { "MovePageDown", { executeMovePageDown, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1607         { "MovePageDownAndModifySelection", { executeMovePageDownAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1608         { "MovePageUp", { executeMovePageUp, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1609         { "MovePageUpAndModifySelection", { executeMovePageUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1610         { "MoveParagraphBackwardAndModifySelection", { executeMoveParagraphBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1611         { "MoveParagraphForwardAndModifySelection", { executeMoveParagraphForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1612         { "MoveRight", { executeMoveRight, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1613         { "MoveRightAndModifySelection", { executeMoveRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1614         { "MoveToBeginningOfDocument", { executeMoveToBeginningOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1615         { "MoveToBeginningOfDocumentAndModifySelection", { executeMoveToBeginningOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1616         { "MoveToBeginningOfLine", { executeMoveToBeginningOfLine, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1617         { "MoveToBeginningOfLineAndModifySelection", { executeMoveToBeginningOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1618         { "MoveToBeginningOfParagraph", { executeMoveToBeginningOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1619         { "MoveToBeginningOfParagraphAndModifySelection", { executeMoveToBeginningOfParagraphAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1620         { "MoveToBeginningOfSentence", { executeMoveToBeginningOfSentence, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1621         { "MoveToBeginningOfSentenceAndModifySelection", { executeMoveToBeginningOfSentenceAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1622         { "MoveToEndOfDocument", { executeMoveToEndOfDocument, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1623         { "MoveToEndOfDocumentAndModifySelection", { executeMoveToEndOfDocumentAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1624         { "MoveToEndOfLine", { executeMoveToEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1625         { "MoveToEndOfLineAndModifySelection", { executeMoveToEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1626         { "MoveToEndOfParagraph", { executeMoveToEndOfParagraph, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1627         { "MoveToEndOfParagraphAndModifySelection", { executeMoveToEndOfParagraphAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1628         { "MoveToEndOfSentence", { executeMoveToEndOfSentence, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1629         { "MoveToEndOfSentenceAndModifySelection", { executeMoveToEndOfSentenceAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1630         { "MoveToLeftEndOfLine", { executeMoveToLeftEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1631         { "MoveToLeftEndOfLineAndModifySelection", { executeMoveToLeftEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1632         { "MoveToRightEndOfLine", { executeMoveToRightEndOfLine, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1633         { "MoveToRightEndOfLineAndModifySelection", { executeMoveToRightEndOfLineAndModifySelection, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1634         { "MoveUp", { executeMoveUp, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1635         { "MoveUpAndModifySelection", { executeMoveUpAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1636         { "MoveWordBackward", { executeMoveWordBackward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1637         { "MoveWordBackwardAndModifySelection", { executeMoveWordBackwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1638         { "MoveWordForward", { executeMoveWordForward, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1639         { "MoveWordForwardAndModifySelection", { executeMoveWordForwardAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1640         { "MoveWordLeft", { executeMoveWordLeft, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1641         { "MoveWordLeftAndModifySelection", { executeMoveWordLeftAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1642         { "MoveWordRight", { executeMoveWordRight, supportedFromMenuOrKeyBinding, enabledInEditableTextOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1643         { "MoveWordRightAndModifySelection", { executeMoveWordRightAndModifySelection, supportedFromMenuOrKeyBinding, enabledVisibleSelectionOrCaretBrowsing, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1644         { "Outdent", { executeOutdent, supported, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1645         { "OverWrite", { executeToggleOverwrite, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1646         { "Paste", { executePaste, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
1647         { "PasteAndMatchStyle", { executePasteAndMatchStyle, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
1648         { "PasteAsPlainText", { executePasteAsPlainText, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
1649         { "PasteAsQuotation", { executePasteAsQuotation, supportedPaste, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabledPaste } },
1650         { "Print", { executePrint, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1651         { "Redo", { executeRedo, supported, enabledRedo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1652         { "RemoveFormat", { executeRemoveFormat, supported, enabledRangeInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1653         { "ScrollPageBackward", { executeScrollPageBackward, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1654         { "ScrollPageForward", { executeScrollPageForward, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1655         { "ScrollLineUp", { executeScrollLineUp, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1656         { "ScrollLineDown", { executeScrollLineDown, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1657         { "ScrollToBeginningOfDocument", { executeScrollToBeginningOfDocument, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1658         { "ScrollToEndOfDocument", { executeScrollToEndOfDocument, supportedFromMenuOrKeyBinding, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1659         { "SelectAll", { executeSelectAll, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1660         { "SelectLine", { executeSelectLine, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1661         { "SelectParagraph", { executeSelectParagraph, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1662         { "SelectSentence", { executeSelectSentence, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1663         { "SelectToMark", { executeSelectToMark, supportedFromMenuOrKeyBinding, enabledVisibleSelectionAndMark, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1664         { "SelectWord", { executeSelectWord, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1665         { "SetMark", { executeSetMark, supportedFromMenuOrKeyBinding, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1666         { "Strikethrough", { executeStrikethrough, supported, enabledInRichlyEditableText, stateStrikethrough, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1667         { "StyleWithCSS", { executeStyleWithCSS, supported, enabled, stateStyleWithCSS, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1668         { "Subscript", { executeSubscript, supported, enabledInRichlyEditableText, stateSubscript, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1669         { "Superscript", { executeSuperscript, supported, enabledInRichlyEditableText, stateSuperscript, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1670         { "SwapWithMark", { executeSwapWithMark, supportedFromMenuOrKeyBinding, enabledVisibleSelectionAndMark, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1671         { "ToggleBold", { executeToggleBold, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateBold, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1672         { "ToggleItalic", { executeToggleItalic, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateItalic, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1673         { "ToggleUnderline", { executeUnderline, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1674         { "Transpose", { executeTranspose, supported, enableCaretInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1675         { "Underline", { executeUnderline, supported, enabledInRichlyEditableText, stateUnderline, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1676         { "Undo", { executeUndo, supported, enabledUndo, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1677         { "Unlink", { executeUnlink, supported, enabledRangeInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1678         { "Unscript", { executeUnscript, supportedFromMenuOrKeyBinding, enabledInRichlyEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1679         { "Unselect", { executeUnselect, supported, enabledVisibleSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1680         { "UseCSS", { executeUseCSS, supported, enabled, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1681         { "Yank", { executeYank, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1682         { "YankAndSelect", { executeYankAndSelect, supportedFromMenuOrKeyBinding, enabledInEditableText, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1683
1684 #if PLATFORM(GTK)
1685         { "PasteGlobalSelection", { executePasteGlobalSelection, supportedFromMenuOrKeyBinding, enabledPaste, stateNone, valueNull, notTextInsertion, allowExecutionWhenDisabled } },
1686 #endif
1687
1688 #if PLATFORM(MAC)
1689         { "TakeFindStringFromSelection", { executeTakeFindStringFromSelection, supportedFromMenuOrKeyBinding, enabledTakeFindStringFromSelection, stateNone, valueNull, notTextInsertion, doNotAllowExecutionWhenDisabled } },
1690 #endif
1691     };
1692
1693     // These unsupported commands are listed here since they appear in the Microsoft
1694     // documentation used as the starting point for our DOM executeCommand support.
1695     //
1696     // 2D-Position (not supported)
1697     // AbsolutePosition (not supported)
1698     // BlockDirLTR (not supported)
1699     // BlockDirRTL (not supported)
1700     // BrowseMode (not supported)
1701     // ClearAuthenticationCache (not supported)
1702     // CreateBookmark (not supported)
1703     // DirLTR (not supported)
1704     // DirRTL (not supported)
1705     // EditMode (not supported)
1706     // InlineDirLTR (not supported)
1707     // InlineDirRTL (not supported)
1708     // InsertButton (not supported)
1709     // InsertFieldSet (not supported)
1710     // InsertIFrame (not supported)
1711     // InsertInputButton (not supported)
1712     // InsertInputCheckbox (not supported)
1713     // InsertInputFileUpload (not supported)
1714     // InsertInputHidden (not supported)
1715     // InsertInputImage (not supported)
1716     // InsertInputPassword (not supported)
1717     // InsertInputRadio (not supported)
1718     // InsertInputReset (not supported)
1719     // InsertInputSubmit (not supported)
1720     // InsertInputText (not supported)
1721     // InsertMarquee (not supported)
1722     // InsertSelectDropDown (not supported)
1723     // InsertSelectListBox (not supported)
1724     // InsertTextArea (not supported)
1725     // LiveResize (not supported)
1726     // MultipleSelection (not supported)
1727     // Open (not supported)
1728     // PlayImage (not supported)
1729     // Refresh (not supported)
1730     // RemoveParaFormat (not supported)
1731     // SaveAs (not supported)
1732     // SizeToControl (not supported)
1733     // SizeToControlHeight (not supported)
1734     // SizeToControlWidth (not supported)
1735     // Stop (not supported)
1736     // StopImage (not supported)
1737     // Unbookmark (not supported)
1738
1739     CommandMap& commandMap = *new CommandMap;
1740
1741     for (auto& command : commands) {
1742         ASSERT(!commandMap.get(command.name));
1743         commandMap.set(command.name, &command.command);
1744     }
1745
1746     return commandMap;
1747 }
1748
1749 static const EditorInternalCommand* internalCommand(const String& commandName)
1750 {
1751     static const CommandMap& commandMap = createCommandMap();
1752     return commandName.isEmpty() ? 0 : commandMap.get(commandName);
1753 }
1754
1755 Editor::Command Editor::command(const String& commandName)
1756 {
1757     return Command(internalCommand(commandName), CommandFromMenuOrKeyBinding, m_frame);
1758 }
1759
1760 Editor::Command Editor::command(const String& commandName, EditorCommandSource source)
1761 {
1762     return Command(internalCommand(commandName), source, m_frame);
1763 }
1764
1765 bool Editor::commandIsSupportedFromMenuOrKeyBinding(const String& commandName)
1766 {
1767     return internalCommand(commandName);
1768 }
1769
1770 Editor::Command::Command()
1771 {
1772 }
1773
1774 Editor::Command::Command(const EditorInternalCommand* command, EditorCommandSource source, Frame& frame)
1775     : m_command(command)
1776     , m_source(source)
1777     , m_frame(command ? &frame : nullptr)
1778 {
1779     ASSERT(command || !m_frame);
1780 }
1781
1782 bool Editor::Command::execute(const String& parameter, Event* triggeringEvent) const
1783 {
1784     if (!isEnabled(triggeringEvent)) {
1785         // Let certain commands be executed when performed explicitly even if they are disabled.
1786         if (!allowExecutionWhenDisabled())
1787             return false;
1788     }
1789     auto document = m_frame->document();
1790     document->updateLayoutIgnorePendingStylesheets();
1791     if (m_frame->document() != document)
1792         return false;
1793
1794     return m_command->execute(*m_frame, triggeringEvent, m_source, parameter);
1795 }
1796
1797 bool Editor::Command::execute(Event* triggeringEvent) const
1798 {
1799     return execute(String(), triggeringEvent);
1800 }
1801
1802 bool Editor::Command::isSupported() const
1803 {
1804     if (!m_command)
1805         return false;
1806     switch (m_source) {
1807     case CommandFromMenuOrKeyBinding:
1808         return true;
1809     case CommandFromDOM:
1810     case CommandFromDOMWithUserInterface:
1811         return m_command->isSupportedFromDOM(m_frame.get());
1812     }
1813     ASSERT_NOT_REACHED();
1814     return false;
1815 }
1816
1817 bool Editor::Command::isEnabled(Event* triggeringEvent) const
1818 {
1819     if (!isSupported() || !m_frame)
1820         return false;
1821     return m_command->isEnabled(*m_frame, triggeringEvent, m_source);
1822 }
1823
1824 TriState Editor::Command::state(Event* triggeringEvent) const
1825 {
1826     if (!isSupported() || !m_frame)
1827         return FalseTriState;
1828     return m_command->state(*m_frame, triggeringEvent);
1829 }
1830
1831 String Editor::Command::value(Event* triggeringEvent) const
1832 {
1833     if (!isSupported() || !m_frame)
1834         return String();
1835     if (m_command->value == valueNull && m_command->state != stateNone)
1836         return m_command->state(*m_frame, triggeringEvent) == TrueTriState ? "true"_s : "false"_s;
1837     return m_command->value(*m_frame, triggeringEvent);
1838 }
1839
1840 bool Editor::Command::isTextInsertion() const
1841 {
1842     return m_command && m_command->isTextInsertion;
1843 }
1844
1845 bool Editor::Command::allowExecutionWhenDisabled() const
1846 {
1847     if (!isSupported() || !m_frame)
1848         return false;
1849     return m_command->allowExecutionWhenDisabled(*m_frame, m_source);
1850 }
1851
1852 } // namespace WebCore