1 /* 2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. 3 * Copyright (C) 2008 Christian Dywan <christian (at) imendio.com> 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include "config.h" 28 #include "ContextMenu.h" 29 30 #if ENABLE(CONTEXT_MENUS) 31 32 #include "ContextMenuController.h" 33 #include "ContextMenuClient.h" 34 #include "CSSComputedStyleDeclaration.h" 35 #include "CSSProperty.h" 36 #include "CSSPropertyNames.h" 37 #include "CString.h" 38 #include "Document.h" 39 #include "DocumentLoader.h" 40 #include "Editor.h" 41 #include "Frame.h" 42 #include "FrameLoader.h" 43 #include "InspectorController.h" 44 #include "KURL.h" 45 #include "LocalizedStrings.h" 46 #include "Node.h" 47 #include "Page.h" 48 #include "ResourceRequest.h" 49 #include "SelectionController.h" 50 #include "Settings.h" 51 #include "TextIterator.h" 52 #include <memory> 53 54 using namespace std; 55 using namespace WTF; 56 using namespace Unicode; 57 58 namespace WebCore { 59 60 ContextMenuController* ContextMenu::controller() const 61 { 62 if (Node* node = m_hitTestResult.innerNonSharedNode()) 63 if (Frame* frame = node->document()->frame()) 64 if (Page* page = frame->page()) 65 return page->contextMenuController(); 66 return 0; 67 } 68 69 static auto_ptr<ContextMenuItem> separatorItem() 70 { 71 return auto_ptr<ContextMenuItem>(new ContextMenuItem(SeparatorType, ContextMenuItemTagNoAction, String())); 72 } 73 74 static void createAndAppendFontSubMenu(const HitTestResult& result, ContextMenuItem& fontMenuItem) 75 { 76 ContextMenu fontMenu(result); 77 78 #if PLATFORM(MAC) 79 ContextMenuItem showFonts(ActionType, ContextMenuItemTagShowFonts, contextMenuItemTagShowFonts()); 80 #endif 81 ContextMenuItem bold(CheckableActionType, ContextMenuItemTagBold, contextMenuItemTagBold()); 82 ContextMenuItem italic(CheckableActionType, ContextMenuItemTagItalic, contextMenuItemTagItalic()); 83 ContextMenuItem underline(CheckableActionType, ContextMenuItemTagUnderline, contextMenuItemTagUnderline()); 84 ContextMenuItem outline(ActionType, ContextMenuItemTagOutline, contextMenuItemTagOutline()); 85 #if PLATFORM(MAC) 86 ContextMenuItem styles(ActionType, ContextMenuItemTagStyles, contextMenuItemTagStyles()); 87 ContextMenuItem showColors(ActionType, ContextMenuItemTagShowColors, contextMenuItemTagShowColors()); 88 #endif 89 90 #if PLATFORM(MAC) 91 fontMenu.appendItem(showFonts); 92 #endif 93 fontMenu.appendItem(bold); 94 fontMenu.appendItem(italic); 95 fontMenu.appendItem(underline); 96 fontMenu.appendItem(outline); 97 #if PLATFORM(MAC) 98 fontMenu.appendItem(styles); 99 fontMenu.appendItem(*separatorItem()); 100 fontMenu.appendItem(showColors); 101 #endif 102 103 fontMenuItem.setSubMenu(&fontMenu); 104 } 105 106 #ifndef BUILDING_ON_TIGER 107 static void createAndAppendSpellingAndGrammarSubMenu(const HitTestResult& result, ContextMenuItem& spellingAndGrammarMenuItem) 108 { 109 ContextMenu spellingAndGrammarMenu(result); 110 111 ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, 112 contextMenuItemTagShowSpellingPanel(true)); 113 ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, 114 contextMenuItemTagCheckSpelling()); 115 ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, 116 contextMenuItemTagCheckSpellingWhileTyping()); 117 ContextMenuItem grammarWithSpelling(CheckableActionType, ContextMenuItemTagCheckGrammarWithSpelling, 118 contextMenuItemTagCheckGrammarWithSpelling()); 119 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 120 ContextMenuItem correctSpelling(CheckableActionType, ContextMenuItemTagCorrectSpellingAutomatically, 121 contextMenuItemTagCorrectSpellingAutomatically()); 122 #endif 123 124 spellingAndGrammarMenu.appendItem(showSpellingPanel); 125 spellingAndGrammarMenu.appendItem(checkSpelling); 126 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 127 spellingAndGrammarMenu.appendItem(*separatorItem()); 128 #endif 129 spellingAndGrammarMenu.appendItem(checkAsYouType); 130 spellingAndGrammarMenu.appendItem(grammarWithSpelling); 131 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 132 spellingAndGrammarMenu.appendItem(correctSpelling); 133 #endif 134 135 spellingAndGrammarMenuItem.setSubMenu(&spellingAndGrammarMenu); 136 } 137 #else 138 139 static void createAndAppendSpellingSubMenu(const HitTestResult& result, ContextMenuItem& spellingMenuItem) 140 { 141 ContextMenu spellingMenu(result); 142 143 ContextMenuItem showSpellingPanel(ActionType, ContextMenuItemTagShowSpellingPanel, 144 contextMenuItemTagShowSpellingPanel(true)); 145 ContextMenuItem checkSpelling(ActionType, ContextMenuItemTagCheckSpelling, 146 contextMenuItemTagCheckSpelling()); 147 ContextMenuItem checkAsYouType(CheckableActionType, ContextMenuItemTagCheckSpellingWhileTyping, 148 contextMenuItemTagCheckSpellingWhileTyping()); 149 150 spellingMenu.appendItem(showSpellingPanel); 151 spellingMenu.appendItem(checkSpelling); 152 spellingMenu.appendItem(checkAsYouType); 153 154 spellingMenuItem.setSubMenu(&spellingMenu); 155 } 156 #endif 157 158 #if PLATFORM(MAC) 159 static void createAndAppendSpeechSubMenu(const HitTestResult& result, ContextMenuItem& speechMenuItem) 160 { 161 ContextMenu speechMenu(result); 162 163 ContextMenuItem start(ActionType, ContextMenuItemTagStartSpeaking, contextMenuItemTagStartSpeaking()); 164 ContextMenuItem stop(ActionType, ContextMenuItemTagStopSpeaking, contextMenuItemTagStopSpeaking()); 165 166 speechMenu.appendItem(start); 167 speechMenu.appendItem(stop); 168 169 speechMenuItem.setSubMenu(&speechMenu); 170 } 171 #endif 172 173 #if !PLATFORM(GTK) 174 static void createAndAppendWritingDirectionSubMenu(const HitTestResult& result, ContextMenuItem& writingDirectionMenuItem) 175 { 176 ContextMenu writingDirectionMenu(result); 177 178 ContextMenuItem defaultItem(ActionType, ContextMenuItemTagDefaultDirection, 179 contextMenuItemTagDefaultDirection()); 180 ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagLeftToRight, contextMenuItemTagLeftToRight()); 181 ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagRightToLeft, contextMenuItemTagRightToLeft()); 182 183 writingDirectionMenu.appendItem(defaultItem); 184 writingDirectionMenu.appendItem(ltr); 185 writingDirectionMenu.appendItem(rtl); 186 187 writingDirectionMenuItem.setSubMenu(&writingDirectionMenu); 188 } 189 190 static void createAndAppendTextDirectionSubMenu(const HitTestResult& result, ContextMenuItem& textDirectionMenuItem) 191 { 192 ContextMenu textDirectionMenu(result); 193 194 ContextMenuItem defaultItem(ActionType, ContextMenuItemTagTextDirectionDefault, contextMenuItemTagDefaultDirection()); 195 ContextMenuItem ltr(CheckableActionType, ContextMenuItemTagTextDirectionLeftToRight, contextMenuItemTagLeftToRight()); 196 ContextMenuItem rtl(CheckableActionType, ContextMenuItemTagTextDirectionRightToLeft, contextMenuItemTagRightToLeft()); 197 198 textDirectionMenu.appendItem(defaultItem); 199 textDirectionMenu.appendItem(ltr); 200 textDirectionMenu.appendItem(rtl); 201 202 textDirectionMenuItem.setSubMenu(&textDirectionMenu); 203 } 204 #endif 205 206 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 207 static void createAndAppendSubstitutionsSubMenu(const HitTestResult& result, ContextMenuItem& substitutionsMenuItem) 208 { 209 ContextMenu substitutionsMenu(result); 210 211 ContextMenuItem showSubstitutions(ActionType, ContextMenuItemTagShowSubstitutions, contextMenuItemTagShowSubstitutions(true)); 212 ContextMenuItem smartCopyPaste(CheckableActionType, ContextMenuItemTagSmartCopyPaste, contextMenuItemTagSmartCopyPaste()); 213 ContextMenuItem smartQuotes(CheckableActionType, ContextMenuItemTagSmartQuotes, contextMenuItemTagSmartQuotes()); 214 ContextMenuItem smartDashes(CheckableActionType, ContextMenuItemTagSmartDashes, contextMenuItemTagSmartDashes()); 215 ContextMenuItem smartLinks(CheckableActionType, ContextMenuItemTagSmartLinks, contextMenuItemTagSmartLinks()); 216 ContextMenuItem textReplacement(CheckableActionType, ContextMenuItemTagTextReplacement, contextMenuItemTagTextReplacement()); 217 218 substitutionsMenu.appendItem(showSubstitutions); 219 substitutionsMenu.appendItem(*separatorItem()); 220 substitutionsMenu.appendItem(smartCopyPaste); 221 substitutionsMenu.appendItem(smartQuotes); 222 substitutionsMenu.appendItem(smartDashes); 223 substitutionsMenu.appendItem(smartLinks); 224 substitutionsMenu.appendItem(textReplacement); 225 226 substitutionsMenuItem.setSubMenu(&substitutionsMenu); 227 } 228 229 static void createAndAppendTransformationsSubMenu(const HitTestResult& result, ContextMenuItem& transformationsMenuItem) 230 { 231 ContextMenu transformationsMenu(result); 232 233 ContextMenuItem makeUpperCase(ActionType, ContextMenuItemTagMakeUpperCase, contextMenuItemTagMakeUpperCase()); 234 ContextMenuItem makeLowerCase(ActionType, ContextMenuItemTagMakeLowerCase, contextMenuItemTagMakeLowerCase()); 235 ContextMenuItem capitalize(ActionType, ContextMenuItemTagCapitalize, contextMenuItemTagCapitalize()); 236 237 transformationsMenu.appendItem(makeUpperCase); 238 transformationsMenu.appendItem(makeLowerCase); 239 transformationsMenu.appendItem(capitalize); 240 241 transformationsMenuItem.setSubMenu(&transformationsMenu); 242 } 243 #endif 244 245 static bool selectionContainsPossibleWord(Frame* frame) 246 { 247 // Current algorithm: look for a character that's not just a separator. 248 for (TextIterator it(frame->selection()->toNormalizedRange().get()); !it.atEnd(); it.advance()) { 249 int length = it.length(); 250 const UChar* characters = it.characters(); 251 for (int i = 0; i < length; ++i) 252 if (!(category(characters[i]) & (Separator_Space | Separator_Line | Separator_Paragraph))) 253 return true; 254 } 255 return false; 256 } 257 258 void ContextMenu::populate() 259 { 260 ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); 261 ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, 262 contextMenuItemTagOpenLinkInNewWindow()); 263 ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, 264 contextMenuItemTagDownloadLinkToDisk()); 265 ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, 266 contextMenuItemTagCopyLinkToClipboard()); 267 ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, 268 contextMenuItemTagOpenImageInNewWindow()); 269 ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, 270 contextMenuItemTagDownloadImageToDisk()); 271 ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, 272 contextMenuItemTagCopyImageToClipboard()); 273 #if PLATFORM(MAC) 274 ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, 275 contextMenuItemTagSearchInSpotlight()); 276 ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, 277 contextMenuItemTagLookUpInDictionary()); 278 #endif 279 #if !PLATFORM(GTK) 280 ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb()); 281 #endif 282 ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy()); 283 ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack()); 284 ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward()); 285 ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop()); 286 ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload()); 287 ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, 288 contextMenuItemTagOpenFrameInNewWindow()); 289 ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, 290 contextMenuItemTagNoGuessesFound()); 291 ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, 292 contextMenuItemTagIgnoreSpelling()); 293 ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, 294 contextMenuItemTagLearnSpelling()); 295 ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, 296 contextMenuItemTagIgnoreGrammar()); 297 ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut()); 298 ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste()); 299 #if PLATFORM(GTK) 300 ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete()); 301 ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll()); 302 #endif 303 304 HitTestResult result = hitTestResult(); 305 306 Node* node = m_hitTestResult.innerNonSharedNode(); 307 if (!node) 308 return; 309 #if PLATFORM(GTK) 310 if (!result.isContentEditable() && (node->isElementNode() && static_cast<Element*>(node)->isFormControlElement())) 311 return; 312 #endif 313 Frame* frame = node->document()->frame(); 314 if (!frame) 315 return; 316 317 if (!result.isContentEditable()) { 318 FrameLoader* loader = frame->loader(); 319 KURL linkURL = result.absoluteLinkURL(); 320 if (!linkURL.isEmpty()) { 321 if (loader->canHandleRequest(ResourceRequest(linkURL))) { 322 appendItem(OpenLinkItem); 323 appendItem(OpenLinkInNewWindowItem); 324 appendItem(DownloadFileItem); 325 } 326 appendItem(CopyLinkItem); 327 } 328 329 KURL imageURL = result.absoluteImageURL(); 330 if (!imageURL.isEmpty()) { 331 if (!linkURL.isEmpty()) 332 appendItem(*separatorItem()); 333 334 appendItem(OpenImageInNewWindowItem); 335 appendItem(DownloadImageItem); 336 if (imageURL.isLocalFile() || m_hitTestResult.image()) 337 appendItem(CopyImageItem); 338 } 339 340 if (imageURL.isEmpty() && linkURL.isEmpty()) { 341 if (result.isSelected()) { 342 if (selectionContainsPossibleWord(frame)) { 343 #if PLATFORM(MAC) 344 appendItem(SearchSpotlightItem); 345 #endif 346 #if !PLATFORM(GTK) 347 appendItem(SearchWebItem); 348 appendItem(*separatorItem()); 349 #endif 350 #if PLATFORM(MAC) 351 appendItem(LookInDictionaryItem); 352 appendItem(*separatorItem()); 353 #endif 354 } 355 appendItem(CopyItem); 356 #if PLATFORM(MAC) 357 appendItem(*separatorItem()); 358 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); 359 createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); 360 appendItem(SpeechMenuItem); 361 #endif 362 } else { 363 #if PLATFORM(GTK) 364 appendItem(BackItem); 365 appendItem(ForwardItem); 366 appendItem(StopItem); 367 appendItem(ReloadItem); 368 #else 369 if (frame->page() && frame->page()->canGoBackOrForward(-1)) 370 appendItem(BackItem); 371 372 if (frame->page() && frame->page()->canGoBackOrForward(1)) 373 appendItem(ForwardItem); 374 375 // use isLoadingInAPISense rather than isLoading because Stop/Reload are 376 // intended to match WebKit's API, not WebCore's internal notion of loading status 377 if (loader->documentLoader()->isLoadingInAPISense()) 378 appendItem(StopItem); 379 else 380 appendItem(ReloadItem); 381 #endif 382 383 if (frame->page() && frame != frame->page()->mainFrame()) 384 appendItem(OpenFrameItem); 385 } 386 } 387 } else { // Make an editing context menu 388 SelectionController* selection = frame->selection(); 389 bool inPasswordField = selection->isInPasswordField(); 390 391 if (!inPasswordField) { 392 // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range 393 // is never considered a misspelling and bad grammar at the same time) 394 bool misspelling; 395 bool badGrammar; 396 Vector<String> guesses = frame->editor()->guessesForMisspelledOrUngrammaticalSelection(misspelling, badGrammar); 397 if (misspelling || badGrammar) { 398 size_t size = guesses.size(); 399 if (size == 0) { 400 // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions 401 // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit) 402 if (misspelling) { 403 appendItem(NoGuessesItem); 404 appendItem(*separatorItem()); 405 } 406 } else { 407 for (unsigned i = 0; i < size; i++) { 408 const String &guess = guesses[i]; 409 if (!guess.isEmpty()) { 410 ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess); 411 appendItem(item); 412 } 413 } 414 appendItem(*separatorItem()); 415 } 416 417 if (misspelling) { 418 appendItem(IgnoreSpellingItem); 419 appendItem(LearnSpellingItem); 420 } else 421 appendItem(IgnoreGrammarItem); 422 appendItem(*separatorItem()); 423 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 424 } else { 425 // If the string was autocorrected, generate a contextual menu item allowing it to be changed back. 426 String replacedString = result.replacedString(); 427 if (!replacedString.isEmpty()) { 428 ContextMenuItem item(ActionType, ContextMenuItemTagChangeBack, contextMenuItemTagChangeBack(replacedString)); 429 appendItem(item); 430 appendItem(*separatorItem()); 431 } 432 #endif 433 } 434 } 435 436 FrameLoader* loader = frame->loader(); 437 KURL linkURL = result.absoluteLinkURL(); 438 if (!linkURL.isEmpty()) { 439 if (loader->canHandleRequest(ResourceRequest(linkURL))) { 440 appendItem(OpenLinkItem); 441 appendItem(OpenLinkInNewWindowItem); 442 appendItem(DownloadFileItem); 443 } 444 appendItem(CopyLinkItem); 445 appendItem(*separatorItem()); 446 } 447 448 if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) { 449 #if PLATFORM(MAC) 450 appendItem(SearchSpotlightItem); 451 #endif 452 #if !PLATFORM(GTK) 453 appendItem(SearchWebItem); 454 appendItem(*separatorItem()); 455 #endif 456 457 #if PLATFORM(MAC) 458 appendItem(LookInDictionaryItem); 459 appendItem(*separatorItem()); 460 #endif 461 } 462 463 appendItem(CutItem); 464 appendItem(CopyItem); 465 appendItem(PasteItem); 466 #if PLATFORM(GTK) 467 appendItem(DeleteItem); 468 appendItem(*separatorItem()); 469 appendItem(SelectAllItem); 470 #endif 471 472 if (!inPasswordField) { 473 appendItem(*separatorItem()); 474 #ifndef BUILDING_ON_TIGER 475 #if !PLATFORM(GTK) 476 ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, 477 contextMenuItemTagSpellingMenu()); 478 createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem); 479 appendItem(SpellingAndGrammarMenuItem); 480 #endif 481 #else 482 ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, 483 contextMenuItemTagSpellingMenu()); 484 createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem); 485 appendItem(SpellingMenuItem); 486 #endif 487 #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 488 ContextMenuItem substitutionsMenuItem(SubmenuType, ContextMenuItemTagSubstitutionsMenu, 489 contextMenuItemTagSubstitutionsMenu()); 490 createAndAppendSubstitutionsSubMenu(m_hitTestResult, substitutionsMenuItem); 491 appendItem(substitutionsMenuItem); 492 ContextMenuItem transformationsMenuItem(SubmenuType, ContextMenuItemTagTransformationsMenu, 493 contextMenuItemTagTransformationsMenu()); 494 createAndAppendTransformationsSubMenu(m_hitTestResult, transformationsMenuItem); 495 appendItem(transformationsMenuItem); 496 #endif 497 #if PLATFORM(GTK) 498 bool shouldShowFontMenu = frame->editor()->canEditRichly(); 499 #else 500 bool shouldShowFontMenu = true; 501 #endif 502 if (shouldShowFontMenu) { 503 ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, 504 contextMenuItemTagFontMenu()); 505 createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem); 506 appendItem(FontMenuItem); 507 } 508 #if PLATFORM(MAC) 509 ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); 510 createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); 511 appendItem(SpeechMenuItem); 512 #endif 513 #if !PLATFORM(GTK) 514 ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, 515 contextMenuItemTagWritingDirectionMenu()); 516 createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem); 517 appendItem(WritingDirectionMenuItem); 518 if (Page* page = frame->page()) { 519 if (Settings* settings = page->settings()) { 520 bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded 521 || (settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection()); 522 if (includeTextDirectionSubmenu) { 523 ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, 524 contextMenuItemTagTextDirectionMenu()); 525 createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem); 526 appendItem(TextDirectionMenuItem); 527 } 528 } 529 } 530 #endif 531 } 532 } 533 } 534 535 #if ENABLE(INSPECTOR) 536 void ContextMenu::addInspectElementItem() 537 { 538 Node* node = m_hitTestResult.innerNonSharedNode(); 539 if (!node) 540 return; 541 542 Frame* frame = node->document()->frame(); 543 if (!frame) 544 return; 545 546 Page* page = frame->page(); 547 if (!page) 548 return; 549 550 if (!page->inspectorController()) 551 return; 552 553 ContextMenuItem InspectElementItem(ActionType, ContextMenuItemTagInspectElement, contextMenuItemTagInspectElement()); 554 appendItem(*separatorItem()); 555 appendItem(InspectElementItem); 556 } 557 #endif // ENABLE(INSPECTOR) 558 559 void ContextMenu::checkOrEnableIfNeeded(ContextMenuItem& item) const 560 { 561 if (item.type() == SeparatorType) 562 return; 563 564 Frame* frame = m_hitTestResult.innerNonSharedNode()->document()->frame(); 565 if (!frame) 566 return; 567 568 bool shouldEnable = true; 569 bool shouldCheck = false; 570 571 switch (item.action()) { 572 case ContextMenuItemTagCheckSpelling: 573 shouldEnable = frame->editor()->canEdit(); 574 break; 575 case ContextMenuItemTagDefaultDirection: 576 shouldCheck = false; 577 shouldEnable = false; 578 break; 579 case ContextMenuItemTagLeftToRight: 580 case ContextMenuItemTagRightToLeft: { 581 ExceptionCode ec = 0; 582 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); 583 String direction = item.action() == ContextMenuItemTagLeftToRight ? "ltr" : "rtl"; 584 style->setProperty(CSSPropertyDirection, direction, false, ec); 585 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; 586 shouldEnable = true; 587 break; 588 } 589 case ContextMenuItemTagTextDirectionDefault: { 590 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionNatural"); 591 shouldCheck = command.state() == TrueTriState; 592 shouldEnable = command.isEnabled(); 593 break; 594 } 595 case ContextMenuItemTagTextDirectionLeftToRight: { 596 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionLeftToRight"); 597 shouldCheck = command.state() == TrueTriState; 598 shouldEnable = command.isEnabled(); 599 break; 600 } 601 case ContextMenuItemTagTextDirectionRightToLeft: { 602 Editor::Command command = frame->editor()->command("MakeTextWritingDirectionRightToLeft"); 603 shouldCheck = command.state() == TrueTriState; 604 shouldEnable = command.isEnabled(); 605 break; 606 } 607 case ContextMenuItemTagCopy: 608 shouldEnable = frame->editor()->canDHTMLCopy() || frame->editor()->canCopy(); 609 break; 610 case ContextMenuItemTagCut: 611 shouldEnable = frame->editor()->canDHTMLCut() || frame->editor()->canCut(); 612 break; 613 case ContextMenuItemTagIgnoreSpelling: 614 case ContextMenuItemTagLearnSpelling: 615 shouldEnable = frame->selection()->isRange(); 616 break; 617 case ContextMenuItemTagPaste: 618 shouldEnable = frame->editor()->canDHTMLPaste() || frame->editor()->canPaste(); 619 break; 620 #if PLATFORM(GTK) 621 case ContextMenuItemTagDelete: 622 shouldEnable = frame->editor()->canDelete(); 623 break; 624 case ContextMenuItemTagSelectAll: 625 case ContextMenuItemTagInputMethods: 626 case ContextMenuItemTagUnicode: 627 shouldEnable = true; 628 break; 629 #endif 630 case ContextMenuItemTagUnderline: { 631 ExceptionCode ec = 0; 632 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); 633 style->setProperty(CSSPropertyWebkitTextDecorationsInEffect, "underline", false, ec); 634 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; 635 shouldEnable = frame->editor()->canEditRichly(); 636 break; 637 } 638 case ContextMenuItemTagLookUpInDictionary: 639 shouldEnable = frame->selection()->isRange(); 640 break; 641 case ContextMenuItemTagCheckGrammarWithSpelling: 642 #ifndef BUILDING_ON_TIGER 643 if (frame->editor()->isGrammarCheckingEnabled()) 644 shouldCheck = true; 645 shouldEnable = true; 646 #endif 647 break; 648 case ContextMenuItemTagItalic: { 649 ExceptionCode ec = 0; 650 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); 651 style->setProperty(CSSPropertyFontStyle, "italic", false, ec); 652 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; 653 shouldEnable = frame->editor()->canEditRichly(); 654 break; 655 } 656 case ContextMenuItemTagBold: { 657 ExceptionCode ec = 0; 658 RefPtr<CSSStyleDeclaration> style = frame->document()->createCSSStyleDeclaration(); 659 style->setProperty(CSSPropertyFontWeight, "bold", false, ec); 660 shouldCheck = frame->editor()->selectionHasStyle(style.get()) != FalseTriState; 661 shouldEnable = frame->editor()->canEditRichly(); 662 break; 663 } 664 case ContextMenuItemTagOutline: 665 shouldEnable = false; 666 break; 667 case ContextMenuItemTagShowSpellingPanel: 668 #ifndef BUILDING_ON_TIGER 669 if (frame->editor()->spellingPanelIsShowing()) 670 item.setTitle(contextMenuItemTagShowSpellingPanel(false)); 671 else 672 item.setTitle(contextMenuItemTagShowSpellingPanel(true)); 673 #endif 674 shouldEnable = frame->editor()->canEdit(); 675 break; 676 case ContextMenuItemTagNoGuessesFound: 677 shouldEnable = false; 678 break; 679 case ContextMenuItemTagCheckSpellingWhileTyping: 680 shouldCheck = frame->editor()->isContinuousSpellCheckingEnabled(); 681 break; 682 #if PLATFORM(MAC) 683 case ContextMenuItemTagSubstitutionsMenu: 684 case ContextMenuItemTagTransformationsMenu: 685 break; 686 case ContextMenuItemTagShowSubstitutions: 687 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 688 if (frame->editor()->substitutionsPanelIsShowing()) 689 item.setTitle(contextMenuItemTagShowSubstitutions(false)); 690 else 691 item.setTitle(contextMenuItemTagShowSubstitutions(true)); 692 shouldEnable = frame->editor()->canEdit(); 693 #endif 694 break; 695 case ContextMenuItemTagMakeUpperCase: 696 case ContextMenuItemTagMakeLowerCase: 697 case ContextMenuItemTagCapitalize: 698 case ContextMenuItemTagChangeBack: 699 shouldEnable = frame->editor()->canEdit(); 700 break; 701 case ContextMenuItemTagCorrectSpellingAutomatically: 702 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 703 shouldCheck = frame->editor()->isAutomaticSpellingCorrectionEnabled(); 704 #endif 705 break; 706 case ContextMenuItemTagSmartCopyPaste: 707 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 708 shouldCheck = frame->editor()->smartInsertDeleteEnabled(); 709 #endif 710 break; 711 case ContextMenuItemTagSmartQuotes: 712 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 713 shouldCheck = frame->editor()->isAutomaticQuoteSubstitutionEnabled(); 714 #endif 715 break; 716 case ContextMenuItemTagSmartDashes: 717 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 718 shouldCheck = frame->editor()->isAutomaticDashSubstitutionEnabled(); 719 #endif 720 break; 721 case ContextMenuItemTagSmartLinks: 722 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 723 shouldCheck = frame->editor()->isAutomaticLinkDetectionEnabled(); 724 #endif 725 break; 726 case ContextMenuItemTagTextReplacement: 727 #if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) 728 shouldCheck = frame->editor()->isAutomaticTextReplacementEnabled(); 729 #endif 730 break; 731 case ContextMenuItemTagStopSpeaking: 732 shouldEnable = controller() && controller()->client() && controller()->client()->isSpeaking(); 733 break; 734 #else // PLATFORM(MAC) ends here 735 case ContextMenuItemTagStopSpeaking: 736 break; 737 #endif 738 #if PLATFORM(GTK) 739 case ContextMenuItemTagGoBack: 740 shouldEnable = frame->page() && frame->page()->canGoBackOrForward(-1); 741 break; 742 case ContextMenuItemTagGoForward: 743 shouldEnable = frame->page() && frame->page()->canGoBackOrForward(1); 744 break; 745 case ContextMenuItemTagStop: 746 shouldEnable = frame->loader()->documentLoader()->isLoadingInAPISense(); 747 break; 748 case ContextMenuItemTagReload: 749 shouldEnable = !frame->loader()->documentLoader()->isLoadingInAPISense(); 750 break; 751 case ContextMenuItemTagFontMenu: 752 shouldEnable = frame->editor()->canEditRichly(); 753 break; 754 #else 755 case ContextMenuItemTagGoBack: 756 case ContextMenuItemTagGoForward: 757 case ContextMenuItemTagStop: 758 case ContextMenuItemTagReload: 759 case ContextMenuItemTagFontMenu: 760 #endif 761 case ContextMenuItemTagNoAction: 762 case ContextMenuItemTagOpenLinkInNewWindow: 763 case ContextMenuItemTagDownloadLinkToDisk: 764 case ContextMenuItemTagCopyLinkToClipboard: 765 case ContextMenuItemTagOpenImageInNewWindow: 766 case ContextMenuItemTagDownloadImageToDisk: 767 case ContextMenuItemTagCopyImageToClipboard: 768 case ContextMenuItemTagOpenFrameInNewWindow: 769 case ContextMenuItemTagSpellingGuess: 770 case ContextMenuItemTagOther: 771 case ContextMenuItemTagSearchInSpotlight: 772 case ContextMenuItemTagSearchWeb: 773 case ContextMenuItemTagOpenWithDefaultApplication: 774 case ContextMenuItemPDFActualSize: 775 case ContextMenuItemPDFZoomIn: 776 case ContextMenuItemPDFZoomOut: 777 case ContextMenuItemPDFAutoSize: 778 case ContextMenuItemPDFSinglePage: 779 case ContextMenuItemPDFFacingPages: 780 case ContextMenuItemPDFContinuous: 781 case ContextMenuItemPDFNextPage: 782 case ContextMenuItemPDFPreviousPage: 783 case ContextMenuItemTagOpenLink: 784 case ContextMenuItemTagIgnoreGrammar: 785 case ContextMenuItemTagSpellingMenu: 786 case ContextMenuItemTagShowFonts: 787 case ContextMenuItemTagStyles: 788 case ContextMenuItemTagShowColors: 789 case ContextMenuItemTagSpeechMenu: 790 case ContextMenuItemTagStartSpeaking: 791 case ContextMenuItemTagWritingDirectionMenu: 792 case ContextMenuItemTagTextDirectionMenu: 793 case ContextMenuItemTagPDFSinglePageScrolling: 794 case ContextMenuItemTagPDFFacingPagesScrolling: 795 #if ENABLE(INSPECTOR) 796 case ContextMenuItemTagInspectElement: 797 #endif 798 case ContextMenuItemBaseCustomTag: 799 case ContextMenuItemBaseApplicationTag: 800 break; 801 } 802 803 item.setChecked(shouldCheck); 804 item.setEnabled(shouldEnable); 805 } 806 807 } // namespace WebCore 808 809 #endif // ENABLE(CONTEXT_MENUS) 810