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