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 83using namespace WebCore; 84 85namespace WebKit { 86 87// Domain for internal error codes. 88static 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. 92enum { 93 PolicyChangeError = -10000, 94}; 95 96FrameLoaderClientImpl::FrameLoaderClientImpl(WebFrameImpl* frame) 97 : m_webFrame(frame) 98 , m_hasRepresentation(false) 99 , m_sentInitialResponseToPlugin(false) 100 , m_nextNavigationPolicy(WebNavigationPolicyIgnore) 101{ 102} 103 104FrameLoaderClientImpl::~FrameLoaderClientImpl() 105{ 106} 107 108void 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 119void 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 129void FrameLoaderClientImpl::documentElementAvailable() 130{ 131 if (m_webFrame->client()) 132 m_webFrame->client()->didCreateDocumentElement(m_webFrame); 133} 134 135void FrameLoaderClientImpl::didCreateScriptContextForFrame() 136{ 137 if (m_webFrame->client()) 138 m_webFrame->client()->didCreateScriptContext(m_webFrame); 139} 140 141void FrameLoaderClientImpl::didDestroyScriptContextForFrame() 142{ 143 if (m_webFrame->client()) 144 m_webFrame->client()->didDestroyScriptContext(m_webFrame); 145} 146 147void FrameLoaderClientImpl::didCreateIsolatedScriptContext() 148{ 149 if (m_webFrame->client()) 150 m_webFrame->client()->didCreateIsolatedScriptContext(m_webFrame); 151} 152 153bool 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 161void FrameLoaderClientImpl::didPerformFirstNavigation() const 162{ 163} 164 165void FrameLoaderClientImpl::registerForIconNotification(bool) 166{ 167} 168 169void FrameLoaderClientImpl::didChangeScrollOffset() 170{ 171 if (m_webFrame->client()) 172 m_webFrame->client()->didChangeScrollOffset(m_webFrame); 173} 174 175bool 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 183bool 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 191bool 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 199void FrameLoaderClientImpl::didNotAllowScript() 200{ 201 if (m_webFrame->client()) 202 m_webFrame->client()->didNotAllowScript(m_webFrame); 203} 204 205void FrameLoaderClientImpl::didNotAllowPlugins() 206{ 207 if (m_webFrame->client()) 208 m_webFrame->client()->didNotAllowPlugins(m_webFrame); 209} 210 211bool FrameLoaderClientImpl::hasWebView() const 212{ 213 return m_webFrame->viewImpl(); 214} 215 216bool 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 224void FrameLoaderClientImpl::makeDocumentView() 225{ 226 m_webFrame->createFrameView(); 227} 228 229void FrameLoaderClientImpl::makeRepresentation(DocumentLoader*) 230{ 231 m_hasRepresentation = true; 232} 233 234void FrameLoaderClientImpl::forceLayout() 235{ 236 // FIXME 237} 238 239void FrameLoaderClientImpl::forceLayoutForNonHTML() 240{ 241 // FIXME 242} 243 244void FrameLoaderClientImpl::setCopiesOnScroll() 245{ 246 // FIXME 247} 248 249void FrameLoaderClientImpl::detachedFromParent2() 250{ 251 // Nothing to do here. 252} 253 254void 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. 278void 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. 298static 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 310void 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 342bool 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 358void FrameLoaderClientImpl::dispatchDidReceiveAuthenticationChallenge( 359 DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) 360{ 361 // FIXME 362} 363 364void FrameLoaderClientImpl::dispatchDidCancelAuthenticationChallenge( 365 DocumentLoader*, unsigned long identifier, const AuthenticationChallenge&) 366{ 367 // FIXME 368} 369 370void 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 380void FrameLoaderClientImpl::dispatchDidReceiveContentLength( 381 DocumentLoader* loader, 382 unsigned long identifier, 383 int dataLength) 384{ 385} 386 387// Called when a particular resource load completes 388void FrameLoaderClientImpl::dispatchDidFinishLoading(DocumentLoader* loader, 389 unsigned long identifier) 390{ 391 if (m_webFrame->client()) 392 m_webFrame->client()->didFinishResourceLoad(m_webFrame, identifier); 393} 394 395void 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 403void 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 413bool 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 428void 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// 514void 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. 542void 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 555void 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 586void 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 658void FrameLoaderClientImpl::dispatchDidChangeLocationWithinPage() 659{ 660 if (m_webFrame) 661 m_webFrame->client()->didChangeLocationWithinPage(m_webFrame); 662} 663 664void FrameLoaderClientImpl::dispatchDidPushStateWithinPage() 665{ 666 dispatchDidNavigateWithinPage(); 667} 668 669void FrameLoaderClientImpl::dispatchDidReplaceStateWithinPage() 670{ 671 dispatchDidNavigateWithinPage(); 672} 673 674void FrameLoaderClientImpl::dispatchDidPopStateWithinPage() 675{ 676 // Ignored since dispatchDidNavigateWithinPage was already called. 677} 678 679void FrameLoaderClientImpl::dispatchWillClose() 680{ 681 if (m_webFrame->client()) 682 m_webFrame->client()->willClose(m_webFrame); 683} 684 685void FrameLoaderClientImpl::dispatchDidReceiveIcon() 686{ 687 // The icon database is disabled, so this should never be called. 688 ASSERT_NOT_REACHED(); 689} 690 691void 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 745void 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 751void FrameLoaderClientImpl::dispatchDidChangeIcons() 752{ 753 if (m_webFrame->client()) 754 m_webFrame->client()->didChangeIcons(m_webFrame); 755} 756 757void 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 767void 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 787void 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 799void 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 814void FrameLoaderClientImpl::dispatchDidFirstLayout() 815{ 816 if (m_webFrame->client()) 817 m_webFrame->client()->didFirstLayout(m_webFrame); 818} 819 820void FrameLoaderClientImpl::dispatchDidFirstVisuallyNonEmptyLayout() 821{ 822 if (m_webFrame->client()) 823 m_webFrame->client()->didFirstVisuallyNonEmptyLayout(m_webFrame); 824} 825 826Frame* 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 847void FrameLoaderClientImpl::dispatchShow() 848{ 849 WebViewImpl* webView = m_webFrame->viewImpl(); 850 if (webView && webView->client()) 851 webView->client()->show(webView->initialNavigationPolicy()); 852} 853 854void 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 882void 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 908void 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 967void FrameLoaderClientImpl::cancelPolicyCheck() 968{ 969 // FIXME 970} 971 972void FrameLoaderClientImpl::dispatchUnableToImplementPolicy(const ResourceError& error) 973{ 974 m_webFrame->client()->unableToImplementPolicyWithError(m_webFrame, error); 975} 976 977void FrameLoaderClientImpl::dispatchWillSendSubmitEvent(HTMLFormElement* form) 978{ 979 if (m_webFrame->client()) 980 m_webFrame->client()->willSendSubmitEvent(m_webFrame, WebFormElement(form)); 981} 982 983void 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 991void FrameLoaderClientImpl::dispatchDidLoadMainResource(DocumentLoader*) 992{ 993 // FIXME 994} 995 996void FrameLoaderClientImpl::revertToProvisionalState(DocumentLoader*) 997{ 998 m_hasRepresentation = true; 999} 1000 1001void 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 1013void FrameLoaderClientImpl::postProgressStartedNotification() 1014{ 1015 WebViewImpl* webview = m_webFrame->viewImpl(); 1016 if (webview && webview->client()) 1017 webview->client()->didStartLoading(); 1018} 1019 1020void 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 1030void 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 1038void FrameLoaderClientImpl::setMainFrameDocumentReady(bool ready) 1039{ 1040 // FIXME 1041} 1042 1043// Creates a new connection and begins downloading from that (contrast this 1044// with |download|). 1045void 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 1054void FrameLoaderClientImpl::willChangeTitle(DocumentLoader*) 1055{ 1056 // FIXME 1057} 1058 1059void FrameLoaderClientImpl::didChangeTitle(DocumentLoader*) 1060{ 1061 // FIXME 1062} 1063 1064// Called whenever data is received. 1065void 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 1097void 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 1112void FrameLoaderClientImpl::updateGlobalHistory() 1113{ 1114} 1115 1116void FrameLoaderClientImpl::updateGlobalHistoryRedirectLinks() 1117{ 1118} 1119 1120bool 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 1144bool 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 1152void FrameLoaderClientImpl::dispatchDidAddBackForwardItem(HistoryItem*) const 1153{ 1154} 1155 1156void FrameLoaderClientImpl::dispatchDidRemoveBackForwardItem(HistoryItem*) const 1157{ 1158} 1159 1160void FrameLoaderClientImpl::dispatchDidChangeBackForwardIndex() const 1161{ 1162} 1163 1164void FrameLoaderClientImpl::didDisplayInsecureContent() 1165{ 1166 if (m_webFrame->client()) 1167 m_webFrame->client()->didDisplayInsecureContent(m_webFrame); 1168} 1169 1170void 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 1176ResourceError FrameLoaderClientImpl::blockedError(const ResourceRequest&) 1177{ 1178 // FIXME 1179 return ResourceError(); 1180} 1181 1182ResourceError 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 1191ResourceError 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 1200ResourceError FrameLoaderClientImpl::interruptForPolicyChangeError( 1201 const ResourceRequest& request) 1202{ 1203 return ResourceError(internalErrorDomain, PolicyChangeError, 1204 request.url().string(), String()); 1205} 1206 1207ResourceError FrameLoaderClientImpl::cannotShowMIMETypeError(const ResourceResponse&) 1208{ 1209 // FIXME 1210 return ResourceError(); 1211} 1212 1213ResourceError FrameLoaderClientImpl::fileDoesNotExistError(const ResourceResponse&) 1214{ 1215 // FIXME 1216 return ResourceError(); 1217} 1218 1219ResourceError FrameLoaderClientImpl::pluginWillHandleLoadError(const ResourceResponse&) 1220{ 1221 // FIXME 1222 return ResourceError(); 1223} 1224 1225bool 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 1237bool FrameLoaderClientImpl::canHandleRequest(const ResourceRequest& request) const 1238{ 1239 return m_webFrame->client()->canHandleRequest( 1240 m_webFrame, WrappedResourceRequest(request)); 1241} 1242 1243bool FrameLoaderClientImpl::canShowMIMETypeAsHTML(const String& MIMEType) const 1244{ 1245 notImplemented(); 1246 return false; 1247} 1248 1249bool 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 1270bool FrameLoaderClientImpl::representationExistsForURLScheme(const String&) const 1271{ 1272 // FIXME 1273 return false; 1274} 1275 1276String 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 1288void 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 1302void FrameLoaderClientImpl::saveViewStateToItem(HistoryItem*) 1303{ 1304 // FIXME 1305} 1306 1307void FrameLoaderClientImpl::restoreViewState() 1308{ 1309 // FIXME: probably scrolls to last position when you go back or forward 1310} 1311 1312void FrameLoaderClientImpl::provisionalLoadStarted() 1313{ 1314 // FIXME: On mac, this does various caching stuff 1315} 1316 1317void FrameLoaderClientImpl::didFinishLoad() 1318{ 1319 OwnPtr<WebPluginLoadObserver> observer = pluginLoadObserver(); 1320 if (observer) 1321 observer->didFinishLoading(); 1322} 1323 1324void FrameLoaderClientImpl::prepareForDataSourceReplacement() 1325{ 1326 // FIXME 1327} 1328 1329PassRefPtr<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 1339void FrameLoaderClientImpl::setTitle(const StringWithDirection& title, const KURL& url) 1340{ 1341 // FIXME: inform consumer of changes to the title. 1342} 1343 1344String FrameLoaderClientImpl::userAgent(const KURL& url) 1345{ 1346 return webKitClient()->userAgent(url); 1347} 1348 1349void FrameLoaderClientImpl::savePlatformDataToCachedFrame(CachedFrame*) 1350{ 1351 // The page cache should be disabled. 1352 ASSERT_NOT_REACHED(); 1353} 1354 1355void 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. 1362void FrameLoaderClientImpl::transitionToCommittedForNewPage() 1363{ 1364 makeDocumentView(); 1365} 1366 1367void FrameLoaderClientImpl::didSaveToPageCache() 1368{ 1369} 1370 1371void FrameLoaderClientImpl::didRestoreFromPageCache() 1372{ 1373} 1374 1375void FrameLoaderClientImpl::dispatchDidBecomeFrameset(bool) 1376{ 1377} 1378 1379bool 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! 1388void FrameLoaderClientImpl::download(ResourceHandle* handle, 1389 const ResourceRequest& request, 1390 const ResourceRequest& initialRequest, 1391 const ResourceResponse& response) 1392{ 1393 ASSERT_NOT_REACHED(); 1394} 1395 1396PassRefPtr<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 1410void 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 1423void 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 1432PassRefPtr<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). 1471void FrameLoaderClientImpl::redirectDataToPlugin(Widget* pluginWidget) 1472{ 1473 if (pluginWidget->isPluginContainer()) 1474 m_pluginWidget = static_cast<WebPluginContainerImpl*>(pluginWidget); 1475 ASSERT(m_pluginWidget.get()); 1476} 1477 1478PassRefPtr<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 1489ObjectContentType 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 1532String FrameLoaderClientImpl::overrideMediaType() const 1533{ 1534 // FIXME 1535 return String(); 1536} 1537 1538bool 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 1560PassOwnPtr<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 1573PassRefPtr<FrameNetworkingContext> FrameLoaderClientImpl::createNetworkingContext() 1574{ 1575 return FrameNetworkingContextImpl::create(m_webFrame->frame()); 1576} 1577 1578} // namespace WebKit 1579