OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. | |
3 * Copyright (C) 2007 Trolltech ASA | |
4 * | |
5 * Redistribution and use in source and binary forms, with or without | |
6 * modification, are permitted provided that the following conditions | |
7 * are met: | |
8 * | |
9 * 1. Redistributions of source code must retain the above copyright | |
10 * notice, this list of conditions and the following disclaimer. | |
11 * 2. Redistributions in binary form must reproduce the above copyright | |
12 * notice, this list of conditions and the following disclaimer in the | |
13 * documentation and/or other materials provided with the distribution. | |
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of | |
15 * its contributors may be used to endorse or promote products derived | |
16 * from this software without specific prior written permission. | |
17 * | |
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY | |
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | |
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | |
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY | |
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | |
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | |
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
28 */ | |
29 | |
30 #include "config.h" | |
31 #include "FrameLoader.h" | |
32 | |
33 #include "Archive.h" | |
34 #include "ArchiveFactory.h" | |
35 #include "CString.h" | |
36 #include "Cache.h" | |
37 #include "CachedPage.h" | |
38 #include "Chrome.h" | |
39 #include "DOMImplementation.h" | |
40 #include "DOMWindow.h" | |
41 #include "DocLoader.h" | |
42 #include "Document.h" | |
43 #include "DocumentLoader.h" | |
44 #include "Editor.h" | |
45 #include "EditorClient.h" | |
46 #include "Element.h" | |
47 #include "Event.h" | |
48 #include "EventNames.h" | |
49 #include "FloatRect.h" | |
50 #include "FormState.h" | |
51 #include "Frame.h" | |
52 #include "FrameLoadRequest.h" | |
53 #include "FrameLoaderClient.h" | |
54 #include "FramePrivate.h" | |
55 #include "FrameTree.h" | |
56 #include "FrameView.h" | |
57 #include "HTMLFormElement.h" | |
58 #include "HTMLFrameElement.h" | |
59 #include "HTMLNames.h" | |
60 #include "HTMLObjectElement.h" | |
61 #include "HTTPParsers.h" | |
62 #include "HistoryItem.h" | |
63 #include "IconDatabase.h" | |
64 #include "IconLoader.h" | |
65 #include "InspectorController.h" | |
66 #include "Logging.h" | |
67 #include "MIMETypeRegistry.h" | |
68 #include "MainResourceLoader.h" | |
69 #include "Page.h" | |
70 #include "PageCache.h" | |
71 #include "PageGroup.h" | |
72 #include "PluginData.h" | |
73 #include "ProgressTracker.h" | |
74 #include "RenderPart.h" | |
75 #include "RenderWidget.h" | |
76 #include "RenderView.h" | |
77 #include "ResourceHandle.h" | |
78 #include "ResourceRequest.h" | |
79 #include "SecurityOrigin.h" | |
80 #include "SegmentedString.h" | |
81 #include "Settings.h" | |
82 #include "SystemTime.h" | |
83 #include "TextResourceDecoder.h" | |
84 #include "WindowFeatures.h" | |
85 #include "XMLHttpRequest.h" | |
86 #include "XMLTokenizer.h" | |
87 #include "ScriptController.h" | |
88 | |
89 #if USE(JSC) | |
90 #include "JSDOMBinding.h" | |
91 #include <kjs/JSObject.h> | |
92 #endif | |
93 | |
94 #if ENABLE(OFFLINE_WEB_APPLICATIONS) | |
95 #include "ApplicationCache.h" | |
96 #include "ApplicationCacheResource.h" | |
97 #endif | |
98 | |
99 #if ENABLE(SVG) | |
100 #include "SVGDocument.h" | |
101 #include "SVGLocatable.h" | |
102 #include "SVGNames.h" | |
103 #include "SVGPreserveAspectRatio.h" | |
104 #include "SVGSVGElement.h" | |
105 #include "SVGViewElement.h" | |
106 #include "SVGViewSpec.h" | |
107 #endif | |
108 | |
109 namespace WebCore { | |
110 | |
111 #if ENABLE(SVG) | |
112 using namespace SVGNames; | |
113 #endif | |
114 using namespace HTMLNames; | |
115 using namespace EventNames; | |
116 | |
117 #if USE(LOW_BANDWIDTH_DISPLAY) | |
118 const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024; | |
119 #endif | |
120 | |
121 struct FormSubmission { | |
122 const char* action; | |
123 String url; | |
124 RefPtr<FormData> data; | |
125 String target; | |
126 String contentType; | |
127 String boundary; | |
128 RefPtr<Event> event; | |
129 | |
130 FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const
String& t, | |
131 const String& ct, const String& b, PassRefPtr<Event> e) | |
132 : action(a) | |
133 , url(u) | |
134 , data(d) | |
135 , target(t) | |
136 , contentType(ct) | |
137 , boundary(b) | |
138 , event(e) | |
139 { | |
140 } | |
141 }; | |
142 | |
143 struct ScheduledRedirection { | |
144 enum Type { redirection, locationChange, historyNavigation, locationChangeDu
ringLoad, reload }; | |
145 Type type; | |
146 double delay; | |
147 String url; | |
148 String referrer; | |
149 bool lockHistory; | |
150 bool wasUserGesture; | |
151 RefPtr<HistoryItem> historyItem; | |
152 | |
153 ScheduledRedirection(double redirectDelay, const String& redirectURL, bool r
edirectLockHistory, bool userGesture) | |
154 : type(redirection) | |
155 , delay(redirectDelay) | |
156 , url(redirectURL) | |
157 , lockHistory(redirectLockHistory) | |
158 , wasUserGesture(userGesture) | |
159 { | |
160 } | |
161 | |
162 ScheduledRedirection(Type locationChangeType, | |
163 const String& locationChangeURL, const String& locationChangeReferre
r, | |
164 bool locationChangeLockHistory, bool locationChangeWasUserGesture) | |
165 : type(locationChangeType) | |
166 , delay(0) | |
167 , url(locationChangeURL) | |
168 , referrer(locationChangeReferrer) | |
169 , lockHistory(locationChangeLockHistory) | |
170 , wasUserGesture(locationChangeWasUserGesture) | |
171 { | |
172 } | |
173 | |
174 explicit ScheduledRedirection(HistoryItem* item) | |
175 : type(historyNavigation) | |
176 , delay(0) | |
177 , lockHistory(false) | |
178 , wasUserGesture(false) | |
179 , historyItem(item) | |
180 { | |
181 } | |
182 }; | |
183 | |
184 static double storedTimeOfLastCompletedLoad; | |
185 static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoa
dsForLocalOnly; | |
186 | |
187 bool isBackForwardLoadType(FrameLoadType type) | |
188 { | |
189 switch (type) { | |
190 case FrameLoadTypeStandard: | |
191 case FrameLoadTypeReload: | |
192 case FrameLoadTypeReloadAllowingStaleData: | |
193 case FrameLoadTypeSame: | |
194 case FrameLoadTypeRedirectWithLockedHistory: | |
195 case FrameLoadTypeReplace: | |
196 return false; | |
197 case FrameLoadTypeBack: | |
198 case FrameLoadTypeForward: | |
199 case FrameLoadTypeIndexedBackForward: | |
200 return true; | |
201 } | |
202 ASSERT_NOT_REACHED(); | |
203 return false; | |
204 } | |
205 | |
206 static int numRequests(Document* document) | |
207 { | |
208 if (!document) | |
209 return 0; | |
210 | |
211 return document->docLoader()->requestCount(); | |
212 } | |
213 | |
214 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) | |
215 : m_frame(frame) | |
216 , m_client(client) | |
217 , m_state(FrameStateCommittedPage) | |
218 , m_loadType(FrameLoadTypeStandard) | |
219 , m_policyLoadType(FrameLoadTypeStandard) | |
220 , m_delegateIsHandlingProvisionalLoadError(false) | |
221 , m_delegateIsDecidingNavigationPolicy(false) | |
222 , m_delegateIsHandlingUnimplementablePolicy(false) | |
223 , m_firstLayoutDone(false) | |
224 , m_quickRedirectComing(false) | |
225 , m_sentRedirectNotification(false) | |
226 , m_inStopAllLoaders(false) | |
227 , m_navigationDuringLoad(false) | |
228 , m_cachePolicy(CachePolicyVerify) | |
229 , m_isExecutingJavaScriptFormAction(false) | |
230 , m_isRunningScript(false) | |
231 , m_didCallImplicitClose(false) | |
232 , m_wasUnloadEventEmitted(false) | |
233 , m_isComplete(false) | |
234 , m_isLoadingMainResource(false) | |
235 , m_firingUnloadEvents(false) | |
236 , m_cancellingWithLoadInProgress(false) | |
237 , m_needsClear(false) | |
238 , m_receivedData(false) | |
239 , m_encodingWasChosenByUser(false) | |
240 , m_containsPlugIns(false) | |
241 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired) | |
242 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired) | |
243 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired) | |
244 , m_opener(0) | |
245 , m_openedByDOM(false) | |
246 , m_creatingInitialEmptyDocument(false) | |
247 , m_isDisplayingInitialEmptyDocument(false) | |
248 , m_committedFirstRealDocumentLoad(false) | |
249 , m_didPerformFirstNavigation(false) | |
250 #ifndef NDEBUG | |
251 , m_didDispatchDidCommitLoad(false) | |
252 #endif | |
253 #if USE(LOW_BANDWIDTH_DISPLAY) | |
254 , m_useLowBandwidthDisplay(true) | |
255 , m_finishedParsingDuringLowBandwidthDisplay(false) | |
256 , m_needToSwitchOutLowBandwidthDisplay(false) | |
257 #endif | |
258 { | |
259 } | |
260 | |
261 FrameLoader::~FrameLoader() | |
262 { | |
263 setOpener(0); | |
264 | |
265 HashSet<Frame*>::iterator end = m_openedFrames.end(); | |
266 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it) | |
267 (*it)->loader()->m_opener = 0; | |
268 | |
269 m_client->frameLoaderDestroyed(); | |
270 } | |
271 | |
272 void FrameLoader::init() | |
273 { | |
274 // this somewhat odd set of steps is needed to give the frame an initial emp
ty document | |
275 m_isDisplayingInitialEmptyDocument = false; | |
276 m_creatingInitialEmptyDocument = true; | |
277 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(Strin
g("")), SubstituteData()).get()); | |
278 setProvisionalDocumentLoader(m_policyDocumentLoader.get()); | |
279 setState(FrameStateProvisional); | |
280 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html
", 0, String(), String())); | |
281 m_provisionalDocumentLoader->finishedLoading(); | |
282 begin(KURL(), false); | |
283 end(); | |
284 m_frame->document()->cancelParsing(); | |
285 m_creatingInitialEmptyDocument = false; | |
286 m_didCallImplicitClose = true; | |
287 } | |
288 | |
289 void FrameLoader::setDefersLoading(bool defers) | |
290 { | |
291 if (m_documentLoader) | |
292 m_documentLoader->setDefersLoading(defers); | |
293 if (m_provisionalDocumentLoader) | |
294 m_provisionalDocumentLoader->setDefersLoading(defers); | |
295 if (m_policyDocumentLoader) | |
296 m_policyDocumentLoader->setDefersLoading(defers); | |
297 } | |
298 | |
299 Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const F
rameLoadRequest& request, const WindowFeatures& features, bool& created) | |
300 { | |
301 ASSERT(!features.dialog || request.frameName().isEmpty()); | |
302 | |
303 if (!request.frameName().isEmpty() && request.frameName() != "_blank") { | |
304 Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.
frameName()); | |
305 if (frame && shouldAllowNavigation(frame)) { | |
306 if (!request.resourceRequest().url().isEmpty()) | |
307 frame->loader()->loadFrameRequestWithFormAndValues(request, fals
e, 0, 0, HashMap<String, String>()); | |
308 if (Page* page = frame->page()) | |
309 page->chrome()->focus(); | |
310 created = false; | |
311 return frame; | |
312 } | |
313 } | |
314 | |
315 // FIXME: Setting the referrer should be the caller's responsibility. | |
316 FrameLoadRequest requestWithReferrer = request; | |
317 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer); | |
318 | |
319 Page* oldPage = m_frame->page(); | |
320 if (!oldPage) | |
321 return 0; | |
322 | |
323 Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, f
eatures); | |
324 if (!page) | |
325 return 0; | |
326 | |
327 Frame* frame = page->mainFrame(); | |
328 if (request.frameName() != "_blank") | |
329 frame->tree()->setName(request.frameName()); | |
330 | |
331 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locat
ionBarVisible); | |
332 page->chrome()->setStatusbarVisible(features.statusBarVisible); | |
333 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible); | |
334 page->chrome()->setMenubarVisible(features.menuBarVisible); | |
335 page->chrome()->setResizable(features.resizable); | |
336 | |
337 // 'x' and 'y' specify the location of the window, while 'width' and 'height
' | |
338 // specify the size of the page. We can only resize the window, so | |
339 // adjust for the difference between the window size and the page size. | |
340 | |
341 FloatRect windowRect = page->chrome()->windowRect(); | |
342 FloatSize pageSize = page->chrome()->pageRect().size(); | |
343 if (features.xSet) | |
344 windowRect.setX(features.x); | |
345 if (features.ySet) | |
346 windowRect.setY(features.y); | |
347 if (features.widthSet) | |
348 windowRect.setWidth(features.width + (windowRect.width() - pageSize.widt
h())); | |
349 if (features.heightSet) | |
350 windowRect.setHeight(features.height + (windowRect.height() - pageSize.h
eight())); | |
351 page->chrome()->setWindowRect(windowRect); | |
352 | |
353 page->chrome()->show(); | |
354 | |
355 created = true; | |
356 return frame; | |
357 } | |
358 | |
359 bool FrameLoader::canHandleRequest(const ResourceRequest& request) | |
360 { | |
361 return m_client->canHandleRequest(request); | |
362 } | |
363 | |
364 void FrameLoader::changeLocation(const String& url, const String& referrer, bool
lockHistory, bool userGesture) | |
365 { | |
366 // http://b/1082089 | |
367 // Hack to prevent FMW in WebCore::FrameLoader::checkNavigationPolicy. | |
368 // Without this, if the frame's javascript onload handler removes the frame, | |
369 // then once control returns into FrameLoader::checkNavigationPolicy (from | |
370 // the call to m_client->dispatchDecidePolicyForNavigationAction()), | |
371 // 'this' has been deallocated and we trash memory. | |
372 RefPtr<Frame> protector(m_frame); | |
373 | |
374 changeLocation(completeURL(url), referrer, lockHistory, userGesture); | |
375 } | |
376 | |
377 | |
378 void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool l
ockHistory, bool userGesture) | |
379 { | |
380 ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) ||
(m_cachePolicy == CachePolicyRefresh) | |
381 ? ReloadIgnoringCacheData : UseProtocolCachePolicy; | |
382 ResourceRequest request(url, referrer, policy); | |
383 | |
384 if (executeIfJavaScriptURL(request.url(), userGesture)) | |
385 return; | |
386 | |
387 urlSelected(request, "_self", 0, lockHistory, userGesture); | |
388 } | |
389 | |
390 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, boo
l lockHistory) | |
391 { | |
392 FrameLoadRequest copy = request; | |
393 if (copy.resourceRequest().httpReferrer().isEmpty()) | |
394 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer); | |
395 | |
396 loadFrameRequestWithFormAndValues(copy, lockHistory, event, 0, HashMap<Strin
g, String>()); | |
397 } | |
398 | |
399 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _tar
get, Event* triggeringEvent, bool lockHistory, bool userGesture) | |
400 { | |
401 if (executeIfJavaScriptURL(request.url(), userGesture, false)) | |
402 return; | |
403 | |
404 String target = _target; | |
405 if (target.isEmpty() && m_frame->document()) | |
406 target = m_frame->document()->baseTarget(); | |
407 | |
408 FrameLoadRequest frameRequest(request, target); | |
409 | |
410 urlSelected(frameRequest, triggeringEvent, lockHistory); | |
411 } | |
412 | |
413 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String
& urlString, const AtomicString& frameName) | |
414 { | |
415 #if USE(LOW_BANDWIDTH_DISPLAY) | |
416 // don't create sub-frame during low bandwidth display | |
417 if (frame()->document()->inLowBandwidthDisplay()) { | |
418 m_needToSwitchOutLowBandwidthDisplay = true; | |
419 return false; | |
420 } | |
421 #endif | |
422 | |
423 // Support for <frame src="javascript:string"> | |
424 KURL scriptURL; | |
425 KURL url; | |
426 if (protocolIs(urlString, "javascript")) { | |
427 scriptURL = KURL(urlString); | |
428 url = blankURL(); | |
429 } else | |
430 url = completeURL(urlString); | |
431 | |
432 Frame* frame = ownerElement->contentFrame(); | |
433 if (frame) | |
434 frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer
, true, userGestureHint()); | |
435 else | |
436 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer); | |
437 | |
438 if (!frame) | |
439 return false; | |
440 | |
441 if (!scriptURL.isEmpty()) | |
442 frame->loader()->executeIfJavaScriptURL(scriptURL); | |
443 | |
444 return true; | |
445 } | |
446 | |
447 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL
& url, const String& name, const String& referrer) | |
448 { | |
449 bool allowsScrolling = true; | |
450 int marginWidth = -1; | |
451 int marginHeight = -1; | |
452 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag
)) { | |
453 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElemen
t); | |
454 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff; | |
455 marginWidth = o->getMarginWidth(); | |
456 marginHeight = o->getMarginHeight(); | |
457 } | |
458 | |
459 if (!canLoad(url, referrer)) { | |
460 FrameLoader::reportLocalLoadFailed(m_frame, url.string()); | |
461 return 0; | |
462 } | |
463 | |
464 bool hideReferrer = shouldHideReferrer(url, referrer); | |
465 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideRef
errer ? String() : referrer, | |
466 allowsScrolling, marginWidth, marginHei
ght); | |
467 | |
468 if (!frame) { | |
469 checkCallImplicitClose(); | |
470 return 0; | |
471 } | |
472 | |
473 frame->loader()->m_isComplete = false; | |
474 | |
475 RenderObject* renderer = ownerElement->renderer(); | |
476 FrameView* view = frame->view(); | |
477 if (renderer && renderer->isWidget() && view) | |
478 static_cast<RenderWidget*>(renderer)->setWidget(view); | |
479 | |
480 checkCallImplicitClose(); | |
481 | |
482 // In these cases, the synchronous load would have finished | |
483 // before we could connect the signals, so make sure to send the | |
484 // completed() signal for the child by hand | |
485 // FIXME: In this case the Frame will have finished loading before | |
486 // it's being added to the child list. It would be a good idea to | |
487 // create the child first, then invoke the loader separately. | |
488 if (url.isEmpty() || url == blankURL()) { | |
489 frame->loader()->completed(); | |
490 frame->loader()->checkCompleted(); | |
491 } | |
492 | |
493 return frame.get(); | |
494 } | |
495 | |
496 void FrameLoader::submitFormAgain() | |
497 { | |
498 if (m_isRunningScript) | |
499 return; | |
500 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release()); | |
501 if (form) | |
502 submitForm(form->action, form->url, form->data, form->target, | |
503 form->contentType, form->boundary, form->event.get()); | |
504 } | |
505 | |
506 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<F
ormData> formData, | |
507 const String& target, const String& contentType, const String& boundary, Eve
nt* event) | |
508 { | |
509 ASSERT(formData); | |
510 | |
511 if (!m_frame->page()) | |
512 return; | |
513 | |
514 KURL u = completeURL(url.isNull() ? "" : url); | |
515 // FIXME: Do we really need to special-case an empty URL? | |
516 // Would it be better to just go on with the form submisson and let the I/O
fail? | |
517 if (u.isEmpty()) | |
518 return; | |
519 | |
520 if (u.protocolIs("javascript")) { | |
521 m_isExecutingJavaScriptFormAction = true; | |
522 executeIfJavaScriptURL(u, false, false); | |
523 m_isExecutingJavaScriptFormAction = false; | |
524 return; | |
525 } | |
526 | |
527 if (m_isRunningScript) { | |
528 if (m_deferredFormSubmission) | |
529 return; | |
530 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, t
arget, | |
531 contentType, boundary, event)); | |
532 return; | |
533 } | |
534 | |
535 formData->generateFiles(m_frame->page()->chrome()->client()); | |
536 | |
537 FrameLoadRequest frameRequest; | |
538 | |
539 if (!m_outgoingReferrer.isEmpty()) | |
540 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer); | |
541 | |
542 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget
() : target); | |
543 | |
544 // Handle mailto: forms | |
545 bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto"); | |
546 if (isMailtoForm && strcmp(action, "GET") != 0) { | |
547 // Append body= for POST mailto, replace the whole query string for GET
one. | |
548 String body = formData->flattenToString(); | |
549 String query = u.query(); | |
550 if (!query.isEmpty()) | |
551 query.append('&'); | |
552 u.setQuery(query + body); | |
553 } | |
554 | |
555 if (strcmp(action, "GET") == 0) { | |
556 u.setQuery(formData->flattenToString()); | |
557 } else { | |
558 if (!isMailtoForm) | |
559 frameRequest.resourceRequest().setHTTPBody(formData.get()); | |
560 frameRequest.resourceRequest().setHTTPMethod("POST"); | |
561 | |
562 // construct some user headers if necessary | |
563 if (contentType.isNull() || contentType == "application/x-www-form-urlen
coded") | |
564 frameRequest.resourceRequest().setHTTPContentType(contentType); | |
565 else // contentType must be "multipart/form-data" | |
566 frameRequest.resourceRequest().setHTTPContentType(contentType + "; b
oundary=" + boundary); | |
567 } | |
568 | |
569 frameRequest.resourceRequest().setURL(u); | |
570 | |
571 submitForm(frameRequest, event); | |
572 } | |
573 | |
574 void FrameLoader::stopLoading(bool sendUnload) | |
575 { | |
576 if (m_frame->document() && m_frame->document()->tokenizer()) | |
577 m_frame->document()->tokenizer()->stopParsing(); | |
578 | |
579 if (sendUnload) { | |
580 if (m_frame->document()) { | |
581 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { | |
582 Node* currentFocusedNode = m_frame->document()->focusedNode(); | |
583 if (currentFocusedNode) | |
584 currentFocusedNode->aboutToUnload(); | |
585 setFiringUnloadEvents(true); | |
586 m_frame->document()->dispatchWindowEvent(unloadEvent, false, fal
se); | |
587 setFiringUnloadEvents(false); | |
588 if (m_frame->document()) | |
589 m_frame->document()->updateRendering(); | |
590 m_wasUnloadEventEmitted = true; | |
591 if (m_frame->eventHandler()->pendingFrameUnloadEventCount()) | |
592 m_frame->eventHandler()->clearPendingFrameUnloadEventCount()
; | |
593 if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount(
)) | |
594 m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventC
ount(); | |
595 } | |
596 } | |
597 if (m_frame->document() && !m_frame->document()->inPageCache()) | |
598 m_frame->document()->removeAllEventListenersFromAllNodes(); | |
599 } | |
600 | |
601 m_isComplete = true; // to avoid calling completed() in finishedParsing() (D
avid) | |
602 m_isLoadingMainResource = false; | |
603 m_didCallImplicitClose = true; // don't want that one either | |
604 m_cachePolicy = CachePolicyVerify; // Why here? | |
605 | |
606 if (m_frame->document() && m_frame->document()->parsing()) { | |
607 finishedParsing(); | |
608 m_frame->document()->setParsing(false); | |
609 } | |
610 | |
611 m_workingURL = KURL(); | |
612 | |
613 if (Document* doc = m_frame->document()) { | |
614 if (DocLoader* docLoader = doc->docLoader()) | |
615 cache()->loader()->cancelRequests(docLoader); | |
616 XMLHttpRequest::cancelRequests(doc); | |
617 #if ENABLE(DATABASE) | |
618 #endif | |
619 } | |
620 | |
621 // tell all subframes to stop as well | |
622 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
623 child->loader()->stopLoading(sendUnload); | |
624 | |
625 cancelRedirection(); | |
626 | |
627 #if USE(LOW_BANDWIDTH_DISPLAY) | |
628 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) { | |
629 // Since loading is forced to stop, reset the state without really switc
hing. | |
630 m_needToSwitchOutLowBandwidthDisplay = false; | |
631 switchOutLowBandwidthDisplayIfReady(); | |
632 } | |
633 #endif | |
634 } | |
635 | |
636 void FrameLoader::stop() | |
637 { | |
638 // http://bugs.webkit.org/show_bug.cgi?id=10854 | |
639 // The frame's last ref may be removed and it will be deleted by checkComple
ted(). | |
640 RefPtr<Frame> protector(m_frame); | |
641 | |
642 if (m_frame->document()) { | |
643 if (m_frame->document()->tokenizer()) | |
644 m_frame->document()->tokenizer()->stopParsing(); | |
645 m_frame->document()->finishParsing(); | |
646 } else | |
647 // WebKit partially uses WebCore when loading non-HTML docs. In these c
ases doc==nil, but | |
648 // WebCore is enough involved that we need to checkCompleted() in order
for m_bComplete to | |
649 // become true. An example is when a subframe is a pure text doc, and th
at subframe is the | |
650 // last one to complete. | |
651 checkCompleted(); | |
652 if (m_iconLoader) | |
653 m_iconLoader->stopLoading(); | |
654 } | |
655 | |
656 bool FrameLoader::closeURL() | |
657 { | |
658 saveDocumentState(); | |
659 stopLoading(true); | |
660 m_frame->editor()->clearUndoRedoOperations(); | |
661 return true; | |
662 } | |
663 | |
664 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress) | |
665 { | |
666 m_cancellingWithLoadInProgress = cancelWithLoadInProgress; | |
667 | |
668 stopRedirectionTimer(); | |
669 | |
670 m_scheduledRedirection.clear(); | |
671 } | |
672 | |
673 KURL FrameLoader::iconURL() | |
674 { | |
675 // If this isn't a top level frame, return nothing | |
676 if (m_frame->tree() && m_frame->tree()->parent()) | |
677 return KURL(); | |
678 | |
679 // If we have an iconURL from a Link element, return that | |
680 if (m_frame->document() && !m_frame->document()->iconURL().isEmpty()) | |
681 return KURL(m_frame->document()->iconURL()); | |
682 | |
683 // Don't return a favicon iconURL unless we're http or https | |
684 if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https")) | |
685 return KURL(); | |
686 | |
687 KURL url; | |
688 url.setProtocol(m_URL.protocol()); | |
689 url.setHost(m_URL.host()); | |
690 if (int port = m_URL.port()) | |
691 url.setPort(port); | |
692 url.setPath("/favicon.ico"); | |
693 return url; | |
694 } | |
695 | |
696 bool FrameLoader::didOpenURL(const KURL& url) | |
697 { | |
698 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedir
ection::locationChangeDuringLoad) | |
699 // A redirect was scheduled before the document was created. | |
700 // This can happen when one frame changes another frame's location. | |
701 return false; | |
702 | |
703 cancelRedirection(); | |
704 m_frame->editor()->clearLastEditCommand(); | |
705 closeURL(); | |
706 | |
707 m_isComplete = false; | |
708 m_isLoadingMainResource = true; | |
709 m_didCallImplicitClose = false; | |
710 | |
711 m_frame->setJSStatusBarText(String()); | |
712 m_frame->setJSDefaultStatusBarText(String()); | |
713 | |
714 m_URL = url; | |
715 if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host()
.isEmpty() && m_URL.path().isEmpty()) | |
716 m_URL.setPath("/"); | |
717 m_workingURL = m_URL; | |
718 | |
719 started(); | |
720 | |
721 return true; | |
722 } | |
723 | |
724 void FrameLoader::didExplicitOpen() | |
725 { | |
726 m_isComplete = false; | |
727 m_didCallImplicitClose = false; | |
728 | |
729 // Calling document.open counts as committing the first real document load. | |
730 m_committedFirstRealDocumentLoad = true; | |
731 | |
732 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing
away results | |
733 // from a subsequent window.document.open / window.document.write call. | |
734 // Cancelling redirection here works for all cases because document.open | |
735 // implicitly precedes document.write. | |
736 cancelRedirection(); | |
737 if (m_frame->document()->url() != blankURL()) | |
738 m_URL = m_frame->document()->url(); | |
739 } | |
740 | |
741 bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool
replaceDocument) | |
742 { | |
743 if (!url.protocolIs("javascript")) | |
744 return false; | |
745 | |
746 String script = decodeURLEscapeSequences(url.string().substring(strlen("java
script:"))); | |
747 | |
748 bool succ; | |
749 String scriptResult = executeScript(script, &succ, userGesture); | |
750 if (!succ) return true; | |
751 | |
752 SecurityOrigin* currentSecurityOrigin = 0; | |
753 if (m_frame->document()) | |
754 currentSecurityOrigin = m_frame->document()->securityOrigin(); | |
755 | |
756 // FIXME: We should always replace the document, but doing so | |
757 // synchronously can cause crashes: | |
758 // http://bugs.webkit.org/show_bug.cgi?id=16782 | |
759 if (replaceDocument) { | |
760 begin(m_URL, true, currentSecurityOrigin); | |
761 write(scriptResult); | |
762 end(); | |
763 } | |
764 | |
765 return true; | |
766 } | |
767 | |
768 void FrameLoader::executeScript(const String& url, int baseLine, const String& s
cript) { | |
769 bool succ; | |
770 executeScript(url, baseLine, script, &succ); | |
771 } | |
772 | |
773 void FrameLoader::executeScript(const String& script, bool forceUserGesture) | |
774 { | |
775 bool succ; | |
776 executeScript(forceUserGesture ? String() : m_URL.string(), 0, script, &succ
); | |
777 } | |
778 | |
779 String FrameLoader::executeScript(const String& script, bool* succ, bool forceUs
erGesture) | |
780 { | |
781 return executeScript(forceUserGesture ? String() : m_URL.string(), 1, script
, succ); | |
782 } | |
783 | |
784 String FrameLoader::executeScript(const String& url, int baseLine, const String&
script, bool* succ) | |
785 { | |
786 *succ = false; | |
787 if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused()) | |
788 return String(); | |
789 | |
790 bool wasRunningScript = m_isRunningScript; | |
791 m_isRunningScript = true; | |
792 | |
793 String result = m_frame->script()->evaluate(url, baseLine, script, 0, succ); | |
794 | |
795 if (!wasRunningScript) { | |
796 m_isRunningScript = false; | |
797 submitFormAgain(); | |
798 Document::updateDocumentsRendering(); | |
799 } | |
800 | |
801 return result; | |
802 } | |
803 | |
804 void FrameLoader::cancelAndClear() | |
805 { | |
806 cancelRedirection(); | |
807 | |
808 if (!m_isComplete) | |
809 closeURL(); | |
810 | |
811 clear(false); | |
812 } | |
813 | |
814 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects) | |
815 { | |
816 // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_
bug.cgi?id=11212>, but putting it | |
817 // back causes a measurable performance regression which we will need to fix
to restore the correct behavior | |
818 // urlsBridgeKnowsAbout.clear(); | |
819 | |
820 m_frame->editor()->clear(); | |
821 | |
822 if (!m_needsClear) | |
823 return; | |
824 m_needsClear = false; | |
825 | |
826 if (m_frame->document() && !m_frame->document()->inPageCache()) { | |
827 m_frame->document()->cancelParsing(); | |
828 if (m_frame->document()->attached()) { | |
829 m_frame->document()->willRemove(); | |
830 m_frame->document()->detach(); | |
831 | |
832 m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document())
; | |
833 } | |
834 } | |
835 | |
836 // Do this after detaching the document so that the unload event works. | |
837 if (clearWindowProperties) { | |
838 m_frame->clearDOMWindow(); | |
839 m_frame->script()->clearWindowShell(); | |
840 } | |
841 | |
842 m_frame->selection()->clear(); | |
843 m_frame->eventHandler()->clear(); | |
844 if (m_frame->view()) | |
845 m_frame->view()->clear(); | |
846 | |
847 m_frame->setSelectionGranularity(CharacterGranularity); | |
848 | |
849 // Do not drop the document before the ScriptController and view are cleared | |
850 // as some destructors might still try to access the document. | |
851 m_frame->setDocument(0); | |
852 m_decoder = 0; | |
853 | |
854 m_containsPlugIns = false; | |
855 | |
856 if (clearScriptObjects) | |
857 m_frame->script()->clearScriptObjects(); | |
858 | |
859 m_redirectionTimer.stop(); | |
860 m_scheduledRedirection.clear(); | |
861 | |
862 m_checkCompletedTimer.stop(); | |
863 m_checkLoadCompleteTimer.stop(); | |
864 | |
865 m_receivedData = false; | |
866 m_isDisplayingInitialEmptyDocument = false; | |
867 | |
868 if (!m_encodingWasChosenByUser) | |
869 m_encoding = String(); | |
870 } | |
871 | |
872 void FrameLoader::receivedFirstData() | |
873 { | |
874 begin(m_workingURL, false); | |
875 | |
876 dispatchDidCommitLoad(); | |
877 dispatchWindowObjectAvailable(); | |
878 | |
879 String ptitle = m_documentLoader->title(); | |
880 // If we have a title let the WebView know about it. | |
881 if (!ptitle.isNull()) | |
882 m_client->dispatchDidReceiveTitle(ptitle); | |
883 | |
884 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); | |
885 m_workingURL = KURL(); | |
886 | |
887 double delay; | |
888 String url; | |
889 if (!m_documentLoader) | |
890 return; | |
891 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"
), false, delay, url)) | |
892 return; | |
893 | |
894 if (url.isEmpty()) | |
895 url = m_URL.string(); | |
896 else | |
897 url = m_frame->document()->completeURL(url).string(); | |
898 | |
899 scheduleHTTPRedirection(delay, url); | |
900 } | |
901 | |
902 const String& FrameLoader::responseMIMEType() const | |
903 { | |
904 return m_responseMIMEType; | |
905 } | |
906 | |
907 void FrameLoader::setResponseMIMEType(const String& type) | |
908 { | |
909 m_responseMIMEType = type; | |
910 } | |
911 | |
912 void FrameLoader::begin() | |
913 { | |
914 begin(KURL()); | |
915 } | |
916 | |
917 void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) | |
918 { | |
919 // We need to take a reference to the security origin because |clear| | |
920 // might destroy the document that owns it. | |
921 RefPtr<SecurityOrigin> forcedSecurityOrigin = origin; | |
922 | |
923 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->docum
ent() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url)); | |
924 clear(resetScripting, resetScripting); | |
925 if (dispatch) | |
926 dispatchWindowObjectAvailable(); | |
927 | |
928 m_needsClear = true; | |
929 m_isComplete = false; | |
930 m_didCallImplicitClose = false; | |
931 m_isLoadingMainResource = true; | |
932 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument; | |
933 | |
934 KURL ref(url); | |
935 ref.setUser(String()); | |
936 ref.setPass(String()); | |
937 ref.setRef(String()); | |
938 m_outgoingReferrer = ref.string(); | |
939 m_URL = url; | |
940 | |
941 RefPtr<Document> document = DOMImplementation::createDocument(m_responseMIME
Type, m_frame, m_frame->inViewSourceMode()); | |
942 m_frame->setDocument(document); | |
943 | |
944 document->setURL(m_URL); | |
945 if (m_decoder) | |
946 document->setDecoder(m_decoder.get()); | |
947 if (forcedSecurityOrigin) | |
948 document->setSecurityOrigin(forcedSecurityOrigin.get()); | |
949 | |
950 m_frame->domWindow()->setURL(document->url()); | |
951 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); | |
952 | |
953 updatePolicyBaseURL(); | |
954 | |
955 Settings* settings = document->settings(); | |
956 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAu
tomatically()); | |
957 | |
958 if (m_documentLoader) { | |
959 String dnsPrefetchControl = m_documentLoader->response().httpHeaderField
("X-DNS-Prefetch-Control"); | |
960 if (!dnsPrefetchControl.isEmpty()) | |
961 document->setDNSPrefetchControl(dnsPrefetchControl); | |
962 } | |
963 | |
964 #if FRAME_LOADS_USER_STYLESHEET | |
965 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL()
; | |
966 if (!userStyleSheet.isEmpty()) | |
967 m_frame->setUserStyleSheetLocation(userStyleSheet); | |
968 #endif | |
969 | |
970 restoreDocumentState(); | |
971 | |
972 document->implicitOpen(); | |
973 | |
974 if (m_frame->view()) | |
975 m_frame->view()->resizeContents(0, 0); | |
976 | |
977 #if USE(LOW_BANDWIDTH_DISPLAY) | |
978 // Low bandwidth display is a first pass display without external resources | |
979 // used to give an instant visual feedback. We currently only enable it for | |
980 // HTML documents in the top frame. | |
981 if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBand
widthDisplay) { | |
982 m_pendingSourceInLowBandwidthDisplay = String(); | |
983 m_finishedParsingDuringLowBandwidthDisplay = false; | |
984 m_needToSwitchOutLowBandwidthDisplay = false; | |
985 document->setLowBandwidthDisplay(true); | |
986 } | |
987 #endif | |
988 } | |
989 | |
990 void FrameLoader::write(const char* str, int len, bool flush) | |
991 { | |
992 if (len == 0 && !flush) | |
993 return; | |
994 | |
995 if (len == -1) | |
996 len = strlen(str); | |
997 | |
998 Tokenizer* tokenizer = m_frame->document()->tokenizer(); | |
999 if (tokenizer && tokenizer->wantsRawData()) { | |
1000 if (len > 0) | |
1001 tokenizer->writeRawData(str, len); | |
1002 return; | |
1003 } | |
1004 | |
1005 if (!m_decoder) { | |
1006 Settings* settings = m_frame->settings(); | |
1007 if (settings) { | |
1008 TextResourceDecoder* hintDecoder = NULL; | |
1009 Frame* parentFrame = m_frame->tree()->parent(); | |
1010 if (parentFrame && parentFrame->document()) | |
1011 hintDecoder = parentFrame->document()->decoder(); | |
1012 m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings
->defaultTextEncodingName(), settings->usesEncodingDetector(), hintDecoder); | |
1013 } else | |
1014 m_decoder = TextResourceDecoder::create(m_responseMIMEType, String()
); | |
1015 if (m_encoding.isEmpty()) { | |
1016 Frame* parentFrame = m_frame->tree()->parent(); | |
1017 // TODO(jungshik) : We might as well consider allowing inheriting ch
arset | |
1018 // from parent even if canAccess returns false as long as the parent
charset | |
1019 // is regarded as safe (that is, it's not UTF-7/ISO-2022-XX/HZ), of
which | |
1020 // we're not yet sure. | |
1021 if (parentFrame && parentFrame->document()->securityOrigin()->canAcc
ess(m_frame->document()->securityOrigin())) | |
1022 m_decoder->setEncoding(parentFrame->document()->inputEncoding(),
TextResourceDecoder::EncodingFromParentFrame); | |
1023 } else { | |
1024 m_decoder->setEncoding(m_encoding, | |
1025 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncod
ing : TextResourceDecoder::EncodingFromHTTPHeader); | |
1026 } | |
1027 m_frame->document()->setDecoder(m_decoder.get()); | |
1028 } | |
1029 | |
1030 String decoded = m_decoder->decode(str, len); | |
1031 if (flush) | |
1032 decoded += m_decoder->flush(); | |
1033 if (decoded.isEmpty()) | |
1034 return; | |
1035 | |
1036 #if USE(LOW_BANDWIDTH_DISPLAY) | |
1037 if (m_frame->document()->inLowBandwidthDisplay()) | |
1038 m_pendingSourceInLowBandwidthDisplay.append(decoded); | |
1039 else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady
() | |
1040 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); | |
1041 #endif | |
1042 | |
1043 if (!m_receivedData) { | |
1044 m_receivedData = true; | |
1045 if (m_decoder->encoding().usesVisualOrdering()) | |
1046 m_frame->document()->setVisuallyOrdered(); | |
1047 m_frame->document()->recalcStyle(Node::Force); | |
1048 } | |
1049 | |
1050 if (tokenizer) { | |
1051 ASSERT(!tokenizer->wantsRawData()); | |
1052 tokenizer->write(decoded, true); | |
1053 } | |
1054 } | |
1055 | |
1056 void FrameLoader::write(const String& str) | |
1057 { | |
1058 if (str.isNull()) | |
1059 return; | |
1060 | |
1061 if (!m_receivedData) { | |
1062 m_receivedData = true; | |
1063 m_frame->document()->setParseMode(Document::Strict); | |
1064 } | |
1065 | |
1066 if (Tokenizer* tokenizer = m_frame->document()->tokenizer()) | |
1067 tokenizer->write(str, true); | |
1068 } | |
1069 | |
1070 void FrameLoader::end() | |
1071 { | |
1072 m_isLoadingMainResource = false; | |
1073 endIfNotLoadingMainResource(); | |
1074 } | |
1075 | |
1076 void FrameLoader::endIfNotLoadingMainResource() | |
1077 { | |
1078 if (m_isLoadingMainResource || !m_frame->page()) | |
1079 return; | |
1080 | |
1081 // http://bugs.webkit.org/show_bug.cgi?id=10854 | |
1082 // The frame's last ref may be removed and it can be deleted by checkComplet
ed(), | |
1083 // so we'll add a protective refcount | |
1084 RefPtr<Frame> protector(m_frame); | |
1085 | |
1086 // make sure nothing's left in there | |
1087 if (m_frame->document()) { | |
1088 write(0, 0, true); | |
1089 m_frame->document()->finishParsing(); | |
1090 #if USE(LOW_BANDWIDTH_DISPLAY) | |
1091 if (m_frame->document()->inLowBandwidthDisplay()) { | |
1092 m_finishedParsingDuringLowBandwidthDisplay = true; | |
1093 switchOutLowBandwidthDisplayIfReady(); | |
1094 } | |
1095 #endif | |
1096 } else | |
1097 // WebKit partially uses WebCore when loading non-HTML docs. In these c
ases doc==nil, but | |
1098 // WebCore is enough involved that we need to checkCompleted() in order
for m_bComplete to | |
1099 // become true. An example is when a subframe is a pure text doc, and t
hat subframe is the | |
1100 // last one to complete. | |
1101 checkCompleted(); | |
1102 } | |
1103 | |
1104 void FrameLoader::iconLoadDecisionAvailable() | |
1105 { | |
1106 if (!m_mayLoadIconLater) | |
1107 return; | |
1108 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for
its icon", this); | |
1109 startIconLoader(); | |
1110 m_mayLoadIconLater = false; | |
1111 } | |
1112 | |
1113 void FrameLoader::startIconLoader() | |
1114 { | |
1115 // FIXME: We kick off the icon loader when the frame is done receiving its m
ain resource. | |
1116 // But we should instead do it when we're done parsing the head element. | |
1117 if (!isLoadingMainFrame()) | |
1118 return; | |
1119 | |
1120 if (!iconDatabase() || !iconDatabase()->isEnabled()) | |
1121 return; | |
1122 | |
1123 KURL url(iconURL()); | |
1124 String urlString(url.string()); | |
1125 if (urlString.isEmpty()) | |
1126 return; | |
1127 | |
1128 // If we're not reloading and the icon database doesn't say to load now then
bail before we actually start the load | |
1129 if (loadType() != FrameLoadTypeReload) { | |
1130 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlSt
ring, m_documentLoader.get()); | |
1131 if (decision == IconLoadNo) { | |
1132 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load
this icon, committing iconURL %s to database for pageURL mapping", urlString.as
cii().data()); | |
1133 commitIconURLToIconDatabase(url); | |
1134 | |
1135 // We were told not to load this icon - that means this icon is alre
ady known by the database | |
1136 // If the icon data hasn't been read in from disk yet, kick off the
read of the icon from the database to make sure someone | |
1137 // has done it. This is after registering for the notification so t
he WebView can call the appropriate delegate method. | |
1138 // Otherwise if the icon data *is* available, notify the delegate | |
1139 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) { | |
1140 LOG(IconDatabase, "Told not to load icon %s but icon data is not
yet available - registering for notification and requesting load from disk", ur
lString.ascii().data()); | |
1141 m_client->registerForIconNotification(); | |
1142 iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0)); | |
1143 iconDatabase()->iconForPageURL(originalRequestURL().string(), In
tSize(0, 0)); | |
1144 } else | |
1145 m_client->dispatchDidReceiveIcon(); | |
1146 | |
1147 return; | |
1148 } | |
1149 | |
1150 if (decision == IconLoadUnknown) { | |
1151 // In this case, we may end up loading the icon later, but we still
want to commit the icon url mapping to the database | |
1152 // just in case we don't end up loading later - if we commit the map
ping a second time after the load, that's no big deal | |
1153 // We also tell the client to register for the notification that the
icon is received now so it isn't missed in case the | |
1154 // icon is later read in from disk | |
1155 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, u
rlString.ascii().data()); | |
1156 m_mayLoadIconLater = true; | |
1157 m_client->registerForIconNotification(); | |
1158 commitIconURLToIconDatabase(url); | |
1159 return; | |
1160 } | |
1161 } | |
1162 | |
1163 // This is either a reload or the icon database said "yes, load the icon", s
o kick off the load! | |
1164 if (!m_iconLoader) | |
1165 m_iconLoader.set(IconLoader::create(m_frame).release()); | |
1166 | |
1167 m_iconLoader->startLoading(); | |
1168 } | |
1169 | |
1170 void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy) | |
1171 { | |
1172 localLoadPolicy = policy; | |
1173 } | |
1174 | |
1175 bool FrameLoader::restrictAccessToLocal() | |
1176 { | |
1177 return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll; | |
1178 } | |
1179 | |
1180 bool FrameLoader::allowSubstituteDataAccessToLocal() | |
1181 { | |
1182 return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly; | |
1183 } | |
1184 | |
1185 static HashSet<String, CaseFoldingHash>& localSchemes() | |
1186 { | |
1187 static HashSet<String, CaseFoldingHash> localSchemes; | |
1188 | |
1189 if (localSchemes.isEmpty()) { | |
1190 localSchemes.add("file"); | |
1191 localSchemes.add("chrome-resource"); | |
1192 #if PLATFORM(MAC) | |
1193 localSchemes.add("applewebdata"); | |
1194 #endif | |
1195 #if PLATFORM(QT) | |
1196 localSchemes.add("qrc"); | |
1197 #endif | |
1198 } | |
1199 | |
1200 return localSchemes; | |
1201 } | |
1202 | |
1203 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon) | |
1204 { | |
1205 ASSERT(iconDatabase()); | |
1206 LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s"
, icon.string().ascii().data(), m_URL.string().ascii().data(), originalRequestUR
L().string().ascii().data()); | |
1207 iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string()); | |
1208 iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().str
ing()); | |
1209 } | |
1210 | |
1211 void FrameLoader::restoreDocumentState() | |
1212 { | |
1213 Document* doc = m_frame->document(); | |
1214 if (!doc) | |
1215 return; | |
1216 | |
1217 HistoryItem* itemToRestore = 0; | |
1218 | |
1219 switch (loadType()) { | |
1220 case FrameLoadTypeReload: | |
1221 case FrameLoadTypeReloadAllowingStaleData: | |
1222 case FrameLoadTypeSame: | |
1223 case FrameLoadTypeReplace: | |
1224 break; | |
1225 case FrameLoadTypeBack: | |
1226 case FrameLoadTypeForward: | |
1227 case FrameLoadTypeIndexedBackForward: | |
1228 case FrameLoadTypeRedirectWithLockedHistory: | |
1229 case FrameLoadTypeStandard: | |
1230 itemToRestore = m_currentHistoryItem.get(); | |
1231 } | |
1232 | |
1233 if (!itemToRestore) | |
1234 return; | |
1235 | |
1236 doc->setStateForNewFormElements(itemToRestore->documentState()); | |
1237 } | |
1238 | |
1239 void FrameLoader::gotoAnchor() | |
1240 { | |
1241 // If our URL has no ref, then we have no place we need to jump to. | |
1242 // OTOH If CSS target was set previously, we want to set it to 0, recalc | |
1243 // and possibly repaint because :target pseudo class may have been | |
1244 // set (see bug 11321). | |
1245 if (!m_URL.hasRef() && !(m_frame->document() && m_frame->document()->getCSST
arget())) | |
1246 return; | |
1247 | |
1248 String ref = m_URL.ref(); | |
1249 if (gotoAnchor(ref)) | |
1250 return; | |
1251 | |
1252 // Try again after decoding the ref, based on the document's encoding. | |
1253 if (m_decoder) | |
1254 gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding())); | |
1255 } | |
1256 | |
1257 void FrameLoader::finishedParsing() | |
1258 { | |
1259 if (m_creatingInitialEmptyDocument) | |
1260 return; | |
1261 | |
1262 // This can be called from the Frame's destructor, in which case we shouldn'
t protect ourselves | |
1263 // because doing so will cause us to re-enter the destructor when protector
goes out of scope. | |
1264 // Null-checking the FrameView indicates whether or not we're in the destruc
tor. | |
1265 RefPtr<Frame> protector = m_frame->view() ? m_frame : 0; | |
1266 | |
1267 checkCompleted(); | |
1268 | |
1269 if (!m_frame->view()) | |
1270 return; // We are being destroyed by something checkCompleted called. | |
1271 | |
1272 // Check if the scrollbars are really needed for the content. | |
1273 // If not, remove them, relayout, and repaint. | |
1274 m_frame->view()->restoreScrollbar(); | |
1275 | |
1276 m_client->dispatchDidFinishDocumentLoad(); | |
1277 | |
1278 gotoAnchor(); | |
1279 } | |
1280 | |
1281 void FrameLoader::loadDone() | |
1282 { | |
1283 if (m_frame->document()) | |
1284 checkCompleted(); | |
1285 } | |
1286 | |
1287 void FrameLoader::checkCompleted() | |
1288 { | |
1289 // Any frame that hasn't completed yet? | |
1290 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
1291 if (!child->loader()->m_isComplete) | |
1292 return; | |
1293 | |
1294 // Have we completed before? | |
1295 if (m_isComplete) | |
1296 return; | |
1297 | |
1298 // Are we still parsing? | |
1299 if (m_frame->document() && m_frame->document()->parsing()) | |
1300 return; | |
1301 | |
1302 // Still waiting for images/scripts? | |
1303 if (m_frame->document()) | |
1304 if (numRequests(m_frame->document())) | |
1305 return; | |
1306 | |
1307 #if USE(LOW_BANDWIDTH_DISPLAY) | |
1308 // as switch will be called, don't complete yet | |
1309 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay() && m
_needToSwitchOutLowBandwidthDisplay) | |
1310 return; | |
1311 #endif | |
1312 | |
1313 // OK, completed. | |
1314 m_isComplete = true; | |
1315 | |
1316 RefPtr<Frame> protect(m_frame); | |
1317 checkCallImplicitClose(); // if we didn't do it before | |
1318 | |
1319 // Do not start a redirection timer for subframes here. | |
1320 // That is deferred until the parent is completed. | |
1321 if (m_scheduledRedirection && !m_frame->tree()->parent()) | |
1322 startRedirectionTimer(); | |
1323 | |
1324 completed(); | |
1325 if (m_frame->page()) | |
1326 checkLoadComplete(); | |
1327 } | |
1328 | |
1329 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*) | |
1330 { | |
1331 checkCompleted(); | |
1332 } | |
1333 | |
1334 void FrameLoader::scheduleCheckCompleted() | |
1335 { | |
1336 if (!m_checkCompletedTimer.isActive()) | |
1337 m_checkCompletedTimer.startOneShot(0); | |
1338 } | |
1339 | |
1340 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*) | |
1341 { | |
1342 if (!m_frame->page()) | |
1343 return; | |
1344 checkLoadComplete(); | |
1345 } | |
1346 | |
1347 void FrameLoader::scheduleCheckLoadComplete() | |
1348 { | |
1349 if (!m_checkLoadCompleteTimer.isActive()) | |
1350 m_checkLoadCompleteTimer.startOneShot(0); | |
1351 } | |
1352 | |
1353 void FrameLoader::checkCallImplicitClose() | |
1354 { | |
1355 if (m_didCallImplicitClose || !m_frame->document() || m_frame->document()->p
arsing()) | |
1356 return; | |
1357 | |
1358 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
1359 if (!child->loader()->m_isComplete) // still got a frame running -> too
early | |
1360 return; | |
1361 | |
1362 m_didCallImplicitClose = true; | |
1363 m_wasUnloadEventEmitted = false; | |
1364 if (m_frame->document()) | |
1365 m_frame->document()->implicitClose(); | |
1366 } | |
1367 | |
1368 KURL FrameLoader::baseURL() const | |
1369 { | |
1370 ASSERT(m_frame->document()); | |
1371 return m_frame->document()->baseURL(); | |
1372 } | |
1373 | |
1374 String FrameLoader::baseTarget() const | |
1375 { | |
1376 ASSERT(m_frame->document()); | |
1377 return m_frame->document()->baseTarget(); | |
1378 } | |
1379 | |
1380 KURL FrameLoader::completeURL(const String& url) | |
1381 { | |
1382 ASSERT(m_frame->document()); | |
1383 return m_frame->document()->completeURL(url); | |
1384 } | |
1385 | |
1386 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url) | |
1387 { | |
1388 if (delay < 0 || delay > INT_MAX / 1000) | |
1389 return; | |
1390 | |
1391 if (!m_frame->page()) | |
1392 return; | |
1393 | |
1394 // We want a new history item if the refresh timeout is > 1 second. | |
1395 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay) | |
1396 scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, fal
se)); | |
1397 } | |
1398 | |
1399 void FrameLoader::scheduleLocationChange(const String& url, const String& referr
er, bool lockHistory, bool wasUserGesture) | |
1400 { | |
1401 if (!m_frame->page()) | |
1402 return; | |
1403 | |
1404 // If the URL we're going to navigate to is the same as the current one, exc
ept for the | |
1405 // fragment part, we don't need to schedule the location change. | |
1406 KURL parsedURL(url); | |
1407 if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) { | |
1408 changeLocation(url, referrer, lockHistory, wasUserGesture); | |
1409 return; | |
1410 } | |
1411 | |
1412 // Handle a location change of a page with no document as a special case. | |
1413 // This may happen when a frame changes the location of another frame. | |
1414 bool duringLoad = !m_committedFirstRealDocumentLoad; | |
1415 | |
1416 // If a redirect was scheduled during a load, then stop the current load. | |
1417 // Otherwise when the current load transitions from a provisional to a | |
1418 // committed state, pending redirects may be cancelled. | |
1419 if (duringLoad) { | |
1420 if (m_provisionalDocumentLoader) | |
1421 m_provisionalDocumentLoader->stopLoading(); | |
1422 stopLoading(true); | |
1423 } | |
1424 | |
1425 ScheduledRedirection::Type type = duringLoad | |
1426 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection:
:locationChange; | |
1427 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistor
y, wasUserGesture)); | |
1428 } | |
1429 | |
1430 void FrameLoader::scheduleRefresh(bool wasUserGesture) | |
1431 { | |
1432 if (!m_frame->page()) | |
1433 return; | |
1434 | |
1435 // Handle a location change of a page with no document as a special case. | |
1436 // This may happen when a frame requests a refresh of another frame. | |
1437 bool duringLoad = !m_frame->document(); | |
1438 | |
1439 // If a refresh was scheduled during a load, then stop the current load. | |
1440 // Otherwise when the current load transitions from a provisional to a | |
1441 // committed state, pending redirects may be cancelled. | |
1442 if (duringLoad) | |
1443 stopLoading(true); | |
1444 | |
1445 ScheduledRedirection::Type type = duringLoad | |
1446 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection:
:locationChange; | |
1447 scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoin
gReferrer, true, wasUserGesture)); | |
1448 m_cachePolicy = CachePolicyRefresh; | |
1449 } | |
1450 | |
1451 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection) | |
1452 { | |
1453 switch (redirection.type) { | |
1454 case ScheduledRedirection::redirection: | |
1455 return false; | |
1456 case ScheduledRedirection::reload: | |
1457 case ScheduledRedirection::historyNavigation: | |
1458 case ScheduledRedirection::locationChange: | |
1459 case ScheduledRedirection::locationChangeDuringLoad: | |
1460 return true; | |
1461 } | |
1462 ASSERT_NOT_REACHED(); | |
1463 return false; | |
1464 } | |
1465 | |
1466 void FrameLoader::scheduleHistoryNavigation(int steps) | |
1467 { | |
1468 if (!m_frame->page()) | |
1469 return; | |
1470 | |
1471 // navigation will always be allowed in the 0 steps case, which is OK becaus
e that's supposed to force a reload. | |
1472 if (!canGoBackOrForward(steps)) { | |
1473 cancelRedirection(); | |
1474 return; | |
1475 } | |
1476 | |
1477 if (steps == 0) { | |
1478 // Special case for go(0) from a frame -> reload only the frame | |
1479 scheduleRedirection(new ScheduledRedirection(ScheduledRedirection::reloa
d, String(), String(), false, false)); | |
1480 return; | |
1481 } | |
1482 | |
1483 Page* page = m_frame->page(); | |
1484 if (!page) | |
1485 return; | |
1486 BackForwardList* list = page->backForwardList(); | |
1487 if (!list) | |
1488 return; | |
1489 | |
1490 // Asynchronously loads the item at the given offset in the history. | |
1491 list->goToItemAtIndexAsync(steps); | |
1492 | |
1493 // The redirection will be handled elsewhere. | |
1494 cancelRedirection(); | |
1495 } | |
1496 | |
1497 // This is called by ContextMenuController, which is only used in test shell | |
1498 // and not Chrome. | |
1499 void FrameLoader::goBackOrForward(int distance) | |
1500 { | |
1501 if (distance == 0) | |
1502 return; | |
1503 | |
1504 Page* page = m_frame->page(); | |
1505 if (!page) | |
1506 return; | |
1507 BackForwardList* list = page->backForwardList(); | |
1508 if (!list) | |
1509 return; | |
1510 | |
1511 HistoryItem* item = list->itemAtIndex(distance); | |
1512 if (!item) { | |
1513 if (distance > 0) { | |
1514 int forwardListCount = list->forwardListCount(); | |
1515 if (forwardListCount > 0) | |
1516 item = list->itemAtIndex(forwardListCount); | |
1517 } else { | |
1518 int backListCount = list->backListCount(); | |
1519 if (backListCount > 0) | |
1520 item = list->itemAtIndex(-backListCount); | |
1521 } | |
1522 } | |
1523 | |
1524 ASSERT(item); // we should not reach this line with an empty back/forward li
st | |
1525 if (item) | |
1526 page->goToItem(item, FrameLoadTypeIndexedBackForward); | |
1527 } | |
1528 | |
1529 void FrameLoader::goToHistoryItem(HistoryItem* item) | |
1530 { | |
1531 Page* page = m_frame->page(); | |
1532 if (!page) | |
1533 return; | |
1534 | |
1535 page->goToItem(item, FrameLoadTypeIndexedBackForward); | |
1536 } | |
1537 | |
1538 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*) | |
1539 { | |
1540 ASSERT(m_frame->page()); | |
1541 | |
1542 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release()); | |
1543 | |
1544 switch (redirection->type) { | |
1545 case ScheduledRedirection::redirection: | |
1546 case ScheduledRedirection::locationChange: | |
1547 case ScheduledRedirection::locationChangeDuringLoad: | |
1548 changeLocation(redirection->url, redirection->referrer, | |
1549 redirection->lockHistory, redirection->wasUserGesture); | |
1550 return; | |
1551 case ScheduledRedirection::reload: | |
1552 urlSelected(m_URL, "", 0, false, false); | |
1553 return; | |
1554 case ScheduledRedirection::historyNavigation: | |
1555 goToHistoryItem(redirection->historyItem.get()); | |
1556 return; | |
1557 } | |
1558 | |
1559 ASSERT_NOT_REACHED(); | |
1560 } | |
1561 | |
1562 /* | |
1563 In the case of saving state about a page with frames, we store a tree of ite
ms that mirrors the frame tree. | |
1564 The item that was the target of the user's navigation is designated as the "
targetItem". | |
1565 When this method is called with doClip=YES we're able to create the whole tr
ee except for the target's children, | |
1566 which will be loaded in the future. That part of the tree will be filled ou
t as the child loads are committed. | |
1567 */ | |
1568 void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer,
Frame* childFrame) | |
1569 { | |
1570 ASSERT(childFrame); | |
1571 HistoryItem* parentItem = currentHistoryItem(); | |
1572 FrameLoadType loadType = this->loadType(); | |
1573 FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory; | |
1574 | |
1575 KURL workingURL = url; | |
1576 | |
1577 // If we're moving in the backforward list, we might want to replace the con
tent | |
1578 // of this child frame with whatever was there at that point. | |
1579 // Reload will maintain the frame contents, LoadSame will not. | |
1580 if (parentItem && parentItem->children().size() && | |
1581 (isBackForwardLoadType(loadType) || loadType == FrameLoadTypeReloadAllow
ingStaleData)) | |
1582 { | |
1583 HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree(
)->name()); | |
1584 if (childItem) { | |
1585 // Use the original URL to ensure we get all the side-effects, such
as | |
1586 // onLoad handlers, of any redirects that happened. An example of wh
ere | |
1587 // this is needed is Radar 3213556. | |
1588 workingURL = KURL(childItem->originalURLString()); | |
1589 // These behaviors implied by these loadTypes should apply to the ch
ild frames | |
1590 childLoadType = loadType; | |
1591 | |
1592 if (isBackForwardLoadType(loadType)) { | |
1593 // For back/forward, remember this item so we can traverse any c
hild items as child frames load | |
1594 childFrame->loader()->setProvisionalHistoryItem(childItem); | |
1595 } else { | |
1596 // For reload, just reinstall the current item, since a new chil
d frame was created but we won't be creating a new BF item | |
1597 childFrame->loader()->setCurrentHistoryItem(childItem); | |
1598 } | |
1599 } | |
1600 } | |
1601 | |
1602 RefPtr<Archive> subframeArchive = activeDocumentLoader()->popArchiveForSubfr
ame(childFrame->tree()->name()); | |
1603 | |
1604 if (subframeArchive) | |
1605 childFrame->loader()->loadArchive(subframeArchive.release()); | |
1606 else | |
1607 childFrame->loader()->loadURL(workingURL, referer, String(), childLoadTy
pe, 0, 0); | |
1608 } | |
1609 | |
1610 void FrameLoader::loadArchive(PassRefPtr<Archive> prpArchive) | |
1611 { | |
1612 RefPtr<Archive> archive = prpArchive; | |
1613 | |
1614 ArchiveResource* mainResource = archive->mainResource(); | |
1615 ASSERT(mainResource); | |
1616 if (!mainResource) | |
1617 return; | |
1618 | |
1619 SubstituteData substituteData(mainResource->data(), mainResource->mimeType()
, mainResource->textEncoding(), KURL()); | |
1620 | |
1621 ResourceRequest request(mainResource->url()); | |
1622 #if PLATFORM(MAC) | |
1623 request.applyWebArchiveHackForMail(); | |
1624 #endif | |
1625 | |
1626 RefPtr<DocumentLoader> documentLoader = m_client->createDocumentLoader(reque
st, substituteData); | |
1627 documentLoader->addAllArchiveResources(archive.get()); | |
1628 load(documentLoader.get()); | |
1629 } | |
1630 | |
1631 String FrameLoader::encoding() const | |
1632 { | |
1633 if (m_encodingWasChosenByUser && !m_encoding.isEmpty()) | |
1634 return m_encoding; | |
1635 if (m_decoder && m_decoder->encoding().isValid()) | |
1636 return m_decoder->encoding().name(); | |
1637 Settings* settings = m_frame->settings(); | |
1638 return settings ? settings->defaultTextEncodingName() : String(); | |
1639 } | |
1640 | |
1641 bool FrameLoader::gotoAnchor(const String& name) | |
1642 { | |
1643 ASSERT(m_frame->document()); | |
1644 | |
1645 if (!m_frame->document()->haveStylesheetsLoaded()) { | |
1646 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true); | |
1647 return false; | |
1648 } | |
1649 | |
1650 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); | |
1651 | |
1652 Node* anchorNode = m_frame->document()->getElementById(AtomicString(name)); | |
1653 if (!anchorNode && !name.isEmpty()) | |
1654 anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->d
ocument()->inCompatMode()); | |
1655 | |
1656 #if ENABLE(SVG) | |
1657 if (m_frame->document()->isSVGDocument()) { | |
1658 if (name.startsWith("xpointer(")) { | |
1659 // We need to parse the xpointer reference here | |
1660 } else if (name.startsWith("svgView(")) { | |
1661 RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->docum
ent())->rootElement(); | |
1662 if (!svg->currentView()->parseViewSpec(name)) | |
1663 return false; | |
1664 svg->setUseCurrentView(true); | |
1665 } else { | |
1666 if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) { | |
1667 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGN
ames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0; | |
1668 if (viewElement.get()) { | |
1669 RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGL
ocatable::nearestViewportElement(viewElement.get())); | |
1670 svg->inheritViewAttributes(viewElement.get()); | |
1671 } | |
1672 } | |
1673 } | |
1674 // FIXME: need to decide which <svg> to focus on, and zoom to that one | |
1675 // FIXME: need to actually "highlight" the viewTarget(s) | |
1676 } | |
1677 #endif | |
1678 | |
1679 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear
the current target. | |
1680 | |
1681 // Implement the rule that "" and "top" both mean top of page as in other br
owsers. | |
1682 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) | |
1683 return false; | |
1684 | |
1685 // We need to update the layout before scrolling, otherwise we could | |
1686 // really mess things up if an anchor scroll comes at a bad moment. | |
1687 if (m_frame->document()) { | |
1688 m_frame->document()->updateRendering(); | |
1689 // Only do a layout if changes have occurred that make it necessary. | |
1690 if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRen
derer()->needsLayout()) | |
1691 m_frame->view()->layout(); | |
1692 } | |
1693 | |
1694 // Scroll nested layers and frames to reveal the anchor. | |
1695 // Align to the top and to the closest side (this matches other browsers). | |
1696 RenderObject* renderer; | |
1697 IntRect rect; | |
1698 if (!anchorNode) | |
1699 renderer = m_frame->document()->renderer(); // top of document | |
1700 else { | |
1701 renderer = anchorNode->renderer(); | |
1702 rect = anchorNode->getRect(); | |
1703 } | |
1704 if (renderer) | |
1705 renderer->enclosingLayer()->scrollRectToVisible(rect, true, RenderLayer:
:gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways); | |
1706 | |
1707 return true; | |
1708 } | |
1709 | |
1710 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const A
tomicString& frameName, | |
1711 const String& mimeType, const Vector<String>& paramNames, const Vector<Strin
g>& paramValues) | |
1712 { | |
1713 if (url.isEmpty() && mimeType.isEmpty()) | |
1714 return false; | |
1715 | |
1716 #if USE(LOW_BANDWIDTH_DISPLAY) | |
1717 // don't care object during low bandwidth display | |
1718 if (frame()->document()->inLowBandwidthDisplay()) { | |
1719 m_needToSwitchOutLowBandwidthDisplay = true; | |
1720 return false; | |
1721 } | |
1722 #endif | |
1723 | |
1724 KURL completedURL; | |
1725 if (!url.isEmpty()) | |
1726 completedURL = completeURL(url); | |
1727 | |
1728 bool useFallback; | |
1729 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(),
useFallback)) { | |
1730 Settings* settings = m_frame->settings(); | |
1731 if (!settings || !settings->arePluginsEnabled() || | |
1732 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMETyp
e(mimeType))) | |
1733 return false; | |
1734 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramVal
ues, useFallback); | |
1735 } | |
1736 | |
1737 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagNa
me(embedTag)); | |
1738 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node(
)); | |
1739 | |
1740 // FIXME: OK to always make a new frame? When does the old frame get removed
? | |
1741 return loadSubframe(element, completedURL, frameName, m_outgoingReferrer); | |
1742 } | |
1743 | |
1744 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool
hasFallback, bool& useFallback) | |
1745 { | |
1746 if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif"
|| mimeType == "image/x-tiff")) { | |
1747 String pluginName = m_frame->page()->pluginData()->pluginNameForMimeType
(mimeType); | |
1748 if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false)) | |
1749 return true; | |
1750 } | |
1751 | |
1752 ObjectContentType objectType = m_client->objectContentType(url, mimeType); | |
1753 // If an object's content can't be handled and it has no fallback, let | |
1754 // it be handled as a plugin to show the broken plugin icon. | |
1755 useFallback = objectType == ObjectContentNone && hasFallback; | |
1756 return objectType == ObjectContentNone || objectType == ObjectContentNetscap
ePlugin || objectType == ObjectContentOtherPlugin; | |
1757 } | |
1758 | |
1759 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String
& mimeType, | |
1760 const Vector<String>& paramNames, const Vector<String>& paramValues, bool us
eFallback) | |
1761 { | |
1762 Widget* widget = 0; | |
1763 | |
1764 if (renderer && !useFallback) { | |
1765 Element* pluginElement = 0; | |
1766 if (renderer->node() && renderer->node()->isElementNode()) | |
1767 pluginElement = static_cast<Element*>(renderer->node()); | |
1768 | |
1769 if (!canLoad(url, String(), frame()->document())) { | |
1770 FrameLoader::reportLocalLoadFailed(m_frame, url.string()); | |
1771 return false; | |
1772 } | |
1773 | |
1774 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), render
er->contentHeight()), | |
1775 pluginElement, url, paramNames, paramVal
ues, mimeType, | |
1776 m_frame->document()->isPluginDocument())
; | |
1777 if (widget) { | |
1778 renderer->setWidget(widget); | |
1779 m_containsPlugIns = true; | |
1780 } | |
1781 } | |
1782 | |
1783 return widget != 0; | |
1784 } | |
1785 | |
1786 void FrameLoader::clearRecordedFormValues() | |
1787 { | |
1788 m_formAboutToBeSubmitted = 0; | |
1789 m_formValuesAboutToBeSubmitted.clear(); | |
1790 } | |
1791 | |
1792 void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr<HTMLFormElement> element) | |
1793 { | |
1794 m_formAboutToBeSubmitted = element; | |
1795 } | |
1796 | |
1797 void FrameLoader::recordFormValue(const String& name, const String& value) | |
1798 { | |
1799 m_formValuesAboutToBeSubmitted.set(name, value); | |
1800 } | |
1801 | |
1802 void FrameLoader::parentCompleted() | |
1803 { | |
1804 if (m_scheduledRedirection && !m_redirectionTimer.isActive()) | |
1805 startRedirectionTimer(); | |
1806 } | |
1807 | |
1808 String FrameLoader::outgoingReferrer() const | |
1809 { | |
1810 return m_outgoingReferrer; | |
1811 } | |
1812 | |
1813 Frame* FrameLoader::opener() | |
1814 { | |
1815 return m_opener; | |
1816 } | |
1817 | |
1818 void FrameLoader::setOpener(Frame* opener) | |
1819 { | |
1820 if (m_opener) | |
1821 m_opener->loader()->m_openedFrames.remove(m_frame); | |
1822 if (opener) | |
1823 opener->loader()->m_openedFrames.add(m_frame); | |
1824 m_opener = opener; | |
1825 | |
1826 if (m_frame->document()) { | |
1827 m_frame->document()->initSecurityContext(); | |
1828 m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOri
gin()); | |
1829 } | |
1830 } | |
1831 | |
1832 bool FrameLoader::openedByDOM() const | |
1833 { | |
1834 return m_openedByDOM; | |
1835 } | |
1836 | |
1837 void FrameLoader::setOpenedByDOM() | |
1838 { | |
1839 m_openedByDOM = true; | |
1840 } | |
1841 | |
1842 void FrameLoader::handleFallbackContent() | |
1843 { | |
1844 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); | |
1845 if (!owner || !owner->hasTagName(objectTag)) | |
1846 return; | |
1847 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent(); | |
1848 } | |
1849 | |
1850 void FrameLoader::provisionalLoadStarted() | |
1851 { | |
1852 Page* page = m_frame->page(); | |
1853 | |
1854 // this is used to update the current history item | |
1855 // in the event of a navigation aytime during loading | |
1856 m_navigationDuringLoad = false; | |
1857 if (page) { | |
1858 Document *document = page->mainFrame()->document(); | |
1859 m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (
document && document->processingLoadEvent()); | |
1860 } | |
1861 | |
1862 m_firstLayoutDone = false; | |
1863 cancelRedirection(true); | |
1864 m_client->provisionalLoadStarted(); | |
1865 } | |
1866 | |
1867 bool FrameLoader::userGestureHint() | |
1868 { | |
1869 Frame* rootFrame = m_frame; | |
1870 while (rootFrame->tree()->parent()) | |
1871 rootFrame = rootFrame->tree()->parent(); | |
1872 | |
1873 if (rootFrame->script()->isEnabled()) | |
1874 return rootFrame->script()->processingUserGesture(); | |
1875 | |
1876 return true; // If JavaScript is disabled, a user gesture must have initiate
d the navigation | |
1877 } | |
1878 | |
1879 void FrameLoader::didNotOpenURL(const KURL& url) | |
1880 { | |
1881 if (m_submittedFormURL == url) | |
1882 m_submittedFormURL = KURL(); | |
1883 } | |
1884 | |
1885 void FrameLoader::resetMultipleFormSubmissionProtection() | |
1886 { | |
1887 m_submittedFormURL = KURL(); | |
1888 } | |
1889 | |
1890 void FrameLoader::setEncoding(const String& name, bool userChosen) | |
1891 { | |
1892 if (!m_workingURL.isEmpty()) | |
1893 receivedFirstData(); | |
1894 m_encoding = name; | |
1895 m_encodingWasChosenByUser = userChosen; | |
1896 } | |
1897 | |
1898 void FrameLoader::addData(const char* bytes, int length) | |
1899 { | |
1900 ASSERT(m_workingURL.isEmpty()); | |
1901 ASSERT(m_frame->document()); | |
1902 ASSERT(m_frame->document()->parsing()); | |
1903 write(bytes, length); | |
1904 } | |
1905 | |
1906 bool FrameLoader::canCachePage() | |
1907 { | |
1908 // Cache the page, if possible. | |
1909 // Don't write to the cache if in the middle of a redirect, since we will wa
nt to | |
1910 // store the final page we end up on. | |
1911 // No point writing to the cache on a reload or loadSame, since we will just
write | |
1912 // over it again when we leave that page. | |
1913 // FIXME: <rdar://problem/4886592> - We should work out the complexities of
caching pages with frames as they | |
1914 // are the most interesting pages on the web, and often those that would ben
efit the most from caching! | |
1915 FrameLoadType loadType = this->loadType(); | |
1916 | |
1917 return m_documentLoader | |
1918 && m_documentLoader->mainDocumentError().isNull() | |
1919 && !m_frame->tree()->childCount() | |
1920 && !m_frame->tree()->parent() | |
1921 // FIXME: If we ever change this so that pages with plug-ins will be cac
hed, | |
1922 // we need to make sure that we don't cache pages that have outstanding
NPObjects | |
1923 // (objects created by the plug-in). Since there is no way to pause/resu
me a Netscape plug-in, | |
1924 // they would need to be destroyed and then recreated, and there is no w
ay that we can recreate | |
1925 // the right NPObjects. See <rdar://problem/5197041> for more informatio
n. | |
1926 && !m_containsPlugIns | |
1927 && !m_URL.protocolIs("https") | |
1928 && m_frame->document() | |
1929 && !m_frame->document()->hasWindowEventListener(unloadEvent) | |
1930 #if ENABLE(DATABASE) | |
1931 && !m_frame->document()->hasOpenDatabases() | |
1932 #endif | |
1933 && m_frame->page() | |
1934 && m_frame->page()->backForwardList()->enabled() | |
1935 && m_frame->page()->backForwardList()->capacity() > 0 | |
1936 && m_frame->page()->settings()->usesPageCache() | |
1937 && m_currentHistoryItem | |
1938 && !isQuickRedirectComing() | |
1939 && loadType != FrameLoadTypeReload | |
1940 && loadType != FrameLoadTypeReloadAllowingStaleData | |
1941 && loadType != FrameLoadTypeSame | |
1942 && !m_documentLoader->isLoadingInAPISense() | |
1943 && !m_documentLoader->isStopping() | |
1944 #if ENABLE(OFFLINE_WEB_APPLICATIONS) | |
1945 // FIXME: We should investigating caching pages that have an associated | |
1946 // application cache. <rdar://problem/5917899> tracks that work. | |
1947 && !m_documentLoader->applicationCache() | |
1948 && !m_documentLoader->candidateApplicationCacheGroup() | |
1949 #endif | |
1950 ; | |
1951 } | |
1952 | |
1953 void FrameLoader::updatePolicyBaseURL() | |
1954 { | |
1955 if (m_frame->tree()->parent() && m_frame->tree()->parent()->document()) | |
1956 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL())
; | |
1957 else | |
1958 setPolicyBaseURL(m_URL); | |
1959 } | |
1960 | |
1961 void FrameLoader::setPolicyBaseURL(const KURL& url) | |
1962 { | |
1963 if (m_frame->document()) | |
1964 m_frame->document()->setPolicyBaseURL(url); | |
1965 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
1966 child->loader()->setPolicyBaseURL(url); | |
1967 } | |
1968 | |
1969 // This does the same kind of work that didOpenURL does, except it relies on the
fact | |
1970 // that a higher level already checked that the URLs match and the scrolling is
the right thing to do. | |
1971 void FrameLoader::scrollToAnchor(const KURL& url) | |
1972 { | |
1973 m_URL = url; | |
1974 updateHistoryForAnchorScroll(); | |
1975 | |
1976 // If we were in the autoscroll/panScroll mode we want to stop it before fol
lowing the link to the anchor | |
1977 m_frame->eventHandler()->stopAutoscrollTimer(); | |
1978 started(); | |
1979 gotoAnchor(); | |
1980 | |
1981 // It's important to model this as a load that starts and immediately finish
es. | |
1982 // Otherwise, the parent frame may think we never finished loading. | |
1983 m_isComplete = false; | |
1984 checkCompleted(); | |
1985 } | |
1986 | |
1987 bool FrameLoader::isComplete() const | |
1988 { | |
1989 return m_isComplete; | |
1990 } | |
1991 | |
1992 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection) | |
1993 { | |
1994 ASSERT(m_frame->page()); | |
1995 | |
1996 stopRedirectionTimer(); | |
1997 m_scheduledRedirection.set(redirection); | |
1998 if (!m_isComplete && redirection->type != ScheduledRedirection::redirection) | |
1999 completed(); | |
2000 if (m_isComplete || redirection->type != ScheduledRedirection::redirection) | |
2001 startRedirectionTimer(); | |
2002 } | |
2003 | |
2004 void FrameLoader::startRedirectionTimer() | |
2005 { | |
2006 ASSERT(m_frame->page()); | |
2007 ASSERT(m_scheduledRedirection); | |
2008 | |
2009 m_redirectionTimer.stop(); | |
2010 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay); | |
2011 | |
2012 switch (m_scheduledRedirection->type) { | |
2013 case ScheduledRedirection::redirection: | |
2014 case ScheduledRedirection::locationChange: | |
2015 case ScheduledRedirection::locationChangeDuringLoad: | |
2016 clientRedirected(KURL(m_scheduledRedirection->url), | |
2017 m_scheduledRedirection->delay, | |
2018 currentTime() + m_redirectionTimer.nextFireInterval(), | |
2019 m_scheduledRedirection->lockHistory, | |
2020 m_isExecutingJavaScriptFormAction); | |
2021 return; | |
2022 case ScheduledRedirection::reload: | |
2023 case ScheduledRedirection::historyNavigation: | |
2024 // Don't report history navigations. | |
2025 return; | |
2026 } | |
2027 ASSERT_NOT_REACHED(); | |
2028 } | |
2029 | |
2030 void FrameLoader::stopRedirectionTimer() | |
2031 { | |
2032 if (!m_redirectionTimer.isActive()) | |
2033 return; | |
2034 | |
2035 m_redirectionTimer.stop(); | |
2036 | |
2037 if (m_scheduledRedirection) { | |
2038 switch (m_scheduledRedirection->type) { | |
2039 case ScheduledRedirection::redirection: | |
2040 case ScheduledRedirection::locationChange: | |
2041 case ScheduledRedirection::locationChangeDuringLoad: | |
2042 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress
); | |
2043 return; | |
2044 case ScheduledRedirection::reload: | |
2045 case ScheduledRedirection::historyNavigation: | |
2046 // Don't report history navigations. | |
2047 return; | |
2048 } | |
2049 ASSERT_NOT_REACHED(); | |
2050 } | |
2051 } | |
2052 | |
2053 void FrameLoader::completed() | |
2054 { | |
2055 RefPtr<Frame> protect(m_frame); | |
2056 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
2057 child->loader()->parentCompleted(); | |
2058 if (Frame* parent = m_frame->tree()->parent()) | |
2059 parent->loader()->checkCompleted(); | |
2060 submitFormAgain(); | |
2061 } | |
2062 | |
2063 void FrameLoader::started() | |
2064 { | |
2065 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent()) | |
2066 frame->loader()->m_isComplete = false; | |
2067 } | |
2068 | |
2069 bool FrameLoader::containsPlugins() const | |
2070 { | |
2071 return m_containsPlugIns; | |
2072 } | |
2073 | |
2074 void FrameLoader::prepareForLoadStart() | |
2075 { | |
2076 if (Page* page = m_frame->page()) | |
2077 page->progress()->progressStarted(m_frame); | |
2078 m_client->dispatchDidStartProvisionalLoad(); | |
2079 } | |
2080 | |
2081 void FrameLoader::setupForReplace() | |
2082 { | |
2083 setState(FrameStateProvisional); | |
2084 m_provisionalDocumentLoader = m_documentLoader; | |
2085 m_documentLoader = 0; | |
2086 detachChildren(); | |
2087 } | |
2088 | |
2089 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType) | |
2090 { | |
2091 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType); | |
2092 } | |
2093 | |
2094 void FrameLoader::loadFrameRequestWithFormState(const FrameLoadRequest& request,
bool lockHistory, Event* event, PassRefPtr<FormState> prpFormState) | |
2095 { | |
2096 RefPtr<FormState> formState = prpFormState; | |
2097 KURL url = request.resourceRequest().url(); | |
2098 | |
2099 String referrer; | |
2100 String argsReferrer = request.resourceRequest().httpReferrer(); | |
2101 if (!argsReferrer.isEmpty()) | |
2102 referrer = argsReferrer; | |
2103 else | |
2104 referrer = m_outgoingReferrer; | |
2105 | |
2106 ASSERT(frame()->document()); | |
2107 if (url.protocolIs("file")) { | |
2108 if (!canLoad(url, String(), frame()->document()) && !canLoad(url, referr
er)) { | |
2109 FrameLoader::reportLocalLoadFailed(m_frame, url.string()); | |
2110 return; | |
2111 } | |
2112 } | |
2113 | |
2114 if (shouldHideReferrer(url, referrer)) | |
2115 referrer = String(); | |
2116 | |
2117 Frame* targetFrame = findFrameForNavigation(request.frameName()); | |
2118 | |
2119 if (request.resourceRequest().httpMethod() != "POST") { | |
2120 FrameLoadType loadType; | |
2121 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData) | |
2122 loadType = FrameLoadTypeReload; | |
2123 else if (lockHistory) | |
2124 loadType = FrameLoadTypeRedirectWithLockedHistory; | |
2125 else | |
2126 loadType = FrameLoadTypeStandard; | |
2127 | |
2128 loadURL(request.resourceRequest().url(), referrer, request.frameName(),
loadType, | |
2129 event, formState.release()); | |
2130 } else | |
2131 loadPostRequest(request.resourceRequest(), referrer, request.frameName()
, event, formState.release()); | |
2132 | |
2133 if (targetFrame && targetFrame != m_frame) | |
2134 if (Page* page = targetFrame->page()) | |
2135 page->chrome()->focus(); | |
2136 } | |
2137 | |
2138 | |
2139 void FrameLoader::loadFrameRequestWithFormAndValues(const FrameLoadRequest& requ
est, bool lockHistory, Event* event, | |
2140 HTMLFormElement* submitForm, const HashMap<String, String>& formValues) | |
2141 { | |
2142 RefPtr<FormState> formState; | |
2143 if (submitForm && !formValues.isEmpty()) | |
2144 formState = FormState::create(submitForm, formValues, m_frame); | |
2145 | |
2146 loadFrameRequestWithFormState(request, lockHistory, event, formState.release
()); | |
2147 } | |
2148 | |
2149 | |
2150 void FrameLoader::loadURL(const KURL& newURL, const String& referrer, const Stri
ng& frameName, FrameLoadType newLoadType, | |
2151 Event* event, PassRefPtr<FormState> prpFormState) | |
2152 { | |
2153 RefPtr<FormState> formState = prpFormState; | |
2154 bool isFormSubmission = formState; | |
2155 | |
2156 ResourceRequest request(newURL); | |
2157 if (!referrer.isEmpty()) | |
2158 request.setHTTPReferrer(referrer); | |
2159 addExtraFieldsToRequest(request, true, event || isFormSubmission); | |
2160 if (newLoadType == FrameLoadTypeReload) | |
2161 request.setCachePolicy(ReloadIgnoringCacheData); | |
2162 | |
2163 ASSERT(newLoadType != FrameLoadTypeSame); | |
2164 | |
2165 NavigationAction action(newURL, newLoadType, isFormSubmission, event); | |
2166 | |
2167 if (!frameName.isEmpty()) { | |
2168 if (Frame* targetFrame = findFrameForNavigation(frameName)) | |
2169 targetFrame->loader()->loadURL(newURL, referrer, String(), newLoadTy
pe, event, formState); | |
2170 else | |
2171 checkNewWindowPolicy(action, request, formState, frameName); | |
2172 return; | |
2173 } | |
2174 | |
2175 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; | |
2176 | |
2177 bool sameURL = shouldTreatURLAsSameAsCurrent(newURL); | |
2178 | |
2179 // Make sure to do scroll to anchor processing even if the URL is | |
2180 // exactly the same so pages with '#' links and DHTML side effects | |
2181 // work properly. | |
2182 if (shouldScrollToAnchor(isFormSubmission, newLoadType, newURL)) { | |
2183 oldDocumentLoader->setTriggeringAction(action); | |
2184 stopPolicyCheck(); | |
2185 checkNavigationPolicy(request, oldDocumentLoader.get(), formState, | |
2186 callContinueFragmentScrollAfterNavigationPolicy, this); | |
2187 } else { | |
2188 // must grab this now, since this load may stop the previous load and cl
ear this flag | |
2189 bool isRedirect = m_quickRedirectComing; | |
2190 loadWithNavigationAction(request, action, newLoadType, formState); | |
2191 if (isRedirect) { | |
2192 m_quickRedirectComing = false; | |
2193 if (m_provisionalDocumentLoader) | |
2194 m_provisionalDocumentLoader->setIsClientRedirect(true); | |
2195 } else if (sameURL) | |
2196 // Example of this case are sites that reload the same URL with a di
fferent cookie | |
2197 // driving the generated content, or a master frame with links that
drive a target | |
2198 // frame, where the user has clicked on the same link repeatedly. | |
2199 // But if the load type is FrameLoadTypeReloadAllowingStaleData, whi
ch means the frame | |
2200 // is reloaded only because user select one encoding from encoding m
enu, so we do not | |
2201 // change the load type. | |
2202 if (m_loadType != FrameLoadTypeReloadAllowingStaleData) | |
2203 m_loadType = FrameLoadTypeSame; | |
2204 } | |
2205 } | |
2206 | |
2207 void FrameLoader::load(const ResourceRequest& request) | |
2208 { | |
2209 load(request, SubstituteData()); | |
2210 } | |
2211 | |
2212 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& sub
stituteData) | |
2213 { | |
2214 if (m_inStopAllLoaders) | |
2215 return; | |
2216 | |
2217 // FIXME: is this the right place to reset loadType? Perhaps this should be
done after loading is finished or aborted. | |
2218 m_loadType = FrameLoadTypeStandard; | |
2219 load(m_client->createDocumentLoader(request, substituteData).get()); | |
2220 } | |
2221 | |
2222 void FrameLoader::load(const ResourceRequest& request, const String& frameName) | |
2223 { | |
2224 if (frameName.isEmpty()) { | |
2225 load(request); | |
2226 return; | |
2227 } | |
2228 | |
2229 Frame* frame = findFrameForNavigation(frameName); | |
2230 if (frame) { | |
2231 frame->loader()->load(request); | |
2232 return; | |
2233 } | |
2234 | |
2235 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), r
equest, 0, frameName); | |
2236 } | |
2237 | |
2238 void FrameLoader::loadWithNavigationAction(const ResourceRequest& request, const
NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState) | |
2239 { | |
2240 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, Subs
tituteData()); | |
2241 | |
2242 loader->setTriggeringAction(action); | |
2243 if (m_documentLoader) { | |
2244 // if the load type is not FrameLoadTypeReloadAllowingStaleData, | |
2245 // which means we will load page by user action, so we need not | |
2246 // use original encoding override. | |
2247 if (type == FrameLoadTypeReloadAllowingStaleData) | |
2248 loader->setOverrideEncoding(m_documentLoader->overrideEncoding()); | |
2249 else | |
2250 loader->setOverrideEncoding(String()); | |
2251 } | |
2252 | |
2253 loadWithDocumentLoader(loader.get(), type, formState); | |
2254 } | |
2255 | |
2256 void FrameLoader::load(DocumentLoader* newDocumentLoader) | |
2257 { | |
2258 ResourceRequest& r = newDocumentLoader->request(); | |
2259 addExtraFieldsToRequest(r, true, false); | |
2260 FrameLoadType type; | |
2261 | |
2262 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url()
)) { | |
2263 r.setCachePolicy(ReloadIgnoringCacheData); | |
2264 type = FrameLoadTypeSame; | |
2265 } else | |
2266 type = FrameLoadTypeStandard; | |
2267 | |
2268 // Do not use original encoding override since it is not loaded by user | |
2269 // selecting encoding. | |
2270 if (m_documentLoader) | |
2271 newDocumentLoader->setOverrideEncoding(String()); | |
2272 | |
2273 // When we loading alternate content for an unreachable URL that we're | |
2274 // visiting in the history list, we treat it as a reload so the history list
| |
2275 // is appropriately maintained. | |
2276 // | |
2277 // FIXME: This seems like a dangerous overloading of the meaning of "FrameLo
adTypeReload" ... | |
2278 // shouldn't a more explicit type of reload be defined, that means roughly | |
2279 // "load without affecting history" ? | |
2280 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) { | |
2281 ASSERT(type == FrameLoadTypeStandard); | |
2282 type = FrameLoadTypeReload; | |
2283 } | |
2284 | |
2285 loadWithDocumentLoader(newDocumentLoader, type, 0); | |
2286 } | |
2287 | |
2288 void FrameLoader::loadWithDocumentLoader(DocumentLoader* loader, FrameLoadType t
ype, PassRefPtr<FormState> prpFormState) | |
2289 { | |
2290 ASSERT(m_client->hasWebView()); | |
2291 | |
2292 // Unfortunately the view must be non-nil, this is ultimately due | |
2293 // to parser requiring a FrameView. We should fix this dependency. | |
2294 | |
2295 ASSERT(m_client->hasFrameView()); | |
2296 | |
2297 m_policyLoadType = type; | |
2298 RefPtr<FormState> formState = prpFormState; | |
2299 bool isFormSubmission = formState; | |
2300 | |
2301 const KURL& newURL = loader->request().url(); | |
2302 | |
2303 if (shouldScrollToAnchor(isFormSubmission, m_policyLoadType, newURL)) { | |
2304 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader; | |
2305 NavigationAction action(newURL, m_policyLoadType, isFormSubmission); | |
2306 | |
2307 oldDocumentLoader->setTriggeringAction(action); | |
2308 stopPolicyCheck(); | |
2309 checkNavigationPolicy(loader->request(), oldDocumentLoader.get(), formSt
ate, | |
2310 callContinueFragmentScrollAfterNavigationPolicy, this); | |
2311 } else { | |
2312 if (Frame* parent = m_frame->tree()->parent()) { | |
2313 if (type == FrameLoadTypeReloadAllowingStaleData) | |
2314 loader->setOverrideEncoding(parent->loader()->documentLoader()->
overrideEncoding()); | |
2315 else | |
2316 loader->setOverrideEncoding(String()); | |
2317 } | |
2318 | |
2319 stopPolicyCheck(); | |
2320 setPolicyDocumentLoader(loader); | |
2321 | |
2322 checkNavigationPolicy(loader->request(), loader, formState, | |
2323 callContinueLoadAfterNavigationPolicy, this); | |
2324 } | |
2325 } | |
2326 | |
2327 bool FrameLoader::canLoad(const KURL& url, const String& referrer, const Documen
t* doc) | |
2328 { | |
2329 // We can always load any URL that isn't considered local (e.g. http URLs) | |
2330 if (!shouldTreatURLAsLocal(url.string())) | |
2331 return true; | |
2332 | |
2333 // If we were provided a document, we let its local file policy dictate the
result, | |
2334 // otherwise we allow local loads only if the supplied referrer is also loca
l. | |
2335 if (doc) | |
2336 return doc->securityOrigin()->canLoadLocalResources(); | |
2337 else if (!referrer.isEmpty()) | |
2338 return shouldTreatURLAsLocal(referrer); | |
2339 else | |
2340 return false; | |
2341 } | |
2342 | |
2343 void FrameLoader::reportLocalLoadFailed(Frame* frame, const String& url) | |
2344 { | |
2345 ASSERT(!url.isEmpty()); | |
2346 if (!frame) | |
2347 return; | |
2348 | |
2349 frame->domWindow()->console()->addMessage(JSMessageSource, ErrorMessageLevel
, "Not allowed to load local resource: " + url, 0, String()); | |
2350 } | |
2351 | |
2352 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer) | |
2353 { | |
2354 bool referrerIsSecureURL = protocolIs(referrer, "https"); | |
2355 bool referrerIsWebURL = referrerIsSecureURL || protocolIs(referrer, "http"); | |
2356 | |
2357 if (!referrerIsWebURL) | |
2358 return true; | |
2359 | |
2360 if (!referrerIsSecureURL) | |
2361 return false; | |
2362 | |
2363 bool URLIsSecureURL = url.protocolIs("https"); | |
2364 | |
2365 return !URLIsSecureURL; | |
2366 } | |
2367 | |
2368 const ResourceRequest& FrameLoader::initialRequest() const | |
2369 { | |
2370 return activeDocumentLoader()->originalRequest(); | |
2371 } | |
2372 | |
2373 void FrameLoader::receivedData(const char* data, int length) | |
2374 { | |
2375 activeDocumentLoader()->receivedData(data, length); | |
2376 } | |
2377 | |
2378 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error) | |
2379 { | |
2380 m_delegateIsHandlingUnimplementablePolicy = true; | |
2381 m_client->dispatchUnableToImplementPolicy(error); | |
2382 m_delegateIsHandlingUnimplementablePolicy = false; | |
2383 } | |
2384 | |
2385 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response) | |
2386 { | |
2387 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response)); | |
2388 } | |
2389 | |
2390 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceReques
t& request) | |
2391 { | |
2392 return m_client->interruptForPolicyChangeError(request); | |
2393 } | |
2394 | |
2395 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, Navig
ationPolicyDecisionFunction function, void* argument) | |
2396 { | |
2397 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argum
ent); | |
2398 } | |
2399 | |
2400 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisi
onFunction function, void* argument) | |
2401 { | |
2402 ASSERT(activeDocumentLoader()); | |
2403 | |
2404 // Always show content with valid substitute data. | |
2405 if (activeDocumentLoader()->substituteData().isValid()) { | |
2406 function(argument, PolicyUse); | |
2407 return; | |
2408 } | |
2409 | |
2410 #if ENABLE(FTPDIR) | |
2411 // Respect the hidden FTP Directory Listing pref so it can be tested even if
the policy delegate might otherwise disallow it | |
2412 Settings* settings = m_frame->settings(); | |
2413 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "applic
ation/x-ftp-directory") { | |
2414 function(argument, PolicyUse); | |
2415 return; | |
2416 } | |
2417 #endif | |
2418 | |
2419 m_policyCheck.set(function, argument); | |
2420 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContent
Policy, | |
2421 MIMEType, activeDocumentLoader()->request()); | |
2422 } | |
2423 | |
2424 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader) | |
2425 { | |
2426 KURL unreachableURL = docLoader->unreachableURL(); | |
2427 | |
2428 if (unreachableURL.isEmpty()) | |
2429 return false; | |
2430 | |
2431 if (!isBackForwardLoadType(m_policyLoadType)) | |
2432 return false; | |
2433 | |
2434 // We only treat unreachableURLs specially during the delegate callbacks | |
2435 // for provisional load errors and navigation policy decisions. The former | |
2436 // case handles well-formed URLs that can't be loaded, and the latter | |
2437 // case handles malformed URLs and unknown schemes. Loading alternate conten
t | |
2438 // at other times behaves like a standard load. | |
2439 DocumentLoader* compareDocumentLoader = 0; | |
2440 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementa
blePolicy) | |
2441 compareDocumentLoader = m_policyDocumentLoader.get(); | |
2442 else if (m_delegateIsHandlingProvisionalLoadError) | |
2443 compareDocumentLoader = m_provisionalDocumentLoader.get(); | |
2444 | |
2445 return compareDocumentLoader && unreachableURL == compareDocumentLoader->req
uest().url(); | |
2446 } | |
2447 | |
2448 void FrameLoader::reloadAllowingStaleData(const String& encoding) | |
2449 { | |
2450 if (!m_documentLoader) | |
2451 return; | |
2452 | |
2453 ResourceRequest request = m_documentLoader->request(); | |
2454 KURL unreachableURL = m_documentLoader->unreachableURL(); | |
2455 if (!unreachableURL.isEmpty()) | |
2456 request.setURL(unreachableURL); | |
2457 | |
2458 request.setCachePolicy(ReturnCacheDataElseLoad); | |
2459 | |
2460 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, Subs
tituteData()); | |
2461 setPolicyDocumentLoader(loader.get()); | |
2462 | |
2463 loader->setOverrideEncoding(encoding); | |
2464 | |
2465 loadWithDocumentLoader(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0
); | |
2466 } | |
2467 | |
2468 void FrameLoader::reload() | |
2469 { | |
2470 if (!m_documentLoader) | |
2471 return; | |
2472 | |
2473 ResourceRequest& initialRequest = m_documentLoader->request(); | |
2474 | |
2475 // If a window is created by javascript, its main frame can have an empty bu
t non-nil URL. | |
2476 // Reloading in this case will lose the current contents (see 4151001). | |
2477 if (initialRequest.url().isEmpty()) | |
2478 return; | |
2479 | |
2480 // Replace error-page URL with the URL we were trying to reach. | |
2481 KURL unreachableURL = m_documentLoader->unreachableURL(); | |
2482 if (!unreachableURL.isEmpty()) | |
2483 initialRequest.setURL(unreachableURL); | |
2484 | |
2485 // Create a new document loader for the reload, this will become m_documentL
oader eventually, | |
2486 // but first it has to be the "policy" document loader, and then the "provis
ional" document loader. | |
2487 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialReques
t, SubstituteData()); | |
2488 | |
2489 ResourceRequest& request = loader->request(); | |
2490 | |
2491 request.setCachePolicy(ReloadIgnoringCacheData); | |
2492 request.setHTTPHeaderField("Cache-Control", "max-age=0"); | |
2493 | |
2494 // If we're about to re-post, set up action so the application can warn the
user. | |
2495 if (request.httpMethod() == "POST") | |
2496 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTy
peFormResubmitted)); | |
2497 | |
2498 loader->setOverrideEncoding(String()); | |
2499 | |
2500 loadWithDocumentLoader(loader.get(), FrameLoadTypeReload, 0); | |
2501 } | |
2502 | |
2503 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const | |
2504 { | |
2505 // The navigation change is safe if the active frame is: | |
2506 // - in the same security origin as the target or one of the target's ance
stors | |
2507 // Or the target frame is: | |
2508 // - a top-level frame in the frame hierarchy | |
2509 | |
2510 if (!targetFrame) | |
2511 return true; | |
2512 | |
2513 if (m_frame == targetFrame) | |
2514 return true; | |
2515 | |
2516 if (!targetFrame->tree()->parent()) | |
2517 return true; | |
2518 | |
2519 Document* activeDocument = m_frame->document(); | |
2520 ASSERT(activeDocument); | |
2521 const SecurityOrigin* activeSecurityOrigin = activeDocument->securityOrigin(
); | |
2522 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ance
storFrame->tree()->parent()) { | |
2523 Document* ancestorDocument = ancestorFrame->document(); | |
2524 if (!ancestorDocument) | |
2525 return true; | |
2526 | |
2527 const SecurityOrigin* ancestorSecurityOrigin = ancestorDocument->securit
yOrigin(); | |
2528 if (activeSecurityOrigin->canAccess(ancestorSecurityOrigin)) | |
2529 return true; | |
2530 } | |
2531 | |
2532 Settings* settings = targetFrame->settings(); | |
2533 if (settings && !settings->privateBrowsingEnabled()) { | |
2534 Document* targetDocument = targetFrame->document(); | |
2535 // FIXME: this error message should contain more specifics of why the na
vigation change is not allowed. | |
2536 String message = String::format("Unsafe JavaScript attempt to initiate a
navigation change for frame with URL %s from frame with URL %s.\n", | |
2537 targetDocument->url().string().utf8().data(), activeDocument->url().
string().utf8().data()); | |
2538 | |
2539 // FIXME: should we print to the console of the activeFrame as well? | |
2540 targetFrame->domWindow()->console()->addMessage(JSMessageSource, ErrorMe
ssageLevel, message, 1, String()); | |
2541 } | |
2542 | |
2543 return false; | |
2544 } | |
2545 | |
2546 void FrameLoader::stopLoadingSubframes() | |
2547 { | |
2548 for (RefPtr<Frame> child = m_frame->tree()->firstChild(); child; child = chi
ld->tree()->nextSibling()) | |
2549 child->loader()->stopAllLoaders(); | |
2550 } | |
2551 | |
2552 void FrameLoader::stopAllLoaders() | |
2553 { | |
2554 // If this method is called from within this method, infinite recursion can
occur (3442218). Avoid this. | |
2555 if (m_inStopAllLoaders) | |
2556 return; | |
2557 | |
2558 m_inStopAllLoaders = true; | |
2559 | |
2560 stopPolicyCheck(); | |
2561 | |
2562 stopLoadingSubframes(); | |
2563 if (m_provisionalDocumentLoader) | |
2564 m_provisionalDocumentLoader->stopLoading(); | |
2565 if (m_documentLoader) | |
2566 m_documentLoader->stopLoading(); | |
2567 | |
2568 setProvisionalDocumentLoader(0); | |
2569 | |
2570 if (m_documentLoader) | |
2571 m_documentLoader->clearArchiveResources(); | |
2572 | |
2573 m_inStopAllLoaders = false; | |
2574 } | |
2575 | |
2576 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete) | |
2577 { | |
2578 stopAllLoaders(); | |
2579 | |
2580 if (deferCheckLoadComplete) | |
2581 scheduleCheckLoadComplete(); | |
2582 else if (m_frame->page()) | |
2583 checkLoadComplete(); | |
2584 } | |
2585 | |
2586 DocumentLoader* FrameLoader::activeDocumentLoader() const | |
2587 { | |
2588 if (m_state == FrameStateProvisional) | |
2589 return m_provisionalDocumentLoader.get(); | |
2590 return m_documentLoader.get(); | |
2591 } | |
2592 | |
2593 bool FrameLoader::isLoading() const | |
2594 { | |
2595 DocumentLoader* docLoader = activeDocumentLoader(); | |
2596 if (!docLoader) | |
2597 return false; | |
2598 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresource
s() || docLoader->isLoadingPlugIns(); | |
2599 } | |
2600 | |
2601 bool FrameLoader::frameHasLoaded() const | |
2602 { | |
2603 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !
m_creatingInitialEmptyDocument); | |
2604 } | |
2605 | |
2606 void FrameLoader::setDocumentLoader(DocumentLoader* loader) | |
2607 { | |
2608 if (!loader && !m_documentLoader) | |
2609 return; | |
2610 | |
2611 ASSERT(loader != m_documentLoader); | |
2612 ASSERT(!loader || loader->frameLoader() == this); | |
2613 | |
2614 m_client->prepareForDataSourceReplacement(); | |
2615 detachChildren(); | |
2616 if (m_documentLoader) | |
2617 m_documentLoader->detachFromFrame(); | |
2618 | |
2619 m_documentLoader = loader; | |
2620 } | |
2621 | |
2622 DocumentLoader* FrameLoader::documentLoader() const | |
2623 { | |
2624 return m_documentLoader.get(); | |
2625 } | |
2626 | |
2627 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader) | |
2628 { | |
2629 if (m_policyDocumentLoader == loader) | |
2630 return; | |
2631 | |
2632 ASSERT(m_frame); | |
2633 if (loader) | |
2634 loader->setFrame(m_frame); | |
2635 if (m_policyDocumentLoader | |
2636 && m_policyDocumentLoader != m_provisionalDocumentLoader | |
2637 && m_policyDocumentLoader != m_documentLoader) | |
2638 m_policyDocumentLoader->detachFromFrame(); | |
2639 | |
2640 m_policyDocumentLoader = loader; | |
2641 } | |
2642 | |
2643 DocumentLoader* FrameLoader::policyDocumentLoader() const | |
2644 { | |
2645 return m_policyDocumentLoader.get(); | |
2646 } | |
2647 | |
2648 DocumentLoader* FrameLoader::provisionalDocumentLoader() const | |
2649 { | |
2650 return m_provisionalDocumentLoader.get(); | |
2651 } | |
2652 | |
2653 DocumentLoader* FrameLoader::policyDocumentLoader() | |
2654 { | |
2655 return m_policyDocumentLoader.get(); | |
2656 } | |
2657 | |
2658 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader) | |
2659 { | |
2660 ASSERT(!loader || !m_provisionalDocumentLoader); | |
2661 ASSERT(!loader || loader->frameLoader() == this); | |
2662 | |
2663 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_document
Loader) | |
2664 m_provisionalDocumentLoader->detachFromFrame(); | |
2665 | |
2666 m_provisionalDocumentLoader = loader; | |
2667 } | |
2668 | |
2669 FrameState FrameLoader::state() const | |
2670 { | |
2671 return m_state; | |
2672 } | |
2673 | |
2674 double FrameLoader::timeOfLastCompletedLoad() | |
2675 { | |
2676 return storedTimeOfLastCompletedLoad; | |
2677 } | |
2678 | |
2679 void FrameLoader::setState(FrameState newState) | |
2680 { | |
2681 m_state = newState; | |
2682 | |
2683 if (newState == FrameStateProvisional) | |
2684 provisionalLoadStarted(); | |
2685 else if (newState == FrameStateComplete) { | |
2686 frameLoadCompleted(); | |
2687 storedTimeOfLastCompletedLoad = currentTime(); | |
2688 if (m_documentLoader) | |
2689 m_documentLoader->stopRecordingResponses(); | |
2690 } | |
2691 } | |
2692 | |
2693 void FrameLoader::clearProvisionalLoad() | |
2694 { | |
2695 setProvisionalDocumentLoader(0); | |
2696 if (Page* page = m_frame->page()) | |
2697 page->progress()->progressCompleted(m_frame); | |
2698 setState(FrameStateComplete); | |
2699 } | |
2700 | |
2701 void FrameLoader::markLoadComplete() | |
2702 { | |
2703 setState(FrameStateComplete); | |
2704 } | |
2705 | |
2706 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage) | |
2707 { | |
2708 RefPtr<CachedPage> cachedPage = prpCachedPage; | |
2709 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; | |
2710 | |
2711 // Check to see if we need to cache the page we are navigating away from int
o the back/forward cache. | |
2712 // We are doing this here because we know for sure that a new page is about
to be loaded. | |
2713 if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isI
nPageCache()) | |
2714 cachePageForHistoryItem(m_currentHistoryItem.get()); | |
2715 | |
2716 if (m_loadType != FrameLoadTypeReplace) | |
2717 closeOldDataSources(); | |
2718 | |
2719 if (!cachedPage && !m_creatingInitialEmptyDocument) | |
2720 m_client->makeRepresentation(pdl.get()); | |
2721 | |
2722 transitionToCommitted(cachedPage); | |
2723 | |
2724 // Call clientRedirectCancelledOrFinished() here so that the frame load dele
gate is notified that the redirect's | |
2725 // status has changed, if there was a redirect. The frame load delegate may
have saved some state about | |
2726 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDat
e:forFrame:. Since we are | |
2727 // just about to commit a new page, there cannot possibly be a pending redir
ect at this point. | |
2728 if (m_sentRedirectNotification) | |
2729 clientRedirectCancelledOrFinished(false); | |
2730 | |
2731 if (cachedPage && cachedPage->document()) { | |
2732 open(*cachedPage); | |
2733 cachedPage->clear(); | |
2734 } else { | |
2735 KURL url = pdl->substituteData().responseURL(); | |
2736 if (url.isEmpty()) | |
2737 url = pdl->url(); | |
2738 if (url.isEmpty()) | |
2739 url = pdl->responseURL(); | |
2740 if (url.isEmpty()) | |
2741 url = blankURL(); | |
2742 | |
2743 didOpenURL(url); | |
2744 } | |
2745 opened(); | |
2746 } | |
2747 | |
2748 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage) | |
2749 { | |
2750 ASSERT(m_client->hasWebView()); | |
2751 ASSERT(m_state == FrameStateProvisional); | |
2752 | |
2753 if (m_state != FrameStateProvisional) | |
2754 return; | |
2755 | |
2756 m_client->setCopiesOnScroll(); | |
2757 updateHistoryForCommit(); | |
2758 | |
2759 // The call to closeURL() invokes the unload event handler, which can execut
e arbitrary | |
2760 // JavaScript. If the script initiates a new load, we need to abandon the cu
rrent load, | |
2761 // or the two will stomp each other. | |
2762 DocumentLoader* pdl = m_provisionalDocumentLoader.get(); | |
2763 if (m_documentLoader) | |
2764 closeURL(); | |
2765 if (pdl != m_provisionalDocumentLoader) | |
2766 return; | |
2767 | |
2768 // Nothing else can interupt this commit - set the Provisional->Committed tr
ansition in stone | |
2769 if (m_documentLoader) | |
2770 m_documentLoader->stopLoadingSubresources(); | |
2771 if (m_documentLoader) | |
2772 m_documentLoader->stopLoadingPlugIns(); | |
2773 | |
2774 setDocumentLoader(m_provisionalDocumentLoader.get()); | |
2775 setProvisionalDocumentLoader(0); | |
2776 setState(FrameStateCommittedPage); | |
2777 | |
2778 // Handle adding the URL to the back/forward list. | |
2779 DocumentLoader* dl = m_documentLoader.get(); | |
2780 String ptitle = dl->title(); | |
2781 | |
2782 switch (m_loadType) { | |
2783 case FrameLoadTypeForward: | |
2784 case FrameLoadTypeBack: | |
2785 case FrameLoadTypeIndexedBackForward: | |
2786 if (Page* page = m_frame->page()) | |
2787 if (page->backForwardList()) { | |
2788 updateHistoryForBackForwardNavigation(); | |
2789 | |
2790 // Create a document view for this document, or used the cac
hed view. | |
2791 if (cachedPage) { | |
2792 DocumentLoader* cachedDocumentLoader = cachedPage->docum
entLoader(); | |
2793 ASSERT(cachedDocumentLoader); | |
2794 cachedDocumentLoader->setFrame(m_frame); | |
2795 m_client->transitionToCommittedFromCachedPage(cachedPage
.get()); | |
2796 | |
2797 } else | |
2798 m_client->transitionToCommittedForNewPage(); | |
2799 } | |
2800 break; | |
2801 | |
2802 case FrameLoadTypeReload: | |
2803 case FrameLoadTypeSame: | |
2804 case FrameLoadTypeReplace: | |
2805 updateHistoryForReload(); | |
2806 m_client->transitionToCommittedForNewPage(); | |
2807 break; | |
2808 | |
2809 // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllow
ingStaleData with the above case | |
2810 case FrameLoadTypeReloadAllowingStaleData: | |
2811 m_client->transitionToCommittedForNewPage(); | |
2812 break; | |
2813 | |
2814 case FrameLoadTypeStandard: | |
2815 updateHistoryForStandardLoad(); | |
2816 #ifndef BUILDING_ON_TIGER | |
2817 // This code was originally added for a Leopard performance imporvem
ent. We decided to | |
2818 // ifdef it to fix correctness issues on Tiger documented in <rdar:/
/problem/5441823>. | |
2819 if (m_frame->view()) | |
2820 m_frame->view()->suppressScrollbars(true); | |
2821 #endif | |
2822 m_client->transitionToCommittedForNewPage(); | |
2823 break; | |
2824 | |
2825 case FrameLoadTypeRedirectWithLockedHistory: | |
2826 updateHistoryForRedirectWithLockedHistory(); | |
2827 m_client->transitionToCommittedForNewPage(); | |
2828 break; | |
2829 | |
2830 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds"
is). | |
2831 // An exception should be thrown if we're in the FrameLoadTypeUninitiali
zed state. | |
2832 default: | |
2833 ASSERT_NOT_REACHED(); | |
2834 } | |
2835 | |
2836 m_responseMIMEType = dl->responseMIMEType(); | |
2837 | |
2838 // Tell the client we've committed this URL. | |
2839 ASSERT(m_client->hasFrameView()); | |
2840 | |
2841 if (m_creatingInitialEmptyDocument) | |
2842 return; | |
2843 | |
2844 m_committedFirstRealDocumentLoad = true; | |
2845 | |
2846 // For non-cached HTML pages, these methods are called in FrameLoader::begin
. | |
2847 if (cachedPage || !m_client->hasHTMLView()) { | |
2848 dispatchDidCommitLoad(); | |
2849 | |
2850 // If we have a title let the WebView know about it. | |
2851 if (!ptitle.isNull()) | |
2852 m_client->dispatchDidReceiveTitle(ptitle); | |
2853 } | |
2854 } | |
2855 | |
2856 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgres
s) | |
2857 { | |
2858 // Note that -webView:didCancelClientRedirectForFrame: is called on the fram
e load delegate even if | |
2859 // the redirect succeeded. We should either rename this API, or add a new m
ethod, like | |
2860 // -webView:didFinishClientRedirectForFrame: | |
2861 m_client->dispatchDidCancelClientRedirect(); | |
2862 | |
2863 if (!cancelWithLoadInProgress) | |
2864 m_quickRedirectComing = false; | |
2865 | |
2866 m_sentRedirectNotification = false; | |
2867 } | |
2868 | |
2869 void FrameLoader::clientRedirected(const KURL& url, double seconds, double fireD
ate, bool lockHistory, bool isJavaScriptFormAction) | |
2870 { | |
2871 m_client->dispatchWillPerformClientRedirect(url, seconds, fireDate); | |
2872 | |
2873 // Remember that we sent a redirect notification to the frame load delegate
so that when we commit | |
2874 // the next provisional load, we can send a corresponding -webView:didCancel
ClientRedirectForFrame: | |
2875 m_sentRedirectNotification = true; | |
2876 | |
2877 // If a "quick" redirect comes in an, we set a special mode so we treat the
next | |
2878 // load as part of the same navigation. If we don't have a document loader,
we have | |
2879 // no "original" load on which to base a redirect, so we treat the redirect
as a normal load. | |
2880 m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptForm
Action; | |
2881 } | |
2882 | |
2883 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationUR
L) | |
2884 { | |
2885 // This function implements the rule: "Don't reload if navigating by fragmen
t within | |
2886 // the same URL, but do reload if going to a new URL or to the same URL with
no | |
2887 // fragment identifier at all." | |
2888 if (!destinationURL.hasRef()) | |
2889 return true; | |
2890 return !equalIgnoringRef(currentURL, destinationURL); | |
2891 } | |
2892 | |
2893 void FrameLoader::closeOldDataSources() | |
2894 { | |
2895 // FIXME: Is it important for this traversal to be postorder instead of preo
rder? | |
2896 // If so, add helpers for postorder traversal, and use them. If not, then le
ts not | |
2897 // use a recursive algorithm here. | |
2898 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tre
e()->nextSibling()) | |
2899 child->loader()->closeOldDataSources(); | |
2900 | |
2901 if (m_documentLoader) | |
2902 m_client->dispatchWillClose(); | |
2903 | |
2904 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DO
MDocument to observers | |
2905 } | |
2906 | |
2907 void FrameLoader::open(CachedPage& cachedPage) | |
2908 { | |
2909 ASSERT(m_frame->page()); | |
2910 ASSERT(m_frame->page()->mainFrame() == m_frame); | |
2911 | |
2912 cancelRedirection(); | |
2913 | |
2914 // We still have to close the previous part page. | |
2915 closeURL(); | |
2916 | |
2917 m_isComplete = false; | |
2918 | |
2919 // Don't re-emit the load event. | |
2920 m_didCallImplicitClose = true; | |
2921 | |
2922 // Delete old status bar messages (if it _was_ activated on last URL). | |
2923 if (m_frame->script()->isEnabled()) { | |
2924 m_frame->setJSStatusBarText(String()); | |
2925 m_frame->setJSDefaultStatusBarText(String()); | |
2926 } | |
2927 | |
2928 KURL url = cachedPage.url(); | |
2929 | |
2930 if ((url.protocolIs("http") || url.protocolIs("https")) && !url.host().isEmp
ty() && url.path().isEmpty()) | |
2931 url.setPath("/"); | |
2932 | |
2933 m_URL = url; | |
2934 m_workingURL = url; | |
2935 | |
2936 started(); | |
2937 | |
2938 clear(); | |
2939 | |
2940 Document* document = cachedPage.document(); | |
2941 ASSERT(document); | |
2942 document->setInPageCache(false); | |
2943 | |
2944 m_needsClear = true; | |
2945 m_isComplete = false; | |
2946 m_didCallImplicitClose = false; | |
2947 m_outgoingReferrer = url.string(); | |
2948 | |
2949 FrameView* view = cachedPage.view(); | |
2950 if (view) | |
2951 view->setWasScrolledByUser(false); | |
2952 m_frame->setView(view); | |
2953 | |
2954 m_frame->setDocument(document); | |
2955 m_frame->domWindow()->setURL(document->url()); | |
2956 m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); | |
2957 | |
2958 m_decoder = document->decoder(); | |
2959 | |
2960 updatePolicyBaseURL(); | |
2961 | |
2962 cachedPage.restore(m_frame->page()); | |
2963 | |
2964 checkCompleted(); | |
2965 } | |
2966 | |
2967 bool FrameLoader::isStopping() const | |
2968 { | |
2969 return activeDocumentLoader()->isStopping(); | |
2970 } | |
2971 | |
2972 void FrameLoader::finishedLoading() | |
2973 { | |
2974 // Retain because the stop may release the last reference to it. | |
2975 RefPtr<Frame> protect(m_frame); | |
2976 | |
2977 RefPtr<DocumentLoader> dl = activeDocumentLoader(); | |
2978 dl->finishedLoading(); | |
2979 if (!dl->mainDocumentError().isNull() || !dl->frameLoader()) | |
2980 return; | |
2981 dl->setPrimaryLoadComplete(true); | |
2982 m_client->dispatchDidLoadMainResource(dl.get()); | |
2983 checkLoadComplete(); | |
2984 } | |
2985 | |
2986 bool FrameLoader::isHostedByObjectElement() const | |
2987 { | |
2988 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); | |
2989 return owner && owner->hasTagName(objectTag); | |
2990 } | |
2991 | |
2992 bool FrameLoader::isLoadingMainFrame() const | |
2993 { | |
2994 Page* page = m_frame->page(); | |
2995 return page && m_frame == page->mainFrame(); | |
2996 } | |
2997 | |
2998 bool FrameLoader::canShowMIMEType(const String& MIMEType) const | |
2999 { | |
3000 return m_client->canShowMIMEType(MIMEType); | |
3001 } | |
3002 | |
3003 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme) | |
3004 { | |
3005 return m_client->representationExistsForURLScheme(URLScheme); | |
3006 } | |
3007 | |
3008 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme) | |
3009 { | |
3010 return m_client->generatedMIMETypeForURLScheme(URLScheme); | |
3011 } | |
3012 | |
3013 void FrameLoader::cancelContentPolicyCheck() | |
3014 { | |
3015 m_client->cancelPolicyCheck(); | |
3016 m_policyCheck.clear(); | |
3017 } | |
3018 | |
3019 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame() | |
3020 { | |
3021 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad(); | |
3022 } | |
3023 | |
3024 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader) | |
3025 { | |
3026 #if PLATFORM(WIN) | |
3027 if (m_creatingInitialEmptyDocument) | |
3028 return; | |
3029 #endif | |
3030 | |
3031 // If loading a webarchive, run through webarchive machinery | |
3032 const String& responseMIMEType = loader->responseMIMEType(); | |
3033 | |
3034 // FIXME: Mac's FrameLoaderClient::finishedLoading() method does work that i
s required even with Archive loads | |
3035 // so we still need to call it. Other platforms should only call finishLoad
ing for non-archive loads | |
3036 // That work should be factored out so this #ifdef can be removed | |
3037 #if PLATFORM(MAC) | |
3038 m_client->finishedLoading(loader); | |
3039 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) | |
3040 return; | |
3041 #else | |
3042 if (!ArchiveFactory::isArchiveMimeType(responseMIMEType)) { | |
3043 m_client->finishedLoading(loader); | |
3044 return; | |
3045 } | |
3046 #endif | |
3047 | |
3048 RefPtr<Archive> archive(ArchiveFactory::create(loader->mainResourceData().ge
t(), responseMIMEType)); | |
3049 if (!archive) | |
3050 return; | |
3051 | |
3052 loader->addAllArchiveResources(archive.get()); | |
3053 | |
3054 ArchiveResource* mainResource = archive->mainResource(); | |
3055 loader->setParsedArchiveData(mainResource->data()); | |
3056 continueLoadWithData(mainResource->data(), mainResource->mimeType(), mainRes
ource->textEncoding(), mainResource->url()); | |
3057 } | |
3058 | |
3059 bool FrameLoader::isReplacing() const | |
3060 { | |
3061 return m_loadType == FrameLoadTypeReplace; | |
3062 } | |
3063 | |
3064 void FrameLoader::setReplacing() | |
3065 { | |
3066 m_loadType = FrameLoadTypeReplace; | |
3067 } | |
3068 | |
3069 void FrameLoader::revertToProvisional(DocumentLoader* loader) | |
3070 { | |
3071 m_client->revertToProvisionalState(loader); | |
3072 } | |
3073 | |
3074 bool FrameLoader::subframeIsLoading() const | |
3075 { | |
3076 // It's most likely that the last added frame is the last to load so we walk
backwards. | |
3077 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree
()->previousSibling()) { | |
3078 FrameLoader* childLoader = child->loader(); | |
3079 DocumentLoader* documentLoader = childLoader->documentLoader(); | |
3080 if (documentLoader && documentLoader->isLoadingInAPISense()) | |
3081 return true; | |
3082 documentLoader = childLoader->provisionalDocumentLoader(); | |
3083 if (documentLoader && documentLoader->isLoadingInAPISense()) | |
3084 return true; | |
3085 } | |
3086 return false; | |
3087 } | |
3088 | |
3089 void FrameLoader::willChangeTitle(DocumentLoader* loader) | |
3090 { | |
3091 m_client->willChangeTitle(loader); | |
3092 } | |
3093 | |
3094 FrameLoadType FrameLoader::loadType() const | |
3095 { | |
3096 return m_loadType; | |
3097 } | |
3098 | |
3099 void FrameLoader::stopPolicyCheck() | |
3100 { | |
3101 m_client->cancelPolicyCheck(); | |
3102 PolicyCheck check = m_policyCheck; | |
3103 m_policyCheck.clear(); | |
3104 check.cancel(); | |
3105 } | |
3106 | |
3107 void FrameLoader::checkLoadCompleteForThisFrame() | |
3108 { | |
3109 ASSERT(m_client->hasWebView()); | |
3110 | |
3111 switch (m_state) { | |
3112 case FrameStateProvisional: { | |
3113 if (m_delegateIsHandlingProvisionalLoadError) | |
3114 return; | |
3115 | |
3116 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader; | |
3117 if (!pdl) | |
3118 return; | |
3119 | |
3120 // If we've received any errors we may be stuck in the provisional s
tate and actually complete. | |
3121 const ResourceError& error = pdl->mainDocumentError(); | |
3122 if (error.isNull()) | |
3123 return; | |
3124 | |
3125 // Check all children first. | |
3126 RefPtr<HistoryItem> item; | |
3127 if (Page* page = m_frame->page()) | |
3128 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFr
ame()) | |
3129 item = m_currentHistoryItem; | |
3130 | |
3131 bool shouldReset = true; | |
3132 if (!pdl->isLoadingInAPISense()) { | |
3133 m_delegateIsHandlingProvisionalLoadError = true; | |
3134 m_client->dispatchDidFailProvisionalLoad(error); | |
3135 m_delegateIsHandlingProvisionalLoadError = false; | |
3136 | |
3137 // FIXME: can stopping loading here possibly have any effect, if
isLoading is false, | |
3138 // which it must be to be in this branch of the if? And is it OK
to just do a full-on | |
3139 // stopAllLoaders instead of stopLoadingSubframes? | |
3140 stopLoadingSubframes(); | |
3141 pdl->stopLoading(); | |
3142 | |
3143 // Finish resetting the load state, but only if another load has
n't been started by the | |
3144 // delegate callback. | |
3145 if (pdl == m_provisionalDocumentLoader) | |
3146 clearProvisionalLoad(); | |
3147 else if (m_provisionalDocumentLoader) { | |
3148 KURL unreachableURL = m_provisionalDocumentLoader->unreachab
leURL(); | |
3149 if (!unreachableURL.isEmpty() && unreachableURL == pdl->requ
est().url()) | |
3150 shouldReset = false; | |
3151 } | |
3152 } | |
3153 if (shouldReset && item) | |
3154 if (Page* page = m_frame->page()) | |
3155 page->backForwardList()->goToItem(item.get()); | |
3156 return; | |
3157 } | |
3158 | |
3159 case FrameStateCommittedPage: { | |
3160 DocumentLoader* dl = m_documentLoader.get(); | |
3161 if (!dl || dl->isLoadingInAPISense()) | |
3162 return; | |
3163 | |
3164 markLoadComplete(); | |
3165 | |
3166 // FIXME: Is this subsequent work important if we already navigated
away? | |
3167 // Maybe there are bugs because of that, or extra work we can skip b
ecause | |
3168 // the new page is ready. | |
3169 | |
3170 m_client->forceLayoutForNonHTML(); | |
3171 | |
3172 // If the user had a scroll point, scroll to it, overriding the anch
or point if any. | |
3173 if (Page* page = m_frame->page()) | |
3174 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoa
dTypeReload) && page->backForwardList()) | |
3175 restoreScrollPositionAndViewState(); | |
3176 | |
3177 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentL
oad) | |
3178 return; | |
3179 | |
3180 const ResourceError& error = dl->mainDocumentError(); | |
3181 #ifndef NDEBUG | |
3182 m_didDispatchDidCommitLoad = false; | |
3183 #endif | |
3184 if (!error.isNull()) | |
3185 m_client->dispatchDidFailLoad(error); | |
3186 else | |
3187 m_client->dispatchDidFinishLoad(); | |
3188 | |
3189 if (Page* page = m_frame->page()) | |
3190 page->progress()->progressCompleted(m_frame); | |
3191 return; | |
3192 } | |
3193 | |
3194 case FrameStateComplete: | |
3195 // Even if already complete, we might have set a previous item on a
frame that | |
3196 // didn't do any data loading on the past transaction. Make sure to
clear these out. | |
3197 m_client->frameLoadCompleted(); | |
3198 return; | |
3199 } | |
3200 | |
3201 ASSERT_NOT_REACHED(); | |
3202 } | |
3203 | |
3204 void FrameLoader::continueAfterContentPolicy(PolicyAction policy) | |
3205 { | |
3206 PolicyCheck check = m_policyCheck; | |
3207 m_policyCheck.clear(); | |
3208 check.call(policy); | |
3209 } | |
3210 | |
3211 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction) | |
3212 { | |
3213 if (!m_provisionalDocumentLoader) | |
3214 return; | |
3215 | |
3216 // DocumentLoader calls back to our prepareForLoadStart | |
3217 m_provisionalDocumentLoader->prepareForLoadStart(); | |
3218 | |
3219 // The load might be cancelled inside of prepareForLoadStart(), nulling out
the m_provisionalDocumentLoader, | |
3220 // so we need to null check it again. | |
3221 if (!m_provisionalDocumentLoader) | |
3222 return; | |
3223 | |
3224 DocumentLoader* activeDocLoader = activeDocumentLoader(); | |
3225 if (activeDocLoader && activeDocLoader->isLoadingMainResource()) | |
3226 return; | |
3227 | |
3228 m_provisionalDocumentLoader->setLoadingFromCachedPage(false); | |
3229 | |
3230 unsigned long identifier = 0; | |
3231 | |
3232 if (Page* page = m_frame->page()) { | |
3233 identifier = page->progress()->createUniqueIdentifier(); | |
3234 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocume
ntLoader.get(), m_provisionalDocumentLoader->originalRequest()); | |
3235 } | |
3236 | |
3237 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier)) | |
3238 m_provisionalDocumentLoader->updateLoading(); | |
3239 } | |
3240 | |
3241 void FrameLoader::didFirstLayout() | |
3242 { | |
3243 if (Page* page = m_frame->page()) | |
3244 if (isBackForwardLoadType(m_loadType) && page->backForwardList()) | |
3245 restoreScrollPositionAndViewState(); | |
3246 | |
3247 m_firstLayoutDone = true; | |
3248 m_client->dispatchDidFirstLayout(); | |
3249 } | |
3250 | |
3251 void FrameLoader::frameLoadCompleted() | |
3252 { | |
3253 m_client->frameLoadCompleted(); | |
3254 | |
3255 // After a canceled provisional load, firstLayoutDone is false. | |
3256 // Reset it to true if we're displaying a page. | |
3257 if (m_documentLoader) | |
3258 m_firstLayoutDone = true; | |
3259 } | |
3260 | |
3261 bool FrameLoader::firstLayoutDone() const | |
3262 { | |
3263 return m_firstLayoutDone; | |
3264 } | |
3265 | |
3266 bool FrameLoader::isQuickRedirectComing() const | |
3267 { | |
3268 return m_quickRedirectComing; | |
3269 } | |
3270 | |
3271 void FrameLoader::detachChildren() | |
3272 { | |
3273 // FIXME: Is it really necessary to do this in reverse order? | |
3274 Frame* previous; | |
3275 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) { | |
3276 previous = child->tree()->previousSibling(); | |
3277 child->loader()->detachFromParent(); | |
3278 } | |
3279 } | |
3280 | |
3281 void FrameLoader::recursiveCheckLoadComplete() | |
3282 { | |
3283 Vector<RefPtr<Frame>, 10> frames; | |
3284 | |
3285 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = fra
me->tree()->nextSibling()) | |
3286 frames.append(frame); | |
3287 | |
3288 unsigned size = frames.size(); | |
3289 for (unsigned i = 0; i < size; i++) | |
3290 frames[i]->loader()->recursiveCheckLoadComplete(); | |
3291 | |
3292 checkLoadCompleteForThisFrame(); | |
3293 } | |
3294 | |
3295 // Called every time a resource is completely loaded, or an error is received. | |
3296 void FrameLoader::checkLoadComplete() | |
3297 { | |
3298 ASSERT(m_client->hasWebView()); | |
3299 | |
3300 // FIXME: Always traversing the entire frame tree is a bit inefficient, but | |
3301 // is currently needed in order to null out the previous history item for al
l frames. | |
3302 if (Page* page = m_frame->page()) | |
3303 page->mainFrame()->loader()->recursiveCheckLoadComplete(); | |
3304 } | |
3305 | |
3306 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const | |
3307 { | |
3308 if (!recurse) | |
3309 return numRequests(m_frame->document()); | |
3310 | |
3311 int count = 0; | |
3312 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_fr
ame)) | |
3313 count += numRequests(frame->document()); | |
3314 return count; | |
3315 } | |
3316 | |
3317 FrameLoaderClient* FrameLoader::client() const | |
3318 { | |
3319 return m_client; | |
3320 } | |
3321 | |
3322 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event) | |
3323 { | |
3324 // FIXME: We'd like to remove this altogether and fix the multiple form subm
ission issue another way. | |
3325 // We do not want to submit more than one form from the same page, | |
3326 // nor do we want to submit a single form more than once. | |
3327 // This flag prevents these from happening; not sure how other browsers prev
ent this. | |
3328 // The flag is reset in each time we start handle a new mouse or key down ev
ent, and | |
3329 // also in setView since this part may get reused for a page from the back/f
orward cache. | |
3330 // The form multi-submit logic here is only needed when we are submitting a
form that affects this frame. | |
3331 // FIXME: Frame targeting is only one of the ways the submission could end u
p doing something other | |
3332 // than replacing this frame's content, so this check is flawed. On the othe
r hand, the check is hardly | |
3333 // needed any more now that we reset m_submittedFormURL on each mouse or key
down event. | |
3334 Frame* target = m_frame->tree()->find(request.frameName()); | |
3335 if (target && m_frame->tree()->isDescendantOf(target)) { | |
3336 if (m_submittedFormURL == request.resourceRequest().url()) | |
3337 return; | |
3338 m_submittedFormURL = request.resourceRequest().url(); | |
3339 } | |
3340 | |
3341 // FIXME: We should probably call userGestureHint() to tell whether this for
m submission was the result of a user gesture. | |
3342 loadFrameRequestWithFormAndValues(request, false, event, m_formAboutToBeSubm
itted.get(), m_formValuesAboutToBeSubmitted); | |
3343 | |
3344 clearRecordedFormValues(); | |
3345 } | |
3346 | |
3347 String FrameLoader::userAgent(const KURL& url) const | |
3348 { | |
3349 return m_client->userAgent(url); | |
3350 } | |
3351 | |
3352 void FrameLoader::tokenizerProcessedData() | |
3353 { | |
3354 // ASSERT(m_frame->page()); | |
3355 // ASSERT(m_frame->document()); | |
3356 | |
3357 checkCompleted(); | |
3358 } | |
3359 | |
3360 void FrameLoader::didTellClientAboutLoad(const String& url) | |
3361 { | |
3362 #if 0 | |
3363 // This hash table is unused in our fork. The only reader is | |
3364 // haveToldClientAboutLoad, and the only caller of that is | |
3365 // loadedResourceFromMemoryCache. We have commented out that location | |
3366 // because we want to send every URL to the client for mixed content | |
3367 // detection. Therefore, this hash table is unused. | |
3368 // | |
3369 // The table stores every URL ever loaded, or which has been attempted to be | |
3370 // loaded by a frame. For some apps like gmail, this can get into the | |
3371 // thousands after it has been running for a while. With Gmail URLs often | |
3372 // being more than 100 characters (and 2-bytes per char in a String), this | |
3373 // can quickly use a lot of memory we don't need. | |
3374 m_urlsClientKnowsAbout.add(url); | |
3375 #endif | |
3376 } | |
3377 | |
3378 bool FrameLoader::haveToldClientAboutLoad(const String& url) | |
3379 { | |
3380 #if 0 | |
3381 // See didTellClientAboutLoad() above for why this is removed in our fork. | |
3382 // This is commented out for consistency only. All lookups will fail anyway. | |
3383 return m_urlsClientKnowsAbout.contains(url); | |
3384 #else | |
3385 return false; | |
3386 #endif | |
3387 } | |
3388 | |
3389 void FrameLoader::handledOnloadEvents() | |
3390 { | |
3391 m_client->dispatchDidHandleOnloadEvents(); | |
3392 } | |
3393 | |
3394 void FrameLoader::frameDetached() | |
3395 { | |
3396 stopAllLoaders(); | |
3397 detachFromParent(); | |
3398 } | |
3399 | |
3400 void FrameLoader::detachFromParent() | |
3401 { | |
3402 RefPtr<Frame> protect(m_frame); | |
3403 | |
3404 closeURL(); | |
3405 stopAllLoaders(); | |
3406 saveScrollPositionAndViewStateToItem(currentHistoryItem()); | |
3407 detachChildren(); | |
3408 | |
3409 if (Page* page = m_frame->page()) | |
3410 page->inspectorController()->frameDetachedFromParent(m_frame); | |
3411 | |
3412 m_client->detachedFromParent2(); | |
3413 setDocumentLoader(0); | |
3414 m_client->detachedFromParent3(); | |
3415 if (Frame* parent = m_frame->tree()->parent()) { | |
3416 parent->tree()->removeChild(m_frame); | |
3417 parent->loader()->scheduleCheckCompleted(); | |
3418 } else { | |
3419 m_frame->setView(0); | |
3420 m_frame->pageDestroyed(); | |
3421 } | |
3422 m_client->detachedFromParent4(); | |
3423 } | |
3424 | |
3425 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainRes
ource, bool alwaysFromRequest) | |
3426 { | |
3427 applyUserAgent(request); | |
3428 | |
3429 if (m_loadType == FrameLoadTypeReload) { | |
3430 request.setCachePolicy(ReloadIgnoringCacheData); | |
3431 request.setHTTPHeaderField("Cache-Control", "max-age=0"); | |
3432 } | |
3433 | |
3434 // Don't set the cookie policy URL if it's already been set. | |
3435 if (request.mainDocumentURL().isEmpty()) { | |
3436 if (mainResource && (isLoadingMainFrame() || alwaysFromRequest)) | |
3437 request.setMainDocumentURL(request.url()); | |
3438 else if (Page* page = m_frame->page()) | |
3439 request.setMainDocumentURL(page->mainFrame()->loader()->url()); | |
3440 } | |
3441 | |
3442 if (mainResource) | |
3443 request.setHTTPAccept("application/xml,application/xhtml+xml,text/html;q
=0.9,text/plain;q=0.8,image/png,*/*;q=0.5"); | |
3444 } | |
3445 | |
3446 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int le
ngth) | |
3447 { | |
3448 if (ArchiveFactory::isArchiveMimeType(loader->response().mimeType())) | |
3449 return; | |
3450 m_client->committedLoad(loader, data, length); | |
3451 } | |
3452 | |
3453 void FrameLoader::loadPostRequest(const ResourceRequest& inRequest, const String
& referrer, const String& frameName, | |
3454 Event* event, PassRefPtr<FormState> prpFormState) | |
3455 { | |
3456 RefPtr<FormState> formState = prpFormState; | |
3457 | |
3458 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag. | |
3459 // This prevents a potential bug which may cause a page with a form that use
s itself | |
3460 // as an action to be returned from the cache without submitting. | |
3461 | |
3462 // FIXME: Where's the code that implements what the comment above says? | |
3463 | |
3464 // Previously when this method was reached, the original FrameLoadRequest ha
d been deconstructed to build a | |
3465 // bunch of parameters that would come in here and then be built back up to
a ResourceRequest. In case | |
3466 // any caller depends on the immutability of the original ResourceRequest, I
'm rebuilding a ResourceRequest | |
3467 // from scratch as it did all along. | |
3468 const KURL& url = inRequest.url(); | |
3469 RefPtr<FormData> formData = inRequest.httpBody(); | |
3470 const String& contentType = inRequest.httpContentType(); | |
3471 | |
3472 ResourceRequest workingResourceRequest(url); | |
3473 addExtraFieldsToRequest(workingResourceRequest, true, true); | |
3474 | |
3475 if (!referrer.isEmpty()) | |
3476 workingResourceRequest.setHTTPReferrer(referrer); | |
3477 workingResourceRequest.setHTTPMethod("POST"); | |
3478 workingResourceRequest.setHTTPBody(formData); | |
3479 workingResourceRequest.setHTTPContentType(contentType); | |
3480 | |
3481 NavigationAction action(url, FrameLoadTypeStandard, true, event); | |
3482 | |
3483 if (!frameName.isEmpty()) { | |
3484 if (Frame* targetFrame = findFrameForNavigation(frameName)) | |
3485 targetFrame->loader()->loadWithNavigationAction(workingResourceReque
st, action, FrameLoadTypeStandard, formState.release()); | |
3486 else | |
3487 checkNewWindowPolicy(action, workingResourceRequest, formState.relea
se(), frameName); | |
3488 } else | |
3489 loadWithNavigationAction(workingResourceRequest, action, FrameLoadTypeSt
andard, formState.release()); | |
3490 } | |
3491 | |
3492 bool FrameLoader::isReloading() const | |
3493 { | |
3494 return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData; | |
3495 } | |
3496 | |
3497 void FrameLoader::loadEmptyDocumentSynchronously() | |
3498 { | |
3499 ResourceRequest request(KURL("")); | |
3500 load(request); | |
3501 } | |
3502 | |
3503 unsigned long FrameLoader::loadResourceSynchronously(const ResourceRequest& requ
est, ResourceError& error, ResourceResponse& response, Vector<char>& data) | |
3504 { | |
3505 // Since this is a subresource, we can load any URL (we ignore the return va
lue). | |
3506 // But we still want to know whether we should hide the referrer or not, so
we call the canLoad method. | |
3507 String referrer = m_outgoingReferrer; | |
3508 if (shouldHideReferrer(request.url(), referrer)) | |
3509 referrer = String(); | |
3510 | |
3511 ResourceRequest initialRequest = request; | |
3512 initialRequest.setTimeoutInterval(10); | |
3513 | |
3514 if (initialRequest.isConditional()) | |
3515 initialRequest.setCachePolicy(ReloadIgnoringCacheData); | |
3516 else | |
3517 initialRequest.setCachePolicy(documentLoader()->request().cachePolicy())
; | |
3518 | |
3519 if (!referrer.isEmpty()) | |
3520 initialRequest.setHTTPReferrer(referrer); | |
3521 | |
3522 if (Page* page = m_frame->page()) | |
3523 initialRequest.setMainDocumentURL(page->mainFrame()->loader()->documentL
oader()->request().url()); | |
3524 initialRequest.setHTTPUserAgent(client()->userAgent(request.url())); | |
3525 | |
3526 unsigned long identifier = 0; | |
3527 ResourceRequest newRequest(initialRequest); | |
3528 requestFromDelegate(newRequest, identifier, error); | |
3529 | |
3530 if (error.isNull()) { | |
3531 ASSERT(!newRequest.isNull()); | |
3532 didTellClientAboutLoad(newRequest.url().string()); | |
3533 | |
3534 #if ENABLE(OFFLINE_WEB_APPLICATIONS) | |
3535 ApplicationCacheResource* resource; | |
3536 if (documentLoader()->shouldLoadResourceFromApplicationCache(newRequest,
resource)) { | |
3537 if (resource) { | |
3538 response = resource->response(); | |
3539 data.append(resource->data()->data(), resource->data()->size
()); | |
3540 } else | |
3541 error = cannotShowURLError(newRequest); | |
3542 } else | |
3543 #endif | |
3544 ResourceHandle::loadResourceSynchronously(newRequest, error, respons
e, data, m_frame); | |
3545 } | |
3546 | |
3547 sendRemainingDelegateMessages(identifier, response, data.size(), error); | |
3548 return identifier; | |
3549 } | |
3550 | |
3551 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, con
st ResourceRequest& clientRequest) | |
3552 { | |
3553 return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLo
ader(), clientRequest); | |
3554 } | |
3555 | |
3556 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clien
tRequest, const ResourceResponse& redirectResponse) | |
3557 { | |
3558 applyUserAgent(clientRequest); | |
3559 dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clie
ntRequest, redirectResponse); | |
3560 } | |
3561 | |
3562 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceRespo
nse& r) | |
3563 { | |
3564 activeDocumentLoader()->addResponse(r); | |
3565 | |
3566 if (Page* page = m_frame->page()) | |
3567 page->progress()->incrementProgress(loader->identifier(), r); | |
3568 dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r
); | |
3569 } | |
3570 | |
3571 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int l
ength, int lengthReceived) | |
3572 { | |
3573 if (Page* page = m_frame->page()) | |
3574 page->progress()->incrementProgress(loader->identifier(), data, length); | |
3575 dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier
(), lengthReceived); | |
3576 } | |
3577 | |
3578 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& err
or) | |
3579 { | |
3580 if (Page* page = m_frame->page()) | |
3581 page->progress()->completeProgress(loader->identifier()); | |
3582 if (!error.isNull()) | |
3583 m_client->dispatchDidFailLoading(loader->documentLoader(), loader->ident
ifier(), error); | |
3584 } | |
3585 | |
3586 const ResourceRequest& FrameLoader::originalRequest() const | |
3587 { | |
3588 return activeDocumentLoader()->originalRequestCopy(); | |
3589 } | |
3590 | |
3591 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isC
omplete) | |
3592 { | |
3593 // Retain because the stop may release the last reference to it. | |
3594 RefPtr<Frame> protect(m_frame); | |
3595 | |
3596 RefPtr<DocumentLoader> loader = activeDocumentLoader(); | |
3597 | |
3598 if (isComplete) { | |
3599 // FIXME: Don't want to do this if an entirely new load is going, so sho
uld check | |
3600 // that both data sources on the frame are either this or nil. | |
3601 stop(); | |
3602 if (m_client->shouldFallBack(error)) | |
3603 handleFallbackContent(); | |
3604 } | |
3605 | |
3606 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) { | |
3607 KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url(
); | |
3608 didNotOpenURL(failedURL); | |
3609 | |
3610 // We might have made a page cache item, but now we're bailing out due t
o an error before we ever | |
3611 // transitioned to the new page (before WebFrameState == commit). The g
oal here is to restore any state | |
3612 // so that the existing view (that wenever got far enough to replace) ca
n continue being used. | |
3613 invalidateCurrentItemCachedPage(); | |
3614 | |
3615 // Call clientRedirectCancelledOrFinished here so that the frame load de
legate is notified that the redirect's | |
3616 // status has changed, if there was a redirect. The frame load delegate
may have saved some state about | |
3617 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fir
eDate:forFrame:. Since we are definitely | |
3618 // not going to use this provisional resource, as it was cancelled, noti
fy the frame load delegate that the redirect | |
3619 // has ended. | |
3620 if (m_sentRedirectNotification) | |
3621 clientRedirectCancelledOrFinished(false); | |
3622 } | |
3623 | |
3624 | |
3625 loader->mainReceivedError(error, isComplete); | |
3626 } | |
3627 | |
3628 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument
, | |
3629 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue) | |
3630 { | |
3631 FrameLoader* loader = static_cast<FrameLoader*>(argument); | |
3632 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue)
; | |
3633 } | |
3634 | |
3635 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequ
est& request, bool shouldContinue) | |
3636 { | |
3637 // FIXME: | |
3638 // some functions check m_quickRedirectComing, and others check for | |
3639 // FrameLoadTypeRedirectWithLockedHistory. | |
3640 bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadType
RedirectWithLockedHistory; | |
3641 m_quickRedirectComing = false; | |
3642 | |
3643 if (!shouldContinue) | |
3644 return; | |
3645 | |
3646 KURL url = request.url(); | |
3647 | |
3648 m_documentLoader->replaceRequestURLForAnchorScroll(url); | |
3649 if (!isRedirect && !shouldTreatURLAsSameAsCurrent(url)) { | |
3650 // NB: must happen after _setURL, since we add based on the current requ
est. | |
3651 // Must also happen before we openURL and displace the scroll position,
since | |
3652 // adding the BF item will save away scroll state. | |
3653 | |
3654 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed
before | |
3655 // it was done, currItem is now set the that slow doc, and prevItem is w
hatever was | |
3656 // before it. Adding the b/f item will bump the slow doc down to prevIt
em, even | |
3657 // though its load is not yet done. I think this all works out OK, for
one because | |
3658 // we have already saved away the scroll and doc state for the long slow
load, | |
3659 // but it's not an obvious case. | |
3660 | |
3661 addHistoryItemForFragmentScroll(); | |
3662 } | |
3663 | |
3664 scrollToAnchor(url); | |
3665 | |
3666 if (!isRedirect) | |
3667 // This will clear previousItem from the rest of the frame tree that did
n't | |
3668 // doing any loading. We need to make a pass on this now, since for anch
or nav | |
3669 // we'll not go through a real load and reach Completed state. | |
3670 checkLoadComplete(); | |
3671 | |
3672 m_client->dispatchDidChangeLocationWithinPage(); | |
3673 m_client->didFinishLoad(); | |
3674 } | |
3675 | |
3676 bool FrameLoader::shouldScrollToAnchor(bool isFormSubmission, FrameLoadType load
Type, const KURL& url) | |
3677 { | |
3678 // Should we do anchor navigation within the existing content? | |
3679 | |
3680 // We don't do this if we are submitting a form, explicitly reloading, | |
3681 // currently displaying a frameset, or if the URL does not have a fragment. | |
3682 // These rules were originally based on what KHTML was doing in KHTMLPart::o
penURL. | |
3683 | |
3684 // FIXME: What about load types other than Standard and Reload? | |
3685 | |
3686 return !isFormSubmission | |
3687 && loadType != FrameLoadTypeReload | |
3688 && loadType != FrameLoadTypeSame | |
3689 && !shouldReload(this->url(), url) | |
3690 // We don't want to just scroll if a link from within a | |
3691 // frameset is trying to reload the frameset into _top. | |
3692 && !m_frame->isFrameSet(); | |
3693 } | |
3694 | |
3695 void FrameLoader::opened() | |
3696 { | |
3697 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirec
t()) | |
3698 updateHistoryForClientRedirect(); | |
3699 | |
3700 if (m_documentLoader->isLoadingFromCachedPage()) { | |
3701 m_frame->document()->didRestoreFromCache(); | |
3702 | |
3703 // Force a layout to update view size and thereby update scrollbars. | |
3704 m_client->forceLayout(); | |
3705 | |
3706 const ResponseVector& responses = m_documentLoader->responses(); | |
3707 size_t count = responses.size(); | |
3708 for (size_t i = 0; i < count; i++) { | |
3709 const ResourceResponse& response = responses[i]; | |
3710 // FIXME: If the WebKit client changes or cancels the request, this
is not respected. | |
3711 ResourceError error; | |
3712 unsigned long identifier; | |
3713 ResourceRequest request(response.url()); | |
3714 requestFromDelegate(request, identifier, error); | |
3715 // FIXME: If we get a resource with more than 2B bytes, this code wo
n't do the right thing. | |
3716 // However, with today's computers and networking speeds, this won't
happen in practice. | |
3717 // Could be an issue with a giant local file. | |
3718 sendRemainingDelegateMessages(identifier, response, static_cast<int>
(response.expectedContentLength()), error); | |
3719 } | |
3720 | |
3721 pageCache()->remove(m_currentHistoryItem.get()); | |
3722 | |
3723 m_documentLoader->setPrimaryLoadComplete(true); | |
3724 | |
3725 // FIXME: Why only this frame and not parent frames? | |
3726 checkLoadCompleteForThisFrame(); | |
3727 } | |
3728 } | |
3729 | |
3730 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const Res
ourceRequest& request, | |
3731 PassRefPtr<FormState> formState, const String& frameName) | |
3732 { | |
3733 m_policyCheck.set(request, formState, frameName, | |
3734 callContinueLoadAfterNewWindowPolicy, this); | |
3735 m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfter
NewWindowPolicy, | |
3736 action, request, formState, frameName); | |
3737 } | |
3738 | |
3739 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy) | |
3740 { | |
3741 PolicyCheck check = m_policyCheck; | |
3742 m_policyCheck.clear(); | |
3743 | |
3744 switch (policy) { | |
3745 case PolicyIgnore: | |
3746 check.clearRequest(); | |
3747 break; | |
3748 case PolicyDownload: | |
3749 m_client->startDownload(check.request()); | |
3750 check.clearRequest(); | |
3751 break; | |
3752 case PolicyUse: | |
3753 break; | |
3754 } | |
3755 | |
3756 check.call(policy == PolicyUse); | |
3757 } | |
3758 | |
3759 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, Document
Loader* loader, | |
3760 PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function,
void* argument) | |
3761 { | |
3762 NavigationAction action = loader->triggeringAction(); | |
3763 if (action.isEmpty()) { | |
3764 action = NavigationAction(request.url(), NavigationTypeOther); | |
3765 loader->setTriggeringAction(action); | |
3766 } | |
3767 | |
3768 // Don't ask more than once for the same request or if we are loading an emp
ty URL. | |
3769 // This avoids confusion on the part of the client. | |
3770 if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!re
quest.isNull() && request.url().isEmpty())) { | |
3771 function(argument, request, 0, true); | |
3772 loader->setLastCheckedRequest(request); | |
3773 return; | |
3774 } | |
3775 | |
3776 // We are always willing to show alternate content for unreachable URLs; | |
3777 // treat it like a reload so it maintains the right state for b/f list. | |
3778 if (loader->substituteData().isValid() && !loader->substituteData().failingU
RL().isEmpty()) { | |
3779 if (isBackForwardLoadType(m_policyLoadType)) | |
3780 m_policyLoadType = FrameLoadTypeReload; | |
3781 function(argument, request, 0, true); | |
3782 return; | |
3783 } | |
3784 | |
3785 loader->setLastCheckedRequest(request); | |
3786 | |
3787 m_policyCheck.set(request, formState.get(), function, argument); | |
3788 | |
3789 m_delegateIsDecidingNavigationPolicy = true; | |
3790 m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfte
rNavigationPolicy, | |
3791 action, request, formState); | |
3792 m_delegateIsDecidingNavigationPolicy = false; | |
3793 } | |
3794 | |
3795 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy) | |
3796 { | |
3797 PolicyCheck check = m_policyCheck; | |
3798 m_policyCheck.clear(); | |
3799 | |
3800 bool shouldContinue = policy == PolicyUse; | |
3801 | |
3802 switch (policy) { | |
3803 case PolicyIgnore: | |
3804 check.clearRequest(); | |
3805 break; | |
3806 case PolicyDownload: | |
3807 m_client->startDownload(check.request()); | |
3808 check.clearRequest(); | |
3809 break; | |
3810 case PolicyUse: { | |
3811 ResourceRequest request(check.request()); | |
3812 | |
3813 if (!m_client->canHandleRequest(request)) { | |
3814 handleUnimplementablePolicy(m_client->cannotShowURLError(check.r
equest())); | |
3815 check.clearRequest(); | |
3816 shouldContinue = false; | |
3817 } | |
3818 break; | |
3819 } | |
3820 } | |
3821 | |
3822 check.call(shouldContinue); | |
3823 } | |
3824 | |
3825 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument, | |
3826 const ResourceRequest& request, PassRefPtr<FormState> formState, bool should
Continue) | |
3827 { | |
3828 FrameLoader* loader = static_cast<FrameLoader*>(argument); | |
3829 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue
); | |
3830 } | |
3831 | |
3832 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& reque
st, PassRefPtr<FormState> formState, bool shouldContinue) | |
3833 { | |
3834 // If we loaded an alternate page to replace an unreachableURL, we'll get in
here with a | |
3835 // nil policyDataSource because loading the alternate page will have passed | |
3836 // through this method already, nested; otherwise, policyDataSource should s
till be set. | |
3837 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableUR
L().isEmpty()); | |
3838 | |
3839 bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isT
argetItem() : false; | |
3840 | |
3841 // Two reasons we can't continue: | |
3842 // 1) Navigation policy delegate said we can't so request is nil. A prima
ry case of this | |
3843 // is the user responding Cancel to the form repost nag sheet. | |
3844 // 2) User responded Cancel to an alert popped up by the before unload ev
ent handler. | |
3845 // The "before unload" event handler runs only for the main frame. | |
3846 bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shou
ldClose()); | |
3847 | |
3848 if (!canContinue) { | |
3849 // If we were waiting for a quick redirect, but the policy delegate deci
ded to ignore it, then we | |
3850 // need to report that the client redirect was cancelled. | |
3851 if (m_quickRedirectComing) | |
3852 clientRedirectCancelledOrFinished(false); | |
3853 | |
3854 setPolicyDocumentLoader(0); | |
3855 | |
3856 // If the navigation request came from the back/forward menu, and we pun
t on it, we have the | |
3857 // problem that we have optimistically moved the b/f cursor already, so
move it back. For sanity, | |
3858 // we only do this when punting a navigation for the target frame or top
-level frame. | |
3859 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_po
licyLoadType)) | |
3860 if (Page* page = m_frame->page()) { | |
3861 Frame* mainFrame = page->mainFrame(); | |
3862 if (HistoryItem* resetItem = mainFrame->loader()->m_currentHisto
ryItem.get()) | |
3863 page->backForwardList()->goToItem(resetItem); | |
3864 } | |
3865 return; | |
3866 } | |
3867 | |
3868 FrameLoadType type = m_policyLoadType; | |
3869 stopAllLoaders(); | |
3870 setProvisionalDocumentLoader(m_policyDocumentLoader.get()); | |
3871 m_loadType = type; | |
3872 setState(FrameStateProvisional); | |
3873 | |
3874 setPolicyDocumentLoader(0); | |
3875 | |
3876 if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage()) | |
3877 return; | |
3878 | |
3879 if (formState) | |
3880 m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubm
itForm, formState); | |
3881 else | |
3882 continueLoadAfterWillSubmitForm(); | |
3883 } | |
3884 | |
3885 | |
3886 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument, | |
3887 const ResourceRequest& request, PassRefPtr<FormState> formState, const Strin
g& frameName, bool shouldContinue) | |
3888 { | |
3889 FrameLoader* loader = static_cast<FrameLoader*>(argument); | |
3890 loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shou
ldContinue); | |
3891 } | |
3892 | |
3893 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& reques
t, | |
3894 PassRefPtr<FormState> formState, const String& frameName, bool shouldContinu
e) | |
3895 { | |
3896 if (!shouldContinue) | |
3897 return; | |
3898 | |
3899 RefPtr<Frame> frame = m_frame; | |
3900 RefPtr<Frame> mainFrame = m_client->dispatchCreatePage(); | |
3901 if (!mainFrame) | |
3902 return; | |
3903 | |
3904 if (frameName != "_blank") | |
3905 mainFrame->tree()->setName(frameName); | |
3906 | |
3907 mainFrame->loader()->setOpenedByDOM(); | |
3908 mainFrame->loader()->m_client->dispatchShow(); | |
3909 mainFrame->loader()->setOpener(frame.get()); | |
3910 mainFrame->loader()->loadWithNavigationAction(request, NavigationAction(), F
rameLoadTypeStandard, formState); | |
3911 } | |
3912 | |
3913 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const
ResourceResponse& response, int length, const ResourceError& error) | |
3914 { | |
3915 if (!response.isNull()) | |
3916 dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response)
; | |
3917 | |
3918 if (length > 0) | |
3919 dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, leng
th); | |
3920 | |
3921 if (error.isNull()) | |
3922 dispatchDidFinishLoading(m_documentLoader.get(), identifier); | |
3923 else | |
3924 m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, err
or); | |
3925 } | |
3926 | |
3927 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& i
dentifier, ResourceError& error) | |
3928 { | |
3929 ASSERT(!request.isNull()); | |
3930 | |
3931 identifier = 0; | |
3932 if (Page* page = m_frame->page()) { | |
3933 identifier = page->progress()->createUniqueIdentifier(); | |
3934 dispatchAssignIdentifierToInitialRequest(identifier, m_documentLoader.ge
t(), request); | |
3935 } | |
3936 | |
3937 ResourceRequest newRequest(request); | |
3938 dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, Reso
urceResponse()); | |
3939 | |
3940 if (newRequest.isNull()) | |
3941 error = cancelledError(request); | |
3942 else | |
3943 error = ResourceError(); | |
3944 | |
3945 request = newRequest; | |
3946 } | |
3947 | |
3948 void FrameLoader::loadedResourceFromMemoryCache(const CachedResource* resource) | |
3949 { | |
3950 ResourceRequest request(resource->url()); | |
3951 const ResourceResponse& response = resource->response(); | |
3952 int length = resource->encodedSize(); | |
3953 | |
3954 if (Page* page = m_frame->page()) | |
3955 page->inspectorController()->didLoadResourceFromMemoryCache(m_documentLo
ader.get(), request, response, length); | |
3956 | |
3957 | |
3958 #if 0 | |
3959 // The following test prevents reporting a resource has been loaded from | |
3960 // the cache as CachedResource.m_sendResourceLoadCallbacks is always false. | |
3961 // Also, haveToldClientAboutLoad() and didTellClientAboutLoad() would cause | |
3962 // dispatchDidLoadResourceFromMemoryCache() to be invoked only the first | |
3963 // time the resource is loaded from the cache. | |
3964 // We want to be notified every time a resource is loaded from the cache | |
3965 // (this is needed to detect mixed-contents), so we removed it. | |
3966 | |
3967 if (!resource->sendResourceLoadCallbacks() || haveToldClientAboutLoad(resour
ce->url())) | |
3968 return; | |
3969 #endif | |
3970 | |
3971 if (m_client->dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(),
request, response, length)) { | |
3972 didTellClientAboutLoad(resource->url()); | |
3973 return; | |
3974 } | |
3975 | |
3976 unsigned long identifier; | |
3977 ResourceError error; | |
3978 ResourceRequest r(request); | |
3979 requestFromDelegate(r, identifier, error); | |
3980 sendRemainingDelegateMessages(identifier, response, length, error); | |
3981 | |
3982 didTellClientAboutLoad(resource->url()); | |
3983 } | |
3984 | |
3985 void FrameLoader::applyUserAgent(ResourceRequest& request) | |
3986 { | |
3987 String userAgent = client()->userAgent(request.url()); | |
3988 ASSERT(!userAgent.isNull()); | |
3989 request.setHTTPUserAgent(userAgent); | |
3990 } | |
3991 | |
3992 bool FrameLoader::canGoBackOrForward(int distance) const | |
3993 { | |
3994 if (Page* page = m_frame->page()) { | |
3995 if (distance == 0) | |
3996 return true; | |
3997 if (distance > 0 && distance <= page->backForwardList()->forwardListCoun
t()) | |
3998 return true; | |
3999 if (distance < 0 && -distance <= page->backForwardList()->backListCount(
)) | |
4000 return true; | |
4001 } | |
4002 return false; | |
4003 } | |
4004 | |
4005 int FrameLoader::getHistoryLength() | |
4006 { | |
4007 if (Page* page = m_frame->page()) | |
4008 return page->backForwardList()->backListCount() + 1; | |
4009 return 0; | |
4010 } | |
4011 | |
4012 KURL FrameLoader::historyURL(int distance) | |
4013 { | |
4014 if (Page* page = m_frame->page()) { | |
4015 BackForwardList* list = page->backForwardList(); | |
4016 HistoryItem* item = list->itemAtIndex(distance); | |
4017 if (!item) { | |
4018 if (distance > 0) { | |
4019 int forwardListCount = list->forwardListCount(); | |
4020 if (forwardListCount > 0) | |
4021 item = list->itemAtIndex(forwardListCount); | |
4022 } else { | |
4023 int backListCount = list->backListCount(); | |
4024 if (backListCount > 0) | |
4025 item = list->itemAtIndex(-backListCount); | |
4026 } | |
4027 } | |
4028 if (item) | |
4029 return item->url(); | |
4030 } | |
4031 return KURL(); | |
4032 } | |
4033 | |
4034 void FrameLoader::addHistoryItemForFragmentScroll() | |
4035 { | |
4036 addBackForwardItemClippedAtTarget(false); | |
4037 } | |
4038 | |
4039 bool FrameLoader::loadProvisionalItemFromCachedPage() | |
4040 { | |
4041 RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.ge
t()); | |
4042 if (!cachedPage || !cachedPage->document()) | |
4043 return false; | |
4044 provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release()); | |
4045 return true; | |
4046 } | |
4047 | |
4048 void FrameLoader::cachePageForHistoryItem(HistoryItem* item) | |
4049 { | |
4050 if (Page* page = m_frame->page()) { | |
4051 RefPtr<CachedPage> cachedPage = CachedPage::create(page); | |
4052 cachedPage->setTimeStampToNow(); | |
4053 cachedPage->setDocumentLoader(documentLoader()); | |
4054 m_client->savePlatformDataToCachedPage(cachedPage.get()); | |
4055 | |
4056 pageCache()->add(item, cachedPage.release()); | |
4057 } | |
4058 } | |
4059 | |
4060 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& url) const | |
4061 { | |
4062 if (!m_currentHistoryItem) | |
4063 return false; | |
4064 return url == m_currentHistoryItem->url() || url == m_currentHistoryItem->or
iginalURL(); | |
4065 } | |
4066 | |
4067 PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal) | |
4068 { | |
4069 DocumentLoader* docLoader = documentLoader(); | |
4070 | |
4071 KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL(); | |
4072 | |
4073 KURL url; | |
4074 KURL originalURL; | |
4075 | |
4076 if (!unreachableURL.isEmpty()) { | |
4077 url = unreachableURL; | |
4078 originalURL = unreachableURL; | |
4079 } else { | |
4080 originalURL = docLoader ? docLoader->originalURL() : KURL(); | |
4081 if (useOriginal) | |
4082 url = originalURL; | |
4083 else if (docLoader) | |
4084 url = docLoader->requestURL(); | |
4085 } | |
4086 | |
4087 LOG(History, "WebCoreHistory: Creating item for %s", url.string().ascii().da
ta()); | |
4088 | |
4089 // Frames that have never successfully loaded any content | |
4090 // may have no URL at all. Currently our history code can't | |
4091 // deal with such things, so we nip that in the bud here. | |
4092 // Later we may want to learn to live with nil for URL. | |
4093 // See bug 3368236 and related bugs for more information. | |
4094 if (url.isEmpty()) | |
4095 url = blankURL(); | |
4096 if (originalURL.isEmpty()) | |
4097 originalURL = blankURL(); | |
4098 | |
4099 Frame* parentFrame = m_frame->tree()->parent(); | |
4100 String parent = parentFrame ? parentFrame->tree()->name() : ""; | |
4101 String title = docLoader ? docLoader->title() : ""; | |
4102 | |
4103 RefPtr<HistoryItem> item = HistoryItem::create(url, m_frame->tree()->name(),
parent, title); | |
4104 item->setOriginalURLString(originalURL.string()); | |
4105 | |
4106 // Save form state if this is a POST | |
4107 if (docLoader) { | |
4108 if (useOriginal) | |
4109 item->setFormInfoFromRequest(docLoader->originalRequest()); | |
4110 else | |
4111 item->setFormInfoFromRequest(docLoader->request()); | |
4112 } | |
4113 | |
4114 // Set the item for which we will save document state | |
4115 m_previousHistoryItem = m_currentHistoryItem; | |
4116 m_currentHistoryItem = item; | |
4117 | |
4118 return item.release(); | |
4119 } | |
4120 | |
4121 void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip) | |
4122 { | |
4123 Page* page = m_frame->page(); | |
4124 if (!page) | |
4125 return; | |
4126 | |
4127 if (documentLoader()->urlForHistory().isEmpty()) | |
4128 return; | |
4129 | |
4130 Frame* mainFrame = page->mainFrame(); | |
4131 ASSERT(mainFrame); | |
4132 FrameLoader* frameLoader = mainFrame->loader(); | |
4133 | |
4134 if (!frameLoader->m_didPerformFirstNavigation && page->backForwardList()->en
tries().size() == 1) { | |
4135 frameLoader->m_didPerformFirstNavigation = true; | |
4136 m_client->didPerformFirstNavigation(); | |
4137 } | |
4138 | |
4139 RefPtr<HistoryItem> item = frameLoader->createHistoryItemTree(m_frame, doCli
p); | |
4140 LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame
%s", item.get(), documentLoader()->url().string().ascii().data()); | |
4141 page->backForwardList()->addItem(item); | |
4142 } | |
4143 | |
4144 PassRefPtr<HistoryItem> FrameLoader::createHistoryItemTree(Frame* targetFrame, b
ool clipAtTarget) | |
4145 { | |
4146 RefPtr<HistoryItem> bfItem = createHistoryItem(m_frame->tree()->parent() ? t
rue : false); | |
4147 if (m_previousHistoryItem) | |
4148 saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get()); | |
4149 if (!(clipAtTarget && m_frame == targetFrame)) { | |
4150 // save frame state for items that aren't loading (khtml doesn't save th
ose) | |
4151 saveDocumentState(); | |
4152 for (Frame* child = m_frame->tree()->firstChild(); child; child = child-
>tree()->nextSibling()) { | |
4153 FrameLoader* childLoader = child->loader(); | |
4154 bool hasChildLoaded = childLoader->frameHasLoaded(); | |
4155 | |
4156 // If the child is a frame corresponding to an <object> element that
never loaded, | |
4157 // we don't want to create a history item, because that causes fallb
ack content | |
4158 // to be ignored on reload. | |
4159 | |
4160 if (!(!hasChildLoaded && childLoader->isHostedByObjectElement())) | |
4161 bfItem->addChildItem(childLoader->createHistoryItemTree(targetFr
ame, clipAtTarget)); | |
4162 } | |
4163 } | |
4164 if (m_frame == targetFrame) | |
4165 bfItem->setIsTargetItem(true); | |
4166 return bfItem; | |
4167 } | |
4168 | |
4169 Frame* FrameLoader::findFrameForNavigation(const AtomicString& name) | |
4170 { | |
4171 Frame* frame = m_frame->tree()->find(name); | |
4172 if (shouldAllowNavigation(frame)) | |
4173 return frame; | |
4174 return 0; | |
4175 } | |
4176 | |
4177 void FrameLoader::saveScrollPositionAndViewStateToItem(HistoryItem* item) | |
4178 { | |
4179 if (!item || !m_frame->view()) | |
4180 return; | |
4181 | |
4182 item->setScrollPoint(IntPoint(m_frame->view()->contentsX(), m_frame->view()-
>contentsY())); | |
4183 // FIXME: It would be great to work out a way to put this code in WebCore in
stead of calling through to the client. | |
4184 m_client->saveViewStateToItem(item); | |
4185 } | |
4186 | |
4187 /* | |
4188 There is a race condition between the layout and load completion that affects r
estoring the scroll position. | |
4189 We try to restore the scroll position at both the first layout and upon load co
mpletion. | |
4190 | |
4191 1) If first layout happens before the load completes, we want to restore the sc
roll position then so that the | |
4192 first time we draw the page is already scrolled to the right place, instead of
starting at the top and later | |
4193 jumping down. It is possible that the old scroll position is past the part of
the doc laid out so far, in | |
4194 which case the restore silent fails and we will fix it in when we try to restor
e on doc completion. | |
4195 2) If the layout happens after the load completes, the attempt to restore at lo
ad completion time silently | |
4196 fails. We then successfully restore it when the layout happens. | |
4197 */ | |
4198 void FrameLoader::restoreScrollPositionAndViewState() | |
4199 { | |
4200 if (!m_committedFirstRealDocumentLoad) | |
4201 return; | |
4202 | |
4203 ASSERT(m_currentHistoryItem); | |
4204 | |
4205 // FIXME: As the ASSERT attests, it seems we should always have a currentIte
m here. | |
4206 // One counterexample is <rdar://problem/4917290> | |
4207 // For now, to cover this issue in release builds, there is no technical har
m to returning | |
4208 // early and from a user standpoint - as in the above radar - the previous p
age load failed | |
4209 // so there *is* no scroll or view state to restore! | |
4210 if (!m_currentHistoryItem) | |
4211 return; | |
4212 | |
4213 // FIXME: It would be great to work out a way to put this code in WebCore in
stead of calling | |
4214 // through to the client. It's currently used only for the PDF view on Mac. | |
4215 m_client->restoreViewState(); | |
4216 | |
4217 if (FrameView* view = m_frame->view()) | |
4218 if (!view->wasScrolledByUser()) { | |
4219 const IntPoint& scrollPoint = m_currentHistoryItem->scrollPoint(); | |
4220 view->setContentsPos(scrollPoint.x(), scrollPoint.y()); | |
4221 } | |
4222 } | |
4223 | |
4224 void FrameLoader::invalidateCurrentItemCachedPage() | |
4225 { | |
4226 // When we are pre-commit, the currentItem is where the pageCache data resid
es | |
4227 CachedPage* cachedPage = pageCache()->get(m_currentHistoryItem.get()); | |
4228 | |
4229 // FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in
RenderFlow::detach | |
4230 // Somehow the PageState object is not properly updated, and is holding onto
a stale document. | |
4231 // Both Xcode and FileMaker see this crash, Safari does not. | |
4232 | |
4233 ASSERT(!cachedPage || cachedPage->document() == m_frame->document()); | |
4234 if (cachedPage && cachedPage->document() == m_frame->document()) { | |
4235 cachedPage->document()->setInPageCache(false); | |
4236 cachedPage->clear(); | |
4237 } | |
4238 | |
4239 if (cachedPage) | |
4240 pageCache()->remove(m_currentHistoryItem.get()); | |
4241 } | |
4242 | |
4243 void FrameLoader::saveDocumentState() | |
4244 { | |
4245 if (m_creatingInitialEmptyDocument) | |
4246 return; | |
4247 | |
4248 // For a standard page load, we will have a previous item set, which will be
used to | |
4249 // store the form state. However, in some cases we will have no previous it
em, and | |
4250 // the current item is the right place to save the state. One example is wh
en we | |
4251 // detach a bunch of frames because we are navigating from a site with frame
s to | |
4252 // another site. Another is when saving the frame state of a frame that is
not the | |
4253 // target of the current navigation (if we even decide to save with that gra
nularity). | |
4254 | |
4255 // Because of previousItem's "masking" of currentItem for this purpose, it's
important | |
4256 // that previousItem be cleared at the end of a page transition. We leverag
e the | |
4257 // checkLoadComplete recursion to achieve this goal. | |
4258 | |
4259 HistoryItem* item = m_previousHistoryItem ? m_previousHistoryItem.get() : m_
currentHistoryItem.get(); | |
4260 if (!item) | |
4261 return; | |
4262 | |
4263 Document* document = m_frame->document(); | |
4264 ASSERT(document); | |
4265 | |
4266 if (document && item->isCurrentDocument(document)) { | |
4267 LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree
()->name().string().utf8().data(), item); | |
4268 item->setDocumentState(document->formElementsState()); | |
4269 } | |
4270 } | |
4271 | |
4272 // Loads content into this frame, as specified by history item | |
4273 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType) | |
4274 { | |
4275 if (!m_frame->page()) | |
4276 return; | |
4277 | |
4278 KURL itemURL = item->url(); | |
4279 KURL itemOriginalURL = item->originalURL(); | |
4280 KURL currentURL; | |
4281 if (documentLoader()) | |
4282 currentURL = documentLoader()->url(); | |
4283 RefPtr<FormData> formData = item->formData(); | |
4284 | |
4285 // Are we navigating to an anchor within the page? | |
4286 // Note if we have child frames we do a real reload, since the child frames
might not | |
4287 // match our current frame structure, or they might not have the right conte
nt. We could | |
4288 // check for all that as an additional optimization. | |
4289 // We also do not do anchor-style navigation if we're posting a form. | |
4290 | |
4291 if (!formData && urlsMatchItem(item)) { | |
4292 // Must do this maintenance here, since we don't go through a real page
reload | |
4293 saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); | |
4294 | |
4295 if (FrameView* view = m_frame->view()) | |
4296 view->setWasScrolledByUser(false); | |
4297 | |
4298 m_currentHistoryItem = item; | |
4299 | |
4300 // FIXME: Form state might need to be saved here too. | |
4301 | |
4302 // We always call scrollToAnchor here, even if the URL doesn't have an | |
4303 // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-
date. | |
4304 scrollToAnchor(item->url()); | |
4305 | |
4306 // must do this maintenance here, since we don't go through a real page
reload | |
4307 restoreScrollPositionAndViewState(); | |
4308 | |
4309 // Fake the URL change by updating the data source's request. This will
no longer | |
4310 // be necessary if we do the better fix described above. | |
4311 documentLoader()->replaceRequestURLForAnchorScroll(itemURL); | |
4312 | |
4313 m_client->dispatchDidChangeLocationWithinPage(); | |
4314 | |
4315 // FrameLoaderClient::didFinishLoad() tells the internal load delegate t
he load finished with no error | |
4316 m_client->didFinishLoad(); | |
4317 } else { | |
4318 // Remember this item so we can traverse any child items as child frames
load | |
4319 m_provisionalHistoryItem = item; | |
4320 | |
4321 bool inPageCache = false; | |
4322 | |
4323 // Check if we'll be using the page cache. We only use the page cache | |
4324 // if one exists and it is less than _backForwardCacheExpirationInterval | |
4325 // seconds old. If the cache is expired it gets flushed here. | |
4326 if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) { | |
4327 double interval = currentTime() - cachedPage->timeStamp(); | |
4328 | |
4329 // FIXME: 1800 should not be hardcoded, it should come from | |
4330 // WebKitBackForwardCacheExpirationIntervalKey in WebKit. | |
4331 // Or we should remove WebKitBackForwardCacheExpirationIntervalKey. | |
4332 if (interval <= 1800) { | |
4333 loadWithDocumentLoader(cachedPage->documentLoader(), loadType, 0
); | |
4334 inPageCache = true; | |
4335 } else { | |
4336 LOG(PageCache, "Not restoring page for %s from back/forward cach
e because cache entry has expired", m_provisionalHistoryItem->url().string().asc
ii().data()); | |
4337 pageCache()->remove(item); | |
4338 } | |
4339 } | |
4340 | |
4341 if (!inPageCache) { | |
4342 ResourceRequest request(itemURL); | |
4343 | |
4344 addExtraFieldsToRequest(request, true, formData); | |
4345 | |
4346 // If this was a repost that failed the page cache, we might try to
repost the form. | |
4347 NavigationAction action; | |
4348 if (formData) { | |
4349 | |
4350 formData->generateFiles(m_frame->page()->chrome()->client()); | |
4351 | |
4352 request.setHTTPMethod("POST"); | |
4353 request.setHTTPReferrer(item->formReferrer()); | |
4354 request.setHTTPBody(formData); | |
4355 request.setHTTPContentType(item->formContentType()); | |
4356 | |
4357 // FIXME: Slight hack to test if the NSURL cache contains the pa
ge we're going to. | |
4358 // We want to know this before talking to the policy delegate, s
ince it affects whether | |
4359 // we show the DoYouReallyWantToRepost nag. | |
4360 // | |
4361 // This trick has a small bug (3123893) where we might find a ca
che hit, but then | |
4362 // have the item vanish when we try to use it in the ensuing nav
. This should be | |
4363 // extremely rare, but in that case the user will get an error o
n the navigation. | |
4364 | |
4365 if (ResourceHandle::willLoadFromCache(request)) | |
4366 action = NavigationAction(itemURL, loadType, false); | |
4367 else { | |
4368 request.setCachePolicy(ReloadIgnoringCacheData); | |
4369 action = NavigationAction(itemURL, NavigationTypeFormResubmi
tted); | |
4370 } | |
4371 } else { | |
4372 switch (loadType) { | |
4373 case FrameLoadTypeReload: | |
4374 request.setCachePolicy(ReloadIgnoringCacheData); | |
4375 break; | |
4376 case FrameLoadTypeBack: | |
4377 case FrameLoadTypeForward: | |
4378 case FrameLoadTypeIndexedBackForward: | |
4379 if (itemURL.protocol() != "https") | |
4380 request.setCachePolicy(ReturnCacheDataElseLoad); | |
4381 break; | |
4382 case FrameLoadTypeStandard: | |
4383 case FrameLoadTypeRedirectWithLockedHistory: | |
4384 // no-op: leave as protocol default | |
4385 // FIXME: I wonder if we ever hit this case | |
4386 break; | |
4387 case FrameLoadTypeSame: | |
4388 case FrameLoadTypeReloadAllowingStaleData: | |
4389 default: | |
4390 ASSERT_NOT_REACHED(); | |
4391 } | |
4392 | |
4393 action = NavigationAction(itemOriginalURL, loadType, false); | |
4394 } | |
4395 | |
4396 loadWithNavigationAction(request, action, loadType, 0); | |
4397 } | |
4398 } | |
4399 } | |
4400 | |
4401 // Walk the frame tree and ensure that the URLs match the URLs in the item. | |
4402 bool FrameLoader::urlsMatchItem(HistoryItem* item) const | |
4403 { | |
4404 const KURL& currentURL = documentLoader()->url(); | |
4405 if (!equalIgnoringRef(currentURL, item->url())) | |
4406 return false; | |
4407 | |
4408 const HistoryItemVector& childItems = item->children(); | |
4409 | |
4410 unsigned size = childItems.size(); | |
4411 for (unsigned i = 0; i < size; ++i) { | |
4412 Frame* childFrame = m_frame->tree()->child(childItems[i]->target()); | |
4413 if (childFrame && !childFrame->loader()->urlsMatchItem(childItems[i].get
())) | |
4414 return false; | |
4415 } | |
4416 | |
4417 return true; | |
4418 } | |
4419 | |
4420 // Main funnel for navigating to a previous location (back/forward, non-search s
nap-back) | |
4421 // This includes recursion to handle loading into framesets properly | |
4422 void FrameLoader::goToItem(HistoryItem* targetItem, FrameLoadType type) | |
4423 { | |
4424 ASSERT(!m_frame->tree()->parent()); | |
4425 | |
4426 // shouldGoToHistoryItem is a private delegate method. This is needed to fix
: | |
4427 // <rdar://problem/3951283> can view pages from the back/forward cache that
should be disallowed by Parental Controls | |
4428 // Ultimately, history item navigations should go through the policy delegat
e. That's covered in: | |
4429 // <rdar://problem/3979539> back/forward cache navigations should consult po
licy delegate | |
4430 Page* page = m_frame->page(); | |
4431 if (!page) | |
4432 return; | |
4433 if (!m_client->shouldGoToHistoryItem(targetItem)) | |
4434 return; | |
4435 | |
4436 // Set the BF cursor before commit, which lets the user quickly click back/f
orward again. | |
4437 // - plus, it only makes sense for the top level of the operation through th
e frametree, | |
4438 // as opposed to happening for some/one of the page commits that might happe
n soon | |
4439 BackForwardList* bfList = page->backForwardList(); | |
4440 HistoryItem* currentItem = bfList->currentItem(); | |
4441 bfList->goToItem(targetItem); | |
4442 recursiveGoToItem(targetItem, currentItem, type); | |
4443 } | |
4444 | |
4445 // The general idea here is to traverse the frame tree and the item tree in para
llel, | |
4446 // tracking whether each frame already has the content the item requests. If th
ere is | |
4447 // a match (by URL), we just restore scroll position and recurse. Otherwise we
must | |
4448 // reload that frame, and all its kids. | |
4449 void FrameLoader::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, Fr
ameLoadType type) | |
4450 { | |
4451 ASSERT(item); | |
4452 ASSERT(fromItem); | |
4453 | |
4454 KURL itemURL = item->url(); | |
4455 KURL currentURL; | |
4456 if (documentLoader()) | |
4457 currentURL = documentLoader()->url(); | |
4458 | |
4459 // Always reload the target frame of the item we're going to. This ensures
that we will | |
4460 // do -some- load for the transition, which means a proper notification will
be posted | |
4461 // to the app. | |
4462 // The exact URL has to match, including fragment. We want to go through th
e _load | |
4463 // method, even if to do a within-page navigation. | |
4464 // The current frame tree and the frame tree snapshot in the item have to ma
tch. | |
4465 if (!item->isTargetItem() && | |
4466 itemURL == currentURL && | |
4467 ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_fr
ame->tree()->name() == item->target()) && | |
4468 childFramesMatchItem(item)) | |
4469 { | |
4470 // This content is good, so leave it alone and look for children that ne
ed reloading | |
4471 // Save form state (works from currentItem, since prevItem is nil) | |
4472 ASSERT(!m_previousHistoryItem); | |
4473 saveDocumentState(); | |
4474 saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); | |
4475 | |
4476 if (FrameView* view = m_frame->view()) | |
4477 view->setWasScrolledByUser(false); | |
4478 | |
4479 m_currentHistoryItem = item; | |
4480 | |
4481 // Restore form state (works from currentItem) | |
4482 restoreDocumentState(); | |
4483 | |
4484 // Restore the scroll position (we choose to do this rather than going b
ack to the anchor point) | |
4485 restoreScrollPositionAndViewState(); | |
4486 | |
4487 const HistoryItemVector& childItems = item->children(); | |
4488 | |
4489 int size = childItems.size(); | |
4490 for (int i = 0; i < size; ++i) { | |
4491 String childName = childItems[i]->target(); | |
4492 HistoryItem* fromChildItem = fromItem->childItemWithName(childName); | |
4493 ASSERT(fromChildItem || fromItem->isTargetItem()); | |
4494 Frame* childFrame = m_frame->tree()->child(childName); | |
4495 ASSERT(childFrame); | |
4496 childFrame->loader()->recursiveGoToItem(childItems[i].get(), fromChi
ldItem, type); | |
4497 } | |
4498 } else { | |
4499 loadItem(item, type); | |
4500 } | |
4501 } | |
4502 | |
4503 // helper method that determines whether the subframes described by the item's s
ubitems | |
4504 // match our own current frameset | |
4505 bool FrameLoader::childFramesMatchItem(HistoryItem* item) const | |
4506 { | |
4507 const HistoryItemVector& childItems = item->children(); | |
4508 if (childItems.size() != m_frame->tree()->childCount()) | |
4509 return false; | |
4510 | |
4511 unsigned size = childItems.size(); | |
4512 for (unsigned i = 0; i < size; ++i) | |
4513 if (!m_frame->tree()->child(childItems[i]->target())) | |
4514 return false; | |
4515 | |
4516 // Found matches for all item targets | |
4517 return true; | |
4518 } | |
4519 | |
4520 // There are 3 things you might think of as "history", all of which are handled
by these functions. | |
4521 // | |
4522 // 1) Back/forward: The m_currentHistoryItem is part of this mechanism. | |
4523 // 2) Global history: Handled by the client. | |
4524 // 3) Visited links: Handled by the PageGroup. | |
4525 | |
4526 void FrameLoader::updateHistoryForStandardLoad() | |
4527 { | |
4528 LOG(History, "WebCoreHistory: Updating History for Standard Load in frame %s
", documentLoader()->url().string().ascii().data()); | |
4529 | |
4530 Settings* settings = m_frame->settings(); | |
4531 bool needPrivacy = !settings || settings->privateBrowsingEnabled(); | |
4532 const KURL& historyURL = documentLoader()->urlForHistory(); | |
4533 | |
4534 // If the navigation occured during load and this is a subframe, update the
current | |
4535 // back/forward item rather than adding a new one and don't add the new URL
to global | |
4536 // history at all. But do add it to visited links. <rdar://problem/5333496> | |
4537 bool frameNavigationDuringLoad = false; | |
4538 if (m_navigationDuringLoad) { | |
4539 HTMLFrameOwnerElement* owner = m_frame->ownerElement(); | |
4540 frameNavigationDuringLoad = owner && !owner->createdByParser(); | |
4541 m_navigationDuringLoad = false; | |
4542 } | |
4543 | |
4544 if (!frameNavigationDuringLoad && !documentLoader()->isClientRedirect()) { | |
4545 if (!historyURL.isEmpty()) { | |
4546 addBackForwardItemClippedAtTarget(true); | |
4547 if (!needPrivacy) | |
4548 m_client->updateGlobalHistory(historyURL); | |
4549 } | |
4550 } else if (documentLoader()->unreachableURL().isEmpty() && m_currentHistoryI
tem) { | |
4551 m_currentHistoryItem->setURL(documentLoader()->url()); | |
4552 m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->request()
); | |
4553 } | |
4554 | |
4555 if (!historyURL.isEmpty() && !needPrivacy) { | |
4556 if (Page* page = m_frame->page()) | |
4557 page->group().addVisitedLink(historyURL); | |
4558 } | |
4559 } | |
4560 | |
4561 void FrameLoader::updateHistoryForClientRedirect() | |
4562 { | |
4563 #if !LOG_DISABLED | |
4564 if (documentLoader()) | |
4565 LOG(History, "WebCoreHistory: Updating History for client redirect in fr
ame %s", documentLoader()->title().utf8().data()); | |
4566 #endif | |
4567 | |
4568 // Clear out form data so we don't try to restore it into the incoming page.
Must happen after | |
4569 // webcore has closed the URL and saved away the form state. | |
4570 if (m_currentHistoryItem) { | |
4571 m_currentHistoryItem->clearDocumentState(); | |
4572 m_currentHistoryItem->clearScrollPoint(); | |
4573 } | |
4574 | |
4575 Settings* settings = m_frame->settings(); | |
4576 bool needPrivacy = !settings || settings->privateBrowsingEnabled(); | |
4577 const KURL& historyURL = documentLoader()->urlForHistory(); | |
4578 | |
4579 if (!historyURL.isEmpty() && !needPrivacy) { | |
4580 if (Page* page = m_frame->page()) | |
4581 page->group().addVisitedLink(historyURL); | |
4582 } | |
4583 } | |
4584 | |
4585 void FrameLoader::updateHistoryForBackForwardNavigation() | |
4586 { | |
4587 #if !LOG_DISABLED | |
4588 if (documentLoader()) | |
4589 LOG(History, "WebCoreHistory: Updating History for back/forward navigati
on in frame %s", documentLoader()->title().utf8().data()); | |
4590 #endif | |
4591 | |
4592 // Must grab the current scroll position before disturbing it | |
4593 saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get()); | |
4594 } | |
4595 | |
4596 void FrameLoader::updateHistoryForReload() | |
4597 { | |
4598 #if !LOG_DISABLED | |
4599 if (documentLoader()) | |
4600 LOG(History, "WebCoreHistory: Updating History for reload in frame %s",
documentLoader()->title().utf8().data()); | |
4601 #endif | |
4602 | |
4603 if (m_currentHistoryItem) { | |
4604 pageCache()->remove(m_currentHistoryItem.get()); | |
4605 | |
4606 if (loadType() == FrameLoadTypeReload) | |
4607 saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get()); | |
4608 | |
4609 // Sometimes loading a page again leads to a different result because of
cookies. Bugzilla 4072 | |
4610 if (documentLoader()->unreachableURL().isEmpty()) | |
4611 m_currentHistoryItem->setURL(documentLoader()->requestURL()); | |
4612 } | |
4613 } | |
4614 | |
4615 void FrameLoader::updateHistoryForRedirectWithLockedHistory() | |
4616 { | |
4617 #if !LOG_DISABLED | |
4618 if (documentLoader()) | |
4619 LOG(History, "WebCoreHistory: Updating History for internal load in fram
e %s", documentLoader()->title().utf8().data()); | |
4620 #endif | |
4621 | |
4622 Settings* settings = m_frame->settings(); | |
4623 bool needPrivacy = !settings || settings->privateBrowsingEnabled(); | |
4624 const KURL& historyURL = documentLoader()->urlForHistory(); | |
4625 | |
4626 if (documentLoader()->isClientRedirect()) { | |
4627 if (!m_currentHistoryItem && !m_frame->tree()->parent()) { | |
4628 addBackForwardItemClippedAtTarget(true); | |
4629 if (!needPrivacy && !historyURL.isEmpty()) | |
4630 m_client->updateGlobalHistory(historyURL); | |
4631 } | |
4632 if (m_currentHistoryItem) { | |
4633 m_currentHistoryItem->setURL(documentLoader()->url()); | |
4634 m_currentHistoryItem->setFormInfoFromRequest(documentLoader()->reque
st()); | |
4635 } | |
4636 } else { | |
4637 Frame* parentFrame = m_frame->tree()->parent(); | |
4638 if (parentFrame && parentFrame->loader()->m_currentHistoryItem) | |
4639 parentFrame->loader()->m_currentHistoryItem->addChildItem(createHist
oryItem(true)); | |
4640 } | |
4641 | |
4642 if (!historyURL.isEmpty() && !needPrivacy) { | |
4643 if (Page* page = m_frame->page()) | |
4644 page->group().addVisitedLink(historyURL); | |
4645 } | |
4646 } | |
4647 | |
4648 void FrameLoader::updateHistoryForCommit() | |
4649 { | |
4650 #if !LOG_DISABLED | |
4651 if (documentLoader()) | |
4652 LOG(History, "WebCoreHistory: Updating History for commit in frame %s",
documentLoader()->title().utf8().data()); | |
4653 #endif | |
4654 FrameLoadType type = loadType(); | |
4655 if (isBackForwardLoadType(type) || | |
4656 (type == FrameLoadTypeReload && !provisionalDocumentLoader()->unreachabl
eURL().isEmpty())) { | |
4657 // Once committed, we want to use current item for saving DocState, and | |
4658 // the provisional item for restoring state. | |
4659 // Note previousItem must be set before we close the URL, which will | |
4660 // happen when the data source is made non-provisional below | |
4661 m_previousHistoryItem = m_currentHistoryItem; | |
4662 ASSERT(m_provisionalHistoryItem); | |
4663 m_currentHistoryItem = m_provisionalHistoryItem; | |
4664 m_provisionalHistoryItem = 0; | |
4665 } | |
4666 } | |
4667 | |
4668 void FrameLoader::updateHistoryForAnchorScroll() | |
4669 { | |
4670 if (m_URL.isEmpty()) | |
4671 return; | |
4672 | |
4673 Settings* settings = m_frame->settings(); | |
4674 if (!settings || settings->privateBrowsingEnabled()) | |
4675 return; | |
4676 | |
4677 Page* page = m_frame->page(); | |
4678 if (!page) | |
4679 return; | |
4680 | |
4681 page->group().addVisitedLink(m_URL); | |
4682 } | |
4683 | |
4684 // Walk the frame tree, telling all frames to save their form state into their c
urrent | |
4685 // history item. | |
4686 void FrameLoader::saveDocumentAndScrollState() | |
4687 { | |
4688 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_fr
ame)) { | |
4689 frame->loader()->saveDocumentState(); | |
4690 frame->loader()->saveScrollPositionAndViewStateToItem(frame->loader()->c
urrentHistoryItem()); | |
4691 } | |
4692 } | |
4693 | |
4694 // FIXME: These 6 setter/getters are here for a dwindling number of users in Web
Kit, WebFrame | |
4695 // being the primary one. After they're no longer needed there, they can be rem
oved! | |
4696 HistoryItem* FrameLoader::currentHistoryItem() | |
4697 { | |
4698 return m_currentHistoryItem.get(); | |
4699 } | |
4700 | |
4701 HistoryItem* FrameLoader::previousHistoryItem() | |
4702 { | |
4703 return m_previousHistoryItem.get(); | |
4704 } | |
4705 | |
4706 HistoryItem* FrameLoader::provisionalHistoryItem() | |
4707 { | |
4708 return m_provisionalHistoryItem.get(); | |
4709 } | |
4710 | |
4711 void FrameLoader::setCurrentHistoryItem(PassRefPtr<HistoryItem> item) | |
4712 { | |
4713 m_currentHistoryItem = item; | |
4714 } | |
4715 | |
4716 void FrameLoader::setPreviousHistoryItem(PassRefPtr<HistoryItem> item) | |
4717 { | |
4718 m_previousHistoryItem = item; | |
4719 } | |
4720 | |
4721 void FrameLoader::setProvisionalHistoryItem(PassRefPtr<HistoryItem> item) | |
4722 { | |
4723 m_provisionalHistoryItem = item; | |
4724 } | |
4725 | |
4726 void FrameLoader::setMainDocumentError(DocumentLoader* loader, const ResourceErr
or& error) | |
4727 { | |
4728 m_client->setMainDocumentError(loader, error); | |
4729 } | |
4730 | |
4731 void FrameLoader::mainReceivedCompleteError(DocumentLoader* loader, const Resour
ceError& error) | |
4732 { | |
4733 loader->setPrimaryLoadComplete(true); | |
4734 m_client->dispatchDidLoadMainResource(activeDocumentLoader()); | |
4735 checkCompleted(); | |
4736 if (m_frame->page()) | |
4737 checkLoadComplete(); | |
4738 } | |
4739 | |
4740 void FrameLoader::mainReceivedError(const ResourceError& error, bool isComplete) | |
4741 { | |
4742 activeDocumentLoader()->mainReceivedError(error, isComplete); | |
4743 } | |
4744 | |
4745 ResourceError FrameLoader::cancelledError(const ResourceRequest& request) const | |
4746 { | |
4747 ResourceError error = m_client->cancelledError(request); | |
4748 error.setIsCancellation(true); | |
4749 return error; | |
4750 } | |
4751 | |
4752 ResourceError FrameLoader::blockedError(const ResourceRequest& request) const | |
4753 { | |
4754 return m_client->blockedError(request); | |
4755 } | |
4756 | |
4757 ResourceError FrameLoader::cannotShowURLError(const ResourceRequest& request) co
nst | |
4758 { | |
4759 return m_client->cannotShowURLError(request); | |
4760 } | |
4761 | |
4762 ResourceError FrameLoader::fileDoesNotExistError(const ResourceResponse& respons
e) const | |
4763 { | |
4764 return m_client->fileDoesNotExistError(response); | |
4765 } | |
4766 | |
4767 void FrameLoader::didFinishLoad(ResourceLoader* loader) | |
4768 { | |
4769 if (Page* page = m_frame->page()) | |
4770 page->progress()->completeProgress(loader->identifier()); | |
4771 dispatchDidFinishLoading(loader->documentLoader(), loader->identifier()); | |
4772 } | |
4773 | |
4774 void FrameLoader::didReceiveAuthenticationChallenge(ResourceLoader* loader, cons
t AuthenticationChallenge& currentWebChallenge) | |
4775 { | |
4776 m_client->dispatchDidReceiveAuthenticationChallenge(loader->documentLoader()
, loader->identifier(), currentWebChallenge); | |
4777 } | |
4778 | |
4779 void FrameLoader::didCancelAuthenticationChallenge(ResourceLoader* loader, const
AuthenticationChallenge& currentWebChallenge) | |
4780 { | |
4781 m_client->dispatchDidCancelAuthenticationChallenge(loader->documentLoader(),
loader->identifier(), currentWebChallenge); | |
4782 } | |
4783 | |
4784 PolicyCheck::PolicyCheck() | |
4785 : m_navigationFunction(0) | |
4786 , m_newWindowFunction(0) | |
4787 , m_contentFunction(0) | |
4788 { | |
4789 } | |
4790 | |
4791 void PolicyCheck::clear() | |
4792 { | |
4793 clearRequest(); | |
4794 m_navigationFunction = 0; | |
4795 m_newWindowFunction = 0; | |
4796 m_contentFunction = 0; | |
4797 } | |
4798 | |
4799 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> form
State, | |
4800 NavigationPolicyDecisionFunction function, void* argument) | |
4801 { | |
4802 m_request = request; | |
4803 m_formState = formState; | |
4804 m_frameName = String(); | |
4805 | |
4806 m_navigationFunction = function; | |
4807 m_newWindowFunction = 0; | |
4808 m_contentFunction = 0; | |
4809 m_argument = argument; | |
4810 } | |
4811 | |
4812 void PolicyCheck::set(const ResourceRequest& request, PassRefPtr<FormState> form
State, | |
4813 const String& frameName, NewWindowPolicyDecisionFunction function, void* arg
ument) | |
4814 { | |
4815 m_request = request; | |
4816 m_formState = formState; | |
4817 m_frameName = frameName; | |
4818 | |
4819 m_navigationFunction = 0; | |
4820 m_newWindowFunction = function; | |
4821 m_contentFunction = 0; | |
4822 m_argument = argument; | |
4823 } | |
4824 | |
4825 void PolicyCheck::set(ContentPolicyDecisionFunction function, void* argument) | |
4826 { | |
4827 m_request = ResourceRequest(); | |
4828 m_formState = 0; | |
4829 m_frameName = String(); | |
4830 | |
4831 m_navigationFunction = 0; | |
4832 m_newWindowFunction = 0; | |
4833 m_contentFunction = function; | |
4834 m_argument = argument; | |
4835 } | |
4836 | |
4837 void PolicyCheck::call(bool shouldContinue) | |
4838 { | |
4839 if (m_navigationFunction) | |
4840 m_navigationFunction(m_argument, m_request, m_formState.get(), shouldCon
tinue); | |
4841 if (m_newWindowFunction) | |
4842 m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameNam
e, shouldContinue); | |
4843 ASSERT(!m_contentFunction); | |
4844 } | |
4845 | |
4846 void PolicyCheck::call(PolicyAction action) | |
4847 { | |
4848 ASSERT(!m_navigationFunction); | |
4849 ASSERT(!m_newWindowFunction); | |
4850 ASSERT(m_contentFunction); | |
4851 m_contentFunction(m_argument, action); | |
4852 } | |
4853 | |
4854 void PolicyCheck::clearRequest() | |
4855 { | |
4856 m_request = ResourceRequest(); | |
4857 m_formState = 0; | |
4858 m_frameName = String(); | |
4859 } | |
4860 | |
4861 void PolicyCheck::cancel() | |
4862 { | |
4863 clearRequest(); | |
4864 if (m_navigationFunction) | |
4865 m_navigationFunction(m_argument, m_request, m_formState.get(), false); | |
4866 if (m_newWindowFunction) | |
4867 m_newWindowFunction(m_argument, m_request, m_formState.get(), m_frameNam
e, false); | |
4868 if (m_contentFunction) | |
4869 m_contentFunction(m_argument, PolicyIgnore); | |
4870 } | |
4871 | |
4872 void FrameLoader::setTitle(const String& title) | |
4873 { | |
4874 documentLoader()->setTitle(title); | |
4875 } | |
4876 | |
4877 KURL FrameLoader::originalRequestURL() const | |
4878 { | |
4879 return activeDocumentLoader()->originalRequest().url(); | |
4880 } | |
4881 | |
4882 String FrameLoader::referrer() const | |
4883 { | |
4884 return documentLoader()->request().httpReferrer(); | |
4885 } | |
4886 | |
4887 void FrameLoader::dispatchWindowObjectAvailable() | |
4888 { | |
4889 // TODO(tc): We should also return early if we have no window shell. | |
4890 // But we can't check that until we refactor ScriptController. | |
4891 if (!m_frame->script()->isEnabled()) | |
4892 return; | |
4893 | |
4894 m_client->windowObjectCleared(); | |
4895 | |
4896 if (Page* page = m_frame->page()) { | |
4897 if (InspectorController* inspector = page->inspectorController()) | |
4898 inspector->inspectedWindowScriptObjectCleared(m_frame); | |
4899 if (InspectorController* inspector = page->parentInspectorController()) | |
4900 inspector->windowScriptObjectAvailable(); | |
4901 } | |
4902 } | |
4903 | |
4904 Widget* FrameLoader::createJavaAppletWidget(const IntSize& size, Element* elemen
t, const HashMap<String, String>& args) | |
4905 { | |
4906 String baseURLString; | |
4907 Vector<String> paramNames; | |
4908 Vector<String> paramValues; | |
4909 HashMap<String, String>::const_iterator end = args.end(); | |
4910 for (HashMap<String, String>::const_iterator it = args.begin(); it != end; +
+it) { | |
4911 if (equalIgnoringCase(it->first, "baseurl")) | |
4912 baseURLString = it->second; | |
4913 paramNames.append(it->first); | |
4914 paramValues.append(it->second); | |
4915 } | |
4916 | |
4917 if (baseURLString.isEmpty()) | |
4918 baseURLString = m_frame->document()->baseURL().string(); | |
4919 KURL baseURL = completeURL(baseURLString); | |
4920 | |
4921 Widget* widget = m_client->createJavaAppletWidget(size, element, baseURL, pa
ramNames, paramValues); | |
4922 if (widget) | |
4923 m_containsPlugIns = true; | |
4924 | |
4925 return widget; | |
4926 } | |
4927 | |
4928 void FrameLoader::didChangeTitle(DocumentLoader* loader) | |
4929 { | |
4930 m_client->didChangeTitle(loader); | |
4931 | |
4932 // The title doesn't get communicated to the WebView until we are committed. | |
4933 if (loader->isCommitted()) { | |
4934 // Must update the entries in the back-forward list too. | |
4935 if (m_currentHistoryItem) | |
4936 m_currentHistoryItem->setTitle(loader->title()); | |
4937 // This must go through the WebFrame because it has the right notion of
the current b/f item. | |
4938 m_client->setTitle(loader->title(), loader->urlForHistory()); | |
4939 m_client->setMainFrameDocumentReady(true); // update observers with new
DOMDocument | |
4940 m_client->dispatchDidReceiveTitle(loader->title()); | |
4941 } | |
4942 } | |
4943 | |
4944 void FrameLoader::continueLoadWithData(SharedBuffer* buffer, const String& mimeT
ype, const String& textEncoding, const KURL& url) | |
4945 { | |
4946 m_responseMIMEType = mimeType; | |
4947 didOpenURL(url); | |
4948 | |
4949 String encoding; | |
4950 if (m_frame) | |
4951 encoding = documentLoader()->overrideEncoding(); | |
4952 bool userChosen = !encoding.isNull(); | |
4953 if (encoding.isNull()) | |
4954 encoding = textEncoding; | |
4955 setEncoding(encoding, userChosen); | |
4956 | |
4957 ASSERT(m_frame->document()); | |
4958 | |
4959 addData(buffer->data(), buffer->size()); | |
4960 } | |
4961 | |
4962 void FrameLoader::registerURLSchemeAsLocal(const String& scheme) | |
4963 { | |
4964 localSchemes().add(scheme); | |
4965 } | |
4966 | |
4967 bool FrameLoader::shouldTreatURLAsLocal(const String& url) | |
4968 { | |
4969 // This avoids an allocation of another String and the HashSet contains() | |
4970 // call for the file: and http: schemes. | |
4971 if (url.length() >= 5) { | |
4972 const UChar* s = url.characters(); | |
4973 if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p' && s[4] ==
':') | |
4974 return false; | |
4975 if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e' && s[4] ==
':') | |
4976 return true; | |
4977 } | |
4978 | |
4979 int loc = url.find(':'); | |
4980 if (loc == -1) | |
4981 return false; | |
4982 | |
4983 String scheme = url.left(loc); | |
4984 return localSchemes().contains(scheme); | |
4985 } | |
4986 | |
4987 bool FrameLoader::shouldTreatSchemeAsLocal(const String& scheme) | |
4988 { | |
4989 // This avoids an allocation of another String and the HashSet contains() | |
4990 // call for the file: and http: schemes. | |
4991 if (scheme.length() == 4) { | |
4992 const UChar* s = scheme.characters(); | |
4993 if (s[0] == 'h' && s[1] == 't' && s[2] == 't' && s[3] == 'p') | |
4994 return false; | |
4995 if (s[0] == 'f' && s[1] == 'i' && s[2] == 'l' && s[3] == 'e') | |
4996 return true; | |
4997 } | |
4998 | |
4999 if (scheme.isEmpty()) | |
5000 return false; | |
5001 | |
5002 return localSchemes().contains(scheme); | |
5003 } | |
5004 | |
5005 void FrameLoader::dispatchDidCommitLoad() | |
5006 { | |
5007 if (m_creatingInitialEmptyDocument) | |
5008 return; | |
5009 | |
5010 #ifndef NDEBUG | |
5011 m_didDispatchDidCommitLoad = true; | |
5012 #endif | |
5013 | |
5014 m_client->dispatchDidCommitLoad(); | |
5015 | |
5016 if (Page* page = m_frame->page()) | |
5017 page->inspectorController()->didCommitLoad(m_documentLoader.get()); | |
5018 } | |
5019 | |
5020 void FrameLoader::dispatchAssignIdentifierToInitialRequest(unsigned long identif
ier, DocumentLoader* loader, const ResourceRequest& request) | |
5021 { | |
5022 m_client->assignIdentifierToInitialRequest(identifier, loader, request); | |
5023 | |
5024 if (Page* page = m_frame->page()) | |
5025 page->inspectorController()->identifierForInitialRequest(identifier, loa
der, request); | |
5026 } | |
5027 | |
5028 void FrameLoader::dispatchWillSendRequest(DocumentLoader* loader, unsigned long
identifier, ResourceRequest& request, const ResourceResponse& redirectResponse) | |
5029 { | |
5030 m_client->dispatchWillSendRequest(loader, identifier, request, redirectRespo
nse); | |
5031 | |
5032 if (Page* page = m_frame->page()) | |
5033 page->inspectorController()->willSendRequest(loader, identifier, request
, redirectResponse); | |
5034 } | |
5035 | |
5036 void FrameLoader::dispatchDidReceiveResponse(DocumentLoader* loader, unsigned lo
ng identifier, const ResourceResponse& r) | |
5037 { | |
5038 m_client->dispatchDidReceiveResponse(loader, identifier, r); | |
5039 | |
5040 if (Page* page = m_frame->page()) | |
5041 page->inspectorController()->didReceiveResponse(loader, identifier, r); | |
5042 } | |
5043 | |
5044 void FrameLoader::dispatchDidReceiveContentLength(DocumentLoader* loader, unsign
ed long identifier, int length) | |
5045 { | |
5046 m_client->dispatchDidReceiveContentLength(loader, identifier, length); | |
5047 | |
5048 if (Page* page = m_frame->page()) | |
5049 page->inspectorController()->didReceiveContentLength(loader, identifier,
length); | |
5050 } | |
5051 | |
5052 void FrameLoader::dispatchDidFinishLoading(DocumentLoader* loader, unsigned long
identifier) | |
5053 { | |
5054 m_client->dispatchDidFinishLoading(loader, identifier); | |
5055 | |
5056 if (Page* page = m_frame->page()) | |
5057 page->inspectorController()->didFinishLoading(loader, identifier); | |
5058 } | |
5059 | |
5060 #if USE(LOW_BANDWIDTH_DISPLAY) | |
5061 | |
5062 bool FrameLoader::addLowBandwidthDisplayRequest(CachedResource* cache) | |
5063 { | |
5064 if (m_frame->document()->inLowBandwidthDisplay() == false) | |
5065 return false; | |
5066 | |
5067 // if cache is loaded, don't add to the list, where notifyFinished() is expe
cted. | |
5068 if (cache->isLoaded()) | |
5069 return false; | |
5070 | |
5071 switch (cache->type()) { | |
5072 case CachedResource::CSSStyleSheet: | |
5073 case CachedResource::Script: | |
5074 m_needToSwitchOutLowBandwidthDisplay = true; | |
5075 m_externalRequestsInLowBandwidthDisplay.add(cache); | |
5076 cache->addClient(this); | |
5077 return true; | |
5078 case CachedResource::ImageResource: | |
5079 case CachedResource::FontResource: | |
5080 #if ENABLE(XSLT) | |
5081 case CachedResource::XSLStyleSheet: | |
5082 #endif | |
5083 #if ENABLE(XBL) | |
5084 case CachedResource::XBLStyleSheet: | |
5085 #endif | |
5086 return false; | |
5087 } | |
5088 | |
5089 ASSERT_NOT_REACHED(); | |
5090 return false; | |
5091 } | |
5092 | |
5093 void FrameLoader::removeAllLowBandwidthDisplayRequests() | |
5094 { | |
5095 HashSet<CachedResource*>::iterator end = m_externalRequestsInLowBandwidthDis
play.end(); | |
5096 for (HashSet<CachedResource*>::iterator it = m_externalRequestsInLowBandwidt
hDisplay.begin(); it != end; ++it) | |
5097 (*it)->removeClient(this); | |
5098 m_externalRequestsInLowBandwidthDisplay.clear(); | |
5099 } | |
5100 | |
5101 void FrameLoader::notifyFinished(CachedResource* script) | |
5102 { | |
5103 HashSet<CachedResource*>::iterator it = m_externalRequestsInLowBandwidthDisp
lay.find(script); | |
5104 if (it != m_externalRequestsInLowBandwidthDisplay.end()) { | |
5105 (*it)->removeClient(this); | |
5106 m_externalRequestsInLowBandwidthDisplay.remove(it); | |
5107 switchOutLowBandwidthDisplayIfReady(); | |
5108 } | |
5109 } | |
5110 | |
5111 void FrameLoader::switchOutLowBandwidthDisplayIfReady() | |
5112 { | |
5113 RefPtr<Document> oldDoc = m_frame->document(); | |
5114 if (oldDoc->inLowBandwidthDisplay()) { | |
5115 if (!m_needToSwitchOutLowBandwidthDisplay) { | |
5116 // no need to switch, just reset state | |
5117 oldDoc->setLowBandwidthDisplay(false); | |
5118 removeAllLowBandwidthDisplayRequests(); | |
5119 m_pendingSourceInLowBandwidthDisplay = String(); | |
5120 m_finishedParsingDuringLowBandwidthDisplay = false; | |
5121 return; | |
5122 } else if (m_externalRequestsInLowBandwidthDisplay.isEmpty() || | |
5123 m_pendingSourceInLowBandwidthDisplay.length() > cMaxPendingSourceLen
gthInLowBandwidthDisplay) { | |
5124 // clear the flag first | |
5125 oldDoc->setLowBandwidthDisplay(false); | |
5126 | |
5127 // similar to clear(), should be refactored to share more code | |
5128 oldDoc->cancelParsing(); | |
5129 oldDoc->detach(); | |
5130 if (m_frame->script()->isEnabled()) | |
5131 m_frame->script()->clearWindowShell(); | |
5132 if (m_frame->view()) | |
5133 m_frame->view()->clear(); | |
5134 | |
5135 // similar to begin(), should be refactored to share more code | |
5136 RefPtr<Document> newDoc = DOMImplementation::createDocument(m_respon
seMIMEType, m_frame, m_frame->inViewSourceMode()); | |
5137 m_frame->setDocument(newDoc); | |
5138 newDoc->setURL(m_URL); | |
5139 if (m_decoder) | |
5140 newDoc->setDecoder(m_decoder.get()); | |
5141 restoreDocumentState(); | |
5142 dispatchWindowObjectAvailable(); | |
5143 newDoc->implicitOpen(); | |
5144 | |
5145 // swap DocLoader ownership | |
5146 DocLoader* docLoader = newDoc->docLoader(); | |
5147 newDoc->setDocLoader(oldDoc->docLoader()); | |
5148 newDoc->docLoader()->replaceDocument(newDoc.get()); | |
5149 docLoader->replaceDocument(oldDoc.get()); | |
5150 oldDoc->setDocLoader(docLoader); | |
5151 | |
5152 // drop the old doc | |
5153 oldDoc = 0; | |
5154 | |
5155 // write decoded data to the new doc, similar to write() | |
5156 if (m_pendingSourceInLowBandwidthDisplay.length()) { | |
5157 // set cachePolicy to Cache to use the loaded resource | |
5158 newDoc->docLoader()->setCachePolicy(CachePolicyCache); | |
5159 if (m_decoder->encoding().usesVisualOrdering()) | |
5160 newDoc->setVisuallyOrdered(); | |
5161 newDoc->recalcStyle(Node::Force); | |
5162 newDoc->tokenizer()->write(m_pendingSourceInLowBandwidthDisplay,
true); | |
5163 | |
5164 if (m_finishedParsingDuringLowBandwidthDisplay) | |
5165 newDoc->finishParsing(); | |
5166 } | |
5167 | |
5168 // update rendering | |
5169 newDoc->updateRendering(); | |
5170 | |
5171 // reset states | |
5172 removeAllLowBandwidthDisplayRequests(); | |
5173 m_pendingSourceInLowBandwidthDisplay = String(); | |
5174 m_finishedParsingDuringLowBandwidthDisplay = false; | |
5175 m_needToSwitchOutLowBandwidthDisplay = false; | |
5176 } | |
5177 } | |
5178 } | |
5179 | |
5180 #endif | |
5181 | |
5182 void FrameLoader::unloadListenerChanged() { | |
5183 m_client->unloadListenerChanged(); | |
5184 } | |
5185 | |
5186 } // namespace WebCore | |
OLD | NEW |