diff -r 000000000000 -r 4f2f89ce4247 WebCore/platform/ContextMenu.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebCore/platform/ContextMenu.cpp Fri Sep 17 09:02:29 2010 +0300 @@ -0,0 +1,828 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Christian Dywan + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "ContextMenu.h" + +#if ENABLE(CONTEXT_MENUS) + +#include "ContextMenuController.h" +#include "ContextMenuClient.h" +#include "CSSComputedStyleDeclaration.h" +#include "CSSProperty.h" +#include "CSSPropertyNames.h" +#include "Document.h" +#include "DocumentLoader.h" +#include "Editor.h" +#include "Frame.h" +#include "FrameLoader.h" +#include "InspectorController.h" +#include "KURL.h" +#include "LocalizedStrings.h" +#include "Node.h" +#include "Page.h" +#include "ResourceRequest.h" +#include "SelectionController.h" +#include "Settings.h" +#include "TextIterator.h" +#include + +using namespace std; +using namespace WTF; +using namespace Unicode; + +namespace WebCore { + +ContextMenuController* ContextMenu::controller() const +{ + if (Node* node = m_hitTestResult.innerNonSharedNode()) + if (Frame* frame = node->document()->frame()) + if (Page* page = frame->page()) + return page->contextMenuController(); + return 0; +} + +static PassOwnPtr separatorItem() +{ + return new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()); +} + +static void createAndAppendFontSubMenu(const HitTestResult& result, ContextMenuItem& fontMenuItem) +{ + ContextMenu fontMenu(result); + +#if PLATFORM(MAC) + ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts()); +#endif + ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold()); + ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic()); + ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline()); + ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline()); +#if PLATFORM(MAC) + ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles()); + ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors()); +#endif + +#if PLATFORM(MAC) + fontMenu.appendItem(showFonts); +#endif + fontMenu.appendItem(bold); + fontMenu.appendItem(italic); + fontMenu.appendItem(underline); + fontMenu.appendItem(outline); +#if PLATFORM(MAC) + fontMenu.appendItem(styles); + fontMenu.appendItem(*separatorItem()); + fontMenu.appendItem(showColors); +#endif + + fontMenuItem.setSubMenu(&fontMenu); +} + +#if !defined(BUILDING_ON_TIGER) + +#if !PLATFORM(GTK) + +static void createAndAppendSpellingAndGrammarSubMenu(const HitTestResult& result, ContextMenuItem& spellingAndGrammarMenuItem) +{ + ContextMenu spellingAndGrammarMenu(result); + + ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, + contextMenuItemTagShowSpellingPanel(true)); + ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, + contextMenuItemTagCheckSpelling()); + ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, + contextMenuItemTagCheckSpellingWhileTyping()); + ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling, + contextMenuItemTagCheckGrammarWithSpelling()); +#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) + ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically, + contextMenuItemTagCorrectSpellingAutomatically()); +#endif + + spellingAndGrammarMenu.appendItem(showSpellingPanel); + spellingAndGrammarMenu.appendItem(checkSpelling); +#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) + spellingAndGrammarMenu.appendItem(*separatorItem()); +#endif + spellingAndGrammarMenu.appendItem(checkAsYouType); + spellingAndGrammarMenu.appendItem(grammarWithSpelling); +#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) + spellingAndGrammarMenu.appendItem(correctSpelling); +#endif + + spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu); +} + +#endif // !PLATFORM(GTK) + +#else + +static void createAndAppendSpellingSubMenu(const HitTestResult& result, ContextMenuItem& spellingMenuItem) +{ + ContextMenu spellingMenu(result); + + ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, + contextMenuItemTagShowSpellingPanel(true)); + ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, + contextMenuItemTagCheckSpelling()); + ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, + contextMenuItemTagCheckSpellingWhileTyping()); + + spellingMenu.appendItem(showSpellingPanel); + spellingMenu.appendItem(checkSpelling); + spellingMenu.appendItem(checkAsYouType); + + spellingMenuItem.setSubMenu(&spellingMenu); +} + +#endif + +#if PLATFORM(MAC) + +static void createAndAppendSpeechSubMenu(const HitTestResult& result, ContextMenuItem& speechMenuItem) +{ + ContextMenu speechMenu(result); + + ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking()); + ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking()); + + speechMenu.appendItem(start); + speechMenu.appendItem(stop); + + speechMenuItem.setSubMenu(&speechMenu); +} + +#endif + +#if !PLATFORM(GTK) + +static void createAndAppendWritingDirectionSubMenu(const HitTestResult& result, ContextMenuItem& writingDirectionMenuItem) +{ + ContextMenu writingDirectionMenu(result); + + ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection, + contextMenuItemTagDefaultDirection()); + ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight()); + ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft()); + + writingDirectionMenu.appendItem(defaultItem); + writingDirectionMenu.appendItem(ltr); + writingDirectionMenu.appendItem(rtl); + + writingDirectionMenuItem.setSubMenu(&writingDirectionMenu); +} + +static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, ContextMenuItem& textDirectionMenuItem) +{ + ContextMenu textDirectionMenu(result); + + ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection()); + ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight()); + ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft()); + + textDirectionMenu.appendItem(defaultItem); + textDirectionMenu.appendItem(ltr); + textDirectionMenu.appendItem(rtl); + + textDirectionMenuItem.setSubMenu(&textDirectionMenu); +} + +#endif + +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + +static void createAndAppendSubstitutionsSubMenu(const HitTestResult& result, ContextMenuItem& substitutionsMenuItem) +{ + ContextMenu substitutionsMenu(result); + + ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true)); + ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste()); + ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes()); + ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes()); + ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks()); + ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement()); + + substitutionsMenu.appendItem(showSubstitutions); + substitutionsMenu.appendItem(*separatorItem()); + substitutionsMenu.appendItem(smartCopyPaste); + substitutionsMenu.appendItem(smartQuotes); + substitutionsMenu.appendItem(smartDashes); + substitutionsMenu.appendItem(smartLinks); + substitutionsMenu.appendItem(textReplacement); + + substitutionsMenuItem.setSubMenu(&substitutionsMenu); +} + +static void createAndAppendTransformationsSubMenu(const HitTestResult& result, ContextMenuItem& transformationsMenuItem) +{ + ContextMenu transformationsMenu(result); + + ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase()); + ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase()); + ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize()); + + transformationsMenu.appendItem(makeUpperCase); + transformationsMenu.appendItem(makeLowerCase); + transformationsMenu.appendItem(capitalize); + + transformationsMenuItem.setSubMenu(&transformationsMenu); +} + +#endif + +static bool selectionContainsPossibleWord(Frame* frame) +{ + // Current algorithm: look for a character that's not just a separator. + for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) { + int length = it.length(); + const UChar* characters = it.characters(); + for (int i = 0; i < length; ++i) + if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph))) + return true; + } + return false; +} + +void ContextMenu::populate() +{ + ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); + ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, + contextMenuItemTagOpenLinkInNewWindow()); + ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, + contextMenuItemTagDownloadLinkToDisk()); + ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, + contextMenuItemTagCopyLinkToClipboard()); + ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, + contextMenuItemTagOpenImageInNewWindow()); + ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, + contextMenuItemTagDownloadImageToDisk()); + ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, + contextMenuItemTagCopyImageToClipboard()); +#if PLATFORM(MAC) + ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, + contextMenuItemTagSearchInSpotlight()); + ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, + contextMenuItemTagLookUpInDictionary()); +#endif +#if !PLATFORM(GTK) + ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb()); +#endif + ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy()); + ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack()); + ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward()); + ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop()); + ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload()); + ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, + contextMenuItemTagOpenFrameInNewWindow()); + ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, + contextMenuItemTagNoGuessesFound()); + ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, + contextMenuItemTagIgnoreSpelling()); + ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, + contextMenuItemTagLearnSpelling()); + ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, + contextMenuItemTagIgnoreGrammar()); + ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut()); + ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste()); +#if PLATFORM(GTK) + ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete()); + ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll()); +#endif + + HitTestResult result = hitTestResult(); + + Node* node = m_hitTestResult.innerNonSharedNode(); + if (!node) + return; +#if PLATFORM(GTK) + if (!result.isContentEditable() && (node->isElementNode() && static_cast(node)->isFormControlElement())) + return; +#endif + Frame* frame = node->document()->frame(); + if (!frame) + return; + + if (!result.isContentEditable()) { + FrameLoader* loader = frame->loader(); + KURL linkURL = result.absoluteLinkURL(); + if (!linkURL.isEmpty()) { + if (loader->canHandleRequest(ResourceRequest(linkURL))) { + appendItem(OpenLinkItem); + appendItem(OpenLinkInNewWindowItem); + appendItem(DownloadFileItem); + } + appendItem(CopyLinkItem); + } + + KURL imageURL = result.absoluteImageURL(); + if (!imageURL.isEmpty()) { + if (!linkURL.isEmpty()) + appendItem(*separatorItem()); + + appendItem(OpenImageInNewWindowItem); + appendItem(DownloadImageItem); + if (imageURL.isLocalFile() || m_hitTestResult.image()) + appendItem(CopyImageItem); + } + + if (imageURL.isEmpty() && linkURL.isEmpty()) { + if (result.isSelected()) { + if (selectionContainsPossibleWord(frame)) { +#if PLATFORM(MAC) + appendItem(SearchSpotlightItem); +#endif +#if !PLATFORM(GTK) + appendItem(SearchWebItem); + appendItem(*separatorItem()); +#endif +#if PLATFORM(MAC) + appendItem(LookInDictionaryItem); + appendItem(*separatorItem()); +#endif + } + appendItem(CopyItem); +#if PLATFORM(MAC) + appendItem(*separatorItem()); + ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); + createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); + appendItem(SpeechMenuItem); +#endif + } else { +#if ENABLE(INSPECTOR) + if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) { +#endif +#if PLATFORM(GTK) + appendItem(BackItem); + appendItem(ForwardItem); + appendItem(StopItem); + appendItem(ReloadItem); +#else + if (frame->page() && frame->page()->canGoBackOrForward(-1)) + appendItem(BackItem); + + if (frame->page() && frame->page()->canGoBackOrForward(1)) + appendItem(ForwardItem); + + // use isLoadingInAPISense rather than isLoading because Stop/Reload are + // intended to match WebKit's API, not WebCore's internal notion of loading status + if (loader->documentLoader()->isLoadingInAPISense()) + appendItem(StopItem); + else + appendItem(ReloadItem); +#endif +#if ENABLE(INSPECTOR) + } +#endif + + if (frame->page() && frame != frame->page()->mainFrame()) + appendItem(OpenFrameItem); + } + } + } else { // Make an editing context menu + SelectionController* selection = frame->selection(); + bool inPasswordField = selection->isInPasswordField(); + bool spellCheckingEnabled = frame->editor()->spellCheckingEnabledInFocusedNode(); + + if (!inPasswordField && spellCheckingEnabled) { + // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range + // is never considered a misspelling and bad grammar at the same time) + bool misspelling; + bool badGrammar; + Vector guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar); + if (misspelling || badGrammar) { + size_t size = guesses.size(); + if (size == 0) { + // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions + // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit) + if (misspelling) { + appendItem(NoGuessesItem); + appendItem(*separatorItem()); + } + } else { + for (unsigned i = 0; i < size; i++) { + const String &guess = guesses[i]; + if (!guess.isEmpty()) { + ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess); + appendItem(item); + } + } + appendItem(*separatorItem()); + } + + if (misspelling) { + appendItem(IgnoreSpellingItem); + appendItem(LearnSpellingItem); + } else + appendItem(IgnoreGrammarItem); + appendItem(*separatorItem()); +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + } else { + // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. + String replacedString = result.replacedString(); + if (!replacedString.isEmpty()) { + ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString)); + appendItem(item); + appendItem(*separatorItem()); + } +#endif + } + } + + FrameLoader* loader = frame->loader(); + KURL linkURL = result.absoluteLinkURL(); + if (!linkURL.isEmpty()) { + if (loader->canHandleRequest(ResourceRequest(linkURL))) { + appendItem(OpenLinkItem); + appendItem(OpenLinkInNewWindowItem); + appendItem(DownloadFileItem); + } + appendItem(CopyLinkItem); + appendItem(*separatorItem()); + } + + if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) { +#if PLATFORM(MAC) + appendItem(SearchSpotlightItem); +#endif +#if !PLATFORM(GTK) + appendItem(SearchWebItem); + appendItem(*separatorItem()); +#endif + +#if PLATFORM(MAC) + appendItem(LookInDictionaryItem); + appendItem(*separatorItem()); +#endif + } + + appendItem(CutItem); + appendItem(CopyItem); + appendItem(PasteItem); +#if PLATFORM(GTK) + appendItem(DeleteItem); + appendItem(*separatorItem()); + appendItem(SelectAllItem); +#endif + + if (!inPasswordField) { + appendItem(*separatorItem()); +#ifndef BUILDING_ON_TIGER +#if !PLATFORM(GTK) + ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, + contextMenuItemTagSpellingMenu()); + createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem); + appendItem(SpellingAndGrammarMenuItem); +#endif +#else + ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, + contextMenuItemTagSpellingMenu()); + createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem); + appendItem(SpellingMenuItem); +#endif +#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, + contextMenuItemTagSubstitutionsMenu()); + createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem); + appendItem(substitutionsMenuItem); + ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, + contextMenuItemTagTransformationsMenu()); + createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem); + appendItem(transformationsMenuItem); +#endif +#if PLATFORM(GTK) + bool shouldShowFontMenu = frame->editor()->canEditRichly(); +#else + bool shouldShowFontMenu = true; +#endif + if (shouldShowFontMenu) { + ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, + contextMenuItemTagFontMenu()); + createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem); + appendItem(FontMenuItem); + } +#if PLATFORM(MAC) + ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); + createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); + appendItem(SpeechMenuItem); +#endif +#if !PLATFORM(GTK) + ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, + contextMenuItemTagWritingDirectionMenu()); + createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem); + appendItem(WritingDirectionMenuItem); + if (Page* page = frame->page()) { + if (Settings* settings = page->settings()) { + bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded + || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection()); + if (includeTextDirectionSubmenu) { + ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, + contextMenuItemTagTextDirectionMenu()); + createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem); + appendItem(TextDirectionMenuItem); + } + } + } +#endif + } + } +} + +#if ENABLE(INSPECTOR) +void ContextMenu::addInspectElementItem() +{ + Node* node = m_hitTestResult.innerNonSharedNode(); + if (!node) + return; + + Frame* frame = node->document()->frame(); + if (!frame) + return; + + Page* page = frame->page(); + if (!page) + return; + + if (!page->inspectorController()) + return; + + ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement()); + appendItem(*separatorItem()); + appendItem(InspectElementItem); +} +#endif // ENABLE(INSPECTOR) + +void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const +{ + if (item.type() == SeparatorType) + return; + + Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame(); + if (!frame) + return; + + bool shouldEnable = true; + bool shouldCheck = false; + + switch (item.action()) { + case ContextMenuItemTagCheckSpelling: + shouldEnable = frame->editor()->canEdit(); + break; + case ContextMenuItemTagDefaultDirection: + shouldCheck = false; + shouldEnable = false; + break; + case ContextMenuItemTagLeftToRight: + case ContextMenuItemTagRightToLeft: { + ExceptionCode ec = 0; + RefPtr style = frame->document()->createCSSStyleDeclaration(); + String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl"; + style->setProperty(CSSPropertyDirection, direction, false, ec); + shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; + shouldEnable = true; + break; + } + case ContextMenuItemTagTextDirectionDefault: { + Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural"); + shouldCheck = command.state() == TrueTriState; + shouldEnable = command.isEnabled(); + break; + } + case ContextMenuItemTagTextDirectionLeftToRight: { + Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight"); + shouldCheck = command.state() == TrueTriState; + shouldEnable = command.isEnabled(); + break; + } + case ContextMenuItemTagTextDirectionRightToLeft: { + Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft"); + shouldCheck = command.state() == TrueTriState; + shouldEnable = command.isEnabled(); + break; + } + case ContextMenuItemTagCopy: + shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); + break; + case ContextMenuItemTagCut: + shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut(); + break; + case ContextMenuItemTagIgnoreSpelling: + case ContextMenuItemTagLearnSpelling: + shouldEnable = frame->selection()->isRange(); + break; + case ContextMenuItemTagPaste: + shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste(); + break; +#if PLATFORM(GTK) + case ContextMenuItemTagDelete: + shouldEnable = frame->editor()->canDelete(); + break; + case ContextMenuItemTagSelectAll: + case ContextMenuItemTagInputMethods: + case ContextMenuItemTagUnicode: + shouldEnable = true; + break; +#endif + case ContextMenuItemTagUnderline: { + ExceptionCode ec = 0; + RefPtr style = frame->document()->createCSSStyleDeclaration(); + style->setProperty(CSSPropertyWebkitTextDecorationsInEffect, "underline", false, ec); + shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; + shouldEnable = frame->editor()->canEditRichly(); + break; + } + case ContextMenuItemTagLookUpInDictionary: + shouldEnable = frame->selection()->isRange(); + break; + case ContextMenuItemTagCheckGrammarWithSpelling: +#ifndef BUILDING_ON_TIGER + if (frame->editor()->isGrammarCheckingEnabled()) + shouldCheck = true; + shouldEnable = true; +#endif + break; + case ContextMenuItemTagItalic: { + ExceptionCode ec = 0; + RefPtr style = frame->document()->createCSSStyleDeclaration(); + style->setProperty(CSSPropertyFontStyle, "italic", false, ec); + shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; + shouldEnable = frame->editor()->canEditRichly(); + break; + } + case ContextMenuItemTagBold: { + ExceptionCode ec = 0; + RefPtr style = frame->document()->createCSSStyleDeclaration(); + style->setProperty(CSSPropertyFontWeight, "bold", false, ec); + shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; + shouldEnable = frame->editor()->canEditRichly(); + break; + } + case ContextMenuItemTagOutline: + shouldEnable = false; + break; + case ContextMenuItemTagShowSpellingPanel: +#ifndef BUILDING_ON_TIGER + if (frame->editor()->spellingPanelIsShowing()) + item.setTitle(contextMenuItemTagShowSpellingPanel(false)); + else + item.setTitle(contextMenuItemTagShowSpellingPanel(true)); +#endif + shouldEnable = frame->editor()->canEdit(); + break; + case ContextMenuItemTagNoGuessesFound: + shouldEnable = false; + break; + case ContextMenuItemTagCheckSpellingWhileTyping: + shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled(); + break; +#if PLATFORM(MAC) + case ContextMenuItemTagSubstitutionsMenu: + case ContextMenuItemTagTransformationsMenu: + break; + case ContextMenuItemTagShowSubstitutions: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + if (frame->editor()->substitutionsPanelIsShowing()) + item.setTitle(contextMenuItemTagShowSubstitutions(false)); + else + item.setTitle(contextMenuItemTagShowSubstitutions(true)); + shouldEnable = frame->editor()->canEdit(); +#endif + break; + case ContextMenuItemTagMakeUpperCase: + case ContextMenuItemTagMakeLowerCase: + case ContextMenuItemTagCapitalize: + case ContextMenuItemTagChangeBack: + shouldEnable = frame->editor()->canEdit(); + break; + case ContextMenuItemTagCorrectSpellingAutomatically: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled(); +#endif + break; + case ContextMenuItemTagSmartCopyPaste: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->smartInsertDeleteEnabled(); +#endif + break; + case ContextMenuItemTagSmartQuotes: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled(); +#endif + break; + case ContextMenuItemTagSmartDashes: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled(); +#endif + break; + case ContextMenuItemTagSmartLinks: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled(); +#endif + break; + case ContextMenuItemTagTextReplacement: +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) + shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled(); +#endif + break; + case ContextMenuItemTagStopSpeaking: + shouldEnable = controller() && controller()->client() && controller()->client()->isSpeaking(); + break; +#else // PLATFORM(MAC) ends here + case ContextMenuItemTagStopSpeaking: + break; +#endif +#if PLATFORM(GTK) + case ContextMenuItemTagGoBack: + shouldEnable = frame->page() && frame->page()->canGoBackOrForward(-1); + break; + case ContextMenuItemTagGoForward: + shouldEnable = frame->page() && frame->page()->canGoBackOrForward(1); + break; + case ContextMenuItemTagStop: + shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense(); + break; + case ContextMenuItemTagReload: + shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense(); + break; + case ContextMenuItemTagFontMenu: + shouldEnable = frame->editor()->canEditRichly(); + break; +#else + case ContextMenuItemTagGoBack: + case ContextMenuItemTagGoForward: + case ContextMenuItemTagStop: + case ContextMenuItemTagReload: + case ContextMenuItemTagFontMenu: +#endif + case ContextMenuItemTagNoAction: + case ContextMenuItemTagOpenLinkInNewWindow: + case ContextMenuItemTagDownloadLinkToDisk: + case ContextMenuItemTagCopyLinkToClipboard: + case ContextMenuItemTagOpenImageInNewWindow: + case ContextMenuItemTagDownloadImageToDisk: + case ContextMenuItemTagCopyImageToClipboard: + case ContextMenuItemTagOpenFrameInNewWindow: + case ContextMenuItemTagSpellingGuess: + case ContextMenuItemTagOther: + case ContextMenuItemTagSearchInSpotlight: + case ContextMenuItemTagSearchWeb: + case ContextMenuItemTagOpenWithDefaultApplication: + case ContextMenuItemPDFActualSize: + case ContextMenuItemPDFZoomIn: + case ContextMenuItemPDFZoomOut: + case ContextMenuItemPDFAutoSize: + case ContextMenuItemPDFSinglePage: + case ContextMenuItemPDFFacingPages: + case ContextMenuItemPDFContinuous: + case ContextMenuItemPDFNextPage: + case ContextMenuItemPDFPreviousPage: + case ContextMenuItemTagOpenLink: + case ContextMenuItemTagIgnoreGrammar: + case ContextMenuItemTagSpellingMenu: + case ContextMenuItemTagShowFonts: + case ContextMenuItemTagStyles: + case ContextMenuItemTagShowColors: + case ContextMenuItemTagSpeechMenu: + case ContextMenuItemTagStartSpeaking: + case ContextMenuItemTagWritingDirectionMenu: + case ContextMenuItemTagTextDirectionMenu: + case ContextMenuItemTagPDFSinglePageScrolling: + case ContextMenuItemTagPDFFacingPagesScrolling: +#if ENABLE(INSPECTOR) + case ContextMenuItemTagInspectElement: +#endif + case ContextMenuItemBaseCustomTag: + case ContextMenuItemBaseApplicationTag: + break; + } + + item.setChecked(shouldCheck); + item.setEnabled(shouldEnable); +} + +} // namespace WebCore + +#endif // ENABLE(CONTEXT_MENUS)