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