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