1/*
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).
5 *
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
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.
16 *
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.
28 */
29
30#include "config.h"
31#include "ChromeClientQt.h"
32
33#include "ApplicationCacheStorage.h"
34#include "DatabaseTracker.h"
35#include "FileChooser.h"
36#include "Frame.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"
44#endif
45#include "HitTestResult.h"
46#include "Icon.h"
47#include "NavigationAction.h"
48#include "NetworkingContext.h"
49#include "NotImplemented.h"
50#include "NotificationPresenterClientQt.h"
51#include "PageClientQt.h"
52#include "PopupMenuQt.h"
53#if defined(Q_WS_MAEMO_5)
54#include "QtMaemoWebPopup.h"
55#else
56#include "QtFallbackWebPopup.h"
57#endif
58#include "QWebPageClient.h"
59#include "ScrollbarTheme.h"
60#include "SearchPopupMenuQt.h"
61#include "SecurityOrigin.h"
62#include "ViewportArguments.h"
63#include "WindowFeatures.h"
64
65#include "qgraphicswebview.h"
66#include "qwebframe_p.h"
67#include "qwebpage.h"
68#include "qwebpage_p.h"
69#include "qwebsecurityorigin.h"
70#include "qwebsecurityorigin_p.h"
71#include "qwebview.h"
72#include <qdebug.h>
73#include <qeventloop.h>
74#include <qtextdocument.h>
75#include <qtooltip.h>
76#include <wtf/OwnPtr.h>
77
78#if ENABLE(VIDEO) && (USE(GSTREAMER) || USE(QT_MULTIMEDIA))
79#include "FullScreenVideoQt.h"
80#include "HTMLMediaElement.h"
81#include "HTMLNames.h"
82#include "HTMLVideoElement.h"
83#if USE(QT_MULTIMEDIA)
84#include "MediaPlayerPrivateQt.h"
85#endif
86#endif
87
88namespace WebCore {
89
90bool ChromeClientQt::dumpVisitedLinksCallbacks = false;
91
92ChromeClientQt::ChromeClientQt(QWebPage* webPage)
93    : m_webPage(webPage)
94    , m_eventLoop(0)
95#if ENABLE(VIDEO) && (USE(GSTREAMER) || USE(QT_MULTIMEDIA))
96    , m_fullScreenVideo(0)
97#endif
98{
99    toolBarsVisible = statusBarVisible = menuBarVisible = true;
100}
101
102ChromeClientQt::~ChromeClientQt()
103{
104    if (m_eventLoop)
105        m_eventLoop->exit();
106
107#if ENABLE(VIDEO) && (USE(GSTREAMER) || USE(QT_MULTIMEDIA))
108    delete m_fullScreenVideo;
109#endif
110}
111
112void ChromeClientQt::setWindowRect(const FloatRect& rect)
113{
114    if (!m_webPage)
115        return;
116    emit m_webPage->geometryChangeRequested(QRect(qRound(rect.x()), qRound(rect.y()),
117                            qRound(rect.width()), qRound(rect.height())));
118}
119
120/*!
121    windowRect represents the rect of the Window, including all interface elements
122    like toolbars/scrollbars etc. It is used by the viewport meta tag as well as
123    by the DOM Window object: outerHeight(), outerWidth(), screenX(), screenY().
124*/
125FloatRect ChromeClientQt::windowRect()
126{
127    if (!platformPageClient())
128        return FloatRect();
129    return platformPageClient()->windowRect();
130}
131
132FloatRect ChromeClientQt::pageRect()
133{
134    if (!m_webPage)
135        return FloatRect();
136    return FloatRect(QRectF(QPointF(0, 0), m_webPage->viewportSize()));
137}
138
139float ChromeClientQt::scaleFactor()
140{
141    if (!m_webPage)
142        return 1;
143    return m_webPage->d->pixelRatio;
144}
145
146void ChromeClientQt::focus()
147{
148    if (!m_webPage)
149        return;
150    QWidget* view = m_webPage->view();
151    if (!view)
152        return;
153
154    view->setFocus();
155}
156
157
158void ChromeClientQt::unfocus()
159{
160    if (!m_webPage)
161        return;
162    QWidget* view = m_webPage->view();
163    if (!view)
164        return;
165    view->clearFocus();
166}
167
168bool ChromeClientQt::canTakeFocus(FocusDirection)
169{
170    // This is called when cycling through links/focusable objects and we
171    // reach the last focusable object. Then we want to claim that we can
172    // take the focus to avoid wrapping.
173    return true;
174}
175
176void ChromeClientQt::takeFocus(FocusDirection)
177{
178    // don't do anything. This is only called when cycling to links/focusable objects,
179    // which in turn is called from focusNextPrevChild. We let focusNextPrevChild
180    // call QWidget::focusNextPrevChild accordingly, so there is no need to do anything
181    // here.
182}
183
184
185void ChromeClientQt::focusedNodeChanged(Node*)
186{
187}
188
189void ChromeClientQt::focusedFrameChanged(Frame*)
190{
191}
192
193Page* ChromeClientQt::createWindow(Frame*, const FrameLoadRequest& request, const WindowFeatures& features, const NavigationAction&)
194{
195    QWebPage* newPage = m_webPage->createWindow(features.dialog ? QWebPage::WebModalDialog : QWebPage::WebBrowserWindow);
196    if (!newPage)
197        return 0;
198
199    // A call to QWebPage::mainFrame() implicitly creates the main frame.
200    // Make sure it exists, as WebCore expects it when returning from this call.
201    newPage->mainFrame();
202    return newPage->d->page;
203}
204
205void ChromeClientQt::show()
206{
207    if (!m_webPage)
208        return;
209    QWidget* view = m_webPage->view();
210    if (!view)
211        return;
212    view->window()->show();
213}
214
215
216bool ChromeClientQt::canRunModal()
217{
218    return true;
219}
220
221
222void ChromeClientQt::runModal()
223{
224    m_eventLoop = new QEventLoop();
225    QEventLoop* eventLoop = m_eventLoop;
226    m_eventLoop->exec();
227    delete eventLoop;
228}
229
230
231void ChromeClientQt::setToolbarsVisible(bool visible)
232{
233    toolBarsVisible = visible;
234    emit m_webPage->toolBarVisibilityChangeRequested(visible);
235}
236
237
238bool ChromeClientQt::toolbarsVisible()
239{
240    return toolBarsVisible;
241}
242
243
244void ChromeClientQt::setStatusbarVisible(bool visible)
245{
246    emit m_webPage->statusBarVisibilityChangeRequested(visible);
247    statusBarVisible = visible;
248}
249
250
251bool ChromeClientQt::statusbarVisible()
252{
253    return statusBarVisible;
254}
255
256
257void ChromeClientQt::setScrollbarsVisible(bool)
258{
259    notImplemented();
260}
261
262
263bool ChromeClientQt::scrollbarsVisible()
264{
265    notImplemented();
266    return true;
267}
268
269
270void ChromeClientQt::setMenubarVisible(bool visible)
271{
272    menuBarVisible = visible;
273    emit m_webPage->menuBarVisibilityChangeRequested(visible);
274}
275
276bool ChromeClientQt::menubarVisible()
277{
278    return menuBarVisible;
279}
280
281void ChromeClientQt::setResizable(bool)
282{
283    notImplemented();
284}
285
286void ChromeClientQt::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message,
287                                         unsigned int lineNumber, const String& sourceID)
288{
289    QString x = message;
290    QString y = sourceID;
291    m_webPage->javaScriptConsoleMessage(x, lineNumber, y);
292}
293
294void ChromeClientQt::chromeDestroyed()
295{
296    delete this;
297}
298
299bool ChromeClientQt::canRunBeforeUnloadConfirmPanel()
300{
301    return true;
302}
303
304bool ChromeClientQt::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
305{
306    return runJavaScriptConfirm(frame, message);
307}
308
309void ChromeClientQt::closeWindowSoon()
310{
311    m_webPage->d->page->setGroupName(String());
312    m_webPage->mainFrame()->d->frame->loader()->stopAllLoaders();
313    emit m_webPage->windowCloseRequested();
314}
315
316void ChromeClientQt::runJavaScriptAlert(Frame* f, const String& msg)
317{
318    QString x = msg;
319    QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
320    m_webPage->javaScriptAlert(webFrame, x);
321}
322
323bool ChromeClientQt::runJavaScriptConfirm(Frame* f, const String& msg)
324{
325    QString x = msg;
326    QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
327    return m_webPage->javaScriptConfirm(webFrame, x);
328}
329
330bool ChromeClientQt::runJavaScriptPrompt(Frame* f, const String& message, const String& defaultValue, String& result)
331{
332    QString x = result;
333    QWebFrame* webFrame = qobject_cast<QWebFrame*>(f->loader()->networkingContext()->originatingObject());
334    bool rc = m_webPage->javaScriptPrompt(webFrame, (QString)message, (QString)defaultValue, &x);
335
336    // Fix up a quirk in the QInputDialog class. If no input happened the string should be empty
337    // but it is null. See https://bugs.webkit.org/show_bug.cgi?id=30914.
338    if (rc && x.isNull())
339        result = String("");
340    else
341        result = x;
342
343    return rc;
344}
345
346void ChromeClientQt::setStatusbarText(const String& msg)
347{
348    QString x = msg;
349    emit m_webPage->statusBarMessage(x);
350}
351
352bool ChromeClientQt::shouldInterruptJavaScript()
353{
354    bool shouldInterrupt = false;
355    QMetaObject::invokeMethod(m_webPage, "shouldInterruptJavaScript", Qt::DirectConnection, Q_RETURN_ARG(bool, shouldInterrupt));
356    return shouldInterrupt;
357}
358
359KeyboardUIMode ChromeClientQt::keyboardUIMode()
360{
361    return m_webPage->settings()->testAttribute(QWebSettings::LinksIncludedInFocusChain)
362        ? KeyboardAccessTabsToLinks : KeyboardAccessDefault;
363}
364
365IntRect ChromeClientQt::windowResizerRect() const
366{
367#if defined(Q_WS_MAC)
368    if (!m_webPage)
369        return IntRect();
370
371    QWebPageClient* pageClient = platformPageClient();
372    if (!pageClient)
373        return IntRect();
374
375    QWidget* ownerWidget = pageClient->ownerWidget();
376    if (!ownerWidget)
377        return IntRect();
378
379    QWidget* topLevelWidget = ownerWidget->window();
380    QRect topLevelGeometry(topLevelWidget->geometry());
381
382    // There's no API in Qt to query for the size of the resizer, so we assume
383    // it has the same width and height as the scrollbar thickness.
384    int scollbarThickness = ScrollbarTheme::nativeTheme()->scrollbarThickness();
385
386    // There's no API in Qt to query for the position of the resizer. Sometimes
387    // it's drawn by the system, and sometimes it's a QSizeGrip. For RTL locales
388    // it might even be on the lower left side of the window, but in WebKit we
389    // always draw scrollbars on the right hand side, so we assume this to be the
390    // location when computing the resize rect to reserve for WebKit.
391    QPoint resizeCornerTopLeft = ownerWidget->mapFrom(topLevelWidget,
392            QPoint(topLevelGeometry.width(), topLevelGeometry.height())
393            - QPoint(scollbarThickness, scollbarThickness));
394
395    QRect resizeCornerRect = QRect(resizeCornerTopLeft, QSize(scollbarThickness, scollbarThickness));
396    return resizeCornerRect.intersected(pageClient->geometryRelativeToOwnerWidget());
397#else
398    return IntRect();
399#endif
400}
401
402void ChromeClientQt::invalidateWindow(const IntRect& windowRect, bool)
403{
404#if ENABLE(TILED_BACKING_STORE)
405    if (platformPageClient()) {
406        WebCore::TiledBackingStore* backingStore = QWebFramePrivate::core(m_webPage->mainFrame())->tiledBackingStore();
407        if (!backingStore)
408            return;
409        backingStore->invalidate(windowRect);
410    }
411#else
412    Q_UNUSED(windowRect);
413#endif
414}
415
416void ChromeClientQt::invalidateContentsAndWindow(const IntRect& windowRect, bool immediate)
417{
418    // No double buffer, so only update the QWidget if content changed.
419    if (platformPageClient()) {
420        QRect rect(windowRect);
421        rect = rect.intersected(QRect(QPoint(0, 0), m_webPage->viewportSize()));
422        if (!rect.isEmpty())
423            platformPageClient()->update(rect);
424    }
425    QMetaObject::invokeMethod(m_webPage, "repaintRequested", Qt::QueuedConnection, Q_ARG(QRect, windowRect));
426
427    // FIXME: There is no "immediate" support for window painting.  This should be done always whenever the flag
428    // is set.
429}
430
431void ChromeClientQt::invalidateContentsForSlowScroll(const IntRect& windowRect, bool immediate)
432{
433    invalidateContentsAndWindow(windowRect, immediate);
434}
435
436void ChromeClientQt::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect&)
437{
438    if (platformPageClient())
439        platformPageClient()->scroll(delta.width(), delta.height(), scrollViewRect);
440    emit m_webPage->scrollRequested(delta.width(), delta.height(), scrollViewRect);
441}
442
443#if ENABLE(TILED_BACKING_STORE)
444void ChromeClientQt::delegatedScrollRequested(const IntPoint& point)
445{
446    QPoint currentPosition(m_webPage->mainFrame()->scrollPosition());
447    emit m_webPage->scrollRequested(point.x() - currentPosition.x(), point.y() - currentPosition.y(), QRect(QPoint(0, 0), m_webPage->viewportSize()));
448}
449#endif
450
451IntRect ChromeClientQt::windowToScreen(const IntRect& rect) const
452{
453    QWebPageClient* pageClient = platformPageClient();
454    if (!pageClient)
455        return rect;
456
457    QWidget* ownerWidget = pageClient->ownerWidget();
458    if (!ownerWidget)
459       return rect;
460
461    QRect screenRect(rect);
462    screenRect.translate(ownerWidget->mapToGlobal(QPoint(0, 0)));
463
464    return screenRect;
465}
466
467IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const
468{
469    QWebPageClient* pageClient = platformPageClient();
470    if (!pageClient)
471        return point;
472
473    QWidget* ownerWidget = pageClient->ownerWidget();
474    if (!ownerWidget)
475        return point;
476
477    return ownerWidget->mapFromGlobal(point);
478}
479
480PlatformPageClient ChromeClientQt::platformPageClient() const
481{
482    return m_webPage->d->client.get();
483}
484
485void ChromeClientQt::contentsSizeChanged(Frame* frame, const IntSize& size) const
486{
487    if (frame->loader()->networkingContext())
488        QWebFramePrivate::kit(frame)->contentsSizeChanged(size);
489}
490
491void ChromeClientQt::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
492{
493    TextDirection dir;
494    if (result.absoluteLinkURL() != lastHoverURL
495        || result.title(dir) != lastHoverTitle
496        || result.textContent() != lastHoverContent) {
497        lastHoverURL = result.absoluteLinkURL();
498        lastHoverTitle = result.title(dir);
499        lastHoverContent = result.textContent();
500        emit m_webPage->linkHovered(lastHoverURL.string(),
501                lastHoverTitle, lastHoverContent);
502    }
503}
504
505void ChromeClientQt::setToolTip(const String &tip, TextDirection)
506{
507#ifndef QT_NO_TOOLTIP
508    QWidget* view = m_webPage->view();
509    if (!view)
510        return;
511
512    if (tip.isEmpty()) {
513        view->setToolTip(QString());
514        QToolTip::hideText();
515    } else {
516        QString dtip = QLatin1String("<p>") + Qt::escape(tip) + QLatin1String("</p>");
517        view->setToolTip(dtip);
518    }
519#else
520    Q_UNUSED(tip);
521#endif
522}
523
524void ChromeClientQt::print(Frame* frame)
525{
526    emit m_webPage->printRequested(QWebFramePrivate::kit(frame));
527}
528
529#if ENABLE(DATABASE)
530void ChromeClientQt::exceededDatabaseQuota(Frame* frame, const String& databaseName)
531{
532    quint64 quota = QWebSettings::offlineStorageDefaultQuota();
533
534    if (!DatabaseTracker::tracker().hasEntryForOrigin(frame->document()->securityOrigin()))
535        DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), quota);
536
537    emit m_webPage->databaseQuotaExceeded(QWebFramePrivate::kit(frame), databaseName);
538}
539#endif
540
541#if ENABLE(OFFLINE_WEB_APPLICATIONS)
542void ChromeClientQt::reachedMaxAppCacheSize(int64_t)
543{
544    // FIXME: Free some space.
545    notImplemented();
546}
547
548void ChromeClientQt::reachedApplicationCacheOriginQuota(SecurityOrigin* origin)
549{
550    int64_t quota;
551    quint64 defaultOriginQuota = WebCore::cacheStorage().defaultOriginQuota();
552
553    QWebSecurityOriginPrivate* priv = new QWebSecurityOriginPrivate(origin);
554    QWebSecurityOrigin* securityOrigin = new QWebSecurityOrigin(priv);
555
556    if (!WebCore::cacheStorage().quotaForOrigin(origin, quota))
557       WebCore::cacheStorage().storeUpdatedQuotaForOrigin(origin, defaultOriginQuota);
558
559    emit m_webPage->applicationCacheQuotaExceeded(securityOrigin, defaultOriginQuota);
560}
561#endif
562
563#if ENABLE(NOTIFICATIONS)
564NotificationPresenter* ChromeClientQt::notificationPresenter() const
565{
566    return NotificationPresenterClientQt::notificationPresenter();
567}
568#endif
569
570void ChromeClientQt::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> prpFileChooser)
571{
572    RefPtr<FileChooser> fileChooser = prpFileChooser;
573    bool supportMulti = m_webPage->supportsExtension(QWebPage::ChooseMultipleFilesExtension);
574
575    if (fileChooser->allowsMultipleFiles() && supportMulti) {
576        QWebPage::ChooseMultipleFilesExtensionOption option;
577        option.parentFrame = QWebFramePrivate::kit(frame);
578
579        if (!fileChooser->filenames().isEmpty())
580            for (unsigned i = 0; i < fileChooser->filenames().size(); ++i)
581                option.suggestedFileNames += fileChooser->filenames()[i];
582
583        QWebPage::ChooseMultipleFilesExtensionReturn output;
584        m_webPage->extension(QWebPage::ChooseMultipleFilesExtension, &option, &output);
585
586        if (!output.fileNames.isEmpty()) {
587            Vector<String> names;
588            for (int i = 0; i < output.fileNames.count(); ++i)
589                names.append(output.fileNames.at(i));
590            fileChooser->chooseFiles(names);
591        }
592    } else {
593        QString suggestedFile;
594        if (!fileChooser->filenames().isEmpty())
595            suggestedFile = fileChooser->filenames()[0];
596        QString file = m_webPage->chooseFile(QWebFramePrivate::kit(frame), suggestedFile);
597        if (!file.isEmpty())
598            fileChooser->chooseFile(file);
599    }
600}
601
602void ChromeClientQt::chooseIconForFiles(const Vector<String>& filenames, FileChooser* chooser)
603{
604    chooser->iconLoaded(Icon::createIconForFiles(filenames));
605}
606
607void ChromeClientQt::setCursor(const Cursor& cursor)
608{
609#ifndef QT_NO_CURSOR
610    QWebPageClient* pageClient = platformPageClient();
611    if (!pageClient)
612        return;
613    pageClient->setCursor(*cursor.platformCursor());
614#else
615    UNUSED_PARAM(cursor);
616#endif
617}
618
619
620#if USE(ACCELERATED_COMPOSITING)
621void ChromeClientQt::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
622{
623    if (platformPageClient())
624        platformPageClient()->setRootGraphicsLayer(graphicsLayer ? graphicsLayer->platformLayer() : 0);
625}
626
627void ChromeClientQt::setNeedsOneShotDrawingSynchronization()
628{
629    // we want the layers to synchronize next time we update the screen anyway
630    if (platformPageClient())
631        platformPageClient()->markForSync(false);
632}
633
634void ChromeClientQt::scheduleCompositingLayerSync()
635{
636    // we want the layers to synchronize ASAP
637    if (platformPageClient())
638        platformPageClient()->markForSync(true);
639}
640
641ChromeClient::CompositingTriggerFlags ChromeClientQt::allowedCompositingTriggers() const
642{
643    if (platformPageClient() && platformPageClient()->allowsAcceleratedCompositing())
644        return AllTriggers;
645
646    return 0;
647}
648
649#endif
650
651#if ENABLE(TILED_BACKING_STORE)
652IntRect ChromeClientQt::visibleRectForTiledBackingStore() const
653{
654    if (!platformPageClient() || !m_webPage)
655        return IntRect();
656
657    if (!platformPageClient()->viewResizesToContentsEnabled())
658        return QRect(m_webPage->mainFrame()->scrollPosition(), m_webPage->mainFrame()->geometry().size());
659
660    return enclosingIntRect(FloatRect(platformPageClient()->graphicsItemVisibleRect()));
661}
662#endif
663
664#if ENABLE(VIDEO) && (USE(GSTREAMER) || USE(QT_MULTIMEDIA))
665FullScreenVideoQt* ChromeClientQt::fullScreenVideo()
666{
667    if (!m_fullScreenVideo)
668        m_fullScreenVideo = new FullScreenVideoQt(this);
669    return m_fullScreenVideo;
670}
671
672bool ChromeClientQt::supportsFullscreenForNode(const Node* node)
673{
674    ASSERT(node);
675    return node->hasTagName(HTMLNames::videoTag) && fullScreenVideo()->isValid();
676}
677
678bool ChromeClientQt::requiresFullscreenForVideoPlayback()
679{
680    return fullScreenVideo()->requiresFullScreenForVideoPlayback();
681}
682
683void ChromeClientQt::enterFullscreenForNode(Node* node)
684{
685    ASSERT(node && node->hasTagName(HTMLNames::videoTag));
686
687    fullScreenVideo()->enterFullScreenForNode(node);
688}
689
690void ChromeClientQt::exitFullscreenForNode(Node* node)
691{
692    ASSERT(node && node->hasTagName(HTMLNames::videoTag));
693
694    fullScreenVideo()->exitFullScreenForNode(node);
695}
696#endif
697
698QWebSelectMethod* ChromeClientQt::createSelectPopup() const
699{
700    QWebSelectMethod* result = m_platformPlugin.createSelectInputMethod();
701    if (result)
702        return result;
703
704#if defined(Q_WS_MAEMO_5)
705    return new QtMaemoWebPopup;
706#elif !defined(QT_NO_COMBOBOX)
707    return new QtFallbackWebPopup(this);
708#else
709    return 0;
710#endif
711}
712
713void ChromeClientQt::dispatchViewportDataDidChange(const ViewportArguments&) const
714{
715    emit m_webPage->viewportChangeRequested();
716}
717
718bool ChromeClientQt::selectItemWritingDirectionIsNatural()
719{
720    return false;
721}
722
723bool ChromeClientQt::selectItemAlignmentFollowsMenuWritingDirection()
724{
725    return false;
726}
727
728PassRefPtr<PopupMenu> ChromeClientQt::createPopupMenu(PopupMenuClient* client) const
729{
730    return adoptRef(new PopupMenuQt(client, this));
731}
732
733PassRefPtr<SearchPopupMenu> ChromeClientQt::createSearchPopupMenu(PopupMenuClient* client) const
734{
735    return adoptRef(new SearchPopupMenuQt(createPopupMenu(client)));
736}
737
738void ChromeClientQt::populateVisitedLinks()
739{
740    // We don't need to do anything here because history is tied to QWebPage rather than stored
741    // in a separate database
742    if (dumpVisitedLinksCallbacks) {
743        printf("Asked to populate visited links for WebView \"%s\"\n",
744                qPrintable(m_webPage->mainFrame()->url().toString()));
745    }
746}
747
748} // namespace WebCore
749