| /* |
| * Copyright (C) 2006-2025 Apple Inc. All rights reserved. |
| * Copyright (C) 2010 Igalia S.L |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #include "config.h" |
| #include "ContextMenuController.h" |
| |
| #if ENABLE(CONTEXT_MENUS) |
| |
| #include "BackForwardController.h" |
| #include "BitmapImage.h" |
| #include "Chrome.h" |
| #include "ContextMenu.h" |
| #include "ContextMenuClient.h" |
| #include "ContextMenuItem.h" |
| #include "ContextMenuProvider.h" |
| #include "Document.h" |
| #include "DocumentFragment.h" |
| #include "DocumentLoader.h" |
| #include "Editor.h" |
| #include "EditorClient.h" |
| #include "ElementAncestorIteratorInlines.h" |
| #include "Event.h" |
| #include "EventHandler.h" |
| #include "FormState.h" |
| #include "FrameLoadRequest.h" |
| #include "FrameLoader.h" |
| #include "FrameSelection.h" |
| #include "FrameSnapshotting.h" |
| #include "HTMLCanvasElement.h" |
| #include "HTMLFormControlElement.h" |
| #include "HTMLFormElement.h" |
| #include "HTMLFrameOwnerElement.h" |
| #include "HTMLImageElement.h" |
| #include "HTMLTableElement.h" |
| #include "HandleUserInputEventResult.h" |
| #include "HitTestResult.h" |
| #include "ImageBuffer.h" |
| #include "ImageOverlay.h" |
| #include "InspectorController.h" |
| #include "LocalFrame.h" |
| #include "LocalFrameLoaderClient.h" |
| #include "LocalizedStrings.h" |
| #include "MouseEvent.h" |
| #include "NavigationAction.h" |
| #include "Node.h" |
| #include "Page.h" |
| #include "PlatformEvent.h" |
| #include "PlatformMouseEvent.h" |
| #include "RenderImage.h" |
| #include "ReplaceSelectionCommand.h" |
| #include "ResourceRequest.h" |
| #include "SVGElementTypeHelpers.h" |
| #include "SVGSVGElement.h" |
| #include "Settings.h" |
| #include "TextIterator.h" |
| #include "TranslationContextMenuInfo.h" |
| #include "TypingCommand.h" |
| #include "UserTypingGestureIndicator.h" |
| #include "WindowFeatures.h" |
| #include "markup.h" |
| #include <wtf/SetForScope.h> |
| #include <wtf/TZoneMallocInlines.h> |
| #include <wtf/WallTime.h> |
| #include <wtf/unicode/CharacterNames.h> |
| |
| #if ENABLE(PDFJS) |
| #include "PDFDocument.h" |
| #endif |
| |
| #if ENABLE(SERVICE_CONTROLS) |
| #include "ImageControlsMac.h" |
| #endif |
| |
| #if PLATFORM(COCOA) |
| #include <wtf/cocoa/RuntimeApplicationChecksCocoa.h> |
| #endif |
| |
| namespace WebCore { |
| |
| WTF_MAKE_TZONE_ALLOCATED_IMPL(ContextMenuController); |
| |
| using namespace WTF::Unicode; |
| |
| ContextMenuController::ContextMenuController(Page& page, UniqueRef<ContextMenuClient>&& client) |
| : m_page(page) |
| , m_client(WTFMove(client)) |
| { |
| } |
| |
| ContextMenuController::~ContextMenuController() |
| { |
| } |
| |
| Page& ContextMenuController::page() |
| { |
| return m_page.get(); |
| } |
| |
| void ContextMenuController::clearContextMenu() |
| { |
| m_contextMenu = nullptr; |
| if (RefPtr menuProvider = std::exchange(m_menuProvider, nullptr)) |
| menuProvider->contextMenuCleared(); |
| } |
| |
| void ContextMenuController::handleContextMenuEvent(Event& event) |
| { |
| if (m_isHandlingContextMenuEvent) |
| return; |
| |
| SetForScope isHandlingContextMenuEventForScope(m_isHandlingContextMenuEvent, true); |
| |
| constexpr OptionSet<HitTestRequest::Type> hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::DisallowUserAgentShadowContent, HitTestRequest::Type::AllowChildFrameContent }; |
| m_contextMenu = maybeCreateContextMenu(event, hitType, ContextMenuContext::Type::ContextMenu); |
| if (!m_contextMenu) |
| return; |
| |
| populate(); |
| |
| showContextMenu(event); |
| } |
| |
| static std::unique_ptr<ContextMenuItem> separatorItem() |
| { |
| return std::unique_ptr<ContextMenuItem>(new ContextMenuItem(ContextMenuItemType::Separator, ContextMenuItemTagNoAction, String())); |
| } |
| |
| void ContextMenuController::showContextMenu(Event& event, ContextMenuProvider& provider) |
| { |
| m_menuProvider = provider; |
| |
| auto contextType = provider.contextMenuContextType(); |
| |
| OptionSet<HitTestRequest::Type> hitType { HitTestRequest::Type::ReadOnly, HitTestRequest::Type::Active, HitTestRequest::Type::AllowChildFrameContent }; |
| if (contextType == ContextMenuContext::Type::ContextMenu) |
| hitType.add(HitTestRequest::Type::DisallowUserAgentShadowContent); |
| |
| m_contextMenu = maybeCreateContextMenu(event, WTFMove(hitType), contextType); |
| if (!m_contextMenu) { |
| clearContextMenu(); |
| return; |
| } |
| |
| provider.populateContextMenu(m_contextMenu.get()); |
| if (m_context.hitTestResult().isSelected()) { |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| populate(); |
| } |
| showContextMenu(event); |
| } |
| |
| #if ENABLE(CONTEXT_MENU_QR_CODE_DETECTION) |
| |
| static void prepareContextForQRCode(ContextMenuContext& context) |
| { |
| auto& result = context.hitTestResult(); |
| |
| RefPtr node = result.innerNonSharedNode(); |
| if (!node || !node->document().settings().contextMenuQRCodeDetectionEnabled()) |
| return; |
| |
| if (result.image() || !result.absoluteLinkURL().isEmpty()) |
| return; |
| |
| RefPtr nodeElement = dynamicDowncast<Element>(*node); |
| if (!nodeElement && !(nodeElement = node->parentOrShadowHostElement())) |
| return; |
| |
| RefPtr<Element> element; |
| for (auto& lineage : lineageOfType<Element>(*nodeElement)) { |
| if (is<HTMLTableElement>(lineage) || is<HTMLCanvasElement>(lineage) || is<HTMLImageElement>(lineage) || is<SVGSVGElement>(lineage)) { |
| element = lineage; |
| break; |
| } |
| } |
| |
| if (!element || !element->renderer()) |
| return; |
| |
| auto elementRect = element->renderer()->absoluteBoundingBoxRect(); |
| |
| // Constant chosen to be larger than we think any QR code would be, matching the original Safari implementation. |
| constexpr auto maxQRCodeContainerDimension = 800; |
| if (elementRect.width() > maxQRCodeContainerDimension || elementRect.height() > maxQRCodeContainerDimension) |
| return; |
| |
| RefPtr frame = element->document().frame(); |
| if (!frame) |
| return; |
| |
| auto nodeSnapshotImageBuffer = snapshotNode(*frame, *element, { { }, ImageBufferPixelFormat::BGRA8, DestinationColorSpace::SRGB() }); |
| RefPtr nodeSnapshotImage = BitmapImage::create(ImageBuffer::sinkIntoNativeImage(WTFMove(nodeSnapshotImageBuffer))); |
| context.setPotentialQRCodeNodeSnapshotImage(nodeSnapshotImage.get()); |
| |
| // FIXME: Node snapshotting does not take transforms into account, making it unreliable for QR code detection. |
| // As a fallback, also take a viewport-level snapshot. A node snapshot is still required to capture partially |
| // obscured elements. This workaround can be removed once rdar://87204215 is fixed. |
| auto viewportSnapshotImageBuffer = snapshotFrameRect(*frame, elementRect, { { }, ImageBufferPixelFormat::BGRA8, DestinationColorSpace::SRGB() }); |
| RefPtr viewportSnapshotImage = BitmapImage::create(ImageBuffer::sinkIntoNativeImage(WTFMove(viewportSnapshotImageBuffer))); |
| context.setPotentialQRCodeViewportSnapshotImage(viewportSnapshotImage.get()); |
| } |
| |
| #endif |
| |
| std::unique_ptr<ContextMenu> ContextMenuController::maybeCreateContextMenu(Event& event, OptionSet<HitTestRequest::Type> hitType, ContextMenuContext::Type contextType) |
| { |
| RefPtr mouseEvent = dynamicDowncast<MouseEvent>(event); |
| if (!mouseEvent) |
| return nullptr; |
| |
| RefPtr node = dynamicDowncast<Node>(mouseEvent->target()); |
| if (!node) |
| return nullptr; |
| RefPtr frame = node->document().frame(); |
| if (!frame) |
| return nullptr; |
| |
| auto result = frame->eventHandler().hitTestResultAtPoint(mouseEvent->absoluteLocation(), WTFMove(hitType)); |
| if (!result.innerNonSharedNode()) |
| return nullptr; |
| |
| m_context = { contextType, result, &event }; |
| #if ENABLE(CONTEXT_MENU_QR_CODE_DETECTION) |
| prepareContextForQRCode(m_context); |
| #endif |
| |
| return makeUnique<ContextMenu>(); |
| } |
| |
| void ContextMenuController::showContextMenu(Event& event) |
| { |
| if ((!m_menuProvider || m_menuProvider->contextMenuContextType() == ContextMenuContext::Type::ContextMenu) && m_page->settings().developerExtrasEnabled()) |
| addDebuggingItems(); |
| |
| event.setDefaultHandled(); |
| } |
| |
| void ContextMenuController::didDismissContextMenu() |
| { |
| if (RefPtr menuProvider = m_menuProvider) |
| menuProvider->didDismissContextMenu(); |
| } |
| |
| static void openNewWindow(const URL& urlToLoad, LocalFrame& frame, Event* event, ShouldOpenExternalURLsPolicy shouldOpenExternalURLsPolicy) |
| { |
| RefPtr oldPage = frame.page(); |
| if (!oldPage) |
| return; |
| |
| FrameLoadRequest frameLoadRequest { frame.protectedDocument().releaseNonNull(), frame.document()->protectedSecurityOrigin(), ResourceRequest(URL { urlToLoad }, frame.loader().outgoingReferrer()), { }, InitiatedByMainFrame::Unknown }; |
| frameLoadRequest.setShouldOpenExternalURLsPolicy(shouldOpenExternalURLsPolicy); |
| frameLoadRequest.setNewFrameOpenerPolicy(NewFrameOpenerPolicy::Suppress); |
| |
| RefPtr newPage = oldPage->chrome().createWindow(frame, { }, { }, { *frame.protectedDocument(), frameLoadRequest.resourceRequest(), frameLoadRequest.initiatedByMainFrame(), frameLoadRequest.isRequestFromClientOrUserInput() }); |
| if (!newPage) |
| return; |
| newPage->chrome().show(); |
| if (RefPtr localMainFrame = dynamicDowncast<LocalFrame>(newPage->mainFrame())) |
| localMainFrame->loader().loadFrameRequest(WTFMove(frameLoadRequest), event, { }); |
| } |
| |
| #if PLATFORM(GTK) |
| |
| static void insertUnicodeCharacter(char16_t character, LocalFrame& frame) |
| { |
| String text(span(character)); |
| if (!frame.protectedEditor()->shouldInsertText(text, frame.selection().selection().toNormalizedRange(), EditorInsertAction::Typed)) |
| return; |
| |
| ASSERT(frame.document()); |
| TypingCommand::insertText(*frame.protectedDocument(), text, nullptr, { }, TypingCommand::TextCompositionType::None); |
| } |
| |
| #endif |
| |
| void ContextMenuController::contextMenuItemSelected(ContextMenuAction action, const String& title) |
| { |
| if (action >= ContextMenuItemBaseCustomTag) { |
| ASSERT(m_menuProvider); |
| m_menuProvider->contextMenuItemSelected(action, title); |
| return; |
| } |
| |
| Ref document = m_context.hitTestResult().innerNonSharedNode()->document(); |
| |
| RefPtr frame = document->frame(); |
| if (!frame) |
| return; |
| |
| RefPtr eventForLoadRequests = [&]() -> Event* { |
| #if PLATFORM(COCOA) |
| if (!linkedOnOrAfterSDKWithBehavior(SDKAlignedBehavior::ContextMenuTriggersLinkActivationNavigationType)) |
| return nullptr; |
| #endif |
| return m_context.event(); |
| }(); |
| |
| switch (action) { |
| case ContextMenuItemTagOpenLinkInNewWindow: |
| openNewWindow(m_context.hitTestResult().absoluteLinkURL(), *frame, eventForLoadRequests.get(), ShouldOpenExternalURLsPolicy::ShouldAllowExternalSchemesButNotAppLinks); |
| break; |
| case ContextMenuItemTagDownloadLinkToDisk: |
| // FIXME: Some day we should be able to do this from within WebCore. (Bug 117709) |
| m_client->downloadURL(m_context.hitTestResult().absoluteLinkURL()); |
| break; |
| case ContextMenuItemTagCopyLinkToClipboard: |
| frame->protectedEditor()->copyURL(m_context.hitTestResult().absoluteLinkURL(), m_context.hitTestResult().textContent()); |
| break; |
| case ContextMenuItemTagOpenImageInNewWindow: |
| openNewWindow(m_context.hitTestResult().absoluteImageURL(), *frame, nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow); |
| break; |
| case ContextMenuItemTagDownloadImageToDisk: |
| // FIXME: Some day we should be able to do this from within WebCore. (Bug 117709) |
| m_client->downloadURL(m_context.hitTestResult().absoluteImageURL()); |
| break; |
| case ContextMenuItemTagCopyImageToClipboard: |
| // FIXME: The Pasteboard class is not written yet |
| // For now, call into the client. This is temporary! |
| frame->protectedEditor()->copyImage(m_context.hitTestResult()); |
| break; |
| #if PLATFORM(GTK) |
| case ContextMenuItemTagCopyImageURLToClipboard: |
| frame->protectedEditor()->copyURL(m_context.hitTestResult().absoluteImageURL(), m_context.hitTestResult().textContent()); |
| break; |
| #endif |
| case ContextMenuItemTagOpenMediaInNewWindow: |
| openNewWindow(m_context.hitTestResult().absoluteMediaURL(), *frame, nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow); |
| break; |
| case ContextMenuItemTagDownloadMediaToDisk: |
| // FIXME: Some day we should be able to do this from within WebCore. (Bug 117709) |
| m_client->downloadURL(m_context.hitTestResult().absoluteMediaURL()); |
| break; |
| case ContextMenuItemTagCopyMediaLinkToClipboard: |
| frame->protectedEditor()->copyURL(m_context.hitTestResult().absoluteMediaURL(), m_context.hitTestResult().textContent()); |
| break; |
| case ContextMenuItemTagToggleMediaControls: |
| m_context.hitTestResult().toggleMediaControlsDisplay(); |
| break; |
| case ContextMenuItemTagToggleMediaLoop: |
| m_context.hitTestResult().toggleMediaLoopPlayback(); |
| break; |
| case ContextMenuItemTagShowMediaStats: |
| m_context.hitTestResult().toggleShowMediaStats(); |
| break; |
| case ContextMenuItemTagToggleVideoFullscreen: |
| m_context.hitTestResult().toggleMediaFullscreenState(); |
| break; |
| case ContextMenuItemTagEnterVideoFullscreen: |
| m_context.hitTestResult().enterFullscreenForVideo(); |
| break; |
| case ContextMenuItemTagMediaPlayPause: |
| m_context.hitTestResult().toggleMediaPlayState(); |
| break; |
| case ContextMenuItemTagMediaMute: |
| m_context.hitTestResult().toggleMediaMuteState(); |
| break; |
| case ContextMenuItemTagToggleVideoEnhancedFullscreen: |
| m_context.hitTestResult().toggleEnhancedFullscreenForVideo(); |
| break; |
| case ContextMenuItemTagToggleVideoViewer: |
| m_context.hitTestResult().toggleVideoViewer(); |
| break; |
| case ContextMenuItemTagOpenFrameInNewWindow: { |
| RefPtr loader = frame->loader().documentLoader(); |
| if (!loader->unreachableURL().isEmpty()) |
| openNewWindow(loader->unreachableURL(), *frame, nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow); |
| else |
| openNewWindow(loader->url(), *frame, nullptr, ShouldOpenExternalURLsPolicy::ShouldNotAllow); |
| break; |
| } |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| case ContextMenuItemTagPlayAllAnimations: { |
| if (RefPtr page = frame->page()) |
| page->setImageAnimationEnabled(true); |
| break; |
| } |
| case ContextMenuItemTagPauseAllAnimations: { |
| if (RefPtr page = frame->page()) |
| page->setImageAnimationEnabled(false); |
| break; |
| } |
| case ContextMenuItemTagPlayAnimation: |
| m_context.hitTestResult().playAnimation(); |
| break; |
| case ContextMenuItemTagPauseAnimation: |
| m_context.hitTestResult().pauseAnimation(); |
| break; |
| #endif // ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| case ContextMenuItemTagCopy: |
| frame->protectedEditor()->copy(); |
| break; |
| case ContextMenuItemTagCopyLinkWithHighlight: |
| if (RefPtr page = frame->page()) { |
| auto url = page->fragmentDirectiveURLForSelectedText(); |
| if (url.isValid()) |
| frame->editor().copyURL(url, { }); |
| } |
| break; |
| case ContextMenuItemTagGoBack: |
| if (RefPtr page = frame->page()) |
| page->checkedBackForward()->goBackOrForward(-1); |
| break; |
| case ContextMenuItemTagGoForward: |
| if (RefPtr page = frame->page()) |
| page->checkedBackForward()->goBackOrForward(1); |
| break; |
| case ContextMenuItemTagStop: |
| frame->loader().stop(); |
| break; |
| case ContextMenuItemTagReload: |
| frame->loader().reload(); |
| break; |
| case ContextMenuItemTagCut: |
| frame->editor().command("Cut"_s).execute(); |
| break; |
| case ContextMenuItemTagPaste: |
| frame->editor().command("Paste"_s).execute(); |
| break; |
| #if PLATFORM(GTK) |
| case ContextMenuItemTagPasteAsPlainText: |
| frame->editor().command("PasteAsPlainText"_s).execute(); |
| break; |
| case ContextMenuItemTagDelete: |
| frame->protectedEditor()->performDelete(); |
| break; |
| case ContextMenuItemTagUnicodeInsertLRMMark: |
| insertUnicodeCharacter(leftToRightMark, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertRLMMark: |
| insertUnicodeCharacter(rightToLeftMark, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertLREMark: |
| insertUnicodeCharacter(leftToRightEmbed, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertRLEMark: |
| insertUnicodeCharacter(rightToLeftEmbed, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertLROMark: |
| insertUnicodeCharacter(leftToRightOverride, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertRLOMark: |
| insertUnicodeCharacter(rightToLeftOverride, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertPDFMark: |
| insertUnicodeCharacter(popDirectionalFormatting, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertZWSMark: |
| insertUnicodeCharacter(zeroWidthSpace, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertZWJMark: |
| insertUnicodeCharacter(zeroWidthJoiner, *frame); |
| break; |
| case ContextMenuItemTagUnicodeInsertZWNJMark: |
| insertUnicodeCharacter(zeroWidthNonJoiner, *frame); |
| break; |
| case ContextMenuItemTagSelectAll: |
| frame->editor().command("SelectAll"_s).execute(); |
| break; |
| case ContextMenuItemTagInsertEmoji: |
| m_client->insertEmoji(*frame); |
| break; |
| #endif |
| case ContextMenuItemTagSpellingGuess: { |
| VisibleSelection selection = frame->selection().selection(); |
| if (frame->protectedEditor()->shouldInsertText(title, selection.toNormalizedRange(), EditorInsertAction::Pasted)) { |
| OptionSet<ReplaceSelectionCommand::CommandOption> replaceOptions { ReplaceSelectionCommand::MatchStyle, ReplaceSelectionCommand::PreventNesting }; |
| |
| if (frame->editor().behavior().shouldAllowSpellingSuggestionsWithoutSelection()) { |
| ASSERT(selection.isCaretOrRange()); |
| VisibleSelection wordSelection(selection.base()); |
| wordSelection.expandUsingGranularity(TextGranularity::WordGranularity); |
| frame->checkedSelection()->setSelection(wordSelection); |
| } else { |
| ASSERT(frame->editor().selectedText().length()); |
| replaceOptions.add(ReplaceSelectionCommand::SelectReplacement); |
| } |
| |
| RefPtr document = frame->document(); |
| ASSERT(document); |
| Ref command = ReplaceSelectionCommand::create(*document, createFragmentFromMarkup(*document, title, emptyString()), replaceOptions); |
| command->apply(); |
| frame->checkedSelection()->revealSelection(SelectionRevealMode::Reveal, ScrollAlignment::alignToEdgeIfNeeded); |
| } |
| break; |
| } |
| case ContextMenuItemTagIgnoreSpelling: |
| frame->protectedEditor()->ignoreSpelling(); |
| break; |
| case ContextMenuItemTagLearnSpelling: |
| frame->protectedEditor()->learnSpelling(); |
| break; |
| case ContextMenuItemTagSearchWeb: |
| m_client->searchWithGoogle(frame.get()); |
| break; |
| case ContextMenuItemTagLookUpInDictionary: |
| // FIXME: Some day we may be able to do this from within WebCore. |
| m_client->lookUpInDictionary(frame.get()); |
| break; |
| case ContextMenuItemTagOpenLink: |
| if (RefPtr targetFrame = m_context.hitTestResult().targetFrame()) { |
| ResourceRequest resourceRequest { m_context.hitTestResult().absoluteLinkURL(), frame->loader().outgoingReferrer() }; |
| FrameLoadRequest frameLoadRequest { frame->protectedDocument().releaseNonNull(), frame->document()->securityOrigin(), WTFMove(resourceRequest), { }, InitiatedByMainFrame::Unknown }; |
| frameLoadRequest.setNewFrameOpenerPolicy(NewFrameOpenerPolicy::Suppress); |
| if (targetFrame->isMainFrame()) |
| frameLoadRequest.setShouldOpenExternalURLsPolicy(ShouldOpenExternalURLsPolicy::ShouldAllow); |
| targetFrame->loader().loadFrameRequest(WTFMove(frameLoadRequest), eventForLoadRequests.get(), { }); |
| } else |
| openNewWindow(m_context.hitTestResult().absoluteLinkURL(), *frame, eventForLoadRequests.get(), ShouldOpenExternalURLsPolicy::ShouldAllow); |
| break; |
| case ContextMenuItemTagBold: |
| frame->editor().command("ToggleBold"_s).execute(); |
| break; |
| case ContextMenuItemTagItalic: |
| frame->editor().command("ToggleItalic"_s).execute(); |
| break; |
| case ContextMenuItemTagUnderline: |
| frame->protectedEditor()->toggleUnderline(); |
| break; |
| case ContextMenuItemTagOutline: |
| // We actually never enable this because CSS does not have a way to specify an outline font, |
| // which may make this difficult to implement. Maybe a special case of text-shadow? |
| break; |
| case ContextMenuItemTagStartSpeaking: { |
| auto selectedRange = frame->selection().selection().toNormalizedRange(); |
| if (!selectedRange || selectedRange->collapsed()) |
| selectedRange = makeRangeSelectingNodeContents(document); |
| m_client->speak(plainText(*selectedRange)); |
| break; |
| } |
| case ContextMenuItemTagStopSpeaking: |
| m_client->stopSpeaking(); |
| break; |
| case ContextMenuItemTagDefaultDirection: |
| frame->protectedEditor()->setBaseWritingDirection(WritingDirection::Natural); |
| break; |
| case ContextMenuItemTagLeftToRight: |
| frame->protectedEditor()->setBaseWritingDirection(WritingDirection::LeftToRight); |
| break; |
| case ContextMenuItemTagRightToLeft: |
| frame->protectedEditor()->setBaseWritingDirection(WritingDirection::RightToLeft); |
| break; |
| case ContextMenuItemTagTextDirectionDefault: |
| frame->editor().command("MakeTextWritingDirectionNatural"_s).execute(); |
| break; |
| case ContextMenuItemTagTextDirectionLeftToRight: |
| frame->editor().command("MakeTextWritingDirectionLeftToRight"_s).execute(); |
| break; |
| case ContextMenuItemTagTextDirectionRightToLeft: |
| frame->editor().command("MakeTextWritingDirectionRightToLeft"_s).execute(); |
| break; |
| case ContextMenuItemTagShowSpellingPanel: |
| frame->protectedEditor()->showSpellingGuessPanel(); |
| break; |
| case ContextMenuItemTagCheckSpelling: |
| frame->protectedEditor()->advanceToNextMisspelling(); |
| break; |
| case ContextMenuItemTagCheckSpellingWhileTyping: |
| frame->protectedEditor()->toggleContinuousSpellChecking(); |
| break; |
| case ContextMenuItemTagCheckGrammarWithSpelling: |
| frame->protectedEditor()->toggleGrammarChecking(); |
| break; |
| #if USE(APPKIT) |
| case ContextMenuItemTagMakeUpperCase: |
| frame->protectedEditor()->uppercaseWord(); |
| break; |
| case ContextMenuItemTagMakeLowerCase: |
| frame->protectedEditor()->lowercaseWord(); |
| break; |
| case ContextMenuItemTagCapitalize: |
| frame->protectedEditor()->capitalizeWord(); |
| break; |
| #endif |
| #if PLATFORM(COCOA) |
| case ContextMenuItemTagChangeBack: |
| frame->protectedEditor()->changeBackToReplacedString(m_context.hitTestResult().replacedString()); |
| break; |
| #endif |
| #if USE(AUTOMATIC_TEXT_REPLACEMENT) |
| case ContextMenuItemTagShowSubstitutions: |
| frame->protectedEditor()->showSubstitutionsPanel(); |
| break; |
| case ContextMenuItemTagSmartCopyPaste: |
| frame->protectedEditor()->toggleSmartInsertDelete(); |
| break; |
| case ContextMenuItemTagSmartQuotes: |
| frame->protectedEditor()->toggleAutomaticQuoteSubstitution(); |
| break; |
| case ContextMenuItemTagSmartDashes: |
| frame->protectedEditor()->toggleAutomaticDashSubstitution(); |
| break; |
| case ContextMenuItemTagSmartLinks: |
| frame->protectedEditor()->toggleAutomaticLinkDetection(); |
| break; |
| case ContextMenuItemTagTextReplacement: |
| frame->protectedEditor()->toggleAutomaticTextReplacement(); |
| break; |
| case ContextMenuItemTagCorrectSpellingAutomatically: |
| frame->protectedEditor()->toggleAutomaticSpellingCorrection(); |
| break; |
| #endif |
| case ContextMenuItemTagInspectElement: |
| if (RefPtr page = frame->page()) |
| page->inspectorController().inspect(m_context.hitTestResult().innerNonSharedNode()); |
| break; |
| case ContextMenuItemTagDictationAlternative: |
| frame->protectedEditor()->applyDictationAlternative(title); |
| break; |
| #if PLATFORM(MAC) |
| case ContextMenuItemTagShowFonts: |
| case ContextMenuItemTagStyles: |
| case ContextMenuItemTagShowColors: |
| #endif |
| case ContextMenuItemTagCopySubject: |
| case ContextMenuItemTagLookUpImage: |
| // These should be handled at the client layer. |
| ASSERT_NOT_REACHED(); |
| break; |
| case ContextMenuItemTagTranslate: |
| #if HAVE(TRANSLATION_UI_SERVICES) |
| if (RefPtr view = frame->view()) { |
| m_client->handleTranslation({ |
| m_context.hitTestResult().selectedText(), |
| view->contentsToRootView(enclosingIntRect(frame->selection().selectionBounds())), |
| view->contentsToRootView(m_context.hitTestResult().roundedPointInInnerNodeFrame()), |
| m_context.hitTestResult().isContentEditable() ? TranslationContextMenuMode::Editable : TranslationContextMenuMode::NonEditable, |
| ImageOverlay::isInsideOverlay(frame->selection().selection()) ? TranslationContextMenuSource::Image : TranslationContextMenuSource::Unspecified, |
| }); |
| } |
| #endif |
| break; |
| |
| case ContextMenuItemTagWritingTools: |
| case ContextMenuItemTagProofread: |
| case ContextMenuItemTagRewrite: |
| case ContextMenuItemTagSummarize: |
| // Writing Tools context menu item actions are handled at the client layer. |
| RELEASE_ASSERT_NOT_REACHED(); |
| break; |
| |
| #if ENABLE(PDFJS) |
| case ContextMenuItemPDFAutoSize: |
| performPDFJSAction(*frame, "context-menu-auto-size"_s); |
| break; |
| case ContextMenuItemPDFZoomIn: |
| performPDFJSAction(*frame, "context-menu-zoom-in"_s); |
| break; |
| case ContextMenuItemPDFZoomOut: |
| performPDFJSAction(*frame, "context-menu-zoom-out"_s); |
| break; |
| case ContextMenuItemPDFActualSize: |
| performPDFJSAction(*frame, "context-menu-actual-size"_s); |
| break; |
| case ContextMenuItemPDFSinglePage: |
| performPDFJSAction(*frame, "context-menu-single-page"_s); |
| break; |
| case ContextMenuItemPDFSinglePageContinuous: |
| performPDFJSAction(*frame, "context-menu-single-page-continuous"_s); |
| break; |
| case ContextMenuItemPDFTwoPages: |
| performPDFJSAction(*frame, "context-menu-two-pages"_s); |
| break; |
| case ContextMenuItemPDFTwoPagesContinuous: |
| performPDFJSAction(*frame, "context-menu-two-pages-continuous"_s); |
| break; |
| case ContextMenuItemPDFNextPage: |
| performPDFJSAction(*frame, "context-menu-next-page"_s); |
| break; |
| case ContextMenuItemPDFPreviousPage: |
| performPDFJSAction(*frame, "context-menu-previous-page"_s); |
| break; |
| #endif |
| default: |
| break; |
| } |
| } |
| |
| void ContextMenuController::appendItem(ContextMenuItem& menuItem, ContextMenu* parentMenu) |
| { |
| checkOrEnableIfNeeded(menuItem); |
| if (parentMenu) |
| parentMenu->appendItem(menuItem); |
| } |
| |
| void ContextMenuController::createAndAppendFontSubMenu(ContextMenuItem& fontMenuItem) |
| { |
| ContextMenu fontMenu; |
| |
| #if PLATFORM(COCOA) |
| ContextMenuItem showFonts(ContextMenuItemType::Action, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts()); |
| #endif |
| ContextMenuItem bold(ContextMenuItemType::CheckableAction, ContextMenuItemTagBold, contextMenuItemTagBold()); |
| ContextMenuItem italic(ContextMenuItemType::CheckableAction, ContextMenuItemTagItalic, contextMenuItemTagItalic()); |
| ContextMenuItem underline(ContextMenuItemType::CheckableAction, ContextMenuItemTagUnderline, contextMenuItemTagUnderline()); |
| ContextMenuItem outline(ContextMenuItemType::Action, ContextMenuItemTagOutline, contextMenuItemTagOutline()); |
| #if PLATFORM(COCOA) |
| ContextMenuItem styles(ContextMenuItemType::Action, ContextMenuItemTagStyles, contextMenuItemTagStyles()); |
| ContextMenuItem showColors(ContextMenuItemType::Action, ContextMenuItemTagShowColors, contextMenuItemTagShowColors()); |
| appendItem(showFonts, &fontMenu); |
| appendItem(*separatorItem(), &fontMenu); |
| #endif |
| appendItem(bold, &fontMenu); |
| appendItem(italic, &fontMenu); |
| appendItem(underline, &fontMenu); |
| appendItem(*separatorItem(), &fontMenu); |
| appendItem(outline, &fontMenu); |
| #if PLATFORM(COCOA) |
| appendItem(styles, &fontMenu); |
| appendItem(showColors, &fontMenu); |
| #endif |
| |
| fontMenuItem.setSubMenu(&fontMenu); |
| } |
| |
| |
| #if !PLATFORM(GTK) |
| |
| void ContextMenuController::createAndAppendSpellingAndGrammarSubMenu(ContextMenuItem& spellingAndGrammarMenuItem) |
| { |
| ContextMenu spellingAndGrammarMenu; |
| |
| ContextMenuItem showSpellingPanel(ContextMenuItemType::Action, ContextMenuItemTagShowSpellingPanel, |
| contextMenuItemTagShowSpellingPanel(true)); |
| ContextMenuItem checkSpelling(ContextMenuItemType::Action, ContextMenuItemTagCheckSpelling, |
| contextMenuItemTagCheckSpelling()); |
| ContextMenuItem checkAsYouType(ContextMenuItemType::CheckableAction, ContextMenuItemTagCheckSpellingWhileTyping, |
| contextMenuItemTagCheckSpellingWhileTyping()); |
| ContextMenuItem grammarWithSpelling(ContextMenuItemType::CheckableAction, ContextMenuItemTagCheckGrammarWithSpelling, |
| contextMenuItemTagCheckGrammarWithSpelling()); |
| #if PLATFORM(COCOA) |
| ContextMenuItem correctSpelling(ContextMenuItemType::CheckableAction, ContextMenuItemTagCorrectSpellingAutomatically, |
| contextMenuItemTagCorrectSpellingAutomatically()); |
| #endif |
| |
| appendItem(showSpellingPanel, &spellingAndGrammarMenu); |
| appendItem(checkSpelling, &spellingAndGrammarMenu); |
| #if PLATFORM(COCOA) |
| appendItem(*separatorItem(), &spellingAndGrammarMenu); |
| #endif |
| appendItem(checkAsYouType, &spellingAndGrammarMenu); |
| appendItem(grammarWithSpelling, &spellingAndGrammarMenu); |
| #if PLATFORM(COCOA) |
| appendItem(correctSpelling, &spellingAndGrammarMenu); |
| #endif |
| |
| spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu); |
| } |
| |
| #endif // !PLATFORM(GTK) |
| |
| |
| #if PLATFORM(COCOA) |
| |
| void ContextMenuController::createAndAppendSpeechSubMenu(ContextMenuItem& speechMenuItem) |
| { |
| ContextMenu speechMenu; |
| |
| ContextMenuItem start(ContextMenuItemType::Action, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking()); |
| ContextMenuItem stop(ContextMenuItemType::Action, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking()); |
| |
| appendItem(start, &speechMenu); |
| appendItem(stop, &speechMenu); |
| |
| speechMenuItem.setSubMenu(&speechMenu); |
| } |
| |
| #endif |
| |
| #if PLATFORM(GTK) |
| |
| void ContextMenuController::createAndAppendUnicodeSubMenu(ContextMenuItem& unicodeMenuItem) |
| { |
| ContextMenu unicodeMenu; |
| |
| ContextMenuItem leftToRightMarkMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertLRMMark, contextMenuItemTagUnicodeInsertLRMMark()); |
| ContextMenuItem rightToLeftMarkMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertRLMMark, contextMenuItemTagUnicodeInsertRLMMark()); |
| ContextMenuItem leftToRightEmbedMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertLREMark, contextMenuItemTagUnicodeInsertLREMark()); |
| ContextMenuItem rightToLeftEmbedMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertRLEMark, contextMenuItemTagUnicodeInsertRLEMark()); |
| ContextMenuItem leftToRightOverrideMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertLROMark, contextMenuItemTagUnicodeInsertLROMark()); |
| ContextMenuItem rightToLeftOverrideMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertRLOMark, contextMenuItemTagUnicodeInsertRLOMark()); |
| ContextMenuItem popDirectionalFormattingMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertPDFMark, contextMenuItemTagUnicodeInsertPDFMark()); |
| ContextMenuItem zeroWidthSpaceMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertZWSMark, contextMenuItemTagUnicodeInsertZWSMark()); |
| ContextMenuItem zeroWidthJoinerMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertZWJMark, contextMenuItemTagUnicodeInsertZWJMark()); |
| ContextMenuItem zeroWidthNonJoinerMenuItem(ContextMenuItemType::Action, ContextMenuItemTagUnicodeInsertZWNJMark, contextMenuItemTagUnicodeInsertZWNJMark()); |
| |
| appendItem(leftToRightMarkMenuItem, &unicodeMenu); |
| appendItem(rightToLeftMarkMenuItem, &unicodeMenu); |
| appendItem(leftToRightEmbedMenuItem, &unicodeMenu); |
| appendItem(rightToLeftEmbedMenuItem, &unicodeMenu); |
| appendItem(leftToRightOverrideMenuItem, &unicodeMenu); |
| appendItem(rightToLeftOverrideMenuItem, &unicodeMenu); |
| appendItem(popDirectionalFormattingMenuItem, &unicodeMenu); |
| appendItem(zeroWidthSpaceMenuItem, &unicodeMenu); |
| appendItem(zeroWidthJoinerMenuItem, &unicodeMenu); |
| appendItem(zeroWidthNonJoinerMenuItem, &unicodeMenu); |
| |
| unicodeMenuItem.setSubMenu(&unicodeMenu); |
| } |
| |
| #else |
| |
| void ContextMenuController::createAndAppendWritingDirectionSubMenu(ContextMenuItem& writingDirectionMenuItem) |
| { |
| ContextMenu writingDirectionMenu; |
| |
| ContextMenuItem defaultItem(ContextMenuItemType::Action, ContextMenuItemTagDefaultDirection, |
| contextMenuItemTagDefaultDirection()); |
| ContextMenuItem ltr(ContextMenuItemType::CheckableAction, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight()); |
| ContextMenuItem rtl(ContextMenuItemType::CheckableAction, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft()); |
| |
| appendItem(defaultItem, &writingDirectionMenu); |
| appendItem(ltr, &writingDirectionMenu); |
| appendItem(rtl, &writingDirectionMenu); |
| |
| writingDirectionMenuItem.setSubMenu(&writingDirectionMenu); |
| } |
| |
| void ContextMenuController::createAndAppendTextDirectionSubMenu(ContextMenuItem& textDirectionMenuItem) |
| { |
| ContextMenu textDirectionMenu; |
| |
| ContextMenuItem defaultItem(ContextMenuItemType::Action, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection()); |
| ContextMenuItem ltr(ContextMenuItemType::CheckableAction, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight()); |
| ContextMenuItem rtl(ContextMenuItemType::CheckableAction, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft()); |
| |
| appendItem(defaultItem, &textDirectionMenu); |
| appendItem(ltr, &textDirectionMenu); |
| appendItem(rtl, &textDirectionMenu); |
| |
| textDirectionMenuItem.setSubMenu(&textDirectionMenu); |
| } |
| |
| #endif |
| |
| #if PLATFORM(COCOA) |
| |
| void ContextMenuController::createAndAppendSubstitutionsSubMenu(ContextMenuItem& substitutionsMenuItem) |
| { |
| ContextMenu substitutionsMenu; |
| |
| ContextMenuItem showSubstitutions(ContextMenuItemType::Action, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true)); |
| ContextMenuItem smartCopyPaste(ContextMenuItemType::CheckableAction, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste()); |
| ContextMenuItem smartQuotes(ContextMenuItemType::CheckableAction, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes()); |
| ContextMenuItem smartDashes(ContextMenuItemType::CheckableAction, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes()); |
| ContextMenuItem smartLinks(ContextMenuItemType::CheckableAction, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks()); |
| ContextMenuItem textReplacement(ContextMenuItemType::CheckableAction, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement()); |
| |
| appendItem(showSubstitutions, &substitutionsMenu); |
| appendItem(*separatorItem(), &substitutionsMenu); |
| appendItem(smartCopyPaste, &substitutionsMenu); |
| appendItem(smartQuotes, &substitutionsMenu); |
| appendItem(smartDashes, &substitutionsMenu); |
| appendItem(smartLinks, &substitutionsMenu); |
| appendItem(textReplacement, &substitutionsMenu); |
| |
| substitutionsMenuItem.setSubMenu(&substitutionsMenu); |
| } |
| |
| void ContextMenuController::createAndAppendTransformationsSubMenu(ContextMenuItem& transformationsMenuItem) |
| { |
| ContextMenu transformationsMenu; |
| |
| ContextMenuItem makeUpperCase(ContextMenuItemType::Action, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase()); |
| ContextMenuItem makeLowerCase(ContextMenuItemType::Action, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase()); |
| ContextMenuItem capitalize(ContextMenuItemType::Action, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize()); |
| |
| appendItem(makeUpperCase, &transformationsMenu); |
| appendItem(makeLowerCase, &transformationsMenu); |
| appendItem(capitalize, &transformationsMenu); |
| |
| transformationsMenuItem.setSubMenu(&transformationsMenu); |
| } |
| |
| #endif |
| |
| #if PLATFORM(COCOA) |
| #define SUPPORTS_TOGGLE_VIDEO_FULLSCREEN 1 |
| #else |
| #define SUPPORTS_TOGGLE_VIDEO_FULLSCREEN 0 |
| #endif |
| |
| #if PLATFORM(COCOA) |
| #define SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS 1 |
| #else |
| #define SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS 0 |
| #endif |
| |
| void ContextMenuController::populate() |
| { |
| ContextMenuItem OpenLinkItem(ContextMenuItemType::Action, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); |
| ContextMenuItem OpenLinkInNewWindowItem(ContextMenuItemType::Action, ContextMenuItemTagOpenLinkInNewWindow, |
| contextMenuItemTagOpenLinkInNewWindow()); |
| ContextMenuItem DownloadFileItem(ContextMenuItemType::Action, ContextMenuItemTagDownloadLinkToDisk, |
| contextMenuItemTagDownloadLinkToDisk()); |
| ContextMenuItem CopyLinkItem(ContextMenuItemType::Action, ContextMenuItemTagCopyLinkToClipboard, |
| contextMenuItemTagCopyLinkToClipboard()); |
| ContextMenuItem OpenImageInNewWindowItem(ContextMenuItemType::Action, ContextMenuItemTagOpenImageInNewWindow, |
| contextMenuItemTagOpenImageInNewWindow()); |
| ContextMenuItem DownloadImageItem(ContextMenuItemType::Action, ContextMenuItemTagDownloadImageToDisk, |
| contextMenuItemTagDownloadImageToDisk()); |
| ContextMenuItem CopyImageItem(ContextMenuItemType::Action, ContextMenuItemTagCopyImageToClipboard, |
| contextMenuItemTagCopyImageToClipboard()); |
| #if PLATFORM(GTK) |
| ContextMenuItem CopyImageURLItem(ContextMenuItemType::Action, ContextMenuItemTagCopyImageURLToClipboard, |
| contextMenuItemTagCopyImageURLToClipboard()); |
| #endif |
| ContextMenuItem OpenMediaInNewWindowItem(ContextMenuItemType::Action, ContextMenuItemTagOpenMediaInNewWindow, String()); |
| ContextMenuItem DownloadMediaItem(ContextMenuItemType::Action, ContextMenuItemTagDownloadMediaToDisk, String()); |
| ContextMenuItem CopyMediaLinkItem(ContextMenuItemType::Action, ContextMenuItemTagCopyMediaLinkToClipboard, String()); |
| ContextMenuItem MediaPlayPause(ContextMenuItemType::Action, ContextMenuItemTagMediaPlayPause, |
| contextMenuItemTagMediaPlay()); |
| ContextMenuItem MediaMute(ContextMenuItemType::Action, ContextMenuItemTagMediaMute, |
| contextMenuItemTagMediaMute()); |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| ContextMenuItem PlayAllAnimations(ContextMenuItemType::Action, ContextMenuItemTagPlayAllAnimations, contextMenuItemTagPlayAllAnimations()); |
| ContextMenuItem PauseAllAnimations(ContextMenuItemType::Action, ContextMenuItemTagPauseAllAnimations, contextMenuItemTagPauseAllAnimations()); |
| ContextMenuItem PlayAnimation(ContextMenuItemType::Action, ContextMenuItemTagPlayAnimation, contextMenuItemTagPlayAnimation()); |
| ContextMenuItem PauseAnimation(ContextMenuItemType::Action, ContextMenuItemTagPauseAnimation, contextMenuItemTagPauseAnimation()); |
| #endif // ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| #if SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS |
| ContextMenuItem ToggleMediaControls(ContextMenuItemType::Action, ContextMenuItemTagToggleMediaControls, |
| contextMenuItemTagHideMediaControls()); |
| #else |
| ContextMenuItem ToggleMediaControls(ContextMenuItemType::CheckableAction, ContextMenuItemTagToggleMediaControls, |
| contextMenuItemTagToggleMediaControls()); |
| #endif |
| ContextMenuItem ToggleMediaLoop(ContextMenuItemType::CheckableAction, ContextMenuItemTagToggleMediaLoop, |
| contextMenuItemTagToggleMediaLoop()); |
| ContextMenuItem EnterVideoFullscreen(ContextMenuItemType::Action, ContextMenuItemTagEnterVideoFullscreen, |
| contextMenuItemTagEnterVideoFullscreen()); |
| ContextMenuItem ToggleVideoFullscreen(ContextMenuItemType::Action, ContextMenuItemTagToggleVideoFullscreen, |
| contextMenuItemTagEnterVideoFullscreen()); |
| #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE) |
| ContextMenuItem ToggleVideoEnhancedFullscreen(ContextMenuItemType::Action, ContextMenuItemTagToggleVideoEnhancedFullscreen, contextMenuItemTagEnterVideoEnhancedFullscreen()); |
| ContextMenuItem ToggleVideoViewer(ContextMenuItemType::Action, ContextMenuItemTagToggleVideoViewer, contextMenuItemTagEnterVideoViewer()); |
| #endif |
| |
| #if ENABLE(PDFJS) |
| ContextMenuItem PDFAutoSizeItem(ContextMenuItemType::Action, ContextMenuItemPDFAutoSize, contextMenuItemPDFAutoSize()); |
| ContextMenuItem PDFZoomInItem(ContextMenuItemType::Action, ContextMenuItemPDFZoomIn, contextMenuItemPDFZoomIn()); |
| ContextMenuItem PDFZoomOutItem(ContextMenuItemType::Action, ContextMenuItemPDFZoomOut, contextMenuItemPDFZoomOut()); |
| ContextMenuItem PDFActualSizeItem(ContextMenuItemType::Action, ContextMenuItemPDFActualSize, contextMenuItemPDFActualSize()); |
| |
| ContextMenuItem PDFSinglePageItem(ContextMenuItemType::Action, ContextMenuItemPDFSinglePage, contextMenuItemPDFSinglePage()); |
| ContextMenuItem PDFSinglePageContinuousItem(ContextMenuItemType::Action, ContextMenuItemPDFSinglePageContinuous, contextMenuItemPDFSinglePageContinuous()); |
| ContextMenuItem PDFTwoPagesItem(ContextMenuItemType::Action, ContextMenuItemPDFTwoPages, contextMenuItemPDFTwoPages()); |
| ContextMenuItem PDFTwoPagesContinuousItem(ContextMenuItemType::Action, ContextMenuItemPDFTwoPagesContinuous, contextMenuItemPDFTwoPagesContinuous()); |
| |
| ContextMenuItem PDFNextPageItem(ContextMenuItemType::Action, ContextMenuItemPDFNextPage, contextMenuItemPDFNextPage()); |
| ContextMenuItem PDFPreviousPageItem(ContextMenuItemType::Action, ContextMenuItemPDFPreviousPage, contextMenuItemPDFPreviousPage()); |
| #endif |
| |
| #if ENABLE(APP_HIGHLIGHTS) |
| ContextMenuItem AddHighlightItem(ContextMenuItemType::Action, ContextMenuItemTagAddHighlightToCurrentQuickNote, contextMenuItemTagAddHighlightToCurrentQuickNote()); |
| ContextMenuItem AddHighlightToNewQuickNoteItem(ContextMenuItemType::Action, ContextMenuItemTagAddHighlightToNewQuickNote, contextMenuItemTagAddHighlightToNewQuickNote()); |
| #endif |
| ContextMenuItem CopyLinkWithHighlightItem(ContextMenuItemType::Action, ContextMenuItemTagCopyLinkWithHighlight, contextMenuItemTagCopyLinkWithHighlight()); |
| #if !PLATFORM(GTK) |
| ContextMenuItem SearchWebItem(ContextMenuItemType::Action, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb()); |
| #endif |
| ContextMenuItem CopyItem(ContextMenuItemType::Action, ContextMenuItemTagCopy, contextMenuItemTagCopy()); |
| ContextMenuItem BackItem(ContextMenuItemType::Action, ContextMenuItemTagGoBack, contextMenuItemTagGoBack()); |
| ContextMenuItem ForwardItem(ContextMenuItemType::Action, ContextMenuItemTagGoForward, contextMenuItemTagGoForward()); |
| ContextMenuItem StopItem(ContextMenuItemType::Action, ContextMenuItemTagStop, contextMenuItemTagStop()); |
| ContextMenuItem ReloadItem(ContextMenuItemType::Action, ContextMenuItemTagReload, contextMenuItemTagReload()); |
| ContextMenuItem OpenFrameItem(ContextMenuItemType::Action, ContextMenuItemTagOpenFrameInNewWindow, |
| contextMenuItemTagOpenFrameInNewWindow()); |
| ContextMenuItem NoGuessesItem(ContextMenuItemType::Action, ContextMenuItemTagNoGuessesFound, |
| contextMenuItemTagNoGuessesFound()); |
| ContextMenuItem IgnoreSpellingItem(ContextMenuItemType::Action, ContextMenuItemTagIgnoreSpelling, |
| contextMenuItemTagIgnoreSpelling()); |
| ContextMenuItem LearnSpellingItem(ContextMenuItemType::Action, ContextMenuItemTagLearnSpelling, |
| contextMenuItemTagLearnSpelling()); |
| ContextMenuItem IgnoreGrammarItem(ContextMenuItemType::Action, ContextMenuItemTagIgnoreGrammar, |
| contextMenuItemTagIgnoreGrammar()); |
| ContextMenuItem CutItem(ContextMenuItemType::Action, ContextMenuItemTagCut, contextMenuItemTagCut()); |
| ContextMenuItem PasteItem(ContextMenuItemType::Action, ContextMenuItemTagPaste, contextMenuItemTagPaste()); |
| #if PLATFORM(GTK) |
| ContextMenuItem PasteAsPlainTextItem(ContextMenuItemType::Action, ContextMenuItemTagPasteAsPlainText, contextMenuItemTagPasteAsPlainText()); |
| ContextMenuItem DeleteItem(ContextMenuItemType::Action, ContextMenuItemTagDelete, contextMenuItemTagDelete()); |
| ContextMenuItem SelectAllItem(ContextMenuItemType::Action, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll()); |
| ContextMenuItem InsertEmojiItem(ContextMenuItemType::Action, ContextMenuItemTagInsertEmoji, contextMenuItemTagInsertEmoji()); |
| #endif |
| #if ENABLE(IMAGE_ANALYSIS) |
| ContextMenuItem LookUpImageItem(ContextMenuItemType::Action, ContextMenuItemTagLookUpImage, contextMenuItemTagLookUpImage()); |
| #endif |
| |
| #if PLATFORM(GTK) || PLATFORM(WIN) |
| ContextMenuItem ShareMenuItem; |
| #else |
| ContextMenuItem ShareMenuItem(ContextMenuItemType::Action, ContextMenuItemTagShareMenu, emptyString()); |
| #endif |
| |
| #if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS) |
| ContextMenuItem copySubjectItem { ContextMenuItemType::Action, ContextMenuItemTagCopySubject, contextMenuItemTagCopySubject() }; |
| #endif |
| |
| RefPtr node = m_context.hitTestResult().innerNonSharedNode(); |
| if (!node) |
| return; |
| #if PLATFORM(GTK) |
| if (!m_context.hitTestResult().isContentEditable() && is<HTMLFormControlElement>(*node)) |
| return; |
| #endif |
| RefPtr frame = node->document().frame(); |
| if (!frame) |
| return; |
| |
| #if ENABLE(SERVICE_CONTROLS) |
| // The default image control menu gets populated solely by the platform. |
| if (m_context.controlledImage()) |
| return; |
| #endif |
| |
| auto addSelectedTextActionsIfNeeded = [&] (const String& selectedText) { |
| if (selectedText.isEmpty()) |
| return; |
| |
| #if PLATFORM(COCOA) |
| ContextMenuItem lookUpInDictionaryItem(ContextMenuItemType::Action, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary(selectedText)); |
| appendItem(lookUpInDictionaryItem, m_contextMenu.get()); |
| #endif |
| |
| #if HAVE(TRANSLATION_UI_SERVICES) |
| ContextMenuItem translateItem(ContextMenuItemType::Action, ContextMenuItemTagTranslate, contextMenuItemTagTranslate(selectedText)); |
| appendItem(translateItem, m_contextMenu.get()); |
| #endif |
| |
| #if PLATFORM(COCOA) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| #endif |
| |
| #if !PLATFORM(GTK) |
| appendItem(SearchWebItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| #endif |
| }; |
| |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| auto canAddAnimationControls = [&] () -> bool { |
| if (!frame->page() || !frame->page()->settings().imageAnimationControlEnabled()) |
| return false; |
| |
| return Image::systemAllowsAnimationControls() || frame->page()->settings().allowAnimationControlsOverride(); |
| }; |
| |
| bool shouldAddPlayAllPauseAllAnimationsItem = canAddAnimationControls(); |
| auto addPlayAllPauseAllAnimationsItem = [&] () { |
| if (!shouldAddPlayAllPauseAllAnimationsItem) |
| return; |
| // Only add this item once. |
| shouldAddPlayAllPauseAllAnimationsItem = false; |
| |
| if (frame->page()->imageAnimationEnabled()) |
| appendItem(PauseAllAnimations, m_contextMenu.get()); |
| else |
| appendItem(PlayAllAnimations, m_contextMenu.get()); |
| }; |
| #endif |
| |
| auto selectedText = m_context.hitTestResult().selectedText(); |
| m_context.setSelectedText(selectedText); |
| |
| if (!m_context.hitTestResult().isContentEditable()) { |
| Ref loader = frame->loader(); |
| URL linkURL = m_context.hitTestResult().absoluteLinkURL(); |
| const bool linkURLEmpty = linkURL.isEmpty(); |
| if (!linkURLEmpty) { |
| if (loader->client().canHandleRequest(ResourceRequest(WTFMove(linkURL)))) { |
| appendItem(OpenLinkItem, m_contextMenu.get()); |
| appendItem(OpenLinkInNewWindowItem, m_contextMenu.get()); |
| appendItem(DownloadFileItem, m_contextMenu.get()); |
| } |
| appendItem(CopyLinkItem, m_contextMenu.get()); |
| } |
| |
| URL imageURL = m_context.hitTestResult().absoluteImageURL(); |
| if (!imageURL.isEmpty()) { |
| if (!linkURLEmpty) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| appendItem(OpenImageInNewWindowItem, m_contextMenu.get()); |
| appendItem(DownloadImageItem, m_contextMenu.get()); |
| |
| RefPtr image = m_context.hitTestResult().image(); |
| if (imageURL.protocolIsFile() || image) { |
| appendItem(CopyImageItem, m_contextMenu.get()); |
| |
| if (image && !image->isAnimated()) { |
| #if ENABLE(IMAGE_ANALYSIS_ENHANCEMENTS) |
| if (m_client->supportsCopySubject()) |
| appendItem(copySubjectItem, m_contextMenu.get()); |
| #endif |
| #if ENABLE(IMAGE_ANALYSIS) |
| if (m_client->supportsLookUpInImages()) |
| appendItem(LookUpImageItem, m_contextMenu.get()); |
| #endif |
| } |
| |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| if (image && image->isAnimated() && canAddAnimationControls()) { |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| if (m_context.hitTestResult().isAnimating()) |
| appendItem(PauseAnimation, m_contextMenu.get()); |
| else |
| appendItem(PlayAnimation, m_contextMenu.get()); |
| // If the individual animation control action is available, group the Pause All Animations / Play All Animations action with it. |
| addPlayAllPauseAllAnimationsItem(); |
| } |
| #endif // ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| } |
| #if PLATFORM(GTK) |
| appendItem(CopyImageURLItem, m_contextMenu.get()); |
| #endif |
| } |
| |
| URL mediaURL = m_context.hitTestResult().absoluteMediaURL(); |
| const bool mediaURLEmpty = mediaURL.isEmpty(); |
| if (!mediaURLEmpty) { |
| if (!linkURLEmpty || !imageURL.isEmpty()) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| appendItem(MediaPlayPause, m_contextMenu.get()); |
| appendItem(MediaMute, m_contextMenu.get()); |
| appendItem(ToggleMediaControls, m_contextMenu.get()); |
| appendItem(ToggleMediaLoop, m_contextMenu.get()); |
| #if SUPPORTS_TOGGLE_VIDEO_FULLSCREEN |
| if (!m_context.hitTestResult().mediaIsInVideoViewer()) |
| appendItem(ToggleVideoFullscreen, m_contextMenu.get()); |
| #else |
| appendItem(EnterVideoFullscreen, m_contextMenu.get()); |
| #endif |
| #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE) |
| appendItem(ToggleVideoEnhancedFullscreen, m_contextMenu.get()); |
| appendItem(ToggleVideoViewer, m_contextMenu.get()); |
| #endif |
| if (m_context.hitTestResult().isDownloadableMedia() && loader->client().canHandleRequest(ResourceRequest(WTFMove(mediaURL)))) { |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| appendItem(CopyMediaLinkItem, m_contextMenu.get()); |
| appendItem(OpenMediaInNewWindowItem, m_contextMenu.get()); |
| appendItem(DownloadMediaItem, m_contextMenu.get()); |
| } |
| } |
| |
| auto selectedRange = frame->selection().selection().range(); |
| bool selectionIsInsideImageOverlay = selectedRange && ImageOverlay::isInsideOverlay(*selectedRange); |
| if (selectionIsInsideImageOverlay || (linkURLEmpty && mediaURLEmpty && imageURL.isEmpty())) { |
| if (!imageURL.isEmpty()) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| RefPtr page = frame->page(); |
| RefPtr ownerElement = frame->ownerElement(); |
| bool isPDFDocument = ownerElement && ownerElement->document().isPDFDocument(); |
| bool isMainFrame = frame->isMainFrame(); |
| |
| if (m_context.hitTestResult().isSelected()) { |
| addSelectedTextActionsIfNeeded(selectedText); |
| |
| appendItem(CopyItem, m_contextMenu.get()); |
| if (!selectionIsInsideImageOverlay && isMainFrame && page && page->settings().scrollToTextFragmentGenerationEnabled()) |
| appendItem(CopyLinkWithHighlightItem, m_contextMenu.get()); |
| #if PLATFORM(COCOA) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| #if ENABLE(APP_HIGHLIGHTS) |
| if (page && page->settings().appHighlightsEnabled() && !selectionIsInsideImageOverlay) { |
| appendItem(AddHighlightToNewQuickNoteItem, m_contextMenu.get()); |
| appendItem(AddHighlightItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| } |
| #endif |
| |
| appendItem(ShareMenuItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| #if ENABLE(WRITING_TOOLS) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| ContextMenuItem writingToolsItem(ContextMenuItemType::Action, ContextMenuItemTagWritingTools, contextMenuItemTagWritingTools()); |
| appendItem(writingToolsItem, m_contextMenu.get()); |
| #if ENABLE(TOP_LEVEL_WRITING_TOOLS_CONTEXT_MENU_ITEMS) |
| ContextMenuItem summarizeItem(ContextMenuItemType::Action, ContextMenuItemTagSummarize, contextMenuItemTagSummarize()); |
| appendItem(summarizeItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| #endif |
| #endif |
| |
| ContextMenuItem SpeechMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); |
| createAndAppendSpeechSubMenu(SpeechMenuItem); |
| appendItem(SpeechMenuItem, m_contextMenu.get()); |
| #endif |
| } else { |
| if (!(page && (page->inspectorController().inspectionLevel() > 0 || page->inspectorController().hasRemoteFrontend()))) { |
| |
| // In GTK+ unavailable items are not hidden but insensitive. |
| #if PLATFORM(GTK) |
| appendItem(BackItem, m_contextMenu.get()); |
| appendItem(ForwardItem, m_contextMenu.get()); |
| appendItem(StopItem, m_contextMenu.get()); |
| appendItem(ReloadItem, m_contextMenu.get()); |
| #else |
| |
| if (isMainFrame) { |
| if (page && page->checkedBackForward()->canGoBackOrForward(-1)) |
| appendItem(BackItem, m_contextMenu.get()); |
| |
| if (page && page->checkedBackForward()->canGoBackOrForward(1)) |
| appendItem(ForwardItem, m_contextMenu.get()); |
| |
| // Here we use isLoadingInAPISense rather than isLoading because Stop/Reload are |
| // intended to match WebKit's API, not WebCore's internal notion of loading status. |
| if (loader->documentLoader()->isLoadingInAPISense()) |
| appendItem(StopItem, m_contextMenu.get()); |
| else |
| appendItem(ReloadItem, m_contextMenu.get()); |
| } |
| #endif |
| } |
| |
| if (page && !isMainFrame && !isPDFDocument) |
| appendItem(OpenFrameItem, m_contextMenu.get()); |
| if (!ShareMenuItem.isNull()) { |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| appendItem(ShareMenuItem, m_contextMenu.get()); |
| } |
| } |
| #if ENABLE(PDFJS) |
| if (isPDFDocument) { |
| if (m_contextMenu && !m_contextMenu->items().isEmpty()) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| appendItem(PDFAutoSizeItem, m_contextMenu.get()); |
| appendItem(PDFZoomInItem, m_contextMenu.get()); |
| appendItem(PDFZoomOutItem, m_contextMenu.get()); |
| appendItem(PDFActualSizeItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| appendItem(PDFSinglePageItem, m_contextMenu.get()); |
| appendItem(PDFSinglePageContinuousItem, m_contextMenu.get()); |
| appendItem(PDFTwoPagesItem, m_contextMenu.get()); |
| appendItem(PDFTwoPagesContinuousItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| appendItem(PDFNextPageItem, m_contextMenu.get()); |
| appendItem(PDFPreviousPageItem, m_contextMenu.get()); |
| } |
| #endif |
| } else if (!ShareMenuItem.isNull()) { |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| appendItem(ShareMenuItem, m_contextMenu.get()); |
| } |
| } else { // Make an editing context menu |
| bool inPasswordField = frame->selection().selection().isInPasswordField(); |
| if (!inPasswordField) { |
| bool haveContextMenuItemsForMisspellingOrGrammer = false; |
| bool spellCheckingEnabled = frame->editor().isSpellCheckingEnabledFor(node.get()); |
| if (spellCheckingEnabled) { |
| // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range |
| // is never considered a misspelling and bad grammar at the same time) |
| auto [guesses, misspelling, badGrammar] = frame->editor().guessesForMisspelledOrUngrammatical(); |
| if (misspelling || badGrammar) { |
| if (guesses.isEmpty()) { |
| // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions |
| // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit) |
| if (misspelling) { |
| appendItem(NoGuessesItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| } |
| } else { |
| for (const auto& guess : guesses) { |
| if (!guess.isEmpty()) { |
| ContextMenuItem item(ContextMenuItemType::Action, ContextMenuItemTagSpellingGuess, guess); |
| appendItem(item, m_contextMenu.get()); |
| } |
| } |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| } |
| if (misspelling) { |
| appendItem(IgnoreSpellingItem, m_contextMenu.get()); |
| appendItem(LearnSpellingItem, m_contextMenu.get()); |
| } else |
| appendItem(IgnoreGrammarItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| haveContextMenuItemsForMisspellingOrGrammer = true; |
| #if PLATFORM(COCOA) |
| } else { |
| // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. |
| String replacedString = m_context.hitTestResult().replacedString(); |
| if (!replacedString.isEmpty()) { |
| ContextMenuItem item(ContextMenuItemType::Action, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString)); |
| appendItem(item, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| haveContextMenuItemsForMisspellingOrGrammer = true; |
| } |
| #endif |
| } |
| } |
| |
| if (!haveContextMenuItemsForMisspellingOrGrammer) { |
| // Spelling and grammar checking is mutually exclusive with dictation alternatives. |
| Vector<String> dictationAlternatives = m_context.hitTestResult().dictationAlternatives(); |
| if (!dictationAlternatives.isEmpty()) { |
| for (auto& alternative : dictationAlternatives) { |
| ContextMenuItem item(ContextMenuItemType::Action, ContextMenuItemTagDictationAlternative, alternative); |
| appendItem(item, m_contextMenu.get()); |
| } |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| } |
| } |
| } |
| |
| Ref loader = frame->loader(); |
| URL linkURL = m_context.hitTestResult().absoluteLinkURL(); |
| if (!linkURL.isEmpty()) { |
| if (loader->client().canHandleRequest(ResourceRequest(WTFMove(linkURL)))) { |
| appendItem(OpenLinkItem, m_contextMenu.get()); |
| appendItem(OpenLinkInNewWindowItem, m_contextMenu.get()); |
| appendItem(DownloadFileItem, m_contextMenu.get()); |
| } |
| appendItem(CopyLinkItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| } |
| |
| if (m_context.hitTestResult().isSelected() && !inPasswordField) |
| addSelectedTextActionsIfNeeded(selectedText); |
| |
| appendItem(CutItem, m_contextMenu.get()); |
| appendItem(CopyItem, m_contextMenu.get()); |
| appendItem(PasteItem, m_contextMenu.get()); |
| #if PLATFORM(GTK) |
| if (frame->editor().canEditRichly()) |
| appendItem(PasteAsPlainTextItem, m_contextMenu.get()); |
| appendItem(DeleteItem, m_contextMenu.get()); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| appendItem(SelectAllItem, m_contextMenu.get()); |
| appendItem(InsertEmojiItem, m_contextMenu.get()); |
| #endif |
| |
| if (!inPasswordField) { |
| #if ENABLE(WRITING_TOOLS) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| ContextMenuItem writingToolsItem(ContextMenuItemType::Action, ContextMenuItemTagWritingTools, contextMenuItemTagWritingTools()); |
| appendItem(writingToolsItem, m_contextMenu.get()); |
| #if ENABLE(TOP_LEVEL_WRITING_TOOLS_CONTEXT_MENU_ITEMS) |
| bool editorHasText = [&] { |
| if (auto range = frame->editor().contextRangeForCandidateRequest()) |
| return !plainText(*range).isEmpty(); |
| |
| return false; |
| }(); |
| |
| if (editorHasText) { |
| ContextMenuItem proofreadItem(ContextMenuItemType::Action, ContextMenuItemTagProofread, contextMenuItemTagProofread()); |
| appendItem(proofreadItem, m_contextMenu.get()); |
| ContextMenuItem rewriteItem(ContextMenuItemType::Action, ContextMenuItemTagRewrite, contextMenuItemTagRewrite()); |
| appendItem(rewriteItem, m_contextMenu.get()); |
| } |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| #endif |
| #endif |
| |
| #if !PLATFORM(GTK) |
| #if !ENABLE(WRITING_TOOLS) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| #endif |
| ContextMenuItem SpellingAndGrammarMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagSpellingMenu, |
| contextMenuItemTagSpellingMenu()); |
| createAndAppendSpellingAndGrammarSubMenu(SpellingAndGrammarMenuItem); |
| appendItem(SpellingAndGrammarMenuItem, m_contextMenu.get()); |
| #endif |
| #if PLATFORM(COCOA) |
| ContextMenuItem substitutionsMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagSubstitutionsMenu, |
| contextMenuItemTagSubstitutionsMenu()); |
| createAndAppendSubstitutionsSubMenu(substitutionsMenuItem); |
| appendItem(substitutionsMenuItem, m_contextMenu.get()); |
| ContextMenuItem transformationsMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagTransformationsMenu, |
| contextMenuItemTagTransformationsMenu()); |
| createAndAppendTransformationsSubMenu(transformationsMenuItem); |
| appendItem(transformationsMenuItem, m_contextMenu.get()); |
| #endif |
| #if PLATFORM(GTK) |
| bool shouldShowFontMenu = frame->editor().canEditRichly(); |
| #else |
| bool shouldShowFontMenu = true; |
| #endif |
| if (shouldShowFontMenu) { |
| ContextMenuItem FontMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagFontMenu, |
| contextMenuItemTagFontMenu()); |
| createAndAppendFontSubMenu(FontMenuItem); |
| appendItem(FontMenuItem, m_contextMenu.get()); |
| } |
| #if PLATFORM(COCOA) |
| ContextMenuItem SpeechMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); |
| createAndAppendSpeechSubMenu(SpeechMenuItem); |
| appendItem(SpeechMenuItem, m_contextMenu.get()); |
| #endif |
| #if PLATFORM(GTK) |
| EditorClient* client = frame->editor().client(); |
| if (client && client->shouldShowUnicodeMenu()) { |
| ContextMenuItem UnicodeMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagUnicode, contextMenuItemTagUnicode()); |
| createAndAppendUnicodeSubMenu(UnicodeMenuItem); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| appendItem(UnicodeMenuItem, m_contextMenu.get()); |
| } |
| #else |
| ContextMenuItem WritingDirectionMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagWritingDirectionMenu, |
| contextMenuItemTagWritingDirectionMenu()); |
| createAndAppendWritingDirectionSubMenu(WritingDirectionMenuItem); |
| appendItem(WritingDirectionMenuItem, m_contextMenu.get()); |
| if (RefPtr page = frame->page()) { |
| bool includeTextDirectionSubmenu = page->settings().textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuInclusionBehavior::AlwaysIncluded |
| || (page->settings().textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuInclusionBehavior::AutomaticallyIncluded && frame->editor().hasBidiSelection()); |
| if (includeTextDirectionSubmenu) { |
| ContextMenuItem TextDirectionMenuItem(ContextMenuItemType::Submenu, ContextMenuItemTagTextDirectionMenu, contextMenuItemTagTextDirectionMenu()); |
| createAndAppendTextDirectionSubMenu(TextDirectionMenuItem); |
| appendItem(TextDirectionMenuItem, m_contextMenu.get()); |
| } |
| } |
| #endif |
| } |
| |
| if (!ShareMenuItem.isNull()) { |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| appendItem(ShareMenuItem, m_contextMenu.get()); |
| } |
| } |
| |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| if (shouldAddPlayAllPauseAllAnimationsItem) { |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| addPlayAllPauseAllAnimationsItem(); |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| } |
| #endif |
| } |
| |
| void ContextMenuController::addDebuggingItems() |
| { |
| RefPtr node = m_context.hitTestResult().innerNonSharedNode(); |
| if (!node) |
| return; |
| |
| RefPtr frame = node->document().frame(); |
| if (!frame) |
| return; |
| |
| RefPtr page = frame->page(); |
| if (!page) |
| return; |
| ASSERT(page->inspectorController().enabled()); |
| |
| #if ENABLE(PDFJS) |
| if (RefPtr ownerElement = frame->ownerElement(); ownerElement && ownerElement->document().isPDFDocument()) |
| return; |
| #endif |
| |
| if (m_contextMenu && !m_contextMenu->items().isEmpty()) |
| appendItem(*separatorItem(), m_contextMenu.get()); |
| |
| ContextMenuItem InspectElementItem(ContextMenuItemType::Action, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement()); |
| appendItem(InspectElementItem, m_contextMenu.get()); |
| |
| #if ENABLE(VIDEO) |
| if (page->settings().showMediaStatsContextMenuItemEnabled() && !m_context.hitTestResult().absoluteMediaURL().isEmpty()) { |
| ContextMenuItem ShowMediaStats(ContextMenuItemType::CheckableAction, ContextMenuItemTagShowMediaStats, contextMenuItemTagShowMediaStats()); |
| appendItem(ShowMediaStats, m_contextMenu.get()); |
| } |
| #endif // ENABLE(VIDEO) |
| } |
| |
| bool ContextMenuController::shouldEnableCopyLinkWithHighlight() const |
| { |
| Ref document = m_context.hitTestResult().innerNonSharedNode()->document(); |
| RefPtr frame = document->frame(); |
| if (!frame) |
| return false; |
| |
| auto url = document->url(); |
| if (!url.isValid() || !url.protocolIsInHTTPFamily()) |
| return false; |
| |
| auto selectedRange = frame->selection().selection().range(); |
| bool selectionIsInsideImageOverlay = selectedRange && ImageOverlay::isInsideOverlay(*selectedRange); |
| if (frame->page() && frame->page()->settings().scrollToTextFragmentGenerationEnabled() && !selectionIsInsideImageOverlay) |
| return frame->selection().isRange(); |
| return false; |
| } |
| |
| void ContextMenuController::checkOrEnableIfNeeded(ContextMenuItem& item) const |
| { |
| if (item.type() == ContextMenuItemType::Separator) |
| return; |
| |
| RefPtr frame = m_context.hitTestResult().innerNonSharedNode()->document().frame(); |
| if (!frame) |
| return; |
| |
| // Custom items already have proper checked and enabled values. |
| if (ContextMenuItemBaseCustomTag <= item.action() && item.action() <= ContextMenuItemLastCustomTag) |
| return; |
| |
| bool shouldEnable = true; |
| bool shouldCheck = false; |
| |
| switch (item.action()) { |
| case ContextMenuItemTagCheckSpelling: |
| shouldEnable = frame->editor().canEdit(); |
| break; |
| case ContextMenuItemTagDefaultDirection: |
| shouldCheck = false; |
| shouldEnable = false; |
| break; |
| case ContextMenuItemTagLeftToRight: |
| case ContextMenuItemTagRightToLeft: { |
| String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr"_s : "rtl"_s; |
| shouldCheck = frame->editor().selectionHasStyle(CSSPropertyDirection, direction) != TriState::False; |
| shouldEnable = true; |
| break; |
| } |
| case ContextMenuItemTagTextDirectionDefault: { |
| Editor::Command command = frame->editor().command("MakeTextWritingDirectionNatural"_s); |
| shouldCheck = command.state() == TriState::True; |
| shouldEnable = command.isEnabled(); |
| break; |
| } |
| case ContextMenuItemTagTextDirectionLeftToRight: { |
| Editor::Command command = frame->editor().command("MakeTextWritingDirectionLeftToRight"_s); |
| shouldCheck = command.state() == TriState::True; |
| shouldEnable = command.isEnabled(); |
| break; |
| } |
| case ContextMenuItemTagTextDirectionRightToLeft: { |
| Editor::Command command = frame->editor().command("MakeTextWritingDirectionRightToLeft"_s); |
| shouldCheck = command.state() == TriState::True; |
| shouldEnable = command.isEnabled(); |
| break; |
| } |
| case ContextMenuItemTagCopy: |
| shouldEnable = frame->editor().canDHTMLCopy() || frame->editor().canCopy(); |
| break; |
| case ContextMenuItemTagCut: |
| shouldEnable = frame->editor().canDHTMLCut() || frame->editor().canCut(); |
| break; |
| case ContextMenuItemTagIgnoreSpelling: |
| case ContextMenuItemTagLearnSpelling: |
| shouldEnable = frame->selection().isRange(); |
| break; |
| case ContextMenuItemTagPaste: |
| shouldEnable = frame->editor().canDHTMLPaste() || frame->editor().canEdit(); |
| break; |
| case ContextMenuItemTagCopyLinkWithHighlight: |
| shouldEnable = shouldEnableCopyLinkWithHighlight(); |
| break; |
| #if PLATFORM(GTK) |
| case ContextMenuItemTagPasteAsPlainText: |
| shouldEnable = frame->editor().canDHTMLPaste() || frame->editor().canEdit(); |
| break; |
| case ContextMenuItemTagDelete: |
| shouldEnable = frame->editor().canDelete(); |
| break; |
| case ContextMenuItemTagInsertEmoji: |
| shouldEnable = frame->editor().canEdit(); |
| break; |
| case ContextMenuItemTagSelectAll: |
| case ContextMenuItemTagInputMethods: |
| case ContextMenuItemTagUnicode: |
| case ContextMenuItemTagUnicodeInsertLRMMark: |
| case ContextMenuItemTagUnicodeInsertRLMMark: |
| case ContextMenuItemTagUnicodeInsertLREMark: |
| case ContextMenuItemTagUnicodeInsertRLEMark: |
| case ContextMenuItemTagUnicodeInsertLROMark: |
| case ContextMenuItemTagUnicodeInsertRLOMark: |
| case ContextMenuItemTagUnicodeInsertPDFMark: |
| case ContextMenuItemTagUnicodeInsertZWSMark: |
| case ContextMenuItemTagUnicodeInsertZWJMark: |
| case ContextMenuItemTagUnicodeInsertZWNJMark: |
| shouldEnable = true; |
| break; |
| #endif |
| case ContextMenuItemTagUnderline: { |
| shouldCheck = frame->editor().selectionHasStyle(CSSPropertyWebkitTextDecorationsInEffect, "underline"_s) != TriState::False; |
| shouldEnable = frame->editor().canEditRichly(); |
| break; |
| } |
| case ContextMenuItemTagLookUpInDictionary: |
| shouldEnable = frame->selection().isRange(); |
| break; |
| case ContextMenuItemTagCheckGrammarWithSpelling: |
| if (frame->editor().isGrammarCheckingEnabled()) |
| shouldCheck = true; |
| shouldEnable = true; |
| break; |
| case ContextMenuItemTagItalic: { |
| shouldCheck = frame->editor().selectionHasStyle(CSSPropertyFontStyle, "italic"_s) != TriState::False; |
| shouldEnable = frame->editor().canEditRichly(); |
| break; |
| } |
| case ContextMenuItemTagBold: { |
| shouldCheck = frame->editor().selectionHasStyle(CSSPropertyFontWeight, "bold"_s) != TriState::False; |
| shouldEnable = frame->editor().canEditRichly(); |
| break; |
| } |
| case ContextMenuItemTagOutline: |
| shouldEnable = false; |
| break; |
| case ContextMenuItemTagShowSpellingPanel: |
| if (frame->editor().spellingPanelIsShowing()) |
| item.setTitle(contextMenuItemTagShowSpellingPanel(false)); |
| else |
| item.setTitle(contextMenuItemTagShowSpellingPanel(true)); |
| shouldEnable = frame->editor().canEdit(); |
| break; |
| case ContextMenuItemTagNoGuessesFound: |
| shouldEnable = false; |
| break; |
| case ContextMenuItemTagCheckSpellingWhileTyping: |
| shouldCheck = frame->editor().isContinuousSpellCheckingEnabled(); |
| break; |
| case ContextMenuItemTagAddHighlightToCurrentQuickNote: |
| shouldEnable = frame->selection().isRange(); |
| break; |
| case ContextMenuItemTagAddHighlightToNewQuickNote: |
| shouldEnable = frame->selection().isRange(); |
| break; |
| #if PLATFORM(COCOA) |
| case ContextMenuItemTagSubstitutionsMenu: |
| case ContextMenuItemTagTransformationsMenu: |
| break; |
| case ContextMenuItemTagShowSubstitutions: |
| if (frame->editor().substitutionsPanelIsShowing()) |
| item.setTitle(contextMenuItemTagShowSubstitutions(false)); |
| else |
| item.setTitle(contextMenuItemTagShowSubstitutions(true)); |
| shouldEnable = frame->editor().canEdit(); |
| break; |
| case ContextMenuItemTagMakeUpperCase: |
| case ContextMenuItemTagMakeLowerCase: |
| case ContextMenuItemTagCapitalize: |
| case ContextMenuItemTagChangeBack: |
| shouldEnable = frame->editor().canEdit(); |
| break; |
| case ContextMenuItemTagCorrectSpellingAutomatically: |
| shouldCheck = frame->editor().isAutomaticSpellingCorrectionEnabled(); |
| shouldEnable = frame->editor().canEnableAutomaticSpellingCorrection(); |
| break; |
| case ContextMenuItemTagSmartCopyPaste: |
| shouldCheck = frame->editor().smartInsertDeleteEnabled(); |
| break; |
| case ContextMenuItemTagSmartQuotes: |
| shouldCheck = frame->editor().isAutomaticQuoteSubstitutionEnabled(); |
| break; |
| case ContextMenuItemTagSmartDashes: |
| shouldCheck = frame->editor().isAutomaticDashSubstitutionEnabled(); |
| break; |
| case ContextMenuItemTagSmartLinks: |
| shouldCheck = frame->editor().isAutomaticLinkDetectionEnabled(); |
| break; |
| case ContextMenuItemTagTextReplacement: |
| shouldCheck = frame->editor().isAutomaticTextReplacementEnabled(); |
| break; |
| case ContextMenuItemTagStopSpeaking: |
| shouldEnable = m_client->isSpeaking(); |
| break; |
| #else // PLATFORM(COCOA) ends here |
| case ContextMenuItemTagStopSpeaking: |
| break; |
| #endif |
| #if PLATFORM(GTK) |
| case ContextMenuItemTagGoBack: |
| shouldEnable = frame->page() && frame->page()->checkedBackForward()->canGoBackOrForward(-1); |
| break; |
| case ContextMenuItemTagGoForward: |
| shouldEnable = frame->page() && frame->page()->checkedBackForward()->canGoBackOrForward(1); |
| break; |
| case ContextMenuItemTagStop: |
| shouldEnable = frame->loader().documentLoader()->isLoadingInAPISense(); |
| break; |
| case ContextMenuItemTagReload: |
| shouldEnable = !frame->loader().documentLoader()->isLoadingInAPISense(); |
| break; |
| case ContextMenuItemTagFontMenu: |
| shouldEnable = frame->editor().canEditRichly(); |
| break; |
| #else |
| case ContextMenuItemTagGoBack: |
| case ContextMenuItemTagGoForward: |
| case ContextMenuItemTagStop: |
| case ContextMenuItemTagReload: |
| case ContextMenuItemTagFontMenu: |
| #endif |
| case ContextMenuItemTagNoAction: |
| case ContextMenuItemTagOpenLinkInNewWindow: |
| case ContextMenuItemTagDownloadLinkToDisk: |
| case ContextMenuItemTagCopyLinkToClipboard: |
| case ContextMenuItemTagOpenImageInNewWindow: |
| case ContextMenuItemTagCopyImageToClipboard: |
| case ContextMenuItemTagCopySubject: |
| #if PLATFORM(GTK) |
| case ContextMenuItemTagCopyImageURLToClipboard: |
| #endif |
| break; |
| case ContextMenuItemTagDownloadImageToDisk: |
| #if PLATFORM(MAC) |
| if (m_context.hitTestResult().absoluteImageURL().protocolIsFile()) |
| shouldEnable = false; |
| #endif |
| break; |
| case ContextMenuItemTagOpenMediaInNewWindow: |
| if (m_context.hitTestResult().mediaIsVideo()) |
| item.setTitle(contextMenuItemTagOpenVideoInNewWindow()); |
| else |
| item.setTitle(contextMenuItemTagOpenAudioInNewWindow()); |
| break; |
| case ContextMenuItemTagDownloadMediaToDisk: |
| if (m_context.hitTestResult().mediaIsVideo()) |
| item.setTitle(contextMenuItemTagDownloadVideoToDisk()); |
| else |
| item.setTitle(contextMenuItemTagDownloadAudioToDisk()); |
| if (m_context.hitTestResult().absoluteImageURL().protocolIsFile()) |
| shouldEnable = false; |
| break; |
| case ContextMenuItemTagCopyMediaLinkToClipboard: |
| if (m_context.hitTestResult().mediaIsVideo()) |
| item.setTitle(contextMenuItemTagCopyVideoLinkToClipboard()); |
| else |
| item.setTitle(contextMenuItemTagCopyAudioLinkToClipboard()); |
| break; |
| case ContextMenuItemTagPlayAllAnimations: |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| item.setTitle(contextMenuItemTagPlayAllAnimations()); |
| #endif |
| break; |
| case ContextMenuItemTagPauseAllAnimations: |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| item.setTitle(contextMenuItemTagPauseAllAnimations()); |
| #endif |
| break; |
| case ContextMenuItemTagPlayAnimation: |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| item.setTitle(contextMenuItemTagPlayAnimation()); |
| #endif |
| break; |
| case ContextMenuItemTagPauseAnimation: |
| #if ENABLE(ACCESSIBILITY_ANIMATION_CONTROL) |
| item.setTitle(contextMenuItemTagPauseAnimation()); |
| #endif |
| break; |
| case ContextMenuItemTagToggleMediaControls: |
| #if SUPPORTS_TOGGLE_SHOW_HIDE_MEDIA_CONTROLS |
| item.setTitle(m_context.hitTestResult().mediaControlsEnabled() ? contextMenuItemTagHideMediaControls() : contextMenuItemTagShowMediaControls()); |
| #else |
| shouldCheck = m_context.hitTestResult().mediaControlsEnabled(); |
| #endif |
| break; |
| case ContextMenuItemTagToggleMediaLoop: |
| shouldCheck = m_context.hitTestResult().mediaLoopEnabled(); |
| break; |
| case ContextMenuItemTagShowMediaStats: |
| shouldCheck = m_context.hitTestResult().mediaStatsShowing(); |
| break; |
| case ContextMenuItemTagToggleVideoFullscreen: |
| #if SUPPORTS_TOGGLE_VIDEO_FULLSCREEN |
| item.setTitle(m_context.hitTestResult().mediaIsInFullscreen() ? contextMenuItemTagExitVideoFullscreen() : contextMenuItemTagEnterVideoFullscreen()); |
| break; |
| #endif |
| case ContextMenuItemTagEnterVideoFullscreen: |
| shouldEnable = m_context.hitTestResult().mediaSupportsFullscreen(); |
| break; |
| case ContextMenuItemTagToggleVideoEnhancedFullscreen: |
| #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE) |
| item.setTitle(m_context.hitTestResult().mediaIsInEnhancedFullscreen() ? contextMenuItemTagExitVideoEnhancedFullscreen() : contextMenuItemTagEnterVideoEnhancedFullscreen()); |
| #endif |
| shouldEnable = m_context.hitTestResult().mediaSupportsEnhancedFullscreen(); |
| break; |
| case ContextMenuItemTagToggleVideoViewer: |
| #if PLATFORM(MAC) && ENABLE(VIDEO_PRESENTATION_MODE) |
| item.setTitle(m_context.hitTestResult().mediaIsInVideoViewer() ? contextMenuItemTagExitVideoViewer() : contextMenuItemTagEnterVideoViewer()); |
| #endif |
| break; |
| case ContextMenuItemTagOpenFrameInNewWindow: |
| case ContextMenuItemTagSpellingGuess: |
| case ContextMenuItemTagOther: |
| case ContextMenuItemTagSearchWeb: |
| case ContextMenuItemTagOpenWithDefaultApplication: |
| case ContextMenuItemPDFActualSize: |
| case ContextMenuItemPDFZoomIn: |
| case ContextMenuItemPDFZoomOut: |
| case ContextMenuItemPDFAutoSize: |
| case ContextMenuItemPDFSinglePage: |
| case ContextMenuItemPDFSinglePageContinuous: |
| case ContextMenuItemPDFTwoPages: |
| case ContextMenuItemPDFTwoPagesContinuous: |
| case ContextMenuItemPDFFacingPages: |
| case ContextMenuItemPDFContinuous: |
| case ContextMenuItemPDFNextPage: |
| case ContextMenuItemPDFPreviousPage: |
| case ContextMenuItemTagOpenLink: |
| case ContextMenuItemTagIgnoreGrammar: |
| case ContextMenuItemTagSpellingMenu: |
| case ContextMenuItemTagShowFonts: |
| case ContextMenuItemTagStyles: |
| case ContextMenuItemTagShowColors: |
| case ContextMenuItemTagSpeechMenu: |
| case ContextMenuItemTagStartSpeaking: |
| case ContextMenuItemTagWritingDirectionMenu: |
| case ContextMenuItemTagTextDirectionMenu: |
| case ContextMenuItemTagPDFSinglePageScrolling: |
| case ContextMenuItemTagPDFFacingPagesScrolling: |
| case ContextMenuItemTagInspectElement: |
| case ContextMenuItemBaseCustomTag: |
| case ContextMenuItemLastCustomTag: |
| case ContextMenuItemBaseApplicationTag: |
| case ContextMenuItemTagDictationAlternative: |
| case ContextMenuItemTagShareMenu: |
| break; |
| case ContextMenuItemTagMediaPlayPause: |
| if (m_context.hitTestResult().mediaPlaying()) |
| item.setTitle(contextMenuItemTagMediaPause()); |
| else |
| item.setTitle(contextMenuItemTagMediaPlay()); |
| break; |
| case ContextMenuItemTagMediaMute: |
| shouldEnable = m_context.hitTestResult().mediaHasAudio(); |
| shouldCheck = shouldEnable && m_context.hitTestResult().mediaMuted(); |
| break; |
| case ContextMenuItemTagLookUpImage: |
| case ContextMenuItemTagTranslate: |
| case ContextMenuItemTagWritingTools: |
| case ContextMenuItemTagProofread: |
| case ContextMenuItemTagRewrite: |
| case ContextMenuItemTagSummarize: |
| break; |
| } |
| |
| item.setChecked(shouldCheck); |
| item.setEnabled(shouldEnable); |
| } |
| |
| #if USE(ACCESSIBILITY_CONTEXT_MENUS) |
| |
| void ContextMenuController::showContextMenuAt(LocalFrame& frame, const IntPoint& clickPoint) |
| { |
| clearContextMenu(); |
| |
| // Simulate a click in the middle of the accessibility object. |
| PlatformMouseEvent mouseEvent(clickPoint, clickPoint, MouseButton::Right, PlatformEvent::Type::MousePressed, 1, { }, WallTime::now(), ForceAtClick, SyntheticClickType::NoTap); |
| |
| frame.eventHandler().handleMousePressEvent(mouseEvent); |
| bool handled = frame.eventHandler().sendContextMenuEvent(mouseEvent); |
| if (handled) |
| m_client->showContextMenu(); |
| } |
| |
| #endif |
| |
| #if ENABLE(SERVICE_CONTROLS) |
| |
| void ContextMenuController::showImageControlsMenu(Event& event) |
| { |
| clearContextMenu(); |
| handleContextMenuEvent(event); |
| m_client->showContextMenu(); |
| } |
| |
| #endif |
| |
| #if ENABLE(PDFJS) |
| |
| void ContextMenuController::performPDFJSAction(LocalFrame& frame, const String& action) |
| { |
| if (RefPtr document = dynamicDowncast<PDFDocument>(frame.ownerElement()->document())) |
| document->postMessageToIframe(action, nullptr); |
| } |
| |
| #endif |
| |
| } // namespace WebCore |
| |
| #endif // ENABLE(CONTEXT_MENUS) |