Home | History | Annotate | Download | only in page
      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