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