2009-11-10 Yaar Schnitman <yaar@chromium.org>
[WebKit-https.git] / WebKit / chromium / src / FrameLoaderClientImpl.cpp
1 /*
2  * Copyright (C) 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "FrameLoaderClientImpl.h"
33
34 #include "Chrome.h"
35 #include "CString.h"
36 #include "Document.h"
37 #include "DocumentLoader.h"
38 #include "FormState.h"
39 #include "FrameLoader.h"
40 #include "FrameLoadRequest.h"
41 #include "HitTestResult.h"
42 #include "HTMLAppletElement.h"
43 #include "HTMLFormElement.h"  // needed by FormState.h
44 #include "HTMLNames.h"
45 #include "MIMETypeRegistry.h"
46 #include "MouseEvent.h"
47 #include "Page.h"
48 #include "PlatformString.h"
49 #include "PluginData.h"
50 #include "StringExtras.h"
51 #include "WebDataSourceImpl.h"
52 #include "WebDevToolsAgentPrivate.h"
53 #include "WebFormElement.h"
54 #include "WebFrameClient.h"
55 #include "WebFrameImpl.h"
56 #include "WebKit.h"
57 #include "WebKitClient.h"
58 #include "WebMimeRegistry.h"
59 #include "WebNode.h"
60 #include "WebPlugin.h"
61 #include "WebPluginContainerImpl.h"
62 #include "WebPluginLoadObserver.h"
63 #include "WebPluginParams.h"
64 #include "WebSecurityOrigin.h"
65 #include "WebURL.h"
66 #include "WebURLError.h"
67 #include "WebVector.h"
68 #include "WebViewClient.h"
69 #include "WebViewImpl.h"
70 #include "WindowFeatures.h"
71 #include "WrappedResourceRequest.h"
72 #include "WrappedResourceResponse.h"
73
74 using namespace WebCore;
75
76 namespace WebKit {
77
78 // Domain for internal error codes.
79 static const char internalErrorDomain[] = "WebKit";
80
81 // An internal error code.  Used to note a policy change error resulting from
82 // dispatchDecidePolicyForMIMEType not passing the PolicyUse option.
83 enum {
84     PolicyChangeError = -10000,
85 };
86
87 FrameLoaderClientImpl::FrameLoaderClientImpl(WebFrameImpl* frame)
88     : m_webFrame(frame)
89     , m_hasRepresentation(false)
90     , m_sentInitialResponseToPlugin(false)
91     , m_nextNavigationPolicy(WebNavigationPolicyIgnore)
92 {
93 }
94
95 FrameLoaderClientImpl::~FrameLoaderClientImpl()
96 {
97 }
98
99 void FrameLoaderClientImpl::frameLoaderDestroyed()
100 {
101     // When the WebFrame was created, it had an extra reference given to it on
102     // behalf of the Frame.  Since the WebFrame owns us, this extra ref also
103     // serves to keep us alive until the FrameLoader is done with us.  The
104     // FrameLoader calls this method when it's going away.  Therefore, we balance
105     // out that extra reference, which may cause 'this' to be deleted.
106     m_webFrame->closing();
107     m_webFrame->deref();
108 }
109
110 void FrameLoaderClientImpl::windowObjectCleared()
111 {
112     if (m_webFrame->client())
113         m_webFrame->client()->didClearWindowObject(m_webFrame);
114
115     WebViewImpl* webview = m_webFrame->viewImpl();
116     if (webview->devToolsAgentPrivate())
117         webview->devToolsAgentPrivate()->didClearWindowObject(m_webFrame);
118 }
119
120 void FrameLoaderClientImpl::documentElementAvailable()
121 {
122     if (m_webFrame->client())
123         m_webFrame->client()->didCreateDocumentElement(m_webFrame);
124 }
125
126 void FrameLoaderClientImpl::didCreateScriptContextForFrame()
127 {
128     if (m_webFrame->client())
129         m_webFrame->client()->didCreateScriptContext(m_webFrame);
130 }
131
132 void FrameLoaderClientImpl::didDestroyScriptContextForFrame()
133 {
134     if (m_webFrame->client())
135         m_webFrame->client()->didDestroyScriptContext(m_webFrame);
136 }
137
138 void FrameLoaderClientImpl::didCreateIsolatedScriptContext()
139 {
140     if (m_webFrame->client())
141         m_webFrame->client()->didCreateIsolatedScriptContext(m_webFrame);
142 }
143
144 void FrameLoaderClientImpl::didPerformFirstNavigation() const
145 {
146 }
147
148 void FrameLoaderClientImpl::registerForIconNotification(bool)
149 {
150 }
151
152 void FrameLoaderClientImpl::didChangeScrollOffset()
153 {
154     if (m_webFrame->client())
155         m_webFrame->client()->didChangeScrollOffset(m_webFrame);
156 }
157
158 bool FrameLoaderClientImpl::allowJavaScript(bool enabledPerSettings)
159 {
160     if (m_webFrame->client())
161         return m_webFrame->client()->allowScript(m_webFrame, enabledPerSettings);
162
163     return enabledPerSettings;
164 }
165
166 bool FrameLoaderClientImpl::hasWebView() const
167 {
168     return m_webFrame->viewImpl();
169 }
170
171 bool FrameLoaderClientImpl::hasFrameView() const
172 {
173     // The Mac port has this notion of a WebFrameView, which seems to be
174     // some wrapper around an NSView.  Since our equivalent is HWND, I guess
175     // we have a "frameview" whenever we have the toplevel HWND.
176     return m_webFrame->viewImpl();
177 }
178
179 void FrameLoaderClientImpl::makeDocumentView()
180 {
181     m_webFrame->createFrameView();
182 }
183
184 void FrameLoaderClientImpl::makeRepresentation(DocumentLoader*)
185 {
186     m_hasRepresentation = true;
187 }
188
189 void FrameLoaderClientImpl::forceLayout()
190 {
191     // FIXME
192 }
193
194 void FrameLoaderClientImpl::forceLayoutForNonHTML()
195 {
196     // FIXME
197 }
198
199 void FrameLoaderClientImpl::setCopiesOnScroll()
200 {
201     // FIXME
202 }
203
204 void FrameLoaderClientImpl::detachedFromParent2()
205 {
206     // Nothing to do here.
207 }
208
209 void FrameLoaderClientImpl::detachedFromParent3()
210 {
211     // Close down the proxy.  The purpose of this change is to make the
212     // call to ScriptController::clearWindowShell a no-op when called from
213     // Frame::pageDestroyed.  Without this change, this call to clearWindowShell
214     // will cause a crash.  If you remove/modify this, just ensure that you can
215     // go to a page and then navigate to a new page without getting any asserts
216     // or crashes.
217     m_webFrame->frame()->script()->proxy()->clearForClose();
218 }
219
220 // This function is responsible for associating the |identifier| with a given
221 // subresource load.  The following functions that accept an |identifier| are
222 // called for each subresource, so they should not be dispatched to the
223 // WebFrame.
224 void FrameLoaderClientImpl::assignIdentifierToInitialRequest(
225     unsigned long identifier, DocumentLoader* loader,
226     const ResourceRequest& request)
227 {
228     if (m_webFrame->client()) {
229         WrappedResourceRequest webreq(request);
230         m_webFrame->client()->assignIdentifierToRequest(
231             m_webFrame, identifier, webreq);
232     }
233 }
234
235 // Determines whether the request being loaded by |loader| is a frame or a
236 // subresource. A subresource in this context is anything other than a frame --
237 // this includes images and xmlhttp requests.  It is important to note that a
238 // subresource is NOT limited to stuff loaded through the frame's subresource
239 // loader. Synchronous xmlhttp requests for example, do not go through the
240 // subresource loader, but we still label them as TargetIsSubResource.
241 //
242 // The important edge cases to consider when modifying this function are
243 // how synchronous resource loads are treated during load/unload threshold.
244 static ResourceRequest::TargetType determineTargetTypeFromLoader(DocumentLoader* loader)
245 {
246     if (loader == loader->frameLoader()->provisionalDocumentLoader()) {
247         if (loader->frameLoader()->isLoadingMainFrame())
248             return ResourceRequest::TargetIsMainFrame;
249         return ResourceRequest::TargetIsSubFrame;
250     }
251     return ResourceRequest::TargetIsSubResource;
252 }
253
254 void FrameLoaderClientImpl::dispatchWillSendRequest(
255     DocumentLoader* loader, unsigned long identifier, ResourceRequest& request,
256     const ResourceResponse& redirectResponse)
257 {
258     if (loader) {
259         // We want to distinguish between a request for a document to be loaded into
260         // the main frame, a sub-frame, or the sub-objects in that document.
261         request.setTargetType(determineTargetTypeFromLoader(loader));
262     }
263
264     // FrameLoader::loadEmptyDocumentSynchronously() creates an empty document
265     // with no URL.  We don't like that, so we'll rename it to about:blank.
266     if (request.url().isEmpty())
267         request.setURL(KURL(ParsedURLString, "about:blank"));
268     if (request.firstPartyForCookies().isEmpty())
269         request.setFirstPartyForCookies(KURL(ParsedURLString, "about:blank"));
270
271     // Give the WebFrameClient a crack at the request.
272     if (m_webFrame->client()) {
273         WrappedResourceRequest webreq(request);
274         WrappedResourceResponse webresp(redirectResponse);
275         m_webFrame->client()->willSendRequest(
276             m_webFrame, identifier, webreq, webresp);
277     }
278 }
279
280 bool FrameLoaderClientImpl::shouldUseCredentialStorage(
281     DocumentLoader*, unsigned long identifier)
282 {
283     // FIXME
284     // Intended to pass through to a method on the resource load delegate.
285     // If implemented, that method controls whether the browser should ask the
286     // networking layer for a stored default credential for the page (say from
287     // the Mac OS keychain). If the method returns false, the user should be
288     // presented with an authentication challenge whether or not the networking
289     // layer has a credential stored.
290     // This returns true for backward compatibility: the ability to override the
291     // system credential store is new. (Actually, not yet fully implemented in
292     // WebKit, as of this writing.)
293     return true;
294 }
295
296 void FrameLoaderClientImpl::dispatchDidReceiveAuthenticationChallenge(
297     DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&)
298 {
299     // FIXME
300 }
301
302 void FrameLoaderClientImpl::dispatchDidCancelAuthenticationChallenge(
303     DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&)
304 {
305     // FIXME
306 }
307
308 void FrameLoaderClientImpl::dispatchDidReceiveResponse(DocumentLoader* loader,
309                                                        unsigned long identifier,
310                                                        const ResourceResponse& response)
311 {
312     if (m_webFrame->client()) {
313         WrappedResourceResponse webresp(response);
314         m_webFrame->client()->didReceiveResponse(m_webFrame, identifier, webresp);
315     }
316 }
317
318 void FrameLoaderClientImpl::dispatchDidReceiveContentLength(
319     DocumentLoader* loader,
320     unsigned long identifier,
321     int lengthReceived)
322 {
323 }
324
325 // Called when a particular resource load completes
326 void FrameLoaderClientImpl::dispatchDidFinishLoading(DocumentLoader* loader,
327                                                     unsigned long identifier)
328 {
329     if (m_webFrame->client())
330         m_webFrame->client()->didFinishResourceLoad(m_webFrame, identifier);
331 }
332
333 void FrameLoaderClientImpl::dispatchDidFailLoading(DocumentLoader* loader,
334                                                   unsigned long identifier,
335                                                   const ResourceError& error)
336 {
337     if (m_webFrame->client())
338         m_webFrame->client()->didFailResourceLoad(m_webFrame, identifier, error);
339 }
340
341 void FrameLoaderClientImpl::dispatchDidFinishDocumentLoad()
342 {
343     // A frame may be reused.  This call ensures we don't hold on to our password
344     // listeners and their associated HTMLInputElements.
345     m_webFrame->clearPasswordListeners();
346
347     if (m_webFrame->client())
348         m_webFrame->client()->didFinishDocumentLoad(m_webFrame);
349 }
350
351 bool FrameLoaderClientImpl::dispatchDidLoadResourceFromMemoryCache(
352     DocumentLoader* loader,
353     const ResourceRequest& request,
354     const ResourceResponse& response,
355     int length)
356 {
357     if (m_webFrame->client()) {
358         WrappedResourceRequest webreq(request);
359         WrappedResourceResponse webresp(response);
360         m_webFrame->client()->didLoadResourceFromMemoryCache(
361             m_webFrame, webreq, webresp);
362     }
363     return false;  // Do not suppress remaining notifications
364 }
365
366 void FrameLoaderClientImpl::dispatchDidLoadResourceByXMLHttpRequest(
367     unsigned long identifier,
368     const ScriptString& source)
369 {
370 }
371
372 void FrameLoaderClientImpl::dispatchDidHandleOnloadEvents()
373 {
374     if (m_webFrame->client())
375         m_webFrame->client()->didHandleOnloadEvents(m_webFrame);
376 }
377
378 // Redirect Tracking
379 // =================
380 // We want to keep track of the chain of redirects that occur during page
381 // loading. There are two types of redirects, server redirects which are HTTP
382 // response codes, and client redirects which are document.location= and meta
383 // refreshes.
384 //
385 // This outlines the callbacks that we get in different redirect situations,
386 // and how each call modifies the redirect chain.
387 //
388 // Normal page load
389 // ----------------
390 //   dispatchDidStartProvisionalLoad() -> adds URL to the redirect list
391 //   dispatchDidCommitLoad()           -> DISPATCHES & clears list
392 //
393 // Server redirect (success)
394 // -------------------------
395 //   dispatchDidStartProvisionalLoad()                    -> adds source URL
396 //   dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL
397 //   dispatchDidCommitLoad()                              -> DISPATCHES
398 //
399 // Client redirect (success)
400 // -------------------------
401 //   (on page)
402 //   dispatchWillPerformClientRedirect() -> saves expected redirect
403 //   dispatchDidStartProvisionalLoad()   -> appends redirect source (since
404 //                                          it matches the expected redirect)
405 //                                          and the current page as the dest)
406 //   dispatchDidCancelClientRedirect()   -> clears expected redirect
407 //   dispatchDidCommitLoad()             -> DISPATCHES
408 //
409 // Client redirect (cancelled)
410 // (e.g meta-refresh trumped by manual doc.location change, or just cancelled
411 // because a link was clicked that requires the meta refresh to be rescheduled
412 // (the SOURCE URL may have changed).
413 // ---------------------------
414 //   dispatchDidCancelClientRedirect()                 -> clears expected redirect
415 //   dispatchDidStartProvisionalLoad()                 -> adds only URL to redirect list
416 //   dispatchDidCommitLoad()                           -> DISPATCHES & clears list
417 //   rescheduled ? dispatchWillPerformClientRedirect() -> saves expected redirect
418 //               : nothing
419
420 // Client redirect (failure)
421 // -------------------------
422 //   (on page)
423 //   dispatchWillPerformClientRedirect() -> saves expected redirect
424 //   dispatchDidStartProvisionalLoad()   -> appends redirect source (since
425 //                                          it matches the expected redirect)
426 //                                          and the current page as the dest)
427 //   dispatchDidCancelClientRedirect()
428 //   dispatchDidFailProvisionalLoad()
429 //
430 // Load 1 -> Server redirect to 2 -> client redirect to 3 -> server redirect to 4
431 // ------------------------------------------------------------------------------
432 //   dispatchDidStartProvisionalLoad()                    -> adds source URL 1
433 //   dispatchDidReceiveServerRedirectForProvisionalLoad() -> adds dest URL 2
434 //   dispatchDidCommitLoad()                              -> DISPATCHES 1+2
435 //    -- begin client redirect and NEW DATA SOURCE
436 //   dispatchWillPerformClientRedirect()                  -> saves expected redirect
437 //   dispatchDidStartProvisionalLoad()                    -> appends URL 2 and URL 3
438 //   dispatchDidReceiveServerRedirectForProvisionalLoad() -> appends destination URL 4
439 //   dispatchDidCancelClientRedirect()                    -> clears expected redirect
440 //   dispatchDidCommitLoad()                              -> DISPATCHES
441 //
442 // Interesting case with multiple location changes involving anchors.
443 // Load page 1 containing future client-redirect (back to 1, e.g meta refresh) > Click
444 // on a link back to the same page (i.e an anchor href) >
445 // client-redirect finally fires (with new source, set to 1#anchor)
446 // -----------------------------------------------------------------------------
447 //   dispatchWillPerformClientRedirect(non-zero 'interval' param) -> saves expected redirect
448 //   -- click on anchor href
449 //   dispatchDidCancelClientRedirect()                            -> clears expected redirect
450 //   dispatchDidStartProvisionalLoad()                            -> adds 1#anchor source
451 //   dispatchDidCommitLoad()                                      -> DISPATCHES 1#anchor
452 //   dispatchWillPerformClientRedirect()                          -> saves exp. source (1#anchor)
453 //   -- redirect timer fires
454 //   dispatchDidStartProvisionalLoad()                            -> appends 1#anchor (src) and 1 (dest)
455 //   dispatchDidCancelClientRedirect()                            -> clears expected redirect
456 //   dispatchDidCommitLoad()                                      -> DISPATCHES 1#anchor + 1
457 //
458 void FrameLoaderClientImpl::dispatchDidReceiveServerRedirectForProvisionalLoad()
459 {
460     WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl();
461     if (!ds) {
462         // Got a server redirect when there is no provisional DS!
463         ASSERT_NOT_REACHED();
464         return;
465     }
466
467     // The server redirect may have been blocked.
468     if (ds->request().isNull())
469         return;
470
471     // A provisional load should have started already, which should have put an
472     // entry in our redirect chain.
473     ASSERT(ds->hasRedirectChain());
474
475     // The URL of the destination is on the provisional data source. We also need
476     // to update the redirect chain to account for this addition (we do this
477     // before the callback so the callback can look at the redirect chain to see
478     // what happened).
479     ds->appendRedirect(ds->request().url());
480
481     if (m_webFrame->client())
482         m_webFrame->client()->didReceiveServerRedirectForProvisionalLoad(m_webFrame);
483 }
484
485 // Called on both success and failure of a client redirect.
486 void FrameLoaderClientImpl::dispatchDidCancelClientRedirect()
487 {
488     // No longer expecting a client redirect.
489     if (m_webFrame->client()) {
490         m_expectedClientRedirectSrc = KURL();
491         m_expectedClientRedirectDest = KURL();
492         m_webFrame->client()->didCancelClientRedirect(m_webFrame);
493     }
494
495     // No need to clear the redirect chain, since that data source has already
496     // been deleted by the time this function is called.
497 }
498
499 void FrameLoaderClientImpl::dispatchWillPerformClientRedirect(
500     const KURL& url,
501     double interval,
502     double fireDate)
503 {
504     // Tells dispatchDidStartProvisionalLoad that if it sees this item it is a
505     // redirect and the source item should be added as the start of the chain.
506     m_expectedClientRedirectSrc = m_webFrame->url();
507     m_expectedClientRedirectDest = url;
508
509     // FIXME: bug 1135512. Webkit does not properly notify us of cancelling
510     // http > file client redirects. Since the FrameLoader's policy is to never
511     // carry out such a navigation anyway, the best thing we can do for now to
512     // not get confused is ignore this notification.
513     if (m_expectedClientRedirectDest.isLocalFile()
514         && m_expectedClientRedirectSrc.protocolInHTTPFamily()) {
515         m_expectedClientRedirectSrc = KURL();
516         m_expectedClientRedirectDest = KURL();
517         return;
518     }
519
520     if (m_webFrame->client()) {
521         m_webFrame->client()->willPerformClientRedirect(
522             m_webFrame,
523             m_expectedClientRedirectSrc,
524             m_expectedClientRedirectDest,
525             static_cast<unsigned int>(interval),
526             static_cast<unsigned int>(fireDate));
527     }
528 }
529
530 void FrameLoaderClientImpl::dispatchDidChangeLocationWithinPage()
531 {
532     // Anchor fragment navigations are not normal loads, so we need to synthesize
533     // some events for our delegate.
534     WebViewImpl* webView = m_webFrame->viewImpl();
535     if (webView->client())
536         webView->client()->didStartLoading();
537
538     WebDataSourceImpl* ds = m_webFrame->dataSourceImpl();
539     ASSERT(ds);  // Should not be null when navigating to a reference fragment!
540     if (ds) {
541         KURL url = ds->request().url();
542         KURL chainEnd;
543         if (ds->hasRedirectChain()) {
544             chainEnd = ds->endOfRedirectChain();
545             ds->clearRedirectChain();
546         }
547
548         // Figure out if this location change is because of a JS-initiated
549         // client redirect (e.g onload/setTimeout document.location.href=).
550         // FIXME: (bugs 1085325, 1046841) We don't get proper redirect
551         // performed/cancelled notifications across anchor navigations, so the
552         // other redirect-tracking code in this class (see
553         // dispatch*ClientRedirect() and dispatchDidStartProvisionalLoad) is
554         // insufficient to catch and properly flag these transitions. Once a
555         // proper fix for this bug is identified and applied the following
556         // block may no longer be required.
557         bool wasClientRedirect =
558             (url == m_expectedClientRedirectDest && chainEnd == m_expectedClientRedirectSrc)
559             || !m_webFrame->isProcessingUserGesture();
560
561         if (wasClientRedirect) {
562             if (m_webFrame->client())
563                 m_webFrame->client()->didCompleteClientRedirect(m_webFrame, chainEnd);
564             ds->appendRedirect(chainEnd);
565             // Make sure we clear the expected redirect since we just effectively
566             // completed it.
567             m_expectedClientRedirectSrc = KURL();
568             m_expectedClientRedirectDest = KURL();
569         }
570
571         // Regardless of how we got here, we are navigating to a URL so we need to
572         // add it to the redirect chain.
573         ds->appendRedirect(url);
574     }
575
576     bool isNewNavigation;
577     webView->didCommitLoad(&isNewNavigation);
578     if (m_webFrame->client())
579         m_webFrame->client()->didChangeLocationWithinPage(m_webFrame, isNewNavigation);
580
581     if (webView->client())
582         webView->client()->didStopLoading();
583 }
584
585 void FrameLoaderClientImpl::dispatchWillClose()
586 {
587     if (m_webFrame->client())
588         m_webFrame->client()->willClose(m_webFrame);
589 }
590
591 void FrameLoaderClientImpl::dispatchDidReceiveIcon()
592 {
593     // The icon database is disabled, so this should never be called.
594     ASSERT_NOT_REACHED();
595 }
596
597 void FrameLoaderClientImpl::dispatchDidStartProvisionalLoad()
598 {
599     // In case a redirect occurs, we need this to be set so that the redirect
600     // handling code can tell where the redirect came from. Server redirects
601     // will occur on the provisional load, so we need to keep track of the most
602     // recent provisional load URL.
603     // See dispatchDidReceiveServerRedirectForProvisionalLoad.
604     WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl();
605     if (!ds) {
606         ASSERT_NOT_REACHED();
607         return;
608     }
609     KURL url = ds->request().url();
610
611     // Since the provisional load just started, we should have not gotten
612     // any redirects yet.
613     ASSERT(!ds->hasRedirectChain());
614
615     // If this load is what we expected from a client redirect, treat it as a
616     // redirect from that original page. The expected redirect urls will be
617     // cleared by DidCancelClientRedirect.
618     bool completingClientRedirect = false;
619     if (m_expectedClientRedirectSrc.isValid()) {
620         // m_expectedClientRedirectDest could be something like
621         // "javascript:history.go(-1)" thus we need to exclude url starts with
622         // "javascript:". See bug: 1080873
623         ASSERT(m_expectedClientRedirectDest.protocolIs("javascript")
624             || m_expectedClientRedirectDest == url);
625         ds->appendRedirect(m_expectedClientRedirectSrc);
626         completingClientRedirect = true;
627     }
628     ds->appendRedirect(url);
629
630     if (m_webFrame->client()) {
631         // Whatever information didCompleteClientRedirect contains should only
632         // be considered relevant until the next provisional load has started.
633         // So we first tell the client that the load started, and then tell it
634         // about the client redirect the load is responsible for completing.
635         m_webFrame->client()->didStartProvisionalLoad(m_webFrame);
636         if (completingClientRedirect) {
637             m_webFrame->client()->didCompleteClientRedirect(
638                 m_webFrame, m_expectedClientRedirectSrc);
639         }
640     }
641 }
642
643 void FrameLoaderClientImpl::dispatchDidReceiveTitle(const String& title)
644 {
645     if (m_webFrame->client())
646         m_webFrame->client()->didReceiveTitle(m_webFrame, title);
647 }
648
649 void FrameLoaderClientImpl::dispatchDidCommitLoad()
650 {
651     WebViewImpl* webview = m_webFrame->viewImpl();
652     bool isNewNavigation;
653     webview->didCommitLoad(&isNewNavigation);
654
655     if (m_webFrame->client())
656         m_webFrame->client()->didCommitProvisionalLoad(m_webFrame, isNewNavigation);
657
658     if (webview->devToolsAgentPrivate())
659         webview->devToolsAgentPrivate()->didCommitProvisionalLoad(m_webFrame, isNewNavigation);
660 }
661
662 void FrameLoaderClientImpl::dispatchDidFailProvisionalLoad(
663     const ResourceError& error)
664 {
665
666     // If a policy change occured, then we do not want to inform the plugin
667     // delegate.  See http://b/907789 for details.  FIXME: This means the
668     // plugin won't receive NPP_URLNotify, which seems like it could result in
669     // a memory leak in the plugin!!
670     if (error.domain() == internalErrorDomain
671         && error.errorCode() == PolicyChangeError) {
672         m_webFrame->didFail(cancelledError(error.failingURL()), true);
673         return;
674     }
675
676     OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver();
677     m_webFrame->didFail(error, true);
678     if (observer)
679         observer->didFailLoading(error);
680 }
681
682 void FrameLoaderClientImpl::dispatchDidFailLoad(const ResourceError& error)
683 {
684     OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver();
685     m_webFrame->didFail(error, false);
686     if (observer)
687         observer->didFailLoading(error);
688
689     // Don't clear the redirect chain, this will happen in the middle of client
690     // redirects, and we need the context. The chain will be cleared when the
691     // provisional load succeeds or fails, not the "real" one.
692 }
693
694 void FrameLoaderClientImpl::dispatchDidFinishLoad()
695 {
696     OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver();
697
698     if (m_webFrame->client())
699         m_webFrame->client()->didFinishLoad(m_webFrame);
700
701     if (observer)
702         observer->didFinishLoading();
703
704     // Don't clear the redirect chain, this will happen in the middle of client
705     // redirects, and we need the context. The chain will be cleared when the
706     // provisional load succeeds or fails, not the "real" one.
707 }
708
709 void FrameLoaderClientImpl::dispatchDidFirstLayout()
710 {
711 }
712
713 void FrameLoaderClientImpl::dispatchDidFirstVisuallyNonEmptyLayout()
714 {
715     // FIXME: called when webkit finished layout of a page that was visually non-empty.
716     // All resources have not necessarily finished loading.
717 }
718
719 Frame* FrameLoaderClientImpl::dispatchCreatePage()
720 {
721     struct WindowFeatures features;
722     Page* newPage = m_webFrame->frame()->page()->chrome()->createWindow(
723         m_webFrame->frame(), FrameLoadRequest(), features);
724
725     // Make sure that we have a valid disposition.  This should have been set in
726     // the preceeding call to dispatchDecidePolicyForNewWindowAction.
727     ASSERT(m_nextNavigationPolicy != WebNavigationPolicyIgnore);
728     WebNavigationPolicy policy = m_nextNavigationPolicy;
729     m_nextNavigationPolicy = WebNavigationPolicyIgnore;
730
731     // createWindow can return null (e.g., popup blocker denies the window).
732     if (!newPage)
733         return 0;
734
735     WebViewImpl::fromPage(newPage)->setInitialNavigationPolicy(policy);
736     return newPage->mainFrame();
737 }
738
739 void FrameLoaderClientImpl::dispatchShow()
740 {
741     WebViewImpl* webView = m_webFrame->viewImpl();
742     if (webView && webView->client())
743         webView->client()->show(webView->initialNavigationPolicy());
744 }
745
746 static bool shouldTreatAsAttachment(const ResourceResponse& response)
747 {
748     const String& contentDisposition =
749         response.httpHeaderField("Content-Disposition");
750     if (contentDisposition.isEmpty())
751         return false;
752
753     // Some broken sites just send
754     // Content-Disposition: ; filename="file"
755     // screen those out here.
756     if (contentDisposition.startsWith(";"))
757         return false;
758
759     if (contentDisposition.startsWith("inline", false))
760         return false;
761
762     // Some broken sites just send
763     // Content-Disposition: filename="file"
764     // without a disposition token... screen those out.
765     if (contentDisposition.startsWith("filename", false))
766         return false;
767
768     // Also in use is Content-Disposition: name="file"
769     if (contentDisposition.startsWith("name", false))
770         return false;
771
772     // We have a content-disposition of "attachment" or unknown.
773     // RFC 2183, section 2.8 says that an unknown disposition
774     // value should be treated as "attachment"
775     return true;
776 }
777
778 void FrameLoaderClientImpl::dispatchDecidePolicyForMIMEType(
779      FramePolicyFunction function,
780      const String& mimeType,
781      const ResourceRequest&)
782 {
783     const ResourceResponse& response =
784         m_webFrame->frame()->loader()->activeDocumentLoader()->response();
785
786     PolicyAction action;
787
788     int statusCode = response.httpStatusCode();
789     if (statusCode == 204 || statusCode == 205) {
790         // The server does not want us to replace the page contents.
791         action = PolicyIgnore;
792     } else if (shouldTreatAsAttachment(response)) {
793         // The server wants us to download instead of replacing the page contents.
794         // Downloading is handled by the embedder, but we still get the initial
795         // response so that we can ignore it and clean up properly.
796         action = PolicyIgnore;
797     } else if (!canShowMIMEType(mimeType)) {
798         // Make sure that we can actually handle this type internally.
799         action = PolicyIgnore;
800     } else {
801         // OK, we will render this page.
802         action = PolicyUse;
803     }
804
805     // NOTE: PolicyChangeError will be generated when action is not PolicyUse.
806     (m_webFrame->frame()->loader()->policyChecker()->*function)(action);
807 }
808
809 void FrameLoaderClientImpl::dispatchDecidePolicyForNewWindowAction(
810     FramePolicyFunction function,
811     const NavigationAction& action,
812     const ResourceRequest& request,
813     PassRefPtr<FormState> formState,
814     const String& frameName)
815 {
816     WebNavigationPolicy navigationPolicy;
817     if (!actionSpecifiesNavigationPolicy(action, &navigationPolicy))
818         navigationPolicy = WebNavigationPolicyNewForegroundTab;
819
820     PolicyAction policyAction;
821     if (navigationPolicy == WebNavigationPolicyDownload)
822         policyAction = PolicyDownload;
823     else {
824         policyAction = PolicyUse;
825
826         // Remember the disposition for when dispatchCreatePage is called.  It is
827         // unfortunate that WebCore does not provide us with any context when
828         // creating or showing the new window that would allow us to avoid having
829         // to keep this state.
830         m_nextNavigationPolicy = navigationPolicy;
831     }
832     (m_webFrame->frame()->loader()->policyChecker()->*function)(policyAction);
833 }
834
835 void FrameLoaderClientImpl::dispatchDecidePolicyForNavigationAction(
836     FramePolicyFunction function,
837     const NavigationAction& action,
838     const ResourceRequest& request,
839     PassRefPtr<FormState> formState) {
840     PolicyAction policyAction = PolicyIgnore;
841
842     // It is valid for this function to be invoked in code paths where the
843     // the webview is closed.
844     // The null check here is to fix a crash that seems strange
845     // (see - https://bugs.webkit.org/show_bug.cgi?id=23554).
846     if (m_webFrame->client() && !request.url().isNull()) {
847       WebNavigationPolicy navigationPolicy = WebNavigationPolicyCurrentTab;
848       actionSpecifiesNavigationPolicy(action, &navigationPolicy);
849
850       // Give the delegate a chance to change the navigation policy.
851       const WebDataSourceImpl* ds = m_webFrame->provisionalDataSourceImpl();
852       if (ds) {
853           KURL url = ds->request().url();
854           if (url.protocolIs(backForwardNavigationScheme)) {
855               handleBackForwardNavigation(url);
856               navigationPolicy = WebNavigationPolicyIgnore;
857           } else {
858               bool isRedirect = ds->hasRedirectChain();
859
860               WebNavigationType webnavType =
861                   WebDataSourceImpl::toWebNavigationType(action.type());
862
863               RefPtr<Node> node;
864               for (const Event* event = action.event(); event; event = event->underlyingEvent()) {
865                   if (event->isMouseEvent()) {
866                       const MouseEvent* mouseEvent =
867                           static_cast<const MouseEvent*>(event);
868                       node = m_webFrame->frame()->eventHandler()->hitTestResultAtPoint(
869                           mouseEvent->absoluteLocation(), false).innerNonSharedNode();
870                       break;
871                   }
872               }
873               WebNode originatingNode(node);
874
875               navigationPolicy = m_webFrame->client()->decidePolicyForNavigation(
876                   m_webFrame, ds->request(), webnavType, originatingNode,
877                   navigationPolicy, isRedirect);
878           }
879       }
880
881       if (navigationPolicy == WebNavigationPolicyCurrentTab)
882           policyAction = PolicyUse;
883       else if (navigationPolicy == WebNavigationPolicyDownload)
884           policyAction = PolicyDownload;
885       else {
886           if (navigationPolicy != WebNavigationPolicyIgnore) {
887               WrappedResourceRequest webreq(request);
888               m_webFrame->client()->loadURLExternally(m_webFrame, webreq, navigationPolicy);
889           }
890           policyAction = PolicyIgnore;
891       }
892     }
893
894     (m_webFrame->frame()->loader()->policyChecker()->*function)(policyAction);
895 }
896
897 void FrameLoaderClientImpl::cancelPolicyCheck()
898 {
899     // FIXME
900 }
901
902 void FrameLoaderClientImpl::dispatchUnableToImplementPolicy(const ResourceError& error)
903 {
904     m_webFrame->client()->unableToImplementPolicyWithError(m_webFrame, error);
905 }
906
907 void FrameLoaderClientImpl::dispatchWillSubmitForm(FramePolicyFunction function,
908     PassRefPtr<FormState> formState)
909 {
910     if (m_webFrame->client())
911         m_webFrame->client()->willSubmitForm(m_webFrame, WebFormElement(formState->form()));
912     (m_webFrame->frame()->loader()->policyChecker()->*function)(PolicyUse);
913 }
914
915 void FrameLoaderClientImpl::dispatchDidLoadMainResource(DocumentLoader*)
916 {
917     // FIXME
918 }
919
920 void FrameLoaderClientImpl::revertToProvisionalState(DocumentLoader*)
921 {
922     m_hasRepresentation = true;
923 }
924
925 void FrameLoaderClientImpl::setMainDocumentError(DocumentLoader*,
926                                                  const ResourceError& error)
927 {
928     if (m_pluginWidget.get()) {
929         if (m_sentInitialResponseToPlugin) {
930             m_pluginWidget->didFailLoading(error);
931             m_sentInitialResponseToPlugin = false;
932         }
933         m_pluginWidget = 0;
934     }
935 }
936
937 void FrameLoaderClientImpl::postProgressStartedNotification()
938 {
939     WebViewImpl* webview = m_webFrame->viewImpl();
940     if (webview && webview->client())
941         webview->client()->didStartLoading();
942 }
943
944 void FrameLoaderClientImpl::postProgressEstimateChangedNotification()
945 {
946     // FIXME
947 }
948
949 void FrameLoaderClientImpl::postProgressFinishedNotification()
950 {
951     // FIXME: why might the webview be null?  http://b/1234461
952     WebViewImpl* webview = m_webFrame->viewImpl();
953     if (webview && webview->client())
954         webview->client()->didStopLoading();
955 }
956
957 void FrameLoaderClientImpl::setMainFrameDocumentReady(bool ready)
958 {
959     // FIXME
960 }
961
962 // Creates a new connection and begins downloading from that (contrast this
963 // with |download|).
964 void FrameLoaderClientImpl::startDownload(const ResourceRequest& request)
965 {
966     if (m_webFrame->client()) {
967         WrappedResourceRequest webreq(request);
968         m_webFrame->client()->loadURLExternally(
969             m_webFrame, webreq, WebNavigationPolicyDownload);
970     }
971 }
972
973 void FrameLoaderClientImpl::willChangeTitle(DocumentLoader*)
974 {
975     // FIXME
976 }
977
978 void FrameLoaderClientImpl::didChangeTitle(DocumentLoader*)
979 {
980     // FIXME
981 }
982
983 // Called whenever data is received.
984 void FrameLoaderClientImpl::committedLoad(DocumentLoader* loader, const char* data, int length)
985 {
986     if (!m_pluginWidget.get()) {
987         if (m_webFrame->client()) {
988             bool preventDefault = false;
989             m_webFrame->client()->didReceiveDocumentData(m_webFrame, data, length, preventDefault);
990             if (!preventDefault)
991                 m_webFrame->commitDocumentData(data, length);
992         }
993     }
994
995     // If we are sending data to MediaDocument, we should stop here
996     // and cancel the request.
997     if (m_webFrame->frame()->document()
998         && m_webFrame->frame()->document()->isMediaDocument())
999         loader->cancelMainResourceLoad(pluginWillHandleLoadError(loader->response()));
1000
1001     // The plugin widget could have been created in the m_webFrame->DidReceiveData
1002     // function.
1003     if (m_pluginWidget.get()) {
1004         if (!m_sentInitialResponseToPlugin) {
1005             m_sentInitialResponseToPlugin = true;
1006             m_pluginWidget->didReceiveResponse(
1007                 m_webFrame->frame()->loader()->activeDocumentLoader()->response());
1008         }
1009         m_pluginWidget->didReceiveData(data, length);
1010     }
1011 }
1012
1013 void FrameLoaderClientImpl::finishedLoading(DocumentLoader* dl)
1014 {
1015     if (m_pluginWidget.get()) {
1016         m_pluginWidget->didFinishLoading();
1017         m_pluginWidget = 0;
1018         m_sentInitialResponseToPlugin = false;
1019     } else {
1020         // This is necessary to create an empty document. See bug 634004.
1021         // However, we only want to do this if makeRepresentation has been called, to
1022         // match the behavior on the Mac.
1023         if (m_hasRepresentation)
1024             dl->frameLoader()->setEncoding("", false);
1025     }
1026 }
1027
1028 void FrameLoaderClientImpl::updateGlobalHistory()
1029 {
1030 }
1031
1032 void FrameLoaderClientImpl::updateGlobalHistoryRedirectLinks()
1033 {
1034 }
1035
1036 bool FrameLoaderClientImpl::shouldGoToHistoryItem(HistoryItem*) const
1037 {
1038     // FIXME
1039     return true;
1040 }
1041
1042 void FrameLoaderClientImpl::didDisplayInsecureContent()
1043 {
1044     if (m_webFrame->client())
1045         m_webFrame->client()->didDisplayInsecureContent(m_webFrame);
1046 }
1047
1048 void FrameLoaderClientImpl::didRunInsecureContent(SecurityOrigin* origin)
1049 {
1050     if (m_webFrame->client())
1051         m_webFrame->client()->didRunInsecureContent(m_webFrame, WebSecurityOrigin(origin));
1052 }
1053
1054 ResourceError FrameLoaderClientImpl::blockedError(const ResourceRequest&)
1055 {
1056     // FIXME
1057     return ResourceError();
1058 }
1059
1060 ResourceError FrameLoaderClientImpl::cancelledError(const ResourceRequest& request)
1061 {
1062     if (!m_webFrame->client())
1063         return ResourceError();
1064
1065     return m_webFrame->client()->cancelledError(
1066         m_webFrame, WrappedResourceRequest(request));
1067 }
1068
1069 ResourceError FrameLoaderClientImpl::cannotShowURLError(const ResourceRequest& request)
1070 {
1071     if (!m_webFrame->client())
1072         return ResourceError();
1073
1074     return m_webFrame->client()->cannotHandleRequestError(
1075         m_webFrame, WrappedResourceRequest(request));
1076 }
1077
1078 ResourceError FrameLoaderClientImpl::interruptForPolicyChangeError(
1079     const ResourceRequest& request)
1080 {
1081     return ResourceError(internalErrorDomain, PolicyChangeError,
1082                          request.url().string(), String());
1083 }
1084
1085 ResourceError FrameLoaderClientImpl::cannotShowMIMETypeError(const ResourceResponse&)
1086 {
1087     // FIXME
1088     return ResourceError();
1089 }
1090
1091 ResourceError FrameLoaderClientImpl::fileDoesNotExistError(const ResourceResponse&)
1092 {
1093     // FIXME
1094     return ResourceError();
1095 }
1096
1097 ResourceError FrameLoaderClientImpl::pluginWillHandleLoadError(const ResourceResponse&)
1098 {
1099     // FIXME
1100     return ResourceError();
1101 }
1102
1103 bool FrameLoaderClientImpl::shouldFallBack(const ResourceError& error)
1104 {
1105     // This method is called when we fail to load the URL for an <object> tag
1106     // that has fallback content (child elements) and is being loaded as a frame.
1107     // The error parameter indicates the reason for the load failure.
1108     // We should let the fallback content load only if this wasn't a cancelled
1109     // request.
1110     // Note: The mac version also has a case for "WebKitErrorPluginWillHandleLoad"
1111     ResourceError c = cancelledError(ResourceRequest());
1112     return error.errorCode() != c.errorCode() || error.domain() != c.domain();
1113 }
1114
1115 bool FrameLoaderClientImpl::canHandleRequest(const ResourceRequest& request) const
1116 {
1117     return m_webFrame->client()->canHandleRequest(
1118         m_webFrame, WrappedResourceRequest(request));
1119 }
1120
1121 bool FrameLoaderClientImpl::canShowMIMEType(const String& mimeType) const
1122 {
1123     // This method is called to determine if the media type can be shown
1124     // "internally" (i.e. inside the browser) regardless of whether or not the
1125     // browser or a plugin is doing the rendering.
1126
1127     // mimeType strings are supposed to be ASCII, but if they are not for some
1128     // reason, then it just means that the mime type will fail all of these "is
1129     // supported" checks and go down the path of an unhandled mime type.
1130     if (webKitClient()->mimeRegistry()->supportsMIMEType(mimeType) == WebMimeRegistry::IsSupported)
1131         return true;
1132
1133     // If Chrome is started with the --disable-plugins switch, pluginData is null.
1134     PluginData* pluginData = m_webFrame->frame()->page()->pluginData();
1135
1136     // See if the type is handled by an installed plugin, if so, we can show it.
1137     // FIXME: (http://b/1085524) This is the place to stick a preference to
1138     //        disable full page plugins (optionally for certain types!)
1139     return !mimeType.isEmpty() && pluginData && pluginData->supportsMimeType(mimeType);
1140 }
1141
1142 bool FrameLoaderClientImpl::representationExistsForURLScheme(const String&) const
1143 {
1144     // FIXME
1145     return false;
1146 }
1147
1148 String FrameLoaderClientImpl::generatedMIMETypeForURLScheme(const String& scheme) const
1149 {
1150     // This appears to generate MIME types for protocol handlers that are handled
1151     // internally. The only place I can find in the WebKit code that uses this
1152     // function is WebView::registerViewClass, where it is used as part of the
1153     // process by which custom view classes for certain document representations
1154     // are registered.
1155     String mimeType("x-apple-web-kit/");
1156     mimeType.append(scheme.lower());
1157     return mimeType;
1158 }
1159
1160 void FrameLoaderClientImpl::frameLoadCompleted()
1161 {
1162     // FIXME: the mac port also conditionally calls setDrawsBackground:YES on
1163     // it's ScrollView here.
1164
1165     // This comment from the Mac port:
1166     // Note: Can be called multiple times.
1167     // Even if already complete, we might have set a previous item on a frame that
1168     // didn't do any data loading on the past transaction. Make sure to clear these out.
1169
1170     // FIXME: setPreviousHistoryItem() no longer exists. http://crbug.com/8566
1171     // m_webFrame->frame()->loader()->setPreviousHistoryItem(0);
1172 }
1173
1174 void FrameLoaderClientImpl::saveViewStateToItem(HistoryItem*)
1175 {
1176     // FIXME
1177 }
1178
1179 void FrameLoaderClientImpl::restoreViewState()
1180 {
1181     // FIXME: probably scrolls to last position when you go back or forward
1182 }
1183
1184 void FrameLoaderClientImpl::provisionalLoadStarted()
1185 {
1186     // FIXME: On mac, this does various caching stuff
1187 }
1188
1189 void FrameLoaderClientImpl::didFinishLoad()
1190 {
1191     OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver();
1192     if (observer)
1193         observer->didFinishLoading();
1194 }
1195
1196 void FrameLoaderClientImpl::prepareForDataSourceReplacement()
1197 {
1198     // FIXME
1199 }
1200
1201 PassRefPtr<DocumentLoader> FrameLoaderClientImpl::createDocumentLoader(
1202     const ResourceRequest& request,
1203     const SubstituteData& data)
1204 {
1205     RefPtr<WebDataSourceImpl> ds = WebDataSourceImpl::create(request, data);
1206     if (m_webFrame->client())
1207         m_webFrame->client()->didCreateDataSource(m_webFrame, ds.get());
1208     return ds.release();
1209 }
1210
1211 void FrameLoaderClientImpl::setTitle(const String& title, const KURL& url)
1212 {
1213     // FIXME: inform consumer of changes to the title.
1214 }
1215
1216 String FrameLoaderClientImpl::userAgent(const KURL& url)
1217 {
1218     return webKitClient()->userAgent(url);
1219 }
1220
1221 void FrameLoaderClientImpl::savePlatformDataToCachedFrame(CachedFrame*)
1222 {
1223     // The page cache should be disabled.
1224     ASSERT_NOT_REACHED();
1225 }
1226
1227 void FrameLoaderClientImpl::transitionToCommittedFromCachedFrame(CachedFrame*)
1228 {
1229     ASSERT_NOT_REACHED();
1230 }
1231
1232 // Called when the FrameLoader goes into a state in which a new page load
1233 // will occur.
1234 void FrameLoaderClientImpl::transitionToCommittedForNewPage()
1235 {
1236     makeDocumentView();
1237 }
1238
1239 bool FrameLoaderClientImpl::canCachePage() const
1240 {
1241     // Since we manage the cache, always report this page as non-cacheable to
1242     // FrameLoader.
1243     return false;
1244 }
1245
1246 // Downloading is handled in the browser process, not WebKit. If we get to this
1247 // point, our download detection code in the ResourceDispatcherHost is broken!
1248 void FrameLoaderClientImpl::download(ResourceHandle* handle,
1249                                      const ResourceRequest& request,
1250                                      const ResourceRequest& initialRequest,
1251                                      const ResourceResponse& response)
1252 {
1253     ASSERT_NOT_REACHED();
1254 }
1255
1256 PassRefPtr<Frame> FrameLoaderClientImpl::createFrame(
1257     const KURL& url,
1258     const String& name,
1259     HTMLFrameOwnerElement* ownerElement,
1260     const String& referrer,
1261     bool allowsScrolling,
1262     int marginWidth,
1263     int marginHeight)
1264 {
1265     FrameLoadRequest frameRequest(ResourceRequest(url, referrer), name);
1266     return m_webFrame->createChildFrame(frameRequest, ownerElement);
1267 }
1268
1269 PassRefPtr<Widget> FrameLoaderClientImpl::createPlugin(
1270     const IntSize& size, // FIXME: how do we use this?
1271     HTMLPlugInElement* element,
1272     const KURL& url,
1273     const Vector<String>& paramNames,
1274     const Vector<String>& paramValues,
1275     const String& mimeType,
1276     bool loadManually)
1277 {
1278 #if !PLATFORM(WIN_OS)
1279     // WebCore asks us to make a plugin even if we don't have a
1280     // registered handler, with a comment saying it's so we can display
1281     // the broken plugin icon.  In Chromium, we normally register a
1282     // fallback plugin handler that allows you to install a missing
1283     // plugin.  Since we don't yet have a default plugin handler, we
1284     // need to return null here rather than going through all the
1285     // plugin-creation IPCs only to discover we don't have a plugin
1286     // registered, which causes a crash.
1287     // FIXME: remove me once we have a default plugin.
1288     if (objectContentType(url, mimeType) != ObjectContentNetscapePlugin)
1289         return 0;
1290 #endif
1291
1292     if (!m_webFrame->client())
1293         return 0;
1294
1295     WebPluginParams params;
1296     params.url = url;
1297     params.mimeType = mimeType;
1298     params.attributeNames = paramNames;
1299     params.attributeValues = paramValues;
1300     params.loadManually = loadManually;
1301
1302     WebPlugin* webPlugin = m_webFrame->client()->createPlugin(m_webFrame, params);
1303     if (!webPlugin)
1304         return 0;
1305
1306     // The container takes ownership of the WebPlugin.
1307     RefPtr<WebPluginContainerImpl> container =
1308         WebPluginContainerImpl::create(element, webPlugin);
1309
1310     if (!webPlugin->initialize(container.get()))
1311         return 0;
1312
1313     // The element might have been removed during plugin initialization!
1314     if (!element->renderer())
1315         return 0;
1316
1317     return container;
1318 }
1319
1320 // This method gets called when a plugin is put in place of html content
1321 // (e.g., acrobat reader).
1322 void FrameLoaderClientImpl::redirectDataToPlugin(Widget* pluginWidget)
1323 {
1324     m_pluginWidget = static_cast<WebPluginContainerImpl*>(pluginWidget);
1325     ASSERT(m_pluginWidget.get());
1326 }
1327
1328 PassRefPtr<Widget> FrameLoaderClientImpl::createJavaAppletWidget(
1329     const IntSize& size,
1330     HTMLAppletElement* element,
1331     const KURL& /* baseURL */,
1332     const Vector<String>& paramNames,
1333     const Vector<String>& paramValues)
1334 {
1335     return createPlugin(size, element, KURL(), paramNames, paramValues,
1336         "application/x-java-applet", false);
1337 }
1338
1339 ObjectContentType FrameLoaderClientImpl::objectContentType(
1340     const KURL& url,
1341     const String& explicitMimeType)
1342 {
1343     // This code is based on Apple's implementation from
1344     // WebCoreSupport/WebFrameBridge.mm.
1345
1346     String mimeType = explicitMimeType;
1347     if (mimeType.isEmpty()) {
1348         // Try to guess the MIME type based off the extension.
1349         String filename = url.lastPathComponent();
1350         int extensionPos = filename.reverseFind('.');
1351         if (extensionPos >= 0)
1352             mimeType = MIMETypeRegistry::getMIMETypeForPath(url.path());
1353
1354         if (mimeType.isEmpty())
1355             return ObjectContentFrame;
1356     }
1357
1358     if (MIMETypeRegistry::isSupportedImageMIMEType(mimeType))
1359         return ObjectContentImage;
1360
1361     // If Chrome is started with the --disable-plugins switch, pluginData is 0.
1362     PluginData* pluginData = m_webFrame->frame()->page()->pluginData();
1363     if (pluginData && pluginData->supportsMimeType(mimeType))
1364         return ObjectContentNetscapePlugin;
1365
1366     if (MIMETypeRegistry::isSupportedNonImageMIMEType(mimeType))
1367         return ObjectContentFrame;
1368
1369     return ObjectContentNone;
1370 }
1371
1372 String FrameLoaderClientImpl::overrideMediaType() const
1373 {
1374     // FIXME
1375     return String();
1376 }
1377
1378 bool FrameLoaderClientImpl::actionSpecifiesNavigationPolicy(
1379     const NavigationAction& action,
1380     WebNavigationPolicy* policy)
1381 {
1382     if ((action.type() != NavigationTypeLinkClicked) || !action.event()->isMouseEvent())
1383         return false;
1384
1385     const MouseEvent* event = static_cast<const MouseEvent*>(action.event());
1386     return WebViewImpl::navigationPolicyFromMouseEvent(
1387         event->button(), event->ctrlKey(), event->shiftKey(), event->altKey(),
1388         event->metaKey(), policy);
1389 }
1390
1391 void FrameLoaderClientImpl::handleBackForwardNavigation(const KURL& url)
1392 {
1393     ASSERT(url.protocolIs(backForwardNavigationScheme));
1394
1395     bool ok;
1396     int offset = url.lastPathComponent().toIntStrict(&ok);
1397     if (!ok)
1398         return;
1399
1400     WebViewImpl* webview = m_webFrame->viewImpl();
1401     if (webview->client())
1402         webview->client()->navigateBackForwardSoon(offset);
1403 }
1404
1405 PassOwnPtr<WebPluginLoadObserver> FrameLoaderClientImpl::pluginLoadObserver()
1406 {
1407     WebDataSourceImpl* ds = WebDataSourceImpl::fromDocumentLoader(
1408         m_webFrame->frame()->loader()->activeDocumentLoader());
1409     return ds->releasePluginLoadObserver();
1410 }
1411
1412 } // namespace WebKit