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