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