1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Igalia S.L
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 "ContextMenuController.h"
29 
30 #if ENABLE(CONTEXT_MENUS)
31 
32 #include "BackForwardController.h"
33 #include "Chrome.h"
34 #include "ContextMenu.h"
35 #include "ContextMenuClient.h"
36 #include "ContextMenuItem.h"
37 #include "ContextMenuProvider.h"
38 #include "Document.h"
39 #include "DocumentFragment.h"
40 #include "DocumentLoader.h"
41 #include "Editor.h"
42 #include "EditorClient.h"
43 #include "Event.h"
44 #include "EventHandler.h"
45 #include "EventNames.h"
46 #include "FormState.h"
47 #include "Frame.h"
48 #include "FrameLoadRequest.h"
49 #include "FrameLoader.h"
50 #include "HTMLFormElement.h"
51 #include "HitTestRequest.h"
52 #include "HitTestResult.h"
53 #include "InspectorController.h"
54 #include "LocalizedStrings.h"
55 #include "MouseEvent.h"
56 #include "NavigationAction.h"
57 #include "Node.h"
58 #include "Page.h"
59 #include "RenderLayer.h"
60 #include "RenderObject.h"
61 #include "ReplaceSelectionCommand.h"
62 #include "ResourceRequest.h"
63 #include "SelectionController.h"
64 #include "Settings.h"
65 #include "TextIterator.h"
66 #include "UserTypingGestureIndicator.h"
67 #include "WindowFeatures.h"
68 #include "markup.h"
69 #include <wtf/unicode/Unicode.h>
70 
71 using namespace WTF;
72 using namespace Unicode;
73 
74 namespace WebCore {
75 
ContextMenuController(Page * page,ContextMenuClient * client)76 ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client)
77     : m_page(page)
78     , m_client(client)
79 {
80     ASSERT_ARG(page, page);
81     ASSERT_ARG(client, client);
82 }
83 
~ContextMenuController()84 ContextMenuController::~ContextMenuController()
85 {
86     m_client->contextMenuDestroyed();
87 }
88 
clearContextMenu()89 void ContextMenuController::clearContextMenu()
90 {
91     m_contextMenu.clear();
92     if (m_menuProvider)
93         m_menuProvider->contextMenuCleared();
94     m_menuProvider = 0;
95 }
96 
handleContextMenuEvent(Event * event)97 void ContextMenuController::handleContextMenuEvent(Event* event)
98 {
99     m_contextMenu = createContextMenu(event);
100     if (!m_contextMenu)
101         return;
102 
103     populate();
104 
105     showContextMenu(event);
106 }
107 
showContextMenu(Event * event,PassRefPtr<ContextMenuProvider> menuProvider)108 void ContextMenuController::showContextMenu(Event* event, PassRefPtr<ContextMenuProvider> menuProvider)
109 {
110     m_menuProvider = menuProvider;
111 
112     m_contextMenu = createContextMenu(event);
113     if (!m_contextMenu) {
114         clearContextMenu();
115         return;
116     }
117 
118     m_menuProvider->populateContextMenu(m_contextMenu.get());
119     showContextMenu(event);
120 }
121 
createContextMenu(Event * event)122 PassOwnPtr<ContextMenu> ContextMenuController::createContextMenu(Event* event)
123 {
124     if (!event->isMouseEvent())
125         return nullptr;
126 
127     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
128     HitTestResult result(mouseEvent->absoluteLocation());
129 
130     if (Frame* frame = event->target()->toNode()->document()->frame())
131         result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false);
132 
133     if (!result.innerNonSharedNode())
134         return nullptr;
135 
136     m_hitTestResult = result;
137 
138     return adoptPtr(new ContextMenu);
139 }
140 
showContextMenu(Event * event)141 void ContextMenuController::showContextMenu(Event* event)
142 {
143 #if ENABLE(INSPECTOR)
144     if (m_page->inspectorController()->enabled())
145         addInspectElementItem();
146 #endif
147 
148 #if USE(CROSS_PLATFORM_CONTEXT_MENUS)
149     m_contextMenu = m_client->customizeMenu(m_contextMenu.release());
150 #else
151     PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get());
152     m_contextMenu->setPlatformDescription(customMenu);
153 #endif
154     event->setDefaultHandled();
155 }
156 
openNewWindow(const KURL & urlToLoad,Frame * frame)157 static void openNewWindow(const KURL& urlToLoad, Frame* frame)
158 {
159     if (Page* oldPage = frame->page()) {
160         FrameLoadRequest request(frame->document()->securityOrigin(), ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer()));
161         if (Page* newPage = oldPage->chrome()->createWindow(frame, request, WindowFeatures(), NavigationAction())) {
162             newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, SendReferrer);
163             newPage->chrome()->show();
164         }
165     }
166 }
167 
contextMenuItemSelected(ContextMenuItem * item)168 void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item)
169 {
170     ASSERT(item->type() == ActionType || item->type() == CheckableActionType);
171 
172     if (item->action() >= ContextMenuItemBaseApplicationTag) {
173         m_client->contextMenuItemSelected(item, m_contextMenu.get());
174         return;
175     }
176 
177     if (item->action() >= ContextMenuItemBaseCustomTag) {
178         ASSERT(m_menuProvider);
179         m_menuProvider->contextMenuItemSelected(item);
180         return;
181     }
182 
183     Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
184     if (!frame)
185         return;
186 
187     switch (item->action()) {
188     case ContextMenuItemTagOpenLinkInNewWindow:
189         openNewWindow(m_hitTestResult.absoluteLinkURL(), frame);
190         break;
191     case ContextMenuItemTagDownloadLinkToDisk:
192         // FIXME: Some day we should be able to do this from within WebCore.
193         m_client->downloadURL(m_hitTestResult.absoluteLinkURL());
194         break;
195     case ContextMenuItemTagCopyLinkToClipboard:
196         frame->editor()->copyURL(m_hitTestResult.absoluteLinkURL(), m_hitTestResult.textContent());
197         break;
198     case ContextMenuItemTagOpenImageInNewWindow:
199         openNewWindow(m_hitTestResult.absoluteImageURL(), frame);
200         break;
201     case ContextMenuItemTagDownloadImageToDisk:
202         // FIXME: Some day we should be able to do this from within WebCore.
203         m_client->downloadURL(m_hitTestResult.absoluteImageURL());
204         break;
205     case ContextMenuItemTagCopyImageToClipboard:
206         // FIXME: The Pasteboard class is not written yet
207         // For now, call into the client. This is temporary!
208         frame->editor()->copyImage(m_hitTestResult);
209         break;
210 #if PLATFORM(QT) || PLATFORM(GTK)
211     case ContextMenuItemTagCopyImageUrlToClipboard:
212         frame->editor()->copyURL(m_hitTestResult.absoluteImageURL(), m_hitTestResult.textContent());
213         break;
214 #endif
215     case ContextMenuItemTagOpenMediaInNewWindow:
216         openNewWindow(m_hitTestResult.absoluteMediaURL(), frame);
217         break;
218     case ContextMenuItemTagCopyMediaLinkToClipboard:
219         frame->editor()->copyURL(m_hitTestResult.absoluteMediaURL(), m_hitTestResult.textContent());
220         break;
221     case ContextMenuItemTagToggleMediaControls:
222         m_hitTestResult.toggleMediaControlsDisplay();
223         break;
224     case ContextMenuItemTagToggleMediaLoop:
225         m_hitTestResult.toggleMediaLoopPlayback();
226         break;
227     case ContextMenuItemTagEnterVideoFullscreen:
228         m_hitTestResult.enterFullscreenForVideo();
229         break;
230     case ContextMenuItemTagMediaPlayPause:
231         m_hitTestResult.toggleMediaPlayState();
232         break;
233     case ContextMenuItemTagMediaMute:
234         m_hitTestResult.toggleMediaMuteState();
235         break;
236     case ContextMenuItemTagOpenFrameInNewWindow: {
237         DocumentLoader* loader = frame->loader()->documentLoader();
238         if (!loader->unreachableURL().isEmpty())
239             openNewWindow(loader->unreachableURL(), frame);
240         else
241             openNewWindow(loader->url(), frame);
242         break;
243     }
244     case ContextMenuItemTagCopy:
245         frame->editor()->copy();
246         break;
247     case ContextMenuItemTagGoBack:
248         if (Page* page = frame->page())
249             page->backForward()->goBackOrForward(-1);
250         break;
251     case ContextMenuItemTagGoForward:
252         if (Page* page = frame->page())
253             page->backForward()->goBackOrForward(1);
254         break;
255     case ContextMenuItemTagStop:
256         frame->loader()->stop();
257         break;
258     case ContextMenuItemTagReload:
259         frame->loader()->reload();
260         break;
261     case ContextMenuItemTagCut:
262         frame->editor()->command("Cut").execute();
263         break;
264     case ContextMenuItemTagPaste:
265         frame->editor()->command("Paste").execute();
266         break;
267 #if PLATFORM(GTK)
268     case ContextMenuItemTagDelete:
269         frame->editor()->performDelete();
270         break;
271 #endif
272 #if PLATFORM(GTK) || PLATFORM(QT)
273     case ContextMenuItemTagSelectAll:
274         frame->editor()->command("SelectAll").execute();
275         break;
276 #endif
277     case ContextMenuItemTagSpellingGuess:
278         ASSERT(frame->editor()->selectedText().length());
279         if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) {
280             Document* document = frame->document();
281             RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting);
282             applyCommand(command);
283             frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
284         }
285         break;
286     case ContextMenuItemTagIgnoreSpelling:
287         frame->editor()->ignoreSpelling();
288         break;
289     case ContextMenuItemTagLearnSpelling:
290         frame->editor()->learnSpelling();
291         break;
292     case ContextMenuItemTagSearchWeb:
293         m_client->searchWithGoogle(frame);
294         break;
295     case ContextMenuItemTagLookUpInDictionary:
296         // FIXME: Some day we may be able to do this from within WebCore.
297         m_client->lookUpInDictionary(frame);
298         break;
299     case ContextMenuItemTagOpenLink:
300         if (Frame* targetFrame = m_hitTestResult.targetFrame())
301             targetFrame->loader()->loadFrameRequest(FrameLoadRequest(frame->document()->securityOrigin(), ResourceRequest(m_hitTestResult.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, SendReferrer);
302         else
303             openNewWindow(m_hitTestResult.absoluteLinkURL(), frame);
304         break;
305     case ContextMenuItemTagBold:
306         frame->editor()->command("ToggleBold").execute();
307         break;
308     case ContextMenuItemTagItalic:
309         frame->editor()->command("ToggleItalic").execute();
310         break;
311     case ContextMenuItemTagUnderline:
312         frame->editor()->toggleUnderline();
313         break;
314     case ContextMenuItemTagOutline:
315         // We actually never enable this because CSS does not have a way to specify an outline font,
316         // which may make this difficult to implement. Maybe a special case of text-shadow?
317         break;
318     case ContextMenuItemTagStartSpeaking: {
319         ExceptionCode ec;
320         RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
321         if (!selectedRange || selectedRange->collapsed(ec)) {
322             Document* document = m_hitTestResult.innerNonSharedNode()->document();
323             selectedRange = document->createRange();
324             selectedRange->selectNode(document->documentElement(), ec);
325         }
326         m_client->speak(plainText(selectedRange.get()));
327         break;
328     }
329     case ContextMenuItemTagStopSpeaking:
330         m_client->stopSpeaking();
331         break;
332     case ContextMenuItemTagDefaultDirection:
333         frame->editor()->setBaseWritingDirection(NaturalWritingDirection);
334         break;
335     case ContextMenuItemTagLeftToRight:
336         frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
337         break;
338     case ContextMenuItemTagRightToLeft:
339         frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
340         break;
341     case ContextMenuItemTagTextDirectionDefault:
342         frame->editor()->command("MakeTextWritingDirectionNatural").execute();
343         break;
344     case ContextMenuItemTagTextDirectionLeftToRight:
345         frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute();
346         break;
347     case ContextMenuItemTagTextDirectionRightToLeft:
348         frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute();
349         break;
350 #if PLATFORM(MAC)
351     case ContextMenuItemTagSearchInSpotlight:
352         m_client->searchWithSpotlight();
353         break;
354 #endif
355     case ContextMenuItemTagShowSpellingPanel:
356         frame->editor()->showSpellingGuessPanel();
357         break;
358     case ContextMenuItemTagCheckSpelling:
359         frame->editor()->advanceToNextMisspelling();
360         break;
361     case ContextMenuItemTagCheckSpellingWhileTyping:
362         frame->editor()->toggleContinuousSpellChecking();
363         break;
364     case ContextMenuItemTagCheckGrammarWithSpelling:
365         frame->editor()->toggleGrammarChecking();
366         break;
367 #if PLATFORM(MAC)
368     case ContextMenuItemTagShowFonts:
369         frame->editor()->showFontPanel();
370         break;
371     case ContextMenuItemTagStyles:
372         frame->editor()->showStylesPanel();
373         break;
374     case ContextMenuItemTagShowColors:
375         frame->editor()->showColorPanel();
376         break;
377 #endif
378 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
379     case ContextMenuItemTagMakeUpperCase:
380         frame->editor()->uppercaseWord();
381         break;
382     case ContextMenuItemTagMakeLowerCase:
383         frame->editor()->lowercaseWord();
384         break;
385     case ContextMenuItemTagCapitalize:
386         frame->editor()->capitalizeWord();
387         break;
388     case ContextMenuItemTagShowSubstitutions:
389         frame->editor()->showSubstitutionsPanel();
390         break;
391     case ContextMenuItemTagSmartCopyPaste:
392         frame->editor()->toggleSmartInsertDelete();
393         break;
394     case ContextMenuItemTagSmartQuotes:
395         frame->editor()->toggleAutomaticQuoteSubstitution();
396         break;
397     case ContextMenuItemTagSmartDashes:
398         frame->editor()->toggleAutomaticDashSubstitution();
399         break;
400     case ContextMenuItemTagSmartLinks:
401         frame->editor()->toggleAutomaticLinkDetection();
402         break;
403     case ContextMenuItemTagTextReplacement:
404         frame->editor()->toggleAutomaticTextReplacement();
405         break;
406     case ContextMenuItemTagCorrectSpellingAutomatically:
407         frame->editor()->toggleAutomaticSpellingCorrection();
408         break;
409     case ContextMenuItemTagChangeBack:
410         frame->editor()->changeBackToReplacedString(m_hitTestResult.replacedString());
411         break;
412 #endif
413 #if ENABLE(INSPECTOR)
414     case ContextMenuItemTagInspectElement:
415         if (Page* page = frame->page())
416             page->inspectorController()->inspect(m_hitTestResult.innerNonSharedNode());
417         break;
418 #endif
419     default:
420         break;
421     }
422 }
423 
appendItem(ContextMenuItem & menuItem,ContextMenu * parentMenu)424 void ContextMenuController::appendItem(ContextMenuItem& menuItem, ContextMenu* parentMenu)
425 {
426     checkOrEnableIfNeeded(menuItem);
427     if (parentMenu)
428         parentMenu->appendItem(menuItem);
429 }
430 
separatorItem()431 static PassOwnPtr<ContextMenuItem> separatorItem()
432 {
433     return adoptPtr(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()));
434 }
435 
createAndAppendFontSubMenu(ContextMenuItem & fontMenuItem)436 void ContextMenuController::createAndAppendFontSubMenu(ContextMenuItem& fontMenuItem)
437 {
438     ContextMenu fontMenu;
439 
440 #if PLATFORM(MAC)
441     ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts());
442 #endif
443     ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold());
444     ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic());
445     ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline());
446     ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline());
447 #if PLATFORM(MAC)
448     ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles());
449     ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors());
450 #endif
451 
452 #if PLATFORM(MAC)
453     appendItem(showFonts, &fontMenu);
454 #endif
455     appendItem(bold, &fontMenu);
456     appendItem(italic, &fontMenu);
457     appendItem(underline, &fontMenu);
458     appendItem(outline, &fontMenu);
459 #if PLATFORM(MAC)
460     appendItem(styles, &fontMenu);
461     appendItem(*separatorItem(), &fontMenu);
462     appendItem(showColors, &fontMenu);
463 #endif
464 
465     fontMenuItem.setSubMenu(&fontMenu);
466 }
467 
468 
469 #if !PLATFORM(GTK)
470 
createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem & spellingAndGrammarMenuItem)471 void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem)
472 {
473     ContextMenu spellingAndGrammarMenu;
474 
475     ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
476         contextMenuItemTagShowSpellingPanel(true));
477     ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
478         contextMenuItemTagCheckSpelling());
479     ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
480         contextMenuItemTagCheckSpellingWhileTyping());
481     ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling,
482         contextMenuItemTagCheckGrammarWithSpelling());
483 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
484     ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically,
485         contextMenuItemTagCorrectSpellingAutomatically());
486 #endif
487 
488     appendItem(showSpellingPanel, &spellingAndGrammarMenu);
489     appendItem(checkSpelling, &spellingAndGrammarMenu);
490 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
491     appendItem(*separatorItem(), &spellingAndGrammarMenu);
492 #endif
493     appendItem(checkAsYouType, &spellingAndGrammarMenu);
494     appendItem(grammarWithSpelling, &spellingAndGrammarMenu);
495 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
496     appendItem(correctSpelling, &spellingAndGrammarMenu);
497 #endif
498 
499     spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu);
500 }
501 
502 #endif // !PLATFORM(GTK)
503 
504 
505 #if PLATFORM(MAC)
506 
createAndAppendSpeechSubMenu(ContextMenuItem & speechMenuItem)507 void ContextMenuController::createAndAppendSpeechSubMenu(ContextMenuItem& speechMenuItem)
508 {
509     ContextMenu speechMenu;
510 
511     ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking());
512     ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking());
513 
514     appendItem(start, &speechMenu);
515     appendItem(stop, &speechMenu);
516 
517     speechMenuItem.setSubMenu(&speechMenu);
518 }
519 
520 #endif
521 
522 #if !PLATFORM(GTK)
523 
createAndAppendWritingDirectionSubMenu(ContextMenuItem & writingDirectionMenuItem)524 void ContextMenuController::createAndAppendWritingDirectionSubMenu(ContextMenuItem& writingDirectionMenuItem)
525 {
526     ContextMenu writingDirectionMenu;
527 
528     ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection,
529         contextMenuItemTagDefaultDirection());
530     ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight());
531     ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft());
532 
533     appendItem(defaultItem, &writingDirectionMenu);
534     appendItem(ltr, &writingDirectionMenu);
535     appendItem(rtl, &writingDirectionMenu);
536 
537     writingDirectionMenuItem.setSubMenu(&writingDirectionMenu);
538 }
539 
createAndAppendTextDirectionSubMenu(ContextMenuItem & textDirectionMenuItem)540 void ContextMenuController::createAndAppendTextDirectionSubMenu(ContextMenuItem& textDirectionMenuItem)
541 {
542     ContextMenu textDirectionMenu;
543 
544     ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection());
545     ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight());
546     ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft());
547 
548     appendItem(defaultItem, &textDirectionMenu);
549     appendItem(ltr, &textDirectionMenu);
550     appendItem(rtl, &textDirectionMenu);
551 
552     textDirectionMenuItem.setSubMenu(&textDirectionMenu);
553 }
554 
555 #endif
556 
557 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
558 
createAndAppendSubstitutionsSubMenu(ContextMenuItem & substitutionsMenuItem)559 void ContextMenuController::createAndAppendSubstitutionsSubMenu(ContextMenuItem& substitutionsMenuItem)
560 {
561     ContextMenu substitutionsMenu;
562 
563     ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true));
564     ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste());
565     ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes());
566     ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes());
567     ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks());
568     ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement());
569 
570     appendItem(showSubstitutions, &substitutionsMenu);
571     appendItem(*separatorItem(), &substitutionsMenu);
572     appendItem(smartCopyPaste, &substitutionsMenu);
573     appendItem(smartQuotes, &substitutionsMenu);
574     appendItem(smartDashes, &substitutionsMenu);
575     appendItem(smartLinks, &substitutionsMenu);
576     appendItem(textReplacement, &substitutionsMenu);
577 
578     substitutionsMenuItem.setSubMenu(&substitutionsMenu);
579 }
580 
createAndAppendTransformationsSubMenu(ContextMenuItem & transformationsMenuItem)581 void ContextMenuController::createAndAppendTransformationsSubMenu(ContextMenuItem& transformationsMenuItem)
582 {
583     ContextMenu transformationsMenu;
584 
585     ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase());
586     ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase());
587     ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize());
588 
589     appendItem(makeUpperCase, &transformationsMenu);
590     appendItem(makeLowerCase, &transformationsMenu);
591     appendItem(capitalize, &transformationsMenu);
592 
593     transformationsMenuItem.setSubMenu(&transformationsMenu);
594 }
595 
596 #endif
597 
selectionContainsPossibleWord(Frame * frame)598 static bool selectionContainsPossibleWord(Frame* frame)
599 {
600     // Current algorithm: look for a character that's not just a separator.
601     for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) {
602         int length = it.length();
603         const UChar* characters = it.characters();
604         for (int i = 0; i < length; ++i)
605             if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph)))
606                 return true;
607     }
608     return false;
609 }
610 
611 #if PLATFORM(MAC)
612 #if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD)
613 #define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 1
614 #else
615 #define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 0
616 #endif
617 #endif
618 
populate()619 void ContextMenuController::populate()
620 {
621     ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink());
622     ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow,
623         contextMenuItemTagOpenLinkInNewWindow());
624     ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk,
625         contextMenuItemTagDownloadLinkToDisk());
626     ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard,
627         contextMenuItemTagCopyLinkToClipboard());
628     ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow,
629         contextMenuItemTagOpenImageInNewWindow());
630     ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk,
631         contextMenuItemTagDownloadImageToDisk());
632     ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard,
633         contextMenuItemTagCopyImageToClipboard());
634 #if PLATFORM(QT) || PLATFORM(GTK)
635     ContextMenuItem CopyImageUrlItem(ActionType, ContextMenuItemTagCopyImageUrlToClipboard,
636         contextMenuItemTagCopyImageUrlToClipboard());
637 #endif
638     ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String());
639     ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard,
640         String());
641     ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause,
642         contextMenuItemTagMediaPlay());
643     ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute,
644         contextMenuItemTagMediaMute());
645     ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls,
646         contextMenuItemTagToggleMediaControls());
647     ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop,
648         contextMenuItemTagToggleMediaLoop());
649     ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen,
650         contextMenuItemTagEnterVideoFullscreen());
651 #if PLATFORM(MAC)
652     ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight,
653         contextMenuItemTagSearchInSpotlight());
654 #endif
655 #if !PLATFORM(GTK)
656     ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb());
657 #endif
658     ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy());
659     ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack());
660     ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward,  contextMenuItemTagGoForward());
661     ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop());
662     ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload());
663     ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow,
664         contextMenuItemTagOpenFrameInNewWindow());
665     ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound,
666         contextMenuItemTagNoGuessesFound());
667     ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling,
668         contextMenuItemTagIgnoreSpelling());
669     ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling,
670         contextMenuItemTagLearnSpelling());
671     ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar,
672         contextMenuItemTagIgnoreGrammar());
673     ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut());
674     ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
675 #if PLATFORM(GTK)
676     ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
677 #endif
678 #if PLATFORM(GTK) || PLATFORM(QT)
679     ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
680 #endif
681 
682     Node* node = m_hitTestResult.innerNonSharedNode();
683     if (!node)
684         return;
685 #if PLATFORM(GTK)
686     if (!m_hitTestResult.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
687         return;
688 #endif
689     Frame* frame = node->document()->frame();
690     if (!frame)
691         return;
692 
693     if (!m_hitTestResult.isContentEditable()) {
694         FrameLoader* loader = frame->loader();
695         KURL linkURL = m_hitTestResult.absoluteLinkURL();
696         if (!linkURL.isEmpty()) {
697             if (loader->canHandleRequest(ResourceRequest(linkURL))) {
698                 appendItem(OpenLinkItem, m_contextMenu.get());
699                 appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
700                 appendItem(DownloadFileItem, m_contextMenu.get());
701             }
702 #if PLATFORM(QT)
703             if (m_hitTestResult.isSelected())
704                 appendItem(CopyItem, m_contextMenu.get());
705 #endif
706             appendItem(CopyLinkItem, m_contextMenu.get());
707         }
708 
709         KURL imageURL = m_hitTestResult.absoluteImageURL();
710         if (!imageURL.isEmpty()) {
711             if (!linkURL.isEmpty())
712                 appendItem(*separatorItem(), m_contextMenu.get());
713 
714             appendItem(OpenImageInNewWindowItem, m_contextMenu.get());
715             appendItem(DownloadImageItem, m_contextMenu.get());
716             if (imageURL.isLocalFile() || m_hitTestResult.image())
717                 appendItem(CopyImageItem, m_contextMenu.get());
718 #if PLATFORM(QT) || PLATFORM(GTK)
719             appendItem(CopyImageUrlItem, m_contextMenu.get());
720 #endif
721         }
722 
723         KURL mediaURL = m_hitTestResult.absoluteMediaURL();
724         if (!mediaURL.isEmpty()) {
725             if (!linkURL.isEmpty() || !imageURL.isEmpty())
726                 appendItem(*separatorItem(), m_contextMenu.get());
727 
728             appendItem(MediaPlayPause, m_contextMenu.get());
729             appendItem(MediaMute, m_contextMenu.get());
730             appendItem(ToggleMediaControls, m_contextMenu.get());
731             appendItem(ToggleMediaLoop, m_contextMenu.get());
732             appendItem(EnterVideoFullscreen, m_contextMenu.get());
733 
734             appendItem(*separatorItem(), m_contextMenu.get());
735             appendItem(CopyMediaLinkItem, m_contextMenu.get());
736             appendItem(OpenMediaInNewWindowItem, m_contextMenu.get());
737         }
738 
739         if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) {
740             if (m_hitTestResult.isSelected()) {
741                 if (selectionContainsPossibleWord(frame)) {
742 #if PLATFORM(MAC)
743                     String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText());
744                     ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString));
745 
746 #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
747                     appendItem(SearchSpotlightItem, m_contextMenu.get());
748 #else
749                     appendItem(LookUpInDictionaryItem, m_contextMenu.get());
750 #endif
751 #endif
752 
753 #if !PLATFORM(GTK)
754                     appendItem(SearchWebItem, m_contextMenu.get());
755                     appendItem(*separatorItem(), m_contextMenu.get());
756 #endif
757 
758 #if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
759                     appendItem(LookUpInDictionaryItem, m_contextMenu.get());
760                     appendItem(*separatorItem(), m_contextMenu.get());
761 #endif
762                 }
763 
764                 appendItem(CopyItem, m_contextMenu.get());
765 #if PLATFORM(MAC)
766                 appendItem(*separatorItem(), m_contextMenu.get());
767 
768                 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
769                 createAndAppendSpeechSubMenu(SpeechMenuItem);
770                 appendItem(SpeechMenuItem, m_contextMenu.get());
771 #endif
772             } else {
773 #if ENABLE(INSPECTOR)
774                 if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) {
775 #endif
776 
777                 // In GTK+ unavailable items are not hidden but insensitive
778 #if PLATFORM(GTK)
779                 appendItem(BackItem, m_contextMenu.get());
780                 appendItem(ForwardItem, m_contextMenu.get());
781                 appendItem(StopItem, m_contextMenu.get());
782                 appendItem(ReloadItem, m_contextMenu.get());
783 #else
784                 if (frame->page() && frame->page()->backForward()->canGoBackOrForward(-1))
785                     appendItem(BackItem, m_contextMenu.get());
786 
787                 if (frame->page() && frame->page()->backForward()->canGoBackOrForward(1))
788                     appendItem(ForwardItem, m_contextMenu.get());
789 
790                 // use isLoadingInAPISense rather than isLoading because Stop/Reload are
791                 // intended to match WebKit's API, not WebCore's internal notion of loading status
792                 if (loader->documentLoader()->isLoadingInAPISense())
793                     appendItem(StopItem, m_contextMenu.get());
794                 else
795                     appendItem(ReloadItem, m_contextMenu.get());
796 #endif
797 #if ENABLE(INSPECTOR)
798                 }
799 #endif
800 
801                 if (frame->page() && frame != frame->page()->mainFrame())
802                     appendItem(OpenFrameItem, m_contextMenu.get());
803             }
804         }
805     } else { // Make an editing context menu
806         SelectionController* selection = frame->selection();
807         bool inPasswordField = selection->isInPasswordField();
808         bool spellCheckingEnabled = frame->editor()->isSpellCheckingEnabledFor(node);
809 
810         if (!inPasswordField && spellCheckingEnabled) {
811             // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
812             // is never considered a misspelling and bad grammar at the same time)
813             bool misspelling;
814             bool badGrammar;
815             Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
816             if (misspelling || badGrammar) {
817                 size_t size = guesses.size();
818                 if (size == 0) {
819                     // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
820                     // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit)
821                     if (misspelling) {
822                         appendItem(NoGuessesItem, m_contextMenu.get());
823                         appendItem(*separatorItem(), m_contextMenu.get());
824                     }
825                 } else {
826                     for (unsigned i = 0; i < size; i++) {
827                         const String &guess = guesses[i];
828                         if (!guess.isEmpty()) {
829                             ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
830                             appendItem(item, m_contextMenu.get());
831                         }
832                     }
833                     appendItem(*separatorItem(), m_contextMenu.get());
834                 }
835 
836                 if (misspelling) {
837                     appendItem(IgnoreSpellingItem, m_contextMenu.get());
838                     appendItem(LearnSpellingItem, m_contextMenu.get());
839                 } else
840                     appendItem(IgnoreGrammarItem, m_contextMenu.get());
841                 appendItem(*separatorItem(), m_contextMenu.get());
842 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
843             } else {
844                 // If the string was autocorrected, generate a contextual menu item allowing it to be changed back.
845                 String replacedString = m_hitTestResult.replacedString();
846                 if (!replacedString.isEmpty()) {
847                     ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString));
848                     appendItem(item, m_contextMenu.get());
849                     appendItem(*separatorItem(), m_contextMenu.get());
850                 }
851 #endif
852             }
853         }
854 
855         FrameLoader* loader = frame->loader();
856         KURL linkURL = m_hitTestResult.absoluteLinkURL();
857         if (!linkURL.isEmpty()) {
858             if (loader->canHandleRequest(ResourceRequest(linkURL))) {
859                 appendItem(OpenLinkItem, m_contextMenu.get());
860                 appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
861                 appendItem(DownloadFileItem, m_contextMenu.get());
862             }
863             appendItem(CopyLinkItem, m_contextMenu.get());
864             appendItem(*separatorItem(), m_contextMenu.get());
865         }
866 
867         if (m_hitTestResult.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) {
868 #if PLATFORM(MAC)
869             String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText());
870             ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString));
871 
872 #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
873             appendItem(SearchSpotlightItem, m_contextMenu.get());
874 #else
875             appendItem(LookUpInDictionaryItem, m_contextMenu.get());
876 #endif
877 #endif
878 
879 #if !PLATFORM(GTK)
880             appendItem(SearchWebItem, m_contextMenu.get());
881             appendItem(*separatorItem(), m_contextMenu.get());
882 #endif
883 
884 #if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
885             appendItem(LookUpInDictionaryItem, m_contextMenu.get());
886             appendItem(*separatorItem(), m_contextMenu.get());
887 #endif
888         }
889 
890         appendItem(CutItem, m_contextMenu.get());
891         appendItem(CopyItem, m_contextMenu.get());
892         appendItem(PasteItem, m_contextMenu.get());
893 #if PLATFORM(GTK)
894         appendItem(DeleteItem, m_contextMenu.get());
895         appendItem(*separatorItem(), m_contextMenu.get());
896 #endif
897 #if PLATFORM(GTK) || PLATFORM(QT)
898         appendItem(SelectAllItem, m_contextMenu.get());
899 #endif
900 
901         if (!inPasswordField) {
902 #if !PLATFORM(GTK)
903             appendItem(*separatorItem(), m_contextMenu.get());
904             ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
905                 contextMenuItemTagSpellingMenu());
906             createAndAppendSpellingAndGrammarSubMenu(SpellingAndGrammarMenuItem);
907             appendItem(SpellingAndGrammarMenuItem, m_contextMenu.get());
908 #endif
909 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
910             ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu,
911                 contextMenuItemTagSubstitutionsMenu());
912             createAndAppendSubstitutionsSubMenu(substitutionsMenuItem);
913             appendItem(substitutionsMenuItem, m_contextMenu.get());
914             ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu,
915                 contextMenuItemTagTransformationsMenu());
916             createAndAppendTransformationsSubMenu(transformationsMenuItem);
917             appendItem(transformationsMenuItem, m_contextMenu.get());
918 #endif
919 #if PLATFORM(GTK)
920             bool shouldShowFontMenu = frame->editor()->canEditRichly();
921 #else
922             bool shouldShowFontMenu = true;
923 #endif
924             if (shouldShowFontMenu) {
925                 ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu,
926                     contextMenuItemTagFontMenu());
927                 createAndAppendFontSubMenu(FontMenuItem);
928                 appendItem(FontMenuItem, m_contextMenu.get());
929             }
930 #if PLATFORM(MAC)
931             ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
932             createAndAppendSpeechSubMenu(SpeechMenuItem);
933             appendItem(SpeechMenuItem, m_contextMenu.get());
934 #endif
935 #if !PLATFORM(GTK)
936             ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu,
937                 contextMenuItemTagWritingDirectionMenu());
938             createAndAppendWritingDirectionSubMenu(WritingDirectionMenuItem);
939             appendItem(WritingDirectionMenuItem, m_contextMenu.get());
940             if (Page* page = frame->page()) {
941                 if (Settings* settings = page->settings()) {
942                     bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
943                         || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
944                     if (includeTextDirectionSubmenu) {
945                         ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu,
946                             contextMenuItemTagTextDirectionMenu());
947                         createAndAppendTextDirectionSubMenu(TextDirectionMenuItem);
948                         appendItem(TextDirectionMenuItem, m_contextMenu.get());
949                     }
950                 }
951             }
952 #endif
953         }
954     }
955 }
956 
957 #if ENABLE(INSPECTOR)
addInspectElementItem()958 void ContextMenuController::addInspectElementItem()
959 {
960     Node* node = m_hitTestResult.innerNonSharedNode();
961     if (!node)
962         return;
963 
964     Frame* frame = node->document()->frame();
965     if (!frame)
966         return;
967 
968     Page* page = frame->page();
969     if (!page)
970         return;
971 
972     if (!page->inspectorController())
973         return;
974 
975     ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement());
976     appendItem(*separatorItem(), m_contextMenu.get());
977     appendItem(InspectElementItem, m_contextMenu.get());
978 }
979 #endif // ENABLE(INSPECTOR)
980 
checkOrEnableIfNeeded(ContextMenuItem & item) const981 void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const
982 {
983     if (item.type() == SeparatorType)
984         return;
985 
986     Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
987     if (!frame)
988         return;
989 
990     // Custom items already have proper checked and enabled values.
991     if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag)
992         return;
993 
994     bool shouldEnable = true;
995     bool shouldCheck = false;
996 
997     switch (item.action()) {
998         case ContextMenuItemTagCheckSpelling:
999             shouldEnable = frame->editor()->canEdit();
1000             break;
1001         case ContextMenuItemTagDefaultDirection:
1002             shouldCheck = false;
1003             shouldEnable = false;
1004             break;
1005         case ContextMenuItemTagLeftToRight:
1006         case ContextMenuItemTagRightToLeft: {
1007             String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
1008             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyDirection, direction) != FalseTriState;
1009             shouldEnable = true;
1010             break;
1011         }
1012         case ContextMenuItemTagTextDirectionDefault: {
1013             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural");
1014             shouldCheck = command.state() == TrueTriState;
1015             shouldEnable = command.isEnabled();
1016             break;
1017         }
1018         case ContextMenuItemTagTextDirectionLeftToRight: {
1019             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight");
1020             shouldCheck = command.state() == TrueTriState;
1021             shouldEnable = command.isEnabled();
1022             break;
1023         }
1024         case ContextMenuItemTagTextDirectionRightToLeft: {
1025             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft");
1026             shouldCheck = command.state() == TrueTriState;
1027             shouldEnable = command.isEnabled();
1028             break;
1029         }
1030         case ContextMenuItemTagCopy:
1031             shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
1032             break;
1033         case ContextMenuItemTagCut:
1034             shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut();
1035             break;
1036         case ContextMenuItemTagIgnoreSpelling:
1037         case ContextMenuItemTagLearnSpelling:
1038             shouldEnable = frame->selection()->isRange();
1039             break;
1040         case ContextMenuItemTagPaste:
1041             shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste();
1042             break;
1043 #if PLATFORM(GTK)
1044         case ContextMenuItemTagDelete:
1045             shouldEnable = frame->editor()->canDelete();
1046             break;
1047         case ContextMenuItemTagSelectAll:
1048         case ContextMenuItemTagInputMethods:
1049         case ContextMenuItemTagUnicode:
1050             shouldEnable = true;
1051             break;
1052 #endif
1053         case ContextMenuItemTagUnderline: {
1054             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline") != FalseTriState;
1055             shouldEnable = frame->editor()->canEditRichly();
1056             break;
1057         }
1058         case ContextMenuItemTagLookUpInDictionary:
1059             shouldEnable = frame->selection()->isRange();
1060             break;
1061         case ContextMenuItemTagCheckGrammarWithSpelling:
1062             if (frame->editor()->isGrammarCheckingEnabled())
1063                 shouldCheck = true;
1064             shouldEnable = true;
1065             break;
1066         case ContextMenuItemTagItalic: {
1067             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontStyle, "italic") != FalseTriState;
1068             shouldEnable = frame->editor()->canEditRichly();
1069             break;
1070         }
1071         case ContextMenuItemTagBold: {
1072             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontWeight, "bold") != FalseTriState;
1073             shouldEnable = frame->editor()->canEditRichly();
1074             break;
1075         }
1076         case ContextMenuItemTagOutline:
1077             shouldEnable = false;
1078             break;
1079         case ContextMenuItemTagShowSpellingPanel:
1080             if (frame->editor()->spellingPanelIsShowing())
1081                 item.setTitle(contextMenuItemTagShowSpellingPanel(false));
1082             else
1083                 item.setTitle(contextMenuItemTagShowSpellingPanel(true));
1084             shouldEnable = frame->editor()->canEdit();
1085             break;
1086         case ContextMenuItemTagNoGuessesFound:
1087             shouldEnable = false;
1088             break;
1089         case ContextMenuItemTagCheckSpellingWhileTyping:
1090             shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled();
1091             break;
1092 #if PLATFORM(MAC)
1093         case ContextMenuItemTagSubstitutionsMenu:
1094         case ContextMenuItemTagTransformationsMenu:
1095             break;
1096         case ContextMenuItemTagShowSubstitutions:
1097 #ifndef BUILDING_ON_LEOPARD
1098             if (frame->editor()->substitutionsPanelIsShowing())
1099                 item.setTitle(contextMenuItemTagShowSubstitutions(false));
1100             else
1101                 item.setTitle(contextMenuItemTagShowSubstitutions(true));
1102             shouldEnable = frame->editor()->canEdit();
1103 #endif
1104             break;
1105         case ContextMenuItemTagMakeUpperCase:
1106         case ContextMenuItemTagMakeLowerCase:
1107         case ContextMenuItemTagCapitalize:
1108         case ContextMenuItemTagChangeBack:
1109             shouldEnable = frame->editor()->canEdit();
1110             break;
1111         case ContextMenuItemTagCorrectSpellingAutomatically:
1112 #ifndef BUILDING_ON_LEOPARD
1113             shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled();
1114 #endif
1115             break;
1116         case ContextMenuItemTagSmartCopyPaste:
1117 #ifndef BUILDING_ON_LEOPARD
1118             shouldCheck = frame->editor()->smartInsertDeleteEnabled();
1119 #endif
1120             break;
1121         case ContextMenuItemTagSmartQuotes:
1122 #ifndef BUILDING_ON_LEOPARD
1123             shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled();
1124 #endif
1125             break;
1126         case ContextMenuItemTagSmartDashes:
1127 #ifndef BUILDING_ON_LEOPARD
1128             shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled();
1129 #endif
1130             break;
1131         case ContextMenuItemTagSmartLinks:
1132 #ifndef BUILDING_ON_LEOPARD
1133             shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled();
1134 #endif
1135             break;
1136         case ContextMenuItemTagTextReplacement:
1137 #ifndef BUILDING_ON_LEOPARD
1138             shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled();
1139 #endif
1140             break;
1141         case ContextMenuItemTagStopSpeaking:
1142             shouldEnable = client() && client()->isSpeaking();
1143             break;
1144 #else // PLATFORM(MAC) ends here
1145         case ContextMenuItemTagStopSpeaking:
1146             break;
1147 #endif
1148 #if PLATFORM(GTK)
1149         case ContextMenuItemTagGoBack:
1150             shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(-1);
1151             break;
1152         case ContextMenuItemTagGoForward:
1153             shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(1);
1154             break;
1155         case ContextMenuItemTagStop:
1156             shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense();
1157             break;
1158         case ContextMenuItemTagReload:
1159             shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense();
1160             break;
1161         case ContextMenuItemTagFontMenu:
1162             shouldEnable = frame->editor()->canEditRichly();
1163             break;
1164 #else
1165         case ContextMenuItemTagGoBack:
1166         case ContextMenuItemTagGoForward:
1167         case ContextMenuItemTagStop:
1168         case ContextMenuItemTagReload:
1169         case ContextMenuItemTagFontMenu:
1170 #endif
1171         case ContextMenuItemTagNoAction:
1172         case ContextMenuItemTagOpenLinkInNewWindow:
1173         case ContextMenuItemTagDownloadLinkToDisk:
1174         case ContextMenuItemTagCopyLinkToClipboard:
1175         case ContextMenuItemTagOpenImageInNewWindow:
1176         case ContextMenuItemTagDownloadImageToDisk:
1177         case ContextMenuItemTagCopyImageToClipboard:
1178 #if PLATFORM(QT) || PLATFORM(GTK)
1179         case ContextMenuItemTagCopyImageUrlToClipboard:
1180 #endif
1181             break;
1182         case ContextMenuItemTagOpenMediaInNewWindow:
1183             if (m_hitTestResult.mediaIsVideo())
1184                 item.setTitle(contextMenuItemTagOpenVideoInNewWindow());
1185             else
1186                 item.setTitle(contextMenuItemTagOpenAudioInNewWindow());
1187             break;
1188         case ContextMenuItemTagCopyMediaLinkToClipboard:
1189             if (m_hitTestResult.mediaIsVideo())
1190                 item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard());
1191             else
1192                 item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard());
1193             break;
1194         case ContextMenuItemTagToggleMediaControls:
1195             shouldCheck = m_hitTestResult.mediaControlsEnabled();
1196             break;
1197         case ContextMenuItemTagToggleMediaLoop:
1198             shouldCheck = m_hitTestResult.mediaLoopEnabled();
1199             break;
1200         case ContextMenuItemTagEnterVideoFullscreen:
1201             shouldEnable = m_hitTestResult.mediaSupportsFullscreen();
1202             break;
1203         case ContextMenuItemTagOpenFrameInNewWindow:
1204         case ContextMenuItemTagSpellingGuess:
1205         case ContextMenuItemTagOther:
1206         case ContextMenuItemTagSearchInSpotlight:
1207         case ContextMenuItemTagSearchWeb:
1208         case ContextMenuItemTagOpenWithDefaultApplication:
1209         case ContextMenuItemPDFActualSize:
1210         case ContextMenuItemPDFZoomIn:
1211         case ContextMenuItemPDFZoomOut:
1212         case ContextMenuItemPDFAutoSize:
1213         case ContextMenuItemPDFSinglePage:
1214         case ContextMenuItemPDFFacingPages:
1215         case ContextMenuItemPDFContinuous:
1216         case ContextMenuItemPDFNextPage:
1217         case ContextMenuItemPDFPreviousPage:
1218         case ContextMenuItemTagOpenLink:
1219         case ContextMenuItemTagIgnoreGrammar:
1220         case ContextMenuItemTagSpellingMenu:
1221         case ContextMenuItemTagShowFonts:
1222         case ContextMenuItemTagStyles:
1223         case ContextMenuItemTagShowColors:
1224         case ContextMenuItemTagSpeechMenu:
1225         case ContextMenuItemTagStartSpeaking:
1226         case ContextMenuItemTagWritingDirectionMenu:
1227         case ContextMenuItemTagTextDirectionMenu:
1228         case ContextMenuItemTagPDFSinglePageScrolling:
1229         case ContextMenuItemTagPDFFacingPagesScrolling:
1230 #if ENABLE(INSPECTOR)
1231         case ContextMenuItemTagInspectElement:
1232 #endif
1233         case ContextMenuItemBaseCustomTag:
1234         case ContextMenuItemCustomTagNoAction:
1235         case ContextMenuItemLastCustomTag:
1236         case ContextMenuItemBaseApplicationTag:
1237             break;
1238         case ContextMenuItemTagMediaPlayPause:
1239             if (m_hitTestResult.mediaPlaying())
1240                 item.setTitle(contextMenuItemTagMediaPause());
1241             else
1242                 item.setTitle(contextMenuItemTagMediaPlay());
1243             break;
1244         case ContextMenuItemTagMediaMute:
1245             shouldEnable = m_hitTestResult.mediaHasAudio();
1246             shouldCheck = shouldEnable &&  m_hitTestResult.mediaMuted();
1247             break;
1248     }
1249 
1250     item.setChecked(shouldCheck);
1251     item.setEnabled(shouldEnable);
1252 }
1253 
1254 } // namespace WebCore
1255 
1256 #endif // ENABLE(CONTEXT_MENUS)
1257