• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "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 
controller() const60 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 
separatorItem()69 static auto_ptr<ContextMenuItem> separatorItem()
70 {
71     return auto_ptr<ContextMenuItem>(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()));
72 }
73 
createAndAppendFontSubMenu(const HitTestResult & result,ContextMenuItem & fontMenuItem)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
createAndAppendSpellingAndGrammarSubMenu(const HitTestResult & result,ContextMenuItem & spellingAndGrammarMenuItem)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 
createAndAppendSpellingSubMenu(const HitTestResult & result,ContextMenuItem & spellingMenuItem)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)
createAndAppendSpeechSubMenu(const HitTestResult & result,ContextMenuItem & speechMenuItem)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)
createAndAppendWritingDirectionSubMenu(const HitTestResult & result,ContextMenuItem & writingDirectionMenuItem)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 
createAndAppendTextDirectionSubMenu(const HitTestResult & result,ContextMenuItem & textDirectionMenuItem)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)
createAndAppendSubstitutionsSubMenu(const HitTestResult & result,ContextMenuItem & substitutionsMenuItem)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 
createAndAppendTransformationsSubMenu(const HitTestResult & result,ContextMenuItem & transformationsMenuItem)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 
selectionContainsPossibleWord(Frame * frame)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 
populate()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)
addInspectElementItem()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 
checkOrEnableIfNeeded(ContextMenuItem & item) const559 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