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