2 * Copyright (C) 2010 Nokia Corporation 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 program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public License
15 * along with this program; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 #include "qwkpage_p.h"
24 #include "qwkpreferences_p.h"
26 #include "ChunkedUpdateDrawingAreaProxy.h"
27 #include "ClientImpl.h"
28 #include "qgraphicswkview.h"
29 #include "qwkcontext.h"
30 #include "qwkcontext_p.h"
31 #include "qwkhistory.h"
32 #include "qwkhistory_p.h"
33 #include "FindIndicator.h"
34 #include "LocalizedStrings.h"
35 #include "NativeWebKeyboardEvent.h"
36 #include "TiledDrawingAreaProxy.h"
37 #include "WebContext.h"
38 #include "WebContextMenuProxyQt.h"
39 #include "WebEventFactoryQt.h"
40 #include "WebPopupMenuProxyQt.h"
41 #include "WKStringQt.h"
43 #include "ViewportArguments.h"
45 #include <QApplication>
46 #include <QGraphicsSceneMouseEvent>
48 #include <QTouchEvent>
50 #include <WebCore/Cursor.h>
51 #include <WebCore/FloatRect.h>
52 #include <WebKit2/WKFrame.h>
53 #include <WebKit2/WKPageGroup.h>
54 #include <WebKit2/WKRetainPtr.h>
56 using namespace WebKit;
57 using namespace WebCore;
59 static WebCore::ContextMenuAction contextMenuActionForWebAction(QWKPage::WebAction action)
62 case QWKPage::OpenLink:
63 return WebCore::ContextMenuItemTagOpenLink;
64 case QWKPage::OpenLinkInNewWindow:
65 return WebCore::ContextMenuItemTagOpenLinkInNewWindow;
66 case QWKPage::CopyLinkToClipboard:
67 return WebCore::ContextMenuItemTagCopyLinkToClipboard;
68 case QWKPage::OpenImageInNewWindow:
69 return WebCore::ContextMenuItemTagOpenImageInNewWindow;
71 return WebCore::ContextMenuItemTagCut;
73 return WebCore::ContextMenuItemTagCopy;
75 return WebCore::ContextMenuItemTagPaste;
76 case QWKPage::SelectAll:
77 return WebCore::ContextMenuItemTagSelectAll;
82 return WebCore::ContextMenuItemTagNoAction;
85 QWKPagePrivate::QWKPagePrivate(QWKPage* qq, QWKContext* c)
91 , backingStoreType(QGraphicsWKView::Simple)
93 memset(actions, 0, sizeof(actions));
94 page = context->d->context->createWebPage(this, 0);
95 history = QWKHistoryPrivate::createHistory(page->backForwardList());
98 QWKPagePrivate::~QWKPagePrivate()
104 void QWKPagePrivate::init(QGraphicsItem* view, QGraphicsWKView::BackingStoreType backingStoreType)
107 this->backingStoreType = backingStoreType;
108 page->initializeWebPage();
111 void QWKPagePrivate::setCursor(const WebCore::Cursor& cursor)
114 emit q->cursorChanged(*cursor.platformCursor());
118 void QWKPagePrivate::setViewportArguments(const ViewportArguments& args)
120 viewportArguments = args;
121 emit q->viewportChangeRequested();
124 void QWKPagePrivate::takeFocus(bool direction)
126 emit q->focusNextPrevChild(direction);
129 PassOwnPtr<DrawingAreaProxy> QWKPagePrivate::createDrawingAreaProxy()
131 // FIXME: We should avoid this cast by decoupling the view from the page.
132 QGraphicsWKView* wkView = static_cast<QGraphicsWKView*>(view);
134 #if ENABLE(TILED_BACKING_STORE)
135 if (backingStoreType == QGraphicsWKView::Tiled)
136 return TiledDrawingAreaProxy::create(wkView, page.get());
138 return ChunkedUpdateDrawingAreaProxy::create(wkView, page.get());
141 void QWKPagePrivate::setViewNeedsDisplay(const WebCore::IntRect& rect)
143 view->update(QRect(rect));
146 void QWKPagePrivate::displayView()
151 void QWKPagePrivate::scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset)
156 WebCore::IntSize QWKPagePrivate::viewSize()
159 return WebCore::IntSize();
162 bool QWKPagePrivate::isViewWindowActive()
168 bool QWKPagePrivate::isViewFocused()
174 bool QWKPagePrivate::isViewVisible()
180 bool QWKPagePrivate::isViewInWindow()
186 void QWKPagePrivate::pageDidRequestScroll(const IntSize& delta)
188 emit q->scrollRequested(delta.width(), delta.height());
191 void QWKPagePrivate::didChangeContentsSize(const IntSize& newSize)
193 emit q->contentsSizeChanged(QSize(newSize));
196 void QWKPagePrivate::toolTipChanged(const String&, const String& newTooltip)
198 emit q->statusBarMessage(QString(newTooltip));
201 void QWKPagePrivate::registerEditCommand(PassRefPtr<WebEditCommandProxy>, WebPageProxy::UndoOrRedo)
205 void QWKPagePrivate::clearAllEditCommands()
209 FloatRect QWKPagePrivate::convertToDeviceSpace(const FloatRect& rect)
214 FloatRect QWKPagePrivate::convertToUserSpace(const FloatRect& rect)
219 void QWKPagePrivate::selectionChanged(bool, bool, bool, bool)
223 void QWKPagePrivate::didNotHandleKeyEvent(const NativeWebKeyboardEvent&)
227 PassRefPtr<WebPopupMenuProxy> QWKPagePrivate::createPopupMenuProxy(WebPageProxy*)
229 return WebPopupMenuProxyQt::create();
232 PassRefPtr<WebContextMenuProxy> QWKPagePrivate::createContextMenuProxy(WebPageProxy*)
234 return WebContextMenuProxyQt::create(q);
237 void QWKPagePrivate::setFindIndicator(PassRefPtr<FindIndicator>, bool fadeOut)
241 void QWKPagePrivate::didCommitLoadForMainFrame(bool useCustomRepresentation)
245 void QWKPagePrivate::didFinishLoadingDataForCustomRepresentation(const CoreIPC::DataReference&)
249 void QWKPagePrivate::paint(QPainter* painter, QRect area)
251 if (page->isValid() && page->drawingArea())
252 page->drawingArea()->paint(IntRect(area), painter);
254 painter->fillRect(area, Qt::white);
257 void QWKPagePrivate::keyPressEvent(QKeyEvent* ev)
259 page->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
262 void QWKPagePrivate::keyReleaseEvent(QKeyEvent* ev)
264 page->handleKeyboardEvent(NativeWebKeyboardEvent(ev));
267 void QWKPagePrivate::mouseMoveEvent(QGraphicsSceneMouseEvent* ev)
269 // For some reason mouse press results in mouse hover (which is
270 // converted to mouse move for WebKit). We ignore these hover
271 // events by comparing lastPos with newPos.
272 // NOTE: lastPos from the event always comes empty, so we work
274 static QPointF lastPos = QPointF();
275 if (lastPos == ev->pos())
279 WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 0);
280 page->handleMouseEvent(mouseEvent);
283 void QWKPagePrivate::mousePressEvent(QGraphicsSceneMouseEvent* ev)
285 if (tripleClickTimer.isActive() && (ev->pos() - tripleClick).manhattanLength() < QApplication::startDragDistance()) {
286 WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 3);
287 page->handleMouseEvent(mouseEvent);
291 WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 1);
292 page->handleMouseEvent(mouseEvent);
295 void QWKPagePrivate::mouseReleaseEvent(QGraphicsSceneMouseEvent* ev)
297 WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 0);
298 page->handleMouseEvent(mouseEvent);
301 void QWKPagePrivate::mouseDoubleClickEvent(QGraphicsSceneMouseEvent* ev)
303 WebMouseEvent mouseEvent = WebEventFactory::createWebMouseEvent(ev, 2);
304 page->handleMouseEvent(mouseEvent);
306 tripleClickTimer.start(QApplication::doubleClickInterval(), q);
307 tripleClick = ev->pos().toPoint();
310 void QWKPagePrivate::wheelEvent(QGraphicsSceneWheelEvent* ev)
312 WebWheelEvent wheelEvent = WebEventFactory::createWebWheelEvent(ev);
313 page->handleWheelEvent(wheelEvent);
316 void QWKPagePrivate::setEditCommandState(const WTF::String&, bool, int)
320 void QWKPagePrivate::updateAction(QWKPage::WebAction action)
325 QAction* a = actions[action];
329 RefPtr<WebKit::WebFrameProxy> mainFrame = page->mainFrame();
333 bool enabled = a->isEnabled();
334 bool checked = a->isChecked();
338 enabled = page->canGoBack();
340 case QWKPage::Forward:
341 enabled = page->canGoForward();
344 enabled = !(WebFrameProxy::LoadStateFinished == mainFrame->loadState());
346 case QWKPage::Reload:
347 enabled = (WebFrameProxy::LoadStateFinished == mainFrame->loadState());
353 a->setEnabled(enabled);
355 if (a->isCheckable())
356 a->setChecked(checked);
357 #endif // QT_NO_ACTION
360 void QWKPagePrivate::updateNavigationActions()
362 updateAction(QWKPage::Back);
363 updateAction(QWKPage::Forward);
364 updateAction(QWKPage::Stop);
365 updateAction(QWKPage::Reload);
369 void QWKPagePrivate::_q_webActionTriggered(bool checked)
371 QAction* a = qobject_cast<QAction*>(q->sender());
374 QWKPage::WebAction action = static_cast<QWKPage::WebAction>(a->data().toInt());
375 q->triggerAction(action, checked);
377 #endif // QT_NO_ACTION
379 void QWKPagePrivate::touchEvent(QTouchEvent* event)
381 #if ENABLE(TOUCH_EVENTS)
382 WebTouchEvent touchEvent = WebEventFactory::createWebTouchEvent(event);
383 page->handleTouchEvent(touchEvent);
389 void QWKPagePrivate::didRelaunchProcess()
391 QGraphicsWKView* wkView = static_cast<QGraphicsWKView*>(view);
393 q->setViewportSize(wkView->size().toSize());
396 QWKPage::QWKPage(QWKContext* context)
397 : d(new QWKPagePrivate(this, context))
399 WKPageLoaderClient loadClient = {
401 this, /* clientInfo */
402 qt_wk_didStartProvisionalLoadForFrame,
403 qt_wk_didReceiveServerRedirectForProvisionalLoadForFrame,
404 qt_wk_didFailProvisionalLoadWithErrorForFrame,
405 qt_wk_didCommitLoadForFrame,
406 qt_wk_didFinishDocumentLoadForFrame,
407 qt_wk_didFinishLoadForFrame,
408 qt_wk_didFailLoadWithErrorForFrame,
409 0, /* didSameDocumentNavigationForFrame */
410 qt_wk_didReceiveTitleForFrame,
411 qt_wk_didFirstLayoutForFrame,
412 qt_wk_didFirstVisuallyNonEmptyLayoutForFrame,
413 qt_wk_didRemoveFrameFromHierarchy,
414 0, /* didDisplayInsecureContentForFrame */
415 0, /* didRunInsecureContentForFrame */
416 0, /* canAuthenticateAgainstProtectionSpaceInFrame */
417 0, /* didReceiveAuthenticationChallengeInFrame */
418 qt_wk_didStartProgress,
419 qt_wk_didChangeProgress,
420 qt_wk_didFinishProgress,
421 qt_wk_didBecomeUnresponsive,
422 qt_wk_didBecomeResponsive,
423 0, /* processDidCrash */
424 0 /* didChangeBackForwardList */
426 WKPageSetPageLoaderClient(pageRef(), &loadClient);
428 WKPageUIClient uiClient = {
430 this, /* clientInfo */
434 qt_wk_runJavaScriptAlert,
435 0, /* runJavaScriptConfirm */
436 0, /* runJavaScriptPrompt */
437 0, /* setStatusText */
438 0, /* mouseDidMoveOverElement */
439 0, /* missingPluginButtonClicked */
440 0, /* didNotHandleKeyEvent */
441 0, /* toolbarsAreVisible */
442 0, /* setToolbarsAreVisible */
443 0, /* menuBarIsVisible */
444 0, /* setMenuBarIsVisible */
445 0, /* statusBarIsVisible */
446 0, /* setStatusBarIsVisible */
448 0, /* setIsResizable */
449 0, /* getWindowFrame */
450 0, /* setWindowFrame */
451 0, /* runBeforeUnloadConfirmPanel */
453 0, /* pageDidScroll */
454 0, /* exceededDatabaseQuota */
455 0, /* runOpenPanel */
456 0, /* decidePolicyForGeolocationPermissionRequest */
457 0, /* headerHeight */
458 0, /* footerHeight */
464 WKPageSetPageUIClient(pageRef(), &uiClient);
472 QWKPage::ViewportAttributes::ViewportAttributes()
474 , m_initialScaleFactor(-1.0)
475 , m_minimumScaleFactor(-1.0)
476 , m_maximumScaleFactor(-1.0)
477 , m_devicePixelRatio(-1.0)
478 , m_isUserScalable(true)
484 QWKPage::ViewportAttributes::ViewportAttributes(const QWKPage::ViewportAttributes& other)
486 , m_initialScaleFactor(other.m_initialScaleFactor)
487 , m_minimumScaleFactor(other.m_minimumScaleFactor)
488 , m_maximumScaleFactor(other.m_maximumScaleFactor)
489 , m_devicePixelRatio(other.m_devicePixelRatio)
490 , m_isUserScalable(other.m_isUserScalable)
491 , m_isValid(other.m_isValid)
492 , m_size(other.m_size)
497 QWKPage::ViewportAttributes::~ViewportAttributes()
502 QWKPage::ViewportAttributes& QWKPage::ViewportAttributes::operator=(const QWKPage::ViewportAttributes& other)
504 if (this != &other) {
506 m_initialScaleFactor = other.m_initialScaleFactor;
507 m_minimumScaleFactor = other.m_minimumScaleFactor;
508 m_maximumScaleFactor = other.m_maximumScaleFactor;
509 m_devicePixelRatio = other.m_devicePixelRatio;
510 m_isUserScalable = other.m_isUserScalable;
511 m_isValid = other.m_isValid;
512 m_size = other.m_size;
518 QWKPage::ViewportAttributes QWKPage::viewportAttributesForSize(const QSize& availableSize) const
520 static int desktopWidth = 980;
521 static int deviceDPI = 160;
523 ViewportAttributes result;
525 if (availableSize.isEmpty())
526 return result; // Returns an invalid instance.
528 // FIXME: Add a way to get these data via the platform plugin and fall back
529 // to the size of the view.
530 int deviceWidth = 480;
531 int deviceHeight = 864;
533 WebCore::ViewportAttributes conf = WebCore::computeViewportAttributes(d->viewportArguments, desktopWidth, deviceWidth, deviceHeight, deviceDPI, availableSize);
535 result.m_isValid = true;
536 result.m_size = conf.layoutSize;
537 result.m_initialScaleFactor = conf.initialScale;
538 result.m_minimumScaleFactor = conf.minimumScale;
539 result.m_maximumScaleFactor = conf.maximumScale;
540 result.m_devicePixelRatio = conf.devicePixelRatio;
541 result.m_isUserScalable = conf.userScalable;
546 void QWKPage::setActualVisibleContentsRect(const QRect& rect) const
548 #if ENABLE(TILED_BACKING_STORE)
549 d->page->setActualVisibleContentRect(rect);
553 void QWKPage::timerEvent(QTimerEvent* ev)
555 int timerId = ev->timerId();
556 if (timerId == d->tripleClickTimer.timerId())
557 d->tripleClickTimer.stop();
559 QObject::timerEvent(ev);
562 WKPageRef QWKPage::pageRef() const
564 return toAPI(d->page.get());
567 QWKContext* QWKPage::context() const
572 QWKPreferences* QWKPage::preferences() const
574 if (!d->preferences) {
575 WKPageGroupRef pageGroupRef = WKPageGetPageGroup(pageRef());
576 d->preferences = QWKPreferencesPrivate::createPreferences(pageGroupRef);
579 return d->preferences;
582 void QWKPage::setCreateNewPageFunction(CreateNewPageFn function)
584 d->createNewPageFn = function;
587 void QWKPage::setCustomUserAgent(const QString& userAgent)
589 WKRetainPtr<WKStringRef> wkUserAgent(WKStringCreateWithQString(userAgent));
590 WKPageSetCustomUserAgent(pageRef(), wkUserAgent.get());
593 QString QWKPage::customUserAgent() const
595 return WKStringCopyQString(WKPageCopyCustomUserAgent(pageRef()));
598 void QWKPage::load(const QUrl& url)
600 WKRetainPtr<WKURLRef> wkurl(WKURLCreateWithQUrl(url));
601 WKPageLoadURL(pageRef(), wkurl.get());
604 void QWKPage::setUrl(const QUrl& url)
609 QUrl QWKPage::url() const
611 WKRetainPtr<WKFrameRef> frame = WKPageGetMainFrame(pageRef());
614 return WKURLCopyQUrl(WKFrameCopyURL(frame.get()));
617 QString QWKPage::title() const
619 return WKStringCopyQString(WKPageCopyTitle(pageRef()));
622 void QWKPage::setViewportSize(const QSize& size)
624 if (d->page->drawingArea())
625 d->page->drawingArea()->setSize(IntSize(size));
628 qreal QWKPage::textZoomFactor() const
630 return WKPageGetTextZoomFactor(pageRef());
633 void QWKPage::setTextZoomFactor(qreal zoomFactor)
635 WKPageSetTextZoomFactor(pageRef(), zoomFactor);
638 qreal QWKPage::pageZoomFactor() const
640 return WKPageGetPageZoomFactor(pageRef());
643 void QWKPage::setPageZoomFactor(qreal zoomFactor)
645 WKPageSetPageZoomFactor(pageRef(), zoomFactor);
648 void QWKPage::setPageAndTextZoomFactors(qreal pageZoomFactor, qreal textZoomFactor)
650 WKPageSetPageAndTextZoomFactors(pageRef(), pageZoomFactor, textZoomFactor);
653 QWKHistory* QWKPage::history() const
658 void QWKPage::setResizesToContentsUsingLayoutSize(const QSize& targetLayoutSize)
660 #if ENABLE(TILED_BACKING_STORE)
661 d->page->setResizesToContentsUsingLayoutSize(targetLayoutSize);
666 void QWKPage::triggerAction(WebAction webAction, bool)
673 d->page->goForward();
676 d->page->stopLoading();
679 d->page->reload(/* reloadFromOrigin */ true);
685 QAction* qtAction = action(webAction);
686 WebKit::WebContextMenuItemData menuItemData(ActionType, contextMenuActionForWebAction(webAction), qtAction->text(), qtAction->isEnabled(), qtAction->isChecked());
687 d->page->contextMenuItemSelected(menuItemData);
689 #endif // QT_NO_ACTION
692 QAction* QWKPage::action(WebAction action) const
694 if (action == QWKPage::NoWebAction || action >= WebActionCount)
697 if (d->actions[action])
698 return d->actions[action];
702 QStyle* style = qobject_cast<QApplication*>(QCoreApplication::instance())->style();
703 bool checkable = false;
707 text = contextMenuItemTagOpenLink();
709 case OpenLinkInNewWindow:
710 text = contextMenuItemTagOpenLinkInNewWindow();
712 case CopyLinkToClipboard:
713 text = contextMenuItemTagCopyLinkToClipboard();
715 case OpenImageInNewWindow:
716 text = contextMenuItemTagOpenImageInNewWindow();
719 text = contextMenuItemTagGoBack();
720 icon = style->standardIcon(QStyle::SP_ArrowBack);
723 text = contextMenuItemTagGoForward();
724 icon = style->standardIcon(QStyle::SP_ArrowForward);
727 text = contextMenuItemTagStop();
728 icon = style->standardIcon(QStyle::SP_BrowserStop);
731 text = contextMenuItemTagReload();
732 icon = style->standardIcon(QStyle::SP_BrowserReload);
735 text = contextMenuItemTagCut();
738 text = contextMenuItemTagCopy();
741 text = contextMenuItemTagPaste();
744 text = contextMenuItemTagSelectAll();
754 QAction* a = new QAction(d->q);
757 a->setCheckable(checkable);
760 connect(a, SIGNAL(triggered(bool)), this, SLOT(_q_webActionTriggered(bool)));
762 d->actions[action] = a;
763 d->updateAction(action);
766 #endif // QT_NO_ACTION
768 void QWKPage::findZoomableAreaForPoint(const QPoint& point)
770 d->page->findZoomableAreaForPoint(point);
773 void QWKPagePrivate::didFindZoomableArea(const IntRect& area)
775 emit q->zoomableAreaFound(QRect(area));
778 #include "moc_qwkpage.cpp"