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; }
bool DragController::startDrag(Frame* src, Clipboard* clipboard, DragOperation srcOp, const PlatformMouseEvent& dragEvent, const IntPoint& dragOrigin, bool isDHTMLDrag) { ASSERT(src); ASSERT(clipboard); if (!src->view() || !src->contentRenderer()) 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_sourceDragOperation = srcOp; DragImageRef dragImage = 0; IntPoint dragLoc(0, 0); IntPoint dragImageOffset(0, 0); if (isDHTMLDrag) dragImage = clipboard->createDragImage(dragImageOffset); else { // This drag operation is not a DHTML drag and may go outside the WebView. // We provide 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 = (DragOperation)(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 = dragSource.innerNonSharedNode(); Image* image = getImage(static_cast<Element*>(node)); if (!imageURL.isEmpty() && node && node->isElementNode() && image && (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, 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); 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 = 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->selection()->toNormalizedRange(); 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; }