2 * Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
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.
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.
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.
22 #include "QWebPageAdapter.h"
24 #include "CSSComputedStyleDeclaration.h"
25 #include "CSSParser.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 "DeviceMotionClientQt.h"
34 #include "DeviceOrientationClientMock.h"
35 #include "DeviceOrientationClientQt.h"
37 #include "DocumentLoader.h"
38 #include "DragClientQt.h"
39 #include "DragController.h"
41 #include "DragSession.h"
42 #include "EditorClientQt.h"
43 #include "FocusController.h"
44 #include "FrameView.h"
45 #if ENABLE(GEOLOCATION)
46 #include "GeolocationClientMock.h"
47 #include "GeolocationClientQt.h"
48 #include "GeolocationController.h"
50 #include "GeolocationPermissionClientQt.h"
51 #include "HTMLFrameOwnerElement.h"
52 #include "HTMLInputElement.h"
53 #include "HitTestResult.h"
54 #include "InitWebCoreQt.h"
55 #include "InspectorClientQt.h"
56 #include "InspectorController.h"
57 #include "InspectorServerQt.h"
58 #include "LocalizedStrings.h"
59 #include "MIMETypeRegistry.h"
60 #include "MemoryCache.h"
61 #include "NetworkingContext.h"
63 #include "NotificationPresenterClientQt.h"
64 #include "PageGroup.h"
65 #include "Pasteboard.h"
66 #include "PlatformKeyboardEvent.h"
67 #include "PlatformTouchEvent.h"
68 #include "PlatformWheelEvent.h"
69 #include "PluginDatabase.h"
70 #include "PluginPackage.h"
71 #include "ProgressTracker.h"
72 #include "QWebFrameAdapter.h"
73 #include "RenderTextControl.h"
74 #include "SchemeRegistry.h"
75 #include "Scrollbar.h"
76 #include "ScrollbarTheme.h"
78 #include "UndoStepQt.h"
79 #include "UserAgentQt.h"
80 #include "WebEventConversion.h"
81 #include "WebKitVersion.h"
82 #include "WindowFeatures.h"
83 #include "qwebhistory_p.h"
84 #include "qwebpluginfactory.h"
85 #include "qwebsettings.h"
88 #include <QGuiApplication>
90 #include <QMouseEvent>
91 #include <QNetworkAccessManager>
92 #include <QStyleHints>
93 #include <QTextCharFormat>
94 #include <QTouchEvent>
95 #include <QWheelEvent>
97 // from text/qfont.cpp
99 extern Q_GUI_EXPORT int qt_defaultDpi();
102 using namespace WebCore;
104 bool QWebPageAdapter::drtRun = false;
106 typedef QWebPageAdapter::MenuItemDescription MenuItem;
108 static inline DragOperation dropActionToDragOp(Qt::DropActions actions)
111 if (actions & Qt::CopyAction)
112 result |= DragOperationCopy;
113 // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
114 // hence it should be considered as "move"
115 if (actions & Qt::MoveAction)
116 result |= (DragOperationMove | DragOperationGeneric);
117 if (actions & Qt::LinkAction)
118 result |= DragOperationLink;
119 if (result == (DragOperationCopy | DragOperationMove | DragOperationGeneric | DragOperationLink))
120 result = DragOperationEvery;
121 return (DragOperation)result;
124 static inline Qt::DropAction dragOpToDropAction(unsigned actions)
126 Qt::DropAction result = Qt::IgnoreAction;
127 if (actions & DragOperationCopy)
128 result = Qt::CopyAction;
129 else if (actions & DragOperationMove)
130 result = Qt::MoveAction;
131 // DragOperationgeneric represents InternetExplorer's equivalent of Move operation,
132 // hence it should be considered as "move"
133 else if (actions & DragOperationGeneric)
134 result = Qt::MoveAction;
135 else if (actions & DragOperationLink)
136 result = Qt::LinkAction;
140 static WebCore::FrameLoadRequest frameLoadRequest(const QUrl &url, WebCore::Frame *frame)
142 return WebCore::FrameLoadRequest(frame->document()->securityOrigin(),
143 WebCore::ResourceRequest(url, frame->loader()->outgoingReferrer()));
146 static void openNewWindow(const QUrl& url, Frame* frame)
148 if (Page* oldPage = frame->page()) {
149 WindowFeatures features;
150 NavigationAction action;
151 FrameLoadRequest request = frameLoadRequest(url, frame);
152 if (Page* newPage = oldPage->chrome()->createWindow(frame, request, features, action)) {
153 newPage->mainFrame()->loader()->loadFrameRequest(request, false, false, 0, 0, MaybeSendReferrer);
154 newPage->chrome()->show();
159 QWebPageAdapter::QWebPageAdapter()
163 , forwardUnsupportedContent(false)
164 , insideOpenCall(false)
165 , clickCausedFocus(false)
170 WebCore::initializeWebCoreQt();
173 void QWebPageAdapter::initializeWebCorePage()
175 #if ENABLE(GEOLOCATION) || ENABLE(DEVICE_ORIENTATION)
176 bool useMock = QWebPageAdapter::drtRun;
178 Page::PageClients pageClients;
179 pageClients.chromeClient = new ChromeClientQt(this);
180 pageClients.contextMenuClient = new ContextMenuClientQt();
181 pageClients.editorClient = new EditorClientQt(this);
182 pageClients.dragClient = new DragClientQt(pageClients.chromeClient);
183 pageClients.inspectorClient = new InspectorClientQt(this);
184 page = new Page(pageClients);
185 #if ENABLE(GEOLOCATION)
187 // In case running in DumpRenderTree mode set the controller to mock provider.
188 GeolocationClientMock* mock = new GeolocationClientMock;
189 WebCore::provideGeolocationTo(page, mock);
190 mock->setController(WebCore::GeolocationController::from(page));
192 WebCore::provideGeolocationTo(page, new GeolocationClientQt(this));
194 #if ENABLE(DEVICE_ORIENTATION)
196 WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientMock);
198 WebCore::provideDeviceOrientationTo(page, new DeviceOrientationClientQt);
199 WebCore::provideDeviceMotionTo(page, new DeviceMotionClientQt);
202 // By default each page is put into their own unique page group, which affects popup windows
203 // and visited links. Page groups (per process only) is a feature making it possible to use
204 // separate settings for each group, so that for instance an integrated browser/email reader
205 // can use different settings for displaying HTML pages and HTML email. To make QtWebKit work
206 // as expected out of the box, we use a default group similar to what other ports are doing.
207 page->setGroupName("Default Group");
209 page->addLayoutMilestones(DidFirstVisuallyNonEmptyLayout);
211 settings = new QWebSettings(page->settings());
213 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
214 WebCore::provideNotification(page, NotificationPresenterClientQt::notificationPresenter());
217 history.d = new QWebHistoryPrivate(static_cast<WebCore::BackForwardListImpl*>(page->backForwardList()));
219 PageGroup::setShouldTrackVisitedLinks(true);
222 QWebPageAdapter::~QWebPageAdapter()
227 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
228 NotificationPresenterClientQt::notificationPresenter()->removeClient();
232 void QWebPageAdapter::deletePage()
234 // Before we delete the page, detach the mainframe's loader
235 FrameLoader* loader = mainFrameAdapter()->frame->loader();
237 loader->detachFromParent();
242 QWebPageAdapter* QWebPageAdapter::kit(Page* page)
244 return static_cast<ChromeClientQt*>(page->chrome()->client())->m_webPage;
247 ViewportArguments QWebPageAdapter::viewportArguments() const
249 return page ? page->viewportArguments() : WebCore::ViewportArguments();
253 void QWebPageAdapter::registerUndoStep(WTF::PassRefPtr<WebCore::UndoStep> step)
255 createUndoStep(QSharedPointer<UndoStepQt>(new UndoStepQt(step)));
258 void QWebPageAdapter::setNetworkAccessManager(QNetworkAccessManager *manager)
260 if (manager == networkManager)
262 if (networkManager && networkManager->parent() == handle())
263 delete networkManager;
264 networkManager = manager;
267 QNetworkAccessManager* QWebPageAdapter::networkAccessManager()
270 networkManager = new QNetworkAccessManager(handle());
271 return networkManager;
274 bool QWebPageAdapter::hasSelection() const
276 Frame* frame = page->focusController()->focusedOrMainFrame();
278 return (frame->selection()->selection().selectionType() != VisibleSelection::NoSelection);
282 QString QWebPageAdapter::selectedText() const
284 Frame* frame = page->focusController()->focusedOrMainFrame();
285 if (frame->selection()->selection().selectionType() == VisibleSelection::NoSelection)
287 return frame->editor()->selectedText();
290 QString QWebPageAdapter::selectedHtml() const
292 return page->focusController()->focusedOrMainFrame()->editor()->selectedRange()->toHTML();
295 bool QWebPageAdapter::isContentEditable() const
297 return page->isEditable();
300 void QWebPageAdapter::setContentEditable(bool editable)
302 page->setEditable(editable);
303 page->setTabKeyCyclesThroughElements(!editable);
305 Frame* frame = mainFrameAdapter()->frame;
307 frame->editor()->applyEditingStyleToBodyElement();
308 // FIXME: mac port calls this if there is no selectedDOMRange
309 // frame->setSelectionFromNone();
314 bool QWebPageAdapter::findText(const QString& subString, FindFlag options)
316 ::TextCaseSensitivity caseSensitivity = ::TextCaseInsensitive;
317 if (options & FindCaseSensitively)
318 caseSensitivity = ::TextCaseSensitive;
320 if (options & HighlightAllOccurrences) {
321 if (subString.isEmpty()) {
322 page->unmarkAllTextMatches();
325 return page->markAllMatchesForText(subString, caseSensitivity, true, 0);
328 if (subString.isEmpty()) {
329 page->mainFrame()->selection()->clear();
330 Frame* frame = page->mainFrame()->tree()->firstChild();
332 frame->selection()->clear();
333 frame = frame->tree()->traverseNextWithWrap(false);
336 ::FindDirection direction = ::FindDirectionForward;
337 if (options & FindBackward)
338 direction = ::FindDirectionBackward;
340 const bool shouldWrap = options & FindWrapsAroundDocument;
342 return page->findString(subString, caseSensitivity, direction, shouldWrap);
345 void QWebPageAdapter::adjustPointForClicking(QMouseEvent* ev)
347 QtPlatformPlugin platformPlugin;
348 OwnPtr<QWebTouchModifier> touchModifier = platformPlugin.createTouchModifier();
352 unsigned topPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Up);
353 unsigned rightPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Right);
354 unsigned bottomPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Down);
355 unsigned leftPadding = touchModifier->hitTestPaddingForTouch(QWebTouchModifier::Left);
357 touchModifier = nullptr;
359 if (!topPadding && !rightPadding && !bottomPadding && !leftPadding)
362 Document* startingDocument = page->mainFrame()->document();
363 if (!startingDocument)
366 IntPoint originalPoint(ev->pos());
367 TouchAdjuster touchAdjuster(topPadding, rightPadding, bottomPadding, leftPadding);
368 IntPoint adjustedPoint = touchAdjuster.findCandidatePointForTouch(originalPoint, startingDocument);
369 if (adjustedPoint == IntPoint::zero())
371 QMouseEvent* ret = new QMouseEvent(ev->type(), QPoint(adjustedPoint), ev->globalPos(), ev->button(), ev->buttons(), ev->modifiers());
376 static bool hasMouseListener(Element* element)
379 return element->hasEventListeners(eventNames().clickEvent)
380 || element->hasEventListeners(eventNames().mousedownEvent)
381 || element->hasEventListeners(eventNames().mouseupEvent);
384 static bool isClickableElement(Element* element, PassRefPtr<NodeList> prpList)
387 RefPtr<NodeList> list = prpList;
388 bool isClickable = hasMouseListener(element);
389 if (!isClickable && list) {
390 Element* parent = element->parentElement();
391 unsigned count = list->length();
392 for (unsigned i = 0; i < count && parent; i++) {
393 if (list->item(i) != parent)
396 isClickable = hasMouseListener(parent);
400 parent = parent->parentElement();
404 ExceptionCode ec = 0;
406 || element->webkitMatchesSelector("a,*:link,*:visited,*[role=button],button,input,select,label", ec)
407 || CSSComputedStyleDeclaration::create(element)->getPropertyValue(cssPropertyID("cursor")) == "pointer";
410 static bool isValidFrameOwner(Element* element)
413 return element->isFrameOwnerElement() && static_cast<HTMLFrameOwnerElement*>(element)->contentFrame();
416 QWebPageAdapter::TouchAdjuster::TouchAdjuster(unsigned topPadding, unsigned rightPadding, unsigned bottomPadding, unsigned leftPadding)
417 : m_topPadding(topPadding)
418 , m_rightPadding(rightPadding)
419 , m_bottomPadding(bottomPadding)
420 , m_leftPadding(leftPadding)
424 IntPoint QWebPageAdapter::TouchAdjuster::findCandidatePointForTouch(const IntPoint& touchPoint, Document* document) const
429 int x = touchPoint.x();
430 int y = touchPoint.y();
432 RefPtr<NodeList> intersectedNodes = document->nodesFromRect(x, y, m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding, false /*ignoreClipping*/, false /*allowShadowContent*/);
433 if (!intersectedNodes)
436 Element* closestClickableElement = 0;
437 IntRect largestIntersectionRect;
438 FrameView* view = document->frame()->view();
440 // Touch rect in contents coordinates.
441 IntRect touchRect(HitTestLocation::rectForPoint(view->windowToContents(IntPoint(x, y)), m_topPadding, m_rightPadding, m_bottomPadding, m_leftPadding));
443 // Iterate over the list of nodes hit looking for the one whose bounding area
444 // has largest intersection with the touch area (point + padding).
445 for (unsigned i = 0; i < intersectedNodes->length(); i++) {
446 Node* currentNode = intersectedNodes->item(i);
448 Element* currentElement = currentNode->isElementNode() ? toElement(currentNode) : 0;
449 if (!currentElement || (!isClickableElement(currentElement, 0) && !isValidFrameOwner(currentElement)))
452 IntRect currentElementBoundingRect = currentElement->pixelSnappedBoundingBox();
453 currentElementBoundingRect.intersect(touchRect);
455 if (currentElementBoundingRect.isEmpty())
458 int currentIntersectionRectArea = currentElementBoundingRect.width() * currentElementBoundingRect.height();
459 int largestIntersectionRectArea = largestIntersectionRect.width() * largestIntersectionRect.height();
460 if (currentIntersectionRectArea > largestIntersectionRectArea) {
461 closestClickableElement = currentElement;
462 largestIntersectionRect = currentElementBoundingRect;
466 if (largestIntersectionRect.isEmpty())
469 // Handle the case when user taps a inner frame. It is done in three steps:
470 // 1) Transform the original touch point to the inner document coordinates;
471 // 1) Call nodesFromRect for the inner document in case;
472 // 3) Re-add the inner frame offset (location) before passing the new clicking
473 // position to WebCore.
474 if (closestClickableElement->isFrameOwnerElement()) {
475 // Adjust client coordinates' origin to be top left of inner frame viewport.
476 RefPtr<ClientRect> rect = closestClickableElement->getBoundingClientRect();
477 IntPoint newTouchPoint = touchPoint;
478 IntSize offset = IntSize(rect->left(), rect->top());
479 newTouchPoint -= offset;
481 HTMLFrameOwnerElement* owner = static_cast<HTMLFrameOwnerElement*>(closestClickableElement);
482 Document* childDocument = owner->contentFrame()->document();
483 return findCandidatePointForTouch(newTouchPoint, childDocument);
485 return view->contentsToWindow(largestIntersectionRect).center();
488 void QWebPageAdapter::mouseMoveEvent(QMouseEvent* ev)
490 WebCore::Frame* frame = mainFrameAdapter()->frame;
494 bool accepted = frame->eventHandler()->mouseMoved(convertMouseEvent(ev, 0));
495 ev->setAccepted(accepted);
498 void QWebPageAdapter::mousePressEvent(QMouseEvent* ev)
500 WebCore::Frame* frame = mainFrameAdapter()->frame;
504 RefPtr<WebCore::Node> oldNode;
505 Frame* focusedFrame = page->focusController()->focusedFrame();
506 if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
507 oldNode = focusedDocument->focusedNode();
509 if (tripleClickTimer.isActive()
510 && (ev->pos() - tripleClick).manhattanLength() < qGuiApp->styleHints()->startDragDistance()) {
511 mouseTripleClickEvent(ev);
515 bool accepted = false;
516 PlatformMouseEvent mev = convertMouseEvent(ev, 1);
517 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
518 if (mev.button() != NoButton)
519 accepted = frame->eventHandler()->handleMousePressEvent(mev);
520 ev->setAccepted(accepted);
522 RefPtr<WebCore::Node> newNode;
523 focusedFrame = page->focusController()->focusedFrame();
524 if (Document* focusedDocument = focusedFrame ? focusedFrame->document() : 0)
525 newNode = focusedDocument->focusedNode();
527 if (newNode && oldNode != newNode)
528 clickCausedFocus = true;
531 void QWebPageAdapter::mouseDoubleClickEvent(QMouseEvent *ev)
533 WebCore::Frame* frame = mainFrameAdapter()->frame;
537 bool accepted = false;
538 PlatformMouseEvent mev = convertMouseEvent(ev, 2);
539 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
540 if (mev.button() != NoButton)
541 accepted = frame->eventHandler()->handleMousePressEvent(mev);
542 ev->setAccepted(accepted);
544 tripleClickTimer.start(qGuiApp->styleHints()->mouseDoubleClickInterval(), handle());
545 tripleClick = QPointF(ev->pos()).toPoint();
548 void QWebPageAdapter::mouseTripleClickEvent(QMouseEvent *ev)
550 WebCore::Frame* frame = mainFrameAdapter()->frame;
554 bool accepted = false;
555 PlatformMouseEvent mev = convertMouseEvent(ev, 3);
556 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
557 if (mev.button() != NoButton)
558 accepted = frame->eventHandler()->handleMousePressEvent(mev);
559 ev->setAccepted(accepted);
562 void QWebPageAdapter::mouseReleaseEvent(QMouseEvent *ev)
564 WebCore::Frame* frame = mainFrameAdapter()->frame;
568 bool accepted = false;
569 PlatformMouseEvent mev = convertMouseEvent(ev, 0);
570 // ignore the event if we can't map Qt's mouse buttons to WebCore::MouseButton
571 if (mev.button() != NoButton)
572 accepted = frame->eventHandler()->handleMouseReleaseEvent(mev);
573 ev->setAccepted(accepted);
575 handleSoftwareInputPanel(ev->button(), QPointF(ev->pos()).toPoint());
578 void QWebPageAdapter::handleSoftwareInputPanel(Qt::MouseButton button, const QPoint& pos)
580 Frame* frame = page->focusController()->focusedFrame();
584 if (client && client->inputMethodEnabled()
585 && frame->document()->focusedNode()
586 && button == Qt::LeftButton && qGuiApp->property("autoSipEnabled").toBool()) {
587 if (!clickCausedFocus || requestSoftwareInputPanel()) {
588 HitTestResult result = frame->eventHandler()->hitTestResultAtPoint(frame->view()->windowToContents(pos), false);
589 if (result.isContentEditable()) {
590 QEvent event(QEvent::RequestSoftwareInputPanel);
591 QGuiApplication::sendEvent(client->ownerWidget(), &event);
596 clickCausedFocus = false;
599 #ifndef QT_NO_WHEELEVENT
600 void QWebPageAdapter::wheelEvent(QWheelEvent *ev, int wheelScrollLines)
602 WebCore::Frame* frame = mainFrameAdapter()->frame;
606 PlatformWheelEvent pev = convertWheelEvent(ev, wheelScrollLines);
607 bool accepted = frame->eventHandler()->handleWheelEvent(pev);
608 ev->setAccepted(accepted);
610 #endif // QT_NO_WHEELEVENT
612 #ifndef QT_NO_DRAGANDDROP
614 Qt::DropAction QWebPageAdapter::dragEntered(const QMimeData *data, const QPoint &pos, Qt::DropActions possibleActions)
616 DragData dragData(data, pos, QCursor::pos(), dropActionToDragOp(possibleActions));
617 return dragOpToDropAction(page->dragController()->dragEntered(&dragData).operation);
620 void QWebPageAdapter::dragLeaveEvent()
622 DragData dragData(0, IntPoint(), QCursor::pos(), DragOperationNone);
623 page->dragController()->dragExited(&dragData);
626 Qt::DropAction QWebPageAdapter::dragUpdated(const QMimeData *data, const QPoint &pos, Qt::DropActions possibleActions)
628 DragData dragData(data, pos, QCursor::pos(), dropActionToDragOp(possibleActions));
629 return dragOpToDropAction(page->dragController()->dragUpdated(&dragData).operation);
632 bool QWebPageAdapter::performDrag(const QMimeData *data, const QPoint &pos, Qt::DropActions possibleActions)
634 DragData dragData(data, pos, QCursor::pos(), dropActionToDragOp(possibleActions));
635 return page->dragController()->performDrag(&dragData);
638 void QWebPageAdapter::inputMethodEvent(QInputMethodEvent *ev)
640 WebCore::Frame *frame = page->focusController()->focusedOrMainFrame();
641 WebCore::Editor *editor = frame->editor();
643 if (!editor->canEdit()) {
649 if (frame->selection()->rootEditableElement())
650 node = frame->selection()->rootEditableElement()->shadowAncestorNode();
652 Vector<CompositionUnderline> underlines;
653 bool hasSelection = false;
655 for (int i = 0; i < ev->attributes().size(); ++i) {
656 const QInputMethodEvent::Attribute& a = ev->attributes().at(i);
658 case QInputMethodEvent::TextFormat: {
659 QTextCharFormat textCharFormat = a.value.value<QTextFormat>().toCharFormat();
660 QColor qcolor = textCharFormat.underlineColor();
661 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));
664 case QInputMethodEvent::Cursor: {
665 frame->selection()->setCaretVisible(a.length); // if length is 0 cursor is invisible
667 RenderObject* caretRenderer = frame->selection()->caretRenderer();
669 QColor qcolor = a.value.value<QColor>();
670 caretRenderer->style()->setColor(Color(makeRGBA(qcolor.red(), qcolor.green(), qcolor.blue(), qcolor.alpha())));
675 case QInputMethodEvent::Selection: {
677 // A selection in the inputMethodEvent is always reflected in the visible text
679 if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
680 textControl->setSelectionRange(qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
683 if (!ev->preeditString().isEmpty())
684 editor->setComposition(ev->preeditString(), underlines, qMin(a.start, (a.start + a.length)), qMax(a.start, (a.start + a.length)));
686 // If we are in the middle of a composition, an empty pre-edit string and a selection of zero
687 // cancels the current composition
688 if (editor->hasComposition() && !(a.start + a.length))
689 editor->setComposition(QString(), underlines, 0, 0);
698 if (node && ev->replacementLength() > 0) {
699 int cursorPos = frame->selection()->extent().offsetInContainerNode();
700 int start = cursorPos + ev->replacementStart();
701 if (HTMLTextFormControlElement* textControl = toTextFormControl(node))
702 textControl->setSelectionRange(start, start + ev->replacementLength());
703 // Commit regardless of whether commitString is empty, to get rid of selection.
704 editor->confirmComposition(ev->commitString());
705 } else if (!ev->commitString().isEmpty()) {
706 if (editor->hasComposition())
707 editor->confirmComposition(ev->commitString());
709 editor->insertText(ev->commitString(), 0);
710 } else if (!hasSelection && !ev->preeditString().isEmpty())
711 editor->setComposition(ev->preeditString(), underlines, 0, 0);
712 else if (ev->preeditString().isEmpty() && editor->hasComposition())
713 editor->confirmComposition(String());
718 QVariant QWebPageAdapter::inputMethodQuery(Qt::InputMethodQuery property) const
720 Frame* frame = page->focusController()->focusedFrame();
724 WebCore::Editor* editor = frame->editor();
726 RenderObject* renderer = 0;
727 RenderTextControl* renderTextControl = 0;
729 if (frame->selection()->rootEditableElement())
730 renderer = frame->selection()->rootEditableElement()->shadowAncestorNode()->renderer();
732 if (renderer && renderer->isTextControl())
733 renderTextControl = toRenderTextControl(renderer);
736 case Qt::ImMicroFocus: {
737 WebCore::FrameView* view = frame->view();
738 if (view && view->needsLayout()) {
739 // We can't access absoluteCaretBounds() while the view needs to layout.
742 return QVariant(view->contentsToWindow(frame->selection()->absoluteCaretBounds()));
745 if (renderTextControl) {
746 RenderStyle* renderStyle = renderTextControl->style();
747 return QVariant(QFont(renderStyle->font().syntheticFont()));
749 return QVariant(QFont());
751 case Qt::ImCursorPosition: {
752 if (editor->hasComposition())
753 return QVariant(frame->selection()->end().offsetInContainerNode());
754 return QVariant(frame->selection()->extent().offsetInContainerNode());
756 case Qt::ImSurroundingText: {
757 if (renderTextControl && renderTextControl->textFormControlElement()) {
758 QString text = renderTextControl->textFormControlElement()->value();
759 RefPtr<Range> range = editor->compositionRange();
761 text.remove(range->startPosition().offsetInContainerNode(), TextIterator::rangeLength(range.get()));
762 return QVariant(text);
766 case Qt::ImCurrentSelection: {
767 if (!editor->hasComposition() && renderTextControl && renderTextControl->textFormControlElement()) {
768 int start = frame->selection()->start().offsetInContainerNode();
769 int end = frame->selection()->end().offsetInContainerNode();
771 return QVariant(QString(renderTextControl->textFormControlElement()->value()).mid(start, end - start));
776 case Qt::ImAnchorPosition: {
777 if (editor->hasComposition())
778 return QVariant(frame->selection()->start().offsetInContainerNode());
779 return QVariant(frame->selection()->base().offsetInContainerNode());
781 case Qt::ImMaximumTextLength: {
782 if (frame->selection()->isContentEditable()) {
783 if (frame->document() && frame->document()->focusedNode()) {
784 if (frame->document()->focusedNode()->hasTagName(HTMLNames::inputTag)) {
785 HTMLInputElement* inputElement = static_cast<HTMLInputElement*>(frame->document()->focusedNode());
786 return QVariant(inputElement->maxLength());
789 return QVariant(HTMLInputElement::maximumLength);
800 double deferredRepaintDelay;
801 double initialDeferredRepaintDelayDuringLoading;
802 double maxDeferredRepaintDelayDuringLoading;
803 double deferredRepaintDelayIncrementDuringLoading;
804 } QRepaintThrottlingPreset;
806 void QWebPageAdapter::dynamicPropertyChangeEvent(QObject* obj, QDynamicPropertyChangeEvent* event)
808 if (event->propertyName() == "_q_viewMode") {
809 page->setViewMode(Page::stringToViewMode(obj->property("_q_viewMode").toString()));
810 } else if (event->propertyName() == "_q_HTMLTokenizerChunkSize") {
811 int chunkSize = obj->property("_q_HTMLTokenizerChunkSize").toInt();
812 page->setCustomHTMLTokenizerChunkSize(chunkSize);
813 } else if (event->propertyName() == "_q_HTMLTokenizerTimeDelay") {
814 double timeDelay = obj->property("_q_HTMLTokenizerTimeDelay").toDouble();
815 page->setCustomHTMLTokenizerTimeDelay(timeDelay);
816 } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelay") {
817 double p = obj->property("_q_RepaintThrottlingDeferredRepaintDelay").toDouble();
818 FrameView::setRepaintThrottlingDeferredRepaintDelay(p);
819 } else if (event->propertyName() == "_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading") {
820 double p = obj->property("_q_RepaintThrottlingnInitialDeferredRepaintDelayDuringLoading").toDouble();
821 FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(p);
822 } else if (event->propertyName() == "_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading") {
823 double p = obj->property("_q_RepaintThrottlingMaxDeferredRepaintDelayDuringLoading").toDouble();
824 FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(p);
825 } else if (event->propertyName() == "_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading") {
826 double p = obj->property("_q_RepaintThrottlingDeferredRepaintDelayIncrementDuringLoading").toDouble();
827 FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(p);
828 } else if (event->propertyName() == "_q_RepaintThrottlingPreset") {
829 static const QRepaintThrottlingPreset presets[] = {
830 { "NoThrottling", 0, 0, 0, 0 },
831 { "Legacy", 0.025, 0, 2.5, 0.5 },
832 { "Minimal", 0.01, 0, 1, 0.2 },
833 { "Medium", 0.025, 1, 5, 0.5 },
834 { "Heavy", 0.1, 2, 10, 1 }
837 QString p = obj->property("_q_RepaintThrottlingPreset").toString();
838 for (size_t i = 0; i < sizeof(presets) / sizeof(presets[0]); i++) {
839 if (p == QLatin1String(presets[i].name)) {
840 FrameView::setRepaintThrottlingDeferredRepaintDelay(presets[i].deferredRepaintDelay);
841 FrameView::setRepaintThrottlingnInitialDeferredRepaintDelayDuringLoading(presets[i].initialDeferredRepaintDelayDuringLoading);
842 FrameView::setRepaintThrottlingMaxDeferredRepaintDelayDuringLoading(presets[i].maxDeferredRepaintDelayDuringLoading);
843 FrameView::setRepaintThrottlingDeferredRepaintDelayIncrementDuringLoading(presets[i].deferredRepaintDelayIncrementDuringLoading);
847 } else if (event->propertyName() == "_q_webInspectorServerPort") {
848 #if ENABLE(INSPECTOR)
849 QVariant port = obj->property("_q_webInspectorServerPort");
850 if (port.isValid()) {
851 InspectorServerQt* inspectorServer = InspectorServerQt::server();
852 inspectorServer->listen(port.toInt());
855 } else if (event->propertyName() == "_q_deadDecodedDataDeletionInterval") {
856 double interval = obj->property("_q_deadDecodedDataDeletionInterval").toDouble();
857 memoryCache()->setDeadDecodedDataDeletionInterval(interval);
861 #endif // QT_NO_DRAGANDDROP
863 #define MAP_ACTION_FROM_VALUE(Name, Value) \
864 case Value: return QWebPageAdapter::Name
866 static QWebPageAdapter::MenuAction adapterActionForContextMenuAction(WebCore::ContextMenuAction action)
869 FOR_EACH_MAPPED_MENU_ACTION(MAP_ACTION_FROM_VALUE, SEMICOLON_SEPARATOR);
870 #if ENABLE(INSPECTOR)
871 case WebCore::ContextMenuItemTagInspectElement:
872 return QWebPageAdapter::InspectElement;
877 return QWebPageAdapter::NoAction;
880 QList<MenuItem> descriptionForPlatformMenu(const QList<ContextMenuItem>* items, Page* page)
882 QList<MenuItem> itemDescriptions;
884 return itemDescriptions;
885 for (int i = 0; i < items->count(); ++i) {
886 const ContextMenuItem &item = items->at(i);
887 MenuItem description;
888 switch (item.type()) {
889 case WebCore::CheckableActionType: /* fall through */
890 case WebCore::ActionType: {
891 QWebPageAdapter::MenuAction action = adapterActionForContextMenuAction(item.action());
892 if (action > QWebPageAdapter::NoAction) {
893 description.type = MenuItem::Action;
894 description.action = action;
895 ContextMenuItem it(item);
896 page->contextMenuController()->checkOrEnableIfNeeded(it);
897 PlatformMenuItemDescription desc = it.releasePlatformDescription();
899 description.traits |= MenuItem::Enabled;
900 if (item.type() == WebCore::CheckableActionType) {
901 description.traits |= MenuItem::Checkable;
903 description.traits |= MenuItem::Checked;
908 case WebCore::SeparatorType:
909 description.type = MenuItem::Separator;
911 case WebCore::SubmenuType: {
912 description.type = MenuItem::SubMenu;
913 description.subMenu = descriptionForPlatformMenu(item.platformSubMenu(), page);
914 description.subMenuTitle = item.title();
915 // Don't append empty submenu descriptions.
916 if (description.subMenu.isEmpty())
920 if (description.type > MenuItem::NoType)
921 itemDescriptions.append(description);
923 return itemDescriptions;
926 QWebHitTestResultPrivate* QWebPageAdapter::updatePositionDependentMenuActions(const QPoint& pos, QBitArray* visitedWebActions)
928 ASSERT(visitedWebActions);
929 WebCore::Frame* focusedFrame = page->focusController()->focusedOrMainFrame();
930 HitTestResult result = focusedFrame->eventHandler()->hitTestResultAtPoint(focusedFrame->view()->windowToContents(pos), /*allowShadowContent*/ false);
931 page->contextMenuController()->setHitTestResult(result);
933 #if ENABLE(INSPECTOR)
934 if (page->inspectorController()->enabled())
935 page->contextMenuController()->addInspectElementItem();
938 WebCore::ContextMenu* webcoreMenu = page->contextMenuController()->contextMenu();
939 QList<MenuItem> itemDescriptions;
940 if (client && webcoreMenu)
941 itemDescriptions = descriptionForPlatformMenu(webcoreMenu->platformDescription(), page);
942 createAndSetCurrentContextMenu(itemDescriptions, visitedWebActions);
943 if (result.scrollbar())
945 return new QWebHitTestResultPrivate(result);
948 static void extractContentTypeFromHash(const HashSet<String>& types, QStringList* list)
953 HashSet<String>::const_iterator endIt = types.end();
954 for (HashSet<String>::const_iterator it = types.begin(); it != endIt; ++it)
958 static void extractContentTypeFromPluginVector(const Vector<PluginPackage*>& plugins, QStringList* list)
963 for (unsigned i = 0; i < plugins.size(); ++i) {
964 MIMEToDescriptionsMap::const_iterator it = plugins[i]->mimeToDescriptions().begin();
965 MIMEToDescriptionsMap::const_iterator end = plugins[i]->mimeToDescriptions().end();
966 for (; it != end; ++it)
971 QStringList QWebPageAdapter::supportedContentTypes() const
973 QStringList mimeTypes;
975 extractContentTypeFromHash(MIMETypeRegistry::getSupportedImageMIMETypes(), &mimeTypes);
976 extractContentTypeFromHash(MIMETypeRegistry::getSupportedNonImageMIMETypes(), &mimeTypes);
977 if (page->settings() && page->settings()->arePluginsEnabled())
978 extractContentTypeFromPluginVector(PluginDatabase::installedPlugins()->plugins(), &mimeTypes);
983 void QWebPageAdapter::_q_cleanupLeakMessages()
986 // Need this to make leak messages accurate.
987 memoryCache()->setCapacities(0, 0, 0);
991 void QWebPageAdapter::_q_onLoadProgressChanged(int)
993 m_totalBytes = page->progress()->totalPageAndResourceBytesToLoad();
994 m_bytesReceived = page->progress()->totalBytesReceived();
997 bool QWebPageAdapter::supportsContentType(const QString& mimeType) const
999 const String type = mimeType.toLower();
1000 if (MIMETypeRegistry::isSupportedImageMIMEType(type))
1003 if (MIMETypeRegistry::isSupportedNonImageMIMEType(type))
1006 if (page->settings() && page->settings()->arePluginsEnabled()
1007 && PluginDatabase::installedPlugins()->isMIMETypeRegistered(type))
1013 void QWebPageAdapter::didShowInspector()
1015 #if ENABLE(INSPECTOR)
1016 page->inspectorController()->show();
1020 void QWebPageAdapter::didCloseInspector()
1022 #if ENABLE(INSPECTOR)
1023 page->inspectorController()->close();
1027 void QWebPageAdapter::updateActionInternal(QWebPageAdapter::MenuAction action, const char* commandName, bool* enabled, bool* checked)
1029 WebCore::FrameLoader* loader = mainFrameAdapter()->frame->loader();
1030 WebCore::Editor* editor = page->focusController()->focusedOrMainFrame()->editor();
1033 case QWebPageAdapter::Back:
1034 *enabled = page->canGoBackOrForward(-1);
1036 case QWebPageAdapter::Forward:
1037 *enabled = page->canGoBackOrForward(1);
1039 case QWebPageAdapter::Stop:
1040 *enabled = loader->isLoading();
1042 case QWebPageAdapter::Reload:
1043 *enabled = !loader->isLoading();
1045 case QWebPageAdapter::SetTextDirectionDefault:
1046 case QWebPageAdapter::SetTextDirectionLeftToRight:
1047 case QWebPageAdapter::SetTextDirectionRightToLeft:
1048 *enabled = editor->canEdit();
1053 // if it's an editor command, let its logic determine state
1055 Editor::Command command = editor->command(commandName);
1056 *enabled = command.isEnabled();
1058 *checked = command.state() != FalseTriState;
1067 void QWebPageAdapter::triggerAction(QWebPageAdapter::MenuAction action, QWebHitTestResultPrivate* hitTestResult, const char* commandName, bool endToEndReload)
1069 Frame* frame = page->focusController()->focusedOrMainFrame();
1072 Editor* editor = frame->editor();
1075 QWebHitTestResultPrivate hitTest;
1077 hitTestResult = &hitTest;
1081 if (Frame* targetFrame = hitTestResult->webCoreFrame) {
1082 targetFrame->loader()->loadFrameRequest(frameLoadRequest(hitTestResult->linkUrl, targetFrame), /*lockHistory*/ false, /*lockBackForwardList*/ false, /*event*/ 0, /*FormState*/ 0, MaybeSendReferrer);
1086 case OpenLinkInNewWindow:
1087 openNewWindow(hitTestResult->linkUrl, frame);
1089 case OpenLinkInThisWindow:
1090 frame->loader()->loadFrameRequest(frameLoadRequest(hitTestResult->linkUrl, frame), /*lockHistory*/ false, /*lockBackForwardList*/ false, /*event*/ 0, /*FormState*/ 0, MaybeSendReferrer);
1092 case OpenFrameInNewWindow: {
1093 KURL url = frame->loader()->documentLoader()->unreachableURL();
1095 url = frame->loader()->documentLoader()->url();
1096 openNewWindow(url, frame);
1099 case CopyLinkToClipboard: {
1100 #if defined(Q_WS_X11)
1101 bool oldSelectionMode = Pasteboard::generalPasteboard()->isSelectionMode();
1102 Pasteboard::generalPasteboard()->setSelectionMode(true);
1103 editor->copyURL(hitTestResult->linkUrl, hitTestResult->linkText);
1104 Pasteboard::generalPasteboard()->setSelectionMode(oldSelectionMode);
1106 editor->copyURL(hitTestResult->linkUrl, hitTestResult->linkText);
1109 case OpenImageInNewWindow:
1110 openNewWindow(hitTestResult->imageUrl, frame);
1112 case DownloadImageToDisk:
1113 frame->loader()->client()->startDownload(WebCore::ResourceRequest(hitTestResult->imageUrl, frame->loader()->outgoingReferrer()));
1115 case DownloadLinkToDisk:
1116 frame->loader()->client()->startDownload(WebCore::ResourceRequest(hitTestResult->linkUrl, frame->loader()->outgoingReferrer()));
1125 mainFrameAdapter()->frame->loader()->stopForUserCancel();
1126 updateNavigationActions();
1129 mainFrameAdapter()->frame->loader()->reload(endToEndReload);
1132 case SetTextDirectionDefault:
1133 editor->setBaseWritingDirection(NaturalWritingDirection);
1135 case SetTextDirectionLeftToRight:
1136 editor->setBaseWritingDirection(LeftToRightWritingDirection);
1138 case SetTextDirectionRightToLeft:
1139 editor->setBaseWritingDirection(RightToLeftWritingDirection);
1141 #if ENABLE(INSPECTOR)
1142 case InspectElement: {
1143 ASSERT(hitTestResult != &hitTest);
1144 page->inspectorController()->inspect(hitTestResult->innerNonSharedNode);
1150 editor->command(commandName).execute();
1156 QString QWebPageAdapter::contextMenuItemTagForAction(QWebPageAdapter::MenuAction action, bool* checkable) const
1161 return contextMenuItemTagOpenLink();
1162 case OpenLinkInNewWindow:
1163 return contextMenuItemTagOpenLinkInNewWindow();
1164 case OpenFrameInNewWindow:
1165 return contextMenuItemTagOpenFrameInNewWindow();
1166 case OpenLinkInThisWindow:
1167 return contextMenuItemTagOpenLinkInThisWindow();
1169 case DownloadLinkToDisk:
1170 return contextMenuItemTagDownloadLinkToDisk();
1171 case CopyLinkToClipboard:
1172 return contextMenuItemTagCopyLinkToClipboard();
1174 case OpenImageInNewWindow:
1175 return contextMenuItemTagOpenImageInNewWindow();
1176 case DownloadImageToDisk:
1177 return contextMenuItemTagDownloadImageToDisk();
1178 case CopyImageToClipboard:
1179 return contextMenuItemTagCopyImageToClipboard();
1180 case CopyImageUrlToClipboard:
1181 return contextMenuItemTagCopyImageUrlToClipboard();
1184 return contextMenuItemTagCut();
1186 return contextMenuItemTagCopy();
1188 return contextMenuItemTagPaste();
1190 return contextMenuItemTagSelectAll();
1193 return contextMenuItemTagGoBack();
1195 return contextMenuItemTagGoForward();
1197 return contextMenuItemTagReload();
1199 return contextMenuItemTagStop();
1201 case SetTextDirectionDefault:
1202 return contextMenuItemTagDefaultDirection();
1203 case SetTextDirectionLeftToRight:
1205 return contextMenuItemTagLeftToRight();
1206 case SetTextDirectionRightToLeft:
1208 return contextMenuItemTagRightToLeft();
1212 return contextMenuItemTagBold();
1215 return contextMenuItemTagItalic();
1216 case ToggleUnderline:
1218 return contextMenuItemTagUnderline();
1220 #if ENABLE(INSPECTOR)
1221 case InspectElement:
1222 return contextMenuItemTagInspectElement();
1225 ASSERT_NOT_REACHED();
1230 #if ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
1231 void QWebPageAdapter::allowNotificationsForFrame(QWebFrameAdapter* frame)
1233 NotificationPresenterClientQt::notificationPresenter()->allowNotificationForFrame(frame->frame);
1236 void QWebPageAdapter::addNotificationPresenterClient()
1238 NotificationPresenterClientQt::notificationPresenter()->addClient();
1241 #ifndef QT_NO_SYSTEMTRAYICON
1242 bool QWebPageAdapter::hasSystemTrayIcon() const
1244 return NotificationPresenterClientQt::notificationPresenter()->hasSystemTrayIcon();
1247 void QWebPageAdapter::setSystemTrayIcon(QObject *icon)
1249 NotificationPresenterClientQt::notificationPresenter()->setSystemTrayIcon(icon);
1251 #endif // QT_NO_SYSTEMTRAYICON
1252 #endif // ENABLE(NOTIFICATIONS) || ENABLE(LEGACY_NOTIFICATIONS)
1254 #if ENABLE(GEOLOCATION)
1255 void QWebPageAdapter::setGeolocationEnabledForFrame(QWebFrameAdapter* frame, bool on)
1257 GeolocationPermissionClientQt::geolocationPermissionClient()->setPermission(frame, on);
1262 QString QWebPageAdapter::defaultUserAgentString()
1264 return UserAgentQt::standardUserAgent("", WEBKIT_MAJOR_VERSION, WEBKIT_MINOR_VERSION);
1267 bool QWebPageAdapter::treatSchemeAsLocal(const QString& scheme)
1269 return WebCore::SchemeRegistry::shouldTreatURLSchemeAsLocal(scheme);
1272 QObject* QWebPageAdapter::currentFrame() const
1274 Frame* frame = page->focusController()->focusedOrMainFrame();
1275 return frame->loader()->networkingContext()->originatingObject();
1278 bool QWebPageAdapter::hasFocusedNode() const
1280 bool hasFocus = false;
1281 Frame* frame = page->focusController()->focusedFrame();
1283 Document* document = frame->document();
1284 hasFocus = document && document->focusedNode();
1289 QWebPageAdapter::ViewportAttributes QWebPageAdapter::viewportAttributesForSize(const QSize &availableSize, const QSize &deviceSize) const
1291 static const int desktopWidth = 980;
1293 float devicePixelRatio = qt_defaultDpi() / WebCore::ViewportArguments::deprecatedTargetDPI;
1295 WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(viewportArguments(), desktopWidth, deviceSize.width(), deviceSize.height(), devicePixelRatio, availableSize);
1296 WebCore::restrictMinimumScaleFactorToViewportSize(conf, availableSize, devicePixelRatio);
1297 WebCore::restrictScaleFactorToInitialScaleIfNotUserScalable(conf);
1299 page->setDeviceScaleFactor(devicePixelRatio);
1300 QWebPageAdapter::ViewportAttributes result;
1302 result.size = QSizeF(conf.layoutSize.width(), conf.layoutSize.height());
1303 result.initialScaleFactor = conf.initialScale;
1304 result.minimumScaleFactor = conf.minimumScale;
1305 result.maximumScaleFactor = conf.maximumScale;
1306 result.devicePixelRatio = devicePixelRatio;
1307 result.isUserScalable = static_cast<bool>(conf.userScalable);
1313 bool QWebPageAdapter::handleKeyEvent(QKeyEvent *ev)
1315 Frame* frame = page->focusController()->focusedOrMainFrame();
1316 return frame->eventHandler()->keyEvent(ev);
1319 bool QWebPageAdapter::handleScrolling(QKeyEvent *ev)
1321 Frame* frame = page->focusController()->focusedOrMainFrame();
1322 WebCore::ScrollDirection direction;
1323 WebCore::ScrollGranularity granularity;
1325 #ifndef QT_NO_SHORTCUT
1326 if (ev == QKeySequence::MoveToNextPage || (ev->key() == Qt::Key_Space && !(ev->modifiers() & Qt::ShiftModifier))) {
1327 granularity = WebCore::ScrollByPage;
1328 direction = WebCore::ScrollDown;
1329 } else if (ev == QKeySequence::MoveToPreviousPage || ((ev->key() == Qt::Key_Space) && (ev->modifiers() & Qt::ShiftModifier))) {
1330 granularity = WebCore::ScrollByPage;
1331 direction = WebCore::ScrollUp;
1333 #endif // QT_NO_SHORTCUT
1334 if ((ev->key() == Qt::Key_Up && ev->modifiers() & Qt::ControlModifier) || ev->key() == Qt::Key_Home) {
1335 granularity = WebCore::ScrollByDocument;
1336 direction = WebCore::ScrollUp;
1337 } else if ((ev->key() == Qt::Key_Down && ev->modifiers() & Qt::ControlModifier) || ev->key() == Qt::Key_End) {
1338 granularity = WebCore::ScrollByDocument;
1339 direction = WebCore::ScrollDown;
1341 switch (ev->key()) {
1343 granularity = WebCore::ScrollByLine;
1344 direction = WebCore::ScrollUp;
1347 granularity = WebCore::ScrollByLine;
1348 direction = WebCore::ScrollDown;
1351 granularity = WebCore::ScrollByLine;
1352 direction = WebCore::ScrollLeft;
1355 granularity = WebCore::ScrollByLine;
1356 direction = WebCore::ScrollRight;
1363 return frame->eventHandler()->scrollRecursively(direction, granularity);
1366 void QWebPageAdapter::focusInEvent(QFocusEvent *)
1368 FocusController* focusController = page->focusController();
1369 focusController->setActive(true);
1370 focusController->setFocused(true);
1371 if (!focusController->focusedFrame())
1372 focusController->setFocusedFrame(mainFrameAdapter()->frame);
1375 void QWebPageAdapter::focusOutEvent(QFocusEvent *)
1377 // only set the focused frame inactive so that we stop painting the caret
1378 // and the focus frame. But don't tell the focus controller so that upon
1379 // focusInEvent() we can re-activate the frame.
1380 FocusController* focusController = page->focusController();
1381 // Call setFocused first so that window.onblur doesn't get called twice
1382 focusController->setFocused(false);
1383 focusController->setActive(false);
1386 bool QWebPageAdapter::handleShortcutOverrideEvent(QKeyEvent* event)
1388 WebCore::Frame* frame = page->focusController()->focusedOrMainFrame();
1389 WebCore::Editor* editor = frame->editor();
1390 if (!editor->canEdit())
1392 if (event->modifiers() == Qt::NoModifier
1393 || event->modifiers() == Qt::ShiftModifier
1394 || event->modifiers() == Qt::KeypadModifier) {
1395 if (event->key() < Qt::Key_Escape)
1398 switch (event->key()) {
1399 case Qt::Key_Return:
1401 case Qt::Key_Delete:
1404 case Qt::Key_Backspace:
1419 bool QWebPageAdapter::touchEvent(QTouchEvent* event)
1421 #if ENABLE(TOUCH_EVENTS)
1422 Frame* frame = mainFrameAdapter()->frame;
1426 // Always accept the QTouchEvent so that we'll receive also TouchUpdate and TouchEnd events
1427 event->setAccepted(true);
1429 // Return whether the default action was cancelled in the JS event handler
1430 return frame->eventHandler()->handleTouchEvent(convertTouchEvent(event));
1437 bool QWebPageAdapter::swallowContextMenuEvent(QContextMenuEvent *event, QWebFrameAdapter *webFrame)
1439 // Check the first and last enum values match at least, since we cast.
1440 ASSERT(int(QWebPageAdapter::ScrollUp) == int(WebCore::ScrollUp));
1441 ASSERT(int(QWebPageAdapter::ScrollRight) == int(WebCore::ScrollRight));
1442 ASSERT(int(QWebPageAdapter::ScrollByLine) == int(WebCore::ScrollByLine));
1443 ASSERT(int(QWebPageAdapter::ScrollByDocument) == int(WebCore::ScrollByDocument));
1445 page->contextMenuController()->clearContextMenu();
1448 Frame* frame = webFrame->frame;
1449 if (Scrollbar* scrollBar = frame->view()->scrollbarAtPoint(convertMouseEvent(event, 1).position())) {
1450 bool horizontal = (scrollBar->orientation() == HorizontalScrollbar);
1451 QWebPageAdapter::ScrollDirection direction = QWebPageAdapter::InvalidScrollDirection;
1452 QWebPageAdapter::ScrollGranularity granularity = QWebPageAdapter::InvalidScrollGranularity;
1453 bool scroll = handleScrollbarContextMenuEvent(event, horizontal, &direction, &granularity);
1456 if (direction == QWebPageAdapter::InvalidScrollDirection || granularity == QWebPageAdapter::InvalidScrollGranularity) {
1457 ScrollbarTheme* theme = scrollBar->theme();
1458 // Set the pressed position to the middle of the thumb so that when we
1459 // do move, the delta will be from the current pixel position of the
1460 // thumb to the new position
1461 int position = theme->trackPosition(scrollBar) + theme->thumbPosition(scrollBar) + theme->thumbLength(scrollBar) / 2;
1462 scrollBar->setPressedPos(position);
1463 const QPoint pos = scrollBar->convertFromContainingWindow(event->pos());
1464 scrollBar->moveThumb(horizontal ? pos.x() : pos.y());
1466 scrollBar->scrollableArea()->scroll(WebCore::ScrollDirection(direction), WebCore::ScrollGranularity(granularity));
1471 WebCore::Frame* focusedFrame = page->focusController()->focusedOrMainFrame();
1472 focusedFrame->eventHandler()->sendContextMenuEvent(convertMouseEvent(event, 1));
1473 ContextMenu* menu = page->contextMenuController()->contextMenu();
1474 // If the website defines its own handler then sendContextMenuEvent takes care of
1475 // calling/showing it and the context menu pointer will be zero. This is the case
1476 // on maps.google.com for example.