ScrollbarPart ScrollbarThemeQt::hitTest(Scrollbar* scrollbar, const PlatformMouseEvent& evt) { QStyleOptionSlider* opt = styleOptionSlider(scrollbar); const QPoint pos = scrollbar->convertFromContainingWindow(evt.pos()); opt->rect.moveTo(QPoint(0, 0)); QStyle::SubControl sc = style()->hitTestComplexControl(QStyle::CC_ScrollBar, opt, pos, 0); return scrollbarPart(sc); }
bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& e) { if (!parent()) return true; // TODO(pkasting): http://b/583875 Right-click should invoke a context menu // (maybe this would be better handled elsewhere?) if (!m_enabled || (e.button() != LeftButton)) { return true; } ASSERT(m_captureStart == None); IntPoint pos = convertFromContainingWindow(e.pos()); const bool horz = (orientation() == HorizontalScrollbar); updateMousePosition(pos.x(), pos.y()); switch (m_mouseOver) { case Arrow1: scroll(horz ? ScrollLeft : ScrollUp, ScrollByLine); break; case Track: return true; case BeforeThumb: scroll(horz ? ScrollLeft : ScrollUp, ScrollByPage); break; case Thumb: m_dragOrigin.thumbPos = horz ? pos.x() : pos.y(); m_dragOrigin.scrollVal = value(); break; case AfterThumb: scroll(horz ? ScrollRight : ScrollDown, ScrollByPage); break; case Arrow2: scroll(horz ? ScrollRight : ScrollDown, ScrollByLine); break; default: ASSERT_NOT_REACHED(); } setCapturingMouse(true); // Kick off auto-repeat timer if (m_mouseOver != Thumb) m_autorepeatTimer.start(kAutorepeatInitialDelay, kAutorepeatRepeatInterval); m_needsLayout = true; // FIXME: Invalidate only the portions that actually changed invalidate(); return true; }
void PlatformScrollbar::handleMouseMoveEventWhenCapturing(const PlatformMouseEvent& e) { IntPoint pos = convertFromContainingWindow(e.pos()); updateMousePosition(pos.x(), pos.y()); if (m_captureStart != Thumb) { // FIXME: Invalidate only the portions that actually changed invalidate(); return; } int xCancelDistance, yCancelDistance, backgroundSpan, thumbGirth, delta; // NOTE: The cancel distance calculations are based on the behavior of the // MSVC8 main window scrollbar + some guessing/extrapolation if (orientation() == HorizontalScrollbar) { xCancelDistance = kOffEndMultiplier * horizontalScrollbarHeight(); yCancelDistance = kOffSideMultiplier * horizontalScrollbarHeight(); backgroundSpan = m_segmentRects[AfterThumb].right() - m_segmentRects[BeforeThumb].x(); thumbGirth = m_segmentRects[Thumb].right() - m_segmentRects[Thumb].x(); delta = pos.x() - m_dragOrigin.thumbPos; } else { xCancelDistance = kOffSideMultiplier * verticalScrollbarWidth(); yCancelDistance = kOffEndMultiplier * verticalScrollbarWidth(); backgroundSpan = m_segmentRects[AfterThumb].bottom() - m_segmentRects[BeforeThumb].y(); thumbGirth = m_segmentRects[Thumb].bottom() - m_segmentRects[Thumb].y(); delta = pos.y() - m_dragOrigin.thumbPos; } // Snap scrollbar back to drag origin if mouse gets too far away if ((m_lastNativePos.x() < (m_segmentRects[BeforeThumb].x() - xCancelDistance)) || (m_lastNativePos.x() > (m_segmentRects[AfterThumb].right() + xCancelDistance)) || (m_lastNativePos.y() < (m_segmentRects[BeforeThumb].y() - yCancelDistance)) || (m_lastNativePos.y() > (m_segmentRects[AfterThumb].bottom() + yCancelDistance))) delta = 0; // Convert delta from pixel coords to scrollbar logical coords if (backgroundSpan > thumbGirth) { if (setValue(m_dragOrigin.scrollVal + (delta * (m_totalSize - m_visibleSize) / (backgroundSpan - thumbGirth)))) { m_needsLayout = true; // FIXME: Invalidate only the portions that actually changed invalidate(); } } }
bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& _mouse, const AtomicString& eventType, int detail, Node* relatedTarget) { assert(!eventDispatchForbidden()); IntPoint contentsPos; if (FrameView* view = document()->view()) contentsPos = view->viewportToContents(_mouse.pos()); return dispatchMouseEvent(eventType, _mouse.button(), detail, contentsPos.x(), contentsPos.y(), _mouse.globalX(), _mouse.globalY(), _mouse.ctrlKey(), _mouse.altKey(), _mouse.shiftKey(), _mouse.metaKey(), false, relatedTarget); }
bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& e) { ScrollView* parentView = parent(); if (!parentView) return true; IntPoint pos = convertFromContainingWindow(e.pos()); updateMousePosition(pos.x(), pos.y()); setCapturingMouse(false); // FIXME: Invalidate only the portions that actually changed invalidate(); return true; }
bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& e) { if (!parent()) return true; if (m_captureStart != None) { handleMouseMoveEventWhenCapturing(e); return true; } IntPoint pos = convertFromContainingWindow(e.pos()); updateMousePosition(pos.x(), pos.y()); // FIXME: Invalidate only the portions that actually changed invalidate(); return true; }
bool ScrollbarThemeWin::shouldSnapBackToDragOrigin(Scrollbar* scrollbar, const PlatformMouseEvent& evt) { // Find the rect within which we shouldn't snap, by expanding the track rect // in both dimensions. IntRect rect = trackRect(scrollbar); const bool horz = scrollbar->orientation() == HorizontalScrollbar; const int thickness = scrollbarThickness(scrollbar->controlSize()); rect.inflateX((horz ? kOffEndMultiplier : kOffSideMultiplier) * thickness); rect.inflateY((horz ? kOffSideMultiplier : kOffEndMultiplier) * thickness); // Convert the event to local coordinates. IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos()); mousePosition.move(scrollbar->x(), scrollbar->y()); // We should snap iff the event is outside our calculated rect. return !rect.contains(mousePosition); }
bool EventTargetNode::dispatchMouseEvent(const PlatformMouseEvent& event, const AtomicString& eventType, int detail, Node* relatedTarget) { ASSERT(!eventDispatchForbidden()); IntPoint contentsPos; if (FrameView* view = document()->view()) contentsPos = view->windowToContents(event.pos()); short button = event.button(); ASSERT(event.eventType() == MouseEventMoved || button != NoButton); return dispatchMouseEvent(eventType, button, detail, contentsPos.x(), contentsPos.y(), event.globalX(), event.globalY(), event.ctrlKey(), event.altKey(), event.shiftKey(), event.metaKey(), false, relatedTarget); }
bool PlatformScrollbar::handleMouseReleaseEvent(const PlatformMouseEvent& evt) { const QPoint pos = convertFromContainingWindow(evt.pos()); const QPoint topLeft = m_opt.rect.topLeft(); m_opt.rect.moveTo(QPoint(0, 0)); QStyle::SubControl scAtMousePoint = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, &m_opt, pos, 0); m_opt.rect.moveTo(topLeft); m_hoveredPart = scAtMousePoint; if (m_hoveredPart == QStyle::SC_None) m_opt.state &= ~QStyle::State_MouseOver; m_opt.state &= ~QStyle::State_Sunken; m_pressedPart = QStyle::SC_None; m_pressedPos = 0; stopTimerIfNeeded(); invalidate(); return true; }
bool PlatformScrollbar::handleContextMenuEvent(const PlatformMouseEvent& event) { #ifndef QT_NO_CONTEXTMENU bool horizontal = (m_orientation == HorizontalScrollbar); QMenu menu; QAction* actScrollHere = menu.addAction(tr("Scroll here")); menu.addSeparator(); QAction* actScrollTop = menu.addAction(horizontal ? tr("Left edge") : tr("Top")); QAction* actScrollBottom = menu.addAction(horizontal ? tr("Right edge") : tr("Bottom")); menu.addSeparator(); QAction* actPageUp = menu.addAction(horizontal ? tr("Page left") : tr("Page up")); QAction* actPageDown = menu.addAction(horizontal ? tr("Page right") : tr("Page down")); menu.addSeparator(); QAction* actScrollUp = menu.addAction(horizontal ? tr("Scroll left") : tr("Scroll up")); QAction* actScrollDown = menu.addAction(horizontal ? tr("Scroll right") : tr("Scroll down")); const QPoint globalPos = QPoint(event.globalX(), event.globalY()); QAction* actionSelected = menu.exec(globalPos); if (actionSelected == 0) /* Do nothing */ ; else if (actionSelected == actScrollHere) { const QPoint pos = convertFromContainingWindow(event.pos()); setValue(pixelPosToRangeValue(horizontal ? pos.x() : pos.y())); } else if (actionSelected == actScrollTop) setValue(0); else if (actionSelected == actScrollBottom) setValue(m_totalSize - m_visibleSize); else if (actionSelected == actPageUp) scroll(horizontal ? ScrollLeft: ScrollUp, ScrollByPage, 1); else if (actionSelected == actPageDown) scroll(horizontal ? ScrollRight : ScrollDown, ScrollByPage, 1); else if (actionSelected == actScrollUp) scroll(horizontal ? ScrollLeft : ScrollUp, ScrollByLine, 1); else if (actionSelected == actScrollDown) scroll(horizontal ? ScrollRight : ScrollDown, ScrollByLine, 1); #endif // QT_NO_CONTEXTMENU return true; }
bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt) { // Early exit for right click if (evt.button() == RightButton) return true; // Handled as context menu const QPoint pos = convertFromContainingWindow(evt.pos()); bool midButtonAbsPos = QApplication::style()->styleHint(QStyle::SH_ScrollBar_MiddleClickAbsolutePosition); // Middle click centers slider thumb, if supported if (midButtonAbsPos && evt.button() == MiddleButton) { setValue(pixelPosToRangeValue((m_orientation == HorizontalScrollbar ? pos.x() : pos.y()) - thumbLength() / 2)); } else { // Left button, or if middle click centering is not supported const QPoint topLeft = m_opt.rect.topLeft(); m_opt.rect.moveTo(QPoint(0, 0)); QStyle::SubControl sc = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, &m_opt, pos, 0); m_opt.rect.moveTo(topLeft); switch (sc) { case QStyle::SC_ScrollBarAddLine: case QStyle::SC_ScrollBarSubLine: case QStyle::SC_ScrollBarSlider: m_opt.state |= QStyle::State_Sunken; case QStyle::SC_ScrollBarAddPage: case QStyle::SC_ScrollBarSubPage: case QStyle::SC_ScrollBarGroove: m_pressedPart = sc; break; default: m_pressedPart = QStyle::SC_None; return false; } m_pressedPos = m_orientation == HorizontalScrollbar ? pos.x() : pos.y(); autoscrollPressedPart(cInitialTimerDelay); invalidate(); } return true; }
ScrollbarPart ScrollbarThemeComposite::hitTest(Scrollbar* scrollbar, const PlatformMouseEvent& evt) { ScrollbarPart result = NoPart; if (!scrollbar->enabled()) return result; IntPoint mousePosition = scrollbar->convertFromContainingWindow(evt.pos()); mousePosition.move(scrollbar->x(), scrollbar->y()); if (!scrollbar->frameRect().contains(mousePosition)) return NoPart; result = ScrollbarBGPart; IntRect track = trackRect(scrollbar); if (track.contains(mousePosition)) { IntRect beforeThumbRect; IntRect thumbRect; IntRect afterThumbRect; splitTrack(scrollbar, track, beforeThumbRect, thumbRect, afterThumbRect); if (thumbRect.contains(mousePosition)) result = ThumbPart; else if (beforeThumbRect.contains(mousePosition)) result = BackTrackPart; else if (afterThumbRect.contains(mousePosition)) result = ForwardTrackPart; else result = TrackBGPart; } else if (backButtonRect(scrollbar, BackButtonStartPart).contains(mousePosition)) result = BackButtonStartPart; else if (backButtonRect(scrollbar, BackButtonEndPart).contains(mousePosition)) result = BackButtonEndPart; else if (forwardButtonRect(scrollbar, ForwardButtonStartPart).contains(mousePosition)) result = ForwardButtonStartPart; else if (forwardButtonRect(scrollbar, ForwardButtonEndPart).contains(mousePosition)) result = ForwardButtonEndPart; return result; }
bool Scrollbar::mouseMoved(const PlatformMouseEvent& evt) { if (m_pressedPart == ThumbPart) { if (theme()->shouldSnapBackToDragOrigin(this, evt)) { if (m_scrollableArea) m_scrollableArea->scrollToOffsetWithoutAnimation(m_orientation, m_dragOrigin); } else { moveThumb(m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y(), theme()->shouldDragDocumentInsteadOfThumb(this, evt)); } return true; } if (m_pressedPart != NoPart) m_pressedPos = (orientation() == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y()); ScrollbarPart part = theme()->hitTest(this, evt); if (part != m_hoveredPart) { if (m_pressedPart != NoPart) { if (part == m_pressedPart) { // The mouse is moving back over the pressed part. We // need to start up the timer action again. startTimerIfNeeded(theme()->autoscrollTimerDelay()); theme()->invalidatePart(this, m_pressedPart); } else if (m_hoveredPart == m_pressedPart) { // The mouse is leaving the pressed part. Kill our timer // if needed. stopTimerIfNeeded(); theme()->invalidatePart(this, m_pressedPart); } } setHoveredPart(part); } return true; }
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; }
bool PlatformScrollbar::handleMousePressEvent(const PlatformMouseEvent& evt) { m_pressedPart = hitTest(evt); m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y()); invalidatePart(m_pressedPart); autoscrollPressedPart(cInitialTimerDelay); return true; }
bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt) { if (m_pressedPart == ThumbPart) { // Drag the thumb. int thumbPos = thumbPosition(); int thumbLen = thumbLength(); int trackLen = trackLength(); int maxPos = trackLen - thumbLen; int delta = 0; if (m_orientation == HorizontalScrollbar) delta = convertFromContainingWindow(evt.pos()).x() - m_pressedPos; else delta = convertFromContainingWindow(evt.pos()).y() - m_pressedPos; if (delta > 0) // The mouse moved down/right. delta = min(maxPos - thumbPos, delta); else if (delta < 0) // The mouse moved up/left. delta = max(-thumbPos, delta); if (delta != 0) { setValue(static_cast<int>((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen))); m_pressedPos += thumbPosition() - thumbPos; } return true; } if (m_pressedPart != NoPart) m_pressedPos = (m_orientation == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y()); ScrollbarPart part = hitTest(evt); if (part != m_hoveredPart) { if (m_pressedPart != NoPart) { if (part == m_pressedPart) { // The mouse is moving back over the pressed part. We // need to start up the timer action again. startTimerIfNeeded(cNormalTimerDelay); invalidatePart(m_pressedPart); } else if (m_hoveredPart == m_pressedPart) { // The mouse is leaving the pressed part. Kill our timer // if needed. stopTimerIfNeeded(); invalidatePart(m_pressedPart); } } else { invalidatePart(part); invalidatePart(m_hoveredPart); } m_hoveredPart = part; } updateViewOnMouseHover(); return true; }
bool PlatformScrollbar::handleMouseMoveEvent(const PlatformMouseEvent& evt) { const QPoint pos = convertFromContainingWindow(evt.pos()); //qDebug() << "PlatformScrollbar::handleMouseMoveEvent" << m_opt.rect << pos << evt.pos(); m_opt.state |= QStyle::State_MouseOver; const QPoint topLeft = m_opt.rect.topLeft(); m_opt.rect.moveTo(QPoint(0, 0)); QStyle::SubControl sc = QApplication::style()->hitTestComplexControl(QStyle::CC_ScrollBar, &m_opt, pos, 0); m_opt.rect.moveTo(topLeft); if (m_pressedPart == QStyle::SC_ScrollBarSlider) { // Drag the thumb. int thumbPos = thumbPosition(); int thumbLen = thumbLength(); int trackLen = trackLength(); int maxPos = trackLen - thumbLen; int delta = 0; if (m_orientation == HorizontalScrollbar) delta = pos.x() - m_pressedPos; else delta = pos.y() - m_pressedPos; if (delta > 0) // The mouse moved down/right. delta = min(maxPos - thumbPos, delta); else if (delta < 0) // The mouse moved up/left. delta = max(-thumbPos, delta); if (delta != 0) { setValue((int)((float)(thumbPos + delta) * (m_totalSize - m_visibleSize) / (trackLen - thumbLen))); m_pressedPos += thumbPosition() - thumbPos; } return true; } if (m_pressedPart != QStyle::SC_None) m_pressedPos = m_orientation == HorizontalScrollbar ? pos.x() : pos.y(); if (sc != m_hoveredPart) { if (m_pressedPart != QStyle::SC_None) { if (sc == m_pressedPart) { // The mouse is moving back over the pressed part. We // need to start up the timer action again. startTimerIfNeeded(cNormalTimerDelay); invalidate(); } else if (m_hoveredPart == m_pressedPart) { // The mouse is leaving the pressed part. Kill our timer // if needed. stopTimerIfNeeded(); invalidate(); } } else { invalidate(); } m_hoveredPart = sc; } return true; }
bool Scrollbar::mouseDown(const PlatformMouseEvent& evt) { // Early exit for right click if (evt.button() == RightButton) return true; // FIXME: Handled as context menu by Qt right now. Should just avoid even calling this method on a right click though. setPressedPart(theme()->hitTest(this, evt)); int pressedPos = (orientation() == HorizontalScrollbar ? convertFromContainingWindow(evt.pos()).x() : convertFromContainingWindow(evt.pos()).y()); if ((m_pressedPart == BackTrackPart || m_pressedPart == ForwardTrackPart) && theme()->shouldCenterOnThumb(this, evt)) { setHoveredPart(ThumbPart); setPressedPart(ThumbPart); m_dragOrigin = m_currentPos; int thumbLen = theme()->thumbLength(this); int desiredPos = pressedPos; // Set the pressed position to the middle of the thumb so that when we do the move, the delta // will be from the current pixel position of the thumb to the new desired position for the thumb. m_pressedPos = theme()->trackPosition(this) + theme()->thumbPosition(this) + thumbLen / 2; moveThumb(desiredPos); return true; } else if (m_pressedPart == ThumbPart) m_dragOrigin = m_currentPos; m_pressedPos = pressedPos; autoscrollPressedPart(theme()->initialAutoscrollTimerDelay()); return true; }
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; }