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
71using namespace WTF;
72using namespace Unicode;
73
74namespace WebCore {
75
76ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client)
77    : m_page(page)
78    , m_client(client)
79    , m_contextMenu(0)
80{
81    ASSERT_ARG(page, page);
82    ASSERT_ARG(client, client);
83}
84
85ContextMenuController::~ContextMenuController()
86{
87    m_client->contextMenuDestroyed();
88}
89
90void ContextMenuController::clearContextMenu()
91{
92    m_contextMenu.set(0);
93    if (m_menuProvider)
94        m_menuProvider->contextMenuCleared();
95    m_menuProvider = 0;
96}
97
98void 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
109void 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
123PassOwnPtr<ContextMenu> ContextMenuController::createContextMenu(Event* event)
124{
125    if (!event->isMouseEvent())
126        return 0;
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 0;
136
137    m_hitTestResult = result;
138
139    return new ContextMenu;
140}
141
142void 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
158static 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
169void 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#ifndef BUILDING_ON_TIGER
366    case ContextMenuItemTagCheckGrammarWithSpelling:
367        frame->editor()->toggleGrammarChecking();
368        break;
369#endif
370#if PLATFORM(MAC)
371    case ContextMenuItemTagShowFonts:
372        frame->editor()->showFontPanel();
373        break;
374    case ContextMenuItemTagStyles:
375        frame->editor()->showStylesPanel();
376        break;
377    case ContextMenuItemTagShowColors:
378        frame->editor()->showColorPanel();
379        break;
380#endif
381#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
382    case ContextMenuItemTagMakeUpperCase:
383        frame->editor()->uppercaseWord();
384        break;
385    case ContextMenuItemTagMakeLowerCase:
386        frame->editor()->lowercaseWord();
387        break;
388    case ContextMenuItemTagCapitalize:
389        frame->editor()->capitalizeWord();
390        break;
391    case ContextMenuItemTagShowSubstitutions:
392        frame->editor()->showSubstitutionsPanel();
393        break;
394    case ContextMenuItemTagSmartCopyPaste:
395        frame->editor()->toggleSmartInsertDelete();
396        break;
397    case ContextMenuItemTagSmartQuotes:
398        frame->editor()->toggleAutomaticQuoteSubstitution();
399        break;
400    case ContextMenuItemTagSmartDashes:
401        frame->editor()->toggleAutomaticDashSubstitution();
402        break;
403    case ContextMenuItemTagSmartLinks:
404        frame->editor()->toggleAutomaticLinkDetection();
405        break;
406    case ContextMenuItemTagTextReplacement:
407        frame->editor()->toggleAutomaticTextReplacement();
408        break;
409    case ContextMenuItemTagCorrectSpellingAutomatically:
410        frame->editor()->toggleAutomaticSpellingCorrection();
411        break;
412    case ContextMenuItemTagChangeBack:
413        frame->editor()->changeBackToReplacedString(m_hitTestResult.replacedString());
414        break;
415#endif
416#if ENABLE(INSPECTOR)
417    case ContextMenuItemTagInspectElement:
418        if (Page* page = frame->page())
419            page->inspectorController()->inspect(m_hitTestResult.innerNonSharedNode());
420        break;
421#endif
422    default:
423        break;
424    }
425}
426
427void ContextMenuController::appendItem(ContextMenuItem& menuItem, ContextMenu* parentMenu)
428{
429    checkOrEnableIfNeeded(menuItem);
430    if (parentMenu)
431        parentMenu->appendItem(menuItem);
432}
433
434static PassOwnPtr<ContextMenuItem> separatorItem()
435{
436    return new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String());
437}
438
439void ContextMenuController::createAndAppendFontSubMenu(ContextMenuItem& fontMenuItem)
440{
441    ContextMenu fontMenu;
442
443#if PLATFORM(MAC)
444    ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts());
445#endif
446    ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold());
447    ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic());
448    ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline());
449    ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline());
450#if PLATFORM(MAC)
451    ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles());
452    ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors());
453#endif
454
455#if PLATFORM(MAC)
456    appendItem(showFonts, &fontMenu);
457#endif
458    appendItem(bold, &fontMenu);
459    appendItem(italic, &fontMenu);
460    appendItem(underline, &fontMenu);
461    appendItem(outline, &fontMenu);
462#if PLATFORM(MAC)
463    appendItem(styles, &fontMenu);
464    appendItem(*separatorItem(), &fontMenu);
465    appendItem(showColors, &fontMenu);
466#endif
467
468    fontMenuItem.setSubMenu(&fontMenu);
469}
470
471#if !defined(BUILDING_ON_TIGER)
472
473#if !PLATFORM(GTK)
474
475void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem)
476{
477    ContextMenu spellingAndGrammarMenu;
478
479    ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
480        contextMenuItemTagShowSpellingPanel(true));
481    ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
482        contextMenuItemTagCheckSpelling());
483    ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
484        contextMenuItemTagCheckSpellingWhileTyping());
485    ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling,
486        contextMenuItemTagCheckGrammarWithSpelling());
487#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
488    ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically,
489        contextMenuItemTagCorrectSpellingAutomatically());
490#endif
491
492    appendItem(showSpellingPanel, &spellingAndGrammarMenu);
493    appendItem(checkSpelling, &spellingAndGrammarMenu);
494#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
495    appendItem(*separatorItem(), &spellingAndGrammarMenu);
496#endif
497    appendItem(checkAsYouType, &spellingAndGrammarMenu);
498    appendItem(grammarWithSpelling, &spellingAndGrammarMenu);
499#if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
500    appendItem(correctSpelling, &spellingAndGrammarMenu);
501#endif
502
503    spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu);
504}
505
506#endif // !PLATFORM(GTK)
507
508#else
509
510void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem)
511{
512    ContextMenu spellingMenu;
513
514    ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
515        contextMenuItemTagShowSpellingPanel(true));
516    ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
517        contextMenuItemTagCheckSpelling());
518    ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
519        contextMenuItemTagCheckSpellingWhileTyping());
520
521    appendItem(showSpellingPanel, &spellingMenu);
522    appendItem(checkSpelling, &spellingMenu);
523    appendItem(checkAsYouType, &spellingMenu);
524
525    spellingMenuItem.setSubMenu(&spellingMenu);
526}
527
528#endif
529
530#if PLATFORM(MAC)
531
532void ContextMenuController::createAndAppendSpeechSubMenu(ContextMenuItem& speechMenuItem)
533{
534    ContextMenu speechMenu;
535
536    ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking());
537    ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking());
538
539    appendItem(start, &speechMenu);
540    appendItem(stop, &speechMenu);
541
542    speechMenuItem.setSubMenu(&speechMenu);
543}
544
545#endif
546
547#if !PLATFORM(GTK)
548
549void ContextMenuController::createAndAppendWritingDirectionSubMenu(ContextMenuItem& writingDirectionMenuItem)
550{
551    ContextMenu writingDirectionMenu;
552
553    ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection,
554        contextMenuItemTagDefaultDirection());
555    ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight());
556    ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft());
557
558    appendItem(defaultItem, &writingDirectionMenu);
559    appendItem(ltr, &writingDirectionMenu);
560    appendItem(rtl, &writingDirectionMenu);
561
562    writingDirectionMenuItem.setSubMenu(&writingDirectionMenu);
563}
564
565void ContextMenuController::createAndAppendTextDirectionSubMenu(ContextMenuItem& textDirectionMenuItem)
566{
567    ContextMenu textDirectionMenu;
568
569    ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection());
570    ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight());
571    ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft());
572
573    appendItem(defaultItem, &textDirectionMenu);
574    appendItem(ltr, &textDirectionMenu);
575    appendItem(rtl, &textDirectionMenu);
576
577    textDirectionMenuItem.setSubMenu(&textDirectionMenu);
578}
579
580#endif
581
582#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
583
584void ContextMenuController::createAndAppendSubstitutionsSubMenu(ContextMenuItem& substitutionsMenuItem)
585{
586    ContextMenu substitutionsMenu;
587
588    ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true));
589    ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste());
590    ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes());
591    ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes());
592    ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks());
593    ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement());
594
595    appendItem(showSubstitutions, &substitutionsMenu);
596    appendItem(*separatorItem(), &substitutionsMenu);
597    appendItem(smartCopyPaste, &substitutionsMenu);
598    appendItem(smartQuotes, &substitutionsMenu);
599    appendItem(smartDashes, &substitutionsMenu);
600    appendItem(smartLinks, &substitutionsMenu);
601    appendItem(textReplacement, &substitutionsMenu);
602
603    substitutionsMenuItem.setSubMenu(&substitutionsMenu);
604}
605
606void ContextMenuController::createAndAppendTransformationsSubMenu(ContextMenuItem& transformationsMenuItem)
607{
608    ContextMenu transformationsMenu;
609
610    ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase());
611    ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase());
612    ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize());
613
614    appendItem(makeUpperCase, &transformationsMenu);
615    appendItem(makeLowerCase, &transformationsMenu);
616    appendItem(capitalize, &transformationsMenu);
617
618    transformationsMenuItem.setSubMenu(&transformationsMenu);
619}
620
621#endif
622
623static bool selectionContainsPossibleWord(Frame* frame)
624{
625    // Current algorithm: look for a character that's not just a separator.
626    for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) {
627        int length = it.length();
628        const UChar* characters = it.characters();
629        for (int i = 0; i < length; ++i)
630            if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph)))
631                return true;
632    }
633    return false;
634}
635
636#if PLATFORM(MAC)
637#if defined(BUILDING_ON_TIGER) || defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD)
638#define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 1
639#else
640#define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 0
641#endif
642#endif
643
644void ContextMenuController::populate()
645{
646    ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink());
647    ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow,
648        contextMenuItemTagOpenLinkInNewWindow());
649    ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk,
650        contextMenuItemTagDownloadLinkToDisk());
651    ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard,
652        contextMenuItemTagCopyLinkToClipboard());
653    ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow,
654        contextMenuItemTagOpenImageInNewWindow());
655    ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk,
656        contextMenuItemTagDownloadImageToDisk());
657    ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard,
658        contextMenuItemTagCopyImageToClipboard());
659#if PLATFORM(QT) || PLATFORM(GTK)
660    ContextMenuItem CopyImageUrlItem(ActionType, ContextMenuItemTagCopyImageUrlToClipboard,
661        contextMenuItemTagCopyImageUrlToClipboard());
662#endif
663    ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String());
664    ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard,
665        String());
666    ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause,
667        contextMenuItemTagMediaPlay());
668    ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute,
669        contextMenuItemTagMediaMute());
670    ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls,
671        contextMenuItemTagToggleMediaControls());
672    ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop,
673        contextMenuItemTagToggleMediaLoop());
674    ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen,
675        contextMenuItemTagEnterVideoFullscreen());
676#if PLATFORM(MAC)
677    ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight,
678        contextMenuItemTagSearchInSpotlight());
679#endif
680#if !PLATFORM(GTK)
681    ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb());
682#endif
683    ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy());
684    ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack());
685    ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward,  contextMenuItemTagGoForward());
686    ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop());
687    ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload());
688    ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow,
689        contextMenuItemTagOpenFrameInNewWindow());
690    ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound,
691        contextMenuItemTagNoGuessesFound());
692    ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling,
693        contextMenuItemTagIgnoreSpelling());
694    ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling,
695        contextMenuItemTagLearnSpelling());
696    ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar,
697        contextMenuItemTagIgnoreGrammar());
698    ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut());
699    ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
700#if PLATFORM(GTK)
701    ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
702#endif
703#if PLATFORM(GTK) || PLATFORM(QT)
704    ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
705#endif
706
707    Node* node = m_hitTestResult.innerNonSharedNode();
708    if (!node)
709        return;
710#if PLATFORM(GTK)
711    if (!m_hitTestResult.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
712        return;
713#endif
714    Frame* frame = node->document()->frame();
715    if (!frame)
716        return;
717
718    if (!m_hitTestResult.isContentEditable()) {
719        FrameLoader* loader = frame->loader();
720        KURL linkURL = m_hitTestResult.absoluteLinkURL();
721        if (!linkURL.isEmpty()) {
722            if (loader->canHandleRequest(ResourceRequest(linkURL))) {
723                appendItem(OpenLinkItem, m_contextMenu.get());
724                appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
725                appendItem(DownloadFileItem, m_contextMenu.get());
726            }
727#if PLATFORM(QT)
728            if (m_hitTestResult.isSelected())
729                appendItem(CopyItem, m_contextMenu.get());
730#endif
731            appendItem(CopyLinkItem, m_contextMenu.get());
732        }
733
734        KURL imageURL = m_hitTestResult.absoluteImageURL();
735        if (!imageURL.isEmpty()) {
736            if (!linkURL.isEmpty())
737                appendItem(*separatorItem(), m_contextMenu.get());
738
739            appendItem(OpenImageInNewWindowItem, m_contextMenu.get());
740            appendItem(DownloadImageItem, m_contextMenu.get());
741            if (imageURL.isLocalFile() || m_hitTestResult.image())
742                appendItem(CopyImageItem, m_contextMenu.get());
743#if PLATFORM(QT) || PLATFORM(GTK)
744            appendItem(CopyImageUrlItem, m_contextMenu.get());
745#endif
746        }
747
748        KURL mediaURL = m_hitTestResult.absoluteMediaURL();
749        if (!mediaURL.isEmpty()) {
750            if (!linkURL.isEmpty() || !imageURL.isEmpty())
751                appendItem(*separatorItem(), m_contextMenu.get());
752
753            appendItem(MediaPlayPause, m_contextMenu.get());
754            appendItem(MediaMute, m_contextMenu.get());
755            appendItem(ToggleMediaControls, m_contextMenu.get());
756            appendItem(ToggleMediaLoop, m_contextMenu.get());
757            appendItem(EnterVideoFullscreen, m_contextMenu.get());
758
759            appendItem(*separatorItem(), m_contextMenu.get());
760            appendItem(CopyMediaLinkItem, m_contextMenu.get());
761            appendItem(OpenMediaInNewWindowItem, m_contextMenu.get());
762        }
763
764        if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) {
765            if (m_hitTestResult.isSelected()) {
766                if (selectionContainsPossibleWord(frame)) {
767#if PLATFORM(MAC)
768                    String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText());
769                    ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString));
770
771#if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
772                    appendItem(SearchSpotlightItem, m_contextMenu.get());
773#else
774                    appendItem(LookUpInDictionaryItem, m_contextMenu.get());
775#endif
776#endif
777
778#if !PLATFORM(GTK)
779                    appendItem(SearchWebItem, m_contextMenu.get());
780                    appendItem(*separatorItem(), m_contextMenu.get());
781#endif
782
783#if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
784                    appendItem(LookUpInDictionaryItem, m_contextMenu.get());
785                    appendItem(*separatorItem(), m_contextMenu.get());
786#endif
787                }
788
789                appendItem(CopyItem, m_contextMenu.get());
790#if PLATFORM(MAC)
791                appendItem(*separatorItem(), m_contextMenu.get());
792
793                ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
794                createAndAppendSpeechSubMenu(SpeechMenuItem);
795                appendItem(SpeechMenuItem, m_contextMenu.get());
796#endif
797            } else {
798#if ENABLE(INSPECTOR)
799                if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) {
800#endif
801
802                // In GTK+ unavailable items are not hidden but insensitive
803#if PLATFORM(GTK)
804                appendItem(BackItem, m_contextMenu.get());
805                appendItem(ForwardItem, m_contextMenu.get());
806                appendItem(StopItem, m_contextMenu.get());
807                appendItem(ReloadItem, m_contextMenu.get());
808#else
809                if (frame->page() && frame->page()->backForward()->canGoBackOrForward(-1))
810                    appendItem(BackItem, m_contextMenu.get());
811
812                if (frame->page() && frame->page()->backForward()->canGoBackOrForward(1))
813                    appendItem(ForwardItem, m_contextMenu.get());
814
815                // use isLoadingInAPISense rather than isLoading because Stop/Reload are
816                // intended to match WebKit's API, not WebCore's internal notion of loading status
817                if (loader->documentLoader()->isLoadingInAPISense())
818                    appendItem(StopItem, m_contextMenu.get());
819                else
820                    appendItem(ReloadItem, m_contextMenu.get());
821#endif
822#if ENABLE(INSPECTOR)
823                }
824#endif
825
826                if (frame->page() && frame != frame->page()->mainFrame())
827                    appendItem(OpenFrameItem, m_contextMenu.get());
828            }
829        }
830    } else { // Make an editing context menu
831        SelectionController* selection = frame->selection();
832        bool inPasswordField = selection->isInPasswordField();
833        bool spellCheckingEnabled = frame->editor()->isSpellCheckingEnabledFor(node);
834
835        if (!inPasswordField && spellCheckingEnabled) {
836            // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
837            // is never considered a misspelling and bad grammar at the same time)
838            bool misspelling;
839            bool badGrammar;
840            Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
841            if (misspelling || badGrammar) {
842                size_t size = guesses.size();
843                if (size == 0) {
844                    // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
845                    // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit)
846                    if (misspelling) {
847                        appendItem(NoGuessesItem, m_contextMenu.get());
848                        appendItem(*separatorItem(), m_contextMenu.get());
849                    }
850                } else {
851                    for (unsigned i = 0; i < size; i++) {
852                        const String &guess = guesses[i];
853                        if (!guess.isEmpty()) {
854                            ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
855                            appendItem(item, m_contextMenu.get());
856                        }
857                    }
858                    appendItem(*separatorItem(), m_contextMenu.get());
859                }
860
861                if (misspelling) {
862                    appendItem(IgnoreSpellingItem, m_contextMenu.get());
863                    appendItem(LearnSpellingItem, m_contextMenu.get());
864                } else
865                    appendItem(IgnoreGrammarItem, m_contextMenu.get());
866                appendItem(*separatorItem(), m_contextMenu.get());
867#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
868            } else {
869                // If the string was autocorrected, generate a contextual menu item allowing it to be changed back.
870                String replacedString = m_hitTestResult.replacedString();
871                if (!replacedString.isEmpty()) {
872                    ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString));
873                    appendItem(item, m_contextMenu.get());
874                    appendItem(*separatorItem(), m_contextMenu.get());
875                }
876#endif
877            }
878        }
879
880        FrameLoader* loader = frame->loader();
881        KURL linkURL = m_hitTestResult.absoluteLinkURL();
882        if (!linkURL.isEmpty()) {
883            if (loader->canHandleRequest(ResourceRequest(linkURL))) {
884                appendItem(OpenLinkItem, m_contextMenu.get());
885                appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
886                appendItem(DownloadFileItem, m_contextMenu.get());
887            }
888            appendItem(CopyLinkItem, m_contextMenu.get());
889            appendItem(*separatorItem(), m_contextMenu.get());
890        }
891
892        if (m_hitTestResult.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) {
893#if PLATFORM(MAC)
894            String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText());
895            ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString));
896
897#if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
898            appendItem(SearchSpotlightItem, m_contextMenu.get());
899#else
900            appendItem(LookUpInDictionaryItem, m_contextMenu.get());
901#endif
902#endif
903
904#if !PLATFORM(GTK)
905            appendItem(SearchWebItem, m_contextMenu.get());
906            appendItem(*separatorItem(), m_contextMenu.get());
907#endif
908
909#if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
910            appendItem(LookUpInDictionaryItem, m_contextMenu.get());
911            appendItem(*separatorItem(), m_contextMenu.get());
912#endif
913        }
914
915        appendItem(CutItem, m_contextMenu.get());
916        appendItem(CopyItem, m_contextMenu.get());
917        appendItem(PasteItem, m_contextMenu.get());
918#if PLATFORM(GTK)
919        appendItem(DeleteItem, m_contextMenu.get());
920        appendItem(*separatorItem(), m_contextMenu.get());
921#endif
922#if PLATFORM(GTK) || PLATFORM(QT)
923        appendItem(SelectAllItem, m_contextMenu.get());
924#endif
925
926        if (!inPasswordField) {
927            appendItem(*separatorItem(), m_contextMenu.get());
928#ifndef BUILDING_ON_TIGER
929#if !PLATFORM(GTK)
930            ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
931                contextMenuItemTagSpellingMenu());
932            createAndAppendSpellingAndGrammarSubMenu(SpellingAndGrammarMenuItem);
933            appendItem(SpellingAndGrammarMenuItem, m_contextMenu.get());
934#endif
935#else
936            ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
937                contextMenuItemTagSpellingMenu());
938            createAndAppendSpellingSubMenu(SpellingMenuItem);
939            appendItem(SpellingMenuItem, m_contextMenu.get());
940#endif
941#if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
942            ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu,
943                contextMenuItemTagSubstitutionsMenu());
944            createAndAppendSubstitutionsSubMenu(substitutionsMenuItem);
945            appendItem(substitutionsMenuItem, m_contextMenu.get());
946            ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu,
947                contextMenuItemTagTransformationsMenu());
948            createAndAppendTransformationsSubMenu(transformationsMenuItem);
949            appendItem(transformationsMenuItem, m_contextMenu.get());
950#endif
951#if PLATFORM(GTK)
952            bool shouldShowFontMenu = frame->editor()->canEditRichly();
953#else
954            bool shouldShowFontMenu = true;
955#endif
956            if (shouldShowFontMenu) {
957                ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu,
958                    contextMenuItemTagFontMenu());
959                createAndAppendFontSubMenu(FontMenuItem);
960                appendItem(FontMenuItem, m_contextMenu.get());
961            }
962#if PLATFORM(MAC)
963            ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
964            createAndAppendSpeechSubMenu(SpeechMenuItem);
965            appendItem(SpeechMenuItem, m_contextMenu.get());
966#endif
967#if !PLATFORM(GTK)
968            ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu,
969                contextMenuItemTagWritingDirectionMenu());
970            createAndAppendWritingDirectionSubMenu(WritingDirectionMenuItem);
971            appendItem(WritingDirectionMenuItem, m_contextMenu.get());
972            if (Page* page = frame->page()) {
973                if (Settings* settings = page->settings()) {
974                    bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
975                        || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
976                    if (includeTextDirectionSubmenu) {
977                        ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu,
978                            contextMenuItemTagTextDirectionMenu());
979                        createAndAppendTextDirectionSubMenu(TextDirectionMenuItem);
980                        appendItem(TextDirectionMenuItem, m_contextMenu.get());
981                    }
982                }
983            }
984#endif
985        }
986    }
987}
988
989#if ENABLE(INSPECTOR)
990void ContextMenuController::addInspectElementItem()
991{
992    Node* node = m_hitTestResult.innerNonSharedNode();
993    if (!node)
994        return;
995
996    Frame* frame = node->document()->frame();
997    if (!frame)
998        return;
999
1000    Page* page = frame->page();
1001    if (!page)
1002        return;
1003
1004    if (!page->inspectorController())
1005        return;
1006
1007    ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement());
1008    appendItem(*separatorItem(), m_contextMenu.get());
1009    appendItem(InspectElementItem, m_contextMenu.get());
1010}
1011#endif // ENABLE(INSPECTOR)
1012
1013void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const
1014{
1015    if (item.type() == SeparatorType)
1016        return;
1017
1018    Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
1019    if (!frame)
1020        return;
1021
1022    // Custom items already have proper checked and enabled values.
1023    if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag)
1024        return;
1025
1026    bool shouldEnable = true;
1027    bool shouldCheck = false;
1028
1029    switch (item.action()) {
1030        case ContextMenuItemTagCheckSpelling:
1031            shouldEnable = frame->editor()->canEdit();
1032            break;
1033        case ContextMenuItemTagDefaultDirection:
1034            shouldCheck = false;
1035            shouldEnable = false;
1036            break;
1037        case ContextMenuItemTagLeftToRight:
1038        case ContextMenuItemTagRightToLeft: {
1039            String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
1040            shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyDirection, direction) != FalseTriState;
1041            shouldEnable = true;
1042            break;
1043        }
1044        case ContextMenuItemTagTextDirectionDefault: {
1045            Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural");
1046            shouldCheck = command.state() == TrueTriState;
1047            shouldEnable = command.isEnabled();
1048            break;
1049        }
1050        case ContextMenuItemTagTextDirectionLeftToRight: {
1051            Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight");
1052            shouldCheck = command.state() == TrueTriState;
1053            shouldEnable = command.isEnabled();
1054            break;
1055        }
1056        case ContextMenuItemTagTextDirectionRightToLeft: {
1057            Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft");
1058            shouldCheck = command.state() == TrueTriState;
1059            shouldEnable = command.isEnabled();
1060            break;
1061        }
1062        case ContextMenuItemTagCopy:
1063            shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
1064            break;
1065        case ContextMenuItemTagCut:
1066            shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut();
1067            break;
1068        case ContextMenuItemTagIgnoreSpelling:
1069        case ContextMenuItemTagLearnSpelling:
1070            shouldEnable = frame->selection()->isRange();
1071            break;
1072        case ContextMenuItemTagPaste:
1073            shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste();
1074            break;
1075#if PLATFORM(GTK)
1076        case ContextMenuItemTagDelete:
1077            shouldEnable = frame->editor()->canDelete();
1078            break;
1079        case ContextMenuItemTagSelectAll:
1080        case ContextMenuItemTagInputMethods:
1081        case ContextMenuItemTagUnicode:
1082            shouldEnable = true;
1083            break;
1084#endif
1085        case ContextMenuItemTagUnderline: {
1086            shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline") != FalseTriState;
1087            shouldEnable = frame->editor()->canEditRichly();
1088            break;
1089        }
1090        case ContextMenuItemTagLookUpInDictionary:
1091            shouldEnable = frame->selection()->isRange();
1092            break;
1093        case ContextMenuItemTagCheckGrammarWithSpelling:
1094#ifndef BUILDING_ON_TIGER
1095            if (frame->editor()->isGrammarCheckingEnabled())
1096                shouldCheck = true;
1097            shouldEnable = true;
1098#endif
1099            break;
1100        case ContextMenuItemTagItalic: {
1101            shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontStyle, "italic") != FalseTriState;
1102            shouldEnable = frame->editor()->canEditRichly();
1103            break;
1104        }
1105        case ContextMenuItemTagBold: {
1106            shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontWeight, "bold") != FalseTriState;
1107            shouldEnable = frame->editor()->canEditRichly();
1108            break;
1109        }
1110        case ContextMenuItemTagOutline:
1111            shouldEnable = false;
1112            break;
1113        case ContextMenuItemTagShowSpellingPanel:
1114#ifndef BUILDING_ON_TIGER
1115            if (frame->editor()->spellingPanelIsShowing())
1116                item.setTitle(contextMenuItemTagShowSpellingPanel(false));
1117            else
1118                item.setTitle(contextMenuItemTagShowSpellingPanel(true));
1119#endif
1120            shouldEnable = frame->editor()->canEdit();
1121            break;
1122        case ContextMenuItemTagNoGuessesFound:
1123            shouldEnable = false;
1124            break;
1125        case ContextMenuItemTagCheckSpellingWhileTyping:
1126            shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled();
1127            break;
1128#if PLATFORM(MAC)
1129        case ContextMenuItemTagSubstitutionsMenu:
1130        case ContextMenuItemTagTransformationsMenu:
1131            break;
1132        case ContextMenuItemTagShowSubstitutions:
1133#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1134            if (frame->editor()->substitutionsPanelIsShowing())
1135                item.setTitle(contextMenuItemTagShowSubstitutions(false));
1136            else
1137                item.setTitle(contextMenuItemTagShowSubstitutions(true));
1138            shouldEnable = frame->editor()->canEdit();
1139#endif
1140            break;
1141        case ContextMenuItemTagMakeUpperCase:
1142        case ContextMenuItemTagMakeLowerCase:
1143        case ContextMenuItemTagCapitalize:
1144        case ContextMenuItemTagChangeBack:
1145            shouldEnable = frame->editor()->canEdit();
1146            break;
1147        case ContextMenuItemTagCorrectSpellingAutomatically:
1148#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1149            shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled();
1150#endif
1151            break;
1152        case ContextMenuItemTagSmartCopyPaste:
1153#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1154            shouldCheck = frame->editor()->smartInsertDeleteEnabled();
1155#endif
1156            break;
1157        case ContextMenuItemTagSmartQuotes:
1158#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1159            shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled();
1160#endif
1161            break;
1162        case ContextMenuItemTagSmartDashes:
1163#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1164            shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled();
1165#endif
1166            break;
1167        case ContextMenuItemTagSmartLinks:
1168#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1169            shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled();
1170#endif
1171            break;
1172        case ContextMenuItemTagTextReplacement:
1173#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
1174            shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled();
1175#endif
1176            break;
1177        case ContextMenuItemTagStopSpeaking:
1178            shouldEnable = client() && client()->isSpeaking();
1179            break;
1180#else // PLATFORM(MAC) ends here
1181        case ContextMenuItemTagStopSpeaking:
1182            break;
1183#endif
1184#if PLATFORM(GTK)
1185        case ContextMenuItemTagGoBack:
1186            shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(-1);
1187            break;
1188        case ContextMenuItemTagGoForward:
1189            shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(1);
1190            break;
1191        case ContextMenuItemTagStop:
1192            shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense();
1193            break;
1194        case ContextMenuItemTagReload:
1195            shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense();
1196            break;
1197        case ContextMenuItemTagFontMenu:
1198            shouldEnable = frame->editor()->canEditRichly();
1199            break;
1200#else
1201        case ContextMenuItemTagGoBack:
1202        case ContextMenuItemTagGoForward:
1203        case ContextMenuItemTagStop:
1204        case ContextMenuItemTagReload:
1205        case ContextMenuItemTagFontMenu:
1206#endif
1207        case ContextMenuItemTagNoAction:
1208        case ContextMenuItemTagOpenLinkInNewWindow:
1209        case ContextMenuItemTagDownloadLinkToDisk:
1210        case ContextMenuItemTagCopyLinkToClipboard:
1211        case ContextMenuItemTagOpenImageInNewWindow:
1212        case ContextMenuItemTagDownloadImageToDisk:
1213        case ContextMenuItemTagCopyImageToClipboard:
1214#if PLATFORM(QT) || PLATFORM(GTK)
1215        case ContextMenuItemTagCopyImageUrlToClipboard:
1216#endif
1217            break;
1218        case ContextMenuItemTagOpenMediaInNewWindow:
1219            if (m_hitTestResult.mediaIsVideo())
1220                item.setTitle(contextMenuItemTagOpenVideoInNewWindow());
1221            else
1222                item.setTitle(contextMenuItemTagOpenAudioInNewWindow());
1223            break;
1224        case ContextMenuItemTagCopyMediaLinkToClipboard:
1225            if (m_hitTestResult.mediaIsVideo())
1226                item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard());
1227            else
1228                item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard());
1229            break;
1230        case ContextMenuItemTagToggleMediaControls:
1231            shouldCheck = m_hitTestResult.mediaControlsEnabled();
1232            break;
1233        case ContextMenuItemTagToggleMediaLoop:
1234            shouldCheck = m_hitTestResult.mediaLoopEnabled();
1235            break;
1236        case ContextMenuItemTagEnterVideoFullscreen:
1237            shouldEnable = m_hitTestResult.mediaSupportsFullscreen();
1238            break;
1239        case ContextMenuItemTagOpenFrameInNewWindow:
1240        case ContextMenuItemTagSpellingGuess:
1241        case ContextMenuItemTagOther:
1242        case ContextMenuItemTagSearchInSpotlight:
1243        case ContextMenuItemTagSearchWeb:
1244        case ContextMenuItemTagOpenWithDefaultApplication:
1245        case ContextMenuItemPDFActualSize:
1246        case ContextMenuItemPDFZoomIn:
1247        case ContextMenuItemPDFZoomOut:
1248        case ContextMenuItemPDFAutoSize:
1249        case ContextMenuItemPDFSinglePage:
1250        case ContextMenuItemPDFFacingPages:
1251        case ContextMenuItemPDFContinuous:
1252        case ContextMenuItemPDFNextPage:
1253        case ContextMenuItemPDFPreviousPage:
1254        case ContextMenuItemTagOpenLink:
1255        case ContextMenuItemTagIgnoreGrammar:
1256        case ContextMenuItemTagSpellingMenu:
1257        case ContextMenuItemTagShowFonts:
1258        case ContextMenuItemTagStyles:
1259        case ContextMenuItemTagShowColors:
1260        case ContextMenuItemTagSpeechMenu:
1261        case ContextMenuItemTagStartSpeaking:
1262        case ContextMenuItemTagWritingDirectionMenu:
1263        case ContextMenuItemTagTextDirectionMenu:
1264        case ContextMenuItemTagPDFSinglePageScrolling:
1265        case ContextMenuItemTagPDFFacingPagesScrolling:
1266#if ENABLE(INSPECTOR)
1267        case ContextMenuItemTagInspectElement:
1268#endif
1269        case ContextMenuItemBaseCustomTag:
1270        case ContextMenuItemCustomTagNoAction:
1271        case ContextMenuItemLastCustomTag:
1272        case ContextMenuItemBaseApplicationTag:
1273            break;
1274        case ContextMenuItemTagMediaPlayPause:
1275            if (m_hitTestResult.mediaPlaying())
1276                item.setTitle(contextMenuItemTagMediaPause());
1277            else
1278                item.setTitle(contextMenuItemTagMediaPlay());
1279            break;
1280        case ContextMenuItemTagMediaMute:
1281            shouldEnable = m_hitTestResult.mediaHasAudio();
1282            shouldCheck = shouldEnable &&  m_hitTestResult.mediaMuted();
1283            break;
1284    }
1285
1286    item.setChecked(shouldCheck);
1287    item.setEnabled(shouldEnable);
1288}
1289
1290} // namespace WebCore
1291
1292#endif // ENABLE(CONTEXT_MENUS)
1293