• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3  * Copyright (C) 2010 Igalia S.L
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include "config.h"
28 #include "ContextMenuController.h"
29 
30 #if ENABLE(CONTEXT_MENUS)
31 
32 #include "BackForwardController.h"
33 #include "Chrome.h"
34 #include "ContextMenu.h"
35 #include "ContextMenuClient.h"
36 #include "ContextMenuItem.h"
37 #include "ContextMenuProvider.h"
38 #include "Document.h"
39 #include "DocumentFragment.h"
40 #include "DocumentLoader.h"
41 #include "Editor.h"
42 #include "EditorClient.h"
43 #include "Event.h"
44 #include "EventHandler.h"
45 #include "EventNames.h"
46 #include "FormState.h"
47 #include "Frame.h"
48 #include "FrameLoadRequest.h"
49 #include "FrameLoader.h"
50 #include "HTMLFormElement.h"
51 #include "HitTestRequest.h"
52 #include "HitTestResult.h"
53 #include "InspectorController.h"
54 #include "LocalizedStrings.h"
55 #include "MouseEvent.h"
56 #include "NavigationAction.h"
57 #include "Node.h"
58 #include "Page.h"
59 #include "RenderLayer.h"
60 #include "RenderObject.h"
61 #include "ReplaceSelectionCommand.h"
62 #include "ResourceRequest.h"
63 #include "SelectionController.h"
64 #include "Settings.h"
65 #include "TextIterator.h"
66 #include "UserTypingGestureIndicator.h"
67 #include "WindowFeatures.h"
68 #include "markup.h"
69 #include <wtf/unicode/Unicode.h>
70 
71 using namespace WTF;
72 using namespace Unicode;
73 
74 namespace WebCore {
75 
ContextMenuController(Page * page,ContextMenuClient * client)76 ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client)
77     : m_page(page)
78     , m_client(client)
79     , m_contextMenu(0)
80 {
81     ASSERT_ARG(page, page);
82     ASSERT_ARG(client, client);
83 }
84 
~ContextMenuController()85 ContextMenuController::~ContextMenuController()
86 {
87     m_client->contextMenuDestroyed();
88 }
89 
clearContextMenu()90 void ContextMenuController::clearContextMenu()
91 {
92     m_contextMenu.set(0);
93     if (m_menuProvider)
94         m_menuProvider->contextMenuCleared();
95     m_menuProvider = 0;
96 }
97 
handleContextMenuEvent(Event * event)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 
showContextMenu(Event * event,PassRefPtr<ContextMenuProvider> menuProvider)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 
createContextMenu(Event * event)123 PassOwnPtr<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 
showContextMenu(Event * event)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 
openNewWindow(const KURL & urlToLoad,Frame * frame)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 
contextMenuItemSelected(ContextMenuItem * item)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 #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 
appendItem(ContextMenuItem & menuItem,ContextMenu * parentMenu)427 void ContextMenuController::appendItem(ContextMenuItem& menuItem, ContextMenu* parentMenu)
428 {
429     checkOrEnableIfNeeded(menuItem);
430     if (parentMenu)
431         parentMenu->appendItem(menuItem);
432 }
433 
separatorItem()434 static PassOwnPtr<ContextMenuItem> separatorItem()
435 {
436     return new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String());
437 }
438 
createAndAppendFontSubMenu(ContextMenuItem & fontMenuItem)439 void 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 
createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem & spellingAndGrammarMenuItem)475 void 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 
createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem & spellingAndGrammarMenuItem)510 void 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 
createAndAppendSpeechSubMenu(ContextMenuItem & speechMenuItem)532 void 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 
createAndAppendWritingDirectionSubMenu(ContextMenuItem & writingDirectionMenuItem)549 void 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 
createAndAppendTextDirectionSubMenu(ContextMenuItem & textDirectionMenuItem)565 void 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 
createAndAppendSubstitutionsSubMenu(ContextMenuItem & substitutionsMenuItem)584 void 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 
createAndAppendTransformationsSubMenu(ContextMenuItem & transformationsMenuItem)606 void 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 
selectionContainsPossibleWord(Frame * frame)623 static 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 
populate()644 void 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)
addInspectElementItem()990 void 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 
checkOrEnableIfNeeded(ContextMenuItem & item) const1013 void 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