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