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