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