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