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