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