/* * Copyright (C) 2010, 2011 Nokia Corporation and/or its subsidiary(-ies) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this program; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #include "config.h" #include "QtWebPageProxy.h" #include #include #include "qquickwebview_p.h" #include "qquickwebview_p_p.h" #include "qquickwebpage_p.h" #include "QtWebError.h" #include "qwebdownloaditem_p.h" #include "qwebdownloaditem_p_p.h" #include "qwebpreferences_p.h" #include "qwebpreferences_p_p.h" #include "DownloadProxy.h" #include "DrawingAreaProxyImpl.h" #include "qwkhistory.h" #include "qwkhistory_p.h" #include "FindIndicator.h" #include "LocalizedStrings.h" #include "NotImplemented.h" #include "QtDownloadManager.h" #include "QtWebPageEventHandler.h" #include "QtWebUndoCommand.h" #include "WebBackForwardList.h" #include "WebContext.h" #include "WebContextMenuProxyQt.h" #include "WebEditCommandProxy.h" #include "WebPopupMenuProxyQtDesktop.h" #include "WKStringQt.h" #include "WKURLQt.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace WebKit; using namespace WebCore; QtWebPageProxy::QtWebPageProxy(QQuickWebPage* qmlWebPage, QQuickWebView* qmlWebView, WKContextRef contextRef, WKPageGroupRef pageGroupRef) : m_qmlWebPage(qmlWebPage) , m_qmlWebView(qmlWebView) , m_context(contextRef ? QtWebContext::create(toImpl(contextRef)) : QtWebContext::defaultContext()) , m_undoStack(adoptPtr(new QUndoStack(this))) , m_navigatorQtObjectEnabled(false) { m_webPageProxy = m_context->createWebPage(this, toImpl(pageGroupRef)); m_history = QWKHistoryPrivate::createHistory(this, m_webPageProxy->backForwardList()); } void QtWebPageProxy::init(QtWebPageEventHandler* eventHandler) { m_eventHandler = eventHandler; m_webPageProxy->initializeWebPage(); } QtWebPageProxy::~QtWebPageProxy() { m_webPageProxy->close(); delete m_history; } void QtWebPageProxy::showContextMenu(QSharedPointer menu) { // Remove the active menu in case this function is called twice. if (activeMenu) activeMenu->hide(); if (menu->isEmpty()) return; QWindow* window = m_qmlWebView->canvas(); if (!window) return; activeMenu = menu; activeMenu->window()->winId(); // Ensure that the menu has a window Q_ASSERT(activeMenu->window()->windowHandle()); activeMenu->window()->windowHandle()->setTransientParent(window); QPoint menuPositionInScene = m_qmlWebView->mapToScene(menu->pos()).toPoint(); menu->exec(window->mapToGlobal(menuPositionInScene)); // The last function to get out of exec() clear the local copy. if (activeMenu == menu) activeMenu.clear(); } void QtWebPageProxy::hideContextMenu() { if (activeMenu) activeMenu->hide(); } void QtWebPageProxy::setCursor(const WebCore::Cursor& cursor) { // FIXME: This is a temporary fix until we get cursor support in QML items. QGuiApplication::setOverrideCursor(*cursor.platformCursor()); } void QtWebPageProxy::setCursorHiddenUntilMouseMoves(bool hiddenUntilMouseMoves) { notImplemented(); } void QtWebPageProxy::setViewNeedsDisplay(const WebCore::IntRect&) { m_qmlWebPage->update(); } void QtWebPageProxy::displayView() { // FIXME: Implement. } void QtWebPageProxy::scrollView(const WebCore::IntRect& scrollRect, const WebCore::IntSize& scrollOffset) { // FIXME: Implement. } WebCore::IntSize QtWebPageProxy::viewSize() { return WebCore::IntSize(m_qmlWebPage->width(), m_qmlWebPage->height()); } bool QtWebPageProxy::isViewWindowActive() { // FIXME: The scene graph does not have the concept of being active or not when this was written. return true; } bool QtWebPageProxy::isViewFocused() { return m_qmlWebView->hasFocus(); } bool QtWebPageProxy::isViewVisible() { return m_qmlWebView->isVisible() && m_qmlWebPage->isVisible(); } bool QtWebPageProxy::isViewInWindow() { // FIXME: Implement. return true; } void QtWebPageProxy::enterAcceleratedCompositingMode(const LayerTreeContext&) { // FIXME: Implement. } void QtWebPageProxy::exitAcceleratedCompositingMode() { // FIXME: Implement. } void QtWebPageProxy::pageDidRequestScroll(const IntPoint& pos) { m_qmlWebView->d_func()->scrollPositionRequested(pos); } void QtWebPageProxy::didChangeContentsSize(const IntSize& newSize) { m_qmlWebView->d_func()->didChangeContentsSize(newSize); } void QtWebPageProxy::didChangeViewportProperties(const WebCore::ViewportArguments& args) { m_qmlWebView->d_func()->didChangeViewportProperties(args); } void QtWebPageProxy::toolTipChanged(const String&, const String& newTooltip) { // There is not yet any UI defined for the tooltips for mobile so we ignore the change. } void QtWebPageProxy::registerEditCommand(PassRefPtr command, WebPageProxy::UndoOrRedo undoOrRedo) { if (undoOrRedo == WebPageProxy::Undo) { const QtWebUndoCommand* webUndoCommand = static_cast(m_undoStack->command(m_undoStack->index())); if (webUndoCommand && webUndoCommand->inUndoRedo()) return; m_undoStack->push(new QtWebUndoCommand(command)); } } void QtWebPageProxy::clearAllEditCommands() { m_undoStack->clear(); } bool QtWebPageProxy::canUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo) { if (undoOrRedo == WebPageProxy::Undo) return m_undoStack->canUndo(); return m_undoStack->canRedo(); } void QtWebPageProxy::executeUndoRedo(WebPageProxy::UndoOrRedo undoOrRedo) { if (undoOrRedo == WebPageProxy::Undo) m_undoStack->undo(); else m_undoStack->redo(); } FloatRect QtWebPageProxy::convertToDeviceSpace(const FloatRect& rect) { return rect; } IntPoint QtWebPageProxy::screenToWindow(const IntPoint& point) { return point; } IntRect QtWebPageProxy::windowToScreen(const IntRect& rect) { return rect; } FloatRect QtWebPageProxy::convertToUserSpace(const FloatRect& rect) { return rect; } void QtWebPageProxy::selectionChanged(bool, bool, bool, bool) { } void QtWebPageProxy::doneWithKeyEvent(const NativeWebKeyboardEvent&, bool) { } PassRefPtr QtWebPageProxy::createPopupMenuProxy(WebPageProxy*) { return WebPopupMenuProxyQtDesktop::create(m_webPageProxy.get(), m_qmlWebView); } PassRefPtr QtWebPageProxy::createContextMenuProxy(WebPageProxy*) { return WebContextMenuProxyQt::create(this); } void QtWebPageProxy::setFindIndicator(PassRefPtr, bool fadeOut, bool animate) { } void QtWebPageProxy::didCommitLoadForMainFrame(bool useCustomRepresentation) { } void QtWebPageProxy::didFinishLoadingDataForCustomRepresentation(const String& suggestedFilename, const CoreIPC::DataReference&) { } void QtWebPageProxy::flashBackingStoreUpdates(const Vector&) { notImplemented(); } WKPageRef QtWebPageProxy::pageRef() const { return toAPI(m_webPageProxy.get());; } void QtWebPageProxy::didFindZoomableArea(const IntPoint& target, const IntRect& area) { ASSERT(m_eventHandler); m_eventHandler->didFindZoomableArea(target, area); } void QtWebPageProxy::didReceiveMessageFromNavigatorQtObject(const String& message) { QVariantMap variantMap; variantMap.insert(QLatin1String("data"), QString(message)); variantMap.insert(QLatin1String("origin"), url()); emit receivedMessageFromNavigatorQtObject(variantMap); } bool QtWebPageProxy::canGoBack() const { return m_webPageProxy->canGoBack(); } void QtWebPageProxy::goBack() { m_webPageProxy->goBack(); } bool QtWebPageProxy::canGoForward() const { return m_webPageProxy->canGoForward(); } void QtWebPageProxy::goForward() { m_webPageProxy->goForward(); } bool QtWebPageProxy::canStop() const { RefPtr mainFrame = m_webPageProxy->mainFrame(); return mainFrame && !(WebFrameProxy::LoadStateFinished == mainFrame->loadState()); } void QtWebPageProxy::stop() { m_webPageProxy->stopLoading(); } bool QtWebPageProxy::canReload() const { RefPtr mainFrame = m_webPageProxy->mainFrame(); if (mainFrame) return (WebFrameProxy::LoadStateFinished == mainFrame->loadState()); return m_webPageProxy->backForwardList()->currentItem(); } void QtWebPageProxy::reload() { m_webPageProxy->reload(/* reloadFromOrigin */ true); } void QtWebPageProxy::updateNavigationState() { emit m_qmlWebView->navigationStateChanged(); } void QtWebPageProxy::didRelaunchProcess() { updateNavigationState(); qWarning("WARNING: The web process has been successfully restarted."); setDrawingAreaSize(viewSize()); } void QtWebPageProxy::processDidCrash() { updateNavigationState(); ASSERT(m_eventHandler); m_eventHandler->resetGestureRecognizers(); WebCore::KURL url(WebCore::ParsedURLString, m_webPageProxy->urlAtProcessExit()); qWarning("WARNING: The web process experienced a crash on '%s'.", qPrintable(QUrl(url).toString(QUrl::RemoveUserInfo))); } QWebPreferences* QtWebPageProxy::preferences() const { if (!m_preferences) m_preferences = adoptPtr(QWebPreferencesPrivate::createPreferences(const_cast(this))); return m_preferences.get(); } void QtWebPageProxy::setCustomUserAgent(const QString& userAgent) { WKRetainPtr wkUserAgent(WKStringCreateWithQString(userAgent)); WKPageSetCustomUserAgent(pageRef(), wkUserAgent.get()); } QString QtWebPageProxy::customUserAgent() const { return WKStringCopyQString(WKPageCopyCustomUserAgent(pageRef())); } void QtWebPageProxy::setNavigatorQtObjectEnabled(bool enabled) { ASSERT(enabled != m_navigatorQtObjectEnabled); // FIXME: Currently we have to keep this information in both processes and the setting is asynchronous. m_navigatorQtObjectEnabled = enabled; m_context->setNavigatorQtObjectEnabled(m_webPageProxy.get(), enabled); } void QtWebPageProxy::postMessageToNavigatorQtObject(const QString& message) { m_context->postMessageToNavigatorQtObject(m_webPageProxy.get(), message); } void QtWebPageProxy::loadHTMLString(const QString& html, const QUrl& baseUrl) { WKRetainPtr wkUrl(WKURLCreateWithQUrl(baseUrl)); WKRetainPtr wkHtmlString(WKStringCreateWithQString(html)); WKPageLoadHTMLString(pageRef(), wkHtmlString.get(), wkUrl.get()); } void QtWebPageProxy::load(const QUrl& url) { WKRetainPtr wkurl = adoptWK(WKURLCreateWithQUrl(url)); WKPageLoadURL(pageRef(), wkurl.get()); } QUrl QtWebPageProxy::url() const { WKRetainPtr frame = WKPageGetMainFrame(pageRef()); if (!frame) return QUrl(); return WKURLCopyQUrl(adoptWK(WKFrameCopyURL(frame.get())).get()); } QString QtWebPageProxy::title() const { return WKStringCopyQString(adoptWK(WKPageCopyTitle(toAPI(m_webPageProxy.get()))).get()); } void QtWebPageProxy::setDrawingAreaSize(const QSize& size) { if (!m_webPageProxy->drawingArea()) return; m_webPageProxy->drawingArea()->setSize(IntSize(size), IntSize()); } qreal QtWebPageProxy::textZoomFactor() const { return WKPageGetTextZoomFactor(pageRef()); } void QtWebPageProxy::setTextZoomFactor(qreal zoomFactor) { WKPageSetTextZoomFactor(pageRef(), zoomFactor); } qreal QtWebPageProxy::pageZoomFactor() const { return WKPageGetPageZoomFactor(pageRef()); } void QtWebPageProxy::setPageZoomFactor(qreal zoomFactor) { WKPageSetPageZoomFactor(pageRef(), zoomFactor); } void QtWebPageProxy::setPageAndTextZoomFactors(qreal pageZoomFactor, qreal textZoomFactor) { WKPageSetPageAndTextZoomFactors(pageRef(), pageZoomFactor, textZoomFactor); } QWKHistory* QtWebPageProxy::history() const { return m_history; } void QtWebPageProxy::startDrag(const WebCore::DragData& dragData, PassRefPtr dragImage) { QImage dragQImage; if (dragImage) dragQImage = dragImage->createQImage(); else if (dragData.platformData() && dragData.platformData()->hasImage()) dragQImage = qvariant_cast(dragData.platformData()->imageData()); DragOperation dragOperationMask = dragData.draggingSourceOperationMask(); QMimeData* mimeData = const_cast(dragData.platformData()); Qt::DropActions supportedDropActions = QtWebPageEventHandler::dragOperationToDropActions(dragOperationMask); QPoint clientPosition; QPoint globalPosition; Qt::DropAction actualDropAction = Qt::IgnoreAction; if (QWindow* window = m_qmlWebView->canvas()) { QDrag* drag = new QDrag(window); drag->setPixmap(QPixmap::fromImage(dragQImage)); drag->setMimeData(mimeData); actualDropAction = drag->exec(supportedDropActions); globalPosition = QCursor::pos(); clientPosition = window->mapFromGlobal(globalPosition); } m_webPageProxy->dragEnded(clientPosition, globalPosition, QtWebPageEventHandler::dropActionToDragOperation(actualDropAction)); } void QtWebPageProxy::handleDownloadRequest(DownloadProxy* download) { // This function is responsible for hooking up a DownloadProxy to our API layer // by creating a QWebDownloadItem. It will then wait for the QWebDownloadItem to be // ready (filled with the ResourceResponse information) so we can pass it through to // our WebViews. QWebDownloadItem* downloadItem = new QWebDownloadItem(); downloadItem->d->downloadProxy = download; connect(downloadItem->d, SIGNAL(receivedResponse(QWebDownloadItem*)), this, SLOT(didReceiveDownloadResponse(QWebDownloadItem*))); m_context->downloadManager()->addDownload(download, downloadItem); } void QtWebPageProxy::didReceiveDownloadResponse(QWebDownloadItem* downloadItem) { // Now that our downloadItem has everything we need we can emit downloadRequested. if (!downloadItem) return; QDeclarativeEngine::setObjectOwnership(downloadItem, QDeclarativeEngine::JavaScriptOwnership); emit m_qmlWebView->experimental()->downloadRequested(downloadItem); } PassOwnPtr QtWebPageProxy::createDrawingAreaProxy() { return DrawingAreaProxyImpl::create(m_webPageProxy.get()); } void QtWebPageProxy::renderToCurrentGLContext(const TransformationMatrix& transform, float opacity) { DrawingAreaProxy* drawingArea = m_webPageProxy->drawingArea(); if (drawingArea) drawingArea->paintToCurrentGLContext(transform, opacity); } #if ENABLE(TOUCH_EVENTS) void QtWebPageProxy::doneWithTouchEvent(const NativeWebTouchEvent& event, bool wasEventHandled) { ASSERT(m_eventHandler); m_eventHandler->doneWithTouchEvent(event, wasEventHandled); } #endif void QtWebPageProxy::setVisibleContentRectAndScale(const QRectF& visibleContentRect, float scale) { if (!m_webPageProxy->drawingArea()) return; QRect alignedVisibleContentRect = visibleContentRect.toAlignedRect(); m_webPageProxy->drawingArea()->setVisibleContentsRectAndScale(alignedVisibleContentRect, scale); // FIXME: Once we support suspend and resume, this should be delayed until the page is active if the page is suspended. m_webPageProxy->setFixedVisibleContentRect(alignedVisibleContentRect); } void QtWebPageProxy::setVisibleContentRectTrajectoryVector(const QPointF& trajectoryVector) { if (!m_webPageProxy->drawingArea()) return; m_webPageProxy->drawingArea()->setVisibleContentRectTrajectoryVector(trajectoryVector); } #include "moc_QtWebPageProxy.cpp"