1/*
2 *  Copyright (C) 2007, 2008 Alp Toker <alp@atoker.com>
3 *  Copyright (C) 2007, 2008, 2009 Holger Hans Peter Freyther
4 *  Copyright (C) 2007 Christian Dywan <christian@twotoasts.de>
5 *  Copyright (C) 2008, 2009 Collabora Ltd.  All rights reserved.
6 *  Copyright (C) 2009, 2010 Gustavo Noronha Silva <gns@gnome.org>
7 *  Copyright (C) Research In Motion Limited 2009. All rights reserved.
8 *  Copyright (C) 2010 Igalia S.L.
9 *  Copyright (C) 2011 Apple Inc. All rights reserved.
10 *
11 *  This library is free software; you can redistribute it and/or
12 *  modify it under the terms of the GNU Lesser General Public
13 *  License as published by the Free Software Foundation; either
14 *  version 2 of the License, or (at your option) any later version.
15 *
16 *  This library is distributed in the hope that it will be useful,
17 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
18 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
19 *  Lesser General Public License for more details.
20 *
21 *  You should have received a copy of the GNU Lesser General Public
22 *  License along with this library; if not, write to the Free Software
23 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
24 */
25
26#include "config.h"
27#include "FrameLoaderClientGtk.h"
28
29#include "AXObjectCache.h"
30#include "AccessibilityObject.h"
31#include "ArchiveResource.h"
32#include "CachedFrame.h"
33#include "Color.h"
34#include "DOMObjectCache.h"
35#include "DocumentLoader.h"
36#include "DocumentLoaderGtk.h"
37#include "FormState.h"
38#include "FrameLoader.h"
39#include "FrameNetworkingContextGtk.h"
40#include "FrameTree.h"
41#include "FrameView.h"
42#include "GOwnPtr.h"
43#include "GRefPtr.h"
44#include "GtkPluginWidget.h"
45#include "HTMLAppletElement.h"
46#include "HTMLFormElement.h"
47#include "HTMLFrameElement.h"
48#include "HTMLFrameOwnerElement.h"
49#include "HTMLNames.h"
50#include "HTMLPlugInElement.h"
51#include "JSDOMBinding.h"
52#include "JSDOMWindow.h"
53#include "Language.h"
54#include "MIMETypeRegistry.h"
55#include "MouseEvent.h"
56#include "NotImplemented.h"
57#include "Page.h"
58#include "PluginDatabase.h"
59#include "ProgressTracker.h"
60#include "RenderPart.h"
61#include "RenderView.h"
62#include "ResourceHandle.h"
63#include "ResourceRequest.h"
64#include "ScriptController.h"
65#include "Settings.h"
66#include "webkiterror.h"
67#include "webkitglobals.h"
68#include "webkitglobalsprivate.h"
69#include "webkiticondatabase.h"
70#include "webkitnetworkrequest.h"
71#include "webkitnetworkrequestprivate.h"
72#include "webkitnetworkresponse.h"
73#include "webkitnetworkresponseprivate.h"
74#include "webkitviewportattributes.h"
75#include "webkitviewportattributesprivate.h"
76#include "webkitwebdatasourceprivate.h"
77#include "webkitwebframe.h"
78#include "webkitwebframeprivate.h"
79#include "webkitwebnavigationaction.h"
80#include "webkitwebnavigationactionprivate.h"
81#include "webkitwebpolicydecision.h"
82#include "webkitwebpolicydecisionprivate.h"
83#include "webkitwebresource.h"
84#include "webkitwebresourceprivate.h"
85#include "webkitwebsettingsprivate.h"
86#include "webkitwebview.h"
87#include "webkitwebviewprivate.h"
88#include <JavaScriptCore/APICast.h>
89#include <gio/gio.h>
90#include <glib.h>
91#include <glib/gi18n-lib.h>
92#include <stdio.h>
93#include <wtf/text/CString.h>
94#include <wtf/text/StringConcatenate.h>
95
96using namespace WebCore;
97
98namespace WebKit {
99
100FrameLoaderClient::FrameLoaderClient(WebKitWebFrame* frame)
101    : m_frame(frame)
102    , m_policyDecision(0)
103    , m_loadingErrorPage(false)
104    , m_pluginView(0)
105    , m_hasSentResponseToPlugin(false)
106    , m_hasRepresentation(false)
107{
108    ASSERT(m_frame);
109}
110
111FrameLoaderClient::~FrameLoaderClient()
112{
113    if (m_policyDecision)
114        g_object_unref(m_policyDecision);
115}
116
117static void initializeDomainsList(HashSet<String>& googleDomains)
118{
119    // Google search domains.
120    googleDomains.add("biz");
121    googleDomains.add("com");
122    googleDomains.add("net");
123    googleDomains.add("org");
124    googleDomains.add("ae");
125    googleDomains.add("ag");
126    googleDomains.add("am");
127    googleDomains.add("at");
128    googleDomains.add("az");
129    googleDomains.add("be");
130    googleDomains.add("bi");
131    googleDomains.add("ca");
132    googleDomains.add("cc");
133    googleDomains.add("cd");
134    googleDomains.add("cg");
135    googleDomains.add("ch");
136    googleDomains.add("cl");
137    googleDomains.add("com.br");
138    googleDomains.add("co.uk");
139    googleDomains.add("co.kr");
140    googleDomains.add("co.jp");
141    googleDomains.add("de");
142    googleDomains.add("dj");
143    googleDomains.add("dk");
144    googleDomains.add("es");
145    googleDomains.add("fi");
146    googleDomains.add("fm");
147    googleDomains.add("fr");
148    googleDomains.add("gg");
149    googleDomains.add("gl");
150    googleDomains.add("gm");
151    googleDomains.add("gs");
152    googleDomains.add("hn");
153    googleDomains.add("hu");
154    googleDomains.add("ie");
155    googleDomains.add("it");
156    googleDomains.add("je");
157    googleDomains.add("kz");
158    googleDomains.add("li");
159    googleDomains.add("lt");
160    googleDomains.add("lu");
161    googleDomains.add("lv");
162    googleDomains.add("ma");
163    googleDomains.add("ms");
164    googleDomains.add("mu");
165    googleDomains.add("mw");
166    googleDomains.add("nl");
167    googleDomains.add("no");
168    googleDomains.add("nu");
169    googleDomains.add("pl");
170    googleDomains.add("pn");
171    googleDomains.add("pt");
172    googleDomains.add("ru");
173    googleDomains.add("rw");
174    googleDomains.add("sh");
175    googleDomains.add("sk");
176    googleDomains.add("sm");
177    googleDomains.add("st");
178    googleDomains.add("td");
179    googleDomains.add("tk");
180    googleDomains.add("tp");
181    googleDomains.add("tv");
182    googleDomains.add("us");
183    googleDomains.add("uz");
184    googleDomains.add("ws");
185}
186
187static bool isGoogleDomain(String host)
188{
189    DEFINE_STATIC_LOCAL(HashSet<String>, googleDomains, ());
190    DEFINE_STATIC_LOCAL(Vector<String>, otherGoogleDomains, ());
191
192    if (googleDomains.isEmpty()) {
193        otherGoogleDomains.append("gmail.com");
194        otherGoogleDomains.append("youtube.com");
195        otherGoogleDomains.append("gstatic.com");
196        otherGoogleDomains.append("ytimg.com");
197
198        initializeDomainsList(googleDomains);
199    }
200
201    // First check if this is one of the various google.com international domains.
202    int position = host.find(".google.");
203    if (position > 0 && googleDomains.contains(host.substring(position + sizeof(".google."))))
204        return true;
205
206    // Then we check the possibility of it being one of the other, .com-only google domains.
207    for (unsigned int i = 0; i < otherGoogleDomains.size(); i++) {
208        if (host.endsWith(otherGoogleDomains.at(i)))
209            return true;
210    }
211
212    return false;
213}
214
215String FrameLoaderClient::userAgent(const KURL& url)
216{
217    WebKitWebSettings* settings = webkit_web_view_get_settings(getViewFromFrame(m_frame));
218
219    gboolean useQuirks;
220    g_object_get(settings, "enable-site-specific-quirks", &useQuirks, NULL);
221
222    // For Google domains, drop the browser's custom User Agent string, and use the standard
223    // WebKit/Safari one, so they don't give us a broken experience.
224    if (useQuirks && isGoogleDomain(url.host()))
225        return webkitUserAgent();
226
227    return String::fromUTF8(webkit_web_settings_get_user_agent(settings));
228}
229
230static void notifyAccessibilityStatus(WebKitWebFrame* frame, WebKitLoadStatus loadStatus)
231{
232    if (loadStatus != WEBKIT_LOAD_PROVISIONAL
233        && loadStatus != WEBKIT_LOAD_FAILED
234        && loadStatus != WEBKIT_LOAD_FINISHED)
235        return;
236
237    WebKitWebFramePrivate* priv = frame->priv;
238    if (!priv->coreFrame || !priv->coreFrame->document())
239        return;
240
241    RenderView* contentRenderer = priv->coreFrame->contentRenderer();
242    if (!contentRenderer)
243        return;
244
245    AXObjectCache* axObjectCache = priv->coreFrame->document()->axObjectCache();
246    if (!axObjectCache)
247        return;
248
249    AccessibilityObject* coreAxObject = axObjectCache->getOrCreate(contentRenderer);
250    if (!coreAxObject)
251        return;
252
253    AtkObject* axObject = coreAxObject->wrapper();
254    if (!axObject || !ATK_IS_DOCUMENT(axObject))
255        return;
256
257    switch (loadStatus) {
258    case WEBKIT_LOAD_PROVISIONAL:
259        g_signal_emit_by_name(axObject, "state-change", "busy", true);
260        if (core(frame)->loader()->loadType() == FrameLoadTypeReload)
261            g_signal_emit_by_name(axObject, "reload");
262        break;
263    case WEBKIT_LOAD_FAILED:
264        g_signal_emit_by_name(axObject, "load-stopped");
265        g_signal_emit_by_name(axObject, "state-change", "busy", false);
266        break;
267    case WEBKIT_LOAD_FINISHED:
268        g_signal_emit_by_name(axObject, "load-complete");
269        g_signal_emit_by_name(axObject, "state-change", "busy", false);
270    default:
271        break;
272    }
273}
274
275static void notifyStatus(WebKitWebFrame* frame, WebKitLoadStatus loadStatus)
276{
277    frame->priv->loadStatus = loadStatus;
278    g_object_notify(G_OBJECT(frame), "load-status");
279
280    WebKitWebView* webView = getViewFromFrame(frame);
281    if (frame == webkit_web_view_get_main_frame(webView)) {
282        webView->priv->loadStatus = loadStatus;
283        g_object_notify(G_OBJECT(webView), "load-status");
284
285        if (AXObjectCache::accessibilityEnabled())
286            notifyAccessibilityStatus(frame, loadStatus);
287    }
288}
289
290static void loadDone(WebKitWebFrame* frame, bool didSucceed)
291{
292    // FIXME: load-done is deprecated. Please remove when signal's been removed.
293    g_signal_emit_by_name(frame, "load-done", didSucceed);
294    notifyStatus(frame, WEBKIT_LOAD_FINISHED);
295}
296
297WTF::PassRefPtr<WebCore::DocumentLoader> FrameLoaderClient::createDocumentLoader(const WebCore::ResourceRequest& request, const SubstituteData& substituteData)
298{
299    RefPtr<WebKit::DocumentLoader> loader = WebKit::DocumentLoader::create(request, substituteData);
300
301    GRefPtr<WebKitWebDataSource> webDataSource(adoptGRef(kitNew(loader.get())));
302    loader->setDataSource(webDataSource.get());
303
304    return loader.release();
305}
306
307void FrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction policyFunction, PassRefPtr<FormState>)
308{
309    // FIXME: This is surely too simple
310    ASSERT(policyFunction);
311    if (!policyFunction)
312        return;
313    (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyUse);
314}
315
316void FrameLoaderClient::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length)
317{
318    if (!m_pluginView) {
319        ASSERT(loader->frame());
320        loader->commitData(data, length);
321
322        Frame* coreFrame = loader->frame();
323        if (coreFrame && coreFrame->document()->isMediaDocument())
324            loader->cancelMainResourceLoad(coreFrame->loader()->client()->pluginWillHandleLoadError(loader->response()));
325    }
326
327    if (m_pluginView) {
328        if (!m_hasSentResponseToPlugin) {
329            m_pluginView->didReceiveResponse(loader->response());
330            m_hasSentResponseToPlugin = true;
331        }
332
333        // FIXME: We may want to investigate refactoring our plugin loading
334        // code to be similar to mac's.
335        // Also, see http://trac.webkit.org/changeset/24118.
336        if (!m_pluginView)
337            return;
338
339        m_pluginView->didReceiveData(data, length);
340    }
341}
342
343bool
344FrameLoaderClient::shouldUseCredentialStorage(WebCore::DocumentLoader*, unsigned long  identifier)
345{
346    notImplemented();
347    return false;
348}
349
350void FrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long  identifier, const AuthenticationChallenge&)
351{
352    notImplemented();
353}
354
355void FrameLoaderClient::dispatchDidCancelAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long  identifier, const AuthenticationChallenge&)
356{
357    notImplemented();
358}
359
360// We convert this to string because it's easier to use strings as
361// keys in a GHashTable.
362static char* toString(unsigned long identifier)
363{
364    return g_strdup_printf("%ld", identifier);
365}
366
367void FrameLoaderClient::dispatchWillSendRequest(WebCore::DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
368{
369    GRefPtr<WebKitNetworkResponse> networkResponse(0);
370
371    // We are adding one more resource to the load, or maybe we are
372    // just redirecting a load.
373    if (redirectResponse.isNull())
374        static_cast<WebKit::DocumentLoader*>(loader)->increaseLoadCount(identifier);
375    else
376        networkResponse = adoptGRef(kitNew(redirectResponse));
377
378    WebKitWebView* webView = getViewFromFrame(m_frame);
379    GOwnPtr<gchar> identifierString(toString(identifier));
380    WebKitWebResource* webResource = webkit_web_view_get_resource(webView, identifierString.get());
381    GRefPtr<WebKitNetworkRequest> networkRequest(adoptGRef(kitNew(request)));
382
383    if (!redirectResponse.isNull()) {
384        // This is a redirect, so we need to update the WebResource's knowledge
385        // of the URI.
386        g_free(webResource->priv->uri);
387        webResource->priv->uri = g_strdup(request.url().string().utf8().data());
388    }
389
390    g_signal_emit_by_name(webView, "resource-request-starting", m_frame, webResource, networkRequest.get(), networkResponse.get());
391
392    // Feed any changes back into the ResourceRequest object.
393    SoupMessage* message = webkit_network_request_get_message(networkRequest.get());
394    if (!message) {
395        request.setURL(KURL(KURL(), String::fromUTF8(webkit_network_request_get_uri(networkRequest.get()))));
396        return;
397    }
398
399    request.updateFromSoupMessage(message);
400}
401
402void FrameLoaderClient::assignIdentifierToInitialRequest(unsigned long identifier, WebCore::DocumentLoader* loader, const ResourceRequest& request)
403{
404    GOwnPtr<gchar> identifierString(toString(identifier));
405
406    WebKitWebResource* webResource = WEBKIT_WEB_RESOURCE(g_object_new(WEBKIT_TYPE_WEB_RESOURCE, "uri", request.url().string().utf8().data(), 0));
407
408    if (loader == loader->frameLoader()->provisionalDocumentLoader()
409        && loader->frameLoader()->isLoadingMainFrame()) {
410        webkit_web_view_add_main_resource(getViewFromFrame(m_frame), identifierString.get(), webResource);
411        return;
412    }
413
414    webkit_web_view_add_resource(getViewFromFrame(m_frame), identifierString.get(), webResource);
415}
416
417void FrameLoaderClient::postProgressStartedNotification()
418{
419    WebKitWebView* webView = getViewFromFrame(m_frame);
420    g_signal_emit_by_name(webView, "load-started", m_frame);
421
422    g_object_notify(G_OBJECT(webView), "progress");
423}
424
425void FrameLoaderClient::postProgressEstimateChangedNotification()
426{
427    WebKitWebView* webView = getViewFromFrame(m_frame);
428    Page* corePage = core(webView);
429
430    g_signal_emit_by_name(webView, "load-progress-changed", lround(corePage->progress()->estimatedProgress()*100));
431
432    g_object_notify(G_OBJECT(webView), "progress");
433}
434
435void FrameLoaderClient::postProgressFinishedNotification()
436{
437    WebKitWebView* webView = getViewFromFrame(m_frame);
438    WebKitWebViewPrivate* privateData = webView->priv;
439
440    // We can get a stopLoad() from dispose when the object is being
441    // destroyed, don't emit the signal in that case.
442    if (!privateData->disposing)
443        g_signal_emit_by_name(webView, "load-finished", m_frame);
444}
445
446void FrameLoaderClient::frameLoaderDestroyed()
447{
448    webkit_web_frame_core_frame_gone(m_frame);
449    g_object_unref(m_frame);
450    m_frame = 0;
451    delete this;
452}
453
454void FrameLoaderClient::dispatchDidReceiveResponse(WebCore::DocumentLoader* loader, unsigned long, const ResourceResponse& response)
455{
456    // Update our knowledge of request soup flags - some are only set
457    // after the request is done.
458    loader->request().setSoupMessageFlags(response.soupMessageFlags());
459
460    m_response = response;
461}
462
463void FrameLoaderClient::dispatchDecidePolicyForResponse(FramePolicyFunction policyFunction, const ResourceResponse& response, const ResourceRequest& resourceRequest)
464{
465    ASSERT(policyFunction);
466    if (!policyFunction)
467        return;
468
469    if (resourceRequest.isNull()) {
470        (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
471        return;
472    }
473
474    WebKitWebView* page = getViewFromFrame(m_frame);
475    GRefPtr<WebKitNetworkRequest> request(adoptGRef(kitNew(resourceRequest)));
476
477    WebKitWebPolicyDecision* policyDecision = webkit_web_policy_decision_new(m_frame, policyFunction);
478    if (m_policyDecision)
479        g_object_unref(m_policyDecision);
480    m_policyDecision = policyDecision;
481
482    String mimeType = response.mimeType();
483
484    gboolean isHandled = false;
485    g_signal_emit_by_name(page, "mime-type-policy-decision-requested", m_frame, request.get(), mimeType.utf8().data(), policyDecision, &isHandled);
486
487    if (isHandled)
488        return;
489
490    GRefPtr<WebKitNetworkResponse> networkResponse(adoptGRef(webkit_web_frame_get_network_response(m_frame)));
491    if (networkResponse) {
492        ResourceResponse response = core(networkResponse.get());
493        if (response.isAttachment()) {
494            webkit_web_policy_decision_download(policyDecision);
495            return;
496        }
497    }
498
499    if (canShowMIMEType(mimeType))
500        webkit_web_policy_decision_use(policyDecision);
501    else
502        webkit_web_policy_decision_ignore(policyDecision);
503}
504
505static WebKitWebNavigationAction* getNavigationAction(const NavigationAction& action, const char* targetFrame)
506{
507    gint button = -1;
508
509    const Event* event = action.event();
510    if (event && event->isMouseEvent()) {
511        const MouseEvent* mouseEvent = static_cast<const MouseEvent*>(event);
512        // DOM button values are 0, 1 and 2 for left, middle and right buttons.
513        // GTK+ uses 1, 2 and 3, so let's add 1 to remain consistent.
514        button = mouseEvent->button() + 1;
515    }
516
517    gint modifierFlags = 0;
518    UIEventWithKeyState* keyStateEvent = findEventWithKeyState(const_cast<Event*>(event));
519    if (keyStateEvent) {
520        if (keyStateEvent->shiftKey())
521            modifierFlags |= GDK_SHIFT_MASK;
522        if (keyStateEvent->ctrlKey())
523            modifierFlags |= GDK_CONTROL_MASK;
524        if (keyStateEvent->altKey())
525            modifierFlags |= GDK_MOD1_MASK;
526        if (keyStateEvent->metaKey())
527            modifierFlags |= GDK_MOD2_MASK;
528    }
529
530    return WEBKIT_WEB_NAVIGATION_ACTION(g_object_new(WEBKIT_TYPE_WEB_NAVIGATION_ACTION,
531                                                     "reason", kit(action.type()),
532                                                     "original-uri", action.url().string().utf8().data(),
533                                                     "button", button,
534                                                     "modifier-state", modifierFlags,
535                                                     "target-frame", targetFrame,
536                                                     NULL));
537}
538
539void FrameLoaderClient::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction policyFunction, const NavigationAction& action, const ResourceRequest& resourceRequest, PassRefPtr<FormState>, const String& frameName)
540{
541    ASSERT(policyFunction);
542    if (!policyFunction)
543        return;
544
545    if (resourceRequest.isNull()) {
546        (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
547        return;
548    }
549
550    WebKitWebPolicyDecision* policyDecision = webkit_web_policy_decision_new(m_frame, policyFunction);
551
552    if (m_policyDecision)
553        g_object_unref(m_policyDecision);
554    m_policyDecision = policyDecision;
555
556    WebKitWebView* webView = getViewFromFrame(m_frame);
557    GRefPtr<WebKitNetworkRequest> request(adoptGRef(webkit_network_request_new(resourceRequest.url().string().utf8().data())));
558    GRefPtr<WebKitWebNavigationAction> navigationAction(adoptGRef(getNavigationAction(action, frameName.utf8().data())));
559    gboolean isHandled = false;
560
561    g_signal_emit_by_name(webView, "new-window-policy-decision-requested", m_frame, request.get(), navigationAction.get(), policyDecision, &isHandled);
562
563    // FIXME: I think Qt version marshals this to another thread so when we
564    // have multi-threaded download, we might need to do the same
565    if (!isHandled)
566        (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyUse);
567}
568
569void FrameLoaderClient::dispatchDecidePolicyForNavigationAction(FramePolicyFunction policyFunction, const NavigationAction& action, const ResourceRequest& resourceRequest, PassRefPtr<FormState>)
570{
571    ASSERT(policyFunction);
572    if (!policyFunction)
573        return;
574
575    if (resourceRequest.isNull()) {
576        (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
577        return;
578    }
579
580    WebKitWebView* webView = getViewFromFrame(m_frame);
581    GRefPtr<WebKitNetworkRequest> request(adoptGRef(kitNew(resourceRequest)));
582    WebKitNavigationResponse response;
583    /*
584     * We still support the deprecated navigation-requested signal, if the
585     * application doesn't ignore the navigation then the new signal is
586     * emitted.
587     * navigation-policy-decision-requested must be emitted after
588     * navigation-requested as the policy decision can be async.
589     */
590    g_signal_emit_by_name(webView, "navigation-requested", m_frame, request.get(), &response);
591
592    if (response == WEBKIT_NAVIGATION_RESPONSE_IGNORE) {
593        (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
594        return;
595    }
596
597    WebKitWebPolicyDecision* policyDecision = webkit_web_policy_decision_new(m_frame, policyFunction);
598    if (m_policyDecision)
599        g_object_unref(m_policyDecision);
600    m_policyDecision = policyDecision;
601
602    GRefPtr<WebKitWebNavigationAction> navigationAction(adoptGRef(getNavigationAction(action, 0)));
603    gboolean isHandled = false;
604    g_signal_emit_by_name(webView, "navigation-policy-decision-requested", m_frame, request.get(), navigationAction.get(), policyDecision, &isHandled);
605
606    // FIXME Implement default behavior when we can query the backend what protocols it supports
607    if (!isHandled)
608        webkit_web_policy_decision_use(m_policyDecision);
609}
610
611PassRefPtr<Widget> FrameLoaderClient::createPlugin(const IntSize& pluginSize, HTMLPlugInElement* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
612{
613    /* Check if we want to embed a GtkWidget, fallback to plugins later */
614    CString urlString = url.string().utf8();
615    CString mimeTypeString = mimeType.utf8();
616
617    ASSERT(paramNames.size() == paramValues.size());
618    GRefPtr<GHashTable> hash = adoptGRef(g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free));
619    for (unsigned i = 0; i < paramNames.size(); ++i) {
620        g_hash_table_insert(hash.get(),
621                            g_strdup(paramNames[i].utf8().data()),
622                            g_strdup(paramValues[i].utf8().data()));
623    }
624
625    GtkWidget* gtkWidget = 0;
626    g_signal_emit_by_name(getViewFromFrame(m_frame), "create-plugin-widget",
627                          mimeTypeString.data(), urlString.data(), hash.get(), &gtkWidget);
628    if (gtkWidget)
629        return adoptRef(new GtkPluginWidget(gtkWidget));
630
631    RefPtr<PluginView> pluginView = PluginView::create(core(m_frame), pluginSize, element, url, paramNames, paramValues, mimeType, loadManually);
632
633    if (pluginView->status() == PluginStatusLoadedSuccessfully)
634        return pluginView;
635
636    return 0;
637}
638
639PassRefPtr<Frame> FrameLoaderClient::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
640                                                 const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
641{
642    ASSERT(m_frame);
643    Frame* parentFrame = core(m_frame);
644    WebKitWebView* webView = getViewFromFrame(m_frame);
645    WebCore::Page* page = core(webView);
646    ASSERT(page == parentFrame->page());
647
648    WebKitWebFrame* kitFrame = WEBKIT_WEB_FRAME(g_object_new(WEBKIT_TYPE_WEB_FRAME, NULL));
649    WebKitWebFramePrivate* framePrivate = kitFrame->priv;
650    framePrivate->webView = webView;
651
652    RefPtr<Frame> childFrame = Frame::create(page, ownerElement, new FrameLoaderClient(kitFrame));
653    framePrivate->coreFrame = childFrame.get();
654
655    childFrame->tree()->setName(name);
656    parentFrame->tree()->appendChild(childFrame);
657    childFrame->init();
658
659    // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
660    if (!childFrame->page())
661        return 0;
662
663    g_signal_emit_by_name(webView, "frame-created", kitFrame);
664
665    parentFrame->loader()->loadURLIntoChildFrame(url, referrer, childFrame.get());
666
667    // The frame's onload handler may have removed it from the document.
668    if (!childFrame->tree()->parent())
669        return 0;
670
671    return childFrame.release();
672}
673
674void FrameLoaderClient::didTransferChildFrameToNewDocument(WebCore::Page*)
675{
676    ASSERT(m_frame);
677
678    // Update the frame's webview to the new parent's webview.
679    Frame* coreFrame = core(m_frame);
680    WebKitWebView* webView = getViewFromFrame(m_frame);
681
682    Frame* parentCoreFrame = coreFrame->tree()->parent();
683    WebKitWebFrame* parentKitFrame = kit(parentCoreFrame);
684    WebKitWebView* parentWebView = getViewFromFrame(parentKitFrame);
685    if (webView != parentWebView)
686        m_frame->priv->webView = parentWebView;
687
688    ASSERT(core(getViewFromFrame(m_frame)) == coreFrame->page());
689}
690
691void FrameLoaderClient::transferLoadingResourceFromPage(unsigned long identifier, WebCore::DocumentLoader* docLoader, const WebCore::ResourceRequest& request, WebCore::Page* oldPage)
692{
693    ASSERT(oldPage != core(m_frame)->page());
694
695    GOwnPtr<gchar> identifierString(toString(identifier));
696    ASSERT(!webkit_web_view_get_resource(getViewFromFrame(m_frame), identifierString.get()));
697
698    assignIdentifierToInitialRequest(identifier, docLoader, request);
699
700    webkit_web_view_remove_resource(kit(oldPage), identifierString.get());
701}
702
703void FrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget)
704{
705    ASSERT(!m_pluginView);
706    m_pluginView = static_cast<PluginView*>(pluginWidget);
707    m_hasSentResponseToPlugin = false;
708}
709
710PassRefPtr<Widget> FrameLoaderClient::createJavaAppletWidget(const IntSize& pluginSize, HTMLAppletElement* element, const KURL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues)
711{
712    return FrameLoaderClient::createPlugin(pluginSize, element, baseURL, paramNames, paramValues, "application/x-java-applet", false);
713}
714
715ObjectContentType FrameLoaderClient::objectContentType(const KURL& url, const String& mimeType, bool shouldPreferPlugInsForImages)
716{
717    return FrameLoader::defaultObjectContentType(url, mimeType, shouldPreferPlugInsForImages);
718}
719
720String FrameLoaderClient::overrideMediaType() const
721{
722    notImplemented();
723    return String();
724}
725
726void FrameLoaderClient::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
727{
728    if (world != mainThreadNormalWorld())
729        return;
730
731    // Is this obsolete now?
732    g_signal_emit_by_name(m_frame, "cleared");
733
734    Frame* coreFrame = core(m_frame);
735    ASSERT(coreFrame);
736
737    Settings* settings = coreFrame->settings();
738    if (!settings || !settings->isJavaScriptEnabled())
739        return;
740
741    // TODO: Consider using g_signal_has_handler_pending() to avoid the overhead
742    // when there are no handlers.
743    JSGlobalContextRef context = toGlobalRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
744    JSObjectRef windowObject = toRef(coreFrame->script()->globalObject(mainThreadNormalWorld()));
745    ASSERT(windowObject);
746
747    WebKitWebView* webView = getViewFromFrame(m_frame);
748    g_signal_emit_by_name(webView, "window-object-cleared", m_frame, context, windowObject);
749
750    // TODO: Re-attach debug clients if present.
751    // The Win port has an example of how we might do this.
752}
753
754void FrameLoaderClient::documentElementAvailable()
755{
756}
757
758void FrameLoaderClient::didPerformFirstNavigation() const
759{
760    WebKitCacheModel cacheModel = webkit_get_cache_model();
761    // If user agents do not determine the cache model, we use WEBKIT_CACHE_MODEL_WEB_BROWSER by default.
762    if (cacheModel == WEBKIT_CACHE_MODEL_DEFAULT)
763        webkit_set_cache_model(WEBKIT_CACHE_MODEL_WEB_BROWSER);
764}
765
766void FrameLoaderClient::registerForIconNotification(bool shouldRegister)
767{
768    notImplemented();
769}
770
771void FrameLoaderClient::setMainFrameDocumentReady(bool ready)
772{
773    if (!ready)
774        DOMObjectCache::clearByFrame(core(m_frame));
775}
776
777bool FrameLoaderClient::hasWebView() const
778{
779    return getViewFromFrame(m_frame);
780}
781
782void FrameLoaderClient::dispatchDidFinishLoad()
783{
784    if (m_loadingErrorPage) {
785        m_loadingErrorPage = false;
786        return;
787    }
788
789    loadDone(m_frame, true);
790}
791
792void FrameLoaderClient::frameLoadCompleted()
793{
794    notImplemented();
795}
796
797void FrameLoaderClient::saveViewStateToItem(HistoryItem*)
798{
799    notImplemented();
800}
801
802void FrameLoaderClient::restoreViewState()
803{
804    notImplemented();
805}
806
807bool FrameLoaderClient::shouldGoToHistoryItem(HistoryItem* item) const
808{
809    // FIXME: This is a very simple implementation. More sophisticated
810    // implementation would delegate the decision to a PolicyDelegate.
811    // See mac implementation for example.
812    return item != 0;
813}
814
815bool FrameLoaderClient::shouldStopLoadingForHistoryItem(HistoryItem* item) const
816{
817    return true;
818}
819
820void FrameLoaderClient::dispatchDidAddBackForwardItem(HistoryItem*) const
821{
822}
823
824void FrameLoaderClient::dispatchDidRemoveBackForwardItem(HistoryItem*) const
825{
826}
827
828void FrameLoaderClient::dispatchDidChangeBackForwardIndex() const
829{
830}
831
832void FrameLoaderClient::didDisplayInsecureContent()
833{
834    notImplemented();
835}
836
837void FrameLoaderClient::didRunInsecureContent(SecurityOrigin*, const KURL&)
838{
839    notImplemented();
840}
841
842void FrameLoaderClient::makeRepresentation(WebCore::DocumentLoader*)
843{
844    m_hasRepresentation = true;
845}
846
847void FrameLoaderClient::forceLayout()
848{
849    FrameView* view = core(m_frame)->view();
850    if (view)
851        view->forceLayout(true);
852}
853
854void FrameLoaderClient::forceLayoutForNonHTML()
855{
856    notImplemented();
857}
858
859void FrameLoaderClient::setCopiesOnScroll()
860{
861    notImplemented();
862}
863
864void FrameLoaderClient::detachedFromParent2()
865{
866    notImplemented();
867}
868
869void FrameLoaderClient::detachedFromParent3()
870{
871    notImplemented();
872}
873
874void FrameLoaderClient::dispatchDidHandleOnloadEvents()
875{
876    g_signal_emit_by_name(getViewFromFrame(m_frame), "onload-event", m_frame);
877}
878
879void FrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad()
880{
881    notImplemented();
882}
883
884void FrameLoaderClient::dispatchDidCancelClientRedirect()
885{
886    notImplemented();
887}
888
889void FrameLoaderClient::dispatchWillPerformClientRedirect(const KURL&, double, double)
890{
891    notImplemented();
892}
893
894void FrameLoaderClient::dispatchDidChangeLocationWithinPage()
895{
896    WebKitWebFramePrivate* priv = m_frame->priv;
897    g_free(priv->uri);
898    priv->uri = g_strdup(core(m_frame)->document()->url().string().utf8().data());
899    g_object_notify(G_OBJECT(m_frame), "uri");
900    WebKitWebView* webView = getViewFromFrame(m_frame);
901    if (m_frame == webkit_web_view_get_main_frame(webView))
902        g_object_notify(G_OBJECT(webView), "uri");
903}
904
905void FrameLoaderClient::dispatchDidPushStateWithinPage()
906{
907    notImplemented();
908}
909
910void FrameLoaderClient::dispatchDidReplaceStateWithinPage()
911{
912    notImplemented();
913}
914
915void FrameLoaderClient::dispatchDidPopStateWithinPage()
916{
917    notImplemented();
918}
919
920void FrameLoaderClient::dispatchWillClose()
921{
922    notImplemented();
923}
924
925void FrameLoaderClient::dispatchDidReceiveIcon()
926{
927    if (m_loadingErrorPage)
928        return;
929
930    const gchar* frameURI = webkit_web_frame_get_uri(m_frame);
931    WebKitIconDatabase* database = webkit_get_icon_database();
932    g_signal_emit_by_name(database, "icon-loaded", m_frame, frameURI);
933
934    WebKitWebView* webView = getViewFromFrame(m_frame);
935
936    // Avoid reporting favicons for non-main frames.
937    if (m_frame != webkit_web_view_get_main_frame(webView))
938        return;
939
940    g_object_notify(G_OBJECT(webView), "icon-uri");
941    g_signal_emit_by_name(webView, "icon-loaded", webkit_web_view_get_icon_uri(webView));
942}
943
944void FrameLoaderClient::dispatchDidStartProvisionalLoad()
945{
946    if (m_loadingErrorPage)
947        return;
948
949    notifyStatus(m_frame, WEBKIT_LOAD_PROVISIONAL);
950}
951
952void FrameLoaderClient::dispatchDidReceiveTitle(const StringWithDirection& title)
953{
954    if (m_loadingErrorPage)
955        return;
956
957    WebKitWebFramePrivate* priv = m_frame->priv;
958    g_free(priv->title);
959    // FIXME: use direction of title.
960    priv->title = g_strdup(title.string().utf8().data());
961
962    g_signal_emit_by_name(m_frame, "title-changed", priv->title);
963    g_object_notify(G_OBJECT(m_frame), "title");
964
965    WebKitWebView* webView = getViewFromFrame(m_frame);
966    if (m_frame == webkit_web_view_get_main_frame(webView)) {
967        g_signal_emit_by_name(webView, "title-changed", m_frame, title.string().utf8().data());
968        g_object_notify(G_OBJECT(webView), "title");
969    }
970}
971
972void FrameLoaderClient::dispatchDidChangeIcons()
973{
974    notImplemented();
975}
976
977void FrameLoaderClient::dispatchDidCommitLoad()
978{
979    if (m_loadingErrorPage)
980        return;
981
982    /* Update the URI once first data has been received.
983     * This means the URI is valid and successfully identify the page that's going to be loaded.
984     */
985    g_object_freeze_notify(G_OBJECT(m_frame));
986
987    WebKitWebFramePrivate* priv = m_frame->priv;
988    g_free(priv->uri);
989    priv->uri = g_strdup(core(m_frame)->loader()->activeDocumentLoader()->url().string().utf8().data());
990    g_free(priv->title);
991    priv->title = NULL;
992    g_object_notify(G_OBJECT(m_frame), "uri");
993    g_object_notify(G_OBJECT(m_frame), "title");
994
995    g_signal_emit_by_name(m_frame, "load-committed");
996    notifyStatus(m_frame, WEBKIT_LOAD_COMMITTED);
997
998    WebKitWebView* webView = getViewFromFrame(m_frame);
999    if (m_frame == webkit_web_view_get_main_frame(webView)) {
1000        g_object_freeze_notify(G_OBJECT(webView));
1001        g_object_notify(G_OBJECT(webView), "uri");
1002        g_object_notify(G_OBJECT(webView), "title");
1003        g_object_thaw_notify(G_OBJECT(webView));
1004        g_signal_emit_by_name(webView, "load-committed", m_frame);
1005    }
1006
1007    g_object_thaw_notify(G_OBJECT(m_frame));
1008}
1009
1010void FrameLoaderClient::dispatchDidFinishDocumentLoad()
1011{
1012    WebKitWebView* webView = getViewFromFrame(m_frame);
1013    g_signal_emit_by_name(webView, "document-load-finished", m_frame);
1014}
1015
1016void FrameLoaderClient::dispatchDidFirstLayout()
1017{
1018    notImplemented();
1019}
1020
1021void FrameLoaderClient::dispatchDidFirstVisuallyNonEmptyLayout()
1022{
1023    if (m_loadingErrorPage)
1024        return;
1025
1026    notifyStatus(m_frame, WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT);
1027}
1028
1029void FrameLoaderClient::dispatchShow()
1030{
1031    WebKitWebView* webView = getViewFromFrame(m_frame);
1032    webkit_web_view_notify_ready(webView);
1033}
1034
1035void FrameLoaderClient::cancelPolicyCheck()
1036{
1037    //FIXME Add support for more than one policy decision at once
1038    if (m_policyDecision)
1039        webkit_web_policy_decision_cancel(m_policyDecision);
1040}
1041
1042void FrameLoaderClient::dispatchDidLoadMainResource(WebCore::DocumentLoader*)
1043{
1044    notImplemented();
1045}
1046
1047void FrameLoaderClient::revertToProvisionalState(WebCore::DocumentLoader*)
1048{
1049    m_hasRepresentation = true;
1050}
1051
1052void FrameLoaderClient::willChangeTitle(WebCore::DocumentLoader*)
1053{
1054    notImplemented();
1055}
1056
1057void FrameLoaderClient::didChangeTitle(WebCore::DocumentLoader *l)
1058{
1059    setTitle(l->title(), l->url());
1060}
1061
1062bool FrameLoaderClient::canHandleRequest(const ResourceRequest&) const
1063{
1064    notImplemented();
1065    return true;
1066}
1067
1068bool FrameLoaderClient::canShowMIMETypeAsHTML(const String& MIMEType) const
1069{
1070    notImplemented();
1071    return false;
1072}
1073
1074bool FrameLoaderClient::canShowMIMEType(const String& type) const
1075{
1076    return (MIMETypeRegistry::isSupportedImageMIMEType(type)
1077            || MIMETypeRegistry::isSupportedNonImageMIMEType(type)
1078            || MIMETypeRegistry::isSupportedMediaMIMEType(type)
1079            || PluginDatabase::installedPlugins()->isMIMETypeRegistered(type));
1080}
1081
1082bool FrameLoaderClient::representationExistsForURLScheme(const String&) const
1083{
1084    notImplemented();
1085    return false;
1086}
1087
1088String FrameLoaderClient::generatedMIMETypeForURLScheme(const String&) const
1089{
1090    notImplemented();
1091    return String();
1092}
1093
1094void FrameLoaderClient::finishedLoading(WebCore::DocumentLoader* documentLoader)
1095{
1096    if (!m_pluginView) {
1097        // This is necessary to create an empty document,
1098        // but it has to be skipped in the provisional phase.
1099        if (m_hasRepresentation)
1100            documentLoader->writer()->setEncoding("", false);
1101    } else {
1102        m_pluginView->didFinishLoading();
1103        m_pluginView = 0;
1104        m_hasSentResponseToPlugin = false;
1105    }
1106}
1107
1108
1109void FrameLoaderClient::provisionalLoadStarted()
1110{
1111    notImplemented();
1112}
1113
1114void FrameLoaderClient::didFinishLoad() {
1115    notImplemented();
1116}
1117
1118void FrameLoaderClient::prepareForDataSourceReplacement()
1119{
1120    notImplemented();
1121}
1122
1123void FrameLoaderClient::setTitle(const StringWithDirection& title, const KURL& url)
1124{
1125    WebKitWebFramePrivate* frameData = m_frame->priv;
1126    g_free(frameData->title);
1127    // FIXME: use direction of title.
1128    frameData->title = g_strdup(title.string().utf8().data());
1129}
1130
1131void FrameLoaderClient::dispatchDidReceiveContentLength(WebCore::DocumentLoader*, unsigned long identifier, int dataLength)
1132{
1133    notImplemented();
1134}
1135
1136void FrameLoaderClient::dispatchDidFinishLoading(WebCore::DocumentLoader* loader, unsigned long identifier)
1137{
1138    static_cast<WebKit::DocumentLoader*>(loader)->decreaseLoadCount(identifier);
1139
1140    WebKitWebView* webView = getViewFromFrame(m_frame);
1141    GOwnPtr<gchar> identifierString(toString(identifier));
1142    WebKitWebResource* webResource = webkit_web_view_get_resource(webView, identifierString.get());
1143
1144    // A NULL WebResource means the load has been interrupted, and
1145    // replaced by another one while this resource was being loaded.
1146    if (!webResource)
1147        return;
1148
1149    const char* uri = webkit_web_resource_get_uri(webResource);
1150    RefPtr<ArchiveResource> coreResource(loader->subresource(KURL(KURL(), uri)));
1151
1152    // If coreResource is NULL here, the resource failed to load,
1153    // unless it's the main resource.
1154    if (!coreResource && webResource != webkit_web_view_get_main_resource(webView))
1155        return;
1156
1157    if (!coreResource)
1158        coreResource = loader->mainResource();
1159
1160    webkit_web_resource_init_with_core_resource(webResource, coreResource.get());
1161
1162    // FIXME: This function should notify the application that the resource
1163    // finished loading, maybe using a load-status property in the
1164    // WebKitWebResource object, similar to what we do for WebKitWebFrame'
1165    // signal.
1166    notImplemented();
1167}
1168
1169void FrameLoaderClient::dispatchDidFailLoading(WebCore::DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
1170{
1171    static_cast<WebKit::DocumentLoader*>(loader)->decreaseLoadCount(identifier);
1172
1173    // FIXME: This function should notify the application that the resource failed
1174    // loading, maybe a 'load-error' signal in the WebKitWebResource object.
1175    notImplemented();
1176}
1177
1178bool FrameLoaderClient::dispatchDidLoadResourceFromMemoryCache(WebCore::DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length)
1179{
1180    notImplemented();
1181    return false;
1182}
1183
1184void FrameLoaderClient::dispatchDidFailProvisionalLoad(const ResourceError& error)
1185{
1186    dispatchDidFailLoad(error);
1187}
1188
1189void FrameLoaderClient::dispatchDidFailLoad(const ResourceError& error)
1190{
1191    if (m_loadingErrorPage)
1192        return;
1193
1194    notifyStatus(m_frame, WEBKIT_LOAD_FAILED);
1195
1196    WebKitWebView* webView = getViewFromFrame(m_frame);
1197    GError* webError = g_error_new_literal(g_quark_from_string(error.domain().utf8().data()),
1198                                           error.errorCode(),
1199                                           error.localizedDescription().utf8().data());
1200    gboolean isHandled = false;
1201    g_signal_emit_by_name(webView, "load-error", m_frame, error.failingURL().utf8().data(), webError, &isHandled);
1202
1203    if (isHandled) {
1204        g_error_free(webError);
1205        return;
1206    }
1207
1208    if (!shouldFallBack(error)) {
1209        g_error_free(webError);
1210        return;
1211    }
1212
1213    m_loadingErrorPage = true;
1214
1215    String content;
1216    gchar* fileContent = 0;
1217    gchar* errorURI = g_filename_to_uri(DATA_DIR"/webkit-1.0/resources/error.html", NULL, NULL);
1218    GFile* errorFile = g_file_new_for_uri(errorURI);
1219    g_free(errorURI);
1220
1221    if (!errorFile)
1222        content = makeString("<html><body>", webError->message, "</body></html>");
1223    else {
1224        gboolean loaded = g_file_load_contents(errorFile, 0, &fileContent, 0, 0, 0);
1225        if (!loaded)
1226            content = makeString("<html><body>", webError->message, "</body></html>");
1227        else
1228            content = String::format(fileContent, error.failingURL().utf8().data(), webError->message);
1229    }
1230
1231    webkit_web_frame_load_alternate_string(m_frame, content.utf8().data(), 0, error.failingURL().utf8().data());
1232
1233    g_free(fileContent);
1234
1235    if (errorFile)
1236        g_object_unref(errorFile);
1237
1238    g_error_free(webError);
1239}
1240
1241void FrameLoaderClient::download(ResourceHandle* handle, const ResourceRequest& request, const ResourceRequest&, const ResourceResponse& response)
1242{
1243    GRefPtr<WebKitNetworkRequest> networkRequest(adoptGRef(kitNew(request)));
1244    WebKitWebView* view = getViewFromFrame(m_frame);
1245
1246    webkit_web_view_request_download(view, networkRequest.get(), response, handle);
1247}
1248
1249ResourceError FrameLoaderClient::cancelledError(const ResourceRequest& request)
1250{
1251    return ResourceError(g_quark_to_string(WEBKIT_NETWORK_ERROR), WEBKIT_NETWORK_ERROR_CANCELLED,
1252                         request.url().string(), _("Load request cancelled"));
1253}
1254
1255ResourceError FrameLoaderClient::blockedError(const ResourceRequest& request)
1256{
1257    return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT,
1258                         request.url().string(), _("Not allowed to use restricted network port"));
1259}
1260
1261ResourceError FrameLoaderClient::cannotShowURLError(const ResourceRequest& request)
1262{
1263    return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL,
1264                         request.url().string(), _("URL cannot be shown"));
1265}
1266
1267ResourceError FrameLoaderClient::interruptForPolicyChangeError(const ResourceRequest& request)
1268{
1269    return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE,
1270                         request.url().string(), _("Frame load was interrupted"));
1271}
1272
1273ResourceError FrameLoaderClient::cannotShowMIMETypeError(const ResourceResponse& response)
1274{
1275    return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_CANNOT_SHOW_MIME_TYPE,
1276                         response.url().string(), _("Content with the specified MIME type cannot be shown"));
1277}
1278
1279ResourceError FrameLoaderClient::fileDoesNotExistError(const ResourceResponse& response)
1280{
1281    return ResourceError(g_quark_to_string(WEBKIT_NETWORK_ERROR), WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST,
1282                         response.url().string(), _("File does not exist"));
1283}
1284
1285ResourceError FrameLoaderClient::pluginWillHandleLoadError(const ResourceResponse& response)
1286{
1287    return ResourceError(g_quark_to_string(WEBKIT_PLUGIN_ERROR), WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD,
1288                         response.url().string(), _("Plugin will handle load"));
1289}
1290
1291bool FrameLoaderClient::shouldFallBack(const ResourceError& error)
1292{
1293    return !(error.isCancellation() || error.errorCode() == WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE || error.errorCode() == WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD);
1294}
1295
1296bool FrameLoaderClient::canCachePage() const
1297{
1298    return true;
1299}
1300
1301Frame* FrameLoaderClient::dispatchCreatePage(const NavigationAction&)
1302{
1303    WebKitWebView* webView = getViewFromFrame(m_frame);
1304    WebKitWebView* newWebView = 0;
1305
1306    g_signal_emit_by_name(webView, "create-web-view", m_frame, &newWebView);
1307
1308    if (!newWebView)
1309        return 0;
1310
1311    WebKitWebViewPrivate* privateData = newWebView->priv;
1312    return core(privateData->mainFrame);
1313}
1314
1315void FrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError&)
1316{
1317    notImplemented();
1318}
1319
1320void FrameLoaderClient::setMainDocumentError(WebCore::DocumentLoader*, const ResourceError& error)
1321{
1322    if (m_pluginView) {
1323        m_pluginView->didFail(error);
1324        m_pluginView = 0;
1325        m_hasSentResponseToPlugin = false;
1326    }
1327}
1328
1329void FrameLoaderClient::startDownload(const ResourceRequest& request)
1330{
1331    GRefPtr<WebKitNetworkRequest> networkRequest(adoptGRef(kitNew(request)));
1332    WebKitWebView* view = getViewFromFrame(m_frame);
1333
1334    webkit_web_view_request_download(view, networkRequest.get());
1335}
1336
1337void FrameLoaderClient::updateGlobalHistory()
1338{
1339    notImplemented();
1340}
1341
1342void FrameLoaderClient::updateGlobalHistoryRedirectLinks()
1343{
1344    notImplemented();
1345}
1346
1347void FrameLoaderClient::savePlatformDataToCachedFrame(CachedFrame* cachedFrame)
1348{
1349    // We need to do this here in order to disconnect the scrollbars
1350    // that are being used by the frame that is being cached from the
1351    // adjustments, otherwise they will react to changes in the
1352    // adjustments, and bad things will happen.
1353    if (cachedFrame->view())
1354        cachedFrame->view()->setGtkAdjustments(0, 0);
1355}
1356
1357static void postCommitFrameViewSetup(WebKitWebFrame *frame, FrameView *view, bool resetValues)
1358{
1359    WebKitWebView* containingWindow = getViewFromFrame(frame);
1360    webkit_web_view_clear_resources(containingWindow);
1361
1362    WebKitWebViewPrivate* priv = containingWindow->priv;
1363    view->setGtkAdjustments(priv->horizontalAdjustment.get(), priv->verticalAdjustment.get(), resetValues);
1364
1365    // Invalidate the viewport attributes - they will only be valid
1366    // again if the page we're beginning to load now has an
1367    // appropriate viewport meta tag.
1368    containingWindow->priv->viewportAttributes->priv->isValid = FALSE;
1369    g_object_notify(G_OBJECT(containingWindow->priv->viewportAttributes.get()), "valid");
1370
1371    if (priv->currentMenu) {
1372        gtk_widget_destroy(GTK_WIDGET(priv->currentMenu));
1373        priv->currentMenu = 0;
1374    }
1375
1376    // Do not allow click counting between main frame loads.
1377    priv->previousClickTime = 0;
1378}
1379
1380void FrameLoaderClient::transitionToCommittedFromCachedFrame(CachedFrame* cachedFrame)
1381{
1382    ASSERT(cachedFrame->view());
1383
1384    Frame* frame = core(m_frame);
1385    if (frame != frame->page()->mainFrame())
1386        return;
1387
1388    postCommitFrameViewSetup(m_frame, cachedFrame->view(), false);
1389}
1390
1391void FrameLoaderClient::transitionToCommittedForNewPage()
1392{
1393    WebKitWebView* containingWindow = getViewFromFrame(m_frame);
1394    GtkAllocation allocation;
1395#if GTK_CHECK_VERSION(2, 18, 0)
1396    gtk_widget_get_allocation(GTK_WIDGET(containingWindow), &allocation);
1397#else
1398    allocation = GTK_WIDGET(containingWindow)->allocation;
1399#endif
1400    IntSize size = IntSize(allocation.width, allocation.height);
1401    bool transparent = webkit_web_view_get_transparent(containingWindow);
1402    Color backgroundColor = transparent ? WebCore::Color::transparent : WebCore::Color::white;
1403    Frame* frame = core(m_frame);
1404    ASSERT(frame);
1405
1406    frame->createView(size, backgroundColor, transparent, IntSize(), false);
1407
1408    // We need to do further manipulation on the FrameView if it was the mainFrame
1409    if (frame != frame->page()->mainFrame())
1410        return;
1411
1412    postCommitFrameViewSetup(m_frame, frame->view(), true);
1413}
1414
1415void FrameLoaderClient::didSaveToPageCache()
1416{
1417}
1418
1419void FrameLoaderClient::didRestoreFromPageCache()
1420{
1421}
1422
1423void FrameLoaderClient::dispatchDidBecomeFrameset(bool)
1424{
1425}
1426
1427PassRefPtr<FrameNetworkingContext> FrameLoaderClient::createNetworkingContext()
1428{
1429    return FrameNetworkingContextGtk::create(core(m_frame));
1430}
1431
1432}
1433