1 /* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2010 Igalia S.L 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "ContextMenuController.h" 29 30 #if ENABLE(CONTEXT_MENUS) 31 32 #include "BackForwardController.h" 33 #include "Chrome.h" 34 #include "ContextMenu.h" 35 #include "ContextMenuClient.h" 36 #include "ContextMenuItem.h" 37 #include "ContextMenuProvider.h" 38 #include "Document.h" 39 #include "DocumentFragment.h" 40 #include "DocumentLoader.h" 41 #include "Editor.h" 42 #include "EditorClient.h" 43 #include "Event.h" 44 #include "EventHandler.h" 45 #include "EventNames.h" 46 #include "FormState.h" 47 #include "Frame.h" 48 #include "FrameLoadRequest.h" 49 #include "FrameLoader.h" 50 #include "HTMLFormElement.h" 51 #include "HitTestRequest.h" 52 #include "HitTestResult.h" 53 #include "InspectorController.h" 54 #include "LocalizedStrings.h" 55 #include "MouseEvent.h" 56 #include "NavigationAction.h" 57 #include "Node.h" 58 #include "Page.h" 59 #include "RenderLayer.h" 60 #include "RenderObject.h" 61 #include "ReplaceSelectionCommand.h" 62 #include "ResourceRequest.h" 63 #include "SelectionController.h" 64 #include "Settings.h" 65 #include "TextIterator.h" 66 #include "UserTypingGestureIndicator.h" 67 #include "WindowFeatures.h" 68 #include "markup.h" 69 #include <wtf/unicode/Unicode.h> 70 71 using namespace WTF; 72 using namespace Unicode; 73 74 namespace WebCore { 75 76 ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client) 77 : m_page(page) 78 , m_client(client) 79 , m_contextMenu(0) 80 { 81 ASSERT_ARG(page, page); 82 ASSERT_ARG(client, client); 83 } 84 85 ContextMenuController::~ContextMenuController() 86 { 87 m_client->contextMenuDestroyed(); 88 } 89 90 void ContextMenuController::clearContextMenu() 91 { 92 m_contextMenu.set(0); 93 if (m_menuProvider) 94 m_menuProvider->contextMenuCleared(); 95 m_menuProvider = 0; 96 } 97 98 void ContextMenuController::handleContextMenuEvent(Event* event) 99 { 100 m_contextMenu = createContextMenu(event); 101 if (!m_contextMenu) 102 return; 103 104 populate(); 105 106 showContextMenu(event); 107 } 108 109 void ContextMenuController::showContextMenu(Event* event, PassRefPtr<ContextMenuProvider> menuProvider) 110 { 111 m_menuProvider = menuProvider; 112 113 m_contextMenu = createContextMenu(event); 114 if (!m_contextMenu) { 115 clearContextMenu(); 116 return; 117 } 118 119 m_menuProvider->populateContextMenu(m_contextMenu.get()); 120 showContextMenu(event); 121 } 122 123 PassOwnPtr<ContextMenu> ContextMenuController::createContextMenu(Event* event) 124 { 125 if (!event->isMouseEvent()) 126 return 0; 127 128 MouseEvent* mouseEvent = static_cast<MouseEvent*>(event); 129 HitTestResult result(mouseEvent->absoluteLocation()); 130 131 if (Frame* frame = event->target()->toNode()->document()->frame()) 132 result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false); 133 134 if (!result.innerNonSharedNode()) 135 return 0; 136 137 m_hitTestResult = result; 138 139 return new ContextMenu; 140 } 141 142 void ContextMenuController::showContextMenu(Event* event) 143 { 144 #if ENABLE(INSPECTOR) 145 if (m_page->inspectorController()->enabled()) 146 addInspectElementItem(); 147 #endif 148 149 #if USE(CROSS_PLATFORM_CONTEXT_MENUS) 150 m_contextMenu = m_client->customizeMenu(m_contextMenu.release()); 151 #else 152 PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get()); 153 m_contextMenu->setPlatformDescription(customMenu); 154 #endif 155 event->setDefaultHandled(); 156 } 157 158 static void openNewWindow(const KURL& urlToLoad, Frame* frame) 159 { 160 if (Page* oldPage = frame->page()) { 161 FrameLoadRequest request(frame->document()->securityOrigin(), ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer())); 162 if (Page* newPage = oldPage->chrome()->createWindow(frame, request, WindowFeatures(), NavigationAction())) { 163 newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer); 164 newPage->chrome()->show(); 165 } 166 } 167 } 168 169 void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) 170 { 171 ASSERT(item->type() == ActionType || item->type() == CheckableActionType); 172 173 if (item->action() >= ContextMenuItemBaseApplicationTag) { 174 m_client->contextMenuItemSelected(item, m_contextMenu.get()); 175 return; 176 } 177 178 if (item->action() >= ContextMenuItemBaseCustomTag) { 179 ASSERT(m_menuProvider); 180 m_menuProvider->contextMenuItemSelected(item); 181 return; 182 } 183 184 Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame(); 185 if (!frame) 186 return; 187 188 switch (item->action()) { 189 case ContextMenuItemTagOpenLinkInNewWindow: 190 openNewWindow(m_hitTestResult.absoluteLinkURL(), frame); 191 break; 192 case ContextMenuItemTagDownloadLinkToDisk: 193 // FIXME: Some day we should be able to do this from within WebCore. 194 m_client->downloadURL(m_hitTestResult.absoluteLinkURL()); 195 break; 196 case ContextMenuItemTagCopyLinkToClipboard: 197 frame->editor()->copyURL(m_hitTestResult.absoluteLinkURL(), m_hitTestResult.textContent()); 198 break; 199 case ContextMenuItemTagOpenImageInNewWindow: 200 openNewWindow(m_hitTestResult.absoluteImageURL(), frame); 201 break; 202 case ContextMenuItemTagDownloadImageToDisk: 203 // FIXME: Some day we should be able to do this from within WebCore. 204 m_client->downloadURL(m_hitTestResult.absoluteImageURL()); 205 break; 206 case ContextMenuItemTagCopyImageToClipboard: 207 // FIXME: The Pasteboard class is not written yet 208 // For now, call into the client. This is temporary! 209 frame->editor()->copyImage(m_hitTestResult); 210 break; 211 #if PLATFORM(QT) || PLATFORM(GTK) 212 case ContextMenuItemTagCopyImageUrlToClipboard: 213 frame->editor()->copyURL(m_hitTestResult.absoluteImageURL(), m_hitTestResult.textContent()); 214 break; 215 #endif 216 case ContextMenuItemTagOpenMediaInNewWindow: 217 openNewWindow(m_hitTestResult.absoluteMediaURL(), frame); 218 break; 219 case ContextMenuItemTagCopyMediaLinkToClipboard: 220 frame->editor()->copyURL(m_hitTestResult.absoluteMediaURL(), m_hitTestResult.textContent()); 221 break; 222 case ContextMenuItemTagToggleMediaControls: 223 m_hitTestResult.toggleMediaControlsDisplay(); 224 break; 225 case ContextMenuItemTagToggleMediaLoop: 226 m_hitTestResult.toggleMediaLoopPlayback(); 227 break; 228 case ContextMenuItemTagEnterVideoFullscreen: 229 m_hitTestResult.enterFullscreenForVideo(); 230 break; 231 case ContextMenuItemTagMediaPlayPause: 232 m_hitTestResult.toggleMediaPlayState(); 233 break; 234 case ContextMenuItemTagMediaMute: 235 m_hitTestResult.toggleMediaMuteState(); 236 break; 237 case ContextMenuItemTagOpenFrameInNewWindow: { 238 DocumentLoader* loader = frame->loader()->documentLoader(); 239 if (!loader->unreachableURL().isEmpty()) 240 openNewWindow(loader->unreachableURL(), frame); 241 else 242 openNewWindow(loader->url(), frame); 243 break; 244 } 245 case ContextMenuItemTagCopy: 246 frame->editor()->copy(); 247 break; 248 case ContextMenuItemTagGoBack: 249 if (Page* page = frame->page()) 250 page->backForward()->goBackOrForward(-1); 251 break; 252 case ContextMenuItemTagGoForward: 253 if (Page* page = frame->page()) 254 page->backForward()->goBackOrForward(1); 255 break; 256 case ContextMenuItemTagStop: 257 frame->loader()->stop(); 258 break; 259 case ContextMenuItemTagReload: 260 frame->loader()->reload(); 261 break; 262 case ContextMenuItemTagCut: 263 frame->editor()->command("Cut").execute(); 264 break; 265 case ContextMenuItemTagPaste: 266 frame->editor()->command("Paste").execute(); 267 break; 268 #if PLATFORM(GTK) 269 case ContextMenuItemTagDelete: 270 frame->editor()->performDelete(); 271 break; 272 #endif 273 #if PLATFORM(GTK) || PLATFORM(QT) 274 case ContextMenuItemTagSelectAll: 275 frame->editor()->command("SelectAll").execute(); 276 break; 277 #endif 278 case ContextMenuItemTagSpellingGuess: 279 ASSERT(frame->editor()->selectedText().length()); 280 if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) { 281 Document* document = frame->document(); 282 RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting); 283 applyCommand(command); 284 frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); 285 } 286 break; 287 case ContextMenuItemTagIgnoreSpelling: 288 frame->editor()->ignoreSpelling(); 289 break; 290 case ContextMenuItemTagLearnSpelling: 291 frame->editor()->learnSpelling(); 292 break; 293 case ContextMenuItemTagSearchWeb: 294 m_client->searchWithGoogle(frame); 295 break; 296 case ContextMenuItemTagLookUpInDictionary: 297 // FIXME: Some day we may be able to do this from within WebCore. 298 m_client->lookUpInDictionary(frame); 299 break; 300 case ContextMenuItemTagOpenLink: 301 if (Frame* targetFrame = m_hitTestResult.targetFrame()) 302 targetFrame->loader()->loadFrameRequest(FrameLoadRequest(frame->document()->securityOrigin(), ResourceRequest(m_hitTestResult.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, SendReferrer); 303 else 304 openNewWindow(m_hitTestResult.absoluteLinkURL(), frame); 305 break; 306 case ContextMenuItemTagBold: 307 frame->editor()->command("ToggleBold").execute(); 308 break; 309 case ContextMenuItemTagItalic: 310 frame->editor()->command("ToggleItalic").execute(); 311 break; 312 case ContextMenuItemTagUnderline: 313 frame->editor()->toggleUnderline(); 314 break; 315 case ContextMenuItemTagOutline: 316 // We actually never enable this because CSS does not have a way to specify an outline font, 317 // which may make this difficult to implement. Maybe a special case of text-shadow? 318 break; 319 case ContextMenuItemTagStartSpeaking: { 320 ExceptionCode ec; 321 RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); 322 if (!selectedRange || selectedRange->collapsed(ec)) { 323 Document* document = m_hitTestResult.innerNonSharedNode()->document(); 324 selectedRange = document->createRange(); 325 selectedRange->selectNode(document->documentElement(), ec); 326 } 327 m_client->speak(plainText(selectedRange.get())); 328 break; 329 } 330 case ContextMenuItemTagStopSpeaking: 331 m_client->stopSpeaking(); 332 break; 333 case ContextMenuItemTagDefaultDirection: 334 frame->editor()->setBaseWritingDirection(NaturalWritingDirection); 335 break; 336 case ContextMenuItemTagLeftToRight: 337 frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); 338 break; 339 case ContextMenuItemTagRightToLeft: 340 frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); 341 break; 342 case ContextMenuItemTagTextDirectionDefault: 343 frame->editor()->command("MakeTextWritingDirectionNatural").execute(); 344 break; 345 case ContextMenuItemTagTextDirectionLeftToRight: 346 frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); 347 break; 348 case ContextMenuItemTagTextDirectionRightToLeft: 349 frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); 350 break; 351 #if PLATFORM(MAC) 352 case ContextMenuItemTagSearchInSpotlight: 353 m_client->searchWithSpotlight(); 354 break; 355 #endif 356 case ContextMenuItemTagShowSpellingPanel: 357 frame->editor()->showSpellingGuessPanel(); 358 break; 359 case ContextMenuItemTagCheckSpelling: 360 frame->editor()->advanceToNextMisspelling(); 361 break; 362 case ContextMenuItemTagCheckSpellingWhileTyping: 363 frame->editor()->toggleContinuousSpellChecking(); 364 break; 365 #ifndef BUILDING_ON_TIGER 366 case ContextMenuItemTagCheckGrammarWithSpelling: 367 frame->editor()->toggleGrammarChecking(); 368 break; 369 #endif 370 #if PLATFORM(MAC) 371 case ContextMenuItemTagShowFonts: 372 frame->editor()->showFontPanel(); 373 break; 374 case ContextMenuItemTagStyles: 375 frame->editor()->showStylesPanel(); 376 break; 377 case ContextMenuItemTagShowColors: 378 frame->editor()->showColorPanel(); 379 break; 380 #endif 381 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 382 case ContextMenuItemTagMakeUpperCase: 383 frame->editor()->uppercaseWord(); 384 break; 385 case ContextMenuItemTagMakeLowerCase: 386 frame->editor()->lowercaseWord(); 387 break; 388 case ContextMenuItemTagCapitalize: 389 frame->editor()->capitalizeWord(); 390 break; 391 case ContextMenuItemTagShowSubstitutions: 392 frame->editor()->showSubstitutionsPanel(); 393 break; 394 case ContextMenuItemTagSmartCopyPaste: 395 frame->editor()->toggleSmartInsertDelete(); 396 break; 397 case ContextMenuItemTagSmartQuotes: 398 frame->editor()->toggleAutomaticQuoteSubstitution(); 399 break; 400 case ContextMenuItemTagSmartDashes: 401 frame->editor()->toggleAutomaticDashSubstitution(); 402 break; 403 case ContextMenuItemTagSmartLinks: 404 frame->editor()->toggleAutomaticLinkDetection(); 405 break; 406 case ContextMenuItemTagTextReplacement: 407 frame->editor()->toggleAutomaticTextReplacement(); 408 break; 409 case ContextMenuItemTagCorrectSpellingAutomatically: 410 frame->editor()->toggleAutomaticSpellingCorrection(); 411 break; 412 case ContextMenuItemTagChangeBack: 413 frame->editor()->changeBackToReplacedString(m_hitTestResult.replacedString()); 414 break; 415 #endif 416 #if ENABLE(INSPECTOR) 417 case ContextMenuItemTagInspectElement: 418 if (Page* page = frame->page()) 419 page->inspectorController()->inspect(m_hitTestResult.innerNonSharedNode()); 420 break; 421 #endif 422 default: 423 break; 424 } 425 } 426 427 void ContextMenuController::appendItem(ContextMenuItem& menuItem, ContextMenu* parentMenu) 428 { 429 checkOrEnableIfNeeded(menuItem); 430 if (parentMenu) 431 parentMenu->appendItem(menuItem); 432 } 433 434 static PassOwnPtr<ContextMenuItem> separatorItem() 435 { 436 return new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()); 437 } 438 439 void ContextMenuController::createAndAppendFontSubMenu(ContextMenuItem& fontMenuItem) 440 { 441 ContextMenu fontMenu; 442 443 #if PLATFORM(MAC) 444 ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts()); 445 #endif 446 ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold()); 447 ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic()); 448 ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline()); 449 ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline()); 450 #if PLATFORM(MAC) 451 ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles()); 452 ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors()); 453 #endif 454 455 #if PLATFORM(MAC) 456 appendItem(showFonts, &fontMenu); 457 #endif 458 appendItem(bold, &fontMenu); 459 appendItem(italic, &fontMenu); 460 appendItem(underline, &fontMenu); 461 appendItem(outline, &fontMenu); 462 #if PLATFORM(MAC) 463 appendItem(styles, &fontMenu); 464 appendItem(*separatorItem(), &fontMenu); 465 appendItem(showColors, &fontMenu); 466 #endif 467 468 fontMenuItem.setSubMenu(&fontMenu); 469 } 470 471 #if !defined(BUILDING_ON_TIGER) 472 473 #if !PLATFORM(GTK) 474 475 void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem) 476 { 477 ContextMenu spellingAndGrammarMenu; 478 479 ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, 480 contextMenuItemTagShowSpellingPanel(true)); 481 ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, 482 contextMenuItemTagCheckSpelling()); 483 ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, 484 contextMenuItemTagCheckSpellingWhileTyping()); 485 ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling, 486 contextMenuItemTagCheckGrammarWithSpelling()); 487 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) 488 ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically, 489 contextMenuItemTagCorrectSpellingAutomatically()); 490 #endif 491 492 appendItem(showSpellingPanel, &spellingAndGrammarMenu); 493 appendItem(checkSpelling, &spellingAndGrammarMenu); 494 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) 495 appendItem(*separatorItem(), &spellingAndGrammarMenu); 496 #endif 497 appendItem(checkAsYouType, &spellingAndGrammarMenu); 498 appendItem(grammarWithSpelling, &spellingAndGrammarMenu); 499 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) 500 appendItem(correctSpelling, &spellingAndGrammarMenu); 501 #endif 502 503 spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu); 504 } 505 506 #endif // !PLATFORM(GTK) 507 508 #else 509 510 void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem) 511 { 512 ContextMenu spellingMenu; 513 514 ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, 515 contextMenuItemTagShowSpellingPanel(true)); 516 ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, 517 contextMenuItemTagCheckSpelling()); 518 ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, 519 contextMenuItemTagCheckSpellingWhileTyping()); 520 521 appendItem(showSpellingPanel, &spellingMenu); 522 appendItem(checkSpelling, &spellingMenu); 523 appendItem(checkAsYouType, &spellingMenu); 524 525 spellingMenuItem.setSubMenu(&spellingMenu); 526 } 527 528 #endif 529 530 #if PLATFORM(MAC) 531 532 void ContextMenuController::createAndAppendSpeechSubMenu(ContextMenuItem& speechMenuItem) 533 { 534 ContextMenu speechMenu; 535 536 ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking()); 537 ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking()); 538 539 appendItem(start, &speechMenu); 540 appendItem(stop, &speechMenu); 541 542 speechMenuItem.setSubMenu(&speechMenu); 543 } 544 545 #endif 546 547 #if !PLATFORM(GTK) 548 549 void ContextMenuController::createAndAppendWritingDirectionSubMenu(ContextMenuItem& writingDirectionMenuItem) 550 { 551 ContextMenu writingDirectionMenu; 552 553 ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection, 554 contextMenuItemTagDefaultDirection()); 555 ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight()); 556 ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft()); 557 558 appendItem(defaultItem, &writingDirectionMenu); 559 appendItem(ltr, &writingDirectionMenu); 560 appendItem(rtl, &writingDirectionMenu); 561 562 writingDirectionMenuItem.setSubMenu(&writingDirectionMenu); 563 } 564 565 void ContextMenuController::createAndAppendTextDirectionSubMenu(ContextMenuItem& textDirectionMenuItem) 566 { 567 ContextMenu textDirectionMenu; 568 569 ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection()); 570 ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight()); 571 ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft()); 572 573 appendItem(defaultItem, &textDirectionMenu); 574 appendItem(ltr, &textDirectionMenu); 575 appendItem(rtl, &textDirectionMenu); 576 577 textDirectionMenuItem.setSubMenu(&textDirectionMenu); 578 } 579 580 #endif 581 582 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 583 584 void ContextMenuController::createAndAppendSubstitutionsSubMenu(ContextMenuItem& substitutionsMenuItem) 585 { 586 ContextMenu substitutionsMenu; 587 588 ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true)); 589 ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste()); 590 ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes()); 591 ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes()); 592 ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks()); 593 ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement()); 594 595 appendItem(showSubstitutions, &substitutionsMenu); 596 appendItem(*separatorItem(), &substitutionsMenu); 597 appendItem(smartCopyPaste, &substitutionsMenu); 598 appendItem(smartQuotes, &substitutionsMenu); 599 appendItem(smartDashes, &substitutionsMenu); 600 appendItem(smartLinks, &substitutionsMenu); 601 appendItem(textReplacement, &substitutionsMenu); 602 603 substitutionsMenuItem.setSubMenu(&substitutionsMenu); 604 } 605 606 void ContextMenuController::createAndAppendTransformationsSubMenu(ContextMenuItem& transformationsMenuItem) 607 { 608 ContextMenu transformationsMenu; 609 610 ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase()); 611 ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase()); 612 ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize()); 613 614 appendItem(makeUpperCase, &transformationsMenu); 615 appendItem(makeLowerCase, &transformationsMenu); 616 appendItem(capitalize, &transformationsMenu); 617 618 transformationsMenuItem.setSubMenu(&transformationsMenu); 619 } 620 621 #endif 622 623 static bool selectionContainsPossibleWord(Frame* frame) 624 { 625 // Current algorithm: look for a character that's not just a separator. 626 for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) { 627 int length = it.length(); 628 const UChar* characters = it.characters(); 629 for (int i = 0; i < length; ++i) 630 if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph))) 631 return true; 632 } 633 return false; 634 } 635 636 #if PLATFORM(MAC) 637 #if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD) 638 #define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 1 639 #else 640 #define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 0 641 #endif 642 #endif 643 644 void ContextMenuController::populate() 645 { 646 ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); 647 ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, 648 contextMenuItemTagOpenLinkInNewWindow()); 649 ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, 650 contextMenuItemTagDownloadLinkToDisk()); 651 ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, 652 contextMenuItemTagCopyLinkToClipboard()); 653 ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, 654 contextMenuItemTagOpenImageInNewWindow()); 655 ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, 656 contextMenuItemTagDownloadImageToDisk()); 657 ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, 658 contextMenuItemTagCopyImageToClipboard()); 659 #if PLATFORM(QT) || PLATFORM(GTK) 660 ContextMenuItem CopyImageUrlItem(ActionType, ContextMenuItemTagCopyImageUrlToClipboard, 661 contextMenuItemTagCopyImageUrlToClipboard()); 662 #endif 663 ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String()); 664 ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard, 665 String()); 666 ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause, 667 contextMenuItemTagMediaPlay()); 668 ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute, 669 contextMenuItemTagMediaMute()); 670 ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls, 671 contextMenuItemTagToggleMediaControls()); 672 ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop, 673 contextMenuItemTagToggleMediaLoop()); 674 ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen, 675 contextMenuItemTagEnterVideoFullscreen()); 676 #if PLATFORM(MAC) 677 ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, 678 contextMenuItemTagSearchInSpotlight()); 679 #endif 680 #if !PLATFORM(GTK) 681 ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb()); 682 #endif 683 ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy()); 684 ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack()); 685 ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward()); 686 ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop()); 687 ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload()); 688 ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, 689 contextMenuItemTagOpenFrameInNewWindow()); 690 ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, 691 contextMenuItemTagNoGuessesFound()); 692 ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, 693 contextMenuItemTagIgnoreSpelling()); 694 ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, 695 contextMenuItemTagLearnSpelling()); 696 ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, 697 contextMenuItemTagIgnoreGrammar()); 698 ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut()); 699 ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste()); 700 #if PLATFORM(GTK) 701 ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete()); 702 #endif 703 #if PLATFORM(GTK) || PLATFORM(QT) 704 ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll()); 705 #endif 706 707 Node* node = m_hitTestResult.innerNonSharedNode(); 708 if (!node) 709 return; 710 #if PLATFORM(GTK) 711 if (!m_hitTestResult.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())) 712 return; 713 #endif 714 Frame* frame = node->document()->frame(); 715 if (!frame) 716 return; 717 718 if (!m_hitTestResult.isContentEditable()) { 719 FrameLoader* loader = frame->loader(); 720 KURL linkURL = m_hitTestResult.absoluteLinkURL(); 721 if (!linkURL.isEmpty()) { 722 if (loader->canHandleRequest(ResourceRequest(linkURL))) { 723 appendItem(OpenLinkItem, m_contextMenu.get()); 724 appendItem(OpenLinkInNewWindowItem, m_contextMenu.get()); 725 appendItem(DownloadFileItem, m_contextMenu.get()); 726 } 727 #if PLATFORM(QT) 728 if (m_hitTestResult.isSelected()) 729 appendItem(CopyItem, m_contextMenu.get()); 730 #endif 731 appendItem(CopyLinkItem, m_contextMenu.get()); 732 } 733 734 KURL imageURL = m_hitTestResult.absoluteImageURL(); 735 if (!imageURL.isEmpty()) { 736 if (!linkURL.isEmpty()) 737 appendItem(*separatorItem(), m_contextMenu.get()); 738 739 appendItem(OpenImageInNewWindowItem, m_contextMenu.get()); 740 appendItem(DownloadImageItem, m_contextMenu.get()); 741 if (imageURL.isLocalFile() || m_hitTestResult.image()) 742 appendItem(CopyImageItem, m_contextMenu.get()); 743 #if PLATFORM(QT) || PLATFORM(GTK) 744 appendItem(CopyImageUrlItem, m_contextMenu.get()); 745 #endif 746 } 747 748 KURL mediaURL = m_hitTestResult.absoluteMediaURL(); 749 if (!mediaURL.isEmpty()) { 750 if (!linkURL.isEmpty() || !imageURL.isEmpty()) 751 appendItem(*separatorItem(), m_contextMenu.get()); 752 753 appendItem(MediaPlayPause, m_contextMenu.get()); 754 appendItem(MediaMute, m_contextMenu.get()); 755 appendItem(ToggleMediaControls, m_contextMenu.get()); 756 appendItem(ToggleMediaLoop, m_contextMenu.get()); 757 appendItem(EnterVideoFullscreen, m_contextMenu.get()); 758 759 appendItem(*separatorItem(), m_contextMenu.get()); 760 appendItem(CopyMediaLinkItem, m_contextMenu.get()); 761 appendItem(OpenMediaInNewWindowItem, m_contextMenu.get()); 762 } 763 764 if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) { 765 if (m_hitTestResult.isSelected()) { 766 if (selectionContainsPossibleWord(frame)) { 767 #if PLATFORM(MAC) 768 String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText()); 769 ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString)); 770 771 #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 772 appendItem(SearchSpotlightItem, m_contextMenu.get()); 773 #else 774 appendItem(LookUpInDictionaryItem, m_contextMenu.get()); 775 #endif 776 #endif 777 778 #if !PLATFORM(GTK) 779 appendItem(SearchWebItem, m_contextMenu.get()); 780 appendItem(*separatorItem(), m_contextMenu.get()); 781 #endif 782 783 #if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 784 appendItem(LookUpInDictionaryItem, m_contextMenu.get()); 785 appendItem(*separatorItem(), m_contextMenu.get()); 786 #endif 787 } 788 789 appendItem(CopyItem, m_contextMenu.get()); 790 #if PLATFORM(MAC) 791 appendItem(*separatorItem(), m_contextMenu.get()); 792 793 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); 794 createAndAppendSpeechSubMenu(SpeechMenuItem); 795 appendItem(SpeechMenuItem, m_contextMenu.get()); 796 #endif 797 } else { 798 #if ENABLE(INSPECTOR) 799 if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) { 800 #endif 801 802 // In GTK+ unavailable items are not hidden but insensitive 803 #if PLATFORM(GTK) 804 appendItem(BackItem, m_contextMenu.get()); 805 appendItem(ForwardItem, m_contextMenu.get()); 806 appendItem(StopItem, m_contextMenu.get()); 807 appendItem(ReloadItem, m_contextMenu.get()); 808 #else 809 if (frame->page() && frame->page()->backForward()->canGoBackOrForward(-1)) 810 appendItem(BackItem, m_contextMenu.get()); 811 812 if (frame->page() && frame->page()->backForward()->canGoBackOrForward(1)) 813 appendItem(ForwardItem, m_contextMenu.get()); 814 815 // use isLoadingInAPISense rather than isLoading because Stop/Reload are 816 // intended to match WebKit's API, not WebCore's internal notion of loading status 817 if (loader->documentLoader()->isLoadingInAPISense()) 818 appendItem(StopItem, m_contextMenu.get()); 819 else 820 appendItem(ReloadItem, m_contextMenu.get()); 821 #endif 822 #if ENABLE(INSPECTOR) 823 } 824 #endif 825 826 if (frame->page() && frame != frame->page()->mainFrame()) 827 appendItem(OpenFrameItem, m_contextMenu.get()); 828 } 829 } 830 } else { // Make an editing context menu 831 SelectionController* selection = frame->selection(); 832 bool inPasswordField = selection->isInPasswordField(); 833 bool spellCheckingEnabled = frame->editor()->isSpellCheckingEnabledFor(node); 834 835 if (!inPasswordField && spellCheckingEnabled) { 836 // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range 837 // is never considered a misspelling and bad grammar at the same time) 838 bool misspelling; 839 bool badGrammar; 840 Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar); 841 if (misspelling || badGrammar) { 842 size_t size = guesses.size(); 843 if (size == 0) { 844 // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions 845 // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit) 846 if (misspelling) { 847 appendItem(NoGuessesItem, m_contextMenu.get()); 848 appendItem(*separatorItem(), m_contextMenu.get()); 849 } 850 } else { 851 for (unsigned i = 0; i < size; i++) { 852 const String &guess = guesses[i]; 853 if (!guess.isEmpty()) { 854 ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess); 855 appendItem(item, m_contextMenu.get()); 856 } 857 } 858 appendItem(*separatorItem(), m_contextMenu.get()); 859 } 860 861 if (misspelling) { 862 appendItem(IgnoreSpellingItem, m_contextMenu.get()); 863 appendItem(LearnSpellingItem, m_contextMenu.get()); 864 } else 865 appendItem(IgnoreGrammarItem, m_contextMenu.get()); 866 appendItem(*separatorItem(), m_contextMenu.get()); 867 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 868 } else { 869 // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. 870 String replacedString = m_hitTestResult.replacedString(); 871 if (!replacedString.isEmpty()) { 872 ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString)); 873 appendItem(item, m_contextMenu.get()); 874 appendItem(*separatorItem(), m_contextMenu.get()); 875 } 876 #endif 877 } 878 } 879 880 FrameLoader* loader = frame->loader(); 881 KURL linkURL = m_hitTestResult.absoluteLinkURL(); 882 if (!linkURL.isEmpty()) { 883 if (loader->canHandleRequest(ResourceRequest(linkURL))) { 884 appendItem(OpenLinkItem, m_contextMenu.get()); 885 appendItem(OpenLinkInNewWindowItem, m_contextMenu.get()); 886 appendItem(DownloadFileItem, m_contextMenu.get()); 887 } 888 appendItem(CopyLinkItem, m_contextMenu.get()); 889 appendItem(*separatorItem(), m_contextMenu.get()); 890 } 891 892 if (m_hitTestResult.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) { 893 #if PLATFORM(MAC) 894 String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText()); 895 ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString)); 896 897 #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 898 appendItem(SearchSpotlightItem, m_contextMenu.get()); 899 #else 900 appendItem(LookUpInDictionaryItem, m_contextMenu.get()); 901 #endif 902 #endif 903 904 #if !PLATFORM(GTK) 905 appendItem(SearchWebItem, m_contextMenu.get()); 906 appendItem(*separatorItem(), m_contextMenu.get()); 907 #endif 908 909 #if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 910 appendItem(LookUpInDictionaryItem, m_contextMenu.get()); 911 appendItem(*separatorItem(), m_contextMenu.get()); 912 #endif 913 } 914 915 appendItem(CutItem, m_contextMenu.get()); 916 appendItem(CopyItem, m_contextMenu.get()); 917 appendItem(PasteItem, m_contextMenu.get()); 918 #if PLATFORM(GTK) 919 appendItem(DeleteItem, m_contextMenu.get()); 920 appendItem(*separatorItem(), m_contextMenu.get()); 921 #endif 922 #if PLATFORM(GTK) || PLATFORM(QT) 923 appendItem(SelectAllItem, m_contextMenu.get()); 924 #endif 925 926 if (!inPasswordField) { 927 appendItem(*separatorItem(), m_contextMenu.get()); 928 #ifndef BUILDING_ON_TIGER 929 #if !PLATFORM(GTK) 930 ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, 931 contextMenuItemTagSpellingMenu()); 932 createAndAppendSpellingAndGrammarSubMenu(SpellingAndGrammarMenuItem); 933 appendItem(SpellingAndGrammarMenuItem, m_contextMenu.get()); 934 #endif 935 #else 936 ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, 937 contextMenuItemTagSpellingMenu()); 938 createAndAppendSpellingSubMenu(SpellingMenuItem); 939 appendItem(SpellingMenuItem, m_contextMenu.get()); 940 #endif 941 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 942 ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, 943 contextMenuItemTagSubstitutionsMenu()); 944 createAndAppendSubstitutionsSubMenu(substitutionsMenuItem); 945 appendItem(substitutionsMenuItem, m_contextMenu.get()); 946 ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, 947 contextMenuItemTagTransformationsMenu()); 948 createAndAppendTransformationsSubMenu(transformationsMenuItem); 949 appendItem(transformationsMenuItem, m_contextMenu.get()); 950 #endif 951 #if PLATFORM(GTK) 952 bool shouldShowFontMenu = frame->editor()->canEditRichly(); 953 #else 954 bool shouldShowFontMenu = true; 955 #endif 956 if (shouldShowFontMenu) { 957 ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, 958 contextMenuItemTagFontMenu()); 959 createAndAppendFontSubMenu(FontMenuItem); 960 appendItem(FontMenuItem, m_contextMenu.get()); 961 } 962 #if PLATFORM(MAC) 963 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); 964 createAndAppendSpeechSubMenu(SpeechMenuItem); 965 appendItem(SpeechMenuItem, m_contextMenu.get()); 966 #endif 967 #if !PLATFORM(GTK) 968 ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, 969 contextMenuItemTagWritingDirectionMenu()); 970 createAndAppendWritingDirectionSubMenu(WritingDirectionMenuItem); 971 appendItem(WritingDirectionMenuItem, m_contextMenu.get()); 972 if (Page* page = frame->page()) { 973 if (Settings* settings = page->settings()) { 974 bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded 975 || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection()); 976 if (includeTextDirectionSubmenu) { 977 ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, 978 contextMenuItemTagTextDirectionMenu()); 979 createAndAppendTextDirectionSubMenu(TextDirectionMenuItem); 980 appendItem(TextDirectionMenuItem, m_contextMenu.get()); 981 } 982 } 983 } 984 #endif 985 } 986 } 987 } 988 989 #if ENABLE(INSPECTOR) 990 void ContextMenuController::addInspectElementItem() 991 { 992 Node* node = m_hitTestResult.innerNonSharedNode(); 993 if (!node) 994 return; 995 996 Frame* frame = node->document()->frame(); 997 if (!frame) 998 return; 999 1000 Page* page = frame->page(); 1001 if (!page) 1002 return; 1003 1004 if (!page->inspectorController()) 1005 return; 1006 1007 ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement()); 1008 appendItem(*separatorItem(), m_contextMenu.get()); 1009 appendItem(InspectElementItem, m_contextMenu.get()); 1010 } 1011 #endif // ENABLE(INSPECTOR) 1012 1013 void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const 1014 { 1015 if (item.type() == SeparatorType) 1016 return; 1017 1018 Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame(); 1019 if (!frame) 1020 return; 1021 1022 // Custom items already have proper checked and enabled values. 1023 if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag) 1024 return; 1025 1026 bool shouldEnable = true; 1027 bool shouldCheck = false; 1028 1029 switch (item.action()) { 1030 case ContextMenuItemTagCheckSpelling: 1031 shouldEnable = frame->editor()->canEdit(); 1032 break; 1033 case ContextMenuItemTagDefaultDirection: 1034 shouldCheck = false; 1035 shouldEnable = false; 1036 break; 1037 case ContextMenuItemTagLeftToRight: 1038 case ContextMenuItemTagRightToLeft: { 1039 String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl"; 1040 shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyDirection, direction) != FalseTriState; 1041 shouldEnable = true; 1042 break; 1043 } 1044 case ContextMenuItemTagTextDirectionDefault: { 1045 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural"); 1046 shouldCheck = command.state() == TrueTriState; 1047 shouldEnable = command.isEnabled(); 1048 break; 1049 } 1050 case ContextMenuItemTagTextDirectionLeftToRight: { 1051 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight"); 1052 shouldCheck = command.state() == TrueTriState; 1053 shouldEnable = command.isEnabled(); 1054 break; 1055 } 1056 case ContextMenuItemTagTextDirectionRightToLeft: { 1057 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft"); 1058 shouldCheck = command.state() == TrueTriState; 1059 shouldEnable = command.isEnabled(); 1060 break; 1061 } 1062 case ContextMenuItemTagCopy: 1063 shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); 1064 break; 1065 case ContextMenuItemTagCut: 1066 shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut(); 1067 break; 1068 case ContextMenuItemTagIgnoreSpelling: 1069 case ContextMenuItemTagLearnSpelling: 1070 shouldEnable = frame->selection()->isRange(); 1071 break; 1072 case ContextMenuItemTagPaste: 1073 shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste(); 1074 break; 1075 #if PLATFORM(GTK) 1076 case ContextMenuItemTagDelete: 1077 shouldEnable = frame->editor()->canDelete(); 1078 break; 1079 case ContextMenuItemTagSelectAll: 1080 case ContextMenuItemTagInputMethods: 1081 case ContextMenuItemTagUnicode: 1082 shouldEnable = true; 1083 break; 1084 #endif 1085 case ContextMenuItemTagUnderline: { 1086 shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline") != FalseTriState; 1087 shouldEnable = frame->editor()->canEditRichly(); 1088 break; 1089 } 1090 case ContextMenuItemTagLookUpInDictionary: 1091 shouldEnable = frame->selection()->isRange(); 1092 break; 1093 case ContextMenuItemTagCheckGrammarWithSpelling: 1094 #ifndef BUILDING_ON_TIGER 1095 if (frame->editor()->isGrammarCheckingEnabled()) 1096 shouldCheck = true; 1097 shouldEnable = true; 1098 #endif 1099 break; 1100 case ContextMenuItemTagItalic: { 1101 shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontStyle, "italic") != FalseTriState; 1102 shouldEnable = frame->editor()->canEditRichly(); 1103 break; 1104 } 1105 case ContextMenuItemTagBold: { 1106 shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontWeight, "bold") != FalseTriState; 1107 shouldEnable = frame->editor()->canEditRichly(); 1108 break; 1109 } 1110 case ContextMenuItemTagOutline: 1111 shouldEnable = false; 1112 break; 1113 case ContextMenuItemTagShowSpellingPanel: 1114 #ifndef BUILDING_ON_TIGER 1115 if (frame->editor()->spellingPanelIsShowing()) 1116 item.setTitle(contextMenuItemTagShowSpellingPanel(false)); 1117 else 1118 item.setTitle(contextMenuItemTagShowSpellingPanel(true)); 1119 #endif 1120 shouldEnable = frame->editor()->canEdit(); 1121 break; 1122 case ContextMenuItemTagNoGuessesFound: 1123 shouldEnable = false; 1124 break; 1125 case ContextMenuItemTagCheckSpellingWhileTyping: 1126 shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled(); 1127 break; 1128 #if PLATFORM(MAC) 1129 case ContextMenuItemTagSubstitutionsMenu: 1130 case ContextMenuItemTagTransformationsMenu: 1131 break; 1132 case ContextMenuItemTagShowSubstitutions: 1133 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 1134 if (frame->editor()->substitutionsPanelIsShowing()) 1135 item.setTitle(contextMenuItemTagShowSubstitutions(false)); 1136 else 1137 item.setTitle(contextMenuItemTagShowSubstitutions(true)); 1138 shouldEnable = frame->editor()->canEdit(); 1139 #endif 1140 break; 1141 case ContextMenuItemTagMakeUpperCase: 1142 case ContextMenuItemTagMakeLowerCase: 1143 case ContextMenuItemTagCapitalize: 1144 case ContextMenuItemTagChangeBack: 1145 shouldEnable = frame->editor()->canEdit(); 1146 break; 1147 case ContextMenuItemTagCorrectSpellingAutomatically: 1148 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 1149 shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled(); 1150 #endif 1151 break; 1152 case ContextMenuItemTagSmartCopyPaste: 1153 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 1154 shouldCheck = frame->editor()->smartInsertDeleteEnabled(); 1155 #endif 1156 break; 1157 case ContextMenuItemTagSmartQuotes: 1158 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 1159 shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled(); 1160 #endif 1161 break; 1162 case ContextMenuItemTagSmartDashes: 1163 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 1164 shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled(); 1165 #endif 1166 break; 1167 case ContextMenuItemTagSmartLinks: 1168 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 1169 shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled(); 1170 #endif 1171 break; 1172 case ContextMenuItemTagTextReplacement: 1173 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 1174 shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled(); 1175 #endif 1176 break; 1177 case ContextMenuItemTagStopSpeaking: 1178 shouldEnable = client() && client()->isSpeaking(); 1179 break; 1180 #else // PLATFORM(MAC) ends here 1181 case ContextMenuItemTagStopSpeaking: 1182 break; 1183 #endif 1184 #if PLATFORM(GTK) 1185 case ContextMenuItemTagGoBack: 1186 shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(-1); 1187 break; 1188 case ContextMenuItemTagGoForward: 1189 shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(1); 1190 break; 1191 case ContextMenuItemTagStop: 1192 shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense(); 1193 break; 1194 case ContextMenuItemTagReload: 1195 shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense(); 1196 break; 1197 case ContextMenuItemTagFontMenu: 1198 shouldEnable = frame->editor()->canEditRichly(); 1199 break; 1200 #else 1201 case ContextMenuItemTagGoBack: 1202 case ContextMenuItemTagGoForward: 1203 case ContextMenuItemTagStop: 1204 case ContextMenuItemTagReload: 1205 case ContextMenuItemTagFontMenu: 1206 #endif 1207 case ContextMenuItemTagNoAction: 1208 case ContextMenuItemTagOpenLinkInNewWindow: 1209 case ContextMenuItemTagDownloadLinkToDisk: 1210 case ContextMenuItemTagCopyLinkToClipboard: 1211 case ContextMenuItemTagOpenImageInNewWindow: 1212 case ContextMenuItemTagDownloadImageToDisk: 1213 case ContextMenuItemTagCopyImageToClipboard: 1214 #if PLATFORM(QT) || PLATFORM(GTK) 1215 case ContextMenuItemTagCopyImageUrlToClipboard: 1216 #endif 1217 break; 1218 case ContextMenuItemTagOpenMediaInNewWindow: 1219 if (m_hitTestResult.mediaIsVideo()) 1220 item.setTitle(contextMenuItemTagOpenVideoInNewWindow()); 1221 else 1222 item.setTitle(contextMenuItemTagOpenAudioInNewWindow()); 1223 break; 1224 case ContextMenuItemTagCopyMediaLinkToClipboard: 1225 if (m_hitTestResult.mediaIsVideo()) 1226 item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard()); 1227 else 1228 item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard()); 1229 break; 1230 case ContextMenuItemTagToggleMediaControls: 1231 shouldCheck = m_hitTestResult.mediaControlsEnabled(); 1232 break; 1233 case ContextMenuItemTagToggleMediaLoop: 1234 shouldCheck = m_hitTestResult.mediaLoopEnabled(); 1235 break; 1236 case ContextMenuItemTagEnterVideoFullscreen: 1237 shouldEnable = m_hitTestResult.mediaSupportsFullscreen(); 1238 break; 1239 case ContextMenuItemTagOpenFrameInNewWindow: 1240 case ContextMenuItemTagSpellingGuess: 1241 case ContextMenuItemTagOther: 1242 case ContextMenuItemTagSearchInSpotlight: 1243 case ContextMenuItemTagSearchWeb: 1244 case ContextMenuItemTagOpenWithDefaultApplication: 1245 case ContextMenuItemPDFActualSize: 1246 case ContextMenuItemPDFZoomIn: 1247 case ContextMenuItemPDFZoomOut: 1248 case ContextMenuItemPDFAutoSize: 1249 case ContextMenuItemPDFSinglePage: 1250 case ContextMenuItemPDFFacingPages: 1251 case ContextMenuItemPDFContinuous: 1252 case ContextMenuItemPDFNextPage: 1253 case ContextMenuItemPDFPreviousPage: 1254 case ContextMenuItemTagOpenLink: 1255 case ContextMenuItemTagIgnoreGrammar: 1256 case ContextMenuItemTagSpellingMenu: 1257 case ContextMenuItemTagShowFonts: 1258 case ContextMenuItemTagStyles: 1259 case ContextMenuItemTagShowColors: 1260 case ContextMenuItemTagSpeechMenu: 1261 case ContextMenuItemTagStartSpeaking: 1262 case ContextMenuItemTagWritingDirectionMenu: 1263 case ContextMenuItemTagTextDirectionMenu: 1264 case ContextMenuItemTagPDFSinglePageScrolling: 1265 case ContextMenuItemTagPDFFacingPagesScrolling: 1266 #if ENABLE(INSPECTOR) 1267 case ContextMenuItemTagInspectElement: 1268 #endif 1269 case ContextMenuItemBaseCustomTag: 1270 case ContextMenuItemCustomTagNoAction: 1271 case ContextMenuItemLastCustomTag: 1272 case ContextMenuItemBaseApplicationTag: 1273 break; 1274 case ContextMenuItemTagMediaPlayPause: 1275 if (m_hitTestResult.mediaPlaying()) 1276 item.setTitle(contextMenuItemTagMediaPause()); 1277 else 1278 item.setTitle(contextMenuItemTagMediaPlay()); 1279 break; 1280 case ContextMenuItemTagMediaMute: 1281 shouldEnable = m_hitTestResult.mediaHasAudio(); 1282 shouldCheck = shouldEnable && m_hitTestResult.mediaMuted(); 1283 break; 1284 } 1285 1286 item.setChecked(shouldCheck); 1287 item.setEnabled(shouldEnable); 1288 } 1289 1290 } // namespace WebCore 1291 1292 #endif // ENABLE(CONTEXT_MENUS) 1293