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