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