Home | History | Annotate | Download | only in WebCoreSupport
      1 /*
      2  * Copyright (C) 2006 Zack Rusin <zack (at) kde.org>
      3  * Copyright (C) 2006 Apple Computer, Inc.  All rights reserved.
      4  *
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     20  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     21  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     23  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     24  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "config.h"
     30 #include "ChromeClientQt.h"
     31 
     32 #include "FileChooser.h"
     33 #include "Frame.h"
     34 #include "FrameLoadRequest.h"
     35 #include "FrameLoader.h"
     36 #include "FrameLoaderClientQt.h"
     37 #include "FrameView.h"
     38 #include "HitTestResult.h"
     39 #include "NotImplemented.h"
     40 #include "WindowFeatures.h"
     41 #include "DatabaseTracker.h"
     42 #include "QtFallbackWebPopup.h"
     43 #include "QWebPageClient.h"
     44 #include "SecurityOrigin.h"
     45 
     46 #include <qdebug.h>
     47 #include <qeventloop.h>
     48 #include <qtextdocument.h>
     49 #include <qtooltip.h>
     50 
     51 #include "qwebpage.h"
     52 #include "qwebpage_p.h"
     53 #include "qwebframe_p.h"
     54 #include "qwebsecurityorigin.h"
     55 #include "qwebsecurityorigin_p.h"
     56 #include "qwebview.h"
     57 
     58 #if USE(ACCELERATED_COMPOSITING)
     59 #include "GraphicsLayerQt.h"
     60 #endif
     61 
     62 namespace WebCore {
     63 
     64 ChromeClientQt::ChromeClientQt(QWebPage* webPage)
     65     : m_webPage(webPage)
     66     , m_eventLoop(0)
     67 {
     68     toolBarsVisible = statusBarVisible = menuBarVisible = true;
     69 }
     70 
     71 ChromeClientQt::~ChromeClientQt()
     72 {
     73     if (m_eventLoop)
     74         m_eventLoop->exit();
     75 }
     76 
     77 void ChromeClientQt::setWindowRect(const FloatRect& rect)
     78 {
     79     if (!m_webPage)
     80         return;
     81     emit m_webPage->geometryChangeRequested(QRect(qRound(rect.x()), qRound(rect.y()),
     82                             qRound(rect.width()), qRound(rect.height())));
     83 }
     84 
     85 
     86 FloatRect ChromeClientQt::windowRect()
     87 {
     88     if (!m_webPage)
     89         return FloatRect();
     90 
     91     QWidget* view = m_webPage->view();
     92     if (!view)
     93         return FloatRect();
     94     return IntRect(view->topLevelWidget()->geometry());
     95 }
     96 
     97 
     98 FloatRect ChromeClientQt::pageRect()
     99 {
    100     if (!m_webPage)
    101         return FloatRect();
    102     return FloatRect(QRectF(QPointF(0,0), m_webPage->viewportSize()));
    103 }
    104 
    105 
    106 float ChromeClientQt::scaleFactor()
    107 {
    108     notImplemented();
    109     return 1;
    110 }
    111 
    112 
    113 void ChromeClientQt::focus()
    114 {
    115     if (!m_webPage)
    116         return;
    117     QWidget* view = m_webPage->view();
    118     if (!view)
    119         return;
    120 
    121     view->setFocus();
    122 }
    123 
    124 
    125 void ChromeClientQt::unfocus()
    126 {
    127     if (!m_webPage)
    128         return;
    129     QWidget* view = m_webPage->view();
    130     if (!view)
    131         return;
    132     view->clearFocus();
    133 }
    134 
    135 bool ChromeClientQt::canTakeFocus(FocusDirection)
    136 {
    137     // This is called when cycling through links/focusable objects and we
    138     // reach the last focusable object. Then we want to claim that we can
    139     // take the focus to avoid wrapping.
    140     return true;
    141 }
    142 
    143 void ChromeClientQt::takeFocus(FocusDirection)
    144 {
    145     // don't do anything. This is only called when cycling to links/focusable objects,
    146     // which in turn is called from focusNextPrevChild. We let focusNextPrevChild
    147     // call QWidget::focusNextPrevChild accordingly, so there is no need to do anything
    148     // here.
    149 }
    150 
    151 
    152 void ChromeClientQt::focusedNodeChanged(WebCore::Node*)
    153 {
    154 }
    155 
    156 
    157 Page* ChromeClientQt::createWindow(Frame*, const FrameLoadRequest& request, const WindowFeatures& features)
    158 {
    159     QWebPage *newPage = m_webPage->createWindow(features.dialog ? QWebPage::WebModalDialog : QWebPage::WebBrowserWindow);
    160     if (!newPage)
    161         return 0;
    162     newPage->mainFrame()->load(request.resourceRequest().url());
    163     return newPage->d->page;
    164 }
    165 
    166 void ChromeClientQt::show()
    167 {
    168     if (!m_webPage)
    169         return;
    170     QWidget* view = m_webPage->view();
    171     if (!view)
    172         return;
    173     view->topLevelWidget()->show();
    174 }
    175 
    176 
    177 bool ChromeClientQt::canRunModal()
    178 {
    179     return true;
    180 }
    181 
    182 
    183 void ChromeClientQt::runModal()
    184 {
    185     m_eventLoop = new QEventLoop();
    186     QEventLoop* eventLoop = m_eventLoop;
    187     m_eventLoop->exec();
    188     delete eventLoop;
    189 }
    190 
    191 
    192 void ChromeClientQt::setToolbarsVisible(bool visible)
    193 {
    194     toolBarsVisible = visible;
    195     emit m_webPage->toolBarVisibilityChangeRequested(visible);
    196 }
    197 
    198 
    199 bool ChromeClientQt::toolbarsVisible()
    200 {
    201     return toolBarsVisible;
    202 }
    203 
    204 
    205 void ChromeClientQt::setStatusbarVisible(bool visible)
    206 {
    207     emit m_webPage->statusBarVisibilityChangeRequested(visible);
    208     statusBarVisible = visible;
    209 }
    210 
    211 
    212 bool ChromeClientQt::statusbarVisible()
    213 {
    214     return statusBarVisible;
    215     return false;
    216 }
    217 
    218 
    219 void ChromeClientQt::setScrollbarsVisible(bool)
    220 {
    221     notImplemented();
    222 }
    223 
    224 
    225 bool ChromeClientQt::scrollbarsVisible()
    226 {
    227     notImplemented();
    228     return true;
    229 }
    230 
    231 
    232 void ChromeClientQt::setMenubarVisible(bool visible)
    233 {
    234     menuBarVisible = visible;
    235     emit m_webPage->menuBarVisibilityChangeRequested(visible);
    236 }
    237 
    238 bool ChromeClientQt::menubarVisible()
    239 {
    240     return menuBarVisible;
    241 }
    242 
    243 void ChromeClientQt::setResizable(bool)
    244 {
    245     notImplemented();
    246 }
    247 
    248 void ChromeClientQt::addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message,
    249                                          unsigned int lineNumber, const String& sourceID)
    250 {
    251     QString x = message;
    252     QString y = sourceID;
    253     m_webPage->javaScriptConsoleMessage(x, lineNumber, y);
    254 }
    255 
    256 void ChromeClientQt::chromeDestroyed()
    257 {
    258     delete this;
    259 }
    260 
    261 bool ChromeClientQt::canRunBeforeUnloadConfirmPanel()
    262 {
    263     return true;
    264 }
    265 
    266 bool ChromeClientQt::runBeforeUnloadConfirmPanel(const String& message, Frame* frame)
    267 {
    268     return runJavaScriptConfirm(frame, message);
    269 }
    270 
    271 void ChromeClientQt::closeWindowSoon()
    272 {
    273     m_webPage->mainFrame()->d->frame->loader()->stopAllLoaders();
    274     emit m_webPage->windowCloseRequested();
    275 }
    276 
    277 void ChromeClientQt::runJavaScriptAlert(Frame* f, const String& msg)
    278 {
    279     QString x = msg;
    280     FrameLoaderClientQt *fl = static_cast<FrameLoaderClientQt*>(f->loader()->client());
    281     m_webPage->javaScriptAlert(fl->webFrame(), x);
    282 }
    283 
    284 bool ChromeClientQt::runJavaScriptConfirm(Frame* f, const String& msg)
    285 {
    286     QString x = msg;
    287     FrameLoaderClientQt *fl = static_cast<FrameLoaderClientQt*>(f->loader()->client());
    288     return m_webPage->javaScriptConfirm(fl->webFrame(), x);
    289 }
    290 
    291 bool ChromeClientQt::runJavaScriptPrompt(Frame* f, const String& message, const String& defaultValue, String& result)
    292 {
    293     QString x = result;
    294     FrameLoaderClientQt *fl = static_cast<FrameLoaderClientQt*>(f->loader()->client());
    295     bool rc = m_webPage->javaScriptPrompt(fl->webFrame(), (QString)message, (QString)defaultValue, &x);
    296 
    297     // Fix up a quirk in the QInputDialog class. If no input happened the string should be empty
    298     // but it is null. See https://bugs.webkit.org/show_bug.cgi?id=30914.
    299     if (rc && x.isNull())
    300         result = String("");
    301     else
    302         result = x;
    303 
    304     return rc;
    305 }
    306 
    307 void ChromeClientQt::setStatusbarText(const String& msg)
    308 {
    309     QString x = msg;
    310     emit m_webPage->statusBarMessage(x);
    311 }
    312 
    313 bool ChromeClientQt::shouldInterruptJavaScript()
    314 {
    315     bool shouldInterrupt = false;
    316     QMetaObject::invokeMethod(m_webPage, "shouldInterruptJavaScript", Qt::DirectConnection, Q_RETURN_ARG(bool, shouldInterrupt));
    317     return shouldInterrupt;
    318 }
    319 
    320 bool ChromeClientQt::tabsToLinks() const
    321 {
    322     return m_webPage->settings()->testAttribute(QWebSettings::LinksIncludedInFocusChain);
    323 }
    324 
    325 IntRect ChromeClientQt::windowResizerRect() const
    326 {
    327     return IntRect();
    328 }
    329 
    330 void ChromeClientQt::repaint(const IntRect& windowRect, bool contentChanged, bool, bool)
    331 {
    332     // No double buffer, so only update the QWidget if content changed.
    333     if (contentChanged) {
    334         if (platformPageClient()) {
    335             QRect rect(windowRect);
    336             rect = rect.intersected(QRect(QPoint(0, 0), m_webPage->viewportSize()));
    337             if (!rect.isEmpty())
    338                 platformPageClient()->update(rect);
    339         }
    340         emit m_webPage->repaintRequested(windowRect);
    341     }
    342 
    343     // FIXME: There is no "immediate" support for window painting.  This should be done always whenever the flag
    344     // is set.
    345 }
    346 
    347 void ChromeClientQt::scroll(const IntSize& delta, const IntRect& scrollViewRect, const IntRect&)
    348 {
    349     if (platformPageClient())
    350         platformPageClient()->scroll(delta.width(), delta.height(), scrollViewRect);
    351     emit m_webPage->scrollRequested(delta.width(), delta.height(), scrollViewRect);
    352 }
    353 
    354 IntRect ChromeClientQt::windowToScreen(const IntRect& rect) const
    355 {
    356     notImplemented();
    357     return rect;
    358 }
    359 
    360 IntPoint ChromeClientQt::screenToWindow(const IntPoint& point) const
    361 {
    362     notImplemented();
    363     return point;
    364 }
    365 
    366 PlatformPageClient ChromeClientQt::platformPageClient() const
    367 {
    368     return m_webPage->d->client;
    369 }
    370 
    371 void ChromeClientQt::contentsSizeChanged(Frame* frame, const IntSize& size) const
    372 {
    373     emit QWebFramePrivate::kit(frame)->contentsSizeChanged(size);
    374 }
    375 
    376 void ChromeClientQt::mouseDidMoveOverElement(const HitTestResult& result, unsigned)
    377 {
    378     TextDirection dir;
    379     if (result.absoluteLinkURL() != lastHoverURL
    380         || result.title(dir) != lastHoverTitle
    381         || result.textContent() != lastHoverContent) {
    382         lastHoverURL = result.absoluteLinkURL();
    383         lastHoverTitle = result.title(dir);
    384         lastHoverContent = result.textContent();
    385         emit m_webPage->linkHovered(lastHoverURL.prettyURL(),
    386                 lastHoverTitle, lastHoverContent);
    387     }
    388 }
    389 
    390 void ChromeClientQt::setToolTip(const String &tip, TextDirection)
    391 {
    392 #ifndef QT_NO_TOOLTIP
    393     QWidget* view = m_webPage->view();
    394     if (!view)
    395         return;
    396 
    397     if (tip.isEmpty()) {
    398         view->setToolTip(QString());
    399         QToolTip::hideText();
    400     } else {
    401         QString dtip = QLatin1String("<p>") + Qt::escape(tip) + QLatin1String("</p>");
    402         view->setToolTip(dtip);
    403     }
    404 #else
    405     Q_UNUSED(tip);
    406 #endif
    407 }
    408 
    409 void ChromeClientQt::print(Frame *frame)
    410 {
    411     emit m_webPage->printRequested(QWebFramePrivate::kit(frame));
    412 }
    413 
    414 #if ENABLE(DATABASE)
    415 void ChromeClientQt::exceededDatabaseQuota(Frame* frame, const String& databaseName)
    416 {
    417     quint64 quota = QWebSettings::offlineStorageDefaultQuota();
    418 
    419     if (!DatabaseTracker::tracker().hasEntryForOrigin(frame->document()->securityOrigin()))
    420         DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), quota);
    421 
    422     emit m_webPage->databaseQuotaExceeded(QWebFramePrivate::kit(frame), databaseName);
    423 }
    424 #endif
    425 
    426 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
    427 void ChromeClientQt::reachedMaxAppCacheSize(int64_t)
    428 {
    429     // FIXME: Free some space.
    430     notImplemented();
    431 }
    432 #endif
    433 
    434 void ChromeClientQt::runOpenPanel(Frame* frame, PassRefPtr<FileChooser> prpFileChooser)
    435 {
    436     RefPtr<FileChooser> fileChooser = prpFileChooser;
    437     bool supportMulti = m_webPage->supportsExtension(QWebPage::ChooseMultipleFilesExtension);
    438 
    439     if (fileChooser->allowsMultipleFiles() && supportMulti) {
    440         QWebPage::ChooseMultipleFilesExtensionOption option;
    441         option.parentFrame = QWebFramePrivate::kit(frame);
    442 
    443         if (!fileChooser->filenames().isEmpty())
    444             for (unsigned i = 0; i < fileChooser->filenames().size(); ++i)
    445                 option.suggestedFileNames += fileChooser->filenames()[i];
    446 
    447         QWebPage::ChooseMultipleFilesExtensionReturn output;
    448         m_webPage->extension(QWebPage::ChooseMultipleFilesExtension, &option, &output);
    449 
    450         if (!output.fileNames.isEmpty()) {
    451             Vector<String> names;
    452             for (int i = 0; i < output.fileNames.count(); ++i)
    453                 names.append(output.fileNames.at(i));
    454             fileChooser->chooseFiles(names);
    455         }
    456     } else {
    457         QString suggestedFile;
    458         if (!fileChooser->filenames().isEmpty())
    459             suggestedFile = fileChooser->filenames()[0];
    460         QString file = m_webPage->chooseFile(QWebFramePrivate::kit(frame), suggestedFile);
    461         if (!file.isEmpty())
    462             fileChooser->chooseFile(file);
    463     }
    464 }
    465 
    466 bool ChromeClientQt::setCursor(PlatformCursorHandle)
    467 {
    468     notImplemented();
    469     return false;
    470 }
    471 
    472 void ChromeClientQt::requestGeolocationPermissionForFrame(Frame*, Geolocation*)
    473 {
    474     // See the comment in WebCore/page/ChromeClient.h
    475     notImplemented();
    476 }
    477 
    478 #if USE(ACCELERATED_COMPOSITING)
    479 void ChromeClientQt::attachRootGraphicsLayer(Frame* frame, GraphicsLayer* graphicsLayer)
    480 {
    481     if (platformPageClient())
    482         platformPageClient()->setRootGraphicsLayer(graphicsLayer ? graphicsLayer->nativeLayer() : 0);
    483 }
    484 
    485 void ChromeClientQt::setNeedsOneShotDrawingSynchronization()
    486 {
    487     // we want the layers to synchronize next time we update the screen anyway
    488     if (platformPageClient())
    489         platformPageClient()->markForSync(false);
    490 }
    491 
    492 void ChromeClientQt::scheduleCompositingLayerSync()
    493 {
    494     // we want the layers to synchronize ASAP
    495     if (platformPageClient())
    496         platformPageClient()->markForSync(true);
    497 }
    498 #endif
    499 
    500 QtAbstractWebPopup* ChromeClientQt::createSelectPopup()
    501 {
    502     return new QtFallbackWebPopup;
    503 }
    504 
    505 }
    506