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