1/* 2 * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Library General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Library General Public License for more details. 13 * 14 * You should have received a copy of the GNU Library General Public License 15 * along with this program; see the file COPYING.LIB. If not, write to 16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 17 * Boston, MA 02110-1301, USA. 18 * 19 */ 20 21#include "config.h" 22#include "QtWebPageEventHandler.h" 23 24#include "NativeWebKeyboardEvent.h" 25#include "NativeWebMouseEvent.h" 26#include "NativeWebWheelEvent.h" 27#include "PageViewportControllerClientQt.h" 28#include "WebPageProxy.h" 29#include "qquickwebpage_p.h" 30#include "qquickwebview_p.h" 31#include <QCursor> 32#include <QDrag> 33#include <QGuiApplication> 34#include <QInputEvent> 35#include <QInputMethod> 36#include <QMimeData> 37#include <QMouseEvent> 38#include <QQuickWindow> 39#include <QStyleHints> 40#include <QTextFormat> 41#include <QTouchEvent> 42#include <QTransform> 43#include <WebCore/DragData.h> 44#include <WebCore/Editor.h> 45 46using namespace WebCore; 47 48namespace WebKit { 49 50static inline Qt::DropAction dragOperationToDropAction(unsigned dragOperation) 51{ 52 Qt::DropAction result = Qt::IgnoreAction; 53 if (dragOperation & DragOperationCopy) 54 result = Qt::CopyAction; 55 else if (dragOperation & DragOperationMove) 56 result = Qt::MoveAction; 57 else if (dragOperation & DragOperationGeneric) 58 result = Qt::MoveAction; 59 else if (dragOperation & DragOperationLink) 60 result = Qt::LinkAction; 61 return result; 62} 63 64static inline Qt::DropActions dragOperationToDropActions(unsigned dragOperations) 65{ 66 Qt::DropActions result = Qt::IgnoreAction; 67 if (dragOperations & DragOperationCopy) 68 result |= Qt::CopyAction; 69 if (dragOperations & DragOperationMove) 70 result |= Qt::MoveAction; 71 if (dragOperations & DragOperationGeneric) 72 result |= Qt::MoveAction; 73 if (dragOperations & DragOperationLink) 74 result |= Qt::LinkAction; 75 return result; 76} 77 78static inline WebCore::DragOperation dropActionToDragOperation(Qt::DropActions actions) 79{ 80 unsigned result = 0; 81 if (actions & Qt::CopyAction) 82 result |= DragOperationCopy; 83 if (actions & Qt::MoveAction) 84 result |= (DragOperationMove | DragOperationGeneric); 85 if (actions & Qt::LinkAction) 86 result |= DragOperationLink; 87 if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink)) 88 result = DragOperationEvery; 89 return (DragOperation)result; 90} 91 92QtWebPageEventHandler::QtWebPageEventHandler(WKPageRef pageRef, QQuickWebPage* qmlWebPage, QQuickWebView* qmlWebView) 93 : m_webPageProxy(toImpl(pageRef)) 94 , m_viewportController(0) 95 , m_panGestureRecognizer(this) 96 , m_pinchGestureRecognizer(this) 97 , m_tapGestureRecognizer(this) 98 , m_webPage(qmlWebPage) 99 , m_webView(qmlWebView) 100 , m_previousClickButton(Qt::NoButton) 101 , m_clickCount(0) 102 , m_postponeTextInputStateChanged(false) 103 , m_isTapHighlightActive(false) 104 , m_isMouseButtonPressed(false) 105{ 106 connect(qApp->inputMethod(), SIGNAL(visibleChanged()), this, SLOT(inputPanelVisibleChanged())); 107} 108 109QtWebPageEventHandler::~QtWebPageEventHandler() 110{ 111 disconnect(qApp->inputMethod(), SIGNAL(visibleChanged()), this, SLOT(inputPanelVisibleChanged())); 112} 113 114void QtWebPageEventHandler::handleMouseMoveEvent(QMouseEvent* ev) 115{ 116 // For some reason mouse press results in mouse hover (which is 117 // converted to mouse move for WebKit). We ignore these hover 118 // events by comparing lastPos with newPos. 119 // NOTE: lastPos from the event always comes empty, so we work 120 // around that here. 121 static QPointF lastPos = QPointF(); 122 QTransform fromItemTransform = m_webPage->transformFromItem(); 123 QPointF webPagePoint = fromItemTransform.map(ev->localPos()); 124 ev->accept(); 125 if (lastPos == webPagePoint) 126 return; 127 lastPos = webPagePoint; 128 129 m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, fromItemTransform, /*eventClickCount*/ 0)); 130} 131 132void QtWebPageEventHandler::handleMousePressEvent(QMouseEvent* ev) 133{ 134 QTransform fromItemTransform = m_webPage->transformFromItem(); 135 QPointF webPagePoint = fromItemTransform.map(ev->localPos()); 136 137 if (m_clickTimer.isActive() 138 && m_previousClickButton == ev->button() 139 && (webPagePoint - m_lastClick).manhattanLength() < qApp->styleHints()->startDragDistance()) { 140 m_clickCount++; 141 } else { 142 m_clickCount = 1; 143 m_previousClickButton = ev->button(); 144 } 145 146 ev->accept(); 147 m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, fromItemTransform, m_clickCount)); 148 149 m_lastClick = webPagePoint; 150 m_clickTimer.start(qApp->styleHints()->mouseDoubleClickInterval(), this); 151} 152 153void QtWebPageEventHandler::handleMouseReleaseEvent(QMouseEvent* ev) 154{ 155 ev->accept(); 156 QTransform fromItemTransform = m_webPage->transformFromItem(); 157 m_webPageProxy->handleMouseEvent(NativeWebMouseEvent(ev, fromItemTransform, /*eventClickCount*/ 0)); 158} 159 160void QtWebPageEventHandler::handleWheelEvent(QWheelEvent* ev) 161{ 162 QTransform fromItemTransform = m_webPage->transformFromItem(); 163 m_webPageProxy->handleWheelEvent(NativeWebWheelEvent(ev, fromItemTransform)); 164} 165 166void QtWebPageEventHandler::handleHoverLeaveEvent(QHoverEvent* ev) 167{ 168 // To get the correct behavior of mouseout, we need to turn the Leave event of our webview into a mouse move 169 // to a very far region. 170 QHoverEvent fakeEvent(QEvent::HoverMove, QPoint(INT_MIN, INT_MIN), ev->oldPosF()); 171 fakeEvent.setTimestamp(ev->timestamp()); 172 // This will apply the transform on the event. 173 handleHoverMoveEvent(&fakeEvent); 174} 175 176void QtWebPageEventHandler::handleHoverMoveEvent(QHoverEvent* ev) 177{ 178 QMouseEvent me(QEvent::MouseMove, ev->posF(), Qt::NoButton, Qt::NoButton, Qt::NoModifier); 179 me.setAccepted(ev->isAccepted()); 180 me.setTimestamp(ev->timestamp()); 181 // This will apply the transform on the event. 182 handleMouseMoveEvent(&me); 183} 184 185void QtWebPageEventHandler::handleDragEnterEvent(QDragEnterEvent* ev) 186{ 187 m_webPageProxy->resetDragOperation(); 188 QTransform fromItemTransform = m_webPage->transformFromItem(); 189 // FIXME: Should not use QCursor::pos() 190 DragData dragData(ev->mimeData(), fromItemTransform.map(ev->pos()), QCursor::pos(), dropActionToDragOperation(ev->possibleActions())); 191 m_webPageProxy->dragEntered(&dragData); 192 ev->acceptProposedAction(); 193} 194 195void QtWebPageEventHandler::handleDragLeaveEvent(QDragLeaveEvent* ev) 196{ 197 bool accepted = ev->isAccepted(); 198 199 // FIXME: Should not use QCursor::pos() 200 DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone); 201 m_webPageProxy->dragExited(&dragData); 202 m_webPageProxy->resetDragOperation(); 203 204 ev->setAccepted(accepted); 205} 206 207void QtWebPageEventHandler::handleDragMoveEvent(QDragMoveEvent* ev) 208{ 209 bool accepted = ev->isAccepted(); 210 211 QTransform fromItemTransform = m_webPage->transformFromItem(); 212 // FIXME: Should not use QCursor::pos() 213 DragData dragData(ev->mimeData(), fromItemTransform.map(ev->pos()), QCursor::pos(), dropActionToDragOperation(ev->possibleActions())); 214 m_webPageProxy->dragUpdated(&dragData); 215 ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation)); 216 if (m_webPageProxy->dragSession().operation != DragOperationNone) 217 ev->accept(); 218 219 ev->setAccepted(accepted); 220} 221 222void QtWebPageEventHandler::handleDropEvent(QDropEvent* ev) 223{ 224 bool accepted = ev->isAccepted(); 225 QTransform fromItemTransform = m_webPage->transformFromItem(); 226 // FIXME: Should not use QCursor::pos() 227 DragData dragData(ev->mimeData(), fromItemTransform.map(ev->pos()), QCursor::pos(), dropActionToDragOperation(ev->possibleActions())); 228 SandboxExtension::Handle handle; 229 SandboxExtension::HandleArray sandboxExtensionForUpload; 230 m_webPageProxy->performDrag(&dragData, String(), handle, sandboxExtensionForUpload); 231 ev->setDropAction(dragOperationToDropAction(m_webPageProxy->dragSession().operation)); 232 ev->accept(); 233 234 ev->setAccepted(accepted); 235} 236 237void QtWebPageEventHandler::activateTapHighlight(const QTouchEvent::TouchPoint& point) 238{ 239#if ENABLE(TOUCH_EVENTS) 240 ASSERT(!point.pos().toPoint().isNull()); 241 ASSERT(!m_isTapHighlightActive); 242 m_isTapHighlightActive = true; 243 QTransform fromItemTransform = m_webPage->transformFromItem(); 244 m_webPageProxy->handlePotentialActivation(IntPoint(fromItemTransform.map(point.pos()).toPoint()), IntSize(point.rect().size().toSize())); 245#else 246 Q_UNUSED(point); 247#endif 248} 249 250void QtWebPageEventHandler::deactivateTapHighlight() 251{ 252#if ENABLE(TOUCH_EVENTS) 253 if (!m_isTapHighlightActive) 254 return; 255 256 // An empty point deactivates the highlighting. 257 m_webPageProxy->handlePotentialActivation(IntPoint(), IntSize()); 258 m_isTapHighlightActive = false; 259#endif 260} 261 262void QtWebPageEventHandler::handleSingleTapEvent(const QTouchEvent::TouchPoint& point) 263{ 264 deactivateTapHighlight(); 265 m_postponeTextInputStateChanged = true; 266 267 QTransform fromItemTransform = m_webPage->transformFromItem(); 268 WebGestureEvent gesture(WebEvent::GestureSingleTap, fromItemTransform.map(point.pos()).toPoint(), point.screenPos().toPoint(), WebEvent::Modifiers(0), 0, IntSize(point.rect().size().toSize()), FloatPoint(0, 0)); 269 m_webPageProxy->handleGestureEvent(gesture); 270} 271 272void QtWebPageEventHandler::handleDoubleTapEvent(const QTouchEvent::TouchPoint& point) 273{ 274 if (!m_webView->isInteractive()) 275 return; 276 277 deactivateTapHighlight(); 278 QTransform fromItemTransform = m_webPage->transformFromItem(); 279 m_webPageProxy->findZoomableAreaForPoint(fromItemTransform.map(point.pos()).toPoint(), IntSize(point.rect().size().toSize())); 280} 281 282void QtWebPageEventHandler::timerEvent(QTimerEvent* ev) 283{ 284 int timerId = ev->timerId(); 285 if (timerId == m_clickTimer.timerId()) 286 m_clickTimer.stop(); 287 else 288 QObject::timerEvent(ev); 289} 290 291void QtWebPageEventHandler::handleKeyPressEvent(QKeyEvent* ev) 292{ 293 m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev)); 294} 295 296void QtWebPageEventHandler::handleKeyReleaseEvent(QKeyEvent* ev) 297{ 298 m_webPageProxy->handleKeyboardEvent(NativeWebKeyboardEvent(ev)); 299} 300 301void QtWebPageEventHandler::handleFocusInEvent(QFocusEvent*) 302{ 303 m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive); 304} 305 306void QtWebPageEventHandler::handleFocusLost() 307{ 308 m_webPageProxy->viewStateDidChange(WebPageProxy::ViewIsFocused | WebPageProxy::ViewWindowIsActive); 309} 310 311void QtWebPageEventHandler::setViewportController(PageViewportControllerClientQt* controller) 312{ 313 m_viewportController = controller; 314} 315 316void QtWebPageEventHandler::handleInputMethodEvent(QInputMethodEvent* ev) 317{ 318 QString commit = ev->commitString(); 319 QString composition = ev->preeditString(); 320 321 int replacementStart = ev->replacementStart(); 322 int replacementLength = ev->replacementLength(); 323 324 // NOTE: We might want to handle events of one char as special 325 // and resend them as key events to make web site completion work. 326 327 int cursorPositionWithinComposition = 0; 328 329 Vector<CompositionUnderline> underlines; 330 331 for (int i = 0; i < ev->attributes().size(); ++i) { 332 const QInputMethodEvent::Attribute& attr = ev->attributes().at(i); 333 switch (attr.type) { 334 case QInputMethodEvent::TextFormat: { 335 if (composition.isEmpty()) 336 break; 337 338 QTextCharFormat textCharFormat = attr.value.value<QTextFormat>().toCharFormat(); 339 QColor qcolor = textCharFormat.underlineColor(); 340 Color color = makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha()); 341 int start = qMin(attr.start, (attr.start + attr.length)); 342 int end = qMax(attr.start, (attr.start + attr.length)); 343 underlines.append(CompositionUnderline(start, end, color, false)); 344 break; 345 } 346 case QInputMethodEvent::Cursor: 347 if (attr.length) 348 cursorPositionWithinComposition = attr.start; 349 break; 350 // Selection is handled further down. 351 default: break; 352 } 353 } 354 355 if (composition.isEmpty()) { 356 int selectionStart = -1; 357 int selectionLength = 0; 358 for (int i = 0; i < ev->attributes().size(); ++i) { 359 const QInputMethodEvent::Attribute& attr = ev->attributes().at(i); 360 if (attr.type == QInputMethodEvent::Selection) { 361 selectionStart = attr.start; 362 selectionLength = attr.length; 363 364 ASSERT(selectionStart >= 0); 365 ASSERT(selectionLength >= 0); 366 break; 367 } 368 } 369 370 m_webPageProxy->confirmComposition(commit, selectionStart, selectionLength); 371 } else { 372 ASSERT(cursorPositionWithinComposition >= 0); 373 ASSERT(replacementStart >= 0); 374 375 m_webPageProxy->setComposition(composition, underlines, 376 cursorPositionWithinComposition, cursorPositionWithinComposition, 377 replacementStart, replacementLength); 378 } 379 380 ev->accept(); 381} 382 383void QtWebPageEventHandler::handleTouchEvent(QTouchEvent* event) 384{ 385#if ENABLE(TOUCH_EVENTS) 386 QTransform fromItemTransform = m_webPage->transformFromItem(); 387 m_webPageProxy->handleTouchEvent(NativeWebTouchEvent(event, fromItemTransform)); 388 event->accept(); 389#else 390 ASSERT_NOT_REACHED(); 391 event->ignore(); 392#endif 393} 394 395void QtWebPageEventHandler::resetGestureRecognizers() 396{ 397 m_panGestureRecognizer.cancel(); 398 m_pinchGestureRecognizer.cancel(); 399 m_tapGestureRecognizer.cancel(); 400} 401 402static void setInputPanelVisible(bool visible) 403{ 404 if (qApp->inputMethod()->isVisible() == visible) 405 return; 406 407 qApp->inputMethod()->setVisible(visible); 408} 409 410void QtWebPageEventHandler::inputPanelVisibleChanged() 411{ 412 if (!m_viewportController) 413 return; 414 415 // We only respond to the input panel becoming visible. 416 if (!m_webView->hasActiveFocus() || !qApp->inputMethod()->isVisible()) 417 return; 418 419 const EditorState& editor = m_webPageProxy->editorState(); 420 if (editor.isContentEditable) 421 m_viewportController->focusEditableArea(QRectF(editor.cursorRect), QRectF(editor.editorRect)); 422} 423 424void QtWebPageEventHandler::updateTextInputState() 425{ 426 if (m_postponeTextInputStateChanged) 427 return; 428 429 const EditorState& editor = m_webPageProxy->editorState(); 430 431 m_webView->setFlag(QQuickItem::ItemAcceptsInputMethod, editor.isContentEditable); 432 433 if (!m_webView->hasActiveFocus()) 434 return; 435 436 qApp->inputMethod()->update(Qt::ImQueryInput | Qt::ImEnabled | Qt::ImHints); 437 438 setInputPanelVisible(editor.isContentEditable); 439} 440 441void QtWebPageEventHandler::handleWillSetInputMethodState() 442{ 443 if (qApp->inputMethod()->isVisible()) 444 qApp->inputMethod()->commit(); 445} 446 447void QtWebPageEventHandler::doneWithGestureEvent(const WebGestureEvent& event, bool wasEventHandled) 448{ 449 if (event.type() != WebEvent::GestureSingleTap) 450 return; 451 452 m_postponeTextInputStateChanged = false; 453 454 if (!wasEventHandled || !m_webView->hasActiveFocus()) 455 return; 456 457 updateTextInputState(); 458} 459 460void QtWebPageEventHandler::handleInputEvent(const QInputEvent* event) 461{ 462 if (m_viewportController) { 463 switch (event->type()) { 464 case QEvent::MouseButtonPress: 465 case QEvent::TouchBegin: 466 m_viewportController->touchBegin(); 467 468 // The page viewport controller might still be animating kinetic scrolling or a scale animation 469 // such as double-tap to zoom or the bounce back effect. A touch stops the kinetic scrolling 470 // where as it does not stop the scale animation. 471 // The gesture recognizer stops the kinetic scrolling animation if needed. 472 break; 473 case QEvent::MouseMove: 474 case QEvent::TouchUpdate: 475 // The scale animation can only be interrupted by a pinch gesture, which will then take over. 476 if (m_viewportController->scaleAnimationActive() && m_pinchGestureRecognizer.isRecognized()) 477 m_viewportController->interruptScaleAnimation(); 478 break; 479 case QEvent::MouseButtonRelease: 480 case QEvent::TouchEnd: 481 m_viewportController->touchEnd(); 482 break; 483 default: 484 break; 485 } 486 487 // If the scale animation is active we don't pass the event to the recognizers. In the future 488 // we would want to queue the event here and repost then when the animation ends. 489 if (m_viewportController->scaleAnimationActive()) 490 return; 491 } 492 493 bool isMouseEvent = false; 494 495 switch (event->type()) { 496 case QEvent::MouseButtonPress: 497 isMouseEvent = true; 498 m_isMouseButtonPressed = true; 499 break; 500 case QEvent::MouseMove: 501 if (!m_isMouseButtonPressed) 502 return; 503 isMouseEvent = true; 504 break; 505 case QEvent::MouseButtonRelease: 506 isMouseEvent = true; 507 m_isMouseButtonPressed = false; 508 break; 509 case QEvent::MouseButtonDblClick: 510 return; 511 default: 512 break; 513 } 514 515 QList<QTouchEvent::TouchPoint> activeTouchPoints; 516 QTouchEvent::TouchPoint currentTouchPoint; 517 qint64 eventTimestampMillis = event->timestamp(); 518 int touchPointCount = 0; 519 520 if (!isMouseEvent) { 521 const QTouchEvent* touchEvent = static_cast<const QTouchEvent*>(event); 522 const QList<QTouchEvent::TouchPoint>& touchPoints = touchEvent->touchPoints(); 523 currentTouchPoint = touchPoints.first(); 524 touchPointCount = touchPoints.size(); 525 activeTouchPoints.reserve(touchPointCount); 526 527 for (int i = 0; i < touchPointCount; ++i) { 528 if (touchPoints[i].state() != Qt::TouchPointReleased) 529 activeTouchPoints << touchPoints[i]; 530 } 531 } else { 532 const QMouseEvent* mouseEvent = static_cast<const QMouseEvent*>(event); 533 touchPointCount = 1; 534 535 // Make a distinction between mouse events on the basis of pressed buttons. 536 currentTouchPoint.setId(mouseEvent->buttons()); 537 currentTouchPoint.setScreenPos(mouseEvent->screenPos()); 538 // For tap gesture hit testing the float touch rect is translated to 539 // an int rect representing the radius of the touch point (size/2), 540 // thus the touch rect has to have a size of at least 2. 541 currentTouchPoint.setRect(QRectF(mouseEvent->localPos(), QSizeF(2, 2))); 542 543 if (m_isMouseButtonPressed) 544 activeTouchPoints << currentTouchPoint; 545 } 546 547 const int activeTouchPointCount = activeTouchPoints.size(); 548 549 if (!activeTouchPointCount) { 550 if (touchPointCount == 1) { 551 // No active touch points, one finger released. 552 if (m_panGestureRecognizer.isRecognized()) 553 m_panGestureRecognizer.finish(currentTouchPoint, eventTimestampMillis); 554 else { 555 // The events did not result in a pan gesture. 556 m_panGestureRecognizer.cancel(); 557 m_tapGestureRecognizer.finish(currentTouchPoint); 558 } 559 560 } else 561 m_pinchGestureRecognizer.finish(); 562 563 // Early return since this was a touch-end event. 564 return; 565 } else if (activeTouchPointCount == 1) { 566 // If the pinch gesture recognizer was previously in active state the content might 567 // be out of valid zoom boundaries, thus we need to finish the pinch gesture here. 568 // This will resume the content to valid zoom levels before the pan gesture is started. 569 m_pinchGestureRecognizer.finish(); 570 m_panGestureRecognizer.update(activeTouchPoints.first(), eventTimestampMillis); 571 } else if (activeTouchPointCount == 2) { 572 m_panGestureRecognizer.cancel(); 573 m_pinchGestureRecognizer.update(activeTouchPoints.first(), activeTouchPoints.last()); 574 } 575 576 if (m_panGestureRecognizer.isRecognized() || m_pinchGestureRecognizer.isRecognized() || m_webView->isMoving()) 577 m_tapGestureRecognizer.cancel(); 578 else if (touchPointCount == 1) 579 m_tapGestureRecognizer.update(currentTouchPoint); 580 581} 582 583#if ENABLE(TOUCH_EVENTS) 584void QtWebPageEventHandler::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled) 585{ 586 if (wasEventHandled || event.type() == WebEvent::TouchCancel) { 587 m_panGestureRecognizer.cancel(); 588 m_pinchGestureRecognizer.cancel(); 589 if (event.type() != WebEvent::TouchMove) 590 m_tapGestureRecognizer.cancel(); 591 return; 592 } 593 594 const QTouchEvent* ev = event.nativeEvent(); 595 596 handleInputEvent(ev); 597} 598#endif 599 600void QtWebPageEventHandler::didFindZoomableArea(const IntPoint& target, const IntRect& area) 601{ 602 if (!m_viewportController) 603 return; 604 605 // FIXME: As the find method might not respond immediately during load etc, 606 // we should ignore all but the latest request. 607 m_viewportController->zoomToAreaGestureEnded(QPointF(target), QRectF(area)); 608} 609 610void QtWebPageEventHandler::startDrag(const WebCore::DragData& dragData, PassRefPtr<ShareableBitmap> dragImage) 611{ 612 QImage dragQImage; 613 if (dragImage) 614 dragQImage = dragImage->createQImage(); 615 else if (dragData.platformData() && dragData.platformData()->hasImage()) 616 dragQImage = qvariant_cast<QImage>(dragData.platformData()->imageData()); 617 618 DragOperation dragOperationMask = dragData.draggingSourceOperationMask(); 619 QMimeData* mimeData = const_cast<QMimeData*>(dragData.platformData()); 620 Qt::DropActions supportedDropActions = dragOperationToDropActions(dragOperationMask); 621 622 QPoint clientPosition; 623 QPoint globalPosition; 624 Qt::DropAction actualDropAction = Qt::IgnoreAction; 625 626 if (QWindow* window = m_webPage->window()) { 627 QDrag* drag = new QDrag(window); 628 drag->setPixmap(QPixmap::fromImage(dragQImage)); 629 drag->setMimeData(mimeData); 630 actualDropAction = drag->exec(supportedDropActions); 631 globalPosition = QCursor::pos(); 632 clientPosition = window->mapFromGlobal(globalPosition); 633 } 634 635 m_webPageProxy->dragEnded(clientPosition, globalPosition, dropActionToDragOperation(actualDropAction)); 636} 637 638} // namespace WebKit 639 640#include "moc_QtWebPageEventHandler.cpp" 641 642