Home | History | Annotate | Download | only in platform
      1 /*
      2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
      3  * Copyright (C) 2008 Christian Dywan <christian (at) imendio.com>
      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 "ContextMenu.h"
     29 
     30 #if ENABLE(CONTEXT_MENUS)
     31 
     32 #include "ContextMenuController.h"
     33 #include "ContextMenuClient.h"
     34 #include "CSSComputedStyleDeclaration.h"
     35 #include "CSSProperty.h"
     36 #include "CSSPropertyNames.h"
     37 #include "CString.h"
     38 #include "Document.h"
     39 #include "DocumentLoader.h"
     40 #include "Editor.h"
     41 #include "Frame.h"
     42 #include "FrameLoader.h"
     43 #include "InspectorController.h"
     44 #include "KURL.h"
     45 #include "LocalizedStrings.h"
     46 #include "Node.h"
     47 #include "Page.h"
     48 #include "ResourceRequest.h"
     49 #include "SelectionController.h"
     50 #include "Settings.h"
     51 #include "TextIterator.h"
     52 #include <memory>
     53 
     54 using namespace std;
     55 using namespace WTF;
     56 using namespace Unicode;
     57 
     58 namespace WebCore {
     59 
     60 ContextMenuController* ContextMenu::controller() const
     61 {
     62     if (Node* node = m_hitTestResult.innerNonSharedNode())
     63         if (Frame* frame = node->document()->frame())
     64             if (Page* page = frame->page())
     65                 return page->contextMenuController();
     66     return 0;
     67 }
     68 
     69 static auto_ptr<ContextMenuItem> separatorItem()
     70 {
     71     return auto_ptr<ContextMenuItem>(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()));
     72 }
     73 
     74 static void createAndAppendFontSubMenu(const HitTestResult& result, ContextMenuItem& fontMenuItem)
     75 {
     76     ContextMenu fontMenu(result);
     77 
     78 #if PLATFORM(MAC)
     79     ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts());
     80 #endif
     81     ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold());
     82     ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic());
     83     ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline());
     84     ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline());
     85 #if PLATFORM(MAC)
     86     ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles());
     87     ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors());
     88 #endif
     89 
     90 #if PLATFORM(MAC)
     91     fontMenu.appendItem(showFonts);
     92 #endif
     93     fontMenu.appendItem(bold);
     94     fontMenu.appendItem(italic);
     95     fontMenu.appendItem(underline);
     96     fontMenu.appendItem(outline);
     97 #if PLATFORM(MAC)
     98     fontMenu.appendItem(styles);
     99     fontMenu.appendItem(*separatorItem());
    100     fontMenu.appendItem(showColors);
    101 #endif
    102 
    103     fontMenuItem.setSubMenu(&fontMenu);
    104 }
    105 
    106 #ifndef BUILDING_ON_TIGER
    107 static void createAndAppendSpellingAndGrammarSubMenu(const HitTestResult& result, ContextMenuItem& spellingAndGrammarMenuItem)
    108 {
    109     ContextMenu spellingAndGrammarMenu(result);
    110 
    111     ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
    112         contextMenuItemTagShowSpellingPanel(true));
    113     ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
    114         contextMenuItemTagCheckSpelling());
    115     ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
    116         contextMenuItemTagCheckSpellingWhileTyping());
    117     ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling,
    118         contextMenuItemTagCheckGrammarWithSpelling());
    119 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    120     ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically,
    121         contextMenuItemTagCorrectSpellingAutomatically());
    122 #endif
    123 
    124     spellingAndGrammarMenu.appendItem(showSpellingPanel);
    125     spellingAndGrammarMenu.appendItem(checkSpelling);
    126 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    127     spellingAndGrammarMenu.appendItem(*separatorItem());
    128 #endif
    129     spellingAndGrammarMenu.appendItem(checkAsYouType);
    130     spellingAndGrammarMenu.appendItem(grammarWithSpelling);
    131 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    132     spellingAndGrammarMenu.appendItem(correctSpelling);
    133 #endif
    134 
    135     spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu);
    136 }
    137 #else
    138 
    139 static void createAndAppendSpellingSubMenu(const HitTestResult& result, ContextMenuItem& spellingMenuItem)
    140 {
    141     ContextMenu spellingMenu(result);
    142 
    143     ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
    144         contextMenuItemTagShowSpellingPanel(true));
    145     ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
    146         contextMenuItemTagCheckSpelling());
    147     ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
    148         contextMenuItemTagCheckSpellingWhileTyping());
    149 
    150     spellingMenu.appendItem(showSpellingPanel);
    151     spellingMenu.appendItem(checkSpelling);
    152     spellingMenu.appendItem(checkAsYouType);
    153 
    154     spellingMenuItem.setSubMenu(&spellingMenu);
    155 }
    156 #endif
    157 
    158 #if PLATFORM(MAC)
    159 static void createAndAppendSpeechSubMenu(const HitTestResult& result, ContextMenuItem& speechMenuItem)
    160 {
    161     ContextMenu speechMenu(result);
    162 
    163     ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking());
    164     ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking());
    165 
    166     speechMenu.appendItem(start);
    167     speechMenu.appendItem(stop);
    168 
    169     speechMenuItem.setSubMenu(&speechMenu);
    170 }
    171 #endif
    172 
    173 #if !PLATFORM(GTK)
    174 static void createAndAppendWritingDirectionSubMenu(const HitTestResult& result, ContextMenuItem& writingDirectionMenuItem)
    175 {
    176     ContextMenu writingDirectionMenu(result);
    177 
    178     ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection,
    179         contextMenuItemTagDefaultDirection());
    180     ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight());
    181     ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft());
    182 
    183     writingDirectionMenu.appendItem(defaultItem);
    184     writingDirectionMenu.appendItem(ltr);
    185     writingDirectionMenu.appendItem(rtl);
    186 
    187     writingDirectionMenuItem.setSubMenu(&writingDirectionMenu);
    188 }
    189 
    190 static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, ContextMenuItem& textDirectionMenuItem)
    191 {
    192     ContextMenu textDirectionMenu(result);
    193 
    194     ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection());
    195     ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight());
    196     ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft());
    197 
    198     textDirectionMenu.appendItem(defaultItem);
    199     textDirectionMenu.appendItem(ltr);
    200     textDirectionMenu.appendItem(rtl);
    201 
    202     textDirectionMenuItem.setSubMenu(&textDirectionMenu);
    203 }
    204 #endif
    205 
    206 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    207 static void createAndAppendSubstitutionsSubMenu(const HitTestResult& result, ContextMenuItem& substitutionsMenuItem)
    208 {
    209     ContextMenu substitutionsMenu(result);
    210 
    211     ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true));
    212     ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste());
    213     ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes());
    214     ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes());
    215     ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks());
    216     ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement());
    217 
    218     substitutionsMenu.appendItem(showSubstitutions);
    219     substitutionsMenu.appendItem(*separatorItem());
    220     substitutionsMenu.appendItem(smartCopyPaste);
    221     substitutionsMenu.appendItem(smartQuotes);
    222     substitutionsMenu.appendItem(smartDashes);
    223     substitutionsMenu.appendItem(smartLinks);
    224     substitutionsMenu.appendItem(textReplacement);
    225 
    226     substitutionsMenuItem.setSubMenu(&substitutionsMenu);
    227 }
    228 
    229 static void createAndAppendTransformationsSubMenu(const HitTestResult& result, ContextMenuItem& transformationsMenuItem)
    230 {
    231     ContextMenu transformationsMenu(result);
    232 
    233     ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase());
    234     ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase());
    235     ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize());
    236 
    237     transformationsMenu.appendItem(makeUpperCase);
    238     transformationsMenu.appendItem(makeLowerCase);
    239     transformationsMenu.appendItem(capitalize);
    240 
    241     transformationsMenuItem.setSubMenu(&transformationsMenu);
    242 }
    243 #endif
    244 
    245 static bool selectionContainsPossibleWord(Frame* frame)
    246 {
    247     // Current algorithm: look for a character that's not just a separator.
    248     for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) {
    249         int length = it.length();
    250         const UChar* characters = it.characters();
    251         for (int i = 0; i < length; ++i)
    252             if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph)))
    253                 return true;
    254     }
    255     return false;
    256 }
    257 
    258 void ContextMenu::populate()
    259 {
    260     ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink());
    261     ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow,
    262         contextMenuItemTagOpenLinkInNewWindow());
    263     ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk,
    264         contextMenuItemTagDownloadLinkToDisk());
    265     ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard,
    266         contextMenuItemTagCopyLinkToClipboard());
    267     ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow,
    268         contextMenuItemTagOpenImageInNewWindow());
    269     ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk,
    270         contextMenuItemTagDownloadImageToDisk());
    271     ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard,
    272         contextMenuItemTagCopyImageToClipboard());
    273 #if PLATFORM(MAC)
    274     ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight,
    275         contextMenuItemTagSearchInSpotlight());
    276     ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary,
    277         contextMenuItemTagLookUpInDictionary());
    278 #endif
    279 #if !PLATFORM(GTK)
    280     ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb());
    281 #endif
    282     ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy());
    283     ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack());
    284     ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward,  contextMenuItemTagGoForward());
    285     ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop());
    286     ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload());
    287     ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow,
    288         contextMenuItemTagOpenFrameInNewWindow());
    289     ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound,
    290         contextMenuItemTagNoGuessesFound());
    291     ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling,
    292         contextMenuItemTagIgnoreSpelling());
    293     ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling,
    294         contextMenuItemTagLearnSpelling());
    295     ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar,
    296         contextMenuItemTagIgnoreGrammar());
    297     ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut());
    298     ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
    299 #if PLATFORM(GTK)
    300     ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
    301     ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
    302 #endif
    303 
    304     HitTestResult result = hitTestResult();
    305 
    306     Node* node = m_hitTestResult.innerNonSharedNode();
    307     if (!node)
    308         return;
    309 #if PLATFORM(GTK)
    310     if (!result.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
    311         return;
    312 #endif
    313     Frame* frame = node->document()->frame();
    314     if (!frame)
    315         return;
    316 
    317     if (!result.isContentEditable()) {
    318         FrameLoader* loader = frame->loader();
    319         KURL linkURL = result.absoluteLinkURL();
    320         if (!linkURL.isEmpty()) {
    321             if (loader->canHandleRequest(ResourceRequest(linkURL))) {
    322                 appendItem(OpenLinkItem);
    323                 appendItem(OpenLinkInNewWindowItem);
    324                 appendItem(DownloadFileItem);
    325             }
    326             appendItem(CopyLinkItem);
    327         }
    328 
    329         KURL imageURL = result.absoluteImageURL();
    330         if (!imageURL.isEmpty()) {
    331             if (!linkURL.isEmpty())
    332                 appendItem(*separatorItem());
    333 
    334             appendItem(OpenImageInNewWindowItem);
    335             appendItem(DownloadImageItem);
    336             if (imageURL.isLocalFile() || m_hitTestResult.image())
    337                 appendItem(CopyImageItem);
    338         }
    339 
    340         if (imageURL.isEmpty() && linkURL.isEmpty()) {
    341             if (result.isSelected()) {
    342                 if (selectionContainsPossibleWord(frame)) {
    343 #if PLATFORM(MAC)
    344                     appendItem(SearchSpotlightItem);
    345 #endif
    346 #if !PLATFORM(GTK)
    347                     appendItem(SearchWebItem);
    348                     appendItem(*separatorItem());
    349 #endif
    350 #if PLATFORM(MAC)
    351                     appendItem(LookInDictionaryItem);
    352                     appendItem(*separatorItem());
    353 #endif
    354                 }
    355                 appendItem(CopyItem);
    356 #if PLATFORM(MAC)
    357                 appendItem(*separatorItem());
    358                 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
    359                 createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem);
    360                 appendItem(SpeechMenuItem);
    361 #endif
    362             } else {
    363 #if PLATFORM(GTK)
    364                 appendItem(BackItem);
    365                 appendItem(ForwardItem);
    366                 appendItem(StopItem);
    367                 appendItem(ReloadItem);
    368 #else
    369                 if (frame->page() && frame->page()->canGoBackOrForward(-1))
    370                     appendItem(BackItem);
    371 
    372                 if (frame->page() && frame->page()->canGoBackOrForward(1))
    373                     appendItem(ForwardItem);
    374 
    375                 // use isLoadingInAPISense rather than isLoading because Stop/Reload are
    376                 // intended to match WebKit's API, not WebCore's internal notion of loading status
    377                 if (loader->documentLoader()->isLoadingInAPISense())
    378                     appendItem(StopItem);
    379                 else
    380                     appendItem(ReloadItem);
    381 #endif
    382 
    383                 if (frame->page() && frame != frame->page()->mainFrame())
    384                     appendItem(OpenFrameItem);
    385             }
    386         }
    387     } else { // Make an editing context menu
    388         SelectionController* selection = frame->selection();
    389         bool inPasswordField = selection->isInPasswordField();
    390 
    391         if (!inPasswordField) {
    392             // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
    393             // is never considered a misspelling and bad grammar at the same time)
    394             bool misspelling;
    395             bool badGrammar;
    396             Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
    397             if (misspelling || badGrammar) {
    398                 size_t size = guesses.size();
    399                 if (size == 0) {
    400                     // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
    401                     // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit)
    402                     if (misspelling) {
    403                         appendItem(NoGuessesItem);
    404                         appendItem(*separatorItem());
    405                     }
    406                 } else {
    407                     for (unsigned i = 0; i < size; i++) {
    408                         const String &guess = guesses[i];
    409                         if (!guess.isEmpty()) {
    410                             ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
    411                             appendItem(item);
    412                         }
    413                     }
    414                     appendItem(*separatorItem());
    415                 }
    416 
    417                 if (misspelling) {
    418                     appendItem(IgnoreSpellingItem);
    419                     appendItem(LearnSpellingItem);
    420                 } else
    421                     appendItem(IgnoreGrammarItem);
    422                 appendItem(*separatorItem());
    423 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    424             } else {
    425                 // If the string was autocorrected, generate a contextual menu item allowing it to be changed back.
    426                 String replacedString = result.replacedString();
    427                 if (!replacedString.isEmpty()) {
    428                     ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString));
    429                     appendItem(item);
    430                     appendItem(*separatorItem());
    431                 }
    432 #endif
    433             }
    434         }
    435 
    436         FrameLoader* loader = frame->loader();
    437         KURL linkURL = result.absoluteLinkURL();
    438         if (!linkURL.isEmpty()) {
    439             if (loader->canHandleRequest(ResourceRequest(linkURL))) {
    440                 appendItem(OpenLinkItem);
    441                 appendItem(OpenLinkInNewWindowItem);
    442                 appendItem(DownloadFileItem);
    443             }
    444             appendItem(CopyLinkItem);
    445             appendItem(*separatorItem());
    446         }
    447 
    448         if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) {
    449 #if PLATFORM(MAC)
    450             appendItem(SearchSpotlightItem);
    451 #endif
    452 #if !PLATFORM(GTK)
    453             appendItem(SearchWebItem);
    454             appendItem(*separatorItem());
    455 #endif
    456 
    457 #if PLATFORM(MAC)
    458             appendItem(LookInDictionaryItem);
    459             appendItem(*separatorItem());
    460 #endif
    461         }
    462 
    463         appendItem(CutItem);
    464         appendItem(CopyItem);
    465         appendItem(PasteItem);
    466 #if PLATFORM(GTK)
    467         appendItem(DeleteItem);
    468         appendItem(*separatorItem());
    469         appendItem(SelectAllItem);
    470 #endif
    471 
    472         if (!inPasswordField) {
    473             appendItem(*separatorItem());
    474 #ifndef BUILDING_ON_TIGER
    475 #if !PLATFORM(GTK)
    476             ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
    477                 contextMenuItemTagSpellingMenu());
    478             createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem);
    479             appendItem(SpellingAndGrammarMenuItem);
    480 #endif
    481 #else
    482             ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
    483                 contextMenuItemTagSpellingMenu());
    484             createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem);
    485             appendItem(SpellingMenuItem);
    486 #endif
    487 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    488             ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu,
    489                 contextMenuItemTagSubstitutionsMenu());
    490             createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem);
    491             appendItem(substitutionsMenuItem);
    492             ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu,
    493                 contextMenuItemTagTransformationsMenu());
    494             createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem);
    495             appendItem(transformationsMenuItem);
    496 #endif
    497 #if PLATFORM(GTK)
    498             bool shouldShowFontMenu = frame->editor()->canEditRichly();
    499 #else
    500             bool shouldShowFontMenu = true;
    501 #endif
    502             if (shouldShowFontMenu) {
    503                 ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu,
    504                     contextMenuItemTagFontMenu());
    505                 createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem);
    506                 appendItem(FontMenuItem);
    507             }
    508 #if PLATFORM(MAC)
    509             ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
    510             createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem);
    511             appendItem(SpeechMenuItem);
    512 #endif
    513 #if !PLATFORM(GTK)
    514             ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu,
    515                 contextMenuItemTagWritingDirectionMenu());
    516             createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem);
    517             appendItem(WritingDirectionMenuItem);
    518             if (Page* page = frame->page()) {
    519                 if (Settings* settings = page->settings()) {
    520                     bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
    521                         || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
    522                     if (includeTextDirectionSubmenu) {
    523                         ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu,
    524                             contextMenuItemTagTextDirectionMenu());
    525                         createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem);
    526                         appendItem(TextDirectionMenuItem);
    527                     }
    528                 }
    529             }
    530 #endif
    531         }
    532     }
    533 }
    534 
    535 #if ENABLE(INSPECTOR)
    536 void ContextMenu::addInspectElementItem()
    537 {
    538     Node* node = m_hitTestResult.innerNonSharedNode();
    539     if (!node)
    540         return;
    541 
    542     Frame* frame = node->document()->frame();
    543     if (!frame)
    544         return;
    545 
    546     Page* page = frame->page();
    547     if (!page)
    548         return;
    549 
    550     if (!page->inspectorController())
    551         return;
    552 
    553     ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement());
    554     appendItem(*separatorItem());
    555     appendItem(InspectElementItem);
    556 }
    557 #endif // ENABLE(INSPECTOR)
    558 
    559 void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const
    560 {
    561     if (item.type() == SeparatorType)
    562         return;
    563 
    564     Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
    565     if (!frame)
    566         return;
    567 
    568     bool shouldEnable = true;
    569     bool shouldCheck = false;
    570 
    571     switch (item.action()) {
    572         case ContextMenuItemTagCheckSpelling:
    573             shouldEnable = frame->editor()->canEdit();
    574             break;
    575         case ContextMenuItemTagDefaultDirection:
    576             shouldCheck = false;
    577             shouldEnable = false;
    578             break;
    579         case ContextMenuItemTagLeftToRight:
    580         case ContextMenuItemTagRightToLeft: {
    581             ExceptionCode ec = 0;
    582             RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    583             String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
    584             style->setProperty(CSSPropertyDirection, direction, false, ec);
    585             shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    586             shouldEnable = true;
    587             break;
    588         }
    589         case ContextMenuItemTagTextDirectionDefault: {
    590             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural");
    591             shouldCheck = command.state() == TrueTriState;
    592             shouldEnable = command.isEnabled();
    593             break;
    594         }
    595         case ContextMenuItemTagTextDirectionLeftToRight: {
    596             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight");
    597             shouldCheck = command.state() == TrueTriState;
    598             shouldEnable = command.isEnabled();
    599             break;
    600         }
    601         case ContextMenuItemTagTextDirectionRightToLeft: {
    602             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft");
    603             shouldCheck = command.state() == TrueTriState;
    604             shouldEnable = command.isEnabled();
    605             break;
    606         }
    607         case ContextMenuItemTagCopy:
    608             shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
    609             break;
    610         case ContextMenuItemTagCut:
    611             shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut();
    612             break;
    613         case ContextMenuItemTagIgnoreSpelling:
    614         case ContextMenuItemTagLearnSpelling:
    615             shouldEnable = frame->selection()->isRange();
    616             break;
    617         case ContextMenuItemTagPaste:
    618             shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste();
    619             break;
    620 #if PLATFORM(GTK)
    621         case ContextMenuItemTagDelete:
    622             shouldEnable = frame->editor()->canDelete();
    623             break;
    624         case ContextMenuItemTagSelectAll:
    625         case ContextMenuItemTagInputMethods:
    626         case ContextMenuItemTagUnicode:
    627             shouldEnable = true;
    628             break;
    629 #endif
    630         case ContextMenuItemTagUnderline: {
    631             ExceptionCode ec = 0;
    632             RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    633             style->setProperty(CSSPropertyWebkitTextDecorationsInEffect, "underline", false, ec);
    634             shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    635             shouldEnable = frame->editor()->canEditRichly();
    636             break;
    637         }
    638         case ContextMenuItemTagLookUpInDictionary:
    639             shouldEnable = frame->selection()->isRange();
    640             break;
    641         case ContextMenuItemTagCheckGrammarWithSpelling:
    642 #ifndef BUILDING_ON_TIGER
    643             if (frame->editor()->isGrammarCheckingEnabled())
    644                 shouldCheck = true;
    645             shouldEnable = true;
    646 #endif
    647             break;
    648         case ContextMenuItemTagItalic: {
    649             ExceptionCode ec = 0;
    650             RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    651             style->setProperty(CSSPropertyFontStyle, "italic", false, ec);
    652             shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    653             shouldEnable = frame->editor()->canEditRichly();
    654             break;
    655         }
    656         case ContextMenuItemTagBold: {
    657             ExceptionCode ec = 0;
    658             RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
    659             style->setProperty(CSSPropertyFontWeight, "bold", false, ec);
    660             shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
    661             shouldEnable = frame->editor()->canEditRichly();
    662             break;
    663         }
    664         case ContextMenuItemTagOutline:
    665             shouldEnable = false;
    666             break;
    667         case ContextMenuItemTagShowSpellingPanel:
    668 #ifndef BUILDING_ON_TIGER
    669             if (frame->editor()->spellingPanelIsShowing())
    670                 item.setTitle(contextMenuItemTagShowSpellingPanel(false));
    671             else
    672                 item.setTitle(contextMenuItemTagShowSpellingPanel(true));
    673 #endif
    674             shouldEnable = frame->editor()->canEdit();
    675             break;
    676         case ContextMenuItemTagNoGuessesFound:
    677             shouldEnable = false;
    678             break;
    679         case ContextMenuItemTagCheckSpellingWhileTyping:
    680             shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled();
    681             break;
    682 #if PLATFORM(MAC)
    683         case ContextMenuItemTagSubstitutionsMenu:
    684         case ContextMenuItemTagTransformationsMenu:
    685             break;
    686         case ContextMenuItemTagShowSubstitutions:
    687 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    688             if (frame->editor()->substitutionsPanelIsShowing())
    689                 item.setTitle(contextMenuItemTagShowSubstitutions(false));
    690             else
    691                 item.setTitle(contextMenuItemTagShowSubstitutions(true));
    692             shouldEnable = frame->editor()->canEdit();
    693 #endif
    694             break;
    695         case ContextMenuItemTagMakeUpperCase:
    696         case ContextMenuItemTagMakeLowerCase:
    697         case ContextMenuItemTagCapitalize:
    698         case ContextMenuItemTagChangeBack:
    699             shouldEnable = frame->editor()->canEdit();
    700             break;
    701         case ContextMenuItemTagCorrectSpellingAutomatically:
    702 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    703             shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled();
    704 #endif
    705             break;
    706         case ContextMenuItemTagSmartCopyPaste:
    707 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    708             shouldCheck = frame->editor()->smartInsertDeleteEnabled();
    709 #endif
    710             break;
    711         case ContextMenuItemTagSmartQuotes:
    712 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    713             shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled();
    714 #endif
    715             break;
    716         case ContextMenuItemTagSmartDashes:
    717 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    718             shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled();
    719 #endif
    720             break;
    721         case ContextMenuItemTagSmartLinks:
    722 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    723             shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled();
    724 #endif
    725             break;
    726         case ContextMenuItemTagTextReplacement:
    727 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
    728             shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled();
    729 #endif
    730             break;
    731         case ContextMenuItemTagStopSpeaking:
    732             shouldEnable = controller() && controller()->client() && controller()->client()->isSpeaking();
    733             break;
    734 #else // PLATFORM(MAC) ends here
    735         case ContextMenuItemTagStopSpeaking:
    736             break;
    737 #endif
    738 #if PLATFORM(GTK)
    739         case ContextMenuItemTagGoBack:
    740             shouldEnable = frame->page() && frame->page()->canGoBackOrForward(-1);
    741             break;
    742         case ContextMenuItemTagGoForward:
    743             shouldEnable = frame->page() && frame->page()->canGoBackOrForward(1);
    744             break;
    745         case ContextMenuItemTagStop:
    746             shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense();
    747             break;
    748         case ContextMenuItemTagReload:
    749             shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense();
    750             break;
    751         case ContextMenuItemTagFontMenu:
    752             shouldEnable = frame->editor()->canEditRichly();
    753             break;
    754 #else
    755         case ContextMenuItemTagGoBack:
    756         case ContextMenuItemTagGoForward:
    757         case ContextMenuItemTagStop:
    758         case ContextMenuItemTagReload:
    759         case ContextMenuItemTagFontMenu:
    760 #endif
    761         case ContextMenuItemTagNoAction:
    762         case ContextMenuItemTagOpenLinkInNewWindow:
    763         case ContextMenuItemTagDownloadLinkToDisk:
    764         case ContextMenuItemTagCopyLinkToClipboard:
    765         case ContextMenuItemTagOpenImageInNewWindow:
    766         case ContextMenuItemTagDownloadImageToDisk:
    767         case ContextMenuItemTagCopyImageToClipboard:
    768         case ContextMenuItemTagOpenFrameInNewWindow:
    769         case ContextMenuItemTagSpellingGuess:
    770         case ContextMenuItemTagOther:
    771         case ContextMenuItemTagSearchInSpotlight:
    772         case ContextMenuItemTagSearchWeb:
    773         case ContextMenuItemTagOpenWithDefaultApplication:
    774         case ContextMenuItemPDFActualSize:
    775         case ContextMenuItemPDFZoomIn:
    776         case ContextMenuItemPDFZoomOut:
    777         case ContextMenuItemPDFAutoSize:
    778         case ContextMenuItemPDFSinglePage:
    779         case ContextMenuItemPDFFacingPages:
    780         case ContextMenuItemPDFContinuous:
    781         case ContextMenuItemPDFNextPage:
    782         case ContextMenuItemPDFPreviousPage:
    783         case ContextMenuItemTagOpenLink:
    784         case ContextMenuItemTagIgnoreGrammar:
    785         case ContextMenuItemTagSpellingMenu:
    786         case ContextMenuItemTagShowFonts:
    787         case ContextMenuItemTagStyles:
    788         case ContextMenuItemTagShowColors:
    789         case ContextMenuItemTagSpeechMenu:
    790         case ContextMenuItemTagStartSpeaking:
    791         case ContextMenuItemTagWritingDirectionMenu:
    792         case ContextMenuItemTagTextDirectionMenu:
    793         case ContextMenuItemTagPDFSinglePageScrolling:
    794         case ContextMenuItemTagPDFFacingPagesScrolling:
    795 #if ENABLE(INSPECTOR)
    796         case ContextMenuItemTagInspectElement:
    797 #endif
    798         case ContextMenuItemBaseCustomTag:
    799         case ContextMenuItemBaseApplicationTag:
    800             break;
    801     }
    802 
    803     item.setChecked(shouldCheck);
    804     item.setEnabled(shouldEnable);
    805 }
    806 
    807 } // namespace WebCore
    808 
    809 #endif // ENABLE(CONTEXT_MENUS)
    810