672111fb9295762e7e919b6ce07cd1bd901b5f85
[WebKit-https.git] / Source / WebKit / qt / WebCoreSupport / QWebPageAdapter.cpp
1 /*
2  * Copyright (C) 2012 Digia Plc 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 library 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 library; 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 "QWebPageAdapter.h"
23
24 #include "CSSComputedStyleDeclaration.h"
25 #include "CSSParser.h"
26 #include "Chrome.h"
27 #include "ChromeClientQt.h"
28 #include "ClientRect.h"
29 #include "ContextMenu.h"
30 #include "ContextMenuClientQt.h"
31 #include "ContextMenuController.h"
32 #if ENABLE(DEVICE_ORIENTATION)
33 #include "DeviceMotionClientMock.h"
34 #include "DeviceMotionController.h"
35 #include "DeviceOrientationClientMock.h"
36 #include "DeviceOrientationController.h"
37 #if HAVE(QTSENSORS)
38 #include "DeviceMotionClientQt.h"
39 #include "DeviceOrientationClientQt.h"
40 #endif
41 #endif
42 #include "DocumentLoader.h"
43 #include "DragClientQt.h"
44 #include "DragController.h"
45 #include "DragData.h"
46 #include "DragSession.h"
47 #include "Editor.h"
48 #include "EditorClientQt.h"
49 #include "EventHandler.h"
50 #include "FocusController.h"
51 #include "FrameLoadRequest.h"
52 #include "FrameSelection.h"
53 #include "FrameView.h"
54 #if ENABLE(GEOLOCATION)
55 #include "GeolocationClientMock.h"
56 #include "GeolocationController.h"
57 #if HAVE(QTLOCATION)
58 #include "GeolocationClientQt.h"
59 #endif
60 #endif
61 #include "GeolocationPermissionClientQt.h"
62 #include "HTMLFrameOwnerElement.h"
63 #include "HTMLInputElement.h"
64 #include "HitTestResult.h"
65 #include "InitWebCoreQt.h"
66 #include "InspectorClientQt.h"
67 #include "InspectorController.h"
68 #include "InspectorServerQt.h"
69 #include "LocalizedStrings.h"
70 #include "MIMETypeRegistry.h"
71 #include "MemoryCache.h"
72 #include "NetworkingContext.h"
73 #include "NodeList.h"
74 #include "NotificationPresenterClientQt.h"
75 #include "PageGroup.h"
76 #include "Pasteboard.h"
77 #include "PlatformKeyboardEvent.h"
78 #include "PlatformMouseEvent.h"
79 #include "PlatformTouchEvent.h"
80 #include "PlatformWheelEvent.h"
81 #include "PluginDatabase.h"
82 #include "PluginPackage.h"
83 #include "ProgressTracker.h"
84 #include "QWebFrameAdapter.h"
85 #include "RenderTextControl.h"
86 #include "SchemeRegistry.h"
87 #include "Scrollbar.h"
88 #include "ScrollbarTheme.h"
89 #include "Settings.h"
90 #include "UndoStepQt.h"
91 #include "UserAgentQt.h"
92 #include "WebEventConversion.h"
93 #include "WebKitVersion.h"
94 #include "WindowFeatures.h"
95 #include "qwebhistory_p.h"
96 #include "qwebpluginfactory.h"
97 #include "qwebsettings.h"
98 #include <Page.h>
99 #include <QBitArray>
100 #include <QGuiApplication>
101 #include <QMimeData>
102 #include <QMouseEvent>
103 #include <QNetworkAccessManager>
104 #include <QStyleHints>
105 #include <QTextCharFormat>
106 #include <QTouchEvent>
107 #include <QWheelEvent>
108
109 // from text/qfont.cpp
110 QT_BEGIN_NAMESPACE
111 extern Q_GUI_EXPORT int qt_defaultDpi();
112 QT_END_NAMESPACE
113
114 using namespace WebCore;
115
116 bool QWebPageAdapter::drtRun = false;
117
118 typedef QWebPageAdapter::MenuItemDescription MenuItem;
119
120 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
121 {
122     unsigned result = 0;
123     if (actions & Qt::CopyAction)
124         result |= DragOperationCopy;
125     // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
126     // hence it should be considered as "move"
127     if (actions & Qt::MoveAction)
128         result |= (DragOperationMove | DragOperationGeneric);
129     if (actions & Qt::LinkAction)
130         result |= DragOperationLink;
131     if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink))
132         result = DragOperationEvery;
133     return (DragOperation)result;
134 }
135
136 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
137 {
138     Qt::DropAction result = Qt::IgnoreAction;
139     if (actions & DragOperationCopy)
140         result = Qt::CopyAction;
141     else if (actions & DragOperationMove)
142         result = Qt::MoveAction;
143     // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
144     // hence it should be considered as "move"
145     else if (actions & DragOperationGeneric)
146         result = Qt::MoveAction;
147     else if (actions & DragOperationLink)
148         result = Qt::LinkAction;
149     return result;
150 }
151
152 static inline WebCore::PageVisibilityState webPageVisibilityStateToWebCoreVisibilityState(QWebPageAdapter::VisibilityState state)
153 {
154     switch (state) {
155     case QWebPageAdapter::VisibilityStatePrerender:
156         return WebCore::PageVisibilityStatePrerender;
157     case QWebPageAdapter::VisibilityStateUnloaded:
158         return WebCore::PageVisibilityStateUnloaded;
159     case QWebPageAdapter::VisibilityStateVisible:
160         return WebCore::PageVisibilityStateVisible;
161     case QWebPageAdapter::VisibilityStateHidden:
162         return WebCore::PageVisibilityStateHidden;
163     default:
164         ASSERT(false);
165         return WebCore::PageVisibilityStateHidden;
166     }
167 }
168
169 static inline QWebPageAdapter::VisibilityState webCoreVisibilityStateToWebPageVisibilityState(WebCore::PageVisibilityState state)
170 {
171     switch (state) {
172     case WebCore::PageVisibilityStatePrerender:
173         return QWebPageAdapter::VisibilityStatePrerender;
174     case WebCore::PageVisibilityStateUnloaded:
175         return QWebPageAdapter::VisibilityStateUnloaded;
176     case WebCore::PageVisibilityStateVisible:
177         return QWebPageAdapter::VisibilityStateVisible;
178     case WebCore::PageVisibilityStateHidden:
179         return QWebPageAdapter::VisibilityStateHidden;
180     default:
181         ASSERT(false);
182         return QWebPageAdapter::VisibilityStateHidden;
183     }
184 }
185
186 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
187 {
188     return WebCore::FrameLoadRequest(frame->document()->securityOrigin(),
189         WebCore::ResourceRequest(url, frame->loader()->outgoingReferrer()));
190 }
191
192 static void openNewWindow(const QUrl& url, Frame* frame)
193 {
194     if (Page* oldPage = frame->page()) {
195         WindowFeatures features;
196         NavigationAction action;
197         FrameLoadRequest request = frameLoadRequest(url, frame);
198         if (Page* newPage = oldPage->chrome().createWindow(frame, request, features, action)) {
199             newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, MaybeSendReferrer);
200             newPage->chrome().show();
201         }
202     }
203 }
204
205 QWebPageAdapter::QWebPageAdapter()
206     : settings(0)
207     , page(0)
208     , pluginFactory(0)
209     , forwardUnsupportedContent(false)
210     , insideOpenCall(false)
211     , clickCausedFocus(false)
212     , m_useNativeVirtualKeyAsDOMKey(false)
213     , m_totalBytes(0)
214     , m_bytesReceived()
215     , networkManager(0)
216 {
217     WebCore::initializeWebCoreQt();
218 }
219
220 void QWebPageAdapter::initializeWebCorePage()
221 {
222 #if ENABLE(GEOLOCATION) || ENABLE(DEVICE_ORIENTATION)
223     const bool useMock = QWebPageAdapter::drtRun;
224 #endif
225     Page::PageClients pageClients;
226     pageClients.chromeClient = new ChromeClientQt(this);
227     pageClients.contextMenuClient = new ContextMenuClientQt();
228     pageClients.editorClient = new EditorClientQt(this);
229     pageClients.dragClient = new DragClientQt(pageClients.chromeClient);
230     pageClients.inspectorClient = new InspectorClientQt(this);
231     page = new Page(pageClients);
232
233 #if ENABLE(GEOLOCATION)
234     if (useMock) {
235         // In case running in DumpRenderTree mode set the controller to mock provider.
236         GeolocationClientMock* mock = new GeolocationClientMock;
237         WebCore::provideGeolocationTo(page, mock);
238         mock->setController(WebCore::GeolocationController::from(page));
239     }
240 #if HAVE(QTLOCATION)
241     else
242         WebCore::provideGeolocationTo(page, new GeolocationClientQt(this));
243 #endif
244 #endif
245
246 #if ENABLE(DEVICE_ORIENTATION)
247     if (useMock) {
248         DeviceOrientationClientMock* mockOrientationClient = new DeviceOrientationClientMock;
249         WebCore::provideDeviceOrientationTo(page, mockOrientationClient);
250
251         DeviceMotionClientMock* mockMotionClient= new DeviceMotionClientMock;
252         WebCore::provideDeviceMotionTo(page, mockMotionClient);
253     }
254 #if HAVE(QTSENSORS)
255     else {
256         WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientQt);
257         WebCore::provideDeviceMotionTo(page, new DeviceMotionClientQt);
258     }
259 #endif
260 #endif
261
262     // By default each page is put into their own unique page group, which affects popup windows
263     // and visited links. Page groups (per process only) is a feature making it possible to use
264     // separate settings for each group, so that for instance an integrated browser/email reader
265     // can use different settings for displaying HTML pages and HTML email. To make QtWebKit work
266     // as expected out of the box, we use a default group similar to what other ports are doing.
267     page->setGroupName("Default Group");
268
269     page->addLayoutMilestones(DidFirstVisuallyNonEmptyLayout);
270
271     settings = new QWebSettings(&page->settings());
272
273 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
274     WebCore::provideNotification(page, NotificationPresenterClientQt::notificationPresenter());
275 #endif
276
277     history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList()));
278
279     PageGroup::setShouldTrackVisitedLinks(true);
280 }
281
282 QWebPageAdapter::~QWebPageAdapter()
283 {
284     delete page;
285     delete settings;
286
287 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
288     NotificationPresenterClientQt::notificationPresenter()->removeClient();
289 #endif
290 }
291
292 void QWebPageAdapter::deletePage()
293 {
294     // Before we delete the page, detach the mainframe's loader
295     FrameLoader* loader = mainFrameAdapter()->frame->loader();
296     if (loader)
297         loader->detachFromParent();
298     delete page;
299     page = 0;
300 }
301
302 QWebPageAdapter* QWebPageAdapter::kit(Page* page)
303 {
304     return static_cast<ChromeClientQt*>(page->chrome().client())->m_webPage;
305 }
306
307 ViewportArguments QWebPageAdapter::viewportArguments() const
308 {
309     return page ? page->viewportArguments() : WebCore::ViewportArguments();
310 }
311
312
313 void QWebPageAdapter::registerUndoStep(WTF::PassRefPtr<WebCore::UndoStep> step)
314 {
315     createUndoStep(QSharedPointer<UndoStepQt>(new UndoStepQt(step)));
316 }
317
318 void QWebPageAdapter::setVisibilityState(VisibilityState state)
319 {
320 #if ENABLE(PAGE_VISIBILITY_API)
321     if (!page)
322         return;
323     page->setVisibilityState(webPageVisibilityStateToWebCoreVisibilityState(state), false);
324 #else
325     Q_UNUSED(state);
326 #endif
327 }
328
329 QWebPageAdapter::VisibilityState QWebPageAdapter::visibilityState() const
330 {
331 #if ENABLE(PAGE_VISIBILITY_API)
332     return webCoreVisibilityStateToWebPageVisibilityState(page->visibilityState());
333 #else
334     return QWebPageAdapter::VisibilityStateVisible;
335 #endif
336 }
337
338 void QWebPageAdapter::setNetworkAccessManager(QNetworkAccessManager *manager)
339 {
340     if (manager == networkManager)
341         return;
342     if (networkManager && networkManager->parent() == handle())
343         delete networkManager;
344     networkManager = manager;
345 }
346
347 QNetworkAccessManager* QWebPageAdapter::networkAccessManager()
348 {
349     if (!networkManager)
350         networkManager = new QNetworkAccessManager(handle());
351     return networkManager;
352 }
353
354 bool QWebPageAdapter::hasSelection() const
355 {
356     Frame* frame = page->focusController()->focusedOrMainFrame();
357     if (frame)
358         return (frame->selection()->selection().selectionType() != VisibleSelection::NoSelection);
359     return false;
360 }
361
362 QString QWebPageAdapter::selectedText() const
363 {
364     Frame* frame = page->focusController()->focusedOrMainFrame();
365     if (frame->selection()->selection().selectionType() == VisibleSelection::NoSelection)
366         return QString();
367     return frame->editor().selectedText();
368 }
369
370 QString QWebPageAdapter::selectedHtml() const
371 {
372     return page->focusController()->focusedOrMainFrame()->editor().selectedRange()->toHTML();
373 }
374
375 bool QWebPageAdapter::isContentEditable() const
376 {
377     return page->isEditable();
378 }
379
380 void QWebPageAdapter::setContentEditable(bool editable)
381 {
382     page->setEditable(editable);
383     page->setTabKeyCyclesThroughElements(!editable);
384
385     Frame* frame = mainFrameAdapter()->frame;
386     if (editable) {
387         frame->editor().applyEditingStyleToBodyElement();
388         // FIXME: mac port calls this if there is no selectedDOMRange
389         // frame->setSelectionFromNone();
390     }
391
392 }
393
394 bool QWebPageAdapter::findText(const QString& subString, FindFlag options)
395 {
396     ::WebCore::FindOptions webCoreFindOptions = 0;
397
398     if (!(options & FindCaseSensitively))
399         webCoreFindOptions |= WebCore::CaseInsensitive;
400
401     if (options & FindBackward)
402         webCoreFindOptions |= WebCore::Backwards;
403
404     if (options & FindWrapsAroundDocument)
405         webCoreFindOptions |= WebCore::WrapAround;
406
407     if (options & FindAtWordBeginningsOnly)
408         webCoreFindOptions |= WebCore::AtWordStarts;
409
410     if (options & TreatMedialCapitalAsWordBeginning)
411         webCoreFindOptions |= WebCore::TreatMedialCapitalAsWordStart;
412
413     if (options & FindBeginsInSelection)
414         webCoreFindOptions |= WebCore::StartInSelection;
415
416     if (options & HighlightAllOccurrences) {
417         if (subString.isEmpty()) {
418             page->unmarkAllTextMatches();
419             return true;
420         }
421         return page->markAllMatchesForText(subString, webCoreFindOptions, /*shouldHighlight*/ true, /*limit*/ 0);
422     }
423
424     if (subString.isEmpty()) {
425         page->mainFrame()->selection()->clear();
426         Frame* frame = page->mainFrame()->tree()->firstChild();
427         while (frame) {
428             frame->selection()->clear();
429             frame = frame->tree()->traverseNextWithWrap(false);
430         }
431     }
432
433     return page->findString(subString, webCoreFindOptions);
434 }
435
436 void QWebPageAdapter::adjustPointForClicking(QMouseEvent* ev)
437 {
438 #if ENABLE(TOUCH_ADJUSTMENT)
439     QtPlatformPlugin platformPlugin;
440     OwnPtr<QWebTouchModifier> touchModifier = platformPlugin.createTouchModifier();
441     if (!touchModifier)
442         return;
443
444     unsigned topPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Up);
445     unsigned rightPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Right);
446     unsigned bottomPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Down);
447     unsigned leftPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Left);
448
449     touchModifier = nullptr;
450
451     if (!topPadding && !rightPadding && !bottomPadding && !leftPadding)
452         return;
453
454     EventHandler* eventHandler = page->mainFrame()->eventHandler();
455     ASSERT(eventHandler);
456
457     IntRect touchRect(ev->pos().x() - leftPadding, ev->pos().y() - topPadding, leftPadding + rightPadding, topPadding + bottomPadding);
458     IntPoint adjustedPoint;
459     Node* adjustedNode;
460     bool foundClickableNode = eventHandler->bestClickableNodeForTouchPoint(touchRect.center(), touchRect.size(), adjustedPoint, adjustedNode);
461     if (!foundClickableNode)
462         return;
463
464     QMouseEvent* ret = new QMouseEvent(ev->type(), QPoint(adjustedPoint), ev->globalPos(), ev->button(), ev->buttons(), ev->modifiers());
465     delete ev;
466     ev = ret;
467 #else
468     Q_UNUSED(ev);
469 #endif
470 }
471
472 void QWebPageAdapter::mouseMoveEvent(QMouseEvent* ev)
473 {
474     WebCore::Frame* frame = mainFrameAdapter()->frame;
475     if (!frame->view())
476         return;
477
478     bool accepted = frame->eventHandler()->mouseMoved(convertMouseEvent(ev, 0));
479     ev->setAccepted(accepted);
480 }
481
482 void QWebPageAdapter::mousePressEvent(QMouseEvent* ev)
483 {
484     WebCore::Frame* frame = mainFrameAdapter()->frame;
485     if (!frame->view())
486         return;
487
488     RefPtr<WebCore::Node> oldNode;
489     Frame* focusedFrame = page->focusController()->focusedFrame();
490     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
491         oldNode = focusedDocument->focusedElement();
492
493     if (tripleClickTimer.isActive()
494         && (ev->pos() - tripleClick).manhattanLength() < qGuiApp->styleHints()->startDragDistance()) {
495         mouseTripleClickEvent(ev);
496         return;
497     }
498
499     bool accepted = false;
500     PlatformMouseEvent mev = convertMouseEvent(ev, 1);
501     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
502     if (mev.button() != NoButton)
503         accepted = frame->eventHandler()->handleMousePressEvent(mev);
504     ev->setAccepted(accepted);
505
506     RefPtr<WebCore::Node> newNode;
507     focusedFrame = page->focusController()->focusedFrame();
508     if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
509         newNode = focusedDocument->focusedElement();
510
511     if (newNode && oldNode != newNode)
512         clickCausedFocus = true;
513 }
514
515 void QWebPageAdapter::mouseDoubleClickEvent(QMouseEvent *ev)
516 {
517     WebCore::Frame* frame = mainFrameAdapter()->frame;
518     if (!frame->view())
519         return;
520
521     bool accepted = false;
522     PlatformMouseEvent mev = convertMouseEvent(ev, 2);
523     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
524     if (mev.button() != NoButton)
525         accepted = frame->eventHandler()->handleMousePressEvent(mev);
526     ev->setAccepted(accepted);
527
528     tripleClickTimer.start(qGuiApp->styleHints()->mouseDoubleClickInterval(), handle());
529     tripleClick = QPointF(ev->pos()).toPoint();
530 }
531
532 void QWebPageAdapter::mouseTripleClickEvent(QMouseEvent *ev)
533 {
534     WebCore::Frame* frame = mainFrameAdapter()->frame;
535     if (!frame->view())
536         return;
537
538     bool accepted = false;
539     PlatformMouseEvent mev = convertMouseEvent(ev, 3);
540     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
541     if (mev.button() != NoButton)
542         accepted = frame->eventHandler()->handleMousePressEvent(mev);
543     ev->setAccepted(accepted);
544 }
545
546 void QWebPageAdapter::mouseReleaseEvent(QMouseEvent *ev)
547 {
548     WebCore::Frame* frame = mainFrameAdapter()->frame;
549     if (!frame->view())
550         return;
551
552     bool accepted = false;
553     PlatformMouseEvent mev = convertMouseEvent(ev, 0);
554     // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
555     if (mev.button() != NoButton)
556         accepted = frame->eventHandler()->handleMouseReleaseEvent(mev);
557     ev->setAccepted(accepted);
558
559     handleSoftwareInputPanel(ev->button(), QPointF(ev->pos()).toPoint());
560 }
561
562 void QWebPageAdapter::handleSoftwareInputPanel(Qt::MouseButton button, const QPoint& pos)
563 {
564     Frame* frame = page->focusController()->focusedFrame();
565     if (!frame)
566         return;
567
568     if (client && client->inputMethodEnabled()
569         && frame->document()->focusedElement()
570             && button == Qt::LeftButton && qGuiApp->property("autoSipEnabled").toBool()) {
571         if (!clickCausedFocus || requestSoftwareInputPanel()) {
572             HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(frame->view()->windowToContents(pos));
573             if (result.isContentEditable()) {
574                 QEvent event(QEvent::RequestSoftwareInputPanel);
575                 QGuiApplication::sendEvent(client->ownerWidget(), &event);
576             }
577         }
578     }
579
580     clickCausedFocus = false;
581 }
582
583 #ifndef QT_NO_WHEELEVENT
584 void QWebPageAdapter::wheelEvent(QWheelEvent *ev, int wheelScrollLines)
585 {
586     WebCore::Frame* frame = mainFrameAdapter()->frame;
587     if (!frame->view())
588         return;
589
590     PlatformWheelEvent pev = convertWheelEvent(ev, wheelScrollLines);
591     bool accepted = frame->eventHandler()->handleWheelEvent(pev);
592     ev->setAccepted(accepted);
593 }
594 #endif // QT_NO_WHEELEVENT
595
596 #ifndef QT_NO_DRAGANDDROP
597
598 Qt::DropAction QWebPageAdapter::dragEntered(const QMimeData *data, const QPoint &pos, Qt::DropActions possibleActions)
599 {
600     DragData dragData(data, pos, QCursor::pos(), dropActionToDragOp(possibleActions));
601     return dragOpToDropAction(page->dragController()->dragEntered(&dragData).operation);
602 }
603
604 void QWebPageAdapter::dragLeaveEvent()
605 {
606     DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
607     page->dragController()->dragExited(&dragData);
608 }
609
610 Qt::DropAction QWebPageAdapter::dragUpdated(const QMimeData *data, const QPoint &pos, Qt::DropActions possibleActions)
611 {
612     DragData dragData(data, pos, QCursor::pos(), dropActionToDragOp(possibleActions));
613     return dragOpToDropAction(page->dragController()->dragUpdated(&dragData).operation);
614 }
615
616 bool QWebPageAdapter::performDrag(const QMimeData *data, const QPoint &pos, Qt::DropActions possibleActions)
617 {
618     DragData dragData(data, pos, QCursor::pos(), dropActionToDragOp(possibleActions));
619     return page->dragController()->performDrag(&dragData);
620 }
621
622 void QWebPageAdapter::inputMethodEvent(QInputMethodEvent *ev)
623 {
624     WebCore::Frame *frame = page->focusController()->focusedOrMainFrame();
625     WebCore::Editor &editor = frame->editor();
626
627     if (!editor.canEdit()) {
628         ev->ignore();
629         return;
630     }
631
632     Node* node = 0;
633     if (frame->selection()->rootEditableElement())
634         node = frame->selection()->rootEditableElement()->deprecatedShadowAncestorNode();
635
636     Vector<CompositionUnderline> underlines;
637     bool hasSelection = false;
638
639     for (int i = 0; i < ev->attributes().size(); ++i) {
640         const QInputMethodEvent::Attribute& a = ev->attributes().at(i);
641         switch (a.type) {
642         case QInputMethodEvent::TextFormat: {
643             QTextCharFormat textCharFormat = a.value.value<QTextFormat>().toCharFormat();
644             QColor qcolor = textCharFormat.underlineColor();
645             underlines.append(CompositionUnderline(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)), Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())), false));
646             break;
647         }
648         case QInputMethodEvent::Cursor: {
649             frame->selection()->setCaretVisible(a.length); // if length is 0 cursor is invisible
650             if (a.length > 0) {
651                 RenderObject* caretRenderer = frame->selection()->caretRenderer();
652                 if (caretRenderer) {
653                     QColor qcolor = a.value.value<QColor>();
654                     caretRenderer->style()->setColor(Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())));
655                 }
656             }
657             break;
658         }
659         case QInputMethodEvent::Selection: {
660             hasSelection = true;
661             // A selection in the inputMethodEvent is always reflected in the visible text
662             if (node) {
663                 if (isHTMLTextFormControlElement(node))
664                     toHTMLTextFormControlElement(node)->setSelectionRange(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
665             }
666
667             if (!ev->preeditString().isEmpty())
668                 editor.setComposition(ev->preeditString(), underlines, qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
669             else {
670                 // If we are in the middle of a composition, an empty pre-edit string and a selection of zero
671                 // cancels the current composition
672                 if (editor.hasComposition() && !(a.start + a.length))
673                     editor.setComposition(QString(), underlines, 0, 0);
674             }
675             break;
676         }
677         default:
678             break;
679         }
680     }
681
682     if (node && ev->replacementLength() > 0) {
683         int cursorPos = frame->selection()->extent().offsetInContainerNode();
684         int start = cursorPos + ev->replacementStart();
685         if (isHTMLTextFormControlElement(node))
686             toHTMLTextFormControlElement(node)->setSelectionRange(start, start + ev->replacementLength());
687         // Commit regardless of whether commitString is empty, to get rid of selection.
688         editor.confirmComposition(ev->commitString());
689     } else if (!ev->commitString().isEmpty()) {
690         if (editor.hasComposition())
691             editor.confirmComposition(ev->commitString());
692         else
693             editor.insertText(ev->commitString(), 0);
694     } else if (!hasSelection && !ev->preeditString().isEmpty())
695         editor.setComposition(ev->preeditString(), underlines, 0, 0);
696     else if (ev->preeditString().isEmpty() && editor.hasComposition())
697         editor.confirmComposition(String());
698
699     ev->accept();
700 }
701
702 QVariant QWebPageAdapter::inputMethodQuery(Qt::InputMethodQuery property) const
703 {
704     Frame* frame = page->focusController()->focusedFrame();
705     if (!frame)
706         return QVariant();
707
708     WebCore::Editor& editor = frame->editor();
709
710     RenderObject* renderer = 0;
711     RenderTextControl* renderTextControl = 0;
712
713     if (frame->selection()->rootEditableElement())
714         renderer = frame->selection()->rootEditableElement()->deprecatedShadowAncestorNode()->renderer();
715
716     if (renderer && renderer->isTextControl())
717         renderTextControl = toRenderTextControl(renderer);
718
719     switch (property) {
720     case Qt::ImMicroFocus: {
721         WebCore::FrameView* view = frame->view();
722         if (view && view->needsLayout()) {
723             // We can't access absoluteCaretBounds() while the view needs to layout.
724             return QVariant();
725         }
726         return QVariant(view->contentsToWindow(frame->selection()->absoluteCaretBounds()));
727     }
728     case Qt::ImFont: {
729         if (renderTextControl) {
730             RenderStyle* renderStyle = renderTextControl->style();
731             return QVariant(QFont(renderStyle->font().syntheticFont()));
732         }
733         return QVariant(QFont());
734     }
735     case Qt::ImCursorPosition: {
736         if (editor.hasComposition())
737             return QVariant(frame->selection()->end().offsetInContainerNode());
738         return QVariant(frame->selection()->extent().offsetInContainerNode());
739     }
740     case Qt::ImSurroundingText: {
741         if (renderTextControl && renderTextControl->textFormControlElement()) {
742             QString text = renderTextControl->textFormControlElement()->value();
743             RefPtr<Range> range = editor.compositionRange();
744             if (range)
745                 text.remove(range->startPosition().offsetInContainerNode(), TextIterator::rangeLength(range.get()));
746             return QVariant(text);
747         }
748         return QVariant();
749     }
750     case Qt::ImCurrentSelection: {
751         if (!editor.hasComposition() && renderTextControl && renderTextControl->textFormControlElement()) {
752             int start = frame->selection()->start().offsetInContainerNode();
753             int end = frame->selection()->end().offsetInContainerNode();
754             if (end > start)
755                 return QVariant(QString(renderTextControl->textFormControlElement()->value()).mid(start, end - start));
756         }
757         return QVariant();
758
759     }
760     case Qt::ImAnchorPosition: {
761         if (editor.hasComposition())
762             return QVariant(frame->selection()->start().offsetInContainerNode());
763         return QVariant(frame->selection()->base().offsetInContainerNode());
764     }
765     case Qt::ImMaximumTextLength: {
766         if (frame->selection()->isContentEditable()) {
767             if (frame->document() && frame->document()->focusedElement()) {
768                 if (isHTMLInputElement(frame->document()->focusedElement())) {
769                     HTMLInputElement* inputElement = toHTMLInputElement(frame->document()->focusedElement());
770                     return QVariant(inputElement->maxLength());
771                 }
772             }
773             return QVariant(HTMLInputElement::maximumLength);
774         }
775         return QVariant(0);
776     }
777     default:
778         return QVariant();
779     }
780 }
781
782 typedef struct {
783     const char* name;
784     double deferredRepaintDelay;
785     double initialDeferredRepaintDelayDuringLoading;
786     double maxDeferredRepaintDelayDuringLoading;
787     double deferredRepaintDelayIncrementDuringLoading;
788 } QRepaintThrottlingPreset;
789
790 void QWebPageAdapter::dynamicPropertyChangeEvent(QObject* obj, QDynamicPropertyChangeEvent* event)
791 {
792     if (event->propertyName() == "_q_viewMode") {
793         page->setViewMode(Page::stringToViewMode(obj->property("_q_viewMode").toString()));
794     } else if (event->propertyName() == "_q_HTMLTokenizerChunkSize") {
795         int chunkSize = obj->property("_q_HTMLTokenizerChunkSize").toInt();
796         page->setCustomHTMLTokenizerChunkSize(chunkSize);
797     } else if (event->propertyName() == "_q_HTMLTokenizerTimeDelay") {
798         double timeDelay = obj->property("_q_HTMLTokenizerTimeDelay").toDouble();
799         page->setCustomHTMLTokenizerTimeDelay(timeDelay);
800     } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelay") {
801         double p = obj->property("_q_RepaintThrottlingDeferredRepaintDelay").toDouble();
802         FrameView::setRepaintThrottlingDeferredRepaintDelay(p);
803     } else if (event->propertyName() == "_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading") {
804         double p = obj->property("_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading").toDouble();
805         FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(p);
806     } else if (event->propertyName() == "_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading") {
807         double p = obj->property("_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading").toDouble();
808         FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(p);
809     } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading") {
810         double p = obj->property("_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading").toDouble();
811         FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(p);
812     } else if (event->propertyName() == "_q_RepaintThrottlingPreset") {
813         static const QRepaintThrottlingPreset presets[] = {
814             {   "NoThrottling",     0,      0,      0,      0 },
815             {   "Legacy",       0.025,      0,    2.5,    0.5 },
816             {   "Minimal",       0.01,      0,      1,    0.2 },
817             {   "Medium",       0.025,      1,      5,    0.5 },
818             {   "Heavy",          0.1,      2,     10,      1 }
819         };
820
821         QString p = obj->property("_q_RepaintThrottlingPreset").toString();
822         for (size_t i = 0; i < sizeof(presets) / sizeof(presets[0]); i++) {
823             if (p == QLatin1String(presets[i].name)) {
824                 FrameView::setRepaintThrottlingDeferredRepaintDelay(presets[i].deferredRepaintDelay);
825                 FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(presets[i].initialDeferredRepaintDelayDuringLoading);
826                 FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(presets[i].maxDeferredRepaintDelayDuringLoading);
827                 FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(presets[i].deferredRepaintDelayIncrementDuringLoading);
828                 break;
829             }
830         }
831     } else if (event->propertyName() == "_q_webInspectorServerPort") {
832 #if ENABLE(INSPECTOR)
833         QVariant port = obj->property("_q_webInspectorServerPort");
834         if (port.isValid()) {
835             InspectorServerQt* inspectorServer = InspectorServerQt::server();
836             inspectorServer->listen(port.toInt());
837         }
838 #endif
839     } else if (event->propertyName() == "_q_deadDecodedDataDeletionInterval") {
840         double interval = obj->property("_q_deadDecodedDataDeletionInterval").toDouble();
841         memoryCache()->setDeadDecodedDataDeletionInterval(interval);
842     }  else if (event->propertyName() == "_q_useNativeVirtualKeyAsDOMKey") {
843         m_useNativeVirtualKeyAsDOMKey = obj->property("_q_useNativeVirtualKeyAsDOMKey").toBool();
844     }
845 }
846
847 #endif // QT_NO_DRAGANDDROP
848
849 #define MAP_ACTION_FROM_VALUE(Name, Value) \
850     case Value: return QWebPageAdapter::Name
851
852 static QWebPageAdapter::MenuAction adapterActionForContextMenuAction(WebCore::ContextMenuAction action)
853 {
854     switch (action) {
855         FOR_EACH_MAPPED_MENU_ACTION(MAP_ACTION_FROM_VALUE, SEMICOLON_SEPARATOR);
856 #if ENABLE(INSPECTOR)
857     case WebCore::ContextMenuItemTagInspectElement:
858         return QWebPageAdapter::InspectElement;
859 #endif
860     default:
861         break;
862     }
863     return QWebPageAdapter::NoAction;
864 }
865
866 QList<MenuItem> descriptionForPlatformMenu(const Vector<ContextMenuItem>& items, Page* page)
867 {
868     QList<MenuItem> itemDescriptions;
869     if (!items.size())
870         return itemDescriptions;
871     for (int i = 0; i < items.size(); ++i) {
872         const ContextMenuItem &item = items.at(i);
873         MenuItem description;
874         switch (item.type()) {
875         case WebCore::CheckableActionType: /* fall through */
876         case WebCore::ActionType: {
877             QWebPageAdapter::MenuAction action = adapterActionForContextMenuAction(item.action());
878             if (action > QWebPageAdapter::NoAction) {
879                 description.type = MenuItem::Action;
880                 description.action = action;
881                 ContextMenuItem it(item);
882                 page->contextMenuController()->checkOrEnableIfNeeded(it);
883                 if (it.enabled())
884                     description.traits |= MenuItem::Enabled;
885                 if (item.type() == WebCore::CheckableActionType) {
886                     description.traits |= MenuItem::Checkable;
887                     if (it.checked())
888                         description.traits |= MenuItem::Checked;
889                 }
890             }
891             break;
892         }
893         case WebCore::SeparatorType:
894             description.type = MenuItem::Separator;
895             break;
896         case WebCore::SubmenuType: {
897             description.type = MenuItem::SubMenu;
898             description.subMenu = descriptionForPlatformMenu(item.subMenuItems(), page);
899             description.subMenuTitle = item.title();
900             // Don't append empty submenu descriptions.
901             if (description.subMenu.isEmpty())
902                 continue;
903         }
904         }
905         if (description.type > MenuItem::NoType)
906             itemDescriptions.append(description);
907     }
908     return itemDescriptions;
909 }
910
911 QWebHitTestResultPrivate* QWebPageAdapter::updatePositionDependentMenuActions(const QPoint& pos, QBitArray* visitedWebActions)
912 {
913     ASSERT(visitedWebActions);
914     WebCore::Frame* focusedFrame = page->focusController()->focusedOrMainFrame();
915     HitTestResult result = focusedFrame->eventHandler()->hitTestResultAtPoint(focusedFrame->view()->windowToContents(pos));
916     page->contextMenuController()->setHitTestResult(result);
917
918 #if ENABLE(INSPECTOR)
919     if (page->inspectorController()->enabled())
920         page->contextMenuController()->addInspectElementItem();
921 #endif
922
923     WebCore::ContextMenu* webcoreMenu = page->contextMenuController()->contextMenu();
924     QList<MenuItem> itemDescriptions;
925     if (client && webcoreMenu)
926         itemDescriptions = descriptionForPlatformMenu(webcoreMenu->items(), page);
927     createAndSetCurrentContextMenu(itemDescriptions, visitedWebActions);
928     if (result.scrollbar())
929         return 0;
930     return new QWebHitTestResultPrivate(result);
931 }
932
933 static void extractContentTypeFromHash(const HashSet<String>& types, QStringList* list)
934 {
935     if (!list)
936         return;
937
938     HashSet<String>::const_iterator endIt = types.end();
939     for (HashSet<String>::const_iterator it = types.begin(); it != endIt; ++it)
940         *list << *it;
941 }
942
943 static void extractContentTypeFromPluginVector(const Vector<PluginPackage*>& plugins, QStringList* list)
944 {
945     if (!list)
946         return;
947
948     for (unsigned i = 0; i < plugins.size(); ++i) {
949         MIMEToDescriptionsMap::const_iterator it = plugins[i]->mimeToDescriptions().begin();
950         MIMEToDescriptionsMap::const_iterator end = plugins[i]->mimeToDescriptions().end();
951         for (; it != end; ++it)
952             *list << it->key;
953     }
954 }
955
956 QStringList QWebPageAdapter::supportedContentTypes() const
957 {
958     QStringList mimeTypes;
959
960     extractContentTypeFromHash(MIMETypeRegistry::getSupportedImageMIMETypes(), &mimeTypes);
961     extractContentTypeFromHash(MIMETypeRegistry::getSupportedNonImageMIMETypes(), &mimeTypes);
962     if (page->settings().arePluginsEnabled())
963         extractContentTypeFromPluginVector(PluginDatabase::installedPlugins()->plugins(), &mimeTypes);
964
965     return mimeTypes;
966 }
967
968 void QWebPageAdapter::_q_cleanupLeakMessages()
969 {
970 #ifndef NDEBUG
971     // Need this to make leak messages accurate.
972     memoryCache()->setCapacities(0, 0, 0);
973 #endif
974 }
975
976 void QWebPageAdapter::_q_onLoadProgressChanged(int)
977 {
978     m_totalBytes = page->progress()->totalPageAndResourceBytesToLoad();
979     m_bytesReceived = page->progress()->totalBytesReceived();
980 }
981
982 bool QWebPageAdapter::supportsContentType(const QString& mimeType) const
983 {
984     const String type = mimeType.toLower();
985     if (MIMETypeRegistry::isSupportedImageMIMEType(type))
986         return true;
987
988     if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
989         return true;
990
991     if (page->settings().arePluginsEnabled()
992         && PluginDatabase::installedPlugins()->isMIMETypeRegistered(type))
993         return true;
994
995     return false;
996 }
997
998 void QWebPageAdapter::didShowInspector()
999 {
1000 #if ENABLE(INSPECTOR)
1001     page->inspectorController()->show();
1002 #endif
1003 }
1004
1005 void QWebPageAdapter::didCloseInspector()
1006 {
1007 #if ENABLE(INSPECTOR)
1008     page->inspectorController()->close();
1009 #endif
1010 }
1011
1012 void QWebPageAdapter::updateActionInternal(QWebPageAdapter::MenuAction action, const char* commandName, bool* enabled, bool* checked)
1013 {
1014     WebCore::FrameLoader* loader = mainFrameAdapter()->frame->loader();
1015     WebCore::Editor& editor = page->focusController()->focusedOrMainFrame()->editor();
1016
1017     switch (action) {
1018     case QWebPageAdapter::Back:
1019         *enabled = page->canGoBackOrForward(-1);
1020         break;
1021     case QWebPageAdapter::Forward:
1022         *enabled = page->canGoBackOrForward(1);
1023         break;
1024     case QWebPageAdapter::Stop:
1025         *enabled = loader->isLoading();
1026         break;
1027     case QWebPageAdapter::Reload:
1028         *enabled = !loader->isLoading();
1029         break;
1030     case QWebPageAdapter::SetTextDirectionDefault:
1031     case QWebPageAdapter::SetTextDirectionLeftToRight:
1032     case QWebPageAdapter::SetTextDirectionRightToLeft:
1033         *enabled = editor.canEdit();
1034         *checked = false;
1035         break;
1036     default: {
1037
1038         // if it's an editor command, let its logic determine state
1039         if (commandName) {
1040             Editor::Command command = editor.command(commandName);
1041             *enabled = command.isEnabled();
1042             if (*enabled)
1043                 *checked = command.state() != FalseTriState;
1044             else
1045                 *checked = false;
1046         }
1047         break;
1048     }
1049     }
1050 }
1051
1052 void QWebPageAdapter::triggerAction(QWebPageAdapter::MenuAction action, QWebHitTestResultPrivate* hitTestResult, const char* commandName, bool endToEndReload)
1053 {
1054     Frame* frame = page->focusController()->focusedOrMainFrame();
1055     if (!frame)
1056         return;
1057     Editor& editor = frame->editor();
1058
1059     // Convenience
1060     QWebHitTestResultPrivate hitTest;
1061     if (!hitTestResult)
1062         hitTestResult = &hitTest;
1063
1064     switch (action) {
1065     case OpenLink:
1066         if (Frame* targetFrame = hitTestResult->webCoreFrame) {
1067             targetFrame->loader()->loadFrameRequest(frameLoadRequest(hitTestResult->linkUrl, targetFrame), /*lockHistory*/ false, /*lockBackForwardList*/ false, /*event*/ 0, /*FormState*/ 0, MaybeSendReferrer);
1068             break;
1069         }
1070         // fall through
1071     case OpenLinkInNewWindow:
1072         openNewWindow(hitTestResult->linkUrl, frame);
1073         break;
1074     case OpenLinkInThisWindow:
1075         frame->loader()->loadFrameRequest(frameLoadRequest(hitTestResult->linkUrl, frame), /*lockHistory*/ false, /*lockBackForwardList*/ false, /*event*/ 0, /*FormState*/ 0, MaybeSendReferrer);
1076         break;
1077     case OpenFrameInNewWindow: {
1078         KURL url = frame->loader()->documentLoader()->unreachableURL();
1079         if (url.isEmpty())
1080             url = frame->loader()->documentLoader()->url();
1081         openNewWindow(url, frame);
1082         break;
1083         }
1084     case CopyLinkToClipboard: {
1085 #if defined(Q_WS_X11)
1086         bool oldSelectionMode = Pasteboard::generalPasteboard()->isSelectionMode();
1087         Pasteboard::generalPasteboard()->setSelectionMode(true);
1088         editor.copyURL(hitTestResult->linkUrl, hitTestResult->linkText);
1089         Pasteboard::generalPasteboard()->setSelectionMode(oldSelectionMode);
1090 #endif
1091         editor.copyURL(hitTestResult->linkUrl, hitTestResult->linkText);
1092         break;
1093     }
1094     case OpenImageInNewWindow:
1095         openNewWindow(hitTestResult->imageUrl, frame);
1096         break;
1097     case DownloadImageToDisk:
1098         frame->loader()->client()->startDownload(WebCore::ResourceRequest(hitTestResult->imageUrl, frame->loader()->outgoingReferrer()));
1099         break;
1100     case DownloadLinkToDisk:
1101         frame->loader()->client()->startDownload(WebCore::ResourceRequest(hitTestResult->linkUrl, frame->loader()->outgoingReferrer()));
1102         break;
1103     case Back:
1104         page->goBack();
1105         break;
1106     case Forward:
1107         page->goForward();
1108         break;
1109     case Stop:
1110         mainFrameAdapter()->frame->loader()->stopForUserCancel();
1111         updateNavigationActions();
1112         break;
1113     case Reload:
1114         mainFrameAdapter()->frame->loader()->reload(endToEndReload);
1115         break;
1116
1117     case SetTextDirectionDefault:
1118         editor.setBaseWritingDirection(NaturalWritingDirection);
1119         break;
1120     case SetTextDirectionLeftToRight:
1121         editor.setBaseWritingDirection(LeftToRightWritingDirection);
1122         break;
1123     case SetTextDirectionRightToLeft:
1124         editor.setBaseWritingDirection(RightToLeftWritingDirection);
1125         break;
1126 #if ENABLE(INSPECTOR)
1127     case InspectElement: {
1128         ASSERT(hitTestResult != &hitTest);
1129         page->inspectorController()->inspect(hitTestResult->innerNonSharedNode);
1130         break;
1131     }
1132 #endif
1133     default:
1134         if (commandName)
1135             editor.command(commandName).execute();
1136         break;
1137     }
1138 }
1139
1140
1141 QString QWebPageAdapter::contextMenuItemTagForAction(QWebPageAdapter::MenuAction action, bool* checkable) const
1142 {
1143     ASSERT(checkable);
1144     switch (action) {
1145     case OpenLink:
1146         return contextMenuItemTagOpenLink();
1147     case OpenLinkInNewWindow:
1148         return contextMenuItemTagOpenLinkInNewWindow();
1149     case OpenFrameInNewWindow:
1150         return contextMenuItemTagOpenFrameInNewWindow();
1151     case OpenLinkInThisWindow:
1152         return contextMenuItemTagOpenLinkInThisWindow();
1153
1154     case DownloadLinkToDisk:
1155         return contextMenuItemTagDownloadLinkToDisk();
1156     case CopyLinkToClipboard:
1157         return contextMenuItemTagCopyLinkToClipboard();
1158
1159     case OpenImageInNewWindow:
1160         return contextMenuItemTagOpenImageInNewWindow();
1161     case DownloadImageToDisk:
1162         return contextMenuItemTagDownloadImageToDisk();
1163     case CopyImageToClipboard:
1164         return contextMenuItemTagCopyImageToClipboard();
1165     case CopyImageUrlToClipboard:
1166         return contextMenuItemTagCopyImageUrlToClipboard();
1167
1168     case Cut:
1169         return contextMenuItemTagCut();
1170     case Copy:
1171         return contextMenuItemTagCopy();
1172     case Paste:
1173         return contextMenuItemTagPaste();
1174     case SelectAll:
1175         return contextMenuItemTagSelectAll();
1176
1177     case Back:
1178         return contextMenuItemTagGoBack();
1179     case Forward:
1180         return contextMenuItemTagGoForward();
1181     case Reload:
1182         return contextMenuItemTagReload();
1183     case Stop:
1184         return contextMenuItemTagStop();
1185
1186     case SetTextDirectionDefault:
1187         return contextMenuItemTagDefaultDirection();
1188     case SetTextDirectionLeftToRight:
1189         *checkable = true;
1190         return contextMenuItemTagLeftToRight();
1191     case SetTextDirectionRightToLeft:
1192         *checkable = true;
1193         return contextMenuItemTagRightToLeft();
1194
1195     case ToggleBold:
1196         *checkable = true;
1197         return contextMenuItemTagBold();
1198     case ToggleItalic:
1199         *checkable = true;
1200         return contextMenuItemTagItalic();
1201     case ToggleUnderline:
1202         *checkable = true;
1203         return contextMenuItemTagUnderline();
1204
1205 #if ENABLE(INSPECTOR)
1206     case InspectElement:
1207         return contextMenuItemTagInspectElement();
1208 #endif
1209     default:
1210         ASSERT_NOT_REACHED();
1211         return QString();
1212     }
1213 }
1214
1215 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
1216 void QWebPageAdapter::setNotificationsAllowedForFrame(QWebFrameAdapter* frame, bool allowed)
1217 {
1218     NotificationPresenterClientQt::notificationPresenter()->setNotificationsAllowedForFrame(frame->frame, allowed);
1219 }
1220
1221 void QWebPageAdapter::addNotificationPresenterClient()
1222 {
1223     NotificationPresenterClientQt::notificationPresenter()->addClient();
1224 }
1225
1226 #ifndef QT_NO_SYSTEMTRAYICON
1227 bool QWebPageAdapter::hasSystemTrayIcon() const
1228 {
1229     return NotificationPresenterClientQt::notificationPresenter()->hasSystemTrayIcon();
1230 }
1231
1232 void QWebPageAdapter::setSystemTrayIcon(QObject *icon)
1233 {
1234     NotificationPresenterClientQt::notificationPresenter()->setSystemTrayIcon(icon);
1235 }
1236 #endif // QT_NO_SYSTEMTRAYICON
1237 #endif // ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
1238
1239 #if ENABLE(GEOLOCATION) && HAVE(QTLOCATION)
1240 void QWebPageAdapter::setGeolocationEnabledForFrame(QWebFrameAdapter* frame, bool on)
1241 {
1242     GeolocationPermissionClientQt::geolocationPermissionClient()->setPermission(frame, on);
1243 }
1244 #endif
1245
1246
1247 QString QWebPageAdapter::defaultUserAgentString()
1248 {
1249     return UserAgentQt::standardUserAgent("", WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION);
1250 }
1251
1252 bool QWebPageAdapter::treatSchemeAsLocal(const QString& scheme)
1253 {
1254     return WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal(scheme);
1255 }
1256
1257 QObject* QWebPageAdapter::currentFrame() const
1258 {
1259     Frame* frame = page->focusController()->focusedOrMainFrame();
1260     return frame->loader()->networkingContext()->originatingObject();
1261 }
1262
1263 bool QWebPageAdapter::hasFocusedNode() const
1264 {
1265     bool hasFocus = false;
1266     Frame* frame = page->focusController()->focusedFrame();
1267     if (frame) {
1268         Document* document = frame->document();
1269         hasFocus = document && document->focusedElement();
1270     }
1271     return hasFocus;
1272 }
1273
1274 QWebPageAdapter::ViewportAttributes QWebPageAdapter::viewportAttributesForSize(const QSize &availableSize, const QSize &deviceSize) const
1275 {
1276     static const int desktopWidth = 980;
1277
1278     float devicePixelRatio = qt_defaultDpi() / WebCore::ViewportArguments::deprecatedTargetDPI;
1279
1280     WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(viewportArguments(), desktopWidth, deviceSize.width(), deviceSize.height(), devicePixelRatio, availableSize);
1281     WebCore::restrictMinimumScaleFactorToViewportSize(conf, availableSize, devicePixelRatio);
1282     WebCore::restrictScaleFactorToInitialScaleIfNotUserScalable(conf);
1283
1284     page->setDeviceScaleFactor(devicePixelRatio);
1285     QWebPageAdapter::ViewportAttributes result;
1286
1287     result.size = QSizeF(conf.layoutSize.width(), conf.layoutSize.height());
1288     result.initialScaleFactor = conf.initialScale;
1289     result.minimumScaleFactor = conf.minimumScale;
1290     result.maximumScaleFactor = conf.maximumScale;
1291     result.devicePixelRatio = devicePixelRatio;
1292     result.isUserScalable = static_cast<bool>(conf.userScalable);
1293
1294     return result;
1295 }
1296
1297
1298 bool QWebPageAdapter::handleKeyEvent(QKeyEvent *ev)
1299 {
1300     Frame* frame = page->focusController()->focusedOrMainFrame();
1301     return frame->eventHandler()->keyEvent(PlatformKeyboardEvent(ev, m_useNativeVirtualKeyAsDOMKey));
1302 }
1303
1304 bool QWebPageAdapter::handleScrolling(QKeyEvent *ev)
1305 {
1306     Frame* frame = page->focusController()->focusedOrMainFrame();
1307     WebCore::ScrollDirection direction;
1308     WebCore::ScrollGranularity granularity;
1309
1310 #ifndef QT_NO_SHORTCUT
1311     if (ev == QKeySequence::MoveToNextPage) {
1312         granularity = WebCore::ScrollByPage;
1313         direction = WebCore::ScrollDown;
1314     } else if (ev == QKeySequence::MoveToPreviousPage) {
1315         granularity = WebCore::ScrollByPage;
1316         direction = WebCore::ScrollUp;
1317     } else
1318 #endif // QT_NO_SHORTCUT
1319     if ((ev->key() == Qt::Key_Up && ev->modifiers() & Qt::ControlModifier) || ev->key() == Qt::Key_Home) {
1320         granularity = WebCore::ScrollByDocument;
1321         direction = WebCore::ScrollUp;
1322     } else if ((ev->key() == Qt::Key_Down && ev->modifiers() & Qt::ControlModifier) || ev->key() == Qt::Key_End) {
1323         granularity = WebCore::ScrollByDocument;
1324         direction = WebCore::ScrollDown;
1325     } else {
1326         switch (ev->key()) {
1327         case Qt::Key_Up:
1328             granularity = WebCore::ScrollByLine;
1329             direction = WebCore::ScrollUp;
1330             break;
1331         case Qt::Key_Down:
1332             granularity = WebCore::ScrollByLine;
1333             direction = WebCore::ScrollDown;
1334             break;
1335         case Qt::Key_Left:
1336             granularity = WebCore::ScrollByLine;
1337             direction = WebCore::ScrollLeft;
1338             break;
1339         case Qt::Key_Right:
1340             granularity = WebCore::ScrollByLine;
1341             direction = WebCore::ScrollRight;
1342             break;
1343         default:
1344             return false;
1345         }
1346     }
1347
1348     return frame->eventHandler()->scrollRecursively(direction, granularity);
1349 }
1350
1351 void QWebPageAdapter::focusInEvent(QFocusEvent *)
1352 {
1353     FocusController* focusController = page->focusController();
1354     focusController->setActive(true);
1355     focusController->setFocused(true);
1356     if (!focusController->focusedFrame())
1357         focusController->setFocusedFrame(mainFrameAdapter()->frame);
1358 }
1359
1360 void QWebPageAdapter::focusOutEvent(QFocusEvent *)
1361 {
1362     // only set the focused frame inactive so that we stop painting the caret
1363     // and the focus frame. But don't tell the focus controller so that upon
1364     // focusInEvent() we can re-activate the frame.
1365     FocusController* focusController = page->focusController();
1366     // Call setFocused first so that window.onblur doesn't get called twice
1367     focusController->setFocused(false);
1368     focusController->setActive(false);
1369 }
1370
1371 bool QWebPageAdapter::handleShortcutOverrideEvent(QKeyEvent* event)
1372 {
1373     WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
1374     WebCore::Editor& editor = frame->editor();
1375     if (!editor.canEdit())
1376         return false;
1377     if (event->modifiers() == Qt::NoModifier
1378         || event->modifiers() == Qt::ShiftModifier
1379         || event->modifiers() == Qt::KeypadModifier) {
1380         if (event->key() < Qt::Key_Escape)
1381             event->accept();
1382         else {
1383             switch (event->key()) {
1384             case Qt::Key_Return:
1385             case Qt::Key_Enter:
1386             case Qt::Key_Delete:
1387             case Qt::Key_Home:
1388             case Qt::Key_End:
1389             case Qt::Key_Backspace:
1390             case Qt::Key_Left:
1391             case Qt::Key_Right:
1392             case Qt::Key_Up:
1393             case Qt::Key_Down:
1394             case Qt::Key_Tab:
1395                 event->accept();
1396             default:
1397                 break;
1398             }
1399         }
1400     }
1401     return true;
1402 }
1403
1404 bool QWebPageAdapter::touchEvent(QTouchEvent* event)
1405 {
1406 #if ENABLE(TOUCH_EVENTS)
1407     Frame* frame = mainFrameAdapter()->frame;
1408     if (!frame->view())
1409         return false;
1410
1411     // Always accept the QTouchEvent so that we'll receive also TouchUpdate and TouchEnd events
1412     event->setAccepted(true);
1413
1414     // Return whether the default action was cancelled in the JS event handler
1415     return frame->eventHandler()->handleTouchEvent(convertTouchEvent(event));
1416 #else
1417     event->ignore();
1418     return false;
1419 #endif
1420 }
1421
1422 bool QWebPageAdapter::swallowContextMenuEvent(QContextMenuEvent *event, QWebFrameAdapter *webFrame)
1423 {
1424     // Check the first and last enum values match at least, since we cast.
1425     ASSERT(int(QWebPageAdapter::ScrollUp) == int(WebCore::ScrollUp));
1426     ASSERT(int(QWebPageAdapter::ScrollRight) == int(WebCore::ScrollRight));
1427     ASSERT(int(QWebPageAdapter::ScrollByLine) == int(WebCore::ScrollByLine));
1428     ASSERT(int(QWebPageAdapter::ScrollByDocument) == int(WebCore::ScrollByDocument));
1429
1430     page->contextMenuController()->clearContextMenu();
1431
1432     if (webFrame) {
1433         Frame* frame = webFrame->frame;
1434         if (Scrollbar* scrollBar = frame->view()->scrollbarAtPoint(convertMouseEvent(event, 1).position())) {
1435             bool horizontal = (scrollBar->orientation() == HorizontalScrollbar);
1436             QWebPageAdapter::ScrollDirection direction = QWebPageAdapter::InvalidScrollDirection;
1437             QWebPageAdapter::ScrollGranularity granularity = QWebPageAdapter::InvalidScrollGranularity;
1438             bool scroll = handleScrollbarContextMenuEvent(event, horizontal, &direction, &granularity);
1439             if (!scroll)
1440                 return true;
1441             if (direction == QWebPageAdapter::InvalidScrollDirection || granularity == QWebPageAdapter::InvalidScrollGranularity) {
1442                 ScrollbarTheme* theme = scrollBar->theme();
1443                 // Set the pressed position to the middle of the thumb so that when we
1444                 // do move, the delta will be from the current pixel position of the
1445                 // thumb to the new position
1446                 int position = theme->trackPosition(scrollBar) + theme->thumbPosition(scrollBar) + theme->thumbLength(scrollBar) / 2;
1447                 scrollBar->setPressedPos(position);
1448                 const QPoint pos = scrollBar->convertFromContainingWindow(event->pos());
1449                 scrollBar->moveThumb(horizontal ? pos.x() : pos.y());
1450             } else
1451                 scrollBar->scrollableArea()->scroll(WebCore::ScrollDirection(direction), WebCore::ScrollGranularity(granularity));
1452             return true;
1453         }
1454     }
1455
1456     WebCore::Frame* focusedFrame = page->focusController()->focusedOrMainFrame();
1457     focusedFrame->eventHandler()->sendContextMenuEvent(convertMouseEvent(event, 1));
1458     ContextMenu* menu = page->contextMenuController()->contextMenu();
1459     // If the website defines its own handler then sendContextMenuEvent takes care of
1460     // calling/showing it and the context menu pointer will be zero. This is the case
1461     // on maps.google.com for example.
1462
1463     return !menu;
1464 }