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