1 /*
2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2008 Christian Dywan <christian@imendio.com>
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 "ContextMenu.h"
29
30 #if ENABLE(CONTEXT_MENUS)
31
32 #include "ContextMenuController.h"
33 #include "ContextMenuClient.h"
34 #include "CSSComputedStyleDeclaration.h"
35 #include "CSSProperty.h"
36 #include "CSSPropertyNames.h"
37 #include "CString.h"
38 #include "Document.h"
39 #include "DocumentLoader.h"
40 #include "Editor.h"
41 #include "Frame.h"
42 #include "FrameLoader.h"
43 #include "InspectorController.h"
44 #include "KURL.h"
45 #include "LocalizedStrings.h"
46 #include "Node.h"
47 #include "Page.h"
48 #include "ResourceRequest.h"
49 #include "SelectionController.h"
50 #include "Settings.h"
51 #include "TextIterator.h"
52 #include <memory>
53
54 using namespace std;
55 using namespace WTF;
56 using namespace Unicode;
57
58 namespace WebCore {
59
controller() const60 ContextMenuController* ContextMenu::controller() const
61 {
62 if (Node* node = m_hitTestResult.innerNonSharedNode())
63 if (Frame* frame = node->document()->frame())
64 if (Page* page = frame->page())
65 return page->contextMenuController();
66 return 0;
67 }
68
separatorItem()69 static auto_ptr<ContextMenuItem> separatorItem()
70 {
71 return auto_ptr<ContextMenuItem>(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()));
72 }
73
createAndAppendFontSubMenu(const HitTestResult & result,ContextMenuItem & fontMenuItem)74 static void createAndAppendFontSubMenu(const HitTestResult& result, ContextMenuItem& fontMenuItem)
75 {
76 ContextMenu fontMenu(result);
77
78 #if PLATFORM(MAC)
79 ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts());
80 #endif
81 ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold());
82 ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic());
83 ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline());
84 ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline());
85 #if PLATFORM(MAC)
86 ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles());
87 ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors());
88 #endif
89
90 #if PLATFORM(MAC)
91 fontMenu.appendItem(showFonts);
92 #endif
93 fontMenu.appendItem(bold);
94 fontMenu.appendItem(italic);
95 fontMenu.appendItem(underline);
96 fontMenu.appendItem(outline);
97 #if PLATFORM(MAC)
98 fontMenu.appendItem(styles);
99 fontMenu.appendItem(*separatorItem());
100 fontMenu.appendItem(showColors);
101 #endif
102
103 fontMenuItem.setSubMenu(&fontMenu);
104 }
105
106 #ifndef BUILDING_ON_TIGER
createAndAppendSpellingAndGrammarSubMenu(const HitTestResult & result,ContextMenuItem & spellingAndGrammarMenuItem)107 static void createAndAppendSpellingAndGrammarSubMenu(const HitTestResult& result, ContextMenuItem& spellingAndGrammarMenuItem)
108 {
109 ContextMenu spellingAndGrammarMenu(result);
110
111 ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
112 contextMenuItemTagShowSpellingPanel(true));
113 ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
114 contextMenuItemTagCheckSpelling());
115 ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
116 contextMenuItemTagCheckSpellingWhileTyping());
117 ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling,
118 contextMenuItemTagCheckGrammarWithSpelling());
119 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
120 ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically,
121 contextMenuItemTagCorrectSpellingAutomatically());
122 #endif
123
124 spellingAndGrammarMenu.appendItem(showSpellingPanel);
125 spellingAndGrammarMenu.appendItem(checkSpelling);
126 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
127 spellingAndGrammarMenu.appendItem(*separatorItem());
128 #endif
129 spellingAndGrammarMenu.appendItem(checkAsYouType);
130 spellingAndGrammarMenu.appendItem(grammarWithSpelling);
131 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
132 spellingAndGrammarMenu.appendItem(correctSpelling);
133 #endif
134
135 spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu);
136 }
137 #else
138
createAndAppendSpellingSubMenu(const HitTestResult & result,ContextMenuItem & spellingMenuItem)139 static void createAndAppendSpellingSubMenu(const HitTestResult& result, ContextMenuItem& spellingMenuItem)
140 {
141 ContextMenu spellingMenu(result);
142
143 ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel,
144 contextMenuItemTagShowSpellingPanel(true));
145 ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling,
146 contextMenuItemTagCheckSpelling());
147 ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping,
148 contextMenuItemTagCheckSpellingWhileTyping());
149
150 spellingMenu.appendItem(showSpellingPanel);
151 spellingMenu.appendItem(checkSpelling);
152 spellingMenu.appendItem(checkAsYouType);
153
154 spellingMenuItem.setSubMenu(&spellingMenu);
155 }
156 #endif
157
158 #if PLATFORM(MAC)
createAndAppendSpeechSubMenu(const HitTestResult & result,ContextMenuItem & speechMenuItem)159 static void createAndAppendSpeechSubMenu(const HitTestResult& result, ContextMenuItem& speechMenuItem)
160 {
161 ContextMenu speechMenu(result);
162
163 ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking());
164 ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking());
165
166 speechMenu.appendItem(start);
167 speechMenu.appendItem(stop);
168
169 speechMenuItem.setSubMenu(&speechMenu);
170 }
171 #endif
172
173 #if !PLATFORM(GTK)
createAndAppendWritingDirectionSubMenu(const HitTestResult & result,ContextMenuItem & writingDirectionMenuItem)174 static void createAndAppendWritingDirectionSubMenu(const HitTestResult& result, ContextMenuItem& writingDirectionMenuItem)
175 {
176 ContextMenu writingDirectionMenu(result);
177
178 ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection,
179 contextMenuItemTagDefaultDirection());
180 ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight());
181 ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft());
182
183 writingDirectionMenu.appendItem(defaultItem);
184 writingDirectionMenu.appendItem(ltr);
185 writingDirectionMenu.appendItem(rtl);
186
187 writingDirectionMenuItem.setSubMenu(&writingDirectionMenu);
188 }
189
createAndAppendTextDirectionSubMenu(const HitTestResult & result,ContextMenuItem & textDirectionMenuItem)190 static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, ContextMenuItem& textDirectionMenuItem)
191 {
192 ContextMenu textDirectionMenu(result);
193
194 ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection());
195 ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight());
196 ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft());
197
198 textDirectionMenu.appendItem(defaultItem);
199 textDirectionMenu.appendItem(ltr);
200 textDirectionMenu.appendItem(rtl);
201
202 textDirectionMenuItem.setSubMenu(&textDirectionMenu);
203 }
204 #endif
205
206 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
createAndAppendSubstitutionsSubMenu(const HitTestResult & result,ContextMenuItem & substitutionsMenuItem)207 static void createAndAppendSubstitutionsSubMenu(const HitTestResult& result, ContextMenuItem& substitutionsMenuItem)
208 {
209 ContextMenu substitutionsMenu(result);
210
211 ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true));
212 ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste());
213 ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes());
214 ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes());
215 ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks());
216 ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement());
217
218 substitutionsMenu.appendItem(showSubstitutions);
219 substitutionsMenu.appendItem(*separatorItem());
220 substitutionsMenu.appendItem(smartCopyPaste);
221 substitutionsMenu.appendItem(smartQuotes);
222 substitutionsMenu.appendItem(smartDashes);
223 substitutionsMenu.appendItem(smartLinks);
224 substitutionsMenu.appendItem(textReplacement);
225
226 substitutionsMenuItem.setSubMenu(&substitutionsMenu);
227 }
228
createAndAppendTransformationsSubMenu(const HitTestResult & result,ContextMenuItem & transformationsMenuItem)229 static void createAndAppendTransformationsSubMenu(const HitTestResult& result, ContextMenuItem& transformationsMenuItem)
230 {
231 ContextMenu transformationsMenu(result);
232
233 ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase());
234 ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase());
235 ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize());
236
237 transformationsMenu.appendItem(makeUpperCase);
238 transformationsMenu.appendItem(makeLowerCase);
239 transformationsMenu.appendItem(capitalize);
240
241 transformationsMenuItem.setSubMenu(&transformationsMenu);
242 }
243 #endif
244
selectionContainsPossibleWord(Frame * frame)245 static bool selectionContainsPossibleWord(Frame* frame)
246 {
247 // Current algorithm: look for a character that's not just a separator.
248 for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) {
249 int length = it.length();
250 const UChar* characters = it.characters();
251 for (int i = 0; i < length; ++i)
252 if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph)))
253 return true;
254 }
255 return false;
256 }
257
populate()258 void ContextMenu::populate()
259 {
260 ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink());
261 ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow,
262 contextMenuItemTagOpenLinkInNewWindow());
263 ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk,
264 contextMenuItemTagDownloadLinkToDisk());
265 ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard,
266 contextMenuItemTagCopyLinkToClipboard());
267 ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow,
268 contextMenuItemTagOpenImageInNewWindow());
269 ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk,
270 contextMenuItemTagDownloadImageToDisk());
271 ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard,
272 contextMenuItemTagCopyImageToClipboard());
273 #if PLATFORM(MAC)
274 ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight,
275 contextMenuItemTagSearchInSpotlight());
276 ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary,
277 contextMenuItemTagLookUpInDictionary());
278 #endif
279 #if !PLATFORM(GTK)
280 ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb());
281 #endif
282 ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy());
283 ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack());
284 ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward());
285 ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop());
286 ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload());
287 ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow,
288 contextMenuItemTagOpenFrameInNewWindow());
289 ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound,
290 contextMenuItemTagNoGuessesFound());
291 ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling,
292 contextMenuItemTagIgnoreSpelling());
293 ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling,
294 contextMenuItemTagLearnSpelling());
295 ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar,
296 contextMenuItemTagIgnoreGrammar());
297 ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut());
298 ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
299 #if PLATFORM(GTK)
300 ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
301 ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
302 #endif
303
304 HitTestResult result = hitTestResult();
305
306 Node* node = m_hitTestResult.innerNonSharedNode();
307 if (!node)
308 return;
309 #if PLATFORM(GTK)
310 if (!result.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
311 return;
312 #endif
313 Frame* frame = node->document()->frame();
314 if (!frame)
315 return;
316
317 if (!result.isContentEditable()) {
318 FrameLoader* loader = frame->loader();
319 KURL linkURL = result.absoluteLinkURL();
320 if (!linkURL.isEmpty()) {
321 if (loader->canHandleRequest(ResourceRequest(linkURL))) {
322 appendItem(OpenLinkItem);
323 appendItem(OpenLinkInNewWindowItem);
324 appendItem(DownloadFileItem);
325 }
326 appendItem(CopyLinkItem);
327 }
328
329 KURL imageURL = result.absoluteImageURL();
330 if (!imageURL.isEmpty()) {
331 if (!linkURL.isEmpty())
332 appendItem(*separatorItem());
333
334 appendItem(OpenImageInNewWindowItem);
335 appendItem(DownloadImageItem);
336 if (imageURL.isLocalFile() || m_hitTestResult.image())
337 appendItem(CopyImageItem);
338 }
339
340 if (imageURL.isEmpty() && linkURL.isEmpty()) {
341 if (result.isSelected()) {
342 if (selectionContainsPossibleWord(frame)) {
343 #if PLATFORM(MAC)
344 appendItem(SearchSpotlightItem);
345 #endif
346 #if !PLATFORM(GTK)
347 appendItem(SearchWebItem);
348 appendItem(*separatorItem());
349 #endif
350 #if PLATFORM(MAC)
351 appendItem(LookInDictionaryItem);
352 appendItem(*separatorItem());
353 #endif
354 }
355 appendItem(CopyItem);
356 #if PLATFORM(MAC)
357 appendItem(*separatorItem());
358 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
359 createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem);
360 appendItem(SpeechMenuItem);
361 #endif
362 } else {
363 #if PLATFORM(GTK)
364 appendItem(BackItem);
365 appendItem(ForwardItem);
366 appendItem(StopItem);
367 appendItem(ReloadItem);
368 #else
369 if (frame->page() && frame->page()->canGoBackOrForward(-1))
370 appendItem(BackItem);
371
372 if (frame->page() && frame->page()->canGoBackOrForward(1))
373 appendItem(ForwardItem);
374
375 // use isLoadingInAPISense rather than isLoading because Stop/Reload are
376 // intended to match WebKit's API, not WebCore's internal notion of loading status
377 if (loader->documentLoader()->isLoadingInAPISense())
378 appendItem(StopItem);
379 else
380 appendItem(ReloadItem);
381 #endif
382
383 if (frame->page() && frame != frame->page()->mainFrame())
384 appendItem(OpenFrameItem);
385 }
386 }
387 } else { // Make an editing context menu
388 SelectionController* selection = frame->selection();
389 bool inPasswordField = selection->isInPasswordField();
390
391 if (!inPasswordField) {
392 // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
393 // is never considered a misspelling and bad grammar at the same time)
394 bool misspelling;
395 bool badGrammar;
396 Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
397 if (misspelling || badGrammar) {
398 size_t size = guesses.size();
399 if (size == 0) {
400 // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
401 // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit)
402 if (misspelling) {
403 appendItem(NoGuessesItem);
404 appendItem(*separatorItem());
405 }
406 } else {
407 for (unsigned i = 0; i < size; i++) {
408 const String &guess = guesses[i];
409 if (!guess.isEmpty()) {
410 ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
411 appendItem(item);
412 }
413 }
414 appendItem(*separatorItem());
415 }
416
417 if (misspelling) {
418 appendItem(IgnoreSpellingItem);
419 appendItem(LearnSpellingItem);
420 } else
421 appendItem(IgnoreGrammarItem);
422 appendItem(*separatorItem());
423 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
424 } else {
425 // If the string was autocorrected, generate a contextual menu item allowing it to be changed back.
426 String replacedString = result.replacedString();
427 if (!replacedString.isEmpty()) {
428 ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString));
429 appendItem(item);
430 appendItem(*separatorItem());
431 }
432 #endif
433 }
434 }
435
436 FrameLoader* loader = frame->loader();
437 KURL linkURL = result.absoluteLinkURL();
438 if (!linkURL.isEmpty()) {
439 if (loader->canHandleRequest(ResourceRequest(linkURL))) {
440 appendItem(OpenLinkItem);
441 appendItem(OpenLinkInNewWindowItem);
442 appendItem(DownloadFileItem);
443 }
444 appendItem(CopyLinkItem);
445 appendItem(*separatorItem());
446 }
447
448 if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) {
449 #if PLATFORM(MAC)
450 appendItem(SearchSpotlightItem);
451 #endif
452 #if !PLATFORM(GTK)
453 appendItem(SearchWebItem);
454 appendItem(*separatorItem());
455 #endif
456
457 #if PLATFORM(MAC)
458 appendItem(LookInDictionaryItem);
459 appendItem(*separatorItem());
460 #endif
461 }
462
463 appendItem(CutItem);
464 appendItem(CopyItem);
465 appendItem(PasteItem);
466 #if PLATFORM(GTK)
467 appendItem(DeleteItem);
468 appendItem(*separatorItem());
469 appendItem(SelectAllItem);
470 #endif
471
472 if (!inPasswordField) {
473 appendItem(*separatorItem());
474 #ifndef BUILDING_ON_TIGER
475 #if !PLATFORM(GTK)
476 ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
477 contextMenuItemTagSpellingMenu());
478 createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem);
479 appendItem(SpellingAndGrammarMenuItem);
480 #endif
481 #else
482 ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu,
483 contextMenuItemTagSpellingMenu());
484 createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem);
485 appendItem(SpellingMenuItem);
486 #endif
487 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
488 ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu,
489 contextMenuItemTagSubstitutionsMenu());
490 createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem);
491 appendItem(substitutionsMenuItem);
492 ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu,
493 contextMenuItemTagTransformationsMenu());
494 createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem);
495 appendItem(transformationsMenuItem);
496 #endif
497 #if PLATFORM(GTK)
498 bool shouldShowFontMenu = frame->editor()->canEditRichly();
499 #else
500 bool shouldShowFontMenu = true;
501 #endif
502 if (shouldShowFontMenu) {
503 ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu,
504 contextMenuItemTagFontMenu());
505 createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem);
506 appendItem(FontMenuItem);
507 }
508 #if PLATFORM(MAC)
509 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
510 createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem);
511 appendItem(SpeechMenuItem);
512 #endif
513 #if !PLATFORM(GTK)
514 ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu,
515 contextMenuItemTagWritingDirectionMenu());
516 createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem);
517 appendItem(WritingDirectionMenuItem);
518 if (Page* page = frame->page()) {
519 if (Settings* settings = page->settings()) {
520 bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
521 || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
522 if (includeTextDirectionSubmenu) {
523 ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu,
524 contextMenuItemTagTextDirectionMenu());
525 createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem);
526 appendItem(TextDirectionMenuItem);
527 }
528 }
529 }
530 #endif
531 }
532 }
533 }
534
535 #if ENABLE(INSPECTOR)
addInspectElementItem()536 void ContextMenu::addInspectElementItem()
537 {
538 Node* node = m_hitTestResult.innerNonSharedNode();
539 if (!node)
540 return;
541
542 Frame* frame = node->document()->frame();
543 if (!frame)
544 return;
545
546 Page* page = frame->page();
547 if (!page)
548 return;
549
550 if (!page->inspectorController())
551 return;
552
553 ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement());
554 appendItem(*separatorItem());
555 appendItem(InspectElementItem);
556 }
557 #endif // ENABLE(INSPECTOR)
558
checkOrEnableIfNeeded(ContextMenuItem & item) const559 void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const
560 {
561 if (item.type() == SeparatorType)
562 return;
563
564 Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
565 if (!frame)
566 return;
567
568 bool shouldEnable = true;
569 bool shouldCheck = false;
570
571 switch (item.action()) {
572 case ContextMenuItemTagCheckSpelling:
573 shouldEnable = frame->editor()->canEdit();
574 break;
575 case ContextMenuItemTagDefaultDirection:
576 shouldCheck = false;
577 shouldEnable = false;
578 break;
579 case ContextMenuItemTagLeftToRight:
580 case ContextMenuItemTagRightToLeft: {
581 ExceptionCode ec = 0;
582 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
583 String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
584 style->setProperty(CSSPropertyDirection, direction, false, ec);
585 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
586 shouldEnable = true;
587 break;
588 }
589 case ContextMenuItemTagTextDirectionDefault: {
590 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural");
591 shouldCheck = command.state() == TrueTriState;
592 shouldEnable = command.isEnabled();
593 break;
594 }
595 case ContextMenuItemTagTextDirectionLeftToRight: {
596 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight");
597 shouldCheck = command.state() == TrueTriState;
598 shouldEnable = command.isEnabled();
599 break;
600 }
601 case ContextMenuItemTagTextDirectionRightToLeft: {
602 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft");
603 shouldCheck = command.state() == TrueTriState;
604 shouldEnable = command.isEnabled();
605 break;
606 }
607 case ContextMenuItemTagCopy:
608 shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
609 break;
610 case ContextMenuItemTagCut:
611 shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut();
612 break;
613 case ContextMenuItemTagIgnoreSpelling:
614 case ContextMenuItemTagLearnSpelling:
615 shouldEnable = frame->selection()->isRange();
616 break;
617 case ContextMenuItemTagPaste:
618 shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste();
619 break;
620 #if PLATFORM(GTK)
621 case ContextMenuItemTagDelete:
622 shouldEnable = frame->editor()->canDelete();
623 break;
624 case ContextMenuItemTagSelectAll:
625 case ContextMenuItemTagInputMethods:
626 case ContextMenuItemTagUnicode:
627 shouldEnable = true;
628 break;
629 #endif
630 case ContextMenuItemTagUnderline: {
631 ExceptionCode ec = 0;
632 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
633 style->setProperty(CSSPropertyWebkitTextDecorationsInEffect, "underline", false, ec);
634 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
635 shouldEnable = frame->editor()->canEditRichly();
636 break;
637 }
638 case ContextMenuItemTagLookUpInDictionary:
639 shouldEnable = frame->selection()->isRange();
640 break;
641 case ContextMenuItemTagCheckGrammarWithSpelling:
642 #ifndef BUILDING_ON_TIGER
643 if (frame->editor()->isGrammarCheckingEnabled())
644 shouldCheck = true;
645 shouldEnable = true;
646 #endif
647 break;
648 case ContextMenuItemTagItalic: {
649 ExceptionCode ec = 0;
650 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
651 style->setProperty(CSSPropertyFontStyle, "italic", false, ec);
652 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
653 shouldEnable = frame->editor()->canEditRichly();
654 break;
655 }
656 case ContextMenuItemTagBold: {
657 ExceptionCode ec = 0;
658 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration();
659 style->setProperty(CSSPropertyFontWeight, "bold", false, ec);
660 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState;
661 shouldEnable = frame->editor()->canEditRichly();
662 break;
663 }
664 case ContextMenuItemTagOutline:
665 shouldEnable = false;
666 break;
667 case ContextMenuItemTagShowSpellingPanel:
668 #ifndef BUILDING_ON_TIGER
669 if (frame->editor()->spellingPanelIsShowing())
670 item.setTitle(contextMenuItemTagShowSpellingPanel(false));
671 else
672 item.setTitle(contextMenuItemTagShowSpellingPanel(true));
673 #endif
674 shouldEnable = frame->editor()->canEdit();
675 break;
676 case ContextMenuItemTagNoGuessesFound:
677 shouldEnable = false;
678 break;
679 case ContextMenuItemTagCheckSpellingWhileTyping:
680 shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled();
681 break;
682 #if PLATFORM(MAC)
683 case ContextMenuItemTagSubstitutionsMenu:
684 case ContextMenuItemTagTransformationsMenu:
685 break;
686 case ContextMenuItemTagShowSubstitutions:
687 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
688 if (frame->editor()->substitutionsPanelIsShowing())
689 item.setTitle(contextMenuItemTagShowSubstitutions(false));
690 else
691 item.setTitle(contextMenuItemTagShowSubstitutions(true));
692 shouldEnable = frame->editor()->canEdit();
693 #endif
694 break;
695 case ContextMenuItemTagMakeUpperCase:
696 case ContextMenuItemTagMakeLowerCase:
697 case ContextMenuItemTagCapitalize:
698 case ContextMenuItemTagChangeBack:
699 shouldEnable = frame->editor()->canEdit();
700 break;
701 case ContextMenuItemTagCorrectSpellingAutomatically:
702 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
703 shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled();
704 #endif
705 break;
706 case ContextMenuItemTagSmartCopyPaste:
707 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
708 shouldCheck = frame->editor()->smartInsertDeleteEnabled();
709 #endif
710 break;
711 case ContextMenuItemTagSmartQuotes:
712 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
713 shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled();
714 #endif
715 break;
716 case ContextMenuItemTagSmartDashes:
717 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
718 shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled();
719 #endif
720 break;
721 case ContextMenuItemTagSmartLinks:
722 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
723 shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled();
724 #endif
725 break;
726 case ContextMenuItemTagTextReplacement:
727 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD)
728 shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled();
729 #endif
730 break;
731 case ContextMenuItemTagStopSpeaking:
732 shouldEnable = controller() && controller()->client() && controller()->client()->isSpeaking();
733 break;
734 #else // PLATFORM(MAC) ends here
735 case ContextMenuItemTagStopSpeaking:
736 break;
737 #endif
738 #if PLATFORM(GTK)
739 case ContextMenuItemTagGoBack:
740 shouldEnable = frame->page() && frame->page()->canGoBackOrForward(-1);
741 break;
742 case ContextMenuItemTagGoForward:
743 shouldEnable = frame->page() && frame->page()->canGoBackOrForward(1);
744 break;
745 case ContextMenuItemTagStop:
746 shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense();
747 break;
748 case ContextMenuItemTagReload:
749 shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense();
750 break;
751 case ContextMenuItemTagFontMenu:
752 shouldEnable = frame->editor()->canEditRichly();
753 break;
754 #else
755 case ContextMenuItemTagGoBack:
756 case ContextMenuItemTagGoForward:
757 case ContextMenuItemTagStop:
758 case ContextMenuItemTagReload:
759 case ContextMenuItemTagFontMenu:
760 #endif
761 case ContextMenuItemTagNoAction:
762 case ContextMenuItemTagOpenLinkInNewWindow:
763 case ContextMenuItemTagDownloadLinkToDisk:
764 case ContextMenuItemTagCopyLinkToClipboard:
765 case ContextMenuItemTagOpenImageInNewWindow:
766 case ContextMenuItemTagDownloadImageToDisk:
767 case ContextMenuItemTagCopyImageToClipboard:
768 case ContextMenuItemTagOpenFrameInNewWindow:
769 case ContextMenuItemTagSpellingGuess:
770 case ContextMenuItemTagOther:
771 case ContextMenuItemTagSearchInSpotlight:
772 case ContextMenuItemTagSearchWeb:
773 case ContextMenuItemTagOpenWithDefaultApplication:
774 case ContextMenuItemPDFActualSize:
775 case ContextMenuItemPDFZoomIn:
776 case ContextMenuItemPDFZoomOut:
777 case ContextMenuItemPDFAutoSize:
778 case ContextMenuItemPDFSinglePage:
779 case ContextMenuItemPDFFacingPages:
780 case ContextMenuItemPDFContinuous:
781 case ContextMenuItemPDFNextPage:
782 case ContextMenuItemPDFPreviousPage:
783 case ContextMenuItemTagOpenLink:
784 case ContextMenuItemTagIgnoreGrammar:
785 case ContextMenuItemTagSpellingMenu:
786 case ContextMenuItemTagShowFonts:
787 case ContextMenuItemTagStyles:
788 case ContextMenuItemTagShowColors:
789 case ContextMenuItemTagSpeechMenu:
790 case ContextMenuItemTagStartSpeaking:
791 case ContextMenuItemTagWritingDirectionMenu:
792 case ContextMenuItemTagTextDirectionMenu:
793 case ContextMenuItemTagPDFSinglePageScrolling:
794 case ContextMenuItemTagPDFFacingPagesScrolling:
795 #if ENABLE(INSPECTOR)
796 case ContextMenuItemTagInspectElement:
797 #endif
798 case ContextMenuItemBaseCustomTag:
799 case ContextMenuItemBaseApplicationTag:
800 break;
801 }
802
803 item.setChecked(shouldCheck);
804 item.setEnabled(shouldEnable);
805 }
806
807 } // namespace WebCore
808
809 #endif // ENABLE(CONTEXT_MENUS)
810