bool DragController::startDrag(Frame* src, const DragState& state, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin) { ASSERT(src); if (!src->view() || !src->contentRenderer()) return false; HitTestResult hitTestResult = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); if (!state.m_dragSrc->contains(hitTestResult.innerNode())) // The original node being dragged isn't under the drag origin anymore... maybe it was // hidden or moved out from under the cursor. Regardless, we don't want to start a drag on // something that's not actually under the drag origin. return false; KURL linkURL = hitTestResult.absoluteLinkURL(); KURL imageURL = hitTestResult.absoluteImageURL(); IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.position()); m_draggingImageURL = KURL(); m_sourceDragOperation = srcOp; DragImageRef dragImage = 0; IntPoint dragLoc(0, 0); IntPoint dragImageOffset(0, 0); Clipboard* clipboard = state.m_dragClipboard.get(); if (state.m_dragType == DragSourceActionDHTML) dragImage = clipboard->createDragImage(dragImageOffset); if (state.m_dragType == DragSourceActionSelection || !imageURL.isEmpty() || !linkURL.isEmpty()) // Selection, image, and link drags receive a default set of allowed drag operations that // follows from: // http://trac.webkit.org/browser/trunk/WebKit/mac/WebView/WebHTMLView.mm?rev=48526#L3430 m_sourceDragOperation = static_cast<DragOperation>(m_sourceDragOperation | DragOperationGeneric | DragOperationCopy); // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. if (dragImage) { dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty()); m_dragOffset = dragImageOffset; } bool startedDrag = true; // optimism - we almost always manage to start the drag Node* node = state.m_dragSrc.get(); Image* image = getImage(static_cast<Element*>(node)); if (state.m_dragType == DragSourceActionSelection) { if (!clipboard->hasData()) { if (enclosingTextFormControl(src->selection()->start())) clipboard->writePlainText(src->editor()->selectedText()); else { RefPtr<Range> selectionRange = src->selection()->toNormalizedRange(); ASSERT(selectionRange); clipboard->writeRange(selectionRange.get(), src); } } m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); if (!dragImage) { dragImage = createDragImageForSelection(src); dragLoc = dragLocForSelectionDrag(src); m_dragOffset = IntPoint(dragOrigin.x() - dragLoc.x(), dragOrigin.y() - dragLoc.y()); } doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (!imageURL.isEmpty() && node && node->isElementNode() && image && !image->isNull() && (m_dragSourceAction & DragSourceActionImage)) { // We shouldn't be starting a drag for an image that can't provide an extension. // This is an early detection for problems encountered later upon drop. ASSERT(!image->filenameExtension().isEmpty()); Element* element = static_cast<Element*>(node); if (!clipboard->hasData()) { m_draggingImageURL = imageURL; prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, hitTestResult.altDisplayString()); } m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard); if (!dragImage) { IntRect imageRect = hitTestResult.imageRect(); imageRect.setLocation(m_page->mainFrame()->view()->rootViewToContents(src->view()->contentsToRootView(imageRect.location()))); doImageDrag(element, dragOrigin, hitTestResult.imageRect(), clipboard, src, m_dragOffset); } else // DHTML defined drag image doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) { if (!clipboard->hasData()) // Simplify whitespace so the title put on the clipboard resembles what the user sees // on the web page. This includes replacing newlines with spaces. clipboard->writeURL(linkURL, hitTestResult.textContent().simplifyWhiteSpace(), src); if (src->selection()->isCaret() && src->selection()->isContentEditable()) { // a user can initiate a drag on a link without having any text // selected. In this case, we should expand the selection to // the enclosing anchor element Position pos = src->selection()->base(); Node* node = enclosingAnchorElement(pos); if (node) src->selection()->setSelection(VisibleSelection::selectionFromContentsOfNode(node)); } m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); if (!dragImage) { dragImage = createDragImageForLink(linkURL, hitTestResult.textContent(), src); IntSize size = dragImageSize(dragImage); m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset); dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y()); } doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); } else if (state.m_dragType == DragSourceActionDHTML) { ASSERT(m_dragSourceAction & DragSourceActionDHTML); m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else { // draggableNode() determined an image or link node was draggable, but it turns out the // image or link had no URL, so there is nothing to drag. startedDrag = false; } if (dragImage) deleteDragImage(dragImage); return startedDrag; }
void ChromeClientImpl::mouseDidMoveOverElement( const HitTestResult& result, unsigned modifierFlags) { if (!m_webView->client()) return; WebURL url; // Find out if the mouse is over a link, and if so, let our UI know... if (result.isLiveLink() && !result.absoluteLinkURL().string().isEmpty()) { url = result.absoluteLinkURL(); } else if (result.innerNonSharedNode() && (isHTMLObjectElement(*result.innerNonSharedNode()) || isHTMLEmbedElement(*result.innerNonSharedNode()))) { RenderObject* object = result.innerNonSharedNode()->renderer(); if (object && object->isWidget()) { Widget* widget = toRenderWidget(object)->widget(); if (widget && widget->isPluginContainer()) { WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget); url = plugin->plugin()->linkAtPosition(result.roundedPointInInnerNodeFrame()); } } } m_webView->client()->setMouseOverURL(url); }
void ChromeClientImpl::mouseDidMoveOverElement( const HitTestResult& result, unsigned modifierFlags) { if (!m_webView->client()) return; // Find out if the mouse is over a link, and if so, let our UI know... if (result.isLiveLink() && !result.absoluteLinkURL().string().isEmpty()) m_webView->client()->setMouseOverURL(result.absoluteLinkURL()); else m_webView->client()->setMouseOverURL(WebURL()); }
void ChromeClientQt::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) { if (result.absoluteLinkURL() != lastHoverURL || result.title() != lastHoverTitle || result.textContent() != lastHoverContent) { lastHoverURL = result.absoluteLinkURL(); lastHoverTitle = result.title(); lastHoverContent = result.textContent(); emit m_webPage->linkHovered(lastHoverURL.prettyURL(), lastHoverTitle, lastHoverContent); } }
void ChromeClientQt::mouseDidMoveOverElement(const HitTestResult& result, unsigned) { TextDirection dir; if (result.absoluteLinkURL() != lastHoverURL || result.title(dir) != lastHoverTitle || result.textContent() != lastHoverContent) { lastHoverURL = result.absoluteLinkURL(); lastHoverTitle = result.title(dir); lastHoverContent = result.textContent(); emit m_webPage->linkHovered(lastHoverURL.string(), lastHoverTitle, lastHoverContent); } }
bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos) { ASSERT(frame); ASSERT(frame->settings()); if (!frame->view() || !frame->contentRenderer()) return false; HitTestResult mouseDownTarget = HitTestResult(framePos); mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true); if (mouseDownTarget.image() && !mouseDownTarget.absoluteImageURL().isEmpty() && frame->settings()->loadsImagesAutomatically() && m_dragSourceAction & DragSourceActionImage) return true; if (!mouseDownTarget.absoluteLinkURL().isEmpty() && m_dragSourceAction & DragSourceActionLink && mouseDownTarget.isLiveLink()) return true; if (mouseDownTarget.isSelected() && m_dragSourceAction & DragSourceActionSelection) return true; return false; }
void ChromeClient::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags) { // check if the element is a link... bool isLink = hit.isLiveLink(); if (isLink) { KURL url = hit.absoluteLinkURL(); if (!url.isEmpty() && url != m_hoveredLinkURL) { TextDirection dir; CString titleString = hit.title(dir).utf8(); CString urlString = url.string().utf8(); g_signal_emit_by_name(m_webView, "hovering-over-link", titleString.data(), urlString.data()); m_hoveredLinkURL = url; } } else if (!isLink && !m_hoveredLinkURL.isEmpty()) { g_signal_emit_by_name(m_webView, "hovering-over-link", 0, 0); m_hoveredLinkURL = KURL(); } if (Node* node = hit.innerNonSharedNode()) { Frame* frame = node->document()->frame(); FrameView* view = frame ? frame->view() : 0; m_webView->priv->tooltipArea = view ? view->contentsToWindow(node->getRect()) : IntRect(); } else m_webView->priv->tooltipArea = IntRect(); }
void Chrome::setToolTip(const HitTestResult& result) { // First priority is a potential toolTip representing a spelling or grammar error String toolTip = result.spellingToolTip(); // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those). if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) { if (Node* node = result.innerNonSharedNode()) { // Get tooltip representing form action, if relevant if (node->hasTagName(inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); if (input->inputType() == HTMLInputElement::SUBMIT) if (HTMLFormElement* form = input->form()) toolTip = form->action(); } } // Get tooltip representing link's URL if (toolTip.isEmpty()) // FIXME: Need to pass this URL through userVisibleString once that's in WebCore toolTip = result.absoluteLinkURL().string(); } // Lastly we'll consider a tooltip for element with "title" attribute if (toolTip.isEmpty()) toolTip = result.title(); m_client->setToolTip(toolTip); }
void Chrome::setToolTip(const HitTestResult& result) { // First priority is a potential toolTip representing a spelling or grammar error TextDirection toolTipDirection; String toolTip = result.spellingToolTip(toolTipDirection); // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those). if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) { // weolar __asm int 3; // if (Node* node = result.innerNonSharedNode()) { // // Get tooltip representing form action, if relevant // if (node->hasTagName(inputTag)) { // HTMLInputElement* input = static_cast<HTMLInputElement*>(node); // if (input->isSubmitButton()) // if (HTMLFormElement* form = input->form()) { // toolTip = form->action(); // if (form->renderer()) // toolTipDirection = form->renderer()->style()->direction(); // else // toolTipDirection = LTR; // } // } // } // Get tooltip representing link's URL if (toolTip.isEmpty()) { // FIXME: Need to pass this URL through userVisibleString once that's in WebCore toolTip = result.absoluteLinkURL().string(); // URL always display as LTR. toolTipDirection = LTR; } }
void ChromeClient::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags) { // If a tooltip must be displayed it will be, afterwards, when // setToolTip is called; this is just a work-around to make sure // it updates its location correctly; see // https://bugs.webkit.org/show_bug.cgi?id=15793. g_object_set(m_webView, "has-tooltip", FALSE, NULL); GdkDisplay* gdkDisplay; GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView)); if (GTK_WIDGET_TOPLEVEL(window)) gdkDisplay = gtk_widget_get_display(window); else gdkDisplay = gdk_display_get_default(); gtk_tooltip_trigger_tooltip_query(gdkDisplay); // check if the element is a link... bool isLink = hit.isLiveLink(); if (isLink) { KURL url = hit.absoluteLinkURL(); if (!url.isEmpty() && url != m_hoveredLinkURL) { TextDirection dir; CString titleString = hit.title(dir).utf8(); CString urlString = url.prettyURL().utf8(); g_signal_emit_by_name(m_webView, "hovering-over-link", titleString.data(), urlString.data()); m_hoveredLinkURL = url; } } else if (!isLink && !m_hoveredLinkURL.isEmpty()) { g_signal_emit_by_name(m_webView, "hovering-over-link", 0, 0); m_hoveredLinkURL = KURL(); } }
void ChromeClientEA::mouseDidMoveOverElement(const HitTestResult& result, unsigned) { #if 0 // This could have interesting usage in UI. On PC, it is mostly used to display info in the // status panel. TextDirection dir; if (result.absoluteLinkURL() != lastHoverURL || result.title(dir) != lastHoverTitle || result.textContent() != lastHoverContent) { lastHoverURL = result.absoluteLinkURL(); lastHoverTitle = result.title(dir); lastHoverContent = result.textContent(); emit m_webPage->linkHovered(lastHoverURL.string(), lastHoverTitle, lastHoverContent); } #endif }
void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) { if (result.innerNode()) { if (result.innerNode()->document().isDNSPrefetchEnabled()) prefetchDNS(result.absoluteLinkURL().host()); } m_client->mouseDidMoveOverElement(result, modifierFlags); }
void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) { if (result.innerNode() && result.innerNode()->document().isDNSPrefetchEnabled()) prefetchDNS(result.absoluteLinkURL().host()); m_client.mouseDidMoveOverElement(result, modifierFlags); InspectorInstrumentation::mouseDidMoveOverElement(&m_page, result, modifierFlags); }
void Chrome::setToolTip(const HitTestResult& result) { // First priority is a potential toolTip representing a spelling or grammar error TextDirection toolTipDirection; String toolTip = result.spellingToolTip(toolTipDirection); // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those). if (toolTip.isEmpty() && m_page.settings().showsURLsInToolTips()) { if (Element* element = result.innerNonSharedElement()) { // Get tooltip representing form action, if relevant if (isHTMLInputElement(element)) { HTMLInputElement* input = toHTMLInputElement(element); if (input->isSubmitButton()) { if (HTMLFormElement* form = input->form()) { toolTip = form->action(); if (form->renderer()) toolTipDirection = form->renderer()->style()->direction(); else toolTipDirection = LTR; } } } } // Get tooltip representing link's URL if (toolTip.isEmpty()) { // FIXME: Need to pass this URL through userVisibleString once that's in WebCore toolTip = result.absoluteLinkURL().string(); // URL always display as LTR. toolTipDirection = LTR; } } // Next we'll consider a tooltip for element with "title" attribute if (toolTip.isEmpty()) toolTip = result.title(toolTipDirection); if (toolTip.isEmpty() && m_page.settings().showsToolTipOverTruncatedText()) toolTip = result.innerTextIfTruncated(toolTipDirection); // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames if (toolTip.isEmpty()) { if (Element* element = result.innerNonSharedElement()) { if (isHTMLInputElement(element)) { toolTip = toHTMLInputElement(element)->defaultToolTip(); // FIXME: We should obtain text direction of tooltip from // ChromeClient or platform. As of October 2011, all client // implementations don't use text direction information for // ChromeClient::setToolTip. We'll work on tooltip text // direction during bidi cleanup in form inputs. toolTipDirection = LTR; } } } m_client.setToolTip(toolTip, toolTipDirection); }
void ChromeClient::mouseDidMoveOverElement(const HitTestResult& result) { if (result.innerNode() && result.innerNode()->document().isDNSPrefetchEnabled()) prefetchDNS(result.absoluteLinkURL().host()); showMouseOverURL(result); setToolTip(result); }
void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) { if (result.innerNode()) { Document* document = result.innerNode()->document(); if (document && document->isDNSPrefetchEnabled()) ResourceHandle::prepareForURL(result.absoluteLinkURL()); } m_client->mouseDidMoveOverElement(result, modifierFlags); InspectorInstrumentation::mouseDidMoveOverElement(m_page, result, modifierFlags); }
WebHitTestResult::Data::Data(const HitTestResult& hitTestResult) : absoluteImageURL(hitTestResult.absoluteImageURL().string()) , absolutePDFURL(hitTestResult.absolutePDFURL().string()) , absoluteLinkURL(hitTestResult.absoluteLinkURL().string()) , absoluteMediaURL(hitTestResult.absoluteMediaURL().string()) , linkLabel(hitTestResult.textContent()) , linkTitle(hitTestResult.titleDisplayString()) , isContentEditable(hitTestResult.isContentEditable()) , elementBoundingBox(elementBoundingBoxInWindowCoordinates(hitTestResult)) , isScrollbar(hitTestResult.scrollbar()) { }
void Chrome::setToolTip(const HitTestResult& result) { // First priority is a potential toolTip representing a spelling or grammar error String toolTip = result.spellingToolTip(); // Next priority is a toolTip from a URL beneath the mouse (if preference is set to show those). if (toolTip.isEmpty() && m_page->settings()->showsURLsInToolTips()) { if (Node* node = result.innerNonSharedNode()) { // Get tooltip representing form action, if relevant if (node->hasTagName(inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); if (input->inputType() == HTMLInputElement::SUBMIT) if (HTMLFormElement* form = input->form()) toolTip = form->action(); } } // Get tooltip representing link's URL if (toolTip.isEmpty()) // FIXME: Need to pass this URL through userVisibleString once that's in WebCore toolTip = result.absoluteLinkURL().string(); } // Next we'll consider a tooltip for element with "title" attribute if (toolTip.isEmpty()) toolTip = result.title(); // Lastly, for <input type="file"> that allow multiple files, we'll consider a tooltip for the selected filenames if (toolTip.isEmpty()) { if (Node* node = result.innerNonSharedNode()) { if (node->hasTagName(inputTag)) { HTMLInputElement* input = static_cast<HTMLInputElement*>(node); if (input->inputType() == HTMLInputElement::FILE) { FileList* files = input->files(); unsigned listSize = files->length(); if (files && listSize > 1) { Vector<UChar> names; for (size_t i = 0; i < listSize; ++i) { append(names, files->item(i)->fileName()); if (i != listSize - 1) names.append('\n'); } toolTip = String::adopt(names); } } } } } m_client->setToolTip(toolTip); }
void Chrome::mouseDidMoveOverElement(const HitTestResult& result, unsigned modifierFlags) { if (result.innerNode()) { Document* document = result.innerNode()->document(); if (document && document->isDNSPrefetchEnabled()) prefetchDNS(result.absoluteLinkURL().host()); } m_client->mouseDidMoveOverElement(result, modifierFlags); #if ENABLE(INSPECTOR) if (InspectorController* inspector = m_page->inspectorController()) inspector->mouseDidMoveOverElement(result, modifierFlags); #endif }
void ChromeClientImpl::showMouseOverURL(const HitTestResult& result) { if (!m_webView->client()) return; WebURL url; // Find out if the mouse is over a link, and if so, let our UI know... if (result.isLiveLink() && !result.absoluteLinkURL().getString().isEmpty()) { url = result.absoluteLinkURL(); } else if (result.innerNode() && (isHTMLObjectElement(*result.innerNode()) || isHTMLEmbedElement(*result.innerNode()))) { LayoutObject* object = result.innerNode()->layoutObject(); if (object && object->isLayoutPart()) { Widget* widget = toLayoutPart(object)->widget(); if (widget && widget->isPluginContainer()) { WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget); url = plugin->plugin()->linkAtPosition( result.roundedPointInInnerNodeFrame()); } } } m_webView->client()->setMouseOverURL(url); }
void ChromeClient::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags) { // check if the element is a link... bool isLink = hit.isLiveLink(); if (isLink) { KURL url = hit.absoluteLinkURL(); if (!url.isEmpty() && url != m_hoveredLinkURL) { CString titleString = hit.title().utf8(); CString urlString = url.prettyURL().utf8(); g_signal_emit_by_name(m_webView, "hovering-over-link", titleString.data(), urlString.data()); m_hoveredLinkURL = url; } } else if (!isLink && !m_hoveredLinkURL.isEmpty()) { g_signal_emit_by_name(m_webView, "hovering-over-link", 0, 0); m_hoveredLinkURL = KURL(); } }
void ChromeClientEfl::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags) { // FIXME, compare with old link, look at Qt impl. bool isLink = hit.isLiveLink(); if (isLink) { KURL url = hit.absoluteLinkURL(); if (!url.isEmpty() && url != m_hoveredLinkURL) { const char* link[2]; TextDirection dir; CString urlStr = url.string().utf8(); CString titleStr = hit.title(dir).utf8(); link[0] = urlStr.data(); link[1] = titleStr.data(); ewk_view_mouse_link_hover_in(m_view, link); m_hoveredLinkURL = url; } } else if (!isLink && !m_hoveredLinkURL.isEmpty()) { ewk_view_mouse_link_hover_out(m_view); m_hoveredLinkURL = KURL(); } }
void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) { ASSERT(item->type() == ActionType || item->type() == CheckableActionType); if (item->action() >= ContextMenuItemBaseApplicationTag) { m_client->contextMenuItemSelected(item, m_contextMenu.get()); return; } HitTestResult result = m_contextMenu->hitTestResult(); Frame* frame = result.innerNonSharedNode()->document()->frame(); if (!frame) return; switch (item->action()) { case ContextMenuItemTagOpenLinkInNewWindow: openNewWindow(result.absoluteLinkURL(), frame); break; case ContextMenuItemTagDownloadLinkToDisk: // FIXME: Some day we should be able to do this from within WebCore. m_client->downloadURL(result.absoluteLinkURL()); break; case ContextMenuItemTagCopyLinkToClipboard: frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent()); break; case ContextMenuItemTagOpenImageInNewWindow: openNewWindow(result.absoluteImageURL(), frame); break; case ContextMenuItemTagDownloadImageToDisk: // FIXME: Some day we should be able to do this from within WebCore. m_client->downloadURL(result.absoluteImageURL()); break; case ContextMenuItemTagCopyImageToClipboard: // FIXME: The Pasteboard class is not written yet // For now, call into the client. This is temporary! frame->editor()->copyImage(result); break; case ContextMenuItemTagOpenFrameInNewWindow: { DocumentLoader* loader = frame->loader()->documentLoader(); if (!loader->unreachableURL().isEmpty()) openNewWindow(loader->unreachableURL(), frame); else openNewWindow(loader->url(), frame); break; } case ContextMenuItemTagCopy: frame->editor()->copy(); break; case ContextMenuItemTagGoBack: frame->loader()->goBackOrForward(-1); break; case ContextMenuItemTagGoForward: frame->loader()->goBackOrForward(1); break; case ContextMenuItemTagStop: frame->loader()->stop(); break; case ContextMenuItemTagReload: frame->loader()->reload(); break; case ContextMenuItemTagCut: frame->editor()->cut(); break; case ContextMenuItemTagPaste: frame->editor()->paste(); break; #if PLATFORM(GTK) || PLATFORM(BAL) case ContextMenuItemTagDelete: frame->editor()->performDelete(); break; case ContextMenuItemTagSelectAll: frame->editor()->command("SelectAll").execute(); break; #endif case ContextMenuItemTagSpellingGuess: ASSERT(frame->selectedText().length()); if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toRange().get(), EditorInsertActionPasted)) { Document* document = frame->document(); RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), true, false, true); applyCommand(command); frame->revealSelection(RenderLayer::gAlignToEdgeIfNeeded); } break; case ContextMenuItemTagIgnoreSpelling: frame->editor()->ignoreSpelling(); break; case ContextMenuItemTagLearnSpelling: frame->editor()->learnSpelling(); break; case ContextMenuItemTagSearchWeb: m_client->searchWithGoogle(frame); break; case ContextMenuItemTagLookUpInDictionary: // FIXME: Some day we may be able to do this from within WebCore. m_client->lookUpInDictionary(frame); break; case ContextMenuItemTagOpenLink: if (Frame* targetFrame = result.targetFrame()) targetFrame->loader()->loadFrameRequestWithFormAndValues(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, 0, 0, HashMap<String, String>()); else openNewWindow(result.absoluteLinkURL(), frame); break; case ContextMenuItemTagBold: frame->editor()->command("ToggleBold").execute(); break; case ContextMenuItemTagItalic: frame->editor()->command("ToggleItalic").execute(); break; case ContextMenuItemTagUnderline: frame->editor()->toggleUnderline(); break; case ContextMenuItemTagOutline: // We actually never enable this because CSS does not have a way to specify an outline font, // which may make this difficult to implement. Maybe a special case of text-shadow? break; case ContextMenuItemTagStartSpeaking: { ExceptionCode ec; RefPtr<Range> selectedRange = frame->selection()->toRange(); if (!selectedRange || selectedRange->collapsed(ec)) { Document* document = result.innerNonSharedNode()->document(); selectedRange = document->createRange(); selectedRange->selectNode(document->documentElement(), ec); } m_client->speak(plainText(selectedRange.get())); break; } case ContextMenuItemTagStopSpeaking: m_client->stopSpeaking(); break; case ContextMenuItemTagDefaultDirection: frame->editor()->setBaseWritingDirection(NaturalWritingDirection); break; case ContextMenuItemTagLeftToRight: frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); break; case ContextMenuItemTagRightToLeft: frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); break; #if PLATFORM(MAC) case ContextMenuItemTagSearchInSpotlight: m_client->searchWithSpotlight(); break; #endif case ContextMenuItemTagShowSpellingPanel: frame->editor()->showSpellingGuessPanel(); break; case ContextMenuItemTagCheckSpelling: frame->editor()->advanceToNextMisspelling(); break; case ContextMenuItemTagCheckSpellingWhileTyping: frame->editor()->toggleContinuousSpellChecking(); break; #ifndef BUILDING_ON_TIGER case ContextMenuItemTagCheckGrammarWithSpelling: frame->editor()->toggleGrammarChecking(); break; #endif #if PLATFORM(MAC) case ContextMenuItemTagShowFonts: frame->editor()->showFontPanel(); break; case ContextMenuItemTagStyles: frame->editor()->showStylesPanel(); break; case ContextMenuItemTagShowColors: frame->editor()->showColorPanel(); break; #endif case ContextMenuItemTagInspectElement: if (Page* page = frame->page()) page->inspectorController()->inspect(result.innerNonSharedNode()); break; default: break; } }
DragOperation DragController::tryDHTMLDrag(DragData* dragData) { ASSERT(dragData); ASSERT(m_document); DragOperation op = DragOperationNone; RefPtr<Frame> frame = m_page->mainFrame(); RefPtr<FrameView> viewProtector = frame->view(); if (!viewProtector) return DragOperationNone; ClipboardAccessPolicy policy = frame->loader()->baseURL().isLocalFile() ? ClipboardReadable : ClipboardTypesReadable; RefPtr<Clipboard> clipboard = dragData->createClipboard(policy); DragOperation srcOp = dragData->draggingSourceOperationMask(); clipboard->setSourceOperation(srcOp); #ifdef __OWB__ if (frame->eventHandler()->updateDragAndDrop(createMouseEvent(dragData), clipboard.get())) { #else PlatformMouseEvent event = createMouseEvent(dragData); if (frame->eventHandler()->updateDragAndDrop(event, clipboard.get())) { #endif // *op unchanged if no source op was set if (!clipboard->destinationOperation(op)) { // The element accepted but they didn't pick an operation, so we pick one for them // (as does WinIE). if (srcOp & DragOperationCopy) op = DragOperationCopy; else if (srcOp & DragOperationMove || srcOp & DragOperationGeneric) op = DragOperationMove; else if (srcOp & DragOperationLink) op = DragOperationLink; else op = DragOperationGeneric; } else if (!(op & srcOp)) { op = DragOperationNone; } clipboard->setAccessPolicy(ClipboardNumb); // invalidate clipboard here for security return op; } return op; } bool DragController::mayStartDragAtEventLocation(const Frame* frame, const IntPoint& framePos) { ASSERT(frame); if (!frame->view() || !frame->renderer()) return false; HitTestResult mouseDownTarget = HitTestResult(framePos); mouseDownTarget = frame->eventHandler()->hitTestResultAtPoint(framePos, true); if (mouseDownTarget.image() && !mouseDownTarget.absoluteImageURL().isEmpty() && frame->settings()->loadsImagesAutomatically() && m_dragSourceAction & DragSourceActionImage) return true; if (!mouseDownTarget.absoluteLinkURL().isEmpty() && m_dragSourceAction & DragSourceActionLink && mouseDownTarget.isLiveLink()) return true; if (mouseDownTarget.isSelected() && m_dragSourceAction & DragSourceActionSelection) return true; return false; }
void ContextMenuController::contextMenuItemSelected(ContextMenuItem* item) { ASSERT(item->type() == ActionType || item->type() == CheckableActionType); if (item->action() >= ContextMenuItemBaseApplicationTag) { m_client->contextMenuItemSelected(item, m_contextMenu.get()); return; } if (item->action() >= ContextMenuItemBaseCustomTag) { ASSERT(m_menuProvider); m_menuProvider->contextMenuItemSelected(item); return; } HitTestResult result = m_contextMenu->hitTestResult(); Frame* frame = result.innerNonSharedNode()->document()->frame(); if (!frame) return; switch (item->action()) { case ContextMenuItemTagOpenLinkInNewWindow: openNewWindow(result.absoluteLinkURL(), frame); break; case ContextMenuItemTagDownloadLinkToDisk: // FIXME: Some day we should be able to do this from within WebCore. m_client->downloadURL(result.absoluteLinkURL()); break; case ContextMenuItemTagCopyLinkToClipboard: frame->editor()->copyURL(result.absoluteLinkURL(), result.textContent()); break; case ContextMenuItemTagOpenImageInNewWindow: openNewWindow(result.absoluteImageURL(), frame); break; case ContextMenuItemTagDownloadImageToDisk: // FIXME: Some day we should be able to do this from within WebCore. m_client->downloadURL(result.absoluteImageURL()); break; case ContextMenuItemTagCopyImageToClipboard: // FIXME: The Pasteboard class is not written yet // For now, call into the client. This is temporary! frame->editor()->copyImage(result); break; case ContextMenuItemTagOpenMediaInNewWindow: openNewWindow(result.absoluteMediaURL(), frame); break; case ContextMenuItemTagCopyMediaLinkToClipboard: frame->editor()->copyURL(result.absoluteMediaURL(), result.textContent()); break; case ContextMenuItemTagToggleMediaControls: result.toggleMediaControlsDisplay(); break; case ContextMenuItemTagToggleMediaLoop: result.toggleMediaLoopPlayback(); break; case ContextMenuItemTagEnterVideoFullscreen: result.enterFullscreenForVideo(); break; case ContextMenuItemTagMediaPlayPause: result.toggleMediaPlayState(); break; case ContextMenuItemTagMediaMute: result.toggleMediaMuteState(); break; case ContextMenuItemTagOpenFrameInNewWindow: { DocumentLoader* loader = frame->loader()->documentLoader(); if (!loader->unreachableURL().isEmpty()) openNewWindow(loader->unreachableURL(), frame); else openNewWindow(loader->url(), frame); break; } case ContextMenuItemTagCopy: frame->editor()->copy(); break; case ContextMenuItemTagGoBack: if (Page* page = frame->page()) page->goBackOrForward(-1); break; case ContextMenuItemTagGoForward: if (Page* page = frame->page()) page->goBackOrForward(1); break; case ContextMenuItemTagStop: frame->loader()->stop(); break; case ContextMenuItemTagReload: frame->loader()->reload(); break; case ContextMenuItemTagCut: frame->editor()->cut(); break; case ContextMenuItemTagPaste: frame->editor()->paste(); break; #if PLATFORM(GTK) case ContextMenuItemTagDelete: frame->editor()->performDelete(); break; case ContextMenuItemTagSelectAll: frame->editor()->command("SelectAll").execute(); break; #endif case ContextMenuItemTagSpellingGuess: ASSERT(frame->editor()->selectedText().length()); if (frame->editor()->shouldInsertText(item->title(), frame->selection()->toNormalizedRange().get(), EditorInsertActionPasted)) { Document* document = frame->document(); RefPtr<ReplaceSelectionCommand> command = ReplaceSelectionCommand::create(document, createFragmentFromMarkup(document, item->title(), ""), true, false, true); applyCommand(command); frame->selection()->revealSelection(ScrollAlignment::alignToEdgeIfNeeded); } break; case ContextMenuItemTagIgnoreSpelling: frame->editor()->ignoreSpelling(); break; case ContextMenuItemTagLearnSpelling: frame->editor()->learnSpelling(); break; case ContextMenuItemTagSearchWeb: m_client->searchWithGoogle(frame); break; case ContextMenuItemTagLookUpInDictionary: // FIXME: Some day we may be able to do this from within WebCore. m_client->lookUpInDictionary(frame); break; case ContextMenuItemTagOpenLink: if (Frame* targetFrame = result.targetFrame()) targetFrame->loader()->loadFrameRequest(FrameLoadRequest(ResourceRequest(result.absoluteLinkURL(), frame->loader()->outgoingReferrer())), false, false, 0, 0, SendReferrer); else openNewWindow(result.absoluteLinkURL(), frame); break; case ContextMenuItemTagBold: frame->editor()->command("ToggleBold").execute(); break; case ContextMenuItemTagItalic: frame->editor()->command("ToggleItalic").execute(); break; case ContextMenuItemTagUnderline: frame->editor()->toggleUnderline(); break; case ContextMenuItemTagOutline: // We actually never enable this because CSS does not have a way to specify an outline font, // which may make this difficult to implement. Maybe a special case of text-shadow? break; case ContextMenuItemTagStartSpeaking: { ExceptionCode ec; RefPtr<Range> selectedRange = frame->selection()->toNormalizedRange(); if (!selectedRange || selectedRange->collapsed(ec)) { Document* document = result.innerNonSharedNode()->document(); selectedRange = document->createRange(); selectedRange->selectNode(document->documentElement(), ec); } m_client->speak(plainText(selectedRange.get())); break; } case ContextMenuItemTagStopSpeaking: m_client->stopSpeaking(); break; case ContextMenuItemTagDefaultDirection: frame->editor()->setBaseWritingDirection(NaturalWritingDirection); break; case ContextMenuItemTagLeftToRight: frame->editor()->setBaseWritingDirection(LeftToRightWritingDirection); break; case ContextMenuItemTagRightToLeft: frame->editor()->setBaseWritingDirection(RightToLeftWritingDirection); break; case ContextMenuItemTagTextDirectionDefault: frame->editor()->command("MakeTextWritingDirectionNatural").execute(); break; case ContextMenuItemTagTextDirectionLeftToRight: frame->editor()->command("MakeTextWritingDirectionLeftToRight").execute(); break; case ContextMenuItemTagTextDirectionRightToLeft: frame->editor()->command("MakeTextWritingDirectionRightToLeft").execute(); break; #if PLATFORM(MAC) case ContextMenuItemTagSearchInSpotlight: m_client->searchWithSpotlight(); break; #endif case ContextMenuItemTagShowSpellingPanel: frame->editor()->showSpellingGuessPanel(); break; case ContextMenuItemTagCheckSpelling: frame->editor()->advanceToNextMisspelling(); break; case ContextMenuItemTagCheckSpellingWhileTyping: frame->editor()->toggleContinuousSpellChecking(); break; #ifndef BUILDING_ON_TIGER case ContextMenuItemTagCheckGrammarWithSpelling: frame->editor()->toggleGrammarChecking(); break; #endif #if PLATFORM(MAC) case ContextMenuItemTagShowFonts: frame->editor()->showFontPanel(); break; case ContextMenuItemTagStyles: frame->editor()->showStylesPanel(); break; case ContextMenuItemTagShowColors: frame->editor()->showColorPanel(); break; #endif #if PLATFORM(MAC) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) case ContextMenuItemTagMakeUpperCase: frame->editor()->uppercaseWord(); break; case ContextMenuItemTagMakeLowerCase: frame->editor()->lowercaseWord(); break; case ContextMenuItemTagCapitalize: frame->editor()->capitalizeWord(); break; case ContextMenuItemTagShowSubstitutions: frame->editor()->showSubstitutionsPanel(); break; case ContextMenuItemTagSmartCopyPaste: frame->editor()->toggleSmartInsertDelete(); break; case ContextMenuItemTagSmartQuotes: frame->editor()->toggleAutomaticQuoteSubstitution(); break; case ContextMenuItemTagSmartDashes: frame->editor()->toggleAutomaticDashSubstitution(); break; case ContextMenuItemTagSmartLinks: frame->editor()->toggleAutomaticLinkDetection(); break; case ContextMenuItemTagTextReplacement: frame->editor()->toggleAutomaticTextReplacement(); break; case ContextMenuItemTagCorrectSpellingAutomatically: frame->editor()->toggleAutomaticSpellingCorrection(); break; case ContextMenuItemTagChangeBack: frame->editor()->changeBackToReplacedString(result.replacedString()); break; #endif #if ENABLE(INSPECTOR) case ContextMenuItemTagInspectElement: if (Page* page = frame->page()) page->inspectorController()->inspect(result.innerNonSharedNode()); break; #endif default: break; } }
bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag) #endif { ASSERT(src); ASSERT(clipboard); if (!src->view() || !src->renderer()) return false; HitTestResult dragSource = HitTestResult(dragOrigin); dragSource = src->eventHandler()->hitTestResultAtPoint(dragOrigin, true); KURL linkURL = dragSource.absoluteLinkURL(); KURL imageURL = dragSource.absoluteImageURL(); bool isSelected = dragSource.isSelected(); IntPoint mouseDraggedPoint = src->view()->windowToContents(dragEvent.pos()); m_draggingImageURL = KURL(); m_dragOperation = srcOp; DragImageRef dragImage = 0; IntPoint dragLoc(0, 0); IntPoint dragImageOffset(0, 0); if (isDHTMLDrag) dragImage = clipboard->createDragImage(dragImageOffset); // We allow DHTML/JS to set the drag image, even if its a link, image or text we're dragging. // This is in the spirit of the IE API, which allows overriding of pasteboard data and DragOp. if (dragImage) { dragLoc = dragLocForDHTMLDrag(mouseDraggedPoint, dragOrigin, dragImageOffset, !linkURL.isEmpty()); m_dragOffset = dragImageOffset; } bool startedDrag = true; // optimism - we almost always manage to start the drag Node* node = dragSource.innerNonSharedNode(); if (!imageURL.isEmpty() && node && node->isElementNode() && getImage(static_cast<Element*>(node)) && (m_dragSourceAction & DragSourceActionImage)) { Element* element = static_cast<Element*>(node); if (!clipboard->hasData()) { m_draggingImageURL = imageURL; prepareClipboardForImageDrag(src, clipboard, element, linkURL, imageURL, dragSource.altDisplayString()); } m_client->willPerformDragSourceAction(DragSourceActionImage, dragOrigin, clipboard); if (!dragImage) { IntRect imageRect = dragSource.imageRect(); imageRect.setLocation(m_page->mainFrame()->view()->windowToContents(src->view()->contentsToWindow(imageRect.location()))); doImageDrag(element, dragOrigin, dragSource.imageRect(), clipboard, src, m_dragOffset); } else // DHTML defined drag image doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (!linkURL.isEmpty() && (m_dragSourceAction & DragSourceActionLink)) { if (!clipboard->hasData()) // Simplify whitespace so the title put on the clipboard resembles what the user sees // on the web page. This includes replacing newlines with spaces. clipboard->writeURL(linkURL, dragSource.textContent().simplifyWhiteSpace(), src); m_client->willPerformDragSourceAction(DragSourceActionLink, dragOrigin, clipboard); if (!dragImage) { dragImage = m_client->createDragImageForLink(linkURL, dragSource.textContent(), src); IntSize size = dragImageSize(dragImage); m_dragOffset = IntPoint(-size.width() / 2, -LinkDragBorderInset); dragLoc = IntPoint(mouseDraggedPoint.x() + m_dragOffset.x(), mouseDraggedPoint.y() + m_dragOffset.y()); } doSystemDrag(dragImage, dragLoc, mouseDraggedPoint, clipboard, src, true); } else if (isSelected && (m_dragSourceAction & DragSourceActionSelection)) { RefPtr<Range> selectionRange = src->selectionController()->toRange(); ASSERT(selectionRange); if (!clipboard->hasData()) clipboard->writeRange(selectionRange.get(), src); m_client->willPerformDragSourceAction(DragSourceActionSelection, dragOrigin, clipboard); if (!dragImage) { dragImage = createDragImageForSelection(src); dragLoc = dragLocForSelectionDrag(src); m_dragOffset = IntPoint((int)(dragOrigin.x() - dragLoc.x()), (int)(dragOrigin.y() - dragLoc.y())); } doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else if (isDHTMLDrag) { ASSERT(m_dragSourceAction & DragSourceActionDHTML); m_client->willPerformDragSourceAction(DragSourceActionDHTML, dragOrigin, clipboard); doSystemDrag(dragImage, dragLoc, dragOrigin, clipboard, src, false); } else { // Only way I know to get here is if to get here is if the original element clicked on in the mousedown is no longer // under the mousedown point, so linkURL, imageURL and isSelected are all false/empty. startedDrag = false; } if (dragImage) deleteDragImage(dragImage); return startedDrag; }
void ContextMenu::populate() { ContextMenuItem OpenLinkItem(ActionType, ContextMenuItemTagOpenLink, contextMenuItemTagOpenLink()); ContextMenuItem OpenLinkInNewWindowItem(ActionType, ContextMenuItemTagOpenLinkInNewWindow, contextMenuItemTagOpenLinkInNewWindow()); ContextMenuItem DownloadFileItem(ActionType, ContextMenuItemTagDownloadLinkToDisk, contextMenuItemTagDownloadLinkToDisk()); ContextMenuItem CopyLinkItem(ActionType, ContextMenuItemTagCopyLinkToClipboard, contextMenuItemTagCopyLinkToClipboard()); ContextMenuItem OpenImageInNewWindowItem(ActionType, ContextMenuItemTagOpenImageInNewWindow, contextMenuItemTagOpenImageInNewWindow()); ContextMenuItem DownloadImageItem(ActionType, ContextMenuItemTagDownloadImageToDisk, contextMenuItemTagDownloadImageToDisk()); ContextMenuItem CopyImageItem(ActionType, ContextMenuItemTagCopyImageToClipboard, contextMenuItemTagCopyImageToClipboard()); #if PLATFORM(MAC) ContextMenuItem SearchSpotlightItem(ActionType, ContextMenuItemTagSearchInSpotlight, contextMenuItemTagSearchInSpotlight()); ContextMenuItem LookInDictionaryItem(ActionType, ContextMenuItemTagLookUpInDictionary, contextMenuItemTagLookUpInDictionary()); #endif ContextMenuItem SearchWebItem(ActionType, ContextMenuItemTagSearchWeb, contextMenuItemTagSearchWeb()); ContextMenuItem CopyItem(ActionType, ContextMenuItemTagCopy, contextMenuItemTagCopy()); ContextMenuItem BackItem(ActionType, ContextMenuItemTagGoBack, contextMenuItemTagGoBack()); ContextMenuItem ForwardItem(ActionType, ContextMenuItemTagGoForward, contextMenuItemTagGoForward()); ContextMenuItem StopItem(ActionType, ContextMenuItemTagStop, contextMenuItemTagStop()); ContextMenuItem ReloadItem(ActionType, ContextMenuItemTagReload, contextMenuItemTagReload()); ContextMenuItem OpenFrameItem(ActionType, ContextMenuItemTagOpenFrameInNewWindow, contextMenuItemTagOpenFrameInNewWindow()); ContextMenuItem NoGuessesItem(ActionType, ContextMenuItemTagNoGuessesFound, contextMenuItemTagNoGuessesFound()); ContextMenuItem IgnoreSpellingItem(ActionType, ContextMenuItemTagIgnoreSpelling, contextMenuItemTagIgnoreSpelling()); ContextMenuItem LearnSpellingItem(ActionType, ContextMenuItemTagLearnSpelling, contextMenuItemTagLearnSpelling()); ContextMenuItem IgnoreGrammarItem(ActionType, ContextMenuItemTagIgnoreGrammar, contextMenuItemTagIgnoreGrammar()); ContextMenuItem CutItem(ActionType, ContextMenuItemTagCut, contextMenuItemTagCut()); ContextMenuItem PasteItem(ActionType, ContextMenuItemTagPaste, contextMenuItemTagPaste()); #if PLATFORM(GTK) ContextMenuItem DeleteItem(ActionType, ContextMenuItemTagDelete, contextMenuItemTagDelete()); ContextMenuItem SelectAllItem(ActionType, ContextMenuItemTagSelectAll, contextMenuItemTagSelectAll()); #endif HitTestResult result = hitTestResult(); Node* node = m_hitTestResult.innerNonSharedNode(); if (!node) return; #if PLATFORM(GTK) if (!result.isContentEditable() && node->isControl()) return; #endif Frame* frame = node->document()->frame(); if (!frame) return; if (!result.isContentEditable()) { FrameLoader* loader = frame->loader(); KURL linkURL = result.absoluteLinkURL(); if (!linkURL.isEmpty()) { if (loader->canHandleRequest(ResourceRequest(linkURL))) { appendItem(OpenLinkItem); appendItem(OpenLinkInNewWindowItem); appendItem(DownloadFileItem); } appendItem(CopyLinkItem); } KURL imageURL = result.absoluteImageURL(); if (!imageURL.isEmpty()) { if (!linkURL.isEmpty()) appendItem(*separatorItem()); appendItem(OpenImageInNewWindowItem); appendItem(DownloadImageItem); if (imageURL.isLocalFile() || m_hitTestResult.image()) appendItem(CopyImageItem); } if (imageURL.isEmpty() && linkURL.isEmpty()) { if (result.isSelected()) { if (selectionContainsPossibleWord(frame)) { #if PLATFORM(MAC) appendItem(SearchSpotlightItem); #endif appendItem(SearchWebItem); appendItem(*separatorItem()); #if PLATFORM(MAC) appendItem(LookInDictionaryItem); appendItem(*separatorItem()); #endif } appendItem(CopyItem); } else { #if PLATFORM(GTK) appendItem(BackItem); appendItem(ForwardItem); appendItem(StopItem); appendItem(ReloadItem); #else if (loader->canGoBackOrForward(-1)) appendItem(BackItem); if (loader->canGoBackOrForward(1)) appendItem(ForwardItem); // use isLoadingInAPISense rather than isLoading because Stop/Reload are // intended to match WebKit's API, not WebCore's internal notion of loading status if (loader->documentLoader()->isLoadingInAPISense()) appendItem(StopItem); else appendItem(ReloadItem); #endif if (frame->page() && frame != frame->page()->mainFrame()) appendItem(OpenFrameItem); } } } else { // Make an editing context menu SelectionController* selection = frame->selection(); bool inPasswordField = selection->isInPasswordField(); if (!inPasswordField) { // Consider adding spelling-related or grammar-related context menu items (never both, since a single selected range // is never considered a misspelling and bad grammar at the same time) bool misspelling = frame->editor()->isSelectionMisspelled(); bool badGrammar = !misspelling && (frame->editor()->isGrammarCheckingEnabled() && frame->editor()->isSelectionUngrammatical()); if (misspelling || badGrammar) { Vector<String> guesses = misspelling ? frame->editor()->guessesForMisspelledSelection() : frame->editor()->guessesForUngrammaticalSelection(); size_t size = guesses.size(); if (size == 0) { // If there's bad grammar but no suggestions (e.g., repeated word), just leave off the suggestions // list and trailing separator rather than adding a "No Guesses Found" item (matches AppKit) if (misspelling) { appendItem(NoGuessesItem); appendItem(*separatorItem()); } } else { for (unsigned i = 0; i < size; i++) { const String &guess = guesses[i]; if (!guess.isEmpty()) { ContextMenuItem item(ActionType, ContextMenuItemTagSpellingGuess, guess); appendItem(item); } } appendItem(*separatorItem()); } if (misspelling) { appendItem(IgnoreSpellingItem); appendItem(LearnSpellingItem); } else appendItem(IgnoreGrammarItem); appendItem(*separatorItem()); } } FrameLoader* loader = frame->loader(); KURL linkURL = result.absoluteLinkURL(); if (!linkURL.isEmpty()) { if (loader->canHandleRequest(ResourceRequest(linkURL))) { appendItem(OpenLinkItem); appendItem(OpenLinkInNewWindowItem); appendItem(DownloadFileItem); } appendItem(CopyLinkItem); appendItem(*separatorItem()); } if (result.isSelected() && !inPasswordField && selectionContainsPossibleWord(frame)) { #if PLATFORM(MAC) appendItem(SearchSpotlightItem); #endif appendItem(SearchWebItem); appendItem(*separatorItem()); #if PLATFORM(MAC) appendItem(LookInDictionaryItem); appendItem(*separatorItem()); #endif } appendItem(CutItem); appendItem(CopyItem); appendItem(PasteItem); #if PLATFORM(GTK) appendItem(DeleteItem); appendItem(*separatorItem()); appendItem(SelectAllItem); #endif if (!inPasswordField) { appendItem(*separatorItem()); #ifndef BUILDING_ON_TIGER ContextMenuItem SpellingAndGrammarMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, contextMenuItemTagSpellingMenu()); createAndAppendSpellingAndGrammarSubMenu(m_hitTestResult, SpellingAndGrammarMenuItem); appendItem(SpellingAndGrammarMenuItem); #else ContextMenuItem SpellingMenuItem(SubmenuType, ContextMenuItemTagSpellingMenu, contextMenuItemTagSpellingMenu()); createAndAppendSpellingSubMenu(m_hitTestResult, SpellingMenuItem); appendItem(SpellingMenuItem); #endif ContextMenuItem FontMenuItem(SubmenuType, ContextMenuItemTagFontMenu, contextMenuItemTagFontMenu()); createAndAppendFontSubMenu(m_hitTestResult, FontMenuItem); appendItem(FontMenuItem); #if PLATFORM(MAC) ContextMenuItem SpeechMenuItem(SubmenuType, ContextMenuItemTagSpeechMenu, contextMenuItemTagSpeechMenu()); createAndAppendSpeechSubMenu(m_hitTestResult, SpeechMenuItem); appendItem(SpeechMenuItem); #endif #if !PLATFORM(GTK) ContextMenuItem WritingDirectionMenuItem(SubmenuType, ContextMenuItemTagWritingDirectionMenu, contextMenuItemTagWritingDirectionMenu()); createAndAppendWritingDirectionSubMenu(m_hitTestResult, WritingDirectionMenuItem); appendItem(WritingDirectionMenuItem); if (Page* page = frame->page()) { if (Settings* settings = page->settings()) { bool includeTextDirectionSubmenu = settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAlwaysIncluded || settings->textDirectionSubmenuInclusionBehavior() == TextDirectionSubmenuAutomaticallyIncluded && frame->editor()->hasBidiSelection(); if (includeTextDirectionSubmenu) { ContextMenuItem TextDirectionMenuItem(SubmenuType, ContextMenuItemTagTextDirectionMenu, contextMenuItemTagTextDirectionMenu()); createAndAppendTextDirectionSubMenu(m_hitTestResult, TextDirectionMenuItem); appendItem(TextDirectionMenuItem); } } } #endif } } }
void ContextMenuClientImpl::showContextMenu(const WebCore::ContextMenu* defaultMenu) { // Displaying the context menu in this function is a big hack as we don't // have context, i.e. whether this is being invoked via a script or in // response to user input (Mouse event WM_RBUTTONDOWN, // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked // in response to the above input events before popping up the context menu. if (!m_webView->contextMenuAllowed()) return; HitTestResult r = m_webView->page()->contextMenuController().hitTestResult(); LocalFrame* selectedFrame = r.innerNodeFrame(); WebContextMenuData data; IntPoint mousePoint = selectedFrame->view()->contentsToWindow(r.roundedPointInInnerNodeFrame()); // FIXME(bokan): crbug.com/371902 - We shouldn't be making these scale // related coordinate transformatios in an ad hoc way. PinchViewport& pinchViewport = selectedFrame->host()->pinchViewport(); mousePoint -= flooredIntSize(pinchViewport.visibleRect().location()); mousePoint.scale(m_webView->pageScaleFactor(), m_webView->pageScaleFactor()); data.mousePosition = mousePoint; // Compute edit flags. data.editFlags = WebContextMenuData::CanDoNone; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canUndo()) data.editFlags |= WebContextMenuData::CanUndo; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canRedo()) data.editFlags |= WebContextMenuData::CanRedo; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canCut()) data.editFlags |= WebContextMenuData::CanCut; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canCopy()) data.editFlags |= WebContextMenuData::CanCopy; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canPaste()) data.editFlags |= WebContextMenuData::CanPaste; if (toLocalFrame(m_webView->focusedWebCoreFrame())->editor().canDelete()) data.editFlags |= WebContextMenuData::CanDelete; // We can always select all... data.editFlags |= WebContextMenuData::CanSelectAll; data.editFlags |= WebContextMenuData::CanTranslate; // Links, Images, Media tags, and Image/Media-Links take preference over // all else. data.linkURL = r.absoluteLinkURL(); if (isHTMLCanvasElement(r.innerNonSharedNode())) { data.mediaType = WebContextMenuData::MediaTypeCanvas; } else if (!r.absoluteImageURL().isEmpty()) { data.srcURL = r.absoluteImageURL(); data.mediaType = WebContextMenuData::MediaTypeImage; data.mediaFlags |= WebContextMenuData::MediaCanPrint; } else if (!r.absoluteMediaURL().isEmpty()) { data.srcURL = r.absoluteMediaURL(); // We know that if absoluteMediaURL() is not empty, then this // is a media element. HTMLMediaElement* mediaElement = toHTMLMediaElement(r.innerNonSharedNode()); if (isHTMLVideoElement(*mediaElement)) data.mediaType = WebContextMenuData::MediaTypeVideo; else if (isHTMLAudioElement(*mediaElement)) data.mediaType = WebContextMenuData::MediaTypeAudio; if (mediaElement->error()) data.mediaFlags |= WebContextMenuData::MediaInError; if (mediaElement->paused()) data.mediaFlags |= WebContextMenuData::MediaPaused; if (mediaElement->muted()) data.mediaFlags |= WebContextMenuData::MediaMuted; if (mediaElement->loop()) data.mediaFlags |= WebContextMenuData::MediaLoop; if (mediaElement->supportsSave()) data.mediaFlags |= WebContextMenuData::MediaCanSave; if (mediaElement->hasAudio()) data.mediaFlags |= WebContextMenuData::MediaHasAudio; // Media controls can be toggled only for video player. If we toggle // controls for audio then the player disappears, and there is no way to // return it back. Don't set this bit for fullscreen video, since // toggling is ignored in that case. if (mediaElement->hasVideo() && !mediaElement->isFullscreen()) data.mediaFlags |= WebContextMenuData::MediaCanToggleControls; if (mediaElement->controls()) data.mediaFlags |= WebContextMenuData::MediaControls; } else if (isHTMLObjectElement(*r.innerNonSharedNode()) || isHTMLEmbedElement(*r.innerNonSharedNode())) { RenderObject* object = r.innerNonSharedNode()->renderer(); if (object && object->isWidget()) { Widget* widget = toRenderWidget(object)->widget(); if (widget && widget->isPluginContainer()) { data.mediaType = WebContextMenuData::MediaTypePlugin; WebPluginContainerImpl* plugin = toWebPluginContainerImpl(widget); WebString text = plugin->plugin()->selectionAsText(); if (!text.isEmpty()) { data.selectedText = text; data.editFlags |= WebContextMenuData::CanCopy; } data.editFlags &= ~WebContextMenuData::CanTranslate; data.linkURL = plugin->plugin()->linkAtPosition(data.mousePosition); if (plugin->plugin()->supportsPaginatedPrint()) data.mediaFlags |= WebContextMenuData::MediaCanPrint; HTMLPlugInElement* pluginElement = toHTMLPlugInElement(r.innerNonSharedNode()); data.srcURL = pluginElement->document().completeURL(pluginElement->url()); data.mediaFlags |= WebContextMenuData::MediaCanSave; // Add context menu commands that are supported by the plugin. if (plugin->plugin()->canRotateView()) data.mediaFlags |= WebContextMenuData::MediaCanRotate; } } } // An image can to be null for many reasons, like being blocked, no image // data received from server yet. data.hasImageContents = (data.mediaType == WebContextMenuData::MediaTypeImage) && r.image() && !(r.image()->isNull()); // If it's not a link, an image, a media element, or an image/media link, // show a selection menu or a more generic page menu. if (selectedFrame->document()->loader()) data.frameEncoding = selectedFrame->document()->encodingName(); // Send the frame and page URLs in any case. data.pageURL = urlFromFrame(m_webView->mainFrameImpl()->frame()); if (selectedFrame != m_webView->mainFrameImpl()->frame()) { data.frameURL = urlFromFrame(selectedFrame); RefPtr<HistoryItem> historyItem = selectedFrame->loader().currentItem(); if (historyItem) data.frameHistoryItem = WebHistoryItem(historyItem); } if (r.isSelected()) { if (!isHTMLInputElement(*r.innerNonSharedNode()) || !toHTMLInputElement(r.innerNonSharedNode())->isPasswordField()) data.selectedText = selectedFrame->selectedText().stripWhiteSpace(); } if (r.isContentEditable()) { data.isEditable = true; // When Chrome enables asynchronous spellchecking, its spellchecker adds spelling markers to misspelled // words and attaches suggestions to these markers in the background. Therefore, when a user right-clicks // a mouse on a word, Chrome just needs to find a spelling marker on the word instead of spellchecking it. if (selectedFrame->settings() && selectedFrame->settings()->asynchronousSpellCheckingEnabled()) { DocumentMarker marker; data.misspelledWord = selectMisspellingAsync(selectedFrame, marker); data.misspellingHash = marker.hash(); if (marker.description().length()) { Vector<String> suggestions; marker.description().split('\n', suggestions); data.dictionarySuggestions = suggestions; } else if (m_webView->spellCheckClient()) { int misspelledOffset, misspelledLength; m_webView->spellCheckClient()->spellCheck(data.misspelledWord, misspelledOffset, misspelledLength, &data.dictionarySuggestions); } } else { data.isSpellCheckingEnabled = toLocalFrame(m_webView->focusedWebCoreFrame())->spellChecker().isContinuousSpellCheckingEnabled(); // Spellchecking might be enabled for the field, but could be disabled on the node. if (toLocalFrame(m_webView->focusedWebCoreFrame())->spellChecker().isSpellCheckingEnabledInFocusedNode()) { data.misspelledWord = selectMisspelledWord(selectedFrame); if (m_webView->spellCheckClient()) { int misspelledOffset, misspelledLength; m_webView->spellCheckClient()->spellCheck( data.misspelledWord, misspelledOffset, misspelledLength, &data.dictionarySuggestions); if (!misspelledLength) data.misspelledWord.reset(); } } } HTMLFormElement* form = selectedFrame->selection().currentForm(); if (form && isHTMLInputElement(*r.innerNonSharedNode())) { HTMLInputElement& selectedElement = toHTMLInputElement(*r.innerNonSharedNode()); WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(&selectedElement)); if (ws.url().isValid()) data.keywordURL = ws.url(); } } if (selectedFrame->editor().selectionHasStyle(CSSPropertyDirection, "ltr") != FalseTriState) data.writingDirectionLeftToRight |= WebContextMenuData::CheckableMenuItemChecked; if (selectedFrame->editor().selectionHasStyle(CSSPropertyDirection, "rtl") != FalseTriState) data.writingDirectionRightToLeft |= WebContextMenuData::CheckableMenuItemChecked; // Now retrieve the security info. DocumentLoader* dl = selectedFrame->loader().documentLoader(); WebDataSource* ds = WebDataSourceImpl::fromDocumentLoader(dl); if (ds) data.securityInfo = ds->response().securityInfo(); data.referrerPolicy = static_cast<WebReferrerPolicy>(selectedFrame->document()->referrerPolicy()); // Filter out custom menu elements and add them into the data. populateCustomMenuItems(defaultMenu, &data); // Extract suggested filename for saving file. if (isHTMLAnchorElement(r.URLElement())) { HTMLAnchorElement* anchor = toHTMLAnchorElement(r.URLElement()); data.suggestedFilename = anchor->fastGetAttribute(HTMLNames::downloadAttr); } data.node = r.innerNonSharedNode(); WebLocalFrameImpl* selectedWebFrame = WebLocalFrameImpl::fromFrame(selectedFrame); if (selectedWebFrame->client()) selectedWebFrame->client()->showContextMenu(data); }
PlatformMenuDescription ContextMenuClientImpl::getCustomMenuFromDefaultItems( ContextMenu* defaultMenu) { // Displaying the context menu in this function is a big hack as we don't // have context, i.e. whether this is being invoked via a script or in // response to user input (Mouse event WM_RBUTTONDOWN, // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked // in response to the above input events before popping up the context menu. if (!m_webView->contextMenuAllowed()) return 0; HitTestResult r = m_webView->page()->contextMenuController()->hitTestResult(); Frame* selectedFrame = r.innerNonSharedNode()->document()->frame(); WebContextMenuData data; data.mousePosition = selectedFrame->view()->contentsToWindow(r.roundedPoint()); // Compute edit flags. data.editFlags = WebContextMenuData::CanDoNone; if (m_webView->focusedWebCoreFrame()->editor()->canUndo()) data.editFlags |= WebContextMenuData::CanUndo; if (m_webView->focusedWebCoreFrame()->editor()->canRedo()) data.editFlags |= WebContextMenuData::CanRedo; if (m_webView->focusedWebCoreFrame()->editor()->canCut()) data.editFlags |= WebContextMenuData::CanCut; if (m_webView->focusedWebCoreFrame()->editor()->canCopy()) data.editFlags |= WebContextMenuData::CanCopy; if (m_webView->focusedWebCoreFrame()->editor()->canPaste()) data.editFlags |= WebContextMenuData::CanPaste; if (m_webView->focusedWebCoreFrame()->editor()->canDelete()) data.editFlags |= WebContextMenuData::CanDelete; // We can always select all... data.editFlags |= WebContextMenuData::CanSelectAll; data.editFlags |= WebContextMenuData::CanTranslate; // Links, Images, Media tags, and Image/Media-Links take preference over // all else. data.linkURL = r.absoluteLinkURL(); if (!r.absoluteImageURL().isEmpty()) { data.srcURL = r.absoluteImageURL(); data.mediaType = WebContextMenuData::MediaTypeImage; } else if (!r.absoluteMediaURL().isEmpty()) { data.srcURL = r.absoluteMediaURL(); // We know that if absoluteMediaURL() is not empty, then this // is a media element. HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(r.innerNonSharedNode()); if (mediaElement->hasTagName(HTMLNames::videoTag)) data.mediaType = WebContextMenuData::MediaTypeVideo; else if (mediaElement->hasTagName(HTMLNames::audioTag)) data.mediaType = WebContextMenuData::MediaTypeAudio; if (mediaElement->error()) data.mediaFlags |= WebContextMenuData::MediaInError; if (mediaElement->paused()) data.mediaFlags |= WebContextMenuData::MediaPaused; if (mediaElement->muted()) data.mediaFlags |= WebContextMenuData::MediaMuted; if (mediaElement->loop()) data.mediaFlags |= WebContextMenuData::MediaLoop; if (mediaElement->supportsSave()) data.mediaFlags |= WebContextMenuData::MediaCanSave; if (mediaElement->hasAudio()) data.mediaFlags |= WebContextMenuData::MediaHasAudio; if (mediaElement->hasVideo()) data.mediaFlags |= WebContextMenuData::MediaHasVideo; if (mediaElement->controls()) data.mediaFlags |= WebContextMenuData::MediaControlRootElement; } else if (r.innerNonSharedNode()->hasTagName(HTMLNames::objectTag) || r.innerNonSharedNode()->hasTagName(HTMLNames::embedTag)) { RenderObject* object = r.innerNonSharedNode()->renderer(); if (object && object->isWidget()) { Widget* widget = toRenderWidget(object)->widget(); if (widget && widget->isPluginContainer()) { data.mediaType = WebContextMenuData::MediaTypePlugin; WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget); WebString text = plugin->plugin()->selectionAsText(); if (!text.isEmpty()) { data.selectedText = text; data.editFlags |= WebContextMenuData::CanCopy; } data.editFlags &= ~WebContextMenuData::CanTranslate; data.linkURL = plugin->plugin()->linkAtPosition(data.mousePosition); if (plugin->plugin()->supportsPaginatedPrint()) data.mediaFlags |= WebContextMenuData::MediaCanPrint; HTMLPlugInImageElement* pluginElement = static_cast<HTMLPlugInImageElement*>(r.innerNonSharedNode()); data.srcURL = pluginElement->document()->completeURL(pluginElement->url()); data.mediaFlags |= WebContextMenuData::MediaCanSave; // Add context menu commands that are supported by the plugin. if (plugin->plugin()->canRotateView()) data.mediaFlags |= WebContextMenuData::MediaCanRotate; } } } data.isImageBlocked = (data.mediaType == WebContextMenuData::MediaTypeImage) && !r.image(); // If it's not a link, an image, a media element, or an image/media link, // show a selection menu or a more generic page menu. if (selectedFrame->document()->loader()) data.frameEncoding = selectedFrame->document()->encoding(); // Send the frame and page URLs in any case. data.pageURL = urlFromFrame(m_webView->mainFrameImpl()->frame()); if (selectedFrame != m_webView->mainFrameImpl()->frame()) { data.frameURL = urlFromFrame(selectedFrame); RefPtr<HistoryItem> historyItem = selectedFrame->loader()->history()->currentItem(); if (historyItem) data.frameHistoryItem = WebHistoryItem(historyItem); } if (r.isSelected()) { if (!r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag) || !static_cast<HTMLInputElement*>(r.innerNonSharedNode())->isPasswordField()) data.selectedText = selectedFrame->editor()->selectedText().stripWhiteSpace(); } if (r.isContentEditable()) { data.isEditable = true; #if ENABLE(INPUT_SPEECH) if (r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag)) { data.isSpeechInputEnabled = static_cast<HTMLInputElement*>(r.innerNonSharedNode())->isSpeechEnabled(); } #endif // When Chrome enables asynchronous spellchecking, its spellchecker adds spelling markers to misspelled // words and attaches suggestions to these markers in the background. Therefore, when a user right-clicks // a mouse on a word, Chrome just needs to find a spelling marker on the word instread of spellchecking it. if (selectedFrame->settings() && selectedFrame->settings()->asynchronousSpellCheckingEnabled()) { VisibleSelection selection = selectedFrame->selection()->selection(); if (selection.isCaret()) { selection.expandUsingGranularity(WordGranularity); RefPtr<Range> range = selection.toNormalizedRange(); Vector<DocumentMarker*> markers = selectedFrame->document()->markers()->markersInRange(range.get(), DocumentMarker::Spelling | DocumentMarker::Grammar); if (markers.size() == 1) { range->setStart(range->startContainer(), markers[0]->startOffset()); range->setEnd(range->endContainer(), markers[0]->endOffset()); data.misspelledWord = range->text(); if (markers[0]->description().length()) { Vector<String> suggestions; markers[0]->description().split('\n', suggestions); data.dictionarySuggestions = suggestions; } else if (m_webView->spellCheckClient()) { int misspelledOffset, misspelledLength; m_webView->spellCheckClient()->spellCheck(data.misspelledWord, misspelledOffset, misspelledLength, &data.dictionarySuggestions); } selection = VisibleSelection(range.get()); if (selectedFrame->selection()->shouldChangeSelection(selection)) selectedFrame->selection()->setSelection(selection, WordGranularity); } } } else if (m_webView->focusedWebCoreFrame()->editor()->isContinuousSpellCheckingEnabled()) { data.isSpellCheckingEnabled = true; // Spellchecking might be enabled for the field, but could be disabled on the node. if (m_webView->focusedWebCoreFrame()->editor()->isSpellCheckingEnabledInFocusedNode()) { data.misspelledWord = selectMisspelledWord(defaultMenu, selectedFrame); if (m_webView->spellCheckClient()) { int misspelledOffset, misspelledLength; m_webView->spellCheckClient()->spellCheck( data.misspelledWord, misspelledOffset, misspelledLength, &data.dictionarySuggestions); if (!misspelledLength) data.misspelledWord.reset(); } } } HTMLFormElement* form = selectedFrame->selection()->currentForm(); if (form && form->checkValidity() && r.innerNonSharedNode()->hasTagName(HTMLNames::inputTag)) { HTMLInputElement* selectedElement = static_cast<HTMLInputElement*>(r.innerNonSharedNode()); if (selectedElement) { WebSearchableFormData ws = WebSearchableFormData(WebFormElement(form), WebInputElement(selectedElement)); if (ws.url().isValid()) data.keywordURL = ws.url(); } } } #if OS(DARWIN) if (selectedFrame->editor()->selectionHasStyle(CSSPropertyDirection, "ltr") != FalseTriState) data.writingDirectionLeftToRight |= WebContextMenuData::CheckableMenuItemChecked; if (selectedFrame->editor()->selectionHasStyle(CSSPropertyDirection, "rtl") != FalseTriState) data.writingDirectionRightToLeft |= WebContextMenuData::CheckableMenuItemChecked; #endif // OS(DARWIN) // Now retrieve the security info. DocumentLoader* dl = selectedFrame->loader()->documentLoader(); WebDataSource* ds = WebDataSourceImpl::fromDocumentLoader(dl); if (ds) data.securityInfo = ds->response().securityInfo(); data.referrerPolicy = static_cast<WebReferrerPolicy>(selectedFrame->document()->referrerPolicy()); // Filter out custom menu elements and add them into the data. populateCustomMenuItems(defaultMenu, &data); data.node = r.innerNonSharedNode(); WebFrame* selected_web_frame = WebFrameImpl::fromFrame(selectedFrame); if (m_webView->client()) m_webView->client()->showContextMenu(selected_web_frame, data); return 0; }
PlatformMenuDescription ContextMenuClientImpl::getCustomMenuFromDefaultItems( ContextMenu* defaultMenu) { // Displaying the context menu in this function is a big hack as we don't // have context, i.e. whether this is being invoked via a script or in // response to user input (Mouse event WM_RBUTTONDOWN, // Keyboard events KeyVK_APPS, Shift+F10). Check if this is being invoked // in response to the above input events before popping up the context menu. if (!m_webView->contextMenuAllowed()) return 0; HitTestResult r = defaultMenu->hitTestResult(); Frame* selectedFrame = r.innerNonSharedNode()->document()->frame(); WebContextMenuData data; data.mousePosition = selectedFrame->view()->contentsToWindow(r.point()); // Compute edit flags. data.editFlags = WebContextMenuData::CanDoNone; if (m_webView->focusedWebCoreFrame()->editor()->canUndo()) data.editFlags |= WebContextMenuData::CanUndo; if (m_webView->focusedWebCoreFrame()->editor()->canRedo()) data.editFlags |= WebContextMenuData::CanRedo; if (m_webView->focusedWebCoreFrame()->editor()->canCut()) data.editFlags |= WebContextMenuData::CanCut; if (m_webView->focusedWebCoreFrame()->editor()->canCopy()) data.editFlags |= WebContextMenuData::CanCopy; if (m_webView->focusedWebCoreFrame()->editor()->canPaste()) data.editFlags |= WebContextMenuData::CanPaste; if (m_webView->focusedWebCoreFrame()->editor()->canDelete()) data.editFlags |= WebContextMenuData::CanDelete; // We can always select all... data.editFlags |= WebContextMenuData::CanSelectAll; data.editFlags |= WebContextMenuData::CanTranslate; // Links, Images, Media tags, and Image/Media-Links take preference over // all else. data.linkURL = r.absoluteLinkURL(); if (!r.absoluteImageURL().isEmpty()) { data.srcURL = r.absoluteImageURL(); data.mediaType = WebContextMenuData::MediaTypeImage; } else if (!r.absoluteMediaURL().isEmpty()) { data.srcURL = r.absoluteMediaURL(); // We know that if absoluteMediaURL() is not empty, then this // is a media element. HTMLMediaElement* mediaElement = static_cast<HTMLMediaElement*>(r.innerNonSharedNode()); if (mediaElement->hasTagName(HTMLNames::videoTag)) data.mediaType = WebContextMenuData::MediaTypeVideo; else if (mediaElement->hasTagName(HTMLNames::audioTag)) data.mediaType = WebContextMenuData::MediaTypeAudio; if (mediaElement->error()) data.mediaFlags |= WebContextMenuData::MediaInError; if (mediaElement->paused()) data.mediaFlags |= WebContextMenuData::MediaPaused; if (mediaElement->muted()) data.mediaFlags |= WebContextMenuData::MediaMuted; if (mediaElement->loop()) data.mediaFlags |= WebContextMenuData::MediaLoop; if (mediaElement->supportsSave()) data.mediaFlags |= WebContextMenuData::MediaCanSave; if (mediaElement->hasAudio()) data.mediaFlags |= WebContextMenuData::MediaHasAudio; if (mediaElement->hasVideo()) data.mediaFlags |= WebContextMenuData::MediaHasVideo; if (mediaElement->controls()) data.mediaFlags |= WebContextMenuData::MediaControls; } else if (r.innerNonSharedNode()->hasTagName(HTMLNames::objectTag) || r.innerNonSharedNode()->hasTagName(HTMLNames::embedTag)) { RenderObject* object = r.innerNonSharedNode()->renderer(); if (object && object->isWidget()) { Widget* widget = toRenderWidget(object)->widget(); if (widget && widget->isPluginContainer()) { WebPluginContainerImpl* plugin = static_cast<WebPluginContainerImpl*>(widget); WebString text = plugin->plugin()->selectionAsText(); if (!text.isEmpty()) { data.selectedText = text; data.editFlags |= WebContextMenuData::CanCopy; } data.editFlags &= ~WebContextMenuData::CanTranslate; data.linkURL = plugin->plugin()->linkAtPosition(data.mousePosition); } } } data.isImageBlocked = (data.mediaType == WebContextMenuData::MediaTypeImage) && !r.image(); // If it's not a link, an image, a media element, or an image/media link, // show a selection menu or a more generic page menu. data.frameEncoding = selectedFrame->loader()->writer()->encoding(); // Send the frame and page URLs in any case. data.pageURL = urlFromFrame(m_webView->mainFrameImpl()->frame()); if (selectedFrame != m_webView->mainFrameImpl()->frame()) data.frameURL = urlFromFrame(selectedFrame); if (r.isSelected()) data.selectedText = selectedFrame->editor()->selectedText().stripWhiteSpace(); if (r.isContentEditable()) { data.isEditable = true; if (m_webView->focusedWebCoreFrame()->editor()->isContinuousSpellCheckingEnabled()) { data.isSpellCheckingEnabled = true; // Spellchecking might be enabled for the field, but could be disabled on the node. if (m_webView->focusedWebCoreFrame()->editor()->spellCheckingEnabledInFocusedNode()) data.misspelledWord = selectMisspelledWord(defaultMenu, selectedFrame); } } #if OS(DARWIN) ExceptionCode ec = 0; RefPtr<CSSStyleDeclaration> style = selectedFrame->document()->createCSSStyleDeclaration(); style->setProperty(CSSPropertyDirection, "ltr", false, ec); if (selectedFrame->editor()->selectionHasStyle(style.get()) != FalseTriState) data.writingDirectionLeftToRight |= WebContextMenuData::CheckableMenuItemChecked; style->setProperty(CSSPropertyDirection, "rtl", false, ec); if (selectedFrame->editor()->selectionHasStyle(style.get()) != FalseTriState) data.writingDirectionRightToLeft |= WebContextMenuData::CheckableMenuItemChecked; #endif // OS(DARWIN) // Now retrieve the security info. DocumentLoader* dl = selectedFrame->loader()->documentLoader(); WebDataSource* ds = WebDataSourceImpl::fromDocumentLoader(dl); if (ds) data.securityInfo = ds->response().securityInfo(); // Filter out custom menu elements and add them into the data. populateCustomMenuItems(defaultMenu, &data); WebFrame* selected_web_frame = WebFrameImpl::fromFrame(selectedFrame); if (m_webView->client()) m_webView->client()->showContextMenu(selected_web_frame, data); return 0; }