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