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