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