Home | History | Annotate | Download | only in WebCoreSupport
      1 /*
      2  * Copyright (C) 2007, 2008 Holger Hans Peter Freyther
      3  * Copyright (C) 2007, 2008 Christian Dywan <christian (at) imendio.com>
      4  * Copyright (C) 2008 Nuanti Ltd.
      5  * Copyright (C) 2008 Alp Toker <alp (at) atoker.com>
      6  * Copyright (C) 2008 Gustavo Noronha Silva <gns (at) gnome.org>
      7  * Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
      8  *
      9  *  This library is free software; you can redistribute it and/or
     10  *  modify it under the terms of the GNU Lesser General Public
     11  *  License as published by the Free Software Foundation; either
     12  *  version 2 of the License, or (at your option) any later version.
     13  *
     14  *  This library is distributed in the hope that it will be useful,
     15  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
     16  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     17  *  Lesser General Public License for more details.
     18  *
     19  *  You should have received a copy of the GNU Lesser General Public
     20  *  License along with this library; if not, write to the Free Software
     21  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
     22  */
     23 
     24 #include "config.h"
     25 #include "ChromeClientGtk.h"
     26 
     27 #include "Chrome.h"
     28 #include "Console.h"
     29 #include "DumpRenderTreeSupportGtk.h"
     30 #include "Element.h"
     31 #include "FileChooser.h"
     32 #include "FileSystem.h"
     33 #include "FloatRect.h"
     34 #include "FrameLoadRequest.h"
     35 #include "FrameView.h"
     36 #include "GtkVersioning.h"
     37 #include "HTMLNames.h"
     38 #include "HitTestResult.h"
     39 #include "Icon.h"
     40 #include "IntRect.h"
     41 #include "KURL.h"
     42 #include "NavigationAction.h"
     43 #include "NotImplemented.h"
     44 #include "PlatformString.h"
     45 #include "PopupMenuClient.h"
     46 #include "PopupMenuGtk.h"
     47 #include "SearchPopupMenuGtk.h"
     48 #include "SecurityOrigin.h"
     49 #include "WindowFeatures.h"
     50 #include "webkitgeolocationpolicydecision.h"
     51 #include "webkitgeolocationpolicydecisionprivate.h"
     52 #include "webkitnetworkrequest.h"
     53 #include "webkitsecurityoriginprivate.h"
     54 #include "webkitviewportattributesprivate.h"
     55 #include "webkitwebframeprivate.h"
     56 #include "webkitwebview.h"
     57 #include "webkitwebviewprivate.h"
     58 #include "webkitwebwindowfeaturesprivate.h"
     59 #include <glib.h>
     60 #include <glib/gi18n-lib.h>
     61 #include <gtk/gtk.h>
     62 #include <wtf/text/CString.h>
     63 
     64 #if ENABLE(DATABASE)
     65 #include "DatabaseTracker.h"
     66 #endif
     67 
     68 using namespace WebCore;
     69 
     70 namespace WebKit {
     71 
     72 ChromeClient::ChromeClient(WebKitWebView* webView)
     73     : m_webView(webView)
     74     , m_closeSoonTimer(0)
     75     , m_pendingScrollInvalidations(false)
     76 {
     77     ASSERT(m_webView);
     78 }
     79 
     80 void ChromeClient::chromeDestroyed()
     81 {
     82     if (m_closeSoonTimer)
     83         g_source_remove(m_closeSoonTimer);
     84 
     85     delete this;
     86 }
     87 
     88 FloatRect ChromeClient::windowRect()
     89 {
     90     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
     91     if (gtk_widget_is_toplevel(window)) {
     92         gint left, top, width, height;
     93         gtk_window_get_position(GTK_WINDOW(window), &left, &top);
     94         gtk_window_get_size(GTK_WINDOW(window), &width, &height);
     95         return IntRect(left, top, width, height);
     96     }
     97     return FloatRect();
     98 }
     99 
    100 void ChromeClient::setWindowRect(const FloatRect& rect)
    101 {
    102     IntRect intrect = IntRect(rect);
    103     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    104 
    105     g_object_set(webWindowFeatures,
    106                  "x", intrect.x(),
    107                  "y", intrect.y(),
    108                  "width", intrect.width(),
    109                  "height", intrect.height(),
    110                  NULL);
    111 
    112     gboolean autoResizeWindow;
    113     WebKitWebSettings* settings = webkit_web_view_get_settings(m_webView);
    114     g_object_get(settings, "auto-resize-window", &autoResizeWindow, NULL);
    115 
    116     if (!autoResizeWindow)
    117         return;
    118 
    119     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
    120     if (gtk_widget_is_toplevel(window)) {
    121         gtk_window_move(GTK_WINDOW(window), intrect.x(), intrect.y());
    122         gtk_window_resize(GTK_WINDOW(window), intrect.width(), intrect.height());
    123     }
    124 }
    125 
    126 FloatRect ChromeClient::pageRect()
    127 {
    128     GtkAllocation allocation;
    129 #if GTK_CHECK_VERSION(2, 18, 0)
    130     gtk_widget_get_allocation(GTK_WIDGET(m_webView), &allocation);
    131 #else
    132     allocation = GTK_WIDGET(m_webView)->allocation;
    133 #endif
    134     return IntRect(allocation.x, allocation.y, allocation.width, allocation.height);
    135 }
    136 
    137 float ChromeClient::scaleFactor()
    138 {
    139     // Not implementable
    140     return 1.0;
    141 }
    142 
    143 void ChromeClient::focus()
    144 {
    145     gtk_widget_grab_focus(GTK_WIDGET(m_webView));
    146 }
    147 
    148 void ChromeClient::unfocus()
    149 {
    150     GtkWidget* window = gtk_widget_get_toplevel(GTK_WIDGET(m_webView));
    151     if (gtk_widget_is_toplevel(window))
    152         gtk_window_set_focus(GTK_WINDOW(window), NULL);
    153 }
    154 
    155 Page* ChromeClient::createWindow(Frame* frame, const FrameLoadRequest& frameLoadRequest, const WindowFeatures& coreFeatures, const NavigationAction&)
    156 {
    157     WebKitWebView* webView = 0;
    158 
    159     g_signal_emit_by_name(m_webView, "create-web-view", kit(frame), &webView);
    160 
    161     if (!webView)
    162         return 0;
    163 
    164     GRefPtr<WebKitWebWindowFeatures> webWindowFeatures(adoptGRef(kitNew(coreFeatures)));
    165     g_object_set(webView, "window-features", webWindowFeatures.get(), NULL);
    166 
    167     return core(webView);
    168 }
    169 
    170 void ChromeClient::show()
    171 {
    172     webkit_web_view_notify_ready(m_webView);
    173 }
    174 
    175 bool ChromeClient::canRunModal()
    176 {
    177     notImplemented();
    178     return false;
    179 }
    180 
    181 void ChromeClient::runModal()
    182 {
    183     notImplemented();
    184 }
    185 
    186 void ChromeClient::setToolbarsVisible(bool visible)
    187 {
    188     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    189 
    190     g_object_set(webWindowFeatures, "toolbar-visible", visible, NULL);
    191 }
    192 
    193 bool ChromeClient::toolbarsVisible()
    194 {
    195     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    196     gboolean visible;
    197 
    198     g_object_get(webWindowFeatures, "toolbar-visible", &visible, NULL);
    199     return visible;
    200 }
    201 
    202 void ChromeClient::setStatusbarVisible(bool visible)
    203 {
    204     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    205 
    206     g_object_set(webWindowFeatures, "statusbar-visible", visible, NULL);
    207 }
    208 
    209 bool ChromeClient::statusbarVisible()
    210 {
    211     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    212     gboolean visible;
    213 
    214     g_object_get(webWindowFeatures, "statusbar-visible", &visible, NULL);
    215     return visible;
    216 }
    217 
    218 void ChromeClient::setScrollbarsVisible(bool visible)
    219 {
    220     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    221 
    222     g_object_set(webWindowFeatures, "scrollbar-visible", visible, NULL);
    223 }
    224 
    225 bool ChromeClient::scrollbarsVisible()
    226 {
    227     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    228     gboolean visible;
    229 
    230     g_object_get(webWindowFeatures, "scrollbar-visible", &visible, NULL);
    231     return visible;
    232 }
    233 
    234 void ChromeClient::setMenubarVisible(bool visible)
    235 {
    236     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    237 
    238     g_object_set(webWindowFeatures, "menubar-visible", visible, NULL);
    239 }
    240 
    241 bool ChromeClient::menubarVisible()
    242 {
    243     WebKitWebWindowFeatures* webWindowFeatures = webkit_web_view_get_window_features(m_webView);
    244     gboolean visible;
    245 
    246     g_object_get(webWindowFeatures, "menubar-visible", &visible, NULL);
    247     return visible;
    248 }
    249 
    250 void ChromeClient::setResizable(bool)
    251 {
    252     // Ignored for now
    253 }
    254 
    255 static gboolean emitCloseWebViewSignalLater(WebKitWebView* view)
    256 {
    257     gboolean isHandled;
    258     g_signal_emit_by_name(view, "close-web-view", &isHandled);
    259     return FALSE;
    260 }
    261 
    262 void ChromeClient::closeWindowSoon()
    263 {
    264     // We may not have a WebView as create-web-view can return NULL.
    265     if (!m_webView)
    266         return;
    267     if (m_closeSoonTimer) // Don't call close-web-view more than once.
    268         return;
    269 
    270     // We need to remove the parent WebView from WebViewSets here, before it actually
    271     // closes, to make sure that JavaScript code that executes before it closes
    272     // can't find it. Otherwise, window.open will select a closed WebView instead of
    273     // opening a new one <rdar://problem/3572585>.
    274     m_webView->priv->corePage->setGroupName("");
    275 
    276     // We also need to stop the load to prevent further parsing or JavaScript execution
    277     // after the window has torn down <rdar://problem/4161660>.
    278     webkit_web_view_stop_loading(m_webView);
    279 
    280     // Clients commonly destroy the web view during the close-web-view signal, but our caller
    281     // may need to send more signals to the web view. For instance, if this happened in the
    282     // onload handler, it will need to call FrameLoaderClient::dispatchDidHandleOnloadEvents.
    283     // Instead of firing the close-web-view signal now, fire it after the caller finishes.
    284     // This seems to match the Mac/Windows port behavior.
    285     m_closeSoonTimer = g_timeout_add(0, reinterpret_cast<GSourceFunc>(emitCloseWebViewSignalLater), m_webView);
    286 }
    287 
    288 bool ChromeClient::canTakeFocus(FocusDirection)
    289 {
    290     return gtk_widget_get_can_focus(GTK_WIDGET(m_webView));
    291 }
    292 
    293 void ChromeClient::takeFocus(FocusDirection)
    294 {
    295     unfocus();
    296 }
    297 
    298 void ChromeClient::focusedNodeChanged(Node*)
    299 {
    300 }
    301 
    302 void ChromeClient::focusedFrameChanged(Frame*)
    303 {
    304 }
    305 
    306 bool ChromeClient::canRunBeforeUnloadConfirmPanel()
    307 {
    308     return true;
    309 }
    310 
    311 bool ChromeClient::runBeforeUnloadConfirmPanel(const WTF::String& message, WebCore::Frame* frame)
    312 {
    313     return runJavaScriptConfirm(frame, message);
    314 }
    315 
    316 void ChromeClient::addMessageToConsole(WebCore::MessageSource source, WebCore::MessageType type, WebCore::MessageLevel level, const WTF::String& message, unsigned int lineNumber, const WTF::String& sourceId)
    317 {
    318     gboolean retval;
    319     g_signal_emit_by_name(m_webView, "console-message", message.utf8().data(), lineNumber, sourceId.utf8().data(), &retval);
    320 }
    321 
    322 void ChromeClient::runJavaScriptAlert(Frame* frame, const String& message)
    323 {
    324     gboolean retval;
    325     g_signal_emit_by_name(m_webView, "script-alert", kit(frame), message.utf8().data(), &retval);
    326 }
    327 
    328 bool ChromeClient::runJavaScriptConfirm(Frame* frame, const String& message)
    329 {
    330     gboolean retval;
    331     gboolean didConfirm;
    332     g_signal_emit_by_name(m_webView, "script-confirm", kit(frame), message.utf8().data(), &didConfirm, &retval);
    333     return didConfirm == TRUE;
    334 }
    335 
    336 bool ChromeClient::runJavaScriptPrompt(Frame* frame, const String& message, const String& defaultValue, String& result)
    337 {
    338     gboolean retval;
    339     gchar* value = 0;
    340     g_signal_emit_by_name(m_webView, "script-prompt", kit(frame), message.utf8().data(), defaultValue.utf8().data(), &value, &retval);
    341     if (value) {
    342         result = String::fromUTF8(value);
    343         g_free(value);
    344         return true;
    345     }
    346     return false;
    347 }
    348 
    349 void ChromeClient::setStatusbarText(const String& string)
    350 {
    351     CString stringMessage = string.utf8();
    352     g_signal_emit_by_name(m_webView, "status-bar-text-changed", stringMessage.data());
    353 }
    354 
    355 bool ChromeClient::shouldInterruptJavaScript()
    356 {
    357     notImplemented();
    358     return false;
    359 }
    360 
    361 KeyboardUIMode ChromeClient::keyboardUIMode()
    362 {
    363     bool tabsToLinks = true;
    364     if (DumpRenderTreeSupportGtk::dumpRenderTreeModeEnabled())
    365         tabsToLinks = DumpRenderTreeSupportGtk::linksIncludedInFocusChain();
    366 
    367     return tabsToLinks ? KeyboardAccessTabsToLinks : KeyboardAccessDefault;
    368 }
    369 
    370 IntRect ChromeClient::windowResizerRect() const
    371 {
    372     notImplemented();
    373     return IntRect();
    374 }
    375 
    376 void ChromeClient::invalidateWindow(const IntRect&, bool immediate)
    377 {
    378     // If we've invalidated regions for scrolling, force GDK to process those invalidations
    379     // now. This will also cause child windows to move right away. This prevents redraw
    380     // artifacts with child windows (e.g. Flash plugin instances).
    381     if (immediate && m_pendingScrollInvalidations) {
    382         m_pendingScrollInvalidations = false;
    383         if (GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView)))
    384             gdk_window_process_updates(window, TRUE);
    385     }
    386 }
    387 
    388 void ChromeClient::invalidateContentsAndWindow(const IntRect& updateRect, bool immediate)
    389 {
    390     GdkRectangle rect = updateRect;
    391     GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView));
    392 
    393     if (window && !updateRect.isEmpty()) {
    394         gdk_window_invalidate_rect(window, &rect, FALSE);
    395         // We don't currently do immediate updates since they delay other UI elements.
    396         //if (immediate)
    397         //    gdk_window_process_updates(window, FALSE);
    398     }
    399 }
    400 
    401 void ChromeClient::invalidateContentsForSlowScroll(const IntRect& updateRect, bool immediate)
    402 {
    403     invalidateContentsAndWindow(updateRect, immediate);
    404 }
    405 
    406 void ChromeClient::scroll(const IntSize& delta, const IntRect& rectToScroll, const IntRect& clipRect)
    407 {
    408     GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(m_webView));
    409     if (!window)
    410         return;
    411 
    412     m_pendingScrollInvalidations = true;
    413 
    414     // We cannot use gdk_window_scroll here because it is only able to
    415     // scroll the whole window at once, and we often need to scroll
    416     // portions of the window only (think frames).
    417     GdkRectangle area = clipRect;
    418     GdkRectangle moveRect;
    419 
    420     GdkRectangle sourceRect = area;
    421     sourceRect.x -= delta.width();
    422     sourceRect.y -= delta.height();
    423 
    424 #ifdef GTK_API_VERSION_2
    425     GdkRegion* invalidRegion = gdk_region_rectangle(&area);
    426 
    427     if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) {
    428         GdkRegion* moveRegion = gdk_region_rectangle(&moveRect);
    429         gdk_window_move_region(window, moveRegion, delta.width(), delta.height());
    430         gdk_region_offset(moveRegion, delta.width(), delta.height());
    431         gdk_region_subtract(invalidRegion, moveRegion);
    432         gdk_region_destroy(moveRegion);
    433     }
    434 
    435     gdk_window_invalidate_region(window, invalidRegion, FALSE);
    436     gdk_region_destroy(invalidRegion);
    437 #else
    438     cairo_region_t* invalidRegion = cairo_region_create_rectangle(&area);
    439 
    440     if (gdk_rectangle_intersect(&area, &sourceRect, &moveRect)) {
    441         cairo_region_t* moveRegion = cairo_region_create_rectangle(&moveRect);
    442         gdk_window_move_region(window, moveRegion, delta.width(), delta.height());
    443         cairo_region_translate(moveRegion, delta.width(), delta.height());
    444         cairo_region_subtract(invalidRegion, moveRegion);
    445         cairo_region_destroy(moveRegion);
    446     }
    447 
    448     gdk_window_invalidate_region(window, invalidRegion, FALSE);
    449     cairo_region_destroy(invalidRegion);
    450 #endif
    451 }
    452 
    453 // FIXME: this does not take into account the WM decorations
    454 static IntPoint widgetScreenPosition(GtkWidget* widget)
    455 {
    456     GtkWidget* window = gtk_widget_get_toplevel(widget);
    457     int widgetX = 0, widgetY = 0;
    458 
    459     gtk_widget_translate_coordinates(widget, window, 0, 0, &widgetX, &widgetY);
    460 
    461     IntPoint result(widgetX, widgetY);
    462     int originX, originY;
    463     gdk_window_get_origin(gtk_widget_get_window(window), &originX, &originY);
    464     result.move(originX, originY);
    465 
    466     return result;
    467 }
    468 
    469 IntRect ChromeClient::windowToScreen(const IntRect& rect) const
    470 {
    471     IntRect result(rect);
    472     IntPoint screenPosition = widgetScreenPosition(GTK_WIDGET(m_webView));
    473     result.move(screenPosition.x(), screenPosition.y());
    474 
    475     return result;
    476 }
    477 
    478 IntPoint ChromeClient::screenToWindow(const IntPoint& point) const
    479 {
    480     IntPoint result(point);
    481     IntPoint screenPosition = widgetScreenPosition(GTK_WIDGET(m_webView));
    482     result.move(-screenPosition.x(), -screenPosition.y());
    483 
    484     return result;
    485 }
    486 
    487 PlatformPageClient ChromeClient::platformPageClient() const
    488 {
    489     return GTK_WIDGET(m_webView);
    490 }
    491 
    492 void ChromeClient::contentsSizeChanged(Frame* frame, const IntSize& size) const
    493 {
    494     // We need to queue a resize request only if the size changed,
    495     // otherwise we get into an infinite loop!
    496     GtkWidget* widget = GTK_WIDGET(m_webView);
    497     GtkRequisition requisition;
    498 #if GTK_CHECK_VERSION(2, 20, 0)
    499     gtk_widget_get_requisition(widget, &requisition);
    500 #else
    501     requisition = widget->requisition;
    502 #endif
    503     if (gtk_widget_get_realized(widget)
    504         && (requisition.height != size.height())
    505         || (requisition.width != size.width()))
    506         gtk_widget_queue_resize_no_redraw(widget);
    507 }
    508 
    509 void ChromeClient::scrollbarsModeDidChange() const
    510 {
    511     WebKitWebFrame* webFrame = webkit_web_view_get_main_frame(m_webView);
    512 
    513     g_object_notify(G_OBJECT(webFrame), "horizontal-scrollbar-policy");
    514     g_object_notify(G_OBJECT(webFrame), "vertical-scrollbar-policy");
    515 
    516     gboolean isHandled;
    517     g_signal_emit_by_name(webFrame, "scrollbars-policy-changed", &isHandled);
    518 
    519     if (isHandled)
    520         return;
    521 
    522     GtkWidget* parent = gtk_widget_get_parent(GTK_WIDGET(m_webView));
    523     if (!parent || !GTK_IS_SCROLLED_WINDOW(parent))
    524         return;
    525 
    526     GtkPolicyType horizontalPolicy = webkit_web_frame_get_horizontal_scrollbar_policy(webFrame);
    527     GtkPolicyType verticalPolicy = webkit_web_frame_get_vertical_scrollbar_policy(webFrame);
    528 
    529     // ScrolledWindow doesn't like to display only part of a widget if
    530     // the scrollbars are completely disabled; We have a disparity
    531     // here on what the policy requested by the web app is and what we
    532     // can represent; the idea is not to show scrollbars, only.
    533     if (horizontalPolicy == GTK_POLICY_NEVER)
    534         horizontalPolicy = GTK_POLICY_AUTOMATIC;
    535 
    536     if (verticalPolicy == GTK_POLICY_NEVER)
    537         verticalPolicy = GTK_POLICY_AUTOMATIC;
    538 
    539     gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(parent),
    540                                    horizontalPolicy, verticalPolicy);
    541 }
    542 
    543 void ChromeClient::mouseDidMoveOverElement(const HitTestResult& hit, unsigned modifierFlags)
    544 {
    545     // check if the element is a link...
    546     bool isLink = hit.isLiveLink();
    547     if (isLink) {
    548         KURL url = hit.absoluteLinkURL();
    549         if (!url.isEmpty() && url != m_hoveredLinkURL) {
    550             TextDirection dir;
    551             CString titleString = hit.title(dir).utf8();
    552             CString urlString = url.prettyURL().utf8();
    553             g_signal_emit_by_name(m_webView, "hovering-over-link", titleString.data(), urlString.data());
    554             m_hoveredLinkURL = url;
    555         }
    556     } else if (!isLink && !m_hoveredLinkURL.isEmpty()) {
    557         g_signal_emit_by_name(m_webView, "hovering-over-link", 0, 0);
    558         m_hoveredLinkURL = KURL();
    559     }
    560 
    561     if (Node* node = hit.innerNonSharedNode()) {
    562         Frame* frame = node->document()->frame();
    563         FrameView* view = frame ? frame->view() : 0;
    564         m_webView->priv->tooltipArea = view ? view->contentsToWindow(node->getRect()) : IntRect();
    565     } else
    566         m_webView->priv->tooltipArea = IntRect();
    567 }
    568 
    569 void ChromeClient::setToolTip(const String& toolTip, TextDirection)
    570 {
    571     webkit_web_view_set_tooltip_text(m_webView, toolTip.utf8().data());
    572 }
    573 
    574 void ChromeClient::print(Frame* frame)
    575 {
    576     WebKitWebFrame* webFrame = kit(frame);
    577     gboolean isHandled = false;
    578     g_signal_emit_by_name(m_webView, "print-requested", webFrame, &isHandled);
    579 
    580     if (isHandled)
    581         return;
    582 
    583     webkit_web_frame_print(webFrame);
    584 }
    585 
    586 #if ENABLE(DATABASE)
    587 void ChromeClient::exceededDatabaseQuota(Frame* frame, const String& databaseName)
    588 {
    589     guint64 defaultQuota = webkit_get_default_web_database_quota();
    590     DatabaseTracker::tracker().setQuota(frame->document()->securityOrigin(), defaultQuota);
    591 
    592     WebKitWebFrame* webFrame = kit(frame);
    593     WebKitSecurityOrigin* origin = webkit_web_frame_get_security_origin(webFrame);
    594     WebKitWebDatabase* webDatabase = webkit_security_origin_get_web_database(origin, databaseName.utf8().data());
    595     g_signal_emit_by_name(m_webView, "database-quota-exceeded", webFrame, webDatabase);
    596 }
    597 #endif
    598 
    599 #if ENABLE(OFFLINE_WEB_APPLICATIONS)
    600 void ChromeClient::reachedMaxAppCacheSize(int64_t spaceNeeded)
    601 {
    602     // FIXME: Free some space.
    603     notImplemented();
    604 }
    605 
    606 void ChromeClient::reachedApplicationCacheOriginQuota(SecurityOrigin*)
    607 {
    608     notImplemented();
    609 }
    610 #endif
    611 
    612 void ChromeClient::runOpenPanel(Frame*, PassRefPtr<FileChooser> prpFileChooser)
    613 {
    614     RefPtr<FileChooser> chooser = prpFileChooser;
    615 
    616     GtkWidget* dialog = gtk_file_chooser_dialog_new(_("Upload File"),
    617                                                     GTK_WINDOW(gtk_widget_get_toplevel(GTK_WIDGET(m_webView))),
    618                                                     GTK_FILE_CHOOSER_ACTION_OPEN,
    619                                                     GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
    620                                                     GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
    621                                                     NULL);
    622 
    623     gtk_file_chooser_set_select_multiple(GTK_FILE_CHOOSER(dialog), chooser->allowsMultipleFiles());
    624 
    625     if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
    626         if (gtk_file_chooser_get_select_multiple(GTK_FILE_CHOOSER(dialog))) {
    627             GSList* filenames = gtk_file_chooser_get_filenames(GTK_FILE_CHOOSER(dialog));
    628             Vector<String> names;
    629             for (GSList* item = filenames ; item ; item = item->next) {
    630                 if (!item->data)
    631                     continue;
    632                 names.append(filenameToString(static_cast<char*>(item->data)));
    633                 g_free(item->data);
    634             }
    635             g_slist_free(filenames);
    636             chooser->chooseFiles(names);
    637         } else {
    638             gchar* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    639             if (filename)
    640                 chooser->chooseFile(filenameToString(filename));
    641             g_free(filename);
    642         }
    643     }
    644     gtk_widget_destroy(dialog);
    645 }
    646 
    647 void ChromeClient::chooseIconForFiles(const Vector<WTF::String>& filenames, WebCore::FileChooser* chooser)
    648 {
    649     chooser->iconLoaded(Icon::createIconForFiles(filenames));
    650 }
    651 
    652 void ChromeClient::dispatchViewportDataDidChange(const ViewportArguments& arguments) const
    653 {
    654     // Recompute the viewport attributes making it valid.
    655     webkitViewportAttributesRecompute(webkit_web_view_get_viewport_attributes(m_webView));
    656 }
    657 
    658 void ChromeClient::setCursor(const Cursor& cursor)
    659 {
    660     // [GTK] Widget::setCursor() gets called frequently
    661     // http://bugs.webkit.org/show_bug.cgi?id=16388
    662     // Setting the cursor may be an expensive operation in some backends,
    663     // so don't re-set the cursor if it's already set to the target value.
    664     GdkWindow* window = gtk_widget_get_window(platformPageClient());
    665     GdkCursor* currentCursor = gdk_window_get_cursor(window);
    666     GdkCursor* newCursor = cursor.platformCursor().get();
    667     if (currentCursor != newCursor)
    668         gdk_window_set_cursor(window, newCursor);
    669 }
    670 
    671 void ChromeClient::requestGeolocationPermissionForFrame(Frame* frame, Geolocation* geolocation)
    672 {
    673     WebKitWebFrame* webFrame = kit(frame);
    674     GRefPtr<WebKitGeolocationPolicyDecision> policyDecision(adoptGRef(webkit_geolocation_policy_decision_new(webFrame, geolocation)));
    675 
    676     gboolean isHandled = FALSE;
    677     g_signal_emit_by_name(m_webView, "geolocation-policy-decision-requested", webFrame, policyDecision.get(), &isHandled);
    678     if (!isHandled)
    679         webkit_geolocation_policy_deny(policyDecision.get());
    680 }
    681 
    682 void ChromeClient::cancelGeolocationPermissionRequestForFrame(WebCore::Frame* frame, WebCore::Geolocation*)
    683 {
    684     g_signal_emit_by_name(m_webView, "geolocation-policy-decision-cancelled", kit(frame));
    685 }
    686 
    687 bool ChromeClient::selectItemWritingDirectionIsNatural()
    688 {
    689     return true;
    690 }
    691 
    692 bool ChromeClient::selectItemAlignmentFollowsMenuWritingDirection()
    693 {
    694     return false;
    695 }
    696 
    697 PassRefPtr<WebCore::PopupMenu> ChromeClient::createPopupMenu(WebCore::PopupMenuClient* client) const
    698 {
    699     return adoptRef(new PopupMenuGtk(client));
    700 }
    701 
    702 PassRefPtr<WebCore::SearchPopupMenu> ChromeClient::createSearchPopupMenu(WebCore::PopupMenuClient* client) const
    703 {
    704     return adoptRef(new SearchPopupMenuGtk(client));
    705 }
    706 
    707 #if ENABLE(VIDEO)
    708 
    709 bool ChromeClient::supportsFullscreenForNode(const Node* node)
    710 {
    711     return node->hasTagName(HTMLNames::videoTag);
    712 }
    713 
    714 void ChromeClient::enterFullscreenForNode(Node* node)
    715 {
    716     webViewEnterFullscreen(m_webView, node);
    717 }
    718 
    719 void ChromeClient::exitFullscreenForNode(Node* node)
    720 {
    721     webViewExitFullscreen(m_webView);
    722 }
    723 #endif
    724 
    725 #if ENABLE(FULLSCREEN_API)
    726 bool ChromeClient::supportsFullScreenForElement(const WebCore::Element* element, bool withKeyboard)
    727 {
    728     if (withKeyboard)
    729         return false;
    730 
    731     return true;
    732 }
    733 
    734 void ChromeClient::enterFullScreenForElement(WebCore::Element* element)
    735 {
    736     element->document()->webkitWillEnterFullScreenForElement(element);
    737     element->document()->webkitDidEnterFullScreenForElement(element);
    738 }
    739 
    740 void ChromeClient::exitFullScreenForElement(WebCore::Element* element)
    741 {
    742     element->document()->webkitWillExitFullScreenForElement(element);
    743     element->document()->webkitDidExitFullScreenForElement(element);
    744 }
    745 #endif
    746 
    747 
    748 }
    749