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