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