2 * Copyright (C) 2006 Zack Rusin <zack@kde.org>
3 * Copyright (C) 2006 Apple Computer, Inc. All rights reserved.
4 * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
18 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
25 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "ChromeClientQt.h"
33 #include "ApplicationCacheStorage.h"
34 #include "DatabaseTracker.h"
35 #include "FileChooser.h"
37 #include "FrameLoadRequest.h"
38 #include "FrameLoader.h"
39 #include "FrameLoaderClientQt.h"
40 #include "FrameView.h"
41 #include "Geolocation.h"
42 #if USE(ACCELERATED_COMPOSITING)
43 #include "GraphicsLayer.h"
45 #include "GeolocationPermissionClientQt.h"
46 #include "HitTestResult.h"
48 #include "NavigationAction.h"
49 #include "NetworkingContext.h"
50 #include "NotImplemented.h"
51 #include "NotificationPresenterClientQt.h"
52 #include "PageClientQt.h"
53 #include "PopupMenuQt.h"
54 #if defined(Q_WS_MAEMO_5)
55 #include "QtMaemoWebPopup.h"
57 #include "QtFallbackWebPopup.h"
59 #include "QWebPageClient.h"
60 #include "ScrollbarTheme.h"
61 #include "SearchPopupMenuQt.h"
62 #include "SecurityOrigin.h"
63 #include "ViewportArguments.h"
64 #include "WindowFeatures.h"
66 #include "qgraphicswebview.h"
67 #include "qwebframe_p.h"
69 #include "qwebpage_p.h"
70 #include "qwebsecurityorigin.h"
71 #include "qwebsecurityorigin_p.h"
74 #include <qeventloop.h>
75 #include <qtextdocument.h>
77 #include <wtf/OwnPtr.h>
79 #if ENABLE(VIDEO) && ENABLE(QT_MULTIMEDIA)
80 #include "FullScreenVideoQt.h"
81 #include "HTMLMediaElement.h"
82 #include "HTMLNames.h"
83 #include "HTMLVideoElement.h"
84 #include "MediaPlayerPrivateQt.h"
89 bool ChromeClientQt::dumpVisitedLinksCallbacks = false;
91 ChromeClientQt::ChromeClientQt(QWebPage* webPage)
94 #if ENABLE(VIDEO) && ENABLE(QT_MULTIMEDIA)
95 , m_fullScreenVideo(0)
98 toolBarsVisible = statusBarVisible = menuBarVisible = true;
101 ChromeClientQt::~ChromeClientQt()
106 #if ENABLE(VIDEO) && ENABLE(QT_MULTIMEDIA)
107 delete m_fullScreenVideo;
111 void ChromeClientQt::setWindowRect(const FloatRect& rect)
115 emit m_webPage->geometryChangeRequested(QRect(qRound(rect.x()), qRound(rect.y()),
116 qRound(rect.width()), qRound(rect.height())));
120 windowRect represents the rect of the Window, including all interface elements
121 like toolbars/scrollbars etc. It is used by the viewport meta tag as well as
122 by the DOM Window object: outerHeight(), outerWidth(), screenX(), screenY().
124 FloatRect ChromeClientQt::windowRect()
126 if (!platformPageClient())
128 return platformPageClient()->windowRect();
131 FloatRect ChromeClientQt::pageRect()
135 return FloatRect(QRectF(QPointF(0, 0), m_webPage->viewportSize()));
138 float ChromeClientQt::scaleFactor()
142 return m_webPage->d->pixelRatio;
145 void ChromeClientQt::focus()
149 QWidget* view = m_webPage->view();
157 void ChromeClientQt::unfocus()
161 QWidget* view = m_webPage->view();
167 bool ChromeClientQt::canTakeFocus(FocusDirection)
169 // This is called when cycling through links/focusable objects and we
170 // reach the last focusable object. Then we want to claim that we can
171 // take the focus to avoid wrapping.
175 void ChromeClientQt::takeFocus(FocusDirection)
177 // don't do anything. This is only called when cycling to links/focusable objects,
178 // which in turn is called from focusNextPrevChild. We let focusNextPrevChild
179 // call QWidget::focusNextPrevChild accordingly, so there is no need to do anything
184 void ChromeClientQt::focusedNodeChanged(Node*)
188 void ChromeClientQt::focusedFrameChanged(Frame*)
192 Page* ChromeClientQt::createWindow(Frame*, const FrameLoadRequest& request, const WindowFeatures& features, const NavigationAction&)
194 QWebPage* newPage = m_webPage->createWindow(features.dialog ? QWebPage::WebModalDialog : QWebPage::WebBrowserWindow);
198 // A call to QWebPage::mainFrame() implicitly creates the main frame.
199 // Make sure it exists, as WebCore expects it when returning from this call.
200 newPage->mainFrame();
201 return newPage->d->page;
204 void ChromeClientQt::show()
208 QWidget* view = m_webPage->view();
211 view->window()->show();
215 bool ChromeClientQt::canRunModal()
221 void ChromeClientQt::runModal()
223 m_eventLoop = new QEventLoop();
224 QEventLoop* eventLoop = m_eventLoop;
230 void ChromeClientQt::setToolbarsVisible(bool visible)
232 toolBarsVisible = visible;
233 emit m_webPage->toolBarVisibilityChangeRequested(visible);
237 bool ChromeClientQt::toolbarsVisible()
239 return toolBarsVisible;
243 void ChromeClientQt::setStatusbarVisible(bool visible)
245 emit m_webPage->statusBarVisibilityChangeRequested(visible);
246 statusBarVisible = visible;
250 bool ChromeClientQt::statusbarVisible()
252 return statusBarVisible;
256 void ChromeClientQt::setScrollbarsVisible(bool)
262 bool ChromeClientQt::scrollbarsVisible()
269 void ChromeClientQt::setMenubarVisible(bool visible)
271 menuBarVisible = visible;
272 emit m_webPage->menuBarVisibilityChangeRequested(visible);
275 bool ChromeClientQt::menubarVisible()
277 return menuBarVisible;
280 void ChromeClientQt::setResizable(bool)
285 void ChromeClientQt::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message,
286 unsigned int lineNumber, const String& sourceID)
289 QString y = sourceID;
290 m_webPage->javaScriptConsoleMessage(x, lineNumber, y);
293 void ChromeClientQt::chromeDestroyed()
298 bool ChromeClientQt::canRunBeforeUnloadConfirmPanel()
303 bool ChromeClientQt::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
305 return runJavaScriptConfirm(frame, message);
308 void ChromeClientQt::closeWindowSoon()
310 m_webPage->mainFrame()->d->frame->loader()->stopAllLoaders();
311 emit m_webPage->windowCloseRequested();
314 void ChromeClientQt::runJavaScriptAlert(Frame* f, const String& msg)
317 QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
318 m_webPage->javaScriptAlert(webFrame, x);
321 bool ChromeClientQt::runJavaScriptConfirm(Frame* f, const String& msg)
324 QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
325 return m_webPage->javaScriptConfirm(webFrame, x);
328 bool ChromeClientQt::runJavaScriptPrompt(Frame* f, const String& message, const String& defaultValue, String& result)
331 QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
332 bool rc = m_webPage->javaScriptPrompt(webFrame, (QString)message, (QString)defaultValue, &x);
334 // Fix up a quirk in the QInputDialog class. If no input happened the string should be empty
335 // but it is null. See https://bugs.webkit.org/show_bug.cgi?id=30914.
336 if (rc && x.isNull())
344 void ChromeClientQt::setStatusbarText(const String& msg)
347 emit m_webPage->statusBarMessage(x);
350 bool ChromeClientQt::shouldInterruptJavaScript()
352 bool shouldInterrupt = false;
353 QMetaObject::invokeMethod(m_webPage, "shouldInterruptJavaScript", Qt::DirectConnection, Q_RETURN_ARG(bool, shouldInterrupt));
354 return shouldInterrupt;
357 bool ChromeClientQt::tabsToLinks() const
359 return m_webPage->settings()->testAttribute(QWebSettings::LinksIncludedInFocusChain);
362 IntRect ChromeClientQt::windowResizerRect() const
364 #if defined(Q_WS_MAC)
368 QWebPageClient* pageClient = platformPageClient();
372 QWidget* ownerWidget = pageClient->ownerWidget();
376 QWidget* topLevelWidget = ownerWidget->window();
377 QRect topLevelGeometry(topLevelWidget->geometry());
379 // There's no API in Qt to query for the size of the resizer, so we assume
380 // it has the same width and height as the scrollbar thickness.
381 int scollbarThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness();
383 // There's no API in Qt to query for the position of the resizer. Sometimes
384 // it's drawn by the system, and sometimes it's a QSizeGrip. For RTL locales
385 // it might even be on the lower left side of the window, but in WebKit we
386 // always draw scrollbars on the right hand side, so we assume this to be the
387 // location when computing the resize rect to reserve for WebKit.
388 QPoint resizeCornerTopLeft = ownerWidget->mapFrom(topLevelWidget,
389 QPoint(topLevelGeometry.width(), topLevelGeometry.height())
390 - QPoint(scollbarThickness, scollbarThickness));
392 QRect resizeCornerRect = QRect(resizeCornerTopLeft, QSize(scollbarThickness, scollbarThickness));
393 return resizeCornerRect.intersected(pageClient->geometryRelativeToOwnerWidget());
399 void ChromeClientQt::invalidateWindow(const IntRect&, bool)
404 void ChromeClientQt::invalidateContentsAndWindow(const IntRect& windowRect, bool immediate)
406 // No double buffer, so only update the QWidget if content changed.
407 if (platformPageClient()) {
408 QRect rect(windowRect);
409 rect = rect.intersected(QRect(QPoint(0, 0), m_webPage->viewportSize()));
411 platformPageClient()->update(rect);
413 emit m_webPage->repaintRequested(windowRect);
415 // FIXME: There is no "immediate" support for window painting. This should be done always whenever the flag
419 void ChromeClientQt::invalidateContentsForSlowScroll(const IntRect& windowRect, bool immediate)
421 invalidateContentsAndWindow(windowRect, immediate);
424 void ChromeClientQt::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect&)
426 if (platformPageClient())
427 platformPageClient()->scroll(delta.width(), delta.height(), scrollViewRect);
428 emit m_webPage->scrollRequested(delta.width(), delta.height(), scrollViewRect);
431 #if ENABLE(TILED_BACKING_STORE)
432 void ChromeClientQt::delegatedScrollRequested(const IntSize& delta)
434 emit m_webPage->scrollRequested(delta.width(), delta.height(), QRect(QPoint(0, 0), m_webPage->viewportSize()));
438 IntRect ChromeClientQt::windowToScreen(const IntRect& rect) const
440 QWebPageClient* pageClient = platformPageClient();
444 QWidget* ownerWidget = pageClient->ownerWidget();
448 QRect screenRect(rect);
449 screenRect.translate(ownerWidget->mapToGlobal(QPoint(0, 0)));
454 IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const
456 QWebPageClient* pageClient = platformPageClient();
460 QWidget* ownerWidget = pageClient->ownerWidget();
464 return ownerWidget->mapFromGlobal(point);
467 PlatformPageClient ChromeClientQt::platformPageClient() const
469 return m_webPage->d->client.get();
472 void ChromeClientQt::contentsSizeChanged(Frame* frame, const IntSize& size) const
474 if (frame->loader()->networkingContext())
475 QWebFramePrivate::kit(frame)->contentsSizeChanged(size);
478 void ChromeClientQt::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
481 if (result.absoluteLinkURL() != lastHoverURL
482 || result.title(dir) != lastHoverTitle
483 || result.textContent() != lastHoverContent) {
484 lastHoverURL = result.absoluteLinkURL();
485 lastHoverTitle = result.title(dir);
486 lastHoverContent = result.textContent();
487 emit m_webPage->linkHovered(lastHoverURL.prettyURL(),
488 lastHoverTitle, lastHoverContent);
492 void ChromeClientQt::setToolTip(const String &tip, TextDirection)
494 #ifndef QT_NO_TOOLTIP
495 QWidget* view = m_webPage->view();
500 view->setToolTip(QString());
501 QToolTip::hideText();
503 QString dtip = QLatin1String("<p>") + Qt::escape(tip) + QLatin1String("</p>");
504 view->setToolTip(dtip);
511 void ChromeClientQt::print(Frame* frame)
513 emit m_webPage->printRequested(QWebFramePrivate::kit(frame));
517 void ChromeClientQt::exceededDatabaseQuota(Frame* frame, const String& databaseName)
519 quint64 quota = QWebSettings::offlineStorageDefaultQuota();
521 if (!DatabaseTracker::tracker().hasEntryForOrigin(frame->document()->securityOrigin()))
522 DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), quota);
524 emit m_webPage->databaseQuotaExceeded(QWebFramePrivate::kit(frame), databaseName);
528 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
529 void ChromeClientQt::reachedMaxAppCacheSize(int64_t)
531 // FIXME: Free some space.
535 void ChromeClientQt::reachedApplicationCacheOriginQuota(SecurityOrigin* origin)
538 quint64 defaultOriginQuota = WebCore::cacheStorage().defaultOriginQuota();
540 QWebSecurityOriginPrivate* priv = new QWebSecurityOriginPrivate(origin);
541 QWebSecurityOrigin* securityOrigin = new QWebSecurityOrigin(priv);
543 if (!WebCore::cacheStorage().quotaForOrigin(origin, quota))
544 WebCore::cacheStorage().storeUpdatedQuotaForOrigin(origin, defaultOriginQuota);
546 emit m_webPage->applicationCacheQuotaExceeded(securityOrigin, defaultOriginQuota);
550 #if ENABLE(NOTIFICATIONS)
551 NotificationPresenter* ChromeClientQt::notificationPresenter() const
553 return NotificationPresenterClientQt::notificationPresenter();
557 void ChromeClientQt::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> prpFileChooser)
559 RefPtr<FileChooser> fileChooser = prpFileChooser;
560 bool supportMulti = m_webPage->supportsExtension(QWebPage::ChooseMultipleFilesExtension);
562 if (fileChooser->allowsMultipleFiles() && supportMulti) {
563 QWebPage::ChooseMultipleFilesExtensionOption option;
564 option.parentFrame = QWebFramePrivate::kit(frame);
566 if (!fileChooser->filenames().isEmpty())
567 for (unsigned i = 0; i < fileChooser->filenames().size(); ++i)
568 option.suggestedFileNames += fileChooser->filenames()[i];
570 QWebPage::ChooseMultipleFilesExtensionReturn output;
571 m_webPage->extension(QWebPage::ChooseMultipleFilesExtension, &option, &output);
573 if (!output.fileNames.isEmpty()) {
574 Vector<String> names;
575 for (int i = 0; i < output.fileNames.count(); ++i)
576 names.append(output.fileNames.at(i));
577 fileChooser->chooseFiles(names);
580 QString suggestedFile;
581 if (!fileChooser->filenames().isEmpty())
582 suggestedFile = fileChooser->filenames()[0];
583 QString file = m_webPage->chooseFile(QWebFramePrivate::kit(frame), suggestedFile);
585 fileChooser->chooseFile(file);
589 void ChromeClientQt::chooseIconForFiles(const Vector<String>& filenames, FileChooser* chooser)
591 chooser->iconLoaded(Icon::createIconForFiles(filenames));
594 void ChromeClientQt::setCursor(const Cursor& cursor)
597 QWebPageClient* pageClient = platformPageClient();
600 pageClient->setCursor(*cursor.platformCursor());
602 UNUSED_PARAM(cursor);
606 void ChromeClientQt::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
608 #if ENABLE(GEOLOCATION)
609 QWebFrame* webFrame = QWebFramePrivate::kit(frame);
610 GeolocationPermissionClientQt::geolocationPermissionClient()->requestGeolocationPermissionForFrame(webFrame, geolocation);
614 void ChromeClientQt::cancelGeolocationPermissionRequestForFrame(Frame* frame, Geolocation* geolocation)
616 #if ENABLE(GEOLOCATION)
617 QWebFrame* webFrame = QWebFramePrivate::kit(frame);
618 GeolocationPermissionClientQt::geolocationPermissionClient()->cancelGeolocationPermissionRequestForFrame(webFrame, geolocation);
622 #if USE(ACCELERATED_COMPOSITING)
623 void ChromeClientQt::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
625 if (platformPageClient())
626 platformPageClient()->setRootGraphicsLayer(graphicsLayer ? graphicsLayer->platformLayer() : 0);
629 void ChromeClientQt::setNeedsOneShotDrawingSynchronization()
631 // we want the layers to synchronize next time we update the screen anyway
632 if (platformPageClient())
633 platformPageClient()->markForSync(false);
636 void ChromeClientQt::scheduleCompositingLayerSync()
638 // we want the layers to synchronize ASAP
639 if (platformPageClient())
640 platformPageClient()->markForSync(true);
643 ChromeClient::CompositingTriggerFlags ChromeClientQt::allowedCompositingTriggers() const
645 if (platformPageClient() && platformPageClient()->allowsAcceleratedCompositing())
653 #if ENABLE(TILED_BACKING_STORE)
654 IntRect ChromeClientQt::visibleRectForTiledBackingStore() const
656 if (!platformPageClient() || !m_webPage)
659 if (!platformPageClient()->viewResizesToContentsEnabled())
660 return QRect(m_webPage->mainFrame()->scrollPosition(), m_webPage->mainFrame()->geometry().size());
662 return enclosingIntRect(FloatRect(platformPageClient()->graphicsItemVisibleRect()));
666 #if ENABLE(VIDEO) && ENABLE(QT_MULTIMEDIA)
667 FullScreenVideoQt* ChromeClientQt::fullScreenVideo()
669 if (!m_fullScreenVideo)
670 m_fullScreenVideo = new FullScreenVideoQt(this);
671 return m_fullScreenVideo;
674 bool ChromeClientQt::supportsFullscreenForNode(const Node* node)
677 return node->hasTagName(HTMLNames::videoTag) && fullScreenVideo()->isValid();
680 bool ChromeClientQt::requiresFullscreenForVideoPlayback()
682 return fullScreenVideo()->requiresFullScreenForVideoPlayback();
685 void ChromeClientQt::enterFullscreenForNode(Node* node)
687 ASSERT(node && node->hasTagName(HTMLNames::videoTag));
689 HTMLVideoElement* videoElement = static_cast<HTMLVideoElement*>(node);
690 PlatformMedia platformMedia = videoElement->platformMedia();
692 ASSERT(platformMedia.type == PlatformMedia::QtMediaPlayerType);
693 if (platformMedia.type != PlatformMedia::QtMediaPlayerType)
696 fullScreenVideo()->enterFullScreenForNode(node);
699 void ChromeClientQt::exitFullscreenForNode(Node* node)
701 ASSERT(node && node->hasTagName(HTMLNames::videoTag));
703 HTMLVideoElement* videoElement = static_cast<HTMLVideoElement*>(node);
704 PlatformMedia platformMedia = videoElement->platformMedia();
706 ASSERT(platformMedia.type == PlatformMedia::QtMediaPlayerType);
707 if (platformMedia.type != PlatformMedia::QtMediaPlayerType)
710 fullScreenVideo()->exitFullScreenForNode(node);
714 QWebSelectMethod* ChromeClientQt::createSelectPopup() const
716 QWebSelectMethod* result = m_platformPlugin.createSelectInputMethod();
720 #if defined(Q_WS_MAEMO_5)
721 return new QtMaemoWebPopup;
722 #elif !defined(QT_NO_COMBOBOX)
723 return new QtFallbackWebPopup(this);
729 void ChromeClientQt::dispatchViewportDataDidChange(const ViewportArguments&) const
731 emit m_webPage->viewportChangeRequested();
734 bool ChromeClientQt::selectItemWritingDirectionIsNatural()
739 PassRefPtr<PopupMenu> ChromeClientQt::createPopupMenu(PopupMenuClient* client) const
741 return adoptRef(new PopupMenuQt(client, this));
744 PassRefPtr<SearchPopupMenu> ChromeClientQt::createSearchPopupMenu(PopupMenuClient* client) const
746 return adoptRef(new SearchPopupMenuQt(createPopupMenu(client)));
749 void ChromeClientQt::populateVisitedLinks()
751 // We don't need to do anything here because history is tied to QWebPage rather than stored
752 // in a separate database
753 if (dumpVisitedLinksCallbacks) {
754 printf("Asked to populate visited links for WebView \"%s\"\n",
755 qPrintable(m_webPage->mainFrame()->url().toString()));
759 } // namespace WebCore