upload webkit/tizen 2.0_beta source.
[framework/web/webkit-efl.git] / Source / WebCore / page / ContextMenuController.cpp
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 "FrameLoaderClient.h"
51 #include "FrameSelection.h"
52 #include "HTMLFormElement.h"
53 #include "HitTestRequest.h"
54 #include "HitTestResult.h"
55 #include "InspectorController.h"
56 #include "LocalizedStrings.h"
57 #include "MouseEvent.h"
58 #include "NavigationAction.h"
59 #include "Node.h"
60 #include "Page.h"
61 #include "PlatformEvent.h"
62 #include "RenderObject.h"
63 #include "ReplaceSelectionCommand.h"
64 #include "ResourceRequest.h"
65 #include "Settings.h"
66 #include "TextIterator.h"
67 #include "TypingCommand.h"
68 #include "UserTypingGestureIndicator.h"
69 #include "WindowFeatures.h"
70 #include "markup.h"
71 #include <wtf/unicode/Unicode.h>
72
73 #if PLATFORM(GTK)
74 #include <wtf/gobject/GOwnPtr.h>
75 #endif
76
77 using namespace WTF;
78 using namespace Unicode;
79
80 namespace WebCore {
81
82 ContextMenuController::ContextMenuController(Page* page, ContextMenuClient* client)
83     : m_page(page)
84     , m_client(client)
85 {
86     ASSERT_ARG(page, page);
87     ASSERT_ARG(client, client);
88 }
89
90 ContextMenuController::~ContextMenuController()
91 {
92 #if ENABLE(TIZEN_CONTEXT_MENU)
93     //this fixes a bug which occured when WebKit was shut down if a context menu was active
94     //then ContextMenuController destructor was calling:
95     //- first m_client->contextMenuDestroyed which destroyed the m_client object explicitly and then
96     //- and then m_contextMenu implicitily
97     //m_contextMenu destructor was then trying to call freePlatformDescription on m_contextMenuClient
98     //which was already destroyed
99     if (contextMenu() && contextMenu()->platformDescription()) {
100         m_client->freePlatformDescription(contextMenu()->platformDescription());
101         contextMenu()->setPlatformDescription(0);
102     }
103 #endif
104     m_client->contextMenuDestroyed();
105 }
106
107 PassOwnPtr<ContextMenuController> ContextMenuController::create(Page* page, ContextMenuClient* client)
108 {
109     return adoptPtr(new ContextMenuController(page, client));
110 }
111
112 void ContextMenuController::clearContextMenu()
113 {
114     m_contextMenu.clear();
115     if (m_menuProvider)
116         m_menuProvider->contextMenuCleared();
117     m_menuProvider = 0;
118 }
119
120 void ContextMenuController::handleContextMenuEvent(Event* event)
121 {
122     m_contextMenu = createContextMenu(event);
123     if (!m_contextMenu)
124         return;
125
126     populate();
127
128     showContextMenu(event);
129 }
130
131 static PassOwnPtr<ContextMenuItem> separatorItem()
132 {
133     return adoptPtr(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String()));
134 }
135
136 void ContextMenuController::showContextMenu(Event* event, PassRefPtr<ContextMenuProvider> menuProvider)
137 {
138     m_menuProvider = menuProvider;
139
140     m_contextMenu = createContextMenu(event);
141     if (!m_contextMenu) {
142         clearContextMenu();
143         return;
144     }
145
146     m_menuProvider->populateContextMenu(m_contextMenu.get());
147     if (m_hitTestResult.isSelected()) {
148         appendItem(*separatorItem(), m_contextMenu.get());
149         populate();
150     }
151     showContextMenu(event);
152 }
153
154 PassOwnPtr<ContextMenu> ContextMenuController::createContextMenu(Event* event)
155 {
156     if (!event->isMouseEvent())
157         return nullptr;
158
159     MouseEvent* mouseEvent = static_cast<MouseEvent*>(event);
160     HitTestResult result(mouseEvent->absoluteLocation());
161
162     if (Frame* frame = event->target()->toNode()->document()->frame())
163         result = frame->eventHandler()->hitTestResultAtPoint(mouseEvent->absoluteLocation(), false);
164
165     if (!result.innerNonSharedNode())
166         return nullptr;
167
168     m_hitTestResult = result;
169
170 #if ENABLE(TIZEN_CONTEXT_MENU)
171     return adoptPtr(new ContextMenu(result));
172 #else
173     return adoptPtr(new ContextMenu);
174 #endif
175 }
176
177 void ContextMenuController::showContextMenu(Event* event)
178 {
179 #if ENABLE(INSPECTOR) && !ENABLE(TIZEN_CONTEXT_MENU)
180     if (m_page->inspectorController()->enabled())
181         addInspectElementItem();
182 #endif
183
184 #if USE(CROSS_PLATFORM_CONTEXT_MENUS)
185     m_contextMenu = m_client->customizeMenu(m_contextMenu.release());
186 #else
187     PlatformMenuDescription customMenu = m_client->getCustomMenuFromDefaultItems(m_contextMenu.get());
188     m_contextMenu->setPlatformDescription(customMenu);
189 #endif
190     event->setDefaultHandled();
191 }
192
193 static void openNewWindow(const KURL& urlToLoad, Frame* frame)
194 {
195     if (Page* oldPage = frame->page()) {
196         FrameLoadRequest request(frame->document()->securityOrigin(), ResourceRequest(urlToLoad, frame->loader()->outgoingReferrer()));
197         if (Page* newPage = oldPage->chrome()->createWindow(frame, request, WindowFeatures(), NavigationAction(request.resourceRequest()))) {
198             newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, MaybeSendReferrer);
199             newPage->chrome()->show();
200         }
201     }
202 }
203
204 #if PLATFORM(GTK)
205 static void insertUnicodeCharacter(UChar character, Frame* frame)
206 {
207     String text(&character, 1);
208     if (!frame->editor()->shouldInsertText(text, frame->selection()->toNormalizedRange().get(), EditorInsertActionTyped))
209         return;
210
211     TypingCommand::insertText(frame->document(), text, 0, TypingCommand::TextCompositionNone);
212 }
213 #endif
214
215 void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item)
216 {
217     ASSERT(item->type() == ActionType || item->type() == CheckableActionType);
218
219     if (item->action() >= ContextMenuItemBaseApplicationTag) {
220         m_client->contextMenuItemSelected(item, m_contextMenu.get());
221         return;
222     }
223
224     if (item->action() >= ContextMenuItemBaseCustomTag) {
225         ASSERT(m_menuProvider);
226         m_menuProvider->contextMenuItemSelected(item);
227         return;
228     }
229
230     Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
231     if (!frame)
232         return;
233
234 #if ENABLE(TIZEN_WEBKIT_PASTEBOARD)
235     if (Page* page = frame->page()) {
236         if (item->action() == ContextMenuItemTagCopyLinkToClipboard
237             || item->action() == ContextMenuItemTagCopyImageToClipboard
238             || item->action() == ContextMenuItemTagCopyImageUrlToClipboard
239             || item->action() == ContextMenuItemTagCopyMediaLinkToClipboard
240             || item->action() == ContextMenuItemTagCopy)
241             Pasteboard::generalPasteboard()->setPage(page);
242     }
243 #endif
244
245     switch (item->action()) {
246     case ContextMenuItemTagOpenLinkInNewWindow:
247         openNewWindow(m_hitTestResult.absoluteLinkURL(), frame);
248         break;
249     case ContextMenuItemTagDownloadLinkToDisk:
250         // FIXME: Some day we should be able to do this from within WebCore.
251         m_client->downloadURL(m_hitTestResult.absoluteLinkURL());
252         break;
253     case ContextMenuItemTagCopyLinkToClipboard:
254         frame->editor()->copyURL(m_hitTestResult.absoluteLinkURL(), m_hitTestResult.textContent());
255         break;
256     case ContextMenuItemTagOpenImageInNewWindow:
257         openNewWindow(m_hitTestResult.absoluteImageURL(), frame);
258         break;
259     case ContextMenuItemTagDownloadImageToDisk:
260         // FIXME: Some day we should be able to do this from within WebCore.
261 #if ENABLE(TIZEN_INSTALL_CONTENT)
262         m_client->saveAsImage(m_contextMenu.get(), frame, m_hitTestResult.absoluteImageURL());
263 #else
264         m_client->downloadURL(m_hitTestResult.absoluteImageURL());
265 #endif
266         break;
267 #if ENABLE(TIZEN_INSTALL_CONTENT)
268     case ContextMenuItemTagSendImageViaEmail:
269         m_client->sendImageViaEmail(m_contextMenu.get(), frame, m_hitTestResult.absoluteImageURL());
270         break;
271     case ContextMenuItemTagSendImageViaMessage:
272         m_client->sendImageViaMessage(m_contextMenu.get(), frame, m_hitTestResult.absoluteImageURL());
273         break;
274 #endif
275     case ContextMenuItemTagCopyImageToClipboard:
276         // FIXME: The Pasteboard class is not written yet
277         // For now, call into the client. This is temporary!
278         frame->editor()->copyImage(m_hitTestResult);
279         break;
280 #if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
281     case ContextMenuItemTagCopyImageUrlToClipboard:
282         frame->editor()->copyURL(m_hitTestResult.absoluteImageURL(), m_hitTestResult.textContent());
283         break;
284 #endif
285     case ContextMenuItemTagOpenMediaInNewWindow:
286         openNewWindow(m_hitTestResult.absoluteMediaURL(), frame);
287         break;
288     case ContextMenuItemTagCopyMediaLinkToClipboard:
289         frame->editor()->copyURL(m_hitTestResult.absoluteMediaURL(), m_hitTestResult.textContent());
290         break;
291     case ContextMenuItemTagToggleMediaControls:
292         m_hitTestResult.toggleMediaControlsDisplay();
293         break;
294     case ContextMenuItemTagToggleMediaLoop:
295         m_hitTestResult.toggleMediaLoopPlayback();
296         break;
297     case ContextMenuItemTagEnterVideoFullscreen:
298         m_hitTestResult.enterFullscreenForVideo();
299         break;
300     case ContextMenuItemTagMediaPlayPause:
301         m_hitTestResult.toggleMediaPlayState();
302         break;
303     case ContextMenuItemTagMediaMute:
304         m_hitTestResult.toggleMediaMuteState();
305         break;
306     case ContextMenuItemTagOpenFrameInNewWindow: {
307         DocumentLoader* loader = frame->loader()->documentLoader();
308         if (!loader->unreachableURL().isEmpty())
309             openNewWindow(loader->unreachableURL(), frame);
310         else
311             openNewWindow(loader->url(), frame);
312         break;
313     }
314     case ContextMenuItemTagCopy:
315         frame->editor()->copy();
316         break;
317     case ContextMenuItemTagGoBack:
318         if (Page* page = frame->page())
319             page->backForward()->goBackOrForward(-1);
320         break;
321     case ContextMenuItemTagGoForward:
322         if (Page* page = frame->page())
323             page->backForward()->goBackOrForward(1);
324         break;
325     case ContextMenuItemTagStop:
326         frame->loader()->stop();
327         break;
328     case ContextMenuItemTagReload:
329         frame->loader()->reload();
330         break;
331     case ContextMenuItemTagCut:
332         frame->editor()->command("Cut").execute();
333         break;
334     case ContextMenuItemTagPaste:
335         frame->editor()->command("Paste").execute();
336         break;
337 #if PLATFORM(GTK)
338     case ContextMenuItemTagDelete:
339         frame->editor()->performDelete();
340         break;
341     case ContextMenuItemTagUnicodeInsertLRMMark:
342         insertUnicodeCharacter(leftToRightMark, frame);
343         break;
344     case ContextMenuItemTagUnicodeInsertRLMMark:
345         insertUnicodeCharacter(rightToLeftMark, frame);
346         break;
347     case ContextMenuItemTagUnicodeInsertLREMark:
348         insertUnicodeCharacter(leftToRightEmbed, frame);
349         break;
350     case ContextMenuItemTagUnicodeInsertRLEMark:
351         insertUnicodeCharacter(rightToLeftEmbed, frame);
352         break;
353     case ContextMenuItemTagUnicodeInsertLROMark:
354         insertUnicodeCharacter(leftToRightOverride, frame);
355         break;
356     case ContextMenuItemTagUnicodeInsertRLOMark:
357         insertUnicodeCharacter(rightToLeftOverride, frame);
358         break;
359     case ContextMenuItemTagUnicodeInsertPDFMark:
360         insertUnicodeCharacter(popDirectionalFormatting, frame);
361         break;
362     case ContextMenuItemTagUnicodeInsertZWSMark:
363         insertUnicodeCharacter(zeroWidthSpace, frame);
364         break;
365     case ContextMenuItemTagUnicodeInsertZWJMark:
366         insertUnicodeCharacter(zeroWidthJoiner, frame);
367         break;
368     case ContextMenuItemTagUnicodeInsertZWNJMark:
369         insertUnicodeCharacter(zeroWidthNonJoiner, frame);
370         break;
371 #endif
372 #if PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(EFL)
373     case ContextMenuItemTagSelectAll:
374         frame->editor()->command("SelectAll").execute();
375         break;
376 #endif
377 #if ENABLE(TIZEN_CONTEXT_MENU_SELECT)
378     case ContextMenuItemTagSelectWord:
379         frame->editor()->command("SelectWord").execute();
380         break;
381 #endif
382     case ContextMenuItemTagSpellingGuess:
383         ASSERT(frame->editor()->selectedText().length());
384         if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) {
385             Document* document = frame->document();
386             RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), ReplaceSelectionCommand::SelectReplacement | ReplaceSelectionCommand::MatchStyle | ReplaceSelectionCommand::PreventNesting);
387             applyCommand(command);
388             frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded);
389         }
390         break;
391     case ContextMenuItemTagIgnoreSpelling:
392         frame->editor()->ignoreSpelling();
393         break;
394     case ContextMenuItemTagLearnSpelling:
395         frame->editor()->learnSpelling();
396         break;
397     case ContextMenuItemTagSearchWeb:
398         m_client->searchWithGoogle(frame);
399         break;
400     case ContextMenuItemTagLookUpInDictionary:
401         // FIXME: Some day we may be able to do this from within WebCore.
402         m_client->lookUpInDictionary(frame);
403         break;
404     case ContextMenuItemTagOpenLink:
405         if (Frame* targetFrame = m_hitTestResult.targetFrame())
406             targetFrame->loader()->loadFrameRequest(FrameLoadRequest(frame->document()->securityOrigin(), ResourceRequest(m_hitTestResult.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, MaybeSendReferrer);
407         else
408             openNewWindow(m_hitTestResult.absoluteLinkURL(), frame);
409         break;
410     case ContextMenuItemTagBold:
411         frame->editor()->command("ToggleBold").execute();
412         break;
413     case ContextMenuItemTagItalic:
414         frame->editor()->command("ToggleItalic").execute();
415         break;
416     case ContextMenuItemTagUnderline:
417         frame->editor()->toggleUnderline();
418         break;
419     case ContextMenuItemTagOutline:
420         // We actually never enable this because CSS does not have a way to specify an outline font,
421         // which may make this difficult to implement. Maybe a special case of text-shadow?
422         break;
423     case ContextMenuItemTagStartSpeaking: {
424         ExceptionCode ec;
425         RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange();
426         if (!selectedRange || selectedRange->collapsed(ec)) {
427             Document* document = m_hitTestResult.innerNonSharedNode()->document();
428             selectedRange = document->createRange();
429             selectedRange->selectNode(document->documentElement(), ec);
430         }
431         m_client->speak(plainText(selectedRange.get()));
432         break;
433     }
434     case ContextMenuItemTagStopSpeaking:
435         m_client->stopSpeaking();
436         break;
437     case ContextMenuItemTagDefaultDirection:
438         frame->editor()->setBaseWritingDirection(NaturalWritingDirection);
439         break;
440     case ContextMenuItemTagLeftToRight:
441         frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection);
442         break;
443     case ContextMenuItemTagRightToLeft:
444         frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection);
445         break;
446     case ContextMenuItemTagTextDirectionDefault:
447         frame->editor()->command("MakeTextWritingDirectionNatural").execute();
448         break;
449     case ContextMenuItemTagTextDirectionLeftToRight:
450         frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute();
451         break;
452     case ContextMenuItemTagTextDirectionRightToLeft:
453         frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute();
454         break;
455 #if PLATFORM(MAC)
456     case ContextMenuItemTagSearchInSpotlight:
457         m_client->searchWithSpotlight();
458         break;
459 #endif
460     case ContextMenuItemTagShowSpellingPanel:
461         frame->editor()->showSpellingGuessPanel();
462         break;
463     case ContextMenuItemTagCheckSpelling:
464         frame->editor()->advanceToNextMisspelling();
465         break;
466     case ContextMenuItemTagCheckSpellingWhileTyping:
467         frame->editor()->toggleContinuousSpellChecking();
468         break;
469     case ContextMenuItemTagCheckGrammarWithSpelling:
470         frame->editor()->toggleGrammarChecking();
471         break;
472 #if PLATFORM(MAC)
473     case ContextMenuItemTagShowFonts:
474         frame->editor()->showFontPanel();
475         break;
476     case ContextMenuItemTagStyles:
477         frame->editor()->showStylesPanel();
478         break;
479     case ContextMenuItemTagShowColors:
480         frame->editor()->showColorPanel();
481         break;
482 #endif
483 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
484     case ContextMenuItemTagMakeUpperCase:
485         frame->editor()->uppercaseWord();
486         break;
487     case ContextMenuItemTagMakeLowerCase:
488         frame->editor()->lowercaseWord();
489         break;
490     case ContextMenuItemTagCapitalize:
491         frame->editor()->capitalizeWord();
492         break;
493     case ContextMenuItemTagShowSubstitutions:
494         frame->editor()->showSubstitutionsPanel();
495         break;
496     case ContextMenuItemTagSmartCopyPaste:
497         frame->editor()->toggleSmartInsertDelete();
498         break;
499     case ContextMenuItemTagSmartQuotes:
500         frame->editor()->toggleAutomaticQuoteSubstitution();
501         break;
502     case ContextMenuItemTagSmartDashes:
503         frame->editor()->toggleAutomaticDashSubstitution();
504         break;
505     case ContextMenuItemTagSmartLinks:
506         frame->editor()->toggleAutomaticLinkDetection();
507         break;
508     case ContextMenuItemTagTextReplacement:
509         frame->editor()->toggleAutomaticTextReplacement();
510         break;
511     case ContextMenuItemTagCorrectSpellingAutomatically:
512         frame->editor()->toggleAutomaticSpellingCorrection();
513         break;
514     case ContextMenuItemTagChangeBack:
515         frame->editor()->changeBackToReplacedString(m_hitTestResult.replacedString());
516         break;
517 #endif
518 #if ENABLE(INSPECTOR)
519     case ContextMenuItemTagInspectElement:
520         if (Page* page = frame->page())
521             page->inspectorController()->inspect(m_hitTestResult.innerNonSharedNode());
522         break;
523 #endif
524     default:
525         break;
526     }
527 }
528
529 void ContextMenuController::appendItem(ContextMenuItem& menuItem, ContextMenu* parentMenu)
530 {
531     checkOrEnableIfNeeded(menuItem);
532     if (parentMenu)
533         parentMenu->appendItem(menuItem);
534 }
535
536 void ContextMenuController::createAndAppendFontSubMenu(ContextMenuItem& fontMenuItem)
537 {
538     ContextMenu fontMenu;
539
540 #if PLATFORM(MAC)
541     ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts());
542 #endif
543     ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold());
544     ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic());
545     ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline());
546     ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline());
547 #if PLATFORM(MAC)
548     ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles());
549     ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors());
550 #endif
551
552 #if PLATFORM(MAC)
553     appendItem(showFonts, &fontMenu);
554 #endif
555     appendItem(bold, &fontMenu);
556     appendItem(italic, &fontMenu);
557     appendItem(underline, &fontMenu);
558     appendItem(outline, &fontMenu);
559 #if PLATFORM(MAC)
560     appendItem(styles, &fontMenu);
561     appendItem(*separatorItem(), &fontMenu);
562     appendItem(showColors, &fontMenu);
563 #endif
564
565     fontMenuItem.setSubMenu(&fontMenu);
566 }
567
568
569 #if !PLATFORM(GTK)
570
571 void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem)
572 {
573     ContextMenu spellingAndGrammarMenu;
574
575     ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, 
576         contextMenuItemTagShowSpellingPanel(true));
577     ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, 
578         contextMenuItemTagCheckSpelling());
579     ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, 
580         contextMenuItemTagCheckSpellingWhileTyping());
581     ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling, 
582         contextMenuItemTagCheckGrammarWithSpelling());
583 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
584     ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically, 
585         contextMenuItemTagCorrectSpellingAutomatically());
586 #endif
587
588     appendItem(showSpellingPanel, &spellingAndGrammarMenu);
589     appendItem(checkSpelling, &spellingAndGrammarMenu);
590 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
591     appendItem(*separatorItem(), &spellingAndGrammarMenu);
592 #endif
593     appendItem(checkAsYouType, &spellingAndGrammarMenu);
594     appendItem(grammarWithSpelling, &spellingAndGrammarMenu);
595 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
596     appendItem(correctSpelling, &spellingAndGrammarMenu);
597 #endif
598
599     spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu);
600 }
601
602 #endif // !PLATFORM(GTK)
603
604
605 #if PLATFORM(MAC)
606
607 void ContextMenuController::createAndAppendSpeechSubMenu(ContextMenuItem& speechMenuItem)
608 {
609     ContextMenu speechMenu;
610
611     ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking());
612     ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking());
613
614     appendItem(start, &speechMenu);
615     appendItem(stop, &speechMenu);
616
617     speechMenuItem.setSubMenu(&speechMenu);
618 }
619
620 #endif
621  
622 #if PLATFORM(GTK)
623
624 void ContextMenuController::createAndAppendUnicodeSubMenu(ContextMenuItem& unicodeMenuItem)
625 {
626     ContextMenu unicodeMenu;
627
628     ContextMenuItem leftToRightMarkMenuItem(ActionType, ContextMenuItemTagUnicodeInsertLRMMark, contextMenuItemTagUnicodeInsertLRMMark());
629     ContextMenuItem rightToLeftMarkMenuItem(ActionType, ContextMenuItemTagUnicodeInsertRLMMark, contextMenuItemTagUnicodeInsertRLMMark());
630     ContextMenuItem leftToRightEmbedMenuItem(ActionType, ContextMenuItemTagUnicodeInsertLREMark, contextMenuItemTagUnicodeInsertLREMark());
631     ContextMenuItem rightToLeftEmbedMenuItem(ActionType, ContextMenuItemTagUnicodeInsertRLEMark, contextMenuItemTagUnicodeInsertRLEMark());
632     ContextMenuItem leftToRightOverrideMenuItem(ActionType, ContextMenuItemTagUnicodeInsertLROMark, contextMenuItemTagUnicodeInsertLROMark());
633     ContextMenuItem rightToLeftOverrideMenuItem(ActionType, ContextMenuItemTagUnicodeInsertRLOMark, contextMenuItemTagUnicodeInsertRLOMark());
634     ContextMenuItem popDirectionalFormattingMenuItem(ActionType, ContextMenuItemTagUnicodeInsertPDFMark, contextMenuItemTagUnicodeInsertPDFMark());
635     ContextMenuItem zeroWidthSpaceMenuItem(ActionType, ContextMenuItemTagUnicodeInsertZWSMark, contextMenuItemTagUnicodeInsertZWSMark());
636     ContextMenuItem zeroWidthJoinerMenuItem(ActionType, ContextMenuItemTagUnicodeInsertZWJMark, contextMenuItemTagUnicodeInsertZWJMark());
637     ContextMenuItem zeroWidthNonJoinerMenuItem(ActionType, ContextMenuItemTagUnicodeInsertZWNJMark, contextMenuItemTagUnicodeInsertZWNJMark());
638
639     appendItem(leftToRightMarkMenuItem, &unicodeMenu);
640     appendItem(rightToLeftMarkMenuItem, &unicodeMenu);
641     appendItem(leftToRightEmbedMenuItem, &unicodeMenu);
642     appendItem(rightToLeftEmbedMenuItem, &unicodeMenu);
643     appendItem(leftToRightOverrideMenuItem, &unicodeMenu);
644     appendItem(rightToLeftOverrideMenuItem, &unicodeMenu);
645     appendItem(popDirectionalFormattingMenuItem, &unicodeMenu);
646     appendItem(zeroWidthSpaceMenuItem, &unicodeMenu);
647     appendItem(zeroWidthJoinerMenuItem, &unicodeMenu);
648     appendItem(zeroWidthNonJoinerMenuItem, &unicodeMenu);
649
650     unicodeMenuItem.setSubMenu(&unicodeMenu);
651 }
652
653 #else
654
655 void ContextMenuController::createAndAppendWritingDirectionSubMenu(ContextMenuItem& writingDirectionMenuItem)
656 {
657     ContextMenu writingDirectionMenu;
658
659     ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection, 
660         contextMenuItemTagDefaultDirection());
661     ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight());
662     ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft());
663
664     appendItem(defaultItem, &writingDirectionMenu);
665     appendItem(ltr, &writingDirectionMenu);
666     appendItem(rtl, &writingDirectionMenu);
667
668     writingDirectionMenuItem.setSubMenu(&writingDirectionMenu);
669 }
670
671 void ContextMenuController::createAndAppendTextDirectionSubMenu(ContextMenuItem& textDirectionMenuItem)
672 {
673     ContextMenu textDirectionMenu;
674
675     ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection());
676     ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight());
677     ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft());
678
679     appendItem(defaultItem, &textDirectionMenu);
680     appendItem(ltr, &textDirectionMenu);
681     appendItem(rtl, &textDirectionMenu);
682
683     textDirectionMenuItem.setSubMenu(&textDirectionMenu);
684 }
685
686 #endif
687
688 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
689
690 void ContextMenuController::createAndAppendSubstitutionsSubMenu(ContextMenuItem& substitutionsMenuItem)
691 {
692     ContextMenu substitutionsMenu;
693
694     ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true));
695     ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste());
696     ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes());
697     ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes());
698     ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks());
699     ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement());
700
701     appendItem(showSubstitutions, &substitutionsMenu);
702     appendItem(*separatorItem(), &substitutionsMenu);
703     appendItem(smartCopyPaste, &substitutionsMenu);
704     appendItem(smartQuotes, &substitutionsMenu);
705     appendItem(smartDashes, &substitutionsMenu);
706     appendItem(smartLinks, &substitutionsMenu);
707     appendItem(textReplacement, &substitutionsMenu);
708
709     substitutionsMenuItem.setSubMenu(&substitutionsMenu);
710 }
711
712 void ContextMenuController::createAndAppendTransformationsSubMenu(ContextMenuItem& transformationsMenuItem)
713 {
714     ContextMenu transformationsMenu;
715
716     ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase());
717     ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase());
718     ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize());
719
720     appendItem(makeUpperCase, &transformationsMenu);
721     appendItem(makeLowerCase, &transformationsMenu);
722     appendItem(capitalize, &transformationsMenu);
723
724     transformationsMenuItem.setSubMenu(&transformationsMenu);
725 }
726
727 #endif
728
729 static bool selectionContainsPossibleWord(Frame* frame)
730 {
731     // Current algorithm: look for a character that's not just a separator.
732     for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) {
733         int length = it.length();
734         const UChar* characters = it.characters();
735         for (int i = 0; i < length; ++i)
736             if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph)))
737                 return true;
738     }
739     return false;
740 }
741
742 #if PLATFORM(MAC)
743 #if defined(BUILDING_ON_LEOPARD) || defined(BUILDING_ON_SNOW_LEOPARD)
744 #define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 1
745 #else
746 #define INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM 0
747 #endif
748 #endif
749
750 void ContextMenuController::populate()
751 {
752     ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink());
753     ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, 
754         contextMenuItemTagOpenLinkInNewWindow());
755     ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, 
756         contextMenuItemTagDownloadLinkToDisk());
757     ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, 
758         contextMenuItemTagCopyLinkToClipboard());
759     ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, 
760         contextMenuItemTagOpenImageInNewWindow());
761     ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, 
762         contextMenuItemTagDownloadImageToDisk());
763     ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, 
764         contextMenuItemTagCopyImageToClipboard());
765 #if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
766     ContextMenuItem CopyImageUrlItem(ActionType, ContextMenuItemTagCopyImageUrlToClipboard, 
767         contextMenuItemTagCopyImageUrlToClipboard());
768 #endif
769     ContextMenuItem OpenMediaInNewWindowItem(ActionType, ContextMenuItemTagOpenMediaInNewWindow, String());
770     ContextMenuItem CopyMediaLinkItem(ActionType, ContextMenuItemTagCopyMediaLinkToClipboard, 
771         String());
772     ContextMenuItem MediaPlayPause(ActionType, ContextMenuItemTagMediaPlayPause, 
773         contextMenuItemTagMediaPlay());
774     ContextMenuItem MediaMute(ActionType, ContextMenuItemTagMediaMute, 
775         contextMenuItemTagMediaMute());
776     ContextMenuItem ToggleMediaControls(CheckableActionType, ContextMenuItemTagToggleMediaControls, 
777         contextMenuItemTagToggleMediaControls());
778     ContextMenuItem ToggleMediaLoop(CheckableActionType, ContextMenuItemTagToggleMediaLoop, 
779         contextMenuItemTagToggleMediaLoop());
780     ContextMenuItem EnterVideoFullscreen(ActionType, ContextMenuItemTagEnterVideoFullscreen, 
781         contextMenuItemTagEnterVideoFullscreen());
782 #if PLATFORM(MAC)
783     ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, 
784         contextMenuItemTagSearchInSpotlight());
785 #endif
786 #if !PLATFORM(GTK)
787     ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb());
788 #endif
789     ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy());
790     ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack());
791     ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward,  contextMenuItemTagGoForward());
792     ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop());
793     ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload());
794     ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, 
795         contextMenuItemTagOpenFrameInNewWindow());
796     ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, 
797         contextMenuItemTagNoGuessesFound());
798     ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, 
799         contextMenuItemTagIgnoreSpelling());
800     ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, 
801         contextMenuItemTagLearnSpelling());
802     ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, 
803         contextMenuItemTagIgnoreGrammar());
804     ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut());
805     ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste());
806 #if PLATFORM(GTK)
807     ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete());
808 #endif
809 #if PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(EFL)
810     ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll());
811 #endif
812 #if ENABLE(TIZEN_CONTEXT_MENU_SELECT)
813     ContextMenuItem SelectWordItem(ActionType, ContextMenuItemTagSelectWord, contextMenuItemTagSelectWord());
814 #endif
815
816     Node* node = m_hitTestResult.innerNonSharedNode();
817     if (!node)
818         return;
819 #if PLATFORM(GTK)
820     if (!m_hitTestResult.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement()))
821         return;
822 #endif
823     Frame* frame = node->document()->frame();
824     if (!frame)
825         return;
826
827     if (!m_hitTestResult.isContentEditable()) {
828         FrameLoader* loader = frame->loader();
829         KURL linkURL = m_hitTestResult.absoluteLinkURL();
830         if (!linkURL.isEmpty()) {
831 #if ENABLE(TIZEN_WEBKIT2_TEXT_SELECTION)
832             if (m_hitTestResult.isSelected()) {
833                 if (selectionContainsPossibleWord(frame)) {
834                     appendItem(SearchWebItem, m_contextMenu.get());
835                 }
836                 appendItem(CopyItem, m_contextMenu.get());
837                 return;
838             }
839 #endif
840 #if ENABLE(TIZEN_DOWNLOAD_LINK_FILTER)
841             if (loader->client()->canHandleRequest(ResourceRequest(linkURL)) &&
842                (linkURL.protocolIs("http") || linkURL.protocolIs("https") || linkURL.protocolIs("ftp") || linkURL.protocolIs("ftps"))) {
843 #else
844             if (loader->client()->canHandleRequest(ResourceRequest(linkURL))) {
845 #endif
846                 appendItem(OpenLinkItem, m_contextMenu.get());
847                 appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
848                 appendItem(DownloadFileItem, m_contextMenu.get());
849             }
850 #if PLATFORM(QT)
851             if (m_hitTestResult.isSelected()) 
852                 appendItem(CopyItem, m_contextMenu.get());
853 #endif
854             appendItem(CopyLinkItem, m_contextMenu.get());
855         }
856
857         KURL imageURL = m_hitTestResult.absoluteImageURL();
858         if (!imageURL.isEmpty()) {
859             if (!linkURL.isEmpty())
860                 appendItem(*separatorItem(), m_contextMenu.get());
861
862             appendItem(OpenImageInNewWindowItem, m_contextMenu.get());
863             appendItem(DownloadImageItem, m_contextMenu.get());
864             if (imageURL.isLocalFile() || m_hitTestResult.image())
865                 appendItem(CopyImageItem, m_contextMenu.get());
866 #if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
867             appendItem(CopyImageUrlItem, m_contextMenu.get());
868 #endif
869         }
870
871         KURL mediaURL = m_hitTestResult.absoluteMediaURL();
872         if (!mediaURL.isEmpty()) {
873             if (!linkURL.isEmpty() || !imageURL.isEmpty())
874                 appendItem(*separatorItem(), m_contextMenu.get());
875
876             appendItem(MediaPlayPause, m_contextMenu.get());
877             appendItem(MediaMute, m_contextMenu.get());
878             appendItem(ToggleMediaControls, m_contextMenu.get());
879             appendItem(ToggleMediaLoop, m_contextMenu.get());
880             appendItem(EnterVideoFullscreen, m_contextMenu.get());
881
882             appendItem(*separatorItem(), m_contextMenu.get());
883             appendItem(CopyMediaLinkItem, m_contextMenu.get());
884             appendItem(OpenMediaInNewWindowItem, m_contextMenu.get());
885         }
886
887         if (imageURL.isEmpty() && linkURL.isEmpty() && mediaURL.isEmpty()) {
888             if (m_hitTestResult.isSelected()) {
889                 if (selectionContainsPossibleWord(frame)) {
890 #if PLATFORM(MAC)
891                     String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText());
892                     ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString));
893
894 #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
895                     appendItem(SearchSpotlightItem, m_contextMenu.get());
896 #else
897                     appendItem(LookUpInDictionaryItem, m_contextMenu.get());
898 #endif
899 #endif
900
901 #if !PLATFORM(GTK)
902                     appendItem(SearchWebItem, m_contextMenu.get());
903                     appendItem(*separatorItem(), m_contextMenu.get());
904 #endif
905
906 #if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
907                     appendItem(LookUpInDictionaryItem, m_contextMenu.get());
908                     appendItem(*separatorItem(), m_contextMenu.get());
909 #endif
910                 }
911
912                 appendItem(CopyItem, m_contextMenu.get());
913 #if PLATFORM(MAC)
914                 appendItem(*separatorItem(), m_contextMenu.get());
915
916                 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
917                 createAndAppendSpeechSubMenu(SpeechMenuItem);
918                 appendItem(SpeechMenuItem, m_contextMenu.get());
919 #endif                
920             } else {
921 #if ENABLE(INSPECTOR)
922                 if (!(frame->page() && frame->page()->inspectorController()->hasInspectorFrontendClient())) {
923 #endif
924
925                 // In GTK+ unavailable items are not hidden but insensitive
926 #if PLATFORM(GTK)
927                 appendItem(BackItem, m_contextMenu.get());
928                 appendItem(ForwardItem, m_contextMenu.get());
929                 appendItem(StopItem, m_contextMenu.get());
930                 appendItem(ReloadItem, m_contextMenu.get());
931 #else
932                 if (frame->page() && frame->page()->backForward()->canGoBackOrForward(-1))
933                     appendItem(BackItem, m_contextMenu.get());
934
935                 if (frame->page() && frame->page()->backForward()->canGoBackOrForward(1))
936                     appendItem(ForwardItem, m_contextMenu.get());
937
938                 // use isLoadingInAPISense rather than isLoading because Stop/Reload are
939                 // intended to match WebKit's API, not WebCore's internal notion of loading status
940                 if (loader->documentLoader()->isLoadingInAPISense())
941                     appendItem(StopItem, m_contextMenu.get());
942                 else
943                     appendItem(ReloadItem, m_contextMenu.get());
944 #endif
945 #if ENABLE(INSPECTOR)
946                 }
947 #endif
948
949                 if (frame->page() && frame != frame->page()->mainFrame())
950                     appendItem(OpenFrameItem, m_contextMenu.get());
951             }
952         }
953     } else { // Make an editing context menu
954         FrameSelection* selection = frame->selection();
955         bool inPasswordField = selection->isInPasswordField();
956         bool spellCheckingEnabled = frame->editor()->isSpellCheckingEnabledFor(node);
957
958         if (!inPasswordField && spellCheckingEnabled) {
959             // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range
960             // is never considered a misspelling and bad grammar at the same time)
961             bool misspelling;
962             bool badGrammar;
963             Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar);
964             if (misspelling || badGrammar) {
965                 size_t size = guesses.size();
966                 if (size == 0) {
967                     // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions
968                     // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit)
969                     if (misspelling) {
970                         appendItem(NoGuessesItem, m_contextMenu.get());
971                         appendItem(*separatorItem(), m_contextMenu.get());
972                     }
973                 } else {
974                     for (unsigned i = 0; i < size; i++) {
975                         const String &guess = guesses[i];
976                         if (!guess.isEmpty()) {
977                             ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess);
978                             appendItem(item, m_contextMenu.get());
979                         }
980                     }
981                     appendItem(*separatorItem(), m_contextMenu.get());                    
982                 }
983                 
984                 if (misspelling) {
985                     appendItem(IgnoreSpellingItem, m_contextMenu.get());
986                     appendItem(LearnSpellingItem, m_contextMenu.get());
987                 } else
988                     appendItem(IgnoreGrammarItem, m_contextMenu.get());
989                 appendItem(*separatorItem(), m_contextMenu.get());
990 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
991             } else {
992                 // If the string was autocorrected, generate a contextual menu item allowing it to be changed back.
993                 String replacedString = m_hitTestResult.replacedString();
994                 if (!replacedString.isEmpty()) {
995                     ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString));
996                     appendItem(item, m_contextMenu.get());
997                     appendItem(*separatorItem(), m_contextMenu.get());
998                 }
999 #endif
1000             }
1001         }
1002
1003         FrameLoader* loader = frame->loader();
1004         KURL linkURL = m_hitTestResult.absoluteLinkURL();
1005         if (!linkURL.isEmpty()) {
1006             if (loader->client()->canHandleRequest(ResourceRequest(linkURL))) {
1007                 appendItem(OpenLinkItem, m_contextMenu.get());
1008                 appendItem(OpenLinkInNewWindowItem, m_contextMenu.get());
1009                 appendItem(DownloadFileItem, m_contextMenu.get());
1010             }
1011             appendItem(CopyLinkItem, m_contextMenu.get());
1012             appendItem(*separatorItem(), m_contextMenu.get());
1013         }
1014
1015         if (m_hitTestResult.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) {
1016 #if PLATFORM(MAC)
1017             String selectedString = frame->displayStringModifiedByEncoding(frame->editor()->selectedText());
1018             ContextMenuItem LookUpInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedString));
1019
1020 #if INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
1021             appendItem(SearchSpotlightItem, m_contextMenu.get());
1022 #else
1023             appendItem(LookUpInDictionaryItem, m_contextMenu.get());
1024 #endif
1025 #endif
1026
1027 #if !PLATFORM(GTK)
1028             appendItem(SearchWebItem, m_contextMenu.get());
1029             appendItem(*separatorItem(), m_contextMenu.get());
1030 #endif
1031
1032 #if PLATFORM(MAC) && INCLUDE_SPOTLIGHT_CONTEXT_MENU_ITEM
1033             appendItem(LookUpInDictionaryItem, m_contextMenu.get());
1034             appendItem(*separatorItem(), m_contextMenu.get());
1035 #endif
1036         }
1037
1038 #if ENABLE(TIZEN_CONTEXT_MENU_WEBKIT_2)
1039         if (m_hitTestResult.isSelected()) {
1040             appendItem(CutItem, m_contextMenu.get());
1041             appendItem(CopyItem, m_contextMenu.get());
1042         }
1043 #else
1044         appendItem(CutItem, m_contextMenu.get());
1045         appendItem(CopyItem, m_contextMenu.get());
1046 #endif
1047         appendItem(PasteItem, m_contextMenu.get());
1048 #if PLATFORM(GTK)
1049         appendItem(DeleteItem, m_contextMenu.get());
1050         appendItem(*separatorItem(), m_contextMenu.get());
1051 #endif
1052 #if PLATFORM(GTK) || PLATFORM(QT) || PLATFORM(EFL)
1053         appendItem(SelectAllItem, m_contextMenu.get());
1054 #endif
1055 #if ENABLE(TIZEN_CONTEXT_MENU_SELECT)
1056         appendItem(SelectWordItem, m_contextMenu.get());
1057 #endif
1058
1059         if (!inPasswordField) {
1060 #if !PLATFORM(GTK)
1061 #if !ENABLE(TIZEN_CONTEXT_MENU_TEMPORARY_FIX)
1062             appendItem(*separatorItem(), m_contextMenu.get());
1063             ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, 
1064                 contextMenuItemTagSpellingMenu());
1065             createAndAppendSpellingAndGrammarSubMenu(SpellingAndGrammarMenuItem);
1066             appendItem(SpellingAndGrammarMenuItem, m_contextMenu.get());
1067 #endif //TIZEN_CONTEXT_MENU_TEMPORARY_FIX
1068 #endif
1069 #if PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD)
1070             ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, 
1071                 contextMenuItemTagSubstitutionsMenu());
1072             createAndAppendSubstitutionsSubMenu(substitutionsMenuItem);
1073             appendItem(substitutionsMenuItem, m_contextMenu.get());
1074             ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, 
1075                 contextMenuItemTagTransformationsMenu());
1076             createAndAppendTransformationsSubMenu(transformationsMenuItem);
1077             appendItem(transformationsMenuItem, m_contextMenu.get());
1078 #endif
1079 #if PLATFORM(GTK)
1080             bool shouldShowFontMenu = frame->editor()->canEditRichly();
1081 #else
1082 #if ENABLE(TIZEN_CONTEXT_MENU_TEMPORARY_FIX)
1083             bool shouldShowFontMenu = false;
1084 #else
1085             bool shouldShowFontMenu = true;
1086 #endif //TIZEN_CONTEXT_MENU_TEMPORARY_FIX
1087 #endif
1088             if (shouldShowFontMenu) {
1089                 ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, 
1090                     contextMenuItemTagFontMenu());
1091                 createAndAppendFontSubMenu(FontMenuItem);
1092                 appendItem(FontMenuItem, m_contextMenu.get());
1093             }
1094 #if PLATFORM(MAC)
1095             ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu());
1096             createAndAppendSpeechSubMenu(SpeechMenuItem);
1097             appendItem(SpeechMenuItem, m_contextMenu.get());
1098 #endif
1099 #if PLATFORM(GTK)
1100             EditorClient* client = frame->editor()->client();
1101             if (client && client->shouldShowUnicodeMenu()) {
1102                 ContextMenuItem UnicodeMenuItem(SubmenuType, ContextMenuItemTagUnicode, contextMenuItemTagUnicode());
1103                 createAndAppendUnicodeSubMenu(UnicodeMenuItem);
1104                 appendItem(*separatorItem(), m_contextMenu.get());
1105                 appendItem(UnicodeMenuItem, m_contextMenu.get());
1106             }
1107 #else
1108             ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, 
1109                 contextMenuItemTagWritingDirectionMenu());
1110 #if !ENABLE(TIZEN_CONTEXT_MENU_TEMPORARY_FIX)
1111             createAndAppendWritingDirectionSubMenu(WritingDirectionMenuItem);
1112             appendItem(WritingDirectionMenuItem, m_contextMenu.get());
1113             if (Page* page = frame->page()) {
1114                 if (Settings* settings = page->settings()) {
1115                     bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded
1116                         || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection());
1117                     if (includeTextDirectionSubmenu) {
1118                         ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, 
1119                             contextMenuItemTagTextDirectionMenu());
1120                         createAndAppendTextDirectionSubMenu(TextDirectionMenuItem);
1121                         appendItem(TextDirectionMenuItem, m_contextMenu.get());
1122                     }
1123                 }
1124             }
1125 #endif //TIZEN_CONTEXT_MENU_TEMPORARY_FIX
1126 #endif
1127         }
1128     }
1129 }
1130
1131 #if ENABLE(INSPECTOR)
1132 void ContextMenuController::addInspectElementItem()
1133 {
1134     Node* node = m_hitTestResult.innerNonSharedNode();
1135     if (!node)
1136         return;
1137
1138     Frame* frame = node->document()->frame();
1139     if (!frame)
1140         return;
1141
1142     Page* page = frame->page();
1143     if (!page)
1144         return;
1145
1146     if (!page->inspectorController())
1147         return;
1148
1149     ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement());
1150 #if USE(CROSS_PLATFORM_CONTEXT_MENUS)
1151     if (!m_contextMenu->items().isEmpty())
1152 #else
1153     if (m_contextMenu->itemCount())
1154 #endif
1155         appendItem(*separatorItem(), m_contextMenu.get());
1156     appendItem(InspectElementItem, m_contextMenu.get());
1157 }
1158 #endif // ENABLE(INSPECTOR)
1159
1160 void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const
1161 {
1162     if (item.type() == SeparatorType)
1163         return;
1164     
1165     Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame();
1166     if (!frame)
1167         return;
1168
1169     // Custom items already have proper checked and enabled values.
1170     if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag)
1171         return;
1172
1173     bool shouldEnable = true;
1174     bool shouldCheck = false; 
1175
1176     switch (item.action()) {
1177         case ContextMenuItemTagCheckSpelling:
1178             shouldEnable = frame->editor()->canEdit();
1179             break;
1180         case ContextMenuItemTagDefaultDirection:
1181             shouldCheck = false;
1182             shouldEnable = false;
1183             break;
1184         case ContextMenuItemTagLeftToRight:
1185         case ContextMenuItemTagRightToLeft: {
1186             String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl";
1187             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyDirection, direction) != FalseTriState;
1188             shouldEnable = true;
1189             break;
1190         }
1191         case ContextMenuItemTagTextDirectionDefault: {
1192             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural");
1193             shouldCheck = command.state() == TrueTriState;
1194             shouldEnable = command.isEnabled();
1195             break;
1196         }
1197         case ContextMenuItemTagTextDirectionLeftToRight: {
1198             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight");
1199             shouldCheck = command.state() == TrueTriState;
1200             shouldEnable = command.isEnabled();
1201             break;
1202         }
1203         case ContextMenuItemTagTextDirectionRightToLeft: {
1204             Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft");
1205             shouldCheck = command.state() == TrueTriState;
1206             shouldEnable = command.isEnabled();
1207             break;
1208         }
1209         case ContextMenuItemTagCopy:
1210             shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy();
1211             break;
1212         case ContextMenuItemTagCut:
1213             shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut();
1214             break;
1215         case ContextMenuItemTagIgnoreSpelling:
1216         case ContextMenuItemTagLearnSpelling:
1217             shouldEnable = frame->selection()->isRange();
1218             break;
1219         case ContextMenuItemTagPaste:
1220             shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste();
1221             break;
1222 #if ENABLE(TIZEN_CONTEXT_MENU_SELECT)
1223         case ContextMenuItemTagSelectWord:
1224             shouldEnable = frame->editor()->canSelectRange();
1225             break;
1226 #endif
1227 #if PLATFORM(GTK)
1228         case ContextMenuItemTagDelete:
1229             shouldEnable = frame->editor()->canDelete();
1230             break;
1231         case ContextMenuItemTagInputMethods:
1232         case ContextMenuItemTagUnicode:
1233         case ContextMenuItemTagUnicodeInsertLRMMark:
1234         case ContextMenuItemTagUnicodeInsertRLMMark:
1235         case ContextMenuItemTagUnicodeInsertLREMark:
1236         case ContextMenuItemTagUnicodeInsertRLEMark:
1237         case ContextMenuItemTagUnicodeInsertLROMark:
1238         case ContextMenuItemTagUnicodeInsertRLOMark:
1239         case ContextMenuItemTagUnicodeInsertPDFMark:
1240         case ContextMenuItemTagUnicodeInsertZWSMark:
1241         case ContextMenuItemTagUnicodeInsertZWJMark:
1242         case ContextMenuItemTagUnicodeInsertZWNJMark:
1243             shouldEnable = true;
1244             break;
1245 #endif
1246 #if PLATFORM(GTK) || PLATFORM(EFL)
1247         case ContextMenuItemTagSelectAll:
1248             shouldEnable = true;
1249             break;
1250 #endif
1251         case ContextMenuItemTagUnderline: {
1252             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline") != FalseTriState;
1253             shouldEnable = frame->editor()->canEditRichly();
1254             break;
1255         }
1256         case ContextMenuItemTagLookUpInDictionary:
1257             shouldEnable = frame->selection()->isRange();
1258             break;
1259         case ContextMenuItemTagCheckGrammarWithSpelling:
1260             if (frame->editor()->isGrammarCheckingEnabled())
1261                 shouldCheck = true;
1262             shouldEnable = true;
1263             break;
1264         case ContextMenuItemTagItalic: {
1265             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontStyle, "italic") != FalseTriState;
1266             shouldEnable = frame->editor()->canEditRichly();
1267             break;
1268         }
1269         case ContextMenuItemTagBold: {
1270             shouldCheck = frame->editor()->selectionHasStyle(CSSPropertyFontWeight, "bold") != FalseTriState;
1271             shouldEnable = frame->editor()->canEditRichly();
1272             break;
1273         }
1274         case ContextMenuItemTagOutline:
1275             shouldEnable = false;
1276             break;
1277         case ContextMenuItemTagShowSpellingPanel:
1278             if (frame->editor()->spellingPanelIsShowing())
1279                 item.setTitle(contextMenuItemTagShowSpellingPanel(false));
1280             else
1281                 item.setTitle(contextMenuItemTagShowSpellingPanel(true));
1282             shouldEnable = frame->editor()->canEdit();
1283             break;
1284         case ContextMenuItemTagNoGuessesFound:
1285             shouldEnable = false;
1286             break;
1287         case ContextMenuItemTagCheckSpellingWhileTyping:
1288             shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled();
1289             break;
1290 #if PLATFORM(MAC)
1291         case ContextMenuItemTagSubstitutionsMenu:
1292         case ContextMenuItemTagTransformationsMenu:
1293             break;
1294         case ContextMenuItemTagShowSubstitutions:
1295 #ifndef BUILDING_ON_LEOPARD
1296             if (frame->editor()->substitutionsPanelIsShowing())
1297                 item.setTitle(contextMenuItemTagShowSubstitutions(false));
1298             else
1299                 item.setTitle(contextMenuItemTagShowSubstitutions(true));
1300             shouldEnable = frame->editor()->canEdit();
1301 #endif
1302             break;
1303         case ContextMenuItemTagMakeUpperCase:
1304         case ContextMenuItemTagMakeLowerCase:
1305         case ContextMenuItemTagCapitalize:
1306         case ContextMenuItemTagChangeBack:
1307             shouldEnable = frame->editor()->canEdit();
1308             break;
1309         case ContextMenuItemTagCorrectSpellingAutomatically:
1310 #ifndef BUILDING_ON_LEOPARD
1311             shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled();
1312 #endif
1313             break;
1314         case ContextMenuItemTagSmartCopyPaste:
1315 #ifndef BUILDING_ON_LEOPARD
1316             shouldCheck = frame->editor()->smartInsertDeleteEnabled();
1317 #endif
1318             break;
1319         case ContextMenuItemTagSmartQuotes:
1320 #ifndef BUILDING_ON_LEOPARD
1321             shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled();
1322 #endif
1323             break;
1324         case ContextMenuItemTagSmartDashes:
1325 #ifndef BUILDING_ON_LEOPARD
1326             shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled();
1327 #endif
1328             break;
1329         case ContextMenuItemTagSmartLinks:
1330 #ifndef BUILDING_ON_LEOPARD
1331             shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled();
1332 #endif
1333             break;
1334         case ContextMenuItemTagTextReplacement:
1335 #ifndef BUILDING_ON_LEOPARD
1336             shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled();
1337 #endif
1338             break;
1339         case ContextMenuItemTagStopSpeaking:
1340             shouldEnable = client() && client()->isSpeaking();
1341             break;
1342 #else // PLATFORM(MAC) ends here
1343         case ContextMenuItemTagStopSpeaking:
1344             break;
1345 #endif
1346 #if PLATFORM(GTK)
1347         case ContextMenuItemTagGoBack:
1348             shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(-1);
1349             break;
1350         case ContextMenuItemTagGoForward:
1351             shouldEnable = frame->page() && frame->page()->backForward()->canGoBackOrForward(1);
1352             break;
1353         case ContextMenuItemTagStop:
1354             shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense();
1355             break;
1356         case ContextMenuItemTagReload:
1357             shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense();
1358             break;
1359         case ContextMenuItemTagFontMenu:
1360             shouldEnable = frame->editor()->canEditRichly();
1361             break;
1362 #else
1363         case ContextMenuItemTagGoBack:
1364         case ContextMenuItemTagGoForward:
1365         case ContextMenuItemTagStop:
1366         case ContextMenuItemTagReload:
1367         case ContextMenuItemTagFontMenu:
1368 #endif
1369         case ContextMenuItemTagNoAction:
1370         case ContextMenuItemTagOpenLinkInNewWindow:
1371         case ContextMenuItemTagDownloadLinkToDisk:
1372         case ContextMenuItemTagCopyLinkToClipboard:
1373         case ContextMenuItemTagOpenImageInNewWindow:
1374         case ContextMenuItemTagDownloadImageToDisk:
1375         case ContextMenuItemTagCopyImageToClipboard:
1376 #if PLATFORM(QT) || PLATFORM(GTK) || PLATFORM(EFL)
1377         case ContextMenuItemTagCopyImageUrlToClipboard:
1378 #endif
1379             break;
1380         case ContextMenuItemTagOpenMediaInNewWindow:
1381             if (m_hitTestResult.mediaIsVideo())
1382                 item.setTitle(contextMenuItemTagOpenVideoInNewWindow());
1383             else
1384                 item.setTitle(contextMenuItemTagOpenAudioInNewWindow());
1385             break;
1386         case ContextMenuItemTagCopyMediaLinkToClipboard:
1387             if (m_hitTestResult.mediaIsVideo())
1388                 item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard());
1389             else
1390                 item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard());
1391             break;
1392         case ContextMenuItemTagToggleMediaControls:
1393             shouldCheck = m_hitTestResult.mediaControlsEnabled();
1394             break;
1395         case ContextMenuItemTagToggleMediaLoop:
1396             shouldCheck = m_hitTestResult.mediaLoopEnabled();
1397             break;
1398         case ContextMenuItemTagEnterVideoFullscreen:
1399             shouldEnable = m_hitTestResult.mediaSupportsFullscreen();
1400             break;
1401         case ContextMenuItemTagOpenFrameInNewWindow:
1402         case ContextMenuItemTagSpellingGuess:
1403         case ContextMenuItemTagOther:
1404         case ContextMenuItemTagSearchInSpotlight:
1405         case ContextMenuItemTagSearchWeb:
1406         case ContextMenuItemTagOpenWithDefaultApplication:
1407         case ContextMenuItemPDFActualSize:
1408         case ContextMenuItemPDFZoomIn:
1409         case ContextMenuItemPDFZoomOut:
1410         case ContextMenuItemPDFAutoSize:
1411         case ContextMenuItemPDFSinglePage:
1412         case ContextMenuItemPDFFacingPages:
1413         case ContextMenuItemPDFContinuous:
1414         case ContextMenuItemPDFNextPage:
1415         case ContextMenuItemPDFPreviousPage:
1416         case ContextMenuItemTagOpenLink:
1417         case ContextMenuItemTagIgnoreGrammar:
1418         case ContextMenuItemTagSpellingMenu:
1419         case ContextMenuItemTagShowFonts:
1420         case ContextMenuItemTagStyles:
1421         case ContextMenuItemTagShowColors:
1422         case ContextMenuItemTagSpeechMenu:
1423         case ContextMenuItemTagStartSpeaking:
1424         case ContextMenuItemTagWritingDirectionMenu:
1425         case ContextMenuItemTagTextDirectionMenu:
1426         case ContextMenuItemTagPDFSinglePageScrolling:
1427         case ContextMenuItemTagPDFFacingPagesScrolling:
1428 #if ENABLE(INSPECTOR)
1429         case ContextMenuItemTagInspectElement:
1430 #endif
1431         case ContextMenuItemBaseCustomTag:
1432         case ContextMenuItemCustomTagNoAction:
1433         case ContextMenuItemLastCustomTag:
1434         case ContextMenuItemBaseApplicationTag:
1435             break;
1436         case ContextMenuItemTagMediaPlayPause:
1437             if (m_hitTestResult.mediaPlaying())
1438                 item.setTitle(contextMenuItemTagMediaPause());
1439             else
1440                 item.setTitle(contextMenuItemTagMediaPlay());
1441             break;
1442         case ContextMenuItemTagMediaMute:
1443             shouldEnable = m_hitTestResult.mediaHasAudio();
1444             shouldCheck = shouldEnable &&  m_hitTestResult.mediaMuted();
1445             break;
1446     }
1447
1448     item.setChecked(shouldCheck);
1449     item.setEnabled(shouldEnable);
1450 }
1451
1452 #if USE(ACCESSIBILITY_CONTEXT_MENUS)
1453 void ContextMenuController::showContextMenuAt(Frame* frame, const IntPoint& clickPoint)
1454 {
1455     // Simulate a click in the middle of the accessibility object.
1456     PlatformMouseEvent mouseEvent(clickPoint, clickPoint, RightButton, PlatformEvent::MousePressed, 1, false, false, false, false, currentTime());
1457     bool handled = frame->eventHandler()->sendContextMenuEvent(mouseEvent);
1458     if (handled && client())
1459         client()->showContextMenu();
1460 }
1461 #endif
1462
1463 } // namespace WebCore
1464
1465 #endif // ENABLE(CONTEXT_MENUS)