2010-06-16 Martin Robinson <mrobinson@igalia.com>
[WebKit-https.git] / WebKit / gtk / WebCoreSupport / FrameLoaderClientGtk.cpp
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  *
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 "FrameLoaderClientGtk.h"
26
27 #include "ArchiveResource.h"
28 #include "CachedFrame.h"
29 #include "Color.h"
30 #include "DocumentLoader.h"
31 #include "DocumentLoaderGtk.h"
32 #include "FormState.h"
33 #include "FrameLoader.h"
34 #include "FrameView.h"
35 #include "FrameTree.h"
36 #include "GOwnPtr.h"
37 #include "GRefPtr.h"
38 #include "GtkPluginWidget.h"
39 #include "HTMLAppletElement.h"
40 #include "HTMLFormElement.h"
41 #include "HTMLFrameElement.h"
42 #include "HTMLFrameOwnerElement.h"
43 #include "HTMLNames.h"
44 #include "HTMLPlugInElement.h"
45 #include "JSDOMWindow.h"
46 #include "Language.h"
47 #include "MIMETypeRegistry.h"
48 #include "MouseEvent.h"
49 #include "NotImplemented.h"
50 #include "PlatformString.h"
51 #include "PluginDatabase.h"
52 #include "RenderPart.h"
53 #include "ResourceHandle.h"
54 #include "ResourceRequest.h"
55 #include "ProgressTracker.h"
56 #include "JSDOMBinding.h"
57 #include "ScriptController.h"
58 #include "webkiterror.h"
59 #include "webkitnetworkrequest.h"
60 #include "webkitnetworkresponse.h"
61 #include "webkitprivate.h"
62 #include "webkitwebframe.h"
63 #include "webkitwebnavigationaction.h"
64 #include "webkitwebpolicydecision.h"
65 #include "webkitwebview.h"
66 #include <wtf/text/CString.h>
67
68 #include <JavaScriptCore/APICast.h>
69 #include <gio/gio.h>
70 #include <glib.h>
71 #include <glib/gi18n-lib.h>
72 #include <stdio.h>
73
74 using namespace WebCore;
75
76 namespace WebKit {
77
78 FrameLoaderClient::FrameLoaderClient(WebKitWebFrame* frame)
79     : m_frame(frame)
80     , m_policyDecision(0)
81     , m_loadingErrorPage(false)
82     , m_pluginView(0)
83     , m_hasSentResponseToPlugin(false)
84 {
85     ASSERT(m_frame);
86 }
87
88 FrameLoaderClient::~FrameLoaderClient()
89 {
90     if (m_policyDecision)
91         g_object_unref(m_policyDecision);
92 }
93
94 String FrameLoaderClient::userAgent(const KURL&)
95 {
96     WebKitWebSettings* settings = webkit_web_view_get_settings(getViewFromFrame(m_frame));
97     return String::fromUTF8(webkit_web_settings_get_user_agent(settings));
98 }
99
100 static void notifyStatus(WebKitWebFrame* frame, WebKitLoadStatus loadStatus)
101 {
102     frame->priv->loadStatus = loadStatus;
103     g_object_notify(G_OBJECT(frame), "load-status");
104
105     WebKitWebView* webView = getViewFromFrame(frame);
106     if (frame == webkit_web_view_get_main_frame(webView)) {
107         webView->priv->loadStatus = loadStatus;
108         g_object_notify(G_OBJECT(webView), "load-status");
109     }
110 }
111
112 static void loadDone(WebKitWebFrame* frame, bool didSucceed)
113 {
114     // FIXME: load-done is deprecated. Please remove when signal's been removed.
115     g_signal_emit_by_name(frame, "load-done", didSucceed);
116     notifyStatus(frame, WEBKIT_LOAD_FINISHED);
117 }
118
119 WTF::PassRefPtr<WebCore::DocumentLoader> FrameLoaderClient::createDocumentLoader(const WebCore::ResourceRequest& request, const SubstituteData& substituteData)
120 {
121     RefPtr<WebKit::DocumentLoader> loader = WebKit::DocumentLoader::create(request, substituteData);
122
123     WebKitWebDataSource* webDataSource = webkit_web_data_source_new_with_loader(loader.get());
124     loader->setDataSource(webDataSource);
125     g_object_unref(webDataSource);
126
127     return loader.release();
128 }
129
130 void FrameLoaderClient::dispatchWillSubmitForm(FramePolicyFunction policyFunction, PassRefPtr<FormState>)
131 {
132     // FIXME: This is surely too simple
133     ASSERT(policyFunction);
134     if (!policyFunction)
135         return;
136     (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyUse);
137 }
138
139
140 void FrameLoaderClient::committedLoad(WebCore::DocumentLoader* loader, const char* data, int length)
141 {
142     if (!m_pluginView) {
143         ASSERT(loader->frame());
144         // Setting the encoding on the frame loader is our way to get work done that is normally done
145         // when the first bit of data is received, even for the case of a document with no data (like about:blank).
146         String encoding = loader->overrideEncoding();
147         bool userChosen = !encoding.isNull();
148         if (!userChosen)
149             encoding = loader->response().textEncodingName();
150
151         FrameLoader* frameLoader = loader->frameLoader();
152         frameLoader->writer()->setEncoding(encoding, userChosen);
153         if (data)
154             frameLoader->addData(data, length);
155
156         Frame* coreFrame = loader->frame();
157         if (coreFrame && coreFrame->document() && coreFrame->document()->isMediaDocument())
158             loader->cancelMainResourceLoad(frameLoader->client()->pluginWillHandleLoadError(loader->response()));
159     }
160
161     if (m_pluginView) {
162         if (!m_hasSentResponseToPlugin) {
163             m_pluginView->didReceiveResponse(loader->response());
164             m_hasSentResponseToPlugin = true;
165         }
166
167         // FIXME: We may want to investigate refactoring our plugin loading
168         // code to be similar to mac's.
169         // Also, see http://trac.webkit.org/changeset/24118.
170         if (!m_pluginView)
171             return;
172
173         m_pluginView->didReceiveData(data, length);
174     }
175 }
176
177 bool
178 FrameLoaderClient::shouldUseCredentialStorage(WebCore::DocumentLoader*, unsigned long  identifier)
179 {
180     notImplemented();
181     return false;
182 }
183
184 void FrameLoaderClient::dispatchDidReceiveAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long  identifier, const AuthenticationChallenge&)
185 {
186     notImplemented();
187 }
188
189 void FrameLoaderClient::dispatchDidCancelAuthenticationChallenge(WebCore::DocumentLoader*, unsigned long  identifier, const AuthenticationChallenge&)
190 {
191     notImplemented();
192 }
193
194 // We convert this to string because it's easier to use strings as
195 // keys in a GHashTable.
196 static char* toString(unsigned long identifier)
197 {
198     return g_strdup_printf("%ld", identifier);
199 }
200
201 void FrameLoaderClient::dispatchWillSendRequest(WebCore::DocumentLoader* loader, unsigned long identifier, ResourceRequest& request, const ResourceResponse& redirectResponse)
202 {
203     GRefPtr<WebKitNetworkResponse> networkResponse(0);
204
205     // We are adding one more resource to the load, or maybe we are
206     // just redirecting a load.
207     if (redirectResponse.isNull())
208         static_cast<WebKit::DocumentLoader*>(loader)->increaseLoadCount(identifier);
209     else
210         networkResponse = adoptGRef(webkit_network_response_new_with_core_response(redirectResponse));
211
212     WebKitWebView* webView = getViewFromFrame(m_frame);
213     GOwnPtr<gchar> identifierString(toString(identifier));
214     WebKitWebResource* webResource = webkit_web_view_get_resource(webView, identifierString.get());
215     GRefPtr<WebKitNetworkRequest> networkRequest(adoptGRef(webkit_network_request_new_with_core_request(request)));
216
217     if (!redirectResponse.isNull()) {
218         // This is a redirect, so we need to update the WebResource's knowledge
219         // of the URI.
220         g_free(webResource->priv->uri);
221         webResource->priv->uri = g_strdup(request.url().string().utf8().data());
222     }
223     
224     g_signal_emit_by_name(webView, "resource-request-starting", m_frame, webResource, networkRequest.get(), networkResponse.get());
225
226     // Feed any changes back into the ResourceRequest object.
227     SoupMessage* message = webkit_network_request_get_message(networkRequest.get());
228     if (!message) {
229         request.setURL(KURL(KURL(), String::fromUTF8(webkit_network_request_get_uri(networkRequest.get()))));
230         return;
231     }
232
233     request.updateFromSoupMessage(message);
234 }
235
236 void FrameLoaderClient::assignIdentifierToInitialRequest(unsigned long identifier, WebCore::DocumentLoader*, const ResourceRequest& request)
237 {
238     GOwnPtr<gchar> identifierString(toString(identifier));
239     webkit_web_view_add_resource(getViewFromFrame(m_frame), identifierString.get(),
240                                  WEBKIT_WEB_RESOURCE(g_object_new(WEBKIT_TYPE_WEB_RESOURCE, "uri", request.url().string().utf8().data(), 0)));
241 }
242
243 void FrameLoaderClient::postProgressStartedNotification()
244 {
245     WebKitWebView* webView = getViewFromFrame(m_frame);
246     g_signal_emit_by_name(webView, "load-started", m_frame);
247
248     g_object_notify(G_OBJECT(webView), "progress");
249 }
250
251 void FrameLoaderClient::postProgressEstimateChangedNotification()
252 {
253     WebKitWebView* webView = getViewFromFrame(m_frame);
254     Page* corePage = core(webView);
255
256     g_signal_emit_by_name(webView, "load-progress-changed", lround(corePage->progress()->estimatedProgress()*100));
257
258     g_object_notify(G_OBJECT(webView), "progress");
259 }
260
261 void FrameLoaderClient::postProgressFinishedNotification()
262 {
263     WebKitWebView* webView = getViewFromFrame(m_frame);
264     WebKitWebViewPrivate* privateData = WEBKIT_WEB_VIEW_GET_PRIVATE(webView);
265
266     // We can get a stopLoad() from dispose when the object is being
267     // destroyed, don't emit the signal in that case.
268     if (!privateData->disposing)
269         g_signal_emit_by_name(webView, "load-finished", m_frame);
270 }
271
272 void FrameLoaderClient::frameLoaderDestroyed()
273 {
274     webkit_web_frame_core_frame_gone(m_frame);
275     g_object_unref(m_frame);
276     m_frame = 0;
277     delete this;
278 }
279
280 void FrameLoaderClient::dispatchDidReceiveResponse(WebCore::DocumentLoader* loader, unsigned long, const ResourceResponse& response)
281 {
282     // Update our knowledge of request soup flags - some are only set
283     // after the request is done.
284     loader->request().setSoupMessageFlags(response.soupMessageFlags());
285
286     m_response = response;
287 }
288
289 void FrameLoaderClient::dispatchDecidePolicyForMIMEType(FramePolicyFunction policyFunction, const String& mimeType, const ResourceRequest& resourceRequest)
290 {
291     ASSERT(policyFunction);
292     if (!policyFunction)
293         return;
294
295     if (resourceRequest.isNull()) {
296         (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
297         return;
298     }
299
300     WebKitWebView* page = getViewFromFrame(m_frame);
301     WebKitNetworkRequest* request = webkit_network_request_new_with_core_request(resourceRequest);
302
303     WebKitWebPolicyDecision* policyDecision = webkit_web_policy_decision_new(m_frame, policyFunction);
304     if (m_policyDecision)
305         g_object_unref(m_policyDecision);
306     m_policyDecision = policyDecision;
307
308     gboolean isHandled = false;
309     g_signal_emit_by_name(page, "mime-type-policy-decision-requested", m_frame, request, mimeType.utf8().data(), policyDecision, &isHandled);
310
311     g_object_unref(request);
312
313     if (isHandled)
314         return;
315
316     GRefPtr<WebKitNetworkResponse> networkResponse(adoptGRef(webkit_web_frame_get_network_response(m_frame)));
317     if (networkResponse) {
318         ResourceResponse response = core(networkResponse.get());
319         if (response.isAttachment()) {
320             webkit_web_policy_decision_download(policyDecision);
321             return;
322         }
323     }
324
325     if (canShowMIMEType(mimeType))
326         webkit_web_policy_decision_use(policyDecision);
327     else
328         webkit_web_policy_decision_ignore(policyDecision);
329 }
330
331 static WebKitWebNavigationAction* getNavigationAction(const NavigationAction& action, const char* targetFrame)
332 {
333     gint button = -1;
334
335     const Event* event = action.event();
336     if (event && event->isMouseEvent()) {
337         const MouseEvent* mouseEvent = static_cast<const MouseEvent*>(event);
338         // DOM button values are 0, 1 and 2 for left, middle and right buttons.
339         // GTK+ uses 1, 2 and 3, so let's add 1 to remain consistent.
340         button = mouseEvent->button() + 1;
341     }
342
343     gint modifierFlags = 0;
344     UIEventWithKeyState* keyStateEvent = findEventWithKeyState(const_cast<Event*>(event));
345     if (keyStateEvent) {
346         if (keyStateEvent->shiftKey())
347             modifierFlags |= GDK_SHIFT_MASK;
348         if (keyStateEvent->ctrlKey())
349             modifierFlags |= GDK_CONTROL_MASK;
350         if (keyStateEvent->altKey())
351             modifierFlags |= GDK_MOD1_MASK;
352         if (keyStateEvent->metaKey())
353             modifierFlags |= GDK_MOD2_MASK;
354     }
355
356     return WEBKIT_WEB_NAVIGATION_ACTION(g_object_new(WEBKIT_TYPE_WEB_NAVIGATION_ACTION,
357                                                      "reason", kit(action.type()),
358                                                      "original-uri", action.url().string().utf8().data(),
359                                                      "button", button,
360                                                      "modifier-state", modifierFlags,
361                                                      "target-frame", targetFrame,
362                                                      NULL));
363 }
364
365 void FrameLoaderClient::dispatchDecidePolicyForNewWindowAction(FramePolicyFunction policyFunction, const NavigationAction& action, const ResourceRequest& resourceRequest, PassRefPtr<FormState>, const String& frameName)
366 {
367     ASSERT(policyFunction);
368     if (!policyFunction)
369         return;
370
371     if (resourceRequest.isNull()) {
372         (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
373         return;
374     }
375
376     WebKitWebPolicyDecision* policyDecision = webkit_web_policy_decision_new(m_frame, policyFunction);
377
378     if (m_policyDecision)
379         g_object_unref(m_policyDecision);
380     m_policyDecision = policyDecision;
381
382     WebKitWebView* webView = getViewFromFrame(m_frame);
383     WebKitNetworkRequest* request = webkit_network_request_new(resourceRequest.url().string().utf8().data());
384     WebKitWebNavigationAction* navigationAction = getNavigationAction(action, frameName.utf8().data());
385     gboolean isHandled = false;
386
387     g_signal_emit_by_name(webView, "new-window-policy-decision-requested", m_frame, request, navigationAction, policyDecision, &isHandled);
388
389     g_object_unref(navigationAction);
390     g_object_unref(request);
391
392     // FIXME: I think Qt version marshals this to another thread so when we
393     // have multi-threaded download, we might need to do the same
394     if (!isHandled)
395         (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyUse);
396 }
397
398 void FrameLoaderClient::dispatchDecidePolicyForNavigationAction(FramePolicyFunction policyFunction, const NavigationAction& action, const ResourceRequest& resourceRequest, PassRefPtr<FormState>)
399 {
400     ASSERT(policyFunction);
401     if (!policyFunction)
402         return;
403
404     if (resourceRequest.isNull()) {
405         (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
406         return;
407     }
408
409     WebKitWebView* webView = getViewFromFrame(m_frame);
410     WebKitNetworkRequest* request = webkit_network_request_new_with_core_request(resourceRequest);
411     WebKitNavigationResponse response;
412     /*
413      * We still support the deprecated navigation-requested signal, if the
414      * application doesn't ignore the navigation then the new signal is
415      * emitted.
416      * navigation-policy-decision-requested must be emitted after
417      * navigation-requested as the policy decision can be async.
418      */
419     g_signal_emit_by_name(webView, "navigation-requested", m_frame, request, &response);
420
421     if (response == WEBKIT_NAVIGATION_RESPONSE_IGNORE) {
422         (core(m_frame)->loader()->policyChecker()->*policyFunction)(PolicyIgnore);
423         g_object_unref(request);
424         return;
425     }
426
427     WebKitWebPolicyDecision* policyDecision = webkit_web_policy_decision_new(m_frame, policyFunction);
428     if (m_policyDecision)
429         g_object_unref(m_policyDecision);
430     m_policyDecision = policyDecision;
431
432     WebKitWebNavigationAction* navigationAction = getNavigationAction(action, NULL);
433     gboolean isHandled = false;
434     g_signal_emit_by_name(webView, "navigation-policy-decision-requested", m_frame, request, navigationAction, policyDecision, &isHandled);
435
436     g_object_unref(navigationAction);
437     g_object_unref(request);
438
439     // FIXME Implement default behavior when we can query the backend what protocols it supports
440     if (!isHandled)
441         webkit_web_policy_decision_use(m_policyDecision);
442 }
443
444 PassRefPtr<Widget> FrameLoaderClient::createPlugin(const IntSize& pluginSize, HTMLPlugInElement* element, const KURL& url, const Vector<String>& paramNames, const Vector<String>& paramValues, const String& mimeType, bool loadManually)
445 {
446     /* Check if we want to embed a GtkWidget, fallback to plugins later */
447     CString urlString = url.string().utf8();
448     CString mimeTypeString = mimeType.utf8();
449
450     ASSERT(paramNames.size() == paramValues.size());
451     GRefPtr<GHashTable> hash = adoptGRef(g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free));
452     for (unsigned i = 0; i < paramNames.size(); ++i) {
453         g_hash_table_insert(hash.get(),
454                             g_strdup(paramNames[i].utf8().data()),
455                             g_strdup(paramValues[i].utf8().data()));
456     }
457
458     GtkWidget* gtkWidget = 0;
459     g_signal_emit_by_name(getViewFromFrame(m_frame), "create-plugin-widget",
460                           mimeTypeString.data(), urlString.data(), hash.get(), &gtkWidget);
461     if (gtkWidget)
462         return adoptRef(new GtkPluginWidget(gtkWidget));
463
464     RefPtr<PluginView> pluginView = PluginView::create(core(m_frame), pluginSize, element, url, paramNames, paramValues, mimeType, loadManually);
465
466     if (pluginView->status() == PluginStatusLoadedSuccessfully)
467         return pluginView;
468
469     return 0;
470 }
471
472 PassRefPtr<Frame> FrameLoaderClient::createFrame(const KURL& url, const String& name, HTMLFrameOwnerElement* ownerElement,
473                                                  const String& referrer, bool allowsScrolling, int marginWidth, int marginHeight)
474 {
475     Frame* coreFrame = core(m_frame);
476
477     ASSERT(core(getViewFromFrame(m_frame)) == coreFrame->page());
478
479     RefPtr<Frame> childFrame = webkit_web_frame_init_with_web_view(getViewFromFrame(m_frame), ownerElement);
480
481     coreFrame->tree()->appendChild(childFrame);
482
483     childFrame->tree()->setName(name);
484     childFrame->init();
485
486     // The creation of the frame may have run arbitrary JavaScript that removed it from the page already.
487     if (!childFrame->page())
488         return 0;
489
490     childFrame->loader()->loadURLIntoChildFrame(url, referrer, childFrame.get());
491
492     // The frame's onload handler may have removed it from the document.
493     if (!childFrame->tree()->parent())
494         return 0;
495
496     return childFrame.release();
497 }
498
499 void FrameLoaderClient::didTransferChildFrameToNewDocument()
500 {
501 }
502
503 void FrameLoaderClient::redirectDataToPlugin(Widget* pluginWidget)
504 {
505     ASSERT(!m_pluginView);
506     m_pluginView = static_cast<PluginView*>(pluginWidget);
507     m_hasSentResponseToPlugin = false;
508 }
509
510 PassRefPtr<Widget> FrameLoaderClient::createJavaAppletWidget(const IntSize& pluginSize, HTMLAppletElement* element, const KURL& baseURL, const Vector<String>& paramNames, const Vector<String>& paramValues)
511 {
512     return FrameLoaderClient::createPlugin(pluginSize, element, baseURL, paramNames, paramValues, "application/x-java-applet", false);
513 }
514
515 ObjectContentType FrameLoaderClient::objectContentType(const KURL& url, const String& mimeType)
516 {
517     return FrameLoader::defaultObjectContentType(url, mimeType);
518 }
519
520 String FrameLoaderClient::overrideMediaType() const
521 {
522     notImplemented();
523     return String();
524 }
525
526 void FrameLoaderClient::dispatchDidClearWindowObjectInWorld(DOMWrapperWorld* world)
527 {
528     if (world != mainThreadNormalWorld())
529         return;
530
531     // Is this obsolete now?
532     g_signal_emit_by_name(m_frame, "cleared");
533
534     Frame* coreFrame = core(m_frame);
535     ASSERT(coreFrame);
536
537     Settings* settings = coreFrame->settings();
538     if (!settings || !settings->isJavaScriptEnabled())
539         return;
540
541     // TODO: Consider using g_signal_has_handler_pending() to avoid the overhead
542     // when there are no handlers.
543     JSGlobalContextRef context = toGlobalRef(coreFrame->script()->globalObject(mainThreadNormalWorld())->globalExec());
544     JSObjectRef windowObject = toRef(coreFrame->script()->globalObject(mainThreadNormalWorld()));
545     ASSERT(windowObject);
546
547     WebKitWebView* webView = getViewFromFrame(m_frame);
548     g_signal_emit_by_name(webView, "window-object-cleared", m_frame, context, windowObject);
549
550     // TODO: Re-attach debug clients if present.
551     // The Win port has an example of how we might do this.
552 }
553
554 void FrameLoaderClient::documentElementAvailable()
555 {
556 }
557
558 void FrameLoaderClient::didPerformFirstNavigation() const
559 {
560 }
561
562 void FrameLoaderClient::registerForIconNotification(bool shouldRegister)
563 {
564     notImplemented();
565 }
566
567 void FrameLoaderClient::setMainFrameDocumentReady(bool)
568 {
569     // this is only interesting once we provide an external API for the DOM
570 }
571
572 bool FrameLoaderClient::hasWebView() const
573 {
574     return getViewFromFrame(m_frame);
575 }
576
577 void FrameLoaderClient::dispatchDidFinishLoad()
578 {
579     if (m_loadingErrorPage) {
580         m_loadingErrorPage = false;
581         return;
582     }
583
584     loadDone(m_frame, true);
585 }
586
587 void FrameLoaderClient::frameLoadCompleted()
588 {
589     notImplemented();
590 }
591
592 void FrameLoaderClient::saveViewStateToItem(HistoryItem*)
593 {
594     notImplemented();
595 }
596
597 void FrameLoaderClient::restoreViewState()
598 {
599     notImplemented();
600 }
601
602 bool FrameLoaderClient::shouldGoToHistoryItem(HistoryItem* item) const
603 {
604     // FIXME: This is a very simple implementation. More sophisticated
605     // implementation would delegate the decision to a PolicyDelegate.
606     // See mac implementation for example.
607     return item != 0;
608 }
609
610 void FrameLoaderClient::dispatchDidAddBackForwardItem(HistoryItem*) const
611 {
612 }
613
614 void FrameLoaderClient::dispatchDidRemoveBackForwardItem(HistoryItem*) const
615 {
616 }
617
618 void FrameLoaderClient::dispatchDidChangeBackForwardIndex() const
619 {
620 }
621
622 void FrameLoaderClient::didDisplayInsecureContent()
623 {
624     notImplemented();
625 }
626
627 void FrameLoaderClient::didRunInsecureContent(SecurityOrigin*)
628 {
629     notImplemented();
630 }
631
632 void FrameLoaderClient::makeRepresentation(WebCore::DocumentLoader*)
633 {
634     notImplemented();
635 }
636
637 void FrameLoaderClient::forceLayout()
638 {
639     FrameView* view = core(m_frame)->view();
640     if (view)
641         view->forceLayout(true);
642 }
643
644 void FrameLoaderClient::forceLayoutForNonHTML()
645 {
646     notImplemented();
647 }
648
649 void FrameLoaderClient::setCopiesOnScroll()
650 {
651     notImplemented();
652 }
653
654 void FrameLoaderClient::detachedFromParent2()
655 {
656     notImplemented();
657 }
658
659 void FrameLoaderClient::detachedFromParent3()
660 {
661     notImplemented();
662 }
663
664 void FrameLoaderClient::dispatchDidHandleOnloadEvents()
665 {
666     g_signal_emit_by_name(getViewFromFrame(m_frame), "onload-event", m_frame);
667 }
668
669 void FrameLoaderClient::dispatchDidReceiveServerRedirectForProvisionalLoad()
670 {
671     notImplemented();
672 }
673
674 void FrameLoaderClient::dispatchDidCancelClientRedirect()
675 {
676     notImplemented();
677 }
678
679 void FrameLoaderClient::dispatchWillPerformClientRedirect(const KURL&, double, double)
680 {
681     notImplemented();
682 }
683
684 void FrameLoaderClient::dispatchDidChangeLocationWithinPage()
685 {
686     WebKitWebFramePrivate* priv = m_frame->priv;
687     g_free(priv->uri);
688     priv->uri = g_strdup(core(m_frame)->loader()->url().prettyURL().utf8().data());
689     g_object_notify(G_OBJECT(m_frame), "uri");
690     WebKitWebView* webView = getViewFromFrame(m_frame);
691     if (m_frame == webkit_web_view_get_main_frame(webView))
692         g_object_notify(G_OBJECT(webView), "uri");
693 }
694
695 void FrameLoaderClient::dispatchDidPushStateWithinPage()
696 {
697     notImplemented();
698 }
699
700 void FrameLoaderClient::dispatchDidReplaceStateWithinPage()
701 {
702     notImplemented();
703 }
704
705 void FrameLoaderClient::dispatchDidPopStateWithinPage()
706 {
707     notImplemented();
708 }
709
710 void FrameLoaderClient::dispatchWillClose()
711 {
712     notImplemented();
713 }
714
715 void FrameLoaderClient::dispatchDidReceiveIcon()
716 {
717     if (m_loadingErrorPage)
718         return;
719
720     WebKitWebView* webView = getViewFromFrame(m_frame);
721
722     // Avoid reporting favicons for non-main frames.
723     if (m_frame != webkit_web_view_get_main_frame(webView))
724         return;
725
726     g_object_notify(G_OBJECT(webView), "icon-uri");
727     g_signal_emit_by_name(webView, "icon-loaded", webkit_web_view_get_icon_uri(webView));
728 }
729
730 void FrameLoaderClient::dispatchDidStartProvisionalLoad()
731 {
732     if (m_loadingErrorPage)
733         return;
734
735     notifyStatus(m_frame, WEBKIT_LOAD_PROVISIONAL);
736 }
737
738 void FrameLoaderClient::dispatchDidReceiveTitle(const String& title)
739 {
740     if (m_loadingErrorPage)
741         return;
742
743     WebKitWebFramePrivate* priv = m_frame->priv;
744     g_free(priv->title);
745     priv->title = g_strdup(title.utf8().data());
746
747     g_signal_emit_by_name(m_frame, "title-changed", priv->title);
748     g_object_notify(G_OBJECT(m_frame), "title");
749
750     WebKitWebView* webView = getViewFromFrame(m_frame);
751     if (m_frame == webkit_web_view_get_main_frame(webView)) {
752         g_signal_emit_by_name(webView, "title-changed", m_frame, title.utf8().data());
753         g_object_notify(G_OBJECT(webView), "title");
754     }
755 }
756
757 void FrameLoaderClient::dispatchDidChangeIcons()
758 {
759     notImplemented();
760 }
761
762 void FrameLoaderClient::dispatchDidCommitLoad()
763 {
764     if (m_loadingErrorPage)
765         return;
766
767     /* Update the URI once first data has been received.
768      * This means the URI is valid and successfully identify the page that's going to be loaded.
769      */
770     g_object_freeze_notify(G_OBJECT(m_frame));
771
772     WebKitWebFramePrivate* priv = m_frame->priv;
773     g_free(priv->uri);
774     priv->uri = g_strdup(core(m_frame)->loader()->activeDocumentLoader()->url().prettyURL().utf8().data());
775     g_free(priv->title);
776     priv->title = NULL;
777     g_object_notify(G_OBJECT(m_frame), "uri");
778     g_object_notify(G_OBJECT(m_frame), "title");
779
780     g_signal_emit_by_name(m_frame, "load-committed");
781     notifyStatus(m_frame, WEBKIT_LOAD_COMMITTED);
782
783     WebKitWebView* webView = getViewFromFrame(m_frame);
784     if (m_frame == webkit_web_view_get_main_frame(webView)) {
785         g_object_freeze_notify(G_OBJECT(webView));
786         g_object_notify(G_OBJECT(webView), "uri");
787         g_object_notify(G_OBJECT(webView), "title");
788         g_object_thaw_notify(G_OBJECT(webView));
789         g_signal_emit_by_name(webView, "load-committed", m_frame);
790     }
791
792     g_object_thaw_notify(G_OBJECT(m_frame));
793 }
794
795 void FrameLoaderClient::dispatchDidFinishDocumentLoad()
796 {
797     WebKitWebView* webView = getViewFromFrame(m_frame);
798     g_signal_emit_by_name(webView, "document-load-finished", m_frame);
799 }
800
801 void FrameLoaderClient::dispatchDidFirstLayout()
802 {
803     notImplemented();
804 }
805
806 void FrameLoaderClient::dispatchDidFirstVisuallyNonEmptyLayout()
807 {
808     if (m_loadingErrorPage)
809         return;
810
811     notifyStatus(m_frame, WEBKIT_LOAD_FIRST_VISUALLY_NON_EMPTY_LAYOUT);
812 }
813
814 void FrameLoaderClient::dispatchShow()
815 {
816     WebKitWebView* webView = getViewFromFrame(m_frame);
817     webkit_web_view_notify_ready(webView);
818 }
819
820 void FrameLoaderClient::cancelPolicyCheck()
821 {
822     //FIXME Add support for more than one policy decision at once
823     if (m_policyDecision)
824         webkit_web_policy_decision_cancel(m_policyDecision);
825 }
826
827 void FrameLoaderClient::dispatchDidLoadMainResource(WebCore::DocumentLoader*)
828 {
829     notImplemented();
830 }
831
832 void FrameLoaderClient::revertToProvisionalState(WebCore::DocumentLoader*)
833 {
834     notImplemented();
835 }
836
837 void FrameLoaderClient::willChangeTitle(WebCore::DocumentLoader*)
838 {
839     notImplemented();
840 }
841
842 void FrameLoaderClient::didChangeTitle(WebCore::DocumentLoader *l)
843 {
844     setTitle(l->title(), l->url());
845 }
846
847 bool FrameLoaderClient::canHandleRequest(const ResourceRequest&) const
848 {
849     notImplemented();
850     return true;
851 }
852
853 bool FrameLoaderClient::canShowMIMEType(const String& type) const
854 {
855     return (MIMETypeRegistry::isSupportedImageMIMEType(type)
856             || MIMETypeRegistry::isSupportedNonImageMIMEType(type)
857             || MIMETypeRegistry::isSupportedMediaMIMEType(type)
858             || PluginDatabase::installedPlugins()->isMIMETypeRegistered(type));
859 }
860
861 bool FrameLoaderClient::representationExistsForURLScheme(const String&) const
862 {
863     notImplemented();
864     return false;
865 }
866
867 String FrameLoaderClient::generatedMIMETypeForURLScheme(const String&) const
868 {
869     notImplemented();
870     return String();
871 }
872
873 void FrameLoaderClient::finishedLoading(WebCore::DocumentLoader* documentLoader)
874 {
875     if (!m_pluginView) {
876         FrameLoader* loader = documentLoader->frameLoader();
877         loader->writer()->setEncoding(m_response.textEncodingName(), false);
878     } else {
879         m_pluginView->didFinishLoading();
880         m_pluginView = 0;
881         m_hasSentResponseToPlugin = false;
882     }
883 }
884
885
886 void FrameLoaderClient::provisionalLoadStarted()
887 {
888     WebKitWebView* webView = getViewFromFrame(m_frame);
889
890     if (m_frame == webkit_web_view_get_main_frame(webView))
891         webkit_web_view_clear_resources(webView);
892 }
893
894 void FrameLoaderClient::didFinishLoad() {
895     notImplemented();
896 }
897
898 void FrameLoaderClient::prepareForDataSourceReplacement() { notImplemented(); }
899
900 void FrameLoaderClient::setTitle(const String& title, const KURL& url)
901 {
902     WebKitWebFramePrivate* frameData = WEBKIT_WEB_FRAME_GET_PRIVATE(m_frame);
903     g_free(frameData->title);
904     frameData->title = g_strdup(title.utf8().data());
905 }
906
907 void FrameLoaderClient::dispatchDidReceiveContentLength(WebCore::DocumentLoader*, unsigned long identifier, int lengthReceived)
908 {
909     notImplemented();
910 }
911
912 void FrameLoaderClient::dispatchDidFinishLoading(WebCore::DocumentLoader* loader, unsigned long identifier)
913 {
914     static_cast<WebKit::DocumentLoader*>(loader)->decreaseLoadCount(identifier);
915
916     WebKitWebView* webView = getViewFromFrame(m_frame);
917     GOwnPtr<gchar> identifierString(toString(identifier));
918     WebKitWebResource* webResource = webkit_web_view_get_resource(webView, identifierString.get());
919
920     // A NULL WebResource means the load has been interrupted, and
921     // replaced by another one while this resource was being loaded.
922     if (!webResource)
923         return;
924
925     const char* uri = webkit_web_resource_get_uri(webResource);
926     RefPtr<ArchiveResource> coreResource(loader->subresource(KURL(KURL(), uri)));
927
928     // If coreResource is NULL here, the resource failed to load,
929     // unless it's the main resource.
930     if (!coreResource && webResource != webkit_web_view_get_main_resource(webView))
931         return;
932
933     if (!coreResource)
934         coreResource = loader->mainResource();
935
936     webkit_web_resource_init_with_core_resource(webResource, coreResource.get());
937
938     // FIXME: This function should notify the application that the resource
939     // finished loading, maybe using a load-status property in the
940     // WebKitWebResource object, similar to what we do for WebKitWebFrame'
941     // signal.
942     notImplemented();
943 }
944
945 void FrameLoaderClient::dispatchDidFailLoading(WebCore::DocumentLoader* loader, unsigned long identifier, const ResourceError& error)
946 {
947     static_cast<WebKit::DocumentLoader*>(loader)->decreaseLoadCount(identifier);
948
949     // FIXME: This function should notify the application that the resource failed
950     // loading, maybe a 'load-error' signal in the WebKitWebResource object.
951     notImplemented();
952 }
953
954 bool FrameLoaderClient::dispatchDidLoadResourceFromMemoryCache(WebCore::DocumentLoader*, const ResourceRequest&, const ResourceResponse&, int length)
955 {
956     notImplemented();
957     return false;
958 }
959
960 void FrameLoaderClient::dispatchDidFailProvisionalLoad(const ResourceError& error)
961 {
962     dispatchDidFailLoad(error);
963 }
964
965 void FrameLoaderClient::dispatchDidFailLoad(const ResourceError& error)
966 {
967     if (m_loadingErrorPage)
968         return;
969
970     notifyStatus(m_frame, WEBKIT_LOAD_FAILED);
971
972     WebKitWebView* webView = getViewFromFrame(m_frame);
973     GError* webError = g_error_new_literal(g_quark_from_string(error.domain().utf8().data()),
974                                            error.errorCode(),
975                                            error.localizedDescription().utf8().data());
976     gboolean isHandled = false;
977     g_signal_emit_by_name(webView, "load-error", m_frame, error.failingURL().utf8().data(), webError, &isHandled);
978
979     if (isHandled) {
980         g_error_free(webError);
981         return;
982     }
983
984     if (!shouldFallBack(error)) {
985         g_error_free(webError);
986         return;
987     }
988
989     m_loadingErrorPage = true;
990
991     String content;
992     gchar* fileContent = 0;
993     gchar* errorURI = g_filename_to_uri(DATA_DIR"/webkit-1.0/resources/error.html", NULL, NULL);
994     GFile* errorFile = g_file_new_for_uri(errorURI);
995     g_free(errorURI);
996
997     if (!errorFile)
998         content = String::format("<html><body>%s</body></html>", webError->message);
999     else {
1000         gboolean loaded = g_file_load_contents(errorFile, 0, &fileContent, 0, 0, 0);
1001         if (!loaded)
1002             content = String::format("<html><body>%s</body></html>", webError->message);
1003         else
1004             content = String::format(fileContent, error.failingURL().utf8().data(), webError->message);
1005     }
1006
1007     webkit_web_frame_load_alternate_string(m_frame, content.utf8().data(), 0, error.failingURL().utf8().data());
1008
1009     g_free(fileContent);
1010
1011     if (errorFile)
1012         g_object_unref(errorFile);
1013
1014     g_error_free(webError);
1015 }
1016
1017 void FrameLoaderClient::download(ResourceHandle* handle, const ResourceRequest& request, const ResourceRequest&, const ResourceResponse& response)
1018 {
1019     WebKitNetworkRequest* networkRequest = webkit_network_request_new_with_core_request(request);
1020     WebKitWebView* view = getViewFromFrame(m_frame);
1021
1022     webkit_web_view_request_download(view, networkRequest, response, handle);
1023     g_object_unref(networkRequest);
1024 }
1025
1026 ResourceError FrameLoaderClient::cancelledError(const ResourceRequest& request)
1027 {
1028     return ResourceError(g_quark_to_string(WEBKIT_NETWORK_ERROR), WEBKIT_NETWORK_ERROR_CANCELLED,
1029                          request.url().string(), _("Load request cancelled"));
1030 }
1031
1032 ResourceError FrameLoaderClient::blockedError(const ResourceRequest& request)
1033 {
1034     return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_CANNOT_USE_RESTRICTED_PORT,
1035                          request.url().string(), _("Not allowed to use restricted network port"));
1036 }
1037
1038 ResourceError FrameLoaderClient::cannotShowURLError(const ResourceRequest& request)
1039 {
1040     return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_CANNOT_SHOW_URL,
1041                          request.url().string(), _("URL cannot be shown"));
1042 }
1043
1044 ResourceError FrameLoaderClient::interruptForPolicyChangeError(const ResourceRequest& request)
1045 {
1046     return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE,
1047                          request.url().string(), _("Frame load was interrupted"));
1048 }
1049
1050 ResourceError FrameLoaderClient::cannotShowMIMETypeError(const ResourceResponse& response)
1051 {
1052     return ResourceError(g_quark_to_string(WEBKIT_POLICY_ERROR), WEBKIT_POLICY_ERROR_CANNOT_SHOW_MIME_TYPE,
1053                          response.url().string(), _("Content with the specified MIME type cannot be shown"));
1054 }
1055
1056 ResourceError FrameLoaderClient::fileDoesNotExistError(const ResourceResponse& response)
1057 {
1058     return ResourceError(g_quark_to_string(WEBKIT_NETWORK_ERROR), WEBKIT_NETWORK_ERROR_FILE_DOES_NOT_EXIST,
1059                          response.url().string(), _("File does not exist"));
1060 }
1061
1062 ResourceError FrameLoaderClient::pluginWillHandleLoadError(const ResourceResponse& response)
1063 {
1064     return ResourceError(g_quark_to_string(WEBKIT_PLUGIN_ERROR), WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD,
1065                          response.url().string(), _("Plugin will handle load"));
1066 }
1067
1068 bool FrameLoaderClient::shouldFallBack(const ResourceError& error)
1069 {
1070     return !(error.isCancellation() || error.errorCode() == WEBKIT_POLICY_ERROR_FRAME_LOAD_INTERRUPTED_BY_POLICY_CHANGE || error.errorCode() == WEBKIT_PLUGIN_ERROR_WILL_HANDLE_LOAD);
1071 }
1072
1073 bool FrameLoaderClient::canCachePage() const
1074 {
1075     return true;
1076 }
1077
1078 Frame* FrameLoaderClient::dispatchCreatePage()
1079 {
1080     WebKitWebView* webView = getViewFromFrame(m_frame);
1081     WebKitWebView* newWebView = 0;
1082
1083     g_signal_emit_by_name(webView, "create-web-view", m_frame, &newWebView);
1084
1085     if (!newWebView)
1086         return 0;
1087
1088     WebKitWebViewPrivate* privateData = WEBKIT_WEB_VIEW_GET_PRIVATE(newWebView);
1089     return core(privateData->mainFrame);
1090 }
1091
1092 void FrameLoaderClient::dispatchUnableToImplementPolicy(const ResourceError&)
1093 {
1094     notImplemented();
1095 }
1096
1097 void FrameLoaderClient::setMainDocumentError(WebCore::DocumentLoader*, const ResourceError& error)
1098 {
1099     if (m_pluginView) {
1100         m_pluginView->didFail(error);
1101         m_pluginView = 0;
1102         m_hasSentResponseToPlugin = false;
1103     }
1104 }
1105
1106 void FrameLoaderClient::startDownload(const ResourceRequest& request)
1107 {
1108     WebKitNetworkRequest* networkRequest = webkit_network_request_new_with_core_request(request);
1109     WebKitWebView* view = getViewFromFrame(m_frame);
1110
1111     webkit_web_view_request_download(view, networkRequest);
1112     g_object_unref(networkRequest);
1113 }
1114
1115 void FrameLoaderClient::updateGlobalHistory()
1116 {
1117     notImplemented();
1118 }
1119
1120 void FrameLoaderClient::updateGlobalHistoryRedirectLinks()
1121 {
1122     notImplemented();
1123 }
1124
1125 void FrameLoaderClient::savePlatformDataToCachedFrame(CachedFrame* cachedFrame)
1126 {
1127     // We need to do this here in order to disconnect the scrollbars
1128     // that are being used by the frame that is being cached from the
1129     // adjustments, otherwise they will react to changes in the
1130     // adjustments, and bad things will happen.
1131     if (cachedFrame->view())
1132         cachedFrame->view()->setGtkAdjustments(0, 0);
1133 }
1134
1135 static void postCommitFrameViewSetup(WebKitWebFrame *frame, FrameView *view, bool resetValues)
1136 {
1137     WebKitWebView* containingWindow = getViewFromFrame(frame);
1138     WebKitWebViewPrivate* priv = WEBKIT_WEB_VIEW_GET_PRIVATE(containingWindow);
1139     view->setGtkAdjustments(priv->horizontalAdjustment, priv->verticalAdjustment, resetValues);
1140
1141     if (priv->currentMenu) {
1142         GtkMenu* menu = priv->currentMenu;
1143         priv->currentMenu = 0;
1144
1145         gtk_menu_popdown(menu);
1146         g_object_unref(menu);
1147     }
1148
1149     // Do not allow click counting between main frame loads.
1150     priv->previousClickTime = 0;
1151 }
1152
1153 void FrameLoaderClient::transitionToCommittedFromCachedFrame(CachedFrame* cachedFrame)
1154 {
1155     ASSERT(cachedFrame->view());
1156
1157     Frame* frame = core(m_frame);
1158     if (frame != frame->page()->mainFrame())
1159         return;
1160
1161     postCommitFrameViewSetup(m_frame, cachedFrame->view(), false);
1162 }
1163
1164 void FrameLoaderClient::transitionToCommittedForNewPage()
1165 {
1166     WebKitWebView* containingWindow = getViewFromFrame(m_frame);
1167     IntSize size = IntSize(GTK_WIDGET(containingWindow)->allocation.width,
1168                            GTK_WIDGET(containingWindow)->allocation.height);
1169     bool transparent = webkit_web_view_get_transparent(containingWindow);
1170     Color backgroundColor = transparent ? WebCore::Color::transparent : WebCore::Color::white;
1171     Frame* frame = core(m_frame);
1172     ASSERT(frame);
1173
1174     frame->createView(size, backgroundColor, transparent, IntSize(), false);
1175
1176     // We need to do further manipulation on the FrameView if it was the mainFrame
1177     if (frame != frame->page()->mainFrame())
1178         return;
1179
1180     postCommitFrameViewSetup(m_frame, frame->view(), true);
1181 }
1182
1183 }