Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(126)

Side by Side Diff: webkit/pending/FrameLoader.cpp

Issue 6500: Cleaning up the unfork (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: Created 12 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « webkit/pending/FrameLoader.h ('k') | webkit/pending/FrameLoaderClient.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(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
OLDNEW
« no previous file with comments | « webkit/pending/FrameLoader.h ('k') | webkit/pending/FrameLoaderClient.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698