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