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