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