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