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