a99ccbaa8340a1993e83c9ef6b7c6f6779e2f082
[WebKit-https.git] / WebCore / loader / FrameLoader.cpp
1 /*
2  * Copyright (C) 2006, 2007 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 "CString.h"
34 #include "Cache.h"
35 #include "CachedPage.h"
36 #include "Chrome.h"
37 #include "DOMImplementation.h"
38 #include "DocLoader.h"
39 #include "Document.h"
40 #include "DocumentLoader.h"
41 #include "EditCommand.h"
42 #include "Editor.h"
43 #include "EditorClient.h"
44 #include "Element.h"
45 #include "Event.h"
46 #include "EventNames.h"
47 #include "FloatRect.h"
48 #include "FormState.h"
49 #include "Frame.h"
50 #include "FrameLoadRequest.h"
51 #include "FrameLoaderClient.h"
52 #include "FramePrivate.h"
53 #include "FrameTree.h"
54 #include "FrameView.h"
55 #include "HTMLFormElement.h"
56 #include "HTMLFrameElement.h"
57 #include "HTMLNames.h"
58 #include "HTMLObjectElement.h"
59 #include "HTTPParsers.h"
60 #include "HistoryItem.h"
61 #include "IconDatabase.h"
62 #include "IconLoader.h"
63 #include "InspectorController.h"
64 #include "Logging.h"
65 #include "MIMETypeRegistry.h"
66 #include "MainResourceLoader.h"
67 #include "Page.h"
68 #include "PageCache.h"
69 #include "ProgressTracker.h"
70 #include "RenderPart.h"
71 #include "RenderWidget.h"
72 #include "ResourceHandle.h"
73 #include "ResourceRequest.h"
74 #include "SecurityOrigin.h"
75 #include "SegmentedString.h"
76 #include "Settings.h"
77 #include "SystemTime.h"
78 #include "TextResourceDecoder.h"
79 #include "WindowFeatures.h"
80 #include "XMLHttpRequest.h"
81 #include "XMLTokenizer.h"
82 #include "kjs_binding.h"
83 #include "kjs_proxy.h"
84 #include "kjs_window.h"
85 #include <kjs/JSLock.h>
86 #include <kjs/object.h>
87
88 #if ENABLE(SVG)
89 #include "SVGDocument.h"
90 #include "SVGLocatable.h"
91 #include "SVGNames.h"
92 #include "SVGPreserveAspectRatio.h"
93 #include "SVGSVGElement.h"
94 #include "SVGViewElement.h"
95 #include "SVGViewSpec.h"
96 #endif
97
98 using KJS::UString;
99 using KJS::JSLock;
100 using KJS::JSValue;
101
102 namespace WebCore {
103
104 #if ENABLE(SVG)
105 using namespace SVGNames;
106 #endif
107 using namespace HTMLNames;
108 using namespace EventNames;
109
110 #if USE(LOW_BANDWIDTH_DISPLAY)
111 const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024;
112 #endif
113
114 struct FormSubmission {
115     const char* action;
116     String URL;
117     RefPtr<FormData> data;
118     String target;
119     String contentType;
120     String boundary;
121     RefPtr<Event> event;
122
123     FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const String& t,
124             const String& ct, const String& b, PassRefPtr<Event> e)
125         : action(a)
126         , URL(u)
127         , data(d)
128         , target(t)
129         , contentType(ct)
130         , boundary(b)
131         , event(e)
132     {
133     }
134 };
135
136 struct ScheduledRedirection {
137     enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad };
138     Type type;
139     double delay;
140     String URL;
141     String referrer;
142     int historySteps;
143     bool lockHistory;
144     bool wasUserGesture;
145
146     ScheduledRedirection(double redirectDelay, const String& redirectURL, bool redirectLockHistory, bool userGesture)
147         : type(redirection)
148         , delay(redirectDelay)
149         , URL(redirectURL)
150         , historySteps(0)
151         , lockHistory(redirectLockHistory)
152         , wasUserGesture(userGesture)
153     {
154     }
155
156     ScheduledRedirection(Type locationChangeType,
157             const String& locationChangeURL, const String& locationChangeReferrer,
158             bool locationChangeLockHistory, bool locationChangeWasUserGesture)
159         : type(locationChangeType)
160         , delay(0)
161         , URL(locationChangeURL)
162         , referrer(locationChangeReferrer)
163         , historySteps(0)
164         , lockHistory(locationChangeLockHistory)
165         , wasUserGesture(locationChangeWasUserGesture)
166     {
167     }
168
169     explicit ScheduledRedirection(int historyNavigationSteps)
170         : type(historyNavigation)
171         , delay(0)
172         , historySteps(historyNavigationSteps)
173         , lockHistory(false)
174         , wasUserGesture(false)
175     {
176     }
177 };
178
179 static double storedTimeOfLastCompletedLoad;
180 static bool m_restrictAccessToLocal = false;
181
182 static bool getString(JSValue* result, String& string)
183 {
184     if (!result)
185         return false;
186     JSLock lock;
187     UString ustring;
188     if (!result->getString(ustring))
189         return false;
190     string = ustring;
191     return true;
192 }
193
194 bool isBackForwardLoadType(FrameLoadType type)
195 {
196     switch (type) {
197         case FrameLoadTypeStandard:
198         case FrameLoadTypeReload:
199         case FrameLoadTypeReloadAllowingStaleData:
200         case FrameLoadTypeSame:
201         case FrameLoadTypeRedirectWithLockedHistory:
202         case FrameLoadTypeReplace:
203             return false;
204         case FrameLoadTypeBack:
205         case FrameLoadTypeForward:
206         case FrameLoadTypeIndexedBackForward:
207             return true;
208     }
209     ASSERT_NOT_REACHED();
210     return false;
211 }
212
213 static int numRequests(Document* document)
214 {
215     if (!document)
216         return 0;
217     
218     return document->docLoader()->requestCount();
219 }
220
221 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
222     : m_frame(frame)
223     , m_client(client)
224     , m_state(FrameStateCommittedPage)
225     , m_loadType(FrameLoadTypeStandard)
226     , m_policyLoadType(FrameLoadTypeStandard)
227     , m_delegateIsHandlingProvisionalLoadError(false)
228     , m_delegateIsDecidingNavigationPolicy(false)
229     , m_delegateIsHandlingUnimplementablePolicy(false)
230     , m_firstLayoutDone(false)
231     , m_quickRedirectComing(false)
232     , m_sentRedirectNotification(false)
233     , m_inStopAllLoaders(false)
234     , m_navigationDuringLoad(false)
235     , m_cachePolicy(CachePolicyVerify)
236     , m_isExecutingJavaScriptFormAction(false)
237     , m_isRunningScript(false)
238     , m_didCallImplicitClose(false)
239     , m_wasUnloadEventEmitted(false)
240     , m_isComplete(false)
241     , m_isLoadingMainResource(false)
242     , m_cancellingWithLoadInProgress(false)
243     , m_needsClear(false)
244     , m_receivedData(false)
245     , m_encodingWasChosenByUser(false)
246     , m_containsPlugIns(false)
247     , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
248     , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
249     , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
250     , m_opener(0)
251     , m_openedByDOM(false)
252     , m_creatingInitialEmptyDocument(false)
253     , m_isDisplayingInitialEmptyDocument(false)
254     , m_committedFirstRealDocumentLoad(false)
255     , m_didPerformFirstNavigation(false)
256 #ifndef NDEBUG
257     , m_didDispatchDidCommitLoad(false)
258 #endif
259 #if USE(LOW_BANDWIDTH_DISPLAY)
260     , m_useLowBandwidthDisplay(true)
261     , m_finishedParsingDuringLowBandwidthDisplay(false)
262     , m_needToSwitchOutLowBandwidthDisplay(false)
263 #endif 
264 {
265 }
266
267 FrameLoader::~FrameLoader()
268 {
269     setOpener(0);
270
271     HashSet<Frame*>::iterator end = m_openedFrames.end();
272     for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
273         (*it)->loader()->m_opener = 0;
274         
275     m_client->frameLoaderDestroyed();
276 }
277
278 void FrameLoader::init()
279 {
280     // this somewhat odd set of steps is needed to give the frame an initial empty document
281     m_isDisplayingInitialEmptyDocument = false;
282     m_creatingInitialEmptyDocument = true;
283     setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(String("")), SubstituteData()).get());
284     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
285     setState(FrameStateProvisional);
286     m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
287     m_provisionalDocumentLoader->finishedLoading();
288     begin(KURL(), false);
289     end();
290     m_frame->document()->cancelParsing();
291     m_creatingInitialEmptyDocument = false;
292     m_didCallImplicitClose = true;
293 }
294
295 void FrameLoader::setDefersLoading(bool defers)
296 {
297     if (m_documentLoader)
298         m_documentLoader->setDefersLoading(defers);
299     if (m_provisionalDocumentLoader)
300         m_provisionalDocumentLoader->setDefersLoading(defers);
301     if (m_policyDocumentLoader)
302         m_policyDocumentLoader->setDefersLoading(defers);
303     m_client->setDefersLoading(defers);
304 }
305
306 Frame* FrameLoader::createWindow(const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
307
308     ASSERT(!features.dialog || request.frameName().isEmpty());
309
310     if (!request.frameName().isEmpty() && request.frameName() != "_blank")
311         if (Frame* frame = m_frame->tree()->find(request.frameName())) {
312             if (!shouldAllowNavigation(frame))
313                 return 0;
314             if (!request.resourceRequest().url().isEmpty())
315                 frame->loader()->load(request, false, true, 0, 0, HashMap<String, String>());
316             if (Page* page = frame->page())
317                 page->chrome()->focus();
318             created = false;
319             return frame;
320         }
321
322     // FIXME: Setting the referrer should be the caller's responsibility.
323     FrameLoadRequest requestWithReferrer = request;
324     requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
325     
326     Page* page = m_frame->page();
327     if (page)
328         page = page->chrome()->createWindow(m_frame, requestWithReferrer, features);
329     if (!page)
330         return 0;
331
332     Frame* frame = page->mainFrame();
333     if (request.frameName() != "_blank")
334         frame->tree()->setName(request.frameName());
335
336     page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
337     page->chrome()->setStatusbarVisible(features.statusBarVisible);
338     page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
339     page->chrome()->setMenubarVisible(features.menuBarVisible);
340     page->chrome()->setResizable(features.resizable);
341
342     // 'x' and 'y' specify the location of the window, while 'width' and 'height' 
343     // specify the size of the page. We can only resize the window, so 
344     // adjust for the difference between the window size and the page size.
345
346     FloatRect windowRect = page->chrome()->windowRect();
347     FloatSize pageSize = page->chrome()->pageRect().size();
348     if (features.xSet)
349         windowRect.setX(features.x);
350     if (features.ySet)
351         windowRect.setY(features.y);
352     if (features.widthSet)
353         windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
354     if (features.heightSet)
355         windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
356     page->chrome()->setWindowRect(windowRect);
357
358     page->chrome()->show();
359
360     created = true;
361     return frame;
362 }
363
364 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
365 {
366     return m_client->canHandleRequest(request);
367 }
368
369 void FrameLoader::changeLocation(const String& URL, const String& referrer, bool lockHistory, bool userGesture)
370 {
371     changeLocation(completeURL(URL), referrer, lockHistory, userGesture);
372 }
373
374 void FrameLoader::changeLocation(const KURL& URL, const String& referrer, bool lockHistory, bool userGesture)
375 {
376     if (URL.url().find("javascript:", 0, false) == 0) {
377         String script = KURL::decode_string(URL.url().mid(strlen("javascript:")));
378         JSValue* result = executeScript(script, userGesture);
379         String scriptResult;
380         if (getString(result, scriptResult)) {
381             begin(m_URL);
382             write(scriptResult);
383             end();
384         }
385         return;
386     }
387
388     ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)
389         ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
390     ResourceRequest request(URL, referrer, policy);
391     
392     urlSelected(request, "_self", 0, lockHistory, userGesture);
393 }
394
395 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool userGesture)
396 {
397     String target = _target;
398     if (target.isEmpty() && m_frame->document())
399         target = m_frame->document()->baseTarget();
400
401     const KURL& url = request.url();
402     if (url.url().startsWith("javascript:", false)) {
403         executeScript(KURL::decode_string(url.url().mid(strlen("javascript:"))), true);
404         return;
405     }
406
407     FrameLoadRequest frameRequest(request, target);
408
409     if (frameRequest.resourceRequest().httpReferrer().isEmpty())
410         frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
411
412     urlSelected(frameRequest, triggeringEvent, lockHistory, userGesture);
413 }
414
415 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
416 {
417 #if USE(LOW_BANDWIDTH_DISPLAY)
418     // don't create sub-frame during low bandwidth display
419     if (frame()->document()->inLowBandwidthDisplay()) {
420         m_needToSwitchOutLowBandwidthDisplay = true;
421         return false;
422     }
423 #endif
424
425     // Support for <frame src="javascript:string">
426     KURL scriptURL;
427     KURL url;
428     if (urlString.startsWith("javascript:", false)) {
429         scriptURL = urlString.deprecatedString();
430         url = "about:blank";
431     } else
432         url = completeURL(urlString);
433
434     Frame* frame = ownerElement->contentFrame();
435     if (frame)
436         frame->loader()->scheduleLocationChange(url.url(), m_outgoingReferrer, true, userGestureHint());
437     else
438         frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
439     
440     if (!frame)
441         return false;
442
443     if (!scriptURL.isEmpty())
444         frame->loader()->replaceContentsWithScriptResult(scriptURL);
445
446     return true;
447 }
448
449 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
450 {
451     bool allowsScrolling = true;
452     int marginWidth = -1;
453     int marginHeight = -1;
454     if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
455         HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
456         allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
457         marginWidth = o->getMarginWidth();
458         marginHeight = o->getMarginHeight();
459     }
460
461     if (!canLoad(url, referrer)) {
462         FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
463         return 0;
464     }
465
466     bool hideReferrer = shouldHideReferrer(url, referrer);
467     RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer,
468                                          allowsScrolling, marginWidth, marginHeight);
469
470     if (!frame)  {
471         checkCallImplicitClose();
472         return 0;
473     }
474     
475     frame->loader()->m_isComplete = false;
476     
477     if (ownerElement->renderer() && frame->view())
478         static_cast<RenderWidget*>(ownerElement->renderer())->setWidget(frame->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 == "about:blank") {
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<FormData> formData,
507     const String& target, const String& contentType, const String& boundary, Event* event)
508 {
509     ASSERT(formData.get());
510     
511     KURL u = completeURL(url.isNull() ? "" : url);
512     // FIXME: Do we really need to special-case an empty URL?
513     // Would it be better to just go on with the form submisson and let the I/O fail?
514     if (u.isEmpty())
515         return;
516
517     DeprecatedString urlString = u.url();
518     if (urlString.startsWith("javascript:", false)) {
519         m_isExecutingJavaScriptFormAction = true;
520         executeScript(KURL::decode_string(urlString.mid(strlen("javascript:"))));
521         m_isExecutingJavaScriptFormAction = false;
522         return;
523     }
524
525     if (m_isRunningScript) {
526         if (m_deferredFormSubmission)
527             return;
528         m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target,
529             contentType, boundary, event));
530         return;
531     }
532
533     FrameLoadRequest frameRequest;
534
535     if (!m_outgoingReferrer.isEmpty())
536         frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
537
538     frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
539
540     // Handle mailto: forms
541     bool mailtoForm = u.protocol() == "mailto";
542     if (mailtoForm) {
543         // Append body=
544         String body;
545         if (equalIgnoringCase(contentType, "multipart/form-data"))
546             // FIXME: is this correct? I suspect not, but what site can we test this on?
547             body = formData->flattenToString();
548         else if (equalIgnoringCase(contentType, "text/plain"))
549             // Convention seems to be to decode, and s/&/\n/
550             body = KURL::decode_string(
551                 formData->flattenToString().replace('&', '\n')
552                 .replace('+', ' ').deprecatedString()); // Recode for the URL
553         else
554             body = formData->flattenToString();
555
556         String query = u.query();
557         if (!query.isEmpty())
558             query.append('&');
559         u.setQuery((query + "body=" + KURL::encode_string(body.deprecatedString())).deprecatedString());
560     }
561
562     if (strcmp(action, "GET") == 0) {
563         if (!mailtoForm)
564             u.setQuery(formData->flattenToString().deprecatedString());
565     } else {
566         frameRequest.resourceRequest().setHTTPBody(formData.get());
567         frameRequest.resourceRequest().setHTTPMethod("POST");
568
569         // construct some user headers if necessary
570         if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
571             frameRequest.resourceRequest().setHTTPContentType(contentType);
572         else // contentType must be "multipart/form-data"
573             frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
574     }
575
576     frameRequest.resourceRequest().setURL(u);
577
578     submitForm(frameRequest, event);
579 }
580
581 void FrameLoader::stopLoading(bool sendUnload)
582 {
583     if (m_frame->document() && m_frame->document()->tokenizer())
584         m_frame->document()->tokenizer()->stopParsing();
585
586     if (sendUnload) {
587         if (m_frame->document()) {
588             if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
589                 Node* currentFocusedNode = m_frame->document()->focusedNode();
590                 if (currentFocusedNode)
591                     currentFocusedNode->aboutToUnload();
592                 m_frame->document()->dispatchWindowEvent(unloadEvent, false, false);
593                 if (m_frame->document())
594                     m_frame->document()->updateRendering();
595                 m_wasUnloadEventEmitted = true;
596             }
597         }
598         if (m_frame->document() && !m_frame->document()->inPageCache())
599             m_frame->document()->removeAllEventListenersFromAllNodes();
600     }
601
602     m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
603     m_isLoadingMainResource = false;
604     m_didCallImplicitClose = true; // don't want that one either
605     m_cachePolicy = CachePolicyVerify; // Why here?
606
607     if (m_frame->document() && m_frame->document()->parsing()) {
608         finishedParsing();
609         m_frame->document()->setParsing(false);
610     }
611   
612     m_workingURL = KURL();
613
614     if (Document* doc = m_frame->document()) {
615         if (DocLoader* docLoader = doc->docLoader())
616             cache()->loader()->cancelRequests(docLoader);
617         XMLHttpRequest::cancelRequests(doc);
618     }
619
620     // tell all subframes to stop as well
621     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
622         child->loader()->stopLoading(sendUnload);
623
624     cancelRedirection();
625
626 #if USE(LOW_BANDWIDTH_DISPLAY)
627     if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) {
628         // Since loading is forced to stop, reset the state without really switching.
629         m_needToSwitchOutLowBandwidthDisplay = false;
630         switchOutLowBandwidthDisplayIfReady();
631     }
632 #endif  
633 }
634
635 void FrameLoader::stop()
636 {
637     // http://bugs.webkit.org/show_bug.cgi?id=10854
638     // The frame's last ref may be removed and it will be deleted by checkCompleted().
639     RefPtr<Frame> protector(m_frame);
640     
641     if (m_frame->document()) {
642         if (m_frame->document()->tokenizer())
643             m_frame->document()->tokenizer()->stopParsing();
644         m_frame->document()->finishParsing();
645     } else
646         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
647         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
648         // become true. An example is when a subframe is a pure text doc, and that subframe is the
649         // last one to complete.
650         checkCompleted();
651     if (m_iconLoader)
652         m_iconLoader->stopLoading();
653 }
654
655 bool FrameLoader::closeURL()
656 {
657     saveDocumentState();
658     stopLoading(true);
659     m_frame->editor()->clearUndoRedoOperations();
660     return true;
661 }
662
663 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
664 {
665     m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
666
667     stopRedirectionTimer();
668
669     m_scheduledRedirection.clear();
670 }
671
672 KURL FrameLoader::iconURL()
673 {
674     // If this isn't a top level frame, return nothing
675     if (m_frame->tree() && m_frame->tree()->parent())
676         return "";
677         
678     // If we have an iconURL from a Link element, return that
679     if (m_frame->document() && !m_frame->document()->iconURL().isEmpty())
680         return m_frame->document()->iconURL().deprecatedString();
681         
682     // Don't return a favicon iconURL unless we're http or https
683     if (m_URL.protocol() != "http" && m_URL.protocol() != "https")
684         return "";
685         
686     KURL url;
687     url.setProtocol(m_URL.protocol());
688     url.setHost(m_URL.host());
689     if (int port = m_URL.port())
690         url.setPort(port);
691     url.setPath("/favicon.ico");
692     return url;
693 }
694
695 bool FrameLoader::didOpenURL(const KURL& url)
696 {
697     if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
698         // A redirect was scheduled before the document was created.
699         // This can happen when one frame changes another frame's location.
700         return false;
701
702     cancelRedirection();
703     m_frame->editor()->setLastEditCommand(0);
704     closeURL();
705
706     m_isComplete = false;
707     m_isLoadingMainResource = true;
708     m_didCallImplicitClose = false;
709
710     m_frame->setJSStatusBarText(String());
711     m_frame->setJSDefaultStatusBarText(String());
712
713     m_URL = url;
714     if (m_URL.protocol().startsWith("http") && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
715         m_URL.setPath("/");
716     m_workingURL = m_URL;
717
718     started();
719
720     return true;
721 }
722
723 void FrameLoader::didExplicitOpen()
724 {
725     m_isComplete = false;
726     m_didCallImplicitClose = false;
727
728     // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
729     // from a subsequent window.document.open / window.document.write call. 
730     // Cancelling redirection here works for all cases because document.open 
731     // implicitly precedes document.write.
732     cancelRedirection(); 
733     if (m_frame->document()->URL() != "about:blank")
734         m_URL = m_frame->document()->URL();
735 }
736
737 void FrameLoader::replaceContentsWithScriptResult(const KURL& url)
738 {
739     JSValue* result = executeScript(KURL::decode_string(url.url().mid(strlen("javascript:"))));
740     String scriptResult;
741     if (!getString(result, scriptResult))
742         return;
743     begin();
744     write(scriptResult);
745     end();
746 }
747
748 JSValue* FrameLoader::executeScript(const String& script, bool forceUserGesture)
749 {
750     return executeScript(forceUserGesture ? String() : String(m_URL.url()), 0, script);
751 }
752
753 JSValue* FrameLoader::executeScript(const String& URL, int baseLine, const String& script)
754 {
755     KJSProxy* proxy = m_frame->scriptProxy();
756     if (!proxy)
757         return 0;
758
759     bool wasRunningScript = m_isRunningScript;
760     m_isRunningScript = true;
761
762     JSValue* result = proxy->evaluate(URL, baseLine, script);
763
764     if (!wasRunningScript) {
765         m_isRunningScript = false;
766         submitFormAgain();
767         Document::updateDocumentsRendering();
768     }
769
770     return result;
771 }
772
773 void FrameLoader::cancelAndClear()
774 {
775     cancelRedirection();
776
777     if (!m_isComplete)
778         closeURL();
779
780     clear(false);
781 }
782
783 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
784 {
785     // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_bug.cgi?id=11212>, but putting it
786     // back causes a measurable performance regression which we will need to fix to restore the correct behavior
787     // urlsBridgeKnowsAbout.clear();
788
789     m_frame->editor()->clear();
790
791     if (!m_needsClear)
792         return;
793     m_needsClear = false;
794     
795     if (m_frame->document() && !m_frame->document()->inPageCache()) {
796         m_frame->document()->cancelParsing();
797         if (m_frame->document()->attached()) {
798             m_frame->document()->willRemove();
799             m_frame->document()->detach();
800         }
801     }
802
803     // Do this after detaching the document so that the unload event works.
804     if (clearWindowProperties) {
805         m_frame->clearScriptProxy();
806         m_frame->clearDOMWindow();
807     }
808
809     m_frame->selectionController()->clear();
810     m_frame->eventHandler()->clear();
811     if (m_frame->view())
812         m_frame->view()->clear();
813
814     // Do not drop the document before the script proxy and view are cleared, as some destructors
815     // might still try to access the document.
816     m_frame->setDocument(0);
817     m_decoder = 0;
818
819     m_containsPlugIns = false;
820     
821     if (clearScriptObjects)
822         m_frame->clearScriptObjects();
823   
824     m_redirectionTimer.stop();
825     m_scheduledRedirection.clear();
826
827     m_checkCompletedTimer.stop();
828     m_checkLoadCompleteTimer.stop();
829
830     m_receivedData = false;
831     m_isDisplayingInitialEmptyDocument = false;
832
833     if (!m_encodingWasChosenByUser)
834         m_encoding = String();
835 }
836
837 void FrameLoader::receivedFirstData()
838 {
839     begin(m_workingURL, false);
840
841     dispatchDidCommitLoad();
842     dispatchWindowObjectAvailable();
843     
844     String ptitle = m_documentLoader->title();
845     // If we have a title let the WebView know about it.
846     if (!ptitle.isNull())
847         m_client->dispatchDidReceiveTitle(ptitle);
848
849     m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
850     m_workingURL = KURL();
851
852     double delay;
853     String URL;
854     if (!m_documentLoader)
855         return;
856     if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, URL))
857         return;
858
859     if (URL.isEmpty())
860         URL = m_URL.url();
861     else
862         URL = m_frame->document()->completeURL(URL);
863
864     scheduleHTTPRedirection(delay, URL);
865 }
866
867 const String& FrameLoader::responseMIMEType() const
868 {
869     return m_responseMIMEType;
870 }
871
872 void FrameLoader::setResponseMIMEType(const String& type)
873 {
874     m_responseMIMEType = type;
875 }
876     
877 void FrameLoader::begin()
878 {
879     begin(KURL());
880 }
881
882 void FrameLoader::begin(const KURL& url, bool dispatch)
883 {
884     bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document() && m_frame->document()->securityOrigin().isSecureTransitionTo(url));
885     clear(resetScripting, resetScripting);
886     if (dispatch)
887         dispatchWindowObjectAvailable();
888
889     m_needsClear = true;
890     m_isComplete = false;
891     m_didCallImplicitClose = false;
892     m_isLoadingMainResource = true;
893     m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
894
895     KURL ref(url);
896     ref.setUser(DeprecatedString());
897     ref.setPass(DeprecatedString());
898     ref.setRef(DeprecatedString());
899     m_outgoingReferrer = ref.url();
900     m_URL = url;
901     KURL baseurl;
902
903     if (!m_URL.isEmpty())
904         baseurl = m_URL;
905
906     RefPtr<Document> document = DOMImplementation::instance()->createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
907     m_frame->setDocument(document);
908
909     document->setURL(m_URL.url());
910     // We prefer m_baseURL over m_URL because m_URL changes when we are
911     // about to load a new page.
912     document->setBaseURL(baseurl.url());
913     if (m_decoder)
914         document->setDecoder(m_decoder.get());
915
916     updatePolicyBaseURL();
917
918     Settings* settings = document->settings();
919     document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
920     KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
921     if (!userStyleSheet.isEmpty())
922         m_frame->setUserStyleSheetLocation(userStyleSheet);
923
924     restoreDocumentState();
925
926     document->implicitOpen();
927
928     if (m_frame->view())
929         m_frame->view()->resizeContents(0, 0);
930
931 #if USE(LOW_BANDWIDTH_DISPLAY)
932     // Low bandwidth display is a first pass display without external resources
933     // used to give an instant visual feedback. We currently only enable it for
934     // HTML documents in the top frame.
935     if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) {
936         m_pendingSourceInLowBandwidthDisplay = String();
937         m_finishedParsingDuringLowBandwidthDisplay = false;
938         m_needToSwitchOutLowBandwidthDisplay = false;
939         document->setLowBandwidthDisplay(true);
940     }
941 #endif
942 }
943
944 void FrameLoader::write(const char* str, int len, bool flush)
945 {
946     if (len == 0 && !flush)
947         return;
948     
949     if (len == -1)
950         len = strlen(str);
951
952     Tokenizer* tokenizer = m_frame->document()->tokenizer();
953     if (tokenizer && tokenizer->wantsRawData()) {
954         if (len > 0)
955             tokenizer->writeRawData(str, len);
956         return;
957     }
958     
959     if (!m_decoder) {
960         Settings* settings = m_frame->settings();
961         m_decoder = new TextResourceDecoder(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String());
962         if (!m_encoding.isNull())
963             m_decoder->setEncoding(m_encoding,
964                 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
965         if (m_frame->document())
966             m_frame->document()->setDecoder(m_decoder.get());
967     }
968
969     String decoded = m_decoder->decode(str, len);
970     if (flush)
971         decoded += m_decoder->flush();
972     if (decoded.isEmpty())
973         return;
974
975 #if USE(LOW_BANDWIDTH_DISPLAY)
976     if (m_frame->document()->inLowBandwidthDisplay())
977         m_pendingSourceInLowBandwidthDisplay.append(decoded);
978     else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady()
979         m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);    
980 #endif
981
982     if (!m_receivedData) {
983         m_receivedData = true;
984         m_frame->document()->determineParseMode(decoded);
985         if (m_decoder->encoding().usesVisualOrdering())
986             m_frame->document()->setVisuallyOrdered();
987         m_frame->document()->recalcStyle(Node::Force);
988     }
989
990     if (tokenizer) {
991         ASSERT(!tokenizer->wantsRawData());
992         tokenizer->write(decoded, true);
993     }
994 }
995
996 void FrameLoader::write(const String& str)
997 {
998     if (str.isNull())
999         return;
1000
1001     if (!m_receivedData) {
1002         m_receivedData = true;
1003         m_frame->document()->setParseMode(Document::Strict);
1004     }
1005
1006     if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
1007         tokenizer->write(str, true);
1008 }
1009
1010 void FrameLoader::end()
1011 {
1012     m_isLoadingMainResource = false;
1013     endIfNotLoadingMainResource();
1014 }
1015
1016 void FrameLoader::endIfNotLoadingMainResource()
1017 {
1018     if (m_isLoadingMainResource)
1019         return;
1020
1021     // http://bugs.webkit.org/show_bug.cgi?id=10854
1022     // The frame's last ref may be removed and it can be deleted by checkCompleted(), 
1023     // so we'll add a protective refcount
1024     RefPtr<Frame> protector(m_frame);
1025
1026     // make sure nothing's left in there
1027     if (m_frame->document()) {
1028         write(0, 0, true);
1029         m_frame->document()->finishParsing();
1030 #if USE(LOW_BANDWIDTH_DISPLAY)
1031         if (m_frame->document()->inLowBandwidthDisplay()) {
1032             m_finishedParsingDuringLowBandwidthDisplay = true;
1033             switchOutLowBandwidthDisplayIfReady();
1034         }
1035 #endif            
1036     } else
1037         // WebKit partially uses WebCore when loading non-HTML docs.  In these cases doc==nil, but
1038         // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1039         // become true.  An example is when a subframe is a pure text doc, and that subframe is the
1040         // last one to complete.
1041         checkCompleted();
1042
1043     if (m_documentLoader && !m_documentLoader->isLoadingFromCachedPage())
1044         startIconLoader();
1045 }
1046
1047 void FrameLoader::iconLoadDecisionAvailable()
1048 {
1049     if (!m_mayLoadIconLater)
1050         return;
1051     LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1052     startIconLoader();
1053     m_mayLoadIconLater = false;
1054 }
1055
1056 void FrameLoader::startIconLoader()
1057 {
1058     // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1059     // But we should instead do it when we're done parsing the head element.
1060     if (!isLoadingMainFrame())
1061         return;
1062
1063     if (!iconDatabase() || !iconDatabase()->isEnabled())
1064         return;
1065     
1066     KURL url(iconURL());
1067     String urlString(url.url());
1068     if (urlString.isEmpty())
1069         return;
1070
1071     // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1072     if (loadType() != FrameLoadTypeReload) {
1073         IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1074         if (decision == IconLoadNo) {
1075             LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1076             commitIconURLToIconDatabase(url);
1077             
1078             // We were told not to load this icon - that means this icon is already known by the database
1079             // 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
1080             // has done it.  This is after registering for the notification so the WebView can call the appropriate delegate method.
1081             // Otherwise if the icon data *is* available, notify the delegate
1082             if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1083                 LOG(IconDatabase, "Told not to load icon %s but icon data is not yet available - registering for notification and requesting load from disk", urlString.ascii().data());
1084                 m_client->registerForIconNotification();
1085                 iconDatabase()->iconForPageURL(m_URL.url(), IntSize(0, 0));
1086                 iconDatabase()->iconForPageURL(originalRequestURL().url(), IntSize(0, 0));
1087             } else
1088                 m_client->dispatchDidReceiveIcon();
1089                 
1090             return;
1091         } 
1092         
1093         if (decision == IconLoadUnknown) {
1094             // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1095             // just in case we don't end up loading later - if we commit the mapping a second time after the load, that's no big deal
1096             // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the 
1097             // icon is later read in from disk
1098             LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1099             m_mayLoadIconLater = true;    
1100             m_client->registerForIconNotification();
1101             commitIconURLToIconDatabase(url);
1102             return;
1103         }
1104     }
1105
1106     // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1107     if (!m_iconLoader)
1108         m_iconLoader.set(IconLoader::create(m_frame).release());
1109         
1110     m_iconLoader->startLoading();
1111 }
1112
1113 bool FrameLoader::restrictAccessToLocal()
1114 {
1115     return m_restrictAccessToLocal;
1116 }
1117
1118 void FrameLoader::setRestrictAccessToLocal(bool access)
1119 {
1120     m_restrictAccessToLocal = access;
1121 }
1122
1123 static HashSet<String, CaseInsensitiveHash<String> >& localSchemes()
1124 {
1125     static HashSet<String, CaseInsensitiveHash<String> > localSchemes;
1126
1127     if (localSchemes.isEmpty()) {
1128         localSchemes.add("file");
1129 #if PLATFORM(MAC)
1130         localSchemes.add("applewebdata");
1131 #endif
1132 #if PLATFORM(QT)
1133         localSchemes.add("qrc");
1134 #endif
1135     }
1136
1137     return localSchemes;
1138 }
1139
1140 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1141 {
1142     ASSERT(iconDatabase());
1143     LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.url().ascii(), m_URL.url().ascii(), originalRequestURL().url().ascii());
1144     iconDatabase()->setIconURLForPageURL(icon.url(), m_URL.url());
1145     iconDatabase()->setIconURLForPageURL(icon.url(), originalRequestURL().url());
1146 }
1147
1148 void FrameLoader::restoreDocumentState()
1149 {
1150     Document* doc = m_frame->document();
1151     if (!doc)
1152         return;
1153         
1154     HistoryItem* itemToRestore = 0;
1155     
1156     switch (loadType()) {
1157         case FrameLoadTypeReload:
1158         case FrameLoadTypeReloadAllowingStaleData:
1159         case FrameLoadTypeSame:
1160         case FrameLoadTypeReplace:
1161             break;
1162         case FrameLoadTypeBack:
1163         case FrameLoadTypeForward:
1164         case FrameLoadTypeIndexedBackForward:
1165         case FrameLoadTypeRedirectWithLockedHistory:
1166         case FrameLoadTypeStandard:
1167             itemToRestore = m_currentHistoryItem.get(); 
1168     }
1169     
1170     if (!itemToRestore)
1171         return;
1172         
1173     doc->setStateForNewFormElements(itemToRestore->documentState());
1174 }
1175
1176 void FrameLoader::gotoAnchor()
1177 {
1178     // If our URL has no ref, then we have no place we need to jump to.
1179     // OTOH if css target was set previously, we want to set it to 0, recalc
1180     // and possibly repaint because :target pseudo class may have been
1181     // set(See bug 11321)
1182     if (!m_URL.hasRef() &&
1183         !(m_frame->document() && m_frame->document()->getCSSTarget()))
1184         return;
1185
1186     DeprecatedString ref = m_URL.encodedHtmlRef();
1187     if (!gotoAnchor(ref)) {
1188         // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1189         // Decoding here has to match encoding in completeURL, which means it has to use the
1190         // page's encoding rather than UTF-8.
1191         if (m_decoder)
1192             gotoAnchor(KURL::decode_string(ref, m_decoder->encoding()));
1193     }
1194 }
1195
1196 void FrameLoader::finishedParsing()
1197 {
1198     if (m_creatingInitialEmptyDocument)
1199         return;
1200
1201     // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1202     // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1203     RefPtr<Frame> protector = m_frame->refCount() > 0 ? m_frame : 0;
1204
1205     checkCompleted();
1206
1207     if (!m_frame->view())
1208         return; // We are being destroyed by something checkCompleted called.
1209
1210     // Check if the scrollbars are really needed for the content.
1211     // If not, remove them, relayout, and repaint.
1212     m_frame->view()->restoreScrollbar();
1213
1214     m_client->dispatchDidFinishDocumentLoad();
1215
1216     gotoAnchor();
1217 }
1218
1219 void FrameLoader::loadDone()
1220 {
1221     if (m_frame->document())
1222         checkCompleted();
1223 }
1224
1225 void FrameLoader::checkCompleted()
1226 {
1227     // Any frame that hasn't completed yet?
1228     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1229         if (!child->loader()->m_isComplete)
1230             return;
1231
1232     // Have we completed before?
1233     if (m_isComplete)
1234         return;
1235
1236     // Are we still parsing?
1237     if (m_frame->document() && m_frame->document()->parsing())
1238         return;
1239
1240     // Still waiting for images/scripts?
1241     if (m_frame->document())
1242         if (numRequests(m_frame->document()))
1243             return;
1244
1245 #if USE(LOW_BANDWIDTH_DISPLAY)
1246     // as switch will be called, don't complete yet
1247     if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay() && m_needToSwitchOutLowBandwidthDisplay)
1248         return;
1249 #endif
1250
1251     // OK, completed.
1252     m_isComplete = true;
1253
1254     RefPtr<Frame> protect(m_frame);
1255     checkCallImplicitClose(); // if we didn't do it before
1256
1257     // Do not start a redirection timer for subframes here.
1258     // That is deferred until the parent is completed.
1259     if (m_scheduledRedirection && !m_frame->tree()->parent())
1260         startRedirectionTimer();
1261
1262     completed();
1263     if (m_frame->page())
1264         checkLoadComplete();
1265 }
1266
1267 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1268 {
1269     checkCompleted();
1270 }
1271
1272 void FrameLoader::scheduleCheckCompleted()
1273 {
1274     if (!m_checkCompletedTimer.isActive())
1275         m_checkCompletedTimer.startOneShot(0);
1276 }
1277
1278 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
1279 {
1280     if (m_frame->page())
1281         checkLoadComplete();
1282 }
1283
1284 void FrameLoader::scheduleCheckLoadComplete()
1285 {
1286     if (!m_checkLoadCompleteTimer.isActive())
1287         m_checkLoadCompleteTimer.startOneShot(0);
1288 }
1289
1290 void FrameLoader::checkCallImplicitClose()
1291 {
1292     if (m_didCallImplicitClose || !m_frame->document() || m_frame->document()->parsing())
1293         return;
1294
1295     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1296         if (!child->loader()->m_isComplete) // still got a frame running -> too early
1297             return;
1298
1299     // All frames completed -> set their domain to the frameset's domain
1300     // This must only be done when loading the frameset initially (#22039),
1301     // not when following a link in a frame (#44162).
1302     if (m_frame->document()) {
1303         String domain = m_frame->document()->domain();
1304         for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1305             if (child->document())
1306                 child->document()->setDomainInternal(domain);
1307     }
1308
1309     m_didCallImplicitClose = true;
1310     m_wasUnloadEventEmitted = false;
1311     if (m_frame->document())
1312         m_frame->document()->implicitClose();
1313 }
1314
1315 KURL FrameLoader::baseURL() const
1316 {
1317     ASSERT(m_frame->document());
1318     return m_frame->document()->baseURL();
1319 }
1320
1321 String FrameLoader::baseTarget() const
1322 {
1323     ASSERT(m_frame->document());
1324     return m_frame->document()->baseTarget();
1325 }
1326
1327 KURL FrameLoader::completeURL(const String& url)
1328 {
1329     ASSERT(m_frame->document());
1330     return m_frame->document()->completeURL(url).deprecatedString();
1331 }
1332
1333 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1334 {
1335     if (delay < 0 || delay > INT_MAX / 1000)
1336         return;
1337         
1338     // We want a new history item if the refresh timeout is > 1 second.
1339     if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1340         scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, false));
1341 }
1342
1343 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool wasUserGesture)
1344 {    
1345     // If the URL we're going to navigate to is the same as the current one, except for the
1346     // fragment part, we don't need to schedule the location change.
1347     KURL u(url.deprecatedString());
1348     if (u.hasRef() && equalIgnoringRef(m_URL, u)) {
1349         changeLocation(url, referrer, lockHistory, wasUserGesture);
1350         return;
1351     }
1352
1353     // Handle a location change of a page with no document as a special case.
1354     // This may happen when a frame changes the location of another frame.
1355     bool duringLoad = !m_committedFirstRealDocumentLoad;
1356
1357     // If a redirect was scheduled during a load, then stop the current load.
1358     // Otherwise when the current load transitions from a provisional to a 
1359     // committed state, pending redirects may be cancelled. 
1360     if (duringLoad) {
1361         if (m_provisionalDocumentLoader)
1362             m_provisionalDocumentLoader->stopLoading();
1363         stopLoading(true);   
1364     }
1365
1366     ScheduledRedirection::Type type = duringLoad
1367         ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1368     scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, wasUserGesture));
1369 }
1370
1371 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1372 {
1373     // Handle a location change of a page with no document as a special case.
1374     // This may happen when a frame requests a refresh of another frame.
1375     bool duringLoad = !m_frame->document();
1376     
1377     // If a refresh was scheduled during a load, then stop the current load.
1378     // Otherwise when the current load transitions from a provisional to a 
1379     // committed state, pending redirects may be cancelled. 
1380     if (duringLoad)
1381         stopLoading(true);   
1382
1383     ScheduledRedirection::Type type = duringLoad
1384         ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1385     scheduleRedirection(new ScheduledRedirection(type, m_URL.url(), m_outgoingReferrer, true, wasUserGesture));
1386     m_cachePolicy = CachePolicyRefresh;
1387 }
1388
1389 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection)
1390 {
1391     switch (redirection.type) {
1392         case ScheduledRedirection::redirection:
1393             return false;
1394         case ScheduledRedirection::historyNavigation:
1395         case ScheduledRedirection::locationChange:
1396         case ScheduledRedirection::locationChangeDuringLoad:
1397             return true;
1398     }
1399     ASSERT_NOT_REACHED();
1400     return false;
1401 }
1402
1403 void FrameLoader::scheduleHistoryNavigation(int steps)
1404 {
1405     // navigation will always be allowed in the 0 steps case, which is OK because
1406     // that's supposed to force a reload.
1407     if (!canGoBackOrForward(steps)) {
1408         cancelRedirection();
1409         return;
1410     }
1411
1412     // If the steps to navigate is not zero (which needs to force a reload), and if we think the navigation is going to be a fragment load
1413     // (when the URL we're going to navigate to is the same as the current one, except for the fragment part - but not exactly the same because that's a reload),
1414     // then we don't need to schedule the navigation.
1415     if (steps != 0) {
1416         KURL destination = historyURL(steps);
1417         // FIXME: This doesn't seem like a reliable way to tell whether or not the load will be a fragment load.
1418         if (equalIgnoringRef(m_URL, destination) && m_URL != destination) {
1419             goBackOrForward(steps);
1420             return;
1421         }
1422     }
1423     
1424     scheduleRedirection(new ScheduledRedirection(steps));
1425 }
1426
1427 void FrameLoader::goBackOrForward(int distance)
1428 {
1429     if (distance == 0)
1430         return;
1431         
1432     Page* page = m_frame->page();
1433     if (!page)
1434         return;
1435     BackForwardList* list = page->backForwardList();
1436     if (!list)
1437         return;
1438     
1439     HistoryItem* item = list->itemAtIndex(distance);
1440     if (!item) {
1441         if (distance > 0) {
1442             int forwardListCount = list->forwardListCount();
1443             if (forwardListCount > 0) 
1444                 item = list->itemAtIndex(forwardListCount);
1445         } else {
1446             int backListCount = list->backListCount();
1447             if (backListCount > 0)
1448                 item = list->itemAtIndex(-backListCount);
1449         }
1450     }
1451     
1452     ASSERT(item); // we should not reach this line with an empty back/forward list
1453     if (item)
1454         page->goToItem(item, FrameLoadTypeIndexedBackForward);
1455 }
1456
1457 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1458 {
1459     OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1460
1461     switch (redirection->type) {
1462         case ScheduledRedirection::redirection:
1463         case ScheduledRedirection::locationChange:
1464         case ScheduledRedirection::locationChangeDuringLoad:
1465             changeLocation(redirection->URL, redirection->referrer,
1466                 redirection->lockHistory, redirection->wasUserGesture);
1467             return;
1468         case ScheduledRedirection::historyNavigation:
1469             if (redirection->historySteps == 0) {
1470                 // Special case for go(0) from a frame -> reload only the frame
1471                 urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->wasUserGesture);
1472                 return;
1473             }
1474             // go(i!=0) from a frame navigates into the history of the frame only,
1475             // in both IE and NS (but not in Mozilla). We can't easily do that.
1476             goBackOrForward(redirection->historySteps);
1477             return;
1478     }
1479     ASSERT_NOT_REACHED();
1480 }
1481
1482 String FrameLoader::encoding() const
1483 {
1484     if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1485         return m_encoding;
1486     if (m_decoder && m_decoder->encoding().isValid())
1487         return m_decoder->encoding().name();
1488     Settings* settings = m_frame->settings();
1489     return settings ? settings->defaultTextEncodingName() : String();
1490 }
1491
1492 bool FrameLoader::gotoAnchor(const String& name)
1493 {
1494     ASSERT(m_frame->document());
1495
1496     if (!m_frame->document()->haveStylesheetsLoaded()) {
1497         m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1498         return false;
1499     }
1500
1501     m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1502
1503     Node* anchorNode = m_frame->document()->getElementById(AtomicString(name));
1504     if (!anchorNode)
1505         anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->document()->inCompatMode());
1506
1507 #if ENABLE(SVG)
1508     if (m_frame->document()->isSVGDocument()) {
1509         if (name.startsWith("xpointer(")) {
1510             // We need to parse the xpointer reference here
1511         } else if (name.startsWith("svgView(")) {
1512             RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
1513             if (!svg->currentView()->parseViewSpec(name))
1514                 return false;
1515             svg->setUseCurrentView(true);
1516         } else {
1517             if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
1518                 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
1519                 if (viewElement.get()) {
1520                     RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get()));
1521                     svg->inheritViewAttributes(viewElement.get());
1522                 }
1523             }
1524         }
1525         // FIXME: need to decide which <svg> to focus on, and zoom to that one
1526         // FIXME: need to actually "highlight" the viewTarget(s)
1527     }
1528 #endif
1529
1530     m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1531   
1532     // Implement the rule that "" and "top" both mean top of page as in other browsers.
1533     if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1534         return false;
1535
1536     // We need to update the layout before scrolling, otherwise we could
1537     // really mess things up if an anchor scroll comes at a bad moment.
1538     if (m_frame->document()) {
1539         m_frame->document()->updateRendering();
1540         // Only do a layout if changes have occurred that make it necessary.      
1541         if (m_frame->view() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout())
1542             m_frame->view()->layout();
1543     }
1544   
1545     // Scroll nested layers and frames to reveal the anchor.
1546     // Align to the top and to the closest side (this matches other browsers).
1547     RenderObject* renderer;
1548     IntRect rect;
1549     if (!anchorNode)
1550         renderer = m_frame->document()->renderer(); // top of document
1551     else {
1552         renderer = anchorNode->renderer();
1553         rect = anchorNode->getRect();
1554     }
1555     if (renderer)
1556         renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1557
1558     return true;
1559 }
1560
1561 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1562     const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1563 {
1564     if (url.isEmpty() && mimeType.isEmpty())
1565         return false;
1566
1567 #if USE(LOW_BANDWIDTH_DISPLAY)
1568     // don't care object during low bandwidth display
1569     if (frame()->document()->inLowBandwidthDisplay()) {
1570         m_needToSwitchOutLowBandwidthDisplay = true;
1571         return false;
1572     }
1573 #endif
1574
1575     KURL completedURL;
1576     if (!url.isEmpty())
1577         completedURL = completeURL(url);
1578
1579     bool useFallback;
1580     if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1581         Settings* settings = m_frame->settings();
1582         if (!settings || !settings->arePluginsEnabled() || 
1583             (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1584             return false;
1585         return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1586     }
1587
1588     ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1589     HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1590     
1591     // FIXME: OK to always make a new frame? When does the old frame get removed?
1592     return loadSubframe(element, completedURL, frameName, m_outgoingReferrer);
1593 }
1594
1595 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1596 {
1597     ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1598     // If an object's content can't be handled and it has no fallback, let
1599     // it be handled as a plugin to show the broken plugin icon.
1600     useFallback = objectType == ObjectContentNone && hasFallback;
1601     return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1602 }
1603
1604 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType, 
1605     const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1606 {
1607     Widget* widget = 0;
1608
1609     if (renderer && !useFallback) {
1610         Element* pluginElement = 0;
1611         if (renderer->node() && renderer->node()->isElementNode())
1612             pluginElement = static_cast<Element*>(renderer->node());
1613
1614         if (!canLoad(url, frame()->document())) {
1615             FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
1616             return false;
1617         }
1618
1619         widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()), 
1620                                         pluginElement, url, paramNames, paramValues, mimeType,
1621                                         m_frame->document()->isPluginDocument());
1622         if (widget) {
1623             renderer->setWidget(widget);
1624             m_containsPlugIns = true;
1625         }
1626     }
1627
1628     return widget != 0;
1629 }
1630
1631 void FrameLoader::clearRecordedFormValues()
1632 {
1633     m_formAboutToBeSubmitted = 0;
1634     m_formValuesAboutToBeSubmitted.clear();
1635 }
1636
1637 void FrameLoader::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1638 {
1639     m_formAboutToBeSubmitted = element;
1640     m_formValuesAboutToBeSubmitted.set(name, value);
1641 }
1642
1643 void FrameLoader::parentCompleted()
1644 {
1645     if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1646         startRedirectionTimer();
1647 }
1648
1649 String FrameLoader::outgoingReferrer() const
1650 {
1651     return m_outgoingReferrer;
1652 }
1653
1654 Frame* FrameLoader::opener()
1655 {
1656     return m_opener;
1657 }
1658
1659 void FrameLoader::setOpener(Frame* opener)
1660 {
1661     if (m_opener)
1662         m_opener->loader()->m_openedFrames.remove(m_frame);
1663     if (opener)
1664         opener->loader()->m_openedFrames.add(m_frame);
1665     m_opener = opener;
1666
1667     if (m_frame->document())
1668         m_frame->document()->initSecurityOrigin();
1669 }
1670
1671 bool FrameLoader::openedByDOM() const
1672 {
1673     return m_openedByDOM;
1674 }
1675
1676 void FrameLoader::setOpenedByDOM()
1677 {
1678     m_openedByDOM = true;
1679 }
1680
1681 void FrameLoader::handleFallbackContent()
1682 {
1683     HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1684     if (!owner || !owner->hasTagName(objectTag))
1685         return;
1686     static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1687 }
1688
1689 void FrameLoader::provisionalLoadStarted()
1690 {
1691     Page* page = m_frame->page();
1692     
1693     // this is used to update the current history item
1694     // in the event of a navigation aytime during loading
1695     m_navigationDuringLoad = false;
1696     if (page) {
1697         Document *document = page->mainFrame()->document();
1698         m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent());
1699     }
1700     
1701     m_firstLayoutDone = false;
1702     cancelRedirection(true);
1703     m_client->provisionalLoadStarted();
1704
1705     if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isInPageCache())
1706         cachePageForHistoryItem(m_currentHistoryItem.get());
1707 }
1708
1709 bool FrameLoader::userGestureHint()
1710 {
1711     Frame* rootFrame = m_frame;
1712     while (rootFrame->tree()->parent())
1713         rootFrame = rootFrame->tree()->parent();
1714
1715     if (rootFrame->scriptProxy())
1716         return rootFrame->scriptProxy()->interpreter()->wasRunByUserGesture();
1717
1718     return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
1719 }
1720
1721 void FrameLoader::didNotOpenURL(const KURL& URL)
1722 {
1723     if (m_submittedFormURL == URL)
1724         m_submittedFormURL = KURL();
1725 }
1726
1727 void FrameLoader::resetMultipleFormSubmissionProtection()
1728 {
1729     m_submittedFormURL = KURL();
1730 }
1731
1732 void FrameLoader::setEncoding(const String& name, bool userChosen)
1733 {
1734     if (!m_workingURL.isEmpty())
1735         receivedFirstData();
1736     m_encoding = name;
1737     m_encodingWasChosenByUser = userChosen;
1738 }
1739
1740 void FrameLoader::addData(const char* bytes, int length)
1741 {
1742     ASSERT(m_workingURL.isEmpty());
1743     ASSERT(m_frame->document());
1744     ASSERT(m_frame->document()->parsing());
1745     write(bytes, length);
1746 }
1747
1748 bool FrameLoader::canCachePage()
1749 {    
1750     // Cache the page, if possible.
1751     // Don't write to the cache if in the middle of a redirect, since we will want to
1752     // store the final page we end up on.
1753     // No point writing to the cache on a reload or loadSame, since we will just write
1754     // over it again when we leave that page.
1755     // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1756     // are the most interesting pages on the web, and often those that would benefit the most from caching!
1757     FrameLoadType loadType = this->loadType();
1758
1759     return m_documentLoader
1760         && m_documentLoader->mainDocumentError().isNull()
1761         && !m_frame->tree()->childCount()
1762         && !m_frame->tree()->parent()
1763         // FIXME: If we ever change this so that pages with plug-ins will be cached,
1764         // we need to make sure that we don't cache pages that have outstanding NPObjects
1765         // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1766         // they would need to be destroyed and then recreated, and there is no way that we can recreate
1767         // the right NPObjects. See <rdar://problem/5197041> for more information.
1768         && !m_containsPlugIns
1769         && !m_URL.protocol().startsWith("https")
1770         && m_frame->document()
1771         && !m_frame->document()->applets()->length()
1772         && !m_frame->document()->hasWindowEventListener(unloadEvent)
1773         && m_frame->page()
1774         && m_frame->page()->backForwardList()->enabled()
1775         && m_frame->page()->backForwardList()->capacity() > 0
1776         && m_frame->page()->settings()->usesPageCache()
1777         && m_currentHistoryItem
1778         && !isQuickRedirectComing()
1779         && loadType != FrameLoadTypeReload 
1780         && loadType != FrameLoadTypeReloadAllowingStaleData
1781         && loadType != FrameLoadTypeSame
1782         && !m_documentLoader->isLoadingInAPISense()
1783         && !m_documentLoader->isStopping();
1784 }
1785
1786 void FrameLoader::updatePolicyBaseURL()
1787 {
1788     if (m_frame->tree()->parent() && m_frame->tree()->parent()->document())
1789         setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
1790     else
1791         setPolicyBaseURL(m_URL.url());
1792 }
1793
1794 void FrameLoader::setPolicyBaseURL(const String& s)
1795 {
1796     if (m_frame->document())
1797         m_frame->document()->setPolicyBaseURL(s);
1798     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1799         child->loader()->setPolicyBaseURL(s);
1800 }
1801
1802 // This does the same kind of work that FrameLoader::openURL does, except it relies on the fact
1803 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1804 void FrameLoader::scrollToAnchor(const KURL& URL)
1805 {
1806     m_URL = URL;
1807     started();
1808
1809     gotoAnchor();
1810
1811     // It's important to model this as a load that starts and immediately finishes.
1812     // Otherwise, the parent frame may think we never finished loading.
1813     m_isComplete = false;
1814     checkCompleted();
1815 }
1816
1817 bool FrameLoader::isComplete() const
1818 {
1819     return m_isComplete;
1820 }
1821
1822 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
1823 {
1824     stopRedirectionTimer();
1825     m_scheduledRedirection.set(redirection);
1826     if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
1827         completed();
1828     if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
1829         startRedirectionTimer();
1830 }
1831
1832 void FrameLoader::startRedirectionTimer()
1833 {
1834     ASSERT(m_scheduledRedirection);
1835
1836     m_redirectionTimer.stop();
1837     m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
1838
1839     switch (m_scheduledRedirection->type) {
1840         case ScheduledRedirection::redirection:
1841         case ScheduledRedirection::locationChange:
1842         case ScheduledRedirection::locationChangeDuringLoad:
1843             clientRedirected(m_scheduledRedirection->URL.deprecatedString(),
1844                 m_scheduledRedirection->delay,
1845                 currentTime() + m_redirectionTimer.nextFireInterval(),
1846                 m_scheduledRedirection->lockHistory,
1847                 m_isExecutingJavaScriptFormAction);
1848             return;
1849         case ScheduledRedirection::historyNavigation:
1850             // Don't report history navigations.
1851             return;
1852     }
1853     ASSERT_NOT_REACHED();
1854 }
1855
1856 void FrameLoader::stopRedirectionTimer()
1857 {
1858     if (!m_redirectionTimer.isActive())
1859         return;
1860
1861     m_redirectionTimer.stop();
1862
1863     if (m_scheduledRedirection) {
1864         switch (m_scheduledRedirection->type) {
1865             case ScheduledRedirection::redirection:
1866             case ScheduledRedirection::locationChange:
1867             case ScheduledRedirection::locationChangeDuringLoad:
1868                 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
1869                 return;
1870             case ScheduledRedirection::historyNavigation:
1871                 // Don't report history navigations.
1872                 return;
1873         }
1874         ASSERT_NOT_REACHED();
1875     }
1876 }
1877
1878 void FrameLoader::completed()
1879 {
1880     RefPtr<Frame> protect(m_frame);
1881     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1882         child->loader()->parentCompleted();
1883     if (Frame* parent = m_frame->tree()->parent())
1884         parent->loader()->checkCompleted();
1885     submitFormAgain();
1886 }
1887
1888 void FrameLoader::started()
1889 {
1890     for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
1891         frame->loader()->m_isComplete = false;
1892 }
1893
1894 bool FrameLoader::containsPlugins() const 
1895
1896     return m_containsPlugIns;
1897 }
1898
1899 void FrameLoader::prepareForLoadStart()
1900 {
1901     if (Page* page = m_frame->page())
1902         page->progress()->progressStarted(m_frame);
1903     m_client->dispatchDidStartProvisionalLoad();
1904 }
1905
1906 void FrameLoader::setupForReplace()
1907 {
1908     setState(FrameStateProvisional);
1909     m_provisionalDocumentLoader = m_documentLoader;
1910     m_documentLoader = 0;
1911     detachChildren();
1912 }
1913
1914 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
1915 {
1916     activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
1917 }
1918
1919 void FrameLoader::finalSetupForReplace(DocumentLoader* loader)
1920 {
1921     m_client->clearUnarchivingState(loader);
1922 }
1923
1924 void FrameLoader::load(const KURL& URL, Event* event)
1925 {
1926     load(ResourceRequest(URL), false, true, event, 0, HashMap<String, String>());
1927 }
1928
1929 void FrameLoader::load(const FrameLoadRequest& request, bool lockHistory, bool userGesture, Event* event,
1930     HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
1931 {
1932     KURL url = request.resourceRequest().url();
1933  
1934     String referrer;
1935     String argsReferrer = request.resourceRequest().httpReferrer();
1936     if (!argsReferrer.isEmpty())
1937         referrer = argsReferrer;
1938     else
1939         referrer = m_outgoingReferrer;
1940  
1941     ASSERT(frame()->document());
1942     if (url.url().startsWith("file:", false)) {
1943         if (!canLoad(url, frame()->document()) && !canLoad(url, referrer)) {
1944             FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
1945             return;
1946         }
1947     }
1948
1949     if (shouldHideReferrer(url, referrer))
1950         referrer = String();
1951     
1952     Frame* targetFrame = m_frame->tree()->find(request.frameName());
1953     if (!shouldAllowNavigation(targetFrame))
1954         return;
1955         
1956     if (request.resourceRequest().httpMethod() != "POST") {
1957         FrameLoadType loadType;
1958         if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1959             loadType = FrameLoadTypeReload;
1960         else if (lockHistory)
1961             loadType = FrameLoadTypeRedirectWithLockedHistory;
1962         else
1963             loadType = FrameLoadTypeStandard;    
1964     
1965         RefPtr<FormState> formState;
1966         if (submitForm && !formValues.isEmpty())
1967             formState = FormState::create(submitForm, formValues, m_frame);
1968         
1969         load(request.resourceRequest().url(), referrer, loadType, 
1970             request.frameName(), event, formState.release());
1971     } else
1972         post(request.resourceRequest().url(), referrer, request.frameName(), 
1973             request.resourceRequest().httpBody(), request.resourceRequest().httpContentType(), event, submitForm, formValues);
1974
1975     if (targetFrame && targetFrame != m_frame)
1976         if (Page* page = targetFrame->page())
1977             page->chrome()->focus();
1978 }
1979
1980 void FrameLoader::load(const KURL& URL, const String& referrer, FrameLoadType newLoadType,
1981     const String& frameName, Event* event, PassRefPtr<FormState> formState)
1982 {
1983     bool isFormSubmission = formState;
1984     
1985     ResourceRequest request(URL);
1986     if (!referrer.isEmpty())
1987         request.setHTTPReferrer(referrer);
1988     addExtraFieldsToRequest(request, true, event || isFormSubmission);
1989     if (newLoadType == FrameLoadTypeReload)
1990         request.setCachePolicy(ReloadIgnoringCacheData);
1991
1992     ASSERT(newLoadType != FrameLoadTypeSame);
1993
1994     NavigationAction action(URL, newLoadType, isFormSubmission, event);
1995
1996     if (!frameName.isEmpty()) {
1997         if (Frame* targetFrame = m_frame->tree()->find(frameName))
1998             targetFrame->loader()->load(URL, referrer, newLoadType, String(), event, formState);
1999         else
2000             checkNewWindowPolicy(action, request, formState, frameName);
2001         return;
2002     }
2003
2004     RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
2005
2006     bool sameURL = shouldTreatURLAsSameAsCurrent(URL);
2007     
2008     // Make sure to do scroll to anchor processing even if the URL is
2009     // exactly the same so pages with '#' links and DHTML side effects
2010     // work properly.
2011     if (!isFormSubmission
2012         && newLoadType != FrameLoadTypeReload
2013         && newLoadType != FrameLoadTypeSame
2014         && !shouldReload(URL, url())
2015         // We don't want to just scroll if a link from within a
2016         // frameset is trying to reload the frameset into _top.
2017         && !m_frame->isFrameSet()) {
2018
2019         // Just do anchor navigation within the existing content.
2020         
2021         // We don't do this if we are submitting a form, explicitly reloading,
2022         // currently displaying a frameset, or if the new URL does not have a fragment.
2023         // These rules are based on what KHTML was doing in KHTMLPart::openURL.
2024         
2025         // FIXME: What about load types other than Standard and Reload?
2026         
2027         oldDocumentLoader->setTriggeringAction(action);
2028         stopPolicyCheck();
2029         checkNavigationPolicy(request, oldDocumentLoader.get(), formState,
2030             callContinueFragmentScrollAfterNavigationPolicy, this);
2031     } else {
2032         // must grab this now, since this load may stop the previous load and clear this flag
2033         bool isRedirect = m_quickRedirectComing;
2034         load(request, action, newLoadType, formState);
2035         if (isRedirect) {
2036             m_quickRedirectComing = false;
2037             if (m_provisionalDocumentLoader)
2038                 m_provisionalDocumentLoader->setIsClientRedirect(true);
2039         } else if (sameURL)
2040             // Example of this case are sites that reload the same URL with a different cookie
2041             // driving the generated content, or a master frame with links that drive a target
2042             // frame, where the user has clicked on the same link repeatedly.
2043             m_loadType = FrameLoadTypeSame;
2044     }
2045 }
2046
2047 void FrameLoader::load(const ResourceRequest& request)
2048 {
2049     load(request, SubstituteData());
2050 }
2051
2052 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData)
2053 {
2054     if (m_inStopAllLoaders)
2055         return;
2056         
2057     // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2058     m_loadType = FrameLoadTypeStandard;
2059     load(m_client->createDocumentLoader(request, substituteData).get());
2060 }
2061
2062 void FrameLoader::load(const ResourceRequest& request, const String& frameName)
2063 {
2064     if (frameName.isEmpty()) {
2065         load(request);
2066         return;
2067     }
2068
2069     Frame* frame = m_frame->tree()->find(frameName);
2070     if (frame) {
2071         frame->loader()->load(request);
2072         return;
2073     }
2074
2075     checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
2076 }
2077
2078 void FrameLoader::load(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState)
2079 {
2080     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2081
2082     loader->setTriggeringAction(action);
2083     if (m_documentLoader)
2084         loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2085
2086     load(loader.get(), type, formState);
2087 }
2088
2089 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2090 {
2091     ResourceRequest& r = newDocumentLoader->request();
2092     addExtraFieldsToRequest(r, true, false);
2093     FrameLoadType type;
2094
2095     if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2096         r.setCachePolicy(ReloadIgnoringCacheData);
2097         type = FrameLoadTypeSame;
2098     } else
2099         type = FrameLoadTypeStandard;
2100
2101     if (m_documentLoader)
2102         newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2103     
2104     // When we loading alternate content for an unreachable URL that we're
2105     // visiting in the b/f list, we treat it as a reload so the b/f list 
2106     // is appropriately maintained.
2107     if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2108         ASSERT(type == FrameLoadTypeStandard);
2109         type = FrameLoadTypeReload;
2110     }
2111
2112     load(newDocumentLoader, type, 0);
2113 }
2114
2115 void FrameLoader::load(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> formState)
2116 {
2117     ASSERT(m_client->hasWebView());
2118
2119     // Unfortunately the view must be non-nil, this is ultimately due
2120     // to parser requiring a FrameView.  We should fix this dependency.
2121
2122     ASSERT(m_client->hasFrameView());
2123
2124     m_policyLoadType = type;
2125
2126     if (Frame* parent = m_frame->tree()->parent())
2127         loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2128
2129     stopPolicyCheck();
2130     setPolicyDocumentLoader(loader);
2131
2132     checkNavigationPolicy(loader->request(), loader, formState,
2133         callContinueLoadAfterNavigationPolicy, this);
2134 }
2135
2136 // FIXME: It would be nice if we could collapse these into one or two functions.
2137 bool FrameLoader::canLoad(const KURL& url, const String& referrer)
2138 {
2139     if (!shouldTreatURLAsLocal(url.url()))
2140         return true;
2141
2142     return shouldTreatURLAsLocal(referrer);
2143 }
2144
2145 bool FrameLoader::canLoad(const KURL& url, const Document* doc)
2146 {
2147     if (!shouldTreatURLAsLocal(url.url()))
2148         return true;
2149
2150     return doc && doc->isAllowedToLoadLocalResources();
2151 }
2152
2153 bool FrameLoader::canLoad(const CachedResource& resource, const Document* doc)
2154 {
2155     if (!resource.treatAsLocal())
2156         return true;
2157
2158     return doc && doc->isAllowedToLoadLocalResources();
2159 }
2160
2161 void FrameLoader::reportLocalLoadFailed(const Page* page, const String& url)
2162 {
2163     ASSERT(!url.isEmpty());
2164     if (page)
2165         page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2166 }
2167
2168 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2169 {
2170     bool referrerIsSecureURL = referrer.startsWith("https:", false);
2171     bool referrerIsWebURL = referrerIsSecureURL || referrer.startsWith("http:", false);
2172
2173     if (!referrerIsWebURL)
2174         return true;
2175
2176     if (!referrerIsSecureURL)
2177         return false;
2178
2179     bool URLIsSecureURL = url.url().startsWith("https:", false);
2180
2181     return !URLIsSecureURL;
2182 }
2183
2184 const ResourceRequest& FrameLoader::initialRequest() const
2185 {
2186     return activeDocumentLoader()->initialRequest();
2187 }
2188
2189 void FrameLoader::receivedData(const char* data, int length)
2190 {
2191     activeDocumentLoader()->receivedData(data, length);
2192 }
2193
2194 bool FrameLoader::willUseArchive(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) const
2195 {
2196     return m_client->willUseArchive(loader, request, originalURL);
2197 }
2198
2199 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2200 {
2201     m_delegateIsHandlingUnimplementablePolicy = true;
2202     m_client->dispatchUnableToImplementPolicy(error);
2203     m_delegateIsHandlingUnimplementablePolicy = false;
2204 }
2205
2206 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2207 {
2208     handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2209 }
2210
2211 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2212 {
2213     return m_client->interruptForPolicyChangeError(request);
2214 }
2215
2216 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2217 {
2218     checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2219 }
2220
2221 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2222 {
2223     ASSERT(activeDocumentLoader());
2224     
2225     // Always show content with valid substitute data.
2226     if (activeDocumentLoader()->substituteData().isValid()) {
2227         function(argument, PolicyUse);
2228         return;
2229     }
2230
2231 #if ENABLE(FTPDIR)
2232     // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2233     Settings* settings = m_frame->settings();
2234     if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2235         function(argument, PolicyUse);
2236         return;
2237     }
2238 #endif
2239
2240     m_policyCheck.set(function, argument);
2241     m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2242         MIMEType, activeDocumentLoader()->request());
2243 }
2244
2245 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2246 {
2247     KURL unreachableURL = docLoader->unreachableURL();
2248
2249     if (unreachableURL.isEmpty())
2250         return false;
2251
2252     if (!isBackForwardLoadType(m_policyLoadType))
2253         return false;
2254
2255     // We only treat unreachableURLs specially during the delegate callbacks
2256     // for provisional load errors and navigation policy decisions. The former
2257     // case handles well-formed URLs that can't be loaded, and the latter
2258     // case handles malformed URLs and unknown schemes. Loading alternate content
2259     // at other times behaves like a standard load.
2260     DocumentLoader* compareDocumentLoader = 0;
2261     if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2262         compareDocumentLoader = m_policyDocumentLoader.get();
2263     else if (m_delegateIsHandlingProvisionalLoadError)
2264         compareDocumentLoader = m_provisionalDocumentLoader.get();
2265
2266     return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2267 }
2268
2269 void FrameLoader::reloadAllowingStaleData(const String& encoding)
2270 {
2271     if (!m_documentLoader)
2272         return;
2273
2274     ResourceRequest request = m_documentLoader->request();
2275     KURL unreachableURL = m_documentLoader->unreachableURL();
2276     if (!unreachableURL.isEmpty())
2277         request.setURL(unreachableURL);
2278
2279     request.setCachePolicy(ReturnCacheDataElseLoad);
2280
2281     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2282     setPolicyDocumentLoader(loader.get());
2283
2284     loader->setOverrideEncoding(encoding);
2285
2286     load(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0);
2287 }
2288
2289 void FrameLoader::reload()
2290 {
2291     if (!m_documentLoader)
2292         return;
2293
2294     ResourceRequest& initialRequest = m_documentLoader->request();
2295     
2296     // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2297     // Reloading in this case will lose the current contents (see 4151001).
2298     if (initialRequest.url().isEmpty())
2299         return;
2300
2301     // Replace error-page URL with the URL we were trying to reach.
2302     KURL unreachableURL = m_documentLoader->unreachableURL();
2303     if (!unreachableURL.isEmpty())
2304         initialRequest = ResourceRequest(unreachableURL);
2305     
2306     RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2307
2308     ResourceRequest& request = loader->request();
2309
2310     request.setCachePolicy(ReloadIgnoringCacheData);
2311     request.setHTTPHeaderField("Cache-Control", "max-age=0");
2312
2313     // If we're about to re-post, set up action so the application can warn the user.
2314     if (request.httpMethod() == "POST")
2315         loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2316
2317     loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2318     
2319     load(loader.get(), FrameLoadTypeReload, 0);
2320 }
2321
2322 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2323 {
2324     // The navigation change is safe if the active frame is:
2325     //   - in the same security origin as the target or one of the target's ancestors
2326     // Or the target frame is:
2327     //   - a top-level frame in the frame hierarchy
2328
2329     if (!targetFrame)
2330         return true;
2331
2332     if (m_frame == targetFrame)
2333         return true;
2334
2335     if (!targetFrame->tree()->parent())
2336         return true;
2337
2338     Document* activeDocument = m_frame->document();
2339     ASSERT(activeDocument);
2340     const SecurityOrigin& activeSecurityOrigin = activeDocument->securityOrigin();
2341     for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2342         Document* ancestorDocument = ancestorFrame->document();
2343         if (!ancestorDocument)
2344             return true;
2345
2346         const SecurityOrigin& ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2347         if (activeSecurityOrigin.canAccess(ancestorSecurityOrigin))
2348             return true;
2349     }
2350
2351     if (!targetFrame->settings()->privateBrowsingEnabled()) {
2352         Document* targetDocument = targetFrame->document();
2353         // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2354         String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2355                                         targetDocument->URL().utf8().data(), activeDocument->URL().utf8().data());
2356
2357         if (KJS::Interpreter::shouldPrintExceptions())
2358             printf("%s", message.utf8().data());
2359
2360         // FIXME: should we print to the console of the activeFrame as well?
2361         if (Page* page = targetFrame->page())
2362             page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, 1, String());
2363     }
2364     
2365     return false;
2366 }
2367
2368 void FrameLoader::stopLoadingSubframes()
2369 {
2370     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2371         child->loader()->stopAllLoaders();
2372 }
2373
2374 void FrameLoader::stopAllLoaders()
2375 {
2376     // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2377     if (m_inStopAllLoaders)
2378         return;
2379
2380     m_inStopAllLoaders = true;
2381
2382     stopPolicyCheck();
2383
2384     stopLoadingSubframes();
2385     if (m_provisionalDocumentLoader)
2386         m_provisionalDocumentLoader->stopLoading();
2387     if (m_documentLoader)
2388         m_documentLoader->stopLoading();
2389     setProvisionalDocumentLoader(0);
2390     m_client->clearArchivedResources();
2391
2392     m_inStopAllLoaders = false;    
2393 }
2394
2395 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2396 {
2397     stopAllLoaders();
2398     
2399     if (deferCheckLoadComplete)
2400         scheduleCheckLoadComplete();
2401     else if (m_frame->page())
2402         checkLoadComplete();
2403 }
2404
2405 void FrameLoader::cancelPendingArchiveLoad(ResourceLoader* loader)
2406 {
2407     m_client->cancelPendingArchiveLoad(loader);
2408 }
2409
2410 DocumentLoader* FrameLoader::activeDocumentLoader() const
2411 {
2412     if (m_state == FrameStateProvisional)
2413         return m_provisionalDocumentLoader.get();
2414     return m_documentLoader.get();
2415 }
2416
2417 bool FrameLoader::isLoading() const
2418 {
2419     DocumentLoader* docLoader = activeDocumentLoader();
2420     if (!docLoader)
2421         return false;
2422     return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2423 }
2424
2425 bool FrameLoader::frameHasLoaded() const
2426 {
2427     return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument); 
2428 }
2429
2430 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2431 {
2432     if (!loader && !m_documentLoader)
2433         return;
2434     
2435     ASSERT(loader != m_documentLoader);
2436     ASSERT(!loader || loader->frameLoader() == this);
2437
2438     m_client->prepareForDataSourceReplacement();
2439     detachChildren();
2440     if (m_documentLoader)
2441         m_documentLoader->detachFromFrame();
2442
2443     m_documentLoader = loader;
2444 }
2445
2446 DocumentLoader* FrameLoader::documentLoader() const
2447 {
2448     return m_documentLoader.get();
2449 }
2450
2451 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2452 {
2453     if (m_policyDocumentLoader == loader)
2454         return;
2455
2456     ASSERT(m_frame);
2457     if (loader)
2458         loader->setFrame(m_frame);
2459     if (m_policyDocumentLoader
2460             && m_policyDocumentLoader != m_provisionalDocumentLoader
2461             && m_policyDocumentLoader != m_documentLoader)
2462         m_policyDocumentLoader->detachFromFrame();
2463
2464     m_policyDocumentLoader = loader;
2465 }
2466    
2467 DocumentLoader* FrameLoader::provisionalDocumentLoader()
2468 {
2469     return m_provisionalDocumentLoader.get();
2470 }
2471
2472 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2473 {
2474     ASSERT(!loader || !m_provisionalDocumentLoader);
2475     ASSERT(!loader || loader->frameLoader() == this);
2476
2477     if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2478         m_provisionalDocumentLoader->detachFromFrame();
2479
2480     m_provisionalDocumentLoader = loader;
2481 }
2482
2483 FrameState FrameLoader::state() const
2484 {
2485     return m_state;
2486 }
2487
2488 double FrameLoader::timeOfLastCompletedLoad()
2489 {
2490     return storedTimeOfLastCompletedLoad;
2491 }
2492
2493 void FrameLoader::setState(FrameState newState)
2494 {    
2495     m_state = newState;
2496     
2497     if (newState == FrameStateProvisional)
2498         provisionalLoadStarted();
2499     else if (newState == FrameStateComplete) {
2500         frameLoadCompleted();
2501         storedTimeOfLastCompletedLoad = currentTime();
2502         if (m_documentLoader)
2503             m_documentLoader->stopRecordingResponses();
2504     }
2505 }
2506
2507 void FrameLoader::clearProvisionalLoad()
2508 {
2509     setProvisionalDocumentLoader(0);
2510     if (Page* page = m_frame->page())
2511         page->progress()->progressCompleted(m_frame);
2512     setState(FrameStateComplete);
2513 }
2514
2515 void FrameLoader::markLoadComplete()
2516 {
2517     setState(FrameStateComplete);
2518 }
2519
2520 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2521 {
2522     RefPtr<CachedPage> cachedPage = prpCachedPage;
2523     RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2524     
2525     if (m_loadType != FrameLoadTypeReplace)
2526         closeOldDataSources();
2527     
2528     if (!cachedPage && !m_creatingInitialEmptyDocument)
2529         m_client->makeRepresentation(pdl.get());
2530     
2531     transitionToCommitted(cachedPage);
2532     
2533     // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2534     // status has changed, if there was a redirect.  The frame load delegate may have saved some state about
2535     // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:.  Since we are
2536     // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2537     if (m_sentRedirectNotification)
2538         clientRedirectCancelledOrFinished(false);
2539     
2540     if (cachedPage && cachedPage->document()) {
2541         open(*cachedPage);
2542         cachedPage->clear();
2543     } else {        
2544         KURL url = pdl->substituteData().responseURL();
2545         if (url.isEmpty())
2546             url = pdl->URL();
2547         if (url.isEmpty())
2548             url = pdl->responseURL();
2549         if (url.isEmpty())
2550             url = "about:blank";
2551
2552         didOpenURL(url);
2553     }
2554     opened();
2555 }
2556
2557 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2558 {
2559     ASSERT(m_client->hasWebView());
2560     ASSERT(m_state == FrameStateProvisional);
2561
2562     if (m_state != FrameStateProvisional)
2563         return;
2564
2565     m_client->setCopiesOnScroll();
2566     updateHistoryForCommit();
2567
2568     // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2569     // JavaScript. If the script initiates a new load, we need to abandon the current load,
2570     // or the two will stomp each other.
2571     DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2572     if (m_documentLoader)
2573         closeURL();
2574     if (pdl != m_provisionalDocumentLoader)
2575         return;
2576
2577     // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2578     if (m_documentLoader)
2579         m_documentLoader->stopLoadingSubresources();
2580     if (m_documentLoader)
2581         m_documentLoader->stopLoadingPlugIns();
2582
2583     setDocumentLoader(m_provisionalDocumentLoader.get());
2584     setProvisionalDocumentLoader(0);
2585     setState(FrameStateCommittedPage);
2586
2587     // Handle adding the URL to the back/forward list.
2588     DocumentLoader* dl = m_documentLoader.get();
2589     String ptitle = dl->title(); 
2590
2591     switch (m_loadType) {
2592         case FrameLoadTypeForward:
2593         case FrameLoadTypeBack:
2594         case FrameLoadTypeIndexedBackForward:
2595             if (Page* page = m_frame->page())
2596                 if (page->backForwardList()) {
2597                     updateHistoryForBackForwardNavigation();
2598
2599                     // Create a document view for this document, or used the cached view.
2600                     if (cachedPage)
2601                         m_client->setDocumentViewFromCachedPage(cachedPage.get());
2602                     else
2603                         m_client->makeDocumentView();
2604                 }
2605             break;
2606
2607         case FrameLoadTypeReload:
2608         case FrameLoadTypeSame:
2609         case FrameLoadTypeReplace:
2610             updateHistoryForReload();
2611             m_client->makeDocumentView();
2612             break;
2613
2614         // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllowingStaleData with the above case
2615         case FrameLoadTypeReloadAllowingStaleData:
2616             m_client->makeDocumentView();
2617             break;
2618
2619         case FrameLoadTypeStandard:
2620             updateHistoryForStandardLoad();
2621 #ifndef BUILDING_ON_TIGER
2622             // This code was originally added for a Leopard performance imporvement. We decided to 
2623             // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
2624             if (m_frame->view())
2625                 m_frame->view()->suppressScrollbars(true);
2626 #endif
2627             m_client->makeDocumentView();
2628             break;
2629
2630         case FrameLoadTypeRedirectWithLockedHistory:
2631             updateHistoryForRedirectWithLockedHistory();
2632             m_client->makeDocumentView();
2633             break;
2634
2635         // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2636         // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2637         default:
2638             ASSERT_NOT_REACHED();
2639     }
2640
2641     m_responseMIMEType = dl->responseMIMEType();
2642
2643     // Tell the client we've committed this URL.
2644     ASSERT(m_client->hasFrameView());
2645
2646     if (m_creatingInitialEmptyDocument)
2647         return;
2648
2649     m_committedFirstRealDocumentLoad = true;
2650     
2651     // For non-cached HTML pages, these methods are called in FrameLoader::begin.
2652     if (cachedPage || !m_client->hasHTMLView()) {
2653         dispatchDidCommitLoad(); 
2654             
2655         // If we have a title let the WebView know about it. 
2656         if (!ptitle.isNull()) 
2657             m_client->dispatchDidReceiveTitle(ptitle);         
2658     }
2659 }
2660
2661 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2662 {
2663     // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2664     // the redirect succeeded.  We should either rename this API, or add a new method, like
2665     // -webView:didFinishClientRedirectForFrame:
2666     m_client->dispatchDidCancelClientRedirect();
2667
2668     if (!cancelWithLoadInProgress)
2669         m_quickRedirectComing = false;
2670
2671     m_sentRedirectNotification = false;
2672 }
2673
2674 void FrameLoader::clientRedirected(const KURL& URL, double seconds, double fireDate, bool lockHistory, bool isJavaScriptFormAction)
2675 {
2676     m_client->dispatchWillPerformClientRedirect(URL, seconds, fireDate);
2677     
2678     // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2679     // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2680     m_sentRedirectNotification = true;
2681     
2682     // If a "quick" redirect comes in an, we set a special mode so we treat the next
2683     // load as part of the same navigation. If we don't have a document loader, we have
2684     // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2685     m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptFormAction;
2686 }
2687
2688 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2689 {
2690     // This function implements the rule: "Don't reload if navigating by fragment within
2691     // the same URL, but do reload if going to a new URL or to the same URL with no
2692     // fragment identifier at all."
2693     if (!currentURL.hasRef() && !destinationURL.hasRef())
2694         return true;
2695     return !equalIgnoringRef(currentURL, destinationURL);
2696 }
2697
2698 void FrameLoader::closeOldDataSources()
2699 {
2700     // FIXME: Is it important for this traversal to be postorder instead of preorder?
2701     // If so, add helpers for postorder traversal, and use them. If not, then lets not
2702     // use a recursive algorithm here.
2703     for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2704         child->loader()->closeOldDataSources();
2705     
2706     if (m_documentLoader)
2707         m_client->dispatchWillClose();
2708
2709     m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2710 }
2711
2712 void FrameLoader::open(CachedPage& cachedPage)
2713 {
2714     ASSERT(m_frame->page());
2715     ASSERT(m_frame->page()->mainFrame() == m_frame);
2716
2717     cancelRedirection();
2718
2719     // We still have to close the previous part page.
2720     closeURL();
2721
2722     m_isComplete = false;
2723     
2724     // Don't re-emit the load event.
2725     m_didCallImplicitClose = true;
2726     
2727     // Delete old status bar messages (if it _was_ activated on last URL).
2728     Settings* settings = m_frame->settings();
2729     if (settings && settings->isJavaScriptEnabled()) {
2730         m_frame->setJSStatusBarText(String());
2731         m_frame->setJSDefaultStatusBarText(String());
2732     }
2733
2734     KURL URL = cachedPage.URL();
2735
2736     if (URL.protocol().startsWith("http") && !URL.host().isEmpty() && URL.path().isEmpty())
2737         URL.setPath("/");
2738     
2739     m_URL = URL;
2740     m_workingURL = URL;
2741
2742     started();
2743
2744     clear();
2745
2746     Document* document = cachedPage.document();
2747     ASSERT(document);
2748     document->setInPageCache(false);
2749
2750     m_needsClear = true;
2751     m_isComplete = false;
2752     m_didCallImplicitClose = false;
2753     m_outgoingReferrer = URL.url();
2754
2755     FrameView* view = cachedPage.view();
2756     if (view)
2757         view->setWasScrolledByUser(false);
2758     m_frame->setView(view);
2759     
2760     m_frame->setDocument(document);
2761     m_decoder = document->decoder();
2762
2763     updatePolicyBaseURL();
2764
2765     cachedPage.restore(m_frame->page());
2766
2767     checkCompleted();
2768 }
2769
2770 bool FrameLoader::isStopping() const
2771 {
2772     return activeDocumentLoader()->isStopping();
2773 }
2774
2775 void FrameLoader::finishedLoading()
2776 {
2777     // Retain because the stop may release the last reference to it.
2778     RefPtr<Frame> protect(m_frame);
2779
2780     RefPtr<DocumentLoader> dl = activeDocumentLoader();
2781     dl->finishedLoading();
2782     if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
2783         return;
2784     dl->setPrimaryLoadComplete(true);
2785     m_client->dispatchDidLoadMainResource(dl.get());
2786     checkLoadComplete();
2787 }
2788
2789 // FIXME: Which one of these URL methods is right?
2790
2791 KURL FrameLoader::url() const
2792 {
2793     return m_URL;
2794 }
2795
2796 KURL FrameLoader::URL() const
2797 {
2798     return activeDocumentLoader()->URL();
2799 }
2800
2801 bool FrameLoader::isArchiveLoadPending(ResourceLoader* loader) const
2802 {
2803     return m_client->isArchiveLoadPending(loader);
2804 }
2805
2806 bool FrameLoader::isHostedByObjectElement() const
2807 {
2808     HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2809     return owner && owner->hasTagName(objectTag);
2810 }
2811
2812 bool FrameLoader::isLoadingMainFrame() const
2813 {
2814     Page* page = m_frame->page();
2815     return page && m_frame == page->mainFrame();
2816 }
2817
2818 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
2819 {
2820     return m_client->canShowMIMEType(MIMEType);
2821 }
2822
2823 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
2824 {
2825     return m_client->representationExistsForURLScheme(URLScheme);
2826 }
2827
2828 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
2829 {
2830     return m_client->generatedMIMETypeForURLScheme(URLScheme);
2831 }
2832
2833 void FrameLoader::cancelContentPolicyCheck()
2834 {
2835     m_client->cancelPolicyCheck();
2836     m_policyCheck.clear();
2837 }
2838
2839 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
2840 {
2841     m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
2842 }
2843
2844 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
2845 {
2846 #if PLATFORM(WIN)
2847     if (!m_creatingInitialEmptyDocument)
2848 #endif
2849         m_client->finishedLoading(loader);
2850 }
2851
2852 bool FrameLoader::isReplacing() const
2853 {
2854     return m_loadType == FrameLoadTypeReplace;
2855 }
2856
2857 void FrameLoader::setReplacing()
2858 {
2859     m_loadType = FrameLoadTypeReplace;
2860 }
2861
2862 void FrameLoader::revertToProvisional(DocumentLoader* loader)
2863 {
2864     m_client->revertToProvisionalState(loader);
2865 }
2866
2867 bool FrameLoader::subframeIsLoading() const
2868 {
2869     // It's most likely that the last added frame is the last to load so we walk backwards.
2870     for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
2871         FrameLoader* childLoader = child->loader();
2872         DocumentLoader* documentLoader = childLoader->documentLoader();
2873         if (documentLoader && documentLoader->isLoadingInAPISense())
2874             return true;
2875         documentLoader = childLoader->provisionalDocumentLoader();
2876         if (documentLoader && documentLoader->isLoadingInAPISense())
2877             return true;
2878     }
2879     return false;
2880 }
2881
2882 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2883 {
2884     m_client->willChangeTitle(loader);
2885 }
2886
2887 FrameLoadType FrameLoader::loadType() const
2888 {
2889     return m_loadType;
2890 }
2891
2892 void FrameLoader::stopPolicyCheck()
2893 {
2894     m_client->cancelPolicyCheck();
2895     PolicyCheck check = m_policyCheck;
2896     m_policyCheck.clear();
2897     check.cancel();
2898 }
2899
2900 void FrameLoader::checkLoadCompleteForThisFrame()
2901 {
2902     ASSERT(m_client->hasWebView());
2903
2904     switch (m_state) {
2905         case FrameStateProvisional: {
2906             if (m_delegateIsHandlingProvisionalLoadError)
2907                 return;
2908
2909             RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2910             if (!pdl)
2911                 return;
2912                 
2913             // If we've received any errors we may be stuck in the provisional state and actually complete.
2914             const ResourceError& error = pdl->mainDocumentError();
2915             if (error.isNull())
2916                 return;
2917
2918             // Check all children first.
2919             RefPtr<HistoryItem> item;
2920             if (Page* page = m_frame->page())
2921                 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
2922                     item = m_currentHistoryItem;
2923                 
2924             bool shouldReset = true;
2925             if (!pdl->isLoadingInAPISense()) {
2926                 m_delegateIsHandlingProvisionalLoadError = true;
2927                 m_client->dispatchDidFailProvisionalLoad(error);
2928                 m_delegateIsHandlingProvisionalLoadError = false;
2929
2930                 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
2931                 // which it must be to be in this branch of the if? And is it OK to just do a full-on
2932                 // stopAllLoaders instead of stopLoadingSubframes?
2933                 stopLoadingSubframes();
2934                 pdl->stopLoading();
2935
2936                 // Finish resetting the load state, but only if another load hasn't been started by the
2937                 // delegate callback.
2938                 if (pdl == m_provisionalDocumentLoader)
2939                     clearProvisionalLoad();
2940                 else if (m_provisionalDocumentLoader) {
2941                     KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
2942                     if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2943                         shouldReset = false;
2944                 }
2945             }
2946             if (shouldReset && item)
2947                 if (Page* page = m_frame->page())
2948                     page->backForwardList()->goToItem(item.get());
2949             return;
2950         }
2951         
2952         case FrameStateCommittedPage: {
2953             DocumentLoader* dl = m_documentLoader.get();            
2954             if (!dl || dl->isLoadingInAPISense())
2955                 return;
2956
2957             markLoadComplete();
2958
2959             // FIXME: Is this subsequent work important if we already navigated away?
2960             // Maybe there are bugs because of that, or extra work we can skip because
2961             // the new page is ready.
2962
2963             m_client->forceLayoutForNonHTML();
2964              
2965             // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2966             if (Page* page = m_frame->page())
2967                 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload) && page->backForwardList())
2968                     restoreScrollPositionAndViewState();
2969
2970             if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
2971                 return;
2972
2973             const ResourceError& error = dl->mainDocumentError();
2974 #ifndef NDEBUG
2975             ASSERT(m_didDispatchDidCommitLoad);
2976             m_didDispatchDidCommitLoad = false;
2977 #endif
2978             if (!error.isNull())
2979                 m_client->dispatchDidFailLoad(error);
2980             else
2981                 m_client->dispatchDidFinishLoad();
2982
2983             if (Page* page = m_frame->page())
2984                 page->progress()->progressCompleted(m_frame);
2985             return;
2986         }
2987         
2988         case FrameStateComplete:
2989             // Even if already complete, we might have set a previous item on a frame that
2990             // didn't do any data loading on the past transaction. Make sure to clear these out.
2991             m_client->frameLoadCompleted();
2992             return;
2993     }
2994
2995     ASSERT_NOT_REACHED();
2996 }
2997
2998 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
2999 {
3000     PolicyCheck check = m_policyCheck;
3001     m_policyCheck.clear();
3002     check.call(policy);
3003 }
3004
3005 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
3006 {
3007     if (!m_provisionalDocumentLoader)
3008         return;
3009
3010     m_provisionalDocumentLoader->prepareForLoadStart();
3011
3012     DocumentLoader* activeDocLoader = activeDocumentLoader();
3013     if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3014         return;
3015
3016     m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
3017
3018     unsigned long identifier = 0;
3019
3020     if (Page* page = m_frame->page()) {
3021         identifier = page->progress()->createUniqueIdentifier();
3022         dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3023     }
3024
3025     if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3026         m_provisionalDocumentLoader->updateLoading();
3027 }
3028
3029 void FrameLoader::didFirstLayout()
3030 {
3031     if (Page* page = m_frame->page())
3032         if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3033             restoreScrollPositionAndViewState();
3034
3035     m_firstLayoutDone = true;
3036     m_client->dispatchDidFirstLayout();
3037 }
3038
3039 void FrameLoader::frameLoadCompleted()
3040 {
3041     m_client->frameLoadCompleted();
3042
3043     // After a canceled provisional load, firstLayoutDone is false.
3044     // Reset it to true if we're displaying a page.
3045     if (m_documentLoader)
3046         m_firstLayoutDone = true;
3047 }
3048
3049 bool FrameLoader::firstLayoutDone() const
3050 {
3051     return m_firstLayoutDone;
3052 }
3053
3054 bool FrameLoader::isQuickRedirectComing() const
3055 {
3056     return m_quickRedirectComing;
3057 }
3058
3059 void FrameLoader::detachChildren()
3060 {
3061     // FIXME: Is it really necessary to do this in reverse order?
3062     Frame* previous;
3063     for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3064         previous = child->tree()->previousSibling();
3065         child->loader()->detachFromParent();
3066     }
3067 }
3068
3069 void FrameLoader::recursiveCheckLoadComplete()
3070 {
3071     Vector<RefPtr<Frame>, 10> frames;
3072     
3073     for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3074         frames.append(frame);
3075     
3076     unsigned size = frames.size();
3077     for (unsigned i = 0; i < size; i++)
3078         frames[i]->loader()->recursiveCheckLoadComplete();
3079     
3080     checkLoadCompleteForThisFrame();
3081 }
3082
3083 // Called every time a resource is completely loaded, or an error is received.
3084 void FrameLoader::checkLoadComplete()
3085 {
3086     ASSERT(m_client->hasWebView());
3087     
3088     // FIXME: Always traversing the entire frame tree is a bit inefficient, but 
3089     // is currently needed in order to null out the previous history item for all frames.
3090     if (Page* page = m_frame->page())
3091         page->mainFrame()->loader()->recursiveCheckLoadComplete();
3092 }
3093
3094 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3095 {
3096     if (!recurse)
3097         return numRequests(m_frame->document());
3098
3099     int count = 0;
3100     for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3101         count += numRequests(frame->document());
3102     return count;
3103 }
3104
3105 FrameLoaderClient* FrameLoader::client() const
3106 {
3107     return m_client;
3108 }
3109
3110 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event)
3111 {
3112     // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
3113     // We do not want to submit more than one form from the same page,
3114     // nor do we want to submit a single form more than once.
3115     // This flag prevents these from happening; not sure how other browsers prevent this.
3116     // The flag is reset in each time we start handle a new mouse or key down event, and
3117     // also in setView since this part may get reused for a page from the back/forward cache.
3118     // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
3119     // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
3120     // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
3121     // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
3122     Frame* target = m_frame->tree()->find(request.frameName());
3123     if (m_frame->tree()->isDescendantOf(target)) {
3124         if (m_submittedFormURL == request.resourceRequest().url())
3125             return;
3126         m_submittedFormURL = request.resourceRequest().url();
3127     }
3128
3129     // FIXME: We should probably call userGestureHint() to tell whether this form submission was the result of a user gesture.
3130     load(request, false, true, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
3131
3132     clearRecordedFormValues();
3133 }
3134
3135 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool userGesture)
3136 {
3137     FrameLoadRequest copy = request;
3138     if (copy.resourceRequest().httpReferrer().isEmpty())
3139         copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
3140
3141     load(copy, lockHistory, userGesture, event, 0, HashMap<String, String>());
3142 }
3143     
3144 String FrameLoader::userAgent(const KURL& url) const
3145 {
3146     return m_client->userAgent(url);
3147 }
3148
3149 void FrameLoader::tokenizerProcessedData()
3150 {
3151     ASSERT(m_frame->page());
3152     ASSERT(m_frame->document());
3153
3154     checkCompleted();
3155 }
3156
3157 void FrameLoader::didTellBridgeAboutLoad(const String& URL)
3158 {
3159     m_urlsBridgeKnowsAbout.add(URL);
3160 }
3161
3162 bool FrameLoader::haveToldBridgeAboutLoad(const String& URL)
3163 {
3164     return m_urlsBridgeKnowsAbout.contains(URL);
3165 }
3166
3167 void FrameLoader::handledOnloadEvents()
3168 {
3169     m_client->dispatchDidHandleOnloadEvents();
3170 }
3171
3172 void FrameLoader::frameDetached()
3173 {
3174     stopAllLoaders();
3175     detachFromParent();
3176 }
3177
3178 void FrameLoader::detachFromParent()
3179 {
3180     RefPtr<Frame> protect(m_frame);
3181
3182     closeURL();
3183     stopAllLoaders();
3184     saveScrollPositionAndViewStateToItem(currentHistoryItem());
3185     detachChildren();
3186
3187     if (Page* page = m_frame->page())
3188         page->inspectorController()->frameDetachedFromParent(m_frame);
3189
3190     m_client->detachedFromParent2();
3191     setDocumentLoader(0);
3192     m_client->detachedFromParent3();
3193     if (Frame* parent = m_frame->tree()->parent()) {
3194         parent->tree()->removeChild(m_frame);
3195         parent->loader()->scheduleCheckCompleted();
3196     } else {
3197         m_frame->setView(0);
3198         m_frame->pageDestroyed();
3199     }
3200 #if PLATFORM(MAC)
3201     [m_frame->bridge() close];
3202 #endif
3203     m_client->detachedFromParent4();
3204 }
3205
3206 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainResource, bool alwaysFromRequest)
3207 {
3208     applyUserAgent(request);
3209     
3210     if (m_loadType == FrameLoadTypeReload) {
3211         request.setCachePolicy(ReloadIgnoringCacheData);
3212         request.setHTTPHeaderField("Cache-Control", "max-age=0");
3213     }
3214     
3215     // Don't set the cookie policy URL if it's already been set.
3216     if (request.mainDocumentURL().isEmpty()) {
3217         if (mainResource && (isLoadingMainFrame() || alwaysFromRequest))
3218             request.setMainDocumentURL(request.url());
3219         else if (Page* page = m_frame->page())
3220             request.setMainDocumentURL(page->mainFrame()->loader()->url());
3221     }
3222     
3223     if (mainResource)
3224         request.setHTTPAccept("text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
3225 }
3226
3227 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
3228 {
3229     m_client->committedLoad(loader, data, length);
3230 }
3231
3232 void FrameLoader::post(const KURL& URL, const String& referrer, const String& frameName, PassRefPtr<FormData> formData, 
3233     const String& contentType, Event* event, HTMLFormElement* form, const HashMap<String, String>& formValues)
3234 {
3235     // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
3236     // This prevents a potential bug which may cause a page with a form that uses itself
3237     // as an action to be returned from the cache without submitting.
3238
3239     // FIXME: Where's the code that implements what the comment above says?
3240
3241     ResourceRequest request(URL);
3242     addExtraFieldsToRequest(request, true, true);
3243
3244     if (!referrer.isEmpty())
3245         request.setHTTPReferrer(referrer);
3246     request.setHTTPMethod("POST");
3247     request.setHTTPBody(formData);
3248     request.setHTTPContentType(contentType);
3249
3250     NavigationAction action(URL, FrameLoadTypeStandard, true, event);
3251
3252     RefPtr<FormState> formState;
3253     if (form && !formValues.isEmpty())
3254         formState = FormState::create(form, formValues, m_frame);
3255
3256     if (!frameName.isEmpty()) {
3257         if (Frame* targetFrame = m_frame->tree()->find(frameName))
3258             targetFrame->loader()->load(request, action, FrameLoadTypeStandard, formState.release());
3259         else
3260             checkNewWindowPolicy(action, request, formState.release(), frameName);
3261     } else
3262         load(request, action, FrameLoadTypeStandard, formState.release());
3263 }
3264
3265 bool FrameLoader::isReloading() const
3266 {
3267     return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData;
3268 }
3269
3270 void FrameLoader::loadEmptyDocumentSynchronously()
3271 {
3272     ResourceRequest request(KURL(""));
3273     load(request);
3274 }
3275
3276 void FrameLoader::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
3277 {
3278     // Since this is a subresource, we can load any URL (we ignore the return value).
3279     // But we still want to know whether we should hide the referrer or not, so we call the canLoad method.
3280     String referrer = m_outgoingReferrer;
3281     if (shouldHideReferrer(request.url(), referrer))
3282         referrer = String();
3283     
3284     ResourceRequest initialRequest = request;
3285     initialRequest.setTimeoutInterval(10);
3286     
3287     if (initialRequest.isConditional())
3288         initialRequest.setCachePolicy(ReloadIgnoringCacheData);
3289     else
3290         initialRequest.setCachePolicy(documentLoader()->request().cachePolicy());
3291     
3292     if (!referrer.isEmpty())
3293         initialRequest.setHTTPReferrer(referrer);
3294
3295     if (Page* page = m_frame->page())
3296         initialRequest.setMainDocumentURL(page->mainFrame()->loader()->documentLoader()->request().url());
3297     initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
3298
3299     unsigned long identifier = 0;    
3300     ResourceRequest newRequest(initialRequest);
3301     requestFromDelegate(newRequest, identifier, error);
3302
3303     if (error.isNull()) {
3304         ASSERT(!newRequest.isNull());
3305         didTellBridgeAboutLoad(newRequest.url().url());
3306         ResourceHandle::loadResourceSynchronously(newRequest, error, response, data);
3307     }
3308     
3309     sendRemainingDelegateMessages(identifier, response, data.size(), error);
3310 }
3311
3312 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest& clientRequest)
3313 {
3314     return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLoader(), clientRequest);
3315 }
3316
3317 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
3318 {
3319     applyUserAgent(clientRequest);
3320     dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse);
3321 }
3322
3323 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r)
3324 {
3325     activeDocumentLoader()->addResponse(r);
3326     
3327     if (Page* page = m_frame->page())
3328         page->progress()->incrementProgress(loader->identifier(), r);
3329     dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r);
3330 }
3331
3332 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int length, int lengthReceived)
3333 {
3334     if (Page* page = m_frame->page())
3335         page->progress()->incrementProgress(loader->identifier(), data, length);
3336     dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier(), lengthReceived);
3337 }
3338
3339 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
3340 {
3341     if (Page* page = m_frame->page())
3342         page->progress()->completeProgress(loader->identifier());
3343     if (!error.isNull())
3344         m_client->dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error);
3345 }
3346
3347 const ResourceRequest& FrameLoader::originalRequest() const
3348 {
3349     return activeDocumentLoader()->originalRequestCopy();
3350 }
3351
3352 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete)
3353 {
3354     // Retain because the stop may release the last reference to it.
3355     RefPtr<Frame> protect(m_frame);
3356
3357     RefPtr<DocumentLoader> loader = activeDocumentLoader();
3358     
3359     if (isComplete) {
3360         // FIXME: Don't want to do this if an entirely new load is going, so should check
3361         // that both data sources on the frame are either this or nil.
3362         stop();
3363         if (m_client->shouldFallBack(error))
3364             handleFallbackContent();
3365     }
3366     
3367     if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
3368         KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url();
3369         didNotOpenURL(failedURL);
3370             
3371         // We might have made a page cache item, but now we're bailing out due to an error before we ever
3372         // transitioned to the new page (before WebFrameState == commit).  The goal here is to restore any state
3373         // so that the existing view (that wenever got far enough to replace) can continue being used.
3374         invalidateCurrentItemCachedPage();
3375         
3376         // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
3377         // status has changed, if there was a redirect. The frame load delegate may have saved some state about
3378         // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
3379         // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
3380         // has ended.
3381         if (m_sentRedirectNotification)
3382             clientRedirectCancelledOrFinished(false);
3383     }
3384     
3385     
3386     loader->mainReceivedError(error, isComplete);
3387 }
3388
3389 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
3390     const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
3391 {
3392     FrameLoader* loader = static_cast<FrameLoader*>(argument);
3393     loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
3394 }
3395
3396 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
3397 {
3398     // FIXME:
3399     // some functions check m_quickRedirectComing, and others check for
3400     // FrameLoadTypeRedirectWithLockedHistory.  
3401     bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedHistory;
3402     m_quickRedirectComing = false;
3403
3404     if (!shouldContinue)
3405         return;
3406
3407     KURL URL = request.url();
3408     
3409     m_documentLoader->replaceRequestURLForAnchorScroll(URL);
3410     if (!isRedirect && !shouldTreatURLAsSameAsCurrent(URL)) {
3411         // NB: must happen after _setURL, since we add based on the current request.
3412         // Must also happen before we openURL and displace the scroll position, since
3413         // adding the BF item will save away scroll state.
3414         
3415         // NB2:  If we were loading a long, slow doc, and the user anchor nav'ed before
3416         // it was done, currItem is now set the that slow doc, and prevItem is whatever was
3417         // before it.  Adding the b/f item will bump the slow doc down to prevItem, even
3418         // though its load is not yet done.  I think this all works out OK, for one because
3419         // we have already saved away the scroll and doc state for the long slow load,
3420         // but it's not an obvious case.
3421
3422         addHistoryItemForFragmentScroll();
3423     }
3424     
3425     scrollToAnchor(URL);
3426     
3427     if (!isRedirect)
3428         // This will clear previousItem from the rest of the frame tree that didn't
3429         // doing any loading. We need to make a pass on this now, since for anchor nav
3430         // we'll not go through a real load and reach Completed state.
3431         checkLoadComplete();
3432  
3433     m_client->dispatchDidChangeLocationWithinPage();
3434     m_client->didFinishLoad();
3435 }
3436
3437 void FrameLoader::opened()
3438 {
3439     if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
3440         updateHistoryForClientRedirect();
3441
3442     if (m_documentLoader->isLoadingFromCachedPage()) {
3443         m_frame->document()->didRestoreFromCache();
3444         
3445         // Force a layout to update view size and thereby update scrollbars.
3446         m_client->forceLayout();
3447
3448         const ResponseVector& responses = m_documentLoader->responses();
3449         size_t count = responses.size();
3450         for (size_t i = 0; i < count; i++) {
3451             const ResourceResponse& response = responses[i];
3452             // FIXME: If the WebKit client changes or cancels the request, this is not respected.
3453             ResourceError error;
3454             unsigned long identifier;
3455             ResourceRequest request(response.url());
3456             requestFromDelegate(request, identifier, error);
3457             // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
3458             // However, with today's computers and networking speeds, this won't happen in practice.
3459             // Could be an issue with a giant local file.
3460             sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
3461         }
3462         
3463         pageCache()->remove(m_currentHistoryItem.get());
3464
3465         m_documentLoader->setPrimaryLoadComplete(true);
3466
3467         // FIXME: Why only this frame and not parent frames?
3468         checkLoadCompleteForThisFrame();
3469     }
3470 }
3471
3472 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request,
3473     PassRefPtr<FormState> formState, const String& frameName)
3474 {
3475     m_policyCheck.set(request, formState, frameName,
3476         callContinueLoadAfterNewWindowPolicy, this);
3477     m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy,
3478         action, request, frameName);
3479 }
3480
3481 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy)
3482 {
3483     PolicyCheck check = m_policyCheck;
3484     m_policyCheck.clear();
3485
3486     switch (policy) {
3487         case PolicyIgnore:
3488             check.clearRequest();
3489             break;
3490         case PolicyDownload:
3491             m_client->startDownload(check.request());
3492             check.clearRequest();
3493             break;
3494         case PolicyUse:
3495             break;
3496     }
3497
3498     check.call(policy == PolicyUse);
3499 }
3500
3501 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
3502     PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument)
3503 {
3504     NavigationAction action = loader->triggeringAction();
3505     if (action.isEmpty()) {
3506         action = NavigationAction(request.url(), NavigationTypeOther);
3507         loader->setTriggeringAction(action);
3508     }
3509         
3510     // Don't ask more than once for the same request or if we are loading an empty URL.
3511     // This avoids confusion on the part of the client.
3512     if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
3513         function(argument, request, 0, true);
3514         loader->setLastCheckedRequest(request);
3515         return;
3516     }
3517     
3518     // We are always willing to show alternate content for unreachable URLs;
3519     // treat it like a reload so it maintains the right state for b/f list.
3520     if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
3521         if (isBackForwardLoadType(m_policyLoadType))
3522             m_policyLoadType = FrameLoadTypeReload;
3523         function(argument, request, 0, true);
3524         return;
3525     }
3526     
3527     loader->setLastCheckedRequest(request);
3528
3529     m_policyCheck.set(request, formState, function, argument);
3530
3531     m_delegateIsDecidingNavigationPolicy = true;
3532     m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy,
3533         action, request);
3534     m_delegateIsDecidingNavigationPolicy = false;
3535 }
3536
3537 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy)
3538 {
3539     PolicyCheck check = m_policyCheck;
3540     m_policyCheck.clear();
3541
3542     bool shouldContinue = policy == PolicyUse;
3543     
3544     switch (policy) {
3545         case PolicyIgnore:
3546             check.clearRequest();
3547             break;
3548         case PolicyDownload:
3549             m_client->startDownload(check.request());
3550             check.clearRequest();
3551             break;
3552         case PolicyUse: {
3553             ResourceRequest request(check.request());
3554             
3555             if (!m_client->canHandleRequest(request)) {
3556                 handleUnimplementablePolicy(m_client->cannotShowURLError(check.request()));
3557                 check.clearRequest();
3558                 shouldContinue = false;
3559             }
3560             break;
3561         }
3562     }
3563
3564     check.call(shouldContinue);
3565 }
3566
3567 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
3568     const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3569 {
3570     FrameLoader* loader = static_cast<FrameLoader*>(argument);
3571     loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
3572 }
3573
3574 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3575 {
3576     // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
3577     // nil policyDataSource because loading the alternate page will have passed
3578     // through this method already, nested; otherwise, policyDataSource should still be set.
3579     ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
3580
3581     bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false;
3582
3583     // Two reasons we can't continue:
3584     //    1) Navigation policy delegate said we can't so request is nil. A primary case of this 
3585     //       is the user responding Cancel to the form repost nag sheet.
3586     //    2) User responded Cancel to an alert popped up by the before unload event handler.
3587     // The "before unload" event handler runs only for the main frame.
3588     bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
3589
3590     if (!canContinue) {
3591         // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we 
3592         // need to report that the client redirect was cancelled.
3593         if (m_quickRedirectComing)
3594             clientRedirectCancelledOrFinished(false);
3595
3596         setPolicyDocumentLoader(0);
3597
3598         // If the navigation request came from the back/forward menu, and we punt on it, we have the 
3599         // problem that we have optimistically moved the b/f cursor already, so move it back.  For sanity, 
3600         // we only do this when punting a navigation for the target frame or top-level frame.  
3601         if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType))
3602             if (Page* page = m_frame->page()) {
3603                 Frame* mainFrame = page->mainFrame();
3604                 if (HistoryItem* resetItem = mainFrame->loader()->m_currentHistoryItem.get())
3605                     page->backForwardList()->goToItem(resetItem);
3606             }
3607         return;
3608     }
3609
3610     FrameLoadType type = m_policyLoadType;
3611     stopAllLoaders();
3612     setProvisionalDocumentLoader(m_policyDocumentLoader.get());
3613     m_loadType = type;
3614     setState(FrameStateProvisional);
3615
3616     setPolicyDocumentLoader(0);
3617
3618     if (isBackForwardLoadType(type) && loadProvisionalItemFromCachedPage())
3619         return;
3620
3621     if (formState)
3622         m_client->dispatchWillSubmitForm(&FrameLoader::continueLoadAfterWillSubmitForm, formState);
3623     else
3624         continueLoadAfterWillSubmitForm();
3625 }
3626
3627
3628 void FrameLoader::callContinueLoadAfterNewWindowPolicy(void* argument,
3629     const ResourceRequest& request, PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3630 {
3631     FrameLoader* loader = static_cast<FrameLoader*>(argument);
3632     loader->continueLoadAfterNewWindowPolicy(request, formState, frameName, shouldContinue);
3633 }
3634
3635 void FrameLoader::continueLoadAfterNewWindowPolicy(const ResourceRequest& request,
3636     PassRefPtr<FormState> formState, const String& frameName, bool shouldContinue)
3637 {
3638     if (!shouldContinue)
3639         return;
3640
3641     RefPtr<Frame> frame = m_frame;
3642     RefPtr<Frame> mainFrame = m_client->dispatchCreatePage();
3643     if (!mainFrame)
3644         return;
3645
3646     if (frameName != "_blank")
3647         mainFrame->tree()->setName(frameName);
3648
3649     mainFrame->loader()->setOpenedByDOM();
3650     mainFrame->loader()->m_client->dispatchShow();
3651     mainFrame->loader()->setOpener(frame.get());
3652     mainFrame->loader()->load(request, NavigationAction(), FrameLoadTypeStandard, formState);
3653 }
3654
3655 void FrameLoader::sendRemainingDelegateMessages(unsigned long identifier, const ResourceResponse& response, int length, const ResourceError& error)
3656 {    
3657     if (!response.isNull())
3658         dispatchDidReceiveResponse(m_documentLoader.get(), identifier, response);
3659     
3660     if (length > 0)
3661         dispatchDidReceiveContentLength(m_documentLoader.get(), identifier, length);
3662     
3663     if (error.isNull())
3664         dispatchDidFinishLoading(m_documentLoader.get(), identifier);
3665     else
3666         m_client->dispatchDidFailLoading(m_documentLoader.get(), identifier, error);
3667 }
3668
3669 void FrameLoader::requestFromDelegate(ResourceRequest& request, unsigned long& identifier, ResourceError& error)
3670 {
3671     ASSERT(!request.isNull());
3672
3673     identifier = 0;
3674     if (Page* page = m_frame->page()) {
3675         identifier = page->progress()->createUniqueIdentifier();
3676         dispatchAssignIdentifierToInitialRequest(identifier, m_documentLoader.get(), request);
3677     }
3678
3679     ResourceRequest newRequest(request);
3680     dispatchWillSendRequest(m_documentLoader.get(), identifier, newRequest, ResourceResponse());
3681
3682     if (newRequest.isNull())
3683         error = m_client->cancelledError(request);
3684     else
3685         error = ResourceError();
3686
3687     request = newRequest;
3688 }
3689
3690 void FrameLoader::loadedResourceFromMemoryCache(const ResourceRequest& request, const ResourceResponse& response, int length)
3691 {
3692     if (dispatchDidLoadResourceFromMemoryCache(m_documentLoader.get(), request, response, length))
3693         return;
3694
3695     unsigned long identifier;
3696     ResourceError error;
3697     ResourceRequest r(request);
3698     requestFromDelegate(r, identifier, error);
3699     sendRemainingDelegateMessages(identifier, response, length, error);
3700 }
3701
3702 void FrameLoader::applyUserAgent(ResourceRequest& request)
3703 {
3704     String userAgent = client()->userAgent(request.url());
3705     ASSERT(!userAgent.isNull());
3706     request.setHTTPUserAgent(userAgent);
3707 }
3708
3709 bool FrameLoader::canGoBackOrForward(int distance) const
3710 {
3711     if (Page* page = m_frame->page()) {
3712         if (distance == 0)
3713             return true;
3714         if (distance > 0 && distance <= page->backForwardList()->forwardListCount())
3715             return true;
3716         if (distance < 0 && -distance <= page->backForwardList()->backListCount())
3717             return true;
3718     }
3719     return false;
3720 }
3721
3722 int FrameLoader::getHistoryLength()
3723 {
3724     if (Page* page = m_frame->page())
3725         return page->backForwardList()->backListCount() + 1;
3726     return 0;
3727 }
3728
3729 KURL FrameLoader::historyURL(int distance)
3730 {
3731     if (Page* page = m_frame->page()) {
3732         BackForwardList* list = page->backForwardList();
3733         HistoryItem* item = list->itemAtIndex(distance);
3734         if (!item) {
3735             if (distance > 0) {
3736                 int forwardListCount = list->forwardListCount();
3737                 if (forwardListCount > 0)
3738                     item = list->itemAtIndex(forwardListCount);
3739             } else {
3740                 int backListCount = list->backListCount();
3741                 if (backListCount > 0)
3742                     item = list->itemAtIndex(-backListCount);
3743             }
3744         }
3745         if (item)
3746             return item->url();
3747     }
3748     return KURL();
3749 }
3750
3751 void FrameLoader::addHistoryItemForFragmentScroll()
3752 {
3753     addBackForwardItemClippedAtTarget(false);
3754 }
3755
3756 bool FrameLoader::loadProvisionalItemFromCachedPage()
3757 {
3758     RefPtr<CachedPage> cachedPage = pageCache()->get(m_provisionalHistoryItem.get());
3759     if (!cachedPage || !cachedPage->document())
3760         return false;
3761     provisionalDocumentLoader()->loadFromCachedPage(cachedPage.release());
3762     return true;
3763 }
3764
3765 void FrameLoader::cachePageForHistoryItem(HistoryItem* item)
3766 {
3767     if (Page* page = m_frame->page()) {
3768         RefPtr<CachedPage> cachedPage = CachedPage::create(page);
3769         cachedPage->setTimeStampToNow();
3770         cachedPage->setDocumentLoader(documentLoader());
3771         m_client->saveDocumentViewToCachedPage(cachedPage.get());
3772
3773         pageCache()->add(item, cachedPage.release());
3774     }
3775 }
3776
3777 bool FrameLoader::shouldTreatURLAsSameAsCurrent(const KURL& URL) const
3778 {
3779     if (!m_currentHistoryItem)
3780         return false;
3781     return URL == m_currentHistoryItem->url() || URL == m_currentHistoryItem->originalURL();
3782 }
3783
3784 PassRefPtr<HistoryItem> FrameLoader::createHistoryItem(bool useOriginal)
3785 {
3786     DocumentLoader* docLoader = documentLoader();
3787     
3788     KURL unreachableURL = docLoader ? docLoader->unreachableURL() : KURL();
3789     
3790     KURL url;
3791     KURL originalURL;
3792
3793     if (!unreachableURL.isEmpty()) {
3794         url = unreachableURL;
3795         originalURL = unreachableURL;
3796     } else {
3797         originalURL = docLoader ? docLoader->originalURL() : KURL();
3798         if (useOriginal)
3799             url = originalURL;
3800         else if (docLoader)
3801             url = docLoader->requestURL();                
3802     }
3803
3804     LOG(History, "WebCoreHistory: Creating item for %s", url.url().ascii());
3805     
3806     // Frames that have never successfully loaded any content
3807     // may have no URL at all. Currently our history code can't
3808     // deal with such things, so we nip that in the bud here.
3809     // Later we may want to learn to live with nil for URL.
3810     // See bug 3368236 and related bugs for more information.
3811     if (url.isEmpty()) 
3812         url = KURL("about:blank");
3813     if (originalURL.isEmpty())
3814         originalURL = KURL("about:blank");
3815     
3816     RefPtr<HistoryItem> item = new HistoryItem(url, m_frame->tree()->name(), m_frame->tree()->parent() ? m_frame->tree()->parent()->tree()->name() : "", docLoader ? docLoader->title() : "");
3817     item->setOriginalURLString(originalURL.url());
3818     
3819     // Save form state if this is a POST
3820     if (docLoader) {
3821         if (useOriginal)
3822             item->setFormInfoFromRequest(docLoader->originalRequest());
3823         else
3824             item->setFormInfoFromRequest(docLoader->request());
3825     }
3826     
3827     // Set the item for which we will save document state
3828     m_previousHistoryItem = m_currentHistoryItem;
3829     m_currentHistoryItem = item;
3830     
3831     return item.release();
3832 }
3833
3834 void FrameLoader::addBackForwardItemClippedAtTarget(bool doClip)
3835 {
3836     if (Page* page = m_frame->page())
3837         if (!documentLoader()->urlForHistory().isEmpty()) {
3838             Frame* mainFrame = page->mainFrame();
3839             ASSERT(mainFrame);
3840             FrameLoader* frameLoader = mainFrame->loader();
3841
3842             if (!frameLoader->m_didPerformFirstNavigation && page->backForwardList()->entries().size() == 1) {
3843                 frameLoader->m_didPerformFirstNavigation = true;
3844                 m_client->didPerformFirstNavigation();
3845             }
3846
3847             RefPtr<HistoryItem> item = frameLoader->createHistoryItemTree(m_frame, doClip);
3848             LOG(BackForward, "WebCoreBackForward - Adding backforward item %p for frame %s", item.get(), documentLoader()->URL().url().ascii());
3849             page->backForwardList()->addItem(item);
3850         }
3851 }
3852
3853 PassRefPtr<HistoryItem> FrameLoader::createHistoryItemTree(Frame* targetFrame, bool clipAtTarget)
3854 {
3855     RefPtr<HistoryItem> bfItem = createHistoryItem(m_frame->tree()->parent() ? true : false);
3856     if (m_previousHistoryItem)
3857         saveScrollPositionAndViewStateToItem(m_previousHistoryItem.get());
3858     if (!(clipAtTarget && m_frame == targetFrame)) {
3859         // save frame state for items that aren't loading (khtml doesn't save those)
3860         saveDocumentState();
3861         for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
3862             bfItem->addChildItem(child->loader()->createHistoryItemTree(targetFrame, clipAtTarget));
3863     }
3864     if (m_frame == targetFrame)
3865         bfItem->setIsTargetItem(true);
3866     return bfItem;
3867 }
3868
3869 void FrameLoader::saveScrollPositionAndViewStateToItem(HistoryItem* item)
3870 {
3871     if (!item || !m_frame->view())
3872         return;
3873         
3874     item->setScrollPoint(IntPoint(m_frame->view()->contentsX(), m_frame->view()->contentsY()));
3875     // FIXME: It would be great to work out a way to put this code in WebCore instead of calling through to the client.
3876     m_client->saveViewStateToItem(item);
3877 }
3878
3879 /*
3880  There is a race condition between the layout and load completion that affects restoring the scroll position.
3881  We try to restore the scroll position at both the first layout and upon load completion.
3882  
3883  1) If first layout happens before the load completes, we want to restore the scroll position then so that the
3884  first time we draw the page is already scrolled to the right place, instead of starting at the top and later
3885  jumping down.  It is possible that the old scroll position is past the part of the doc laid out so far, in
3886  which case the restore silent fails and we will fix it in when we try to restore on doc completion.
3887  2) If the layout happens after the load completes, the attempt to restore at load completion time silently
3888  fails.  We then successfully restore it when the layout happens.
3889 */
3890 void FrameLoader::restoreScrollPositionAndViewState()
3891 {
3892     if (!m_committedFirstRealDocumentLoad)
3893         return;
3894
3895     ASSERT(m_currentHistoryItem);
3896     
3897     // FIXME: As the ASSERT attests, it seems we should always have a currentItem here.
3898     // One counterexample is <rdar://problem/4917290>
3899     // For now, to cover this issue in release builds, there is no technical harm to returning
3900     // early and from a user standpoint - as in the above radar - the previous page load failed 
3901     // so there *is* no scroll or view state to restore!
3902     if (!m_currentHistoryItem)
3903         return;
3904     
3905     // FIXME: It would be great to work out a way to put this code in WebCore instead of calling
3906     // through to the client. It's currently used only for the PDF view on Mac.
3907     m_client->restoreViewState();
3908     
3909     if (FrameView* view = m_frame->view())
3910         if (!view->wasScrolledByUser()) {
3911             const IntPoint& scrollPoint = m_currentHistoryItem->scrollPoint();
3912             view->setContentsPos(scrollPoint.x(), scrollPoint.y());
3913         }
3914 }
3915
3916 void FrameLoader::invalidateCurrentItemCachedPage()
3917 {
3918     // When we are pre-commit, the currentItem is where the pageCache data resides    
3919     CachedPage* cachedPage = pageCache()->get(m_currentHistoryItem.get());
3920
3921     // FIXME: This is a grotesque hack to fix <rdar://problem/4059059> Crash in RenderFlow::detach
3922     // Somehow the PageState object is not properly updated, and is holding onto a stale document.
3923     // Both Xcode and FileMaker see this crash, Safari does not.
3924     
3925     ASSERT(!cachedPage || cachedPage->document() == m_frame->document());
3926     if (cachedPage && cachedPage->document() == m_frame->document()) {
3927         cachedPage->document()->setInPageCache(false);
3928         cachedPage->clear();
3929     }
3930     
3931     if (cachedPage)
3932         pageCache()->remove(m_currentHistoryItem.get());
3933 }
3934
3935 void FrameLoader::saveDocumentState()
3936 {
3937     if (m_creatingInitialEmptyDocument)
3938         return;
3939
3940     // For a standard page load, we will have a previous item set, which will be used to
3941     // store the form state.  However, in some cases we will have no previous item, and
3942     // the current item is the right place to save the state.  One example is when we
3943     // detach a bunch of frames because we are navigating from a site with frames to
3944     // another site.  Another is when saving the frame state of a frame that is not the
3945     // target of the current navigation (if we even decide to save with that granularity).
3946
3947     // Because of previousItem's "masking" of currentItem for this purpose, it's important
3948     // that previousItem be cleared at the end of a page transition.  We leverage the
3949     // checkLoadComplete recursion to achieve this goal.
3950
3951     HistoryItem* item = m_previousHistoryItem ? m_previousHistoryItem.get() : m_currentHistoryItem.get();
3952     if (!item)
3953         return;
3954
3955     Document* document = m_frame->document();
3956     ASSERT(document);
3957     
3958     if (document && item->isCurrentDocument(document)) {
3959         LOG(Loading, "WebCoreLoading %s: saving form state to %p", m_frame->tree()->name().domString().utf8().data(), item);
3960         item->setDocumentState(document->formElementsState());
3961     }
3962 }
3963
3964 // Loads content into this frame, as specified by history item
3965 void FrameLoader::loadItem(HistoryItem* item, FrameLoadType loadType)
3966 {
3967     KURL itemURL = item->url();
3968     KURL itemOriginalURL = item->originalURL();
3969     KURL currentURL;
3970     if (documentLoader())
3971         currentURL = documentLoader()->URL();
3972     RefPtr<FormData> formData = item->formData();
3973
3974     // Are we navigating to an anchor within the page?
3975     // Note if we have child frames we do a real reload, since the child frames might not
3976     // match our current frame structure, or they might not have the right content.  We could
3977     // check for all that as an additional optimization.
3978     // We also do not do anchor-style navigation if we're posting a form.
3979     
3980     if (!formData && !shouldReload(itemURL, currentURL) && urlsMatchItem(item)) {
3981         // Must do this maintenance here, since we don't go through a real page reload
3982         saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
3983
3984         if (FrameView* view = m_frame->view())
3985             view->setWasScrolledByUser(false);
3986
3987         m_currentHistoryItem = item;
3988
3989         // FIXME: Form state might need to be saved here too.
3990
3991         // We always call scrollToAnchor here, even if the URL doesn't have an
3992         // anchor fragment. This is so we'll keep the WebCore Frame's URL up-to-date.
3993         scrollToAnchor(item->url());
3994     
3995         // must do this maintenance here, since we don't go through a real page reload
3996         restoreScrollPositionAndViewState();
3997         
3998         // Fake the URL change by updating the data source's request.  This will no longer
3999         // be necessary if we do the better fix described above.
4000         documentLoader()->replaceRequestURLForAnchorScroll(itemURL);
4001
4002         m_client->dispatchDidChangeLocationWithinPage();
4003         
4004         // FrameLoaderClient::didFinishLoad() tells the internal load delegate the load finished with no error
4005         m_client->didFinishLoad();
4006     } else {
4007         // Remember this item so we can traverse any child items as child frames load
4008         m_provisionalHistoryItem = item;
4009
4010         bool inPageCache = false;
4011         
4012         // Check if we'll be using the page cache.  We only use the page cache
4013         // if one exists and it is less than _backForwardCacheExpirationInterval
4014         // seconds old.  If the cache is expired it gets flushed here.
4015         if (RefPtr<CachedPage> cachedPage = pageCache()->get(item)) {
4016             double interval = currentTime() - cachedPage->timeStamp();
4017             
4018             // FIXME: 1800 should not be hardcoded, it should come from
4019             // WebKitBackForwardCacheExpirationIntervalKey in WebKit.
4020             // Or we should remove WebKitBackForwardCacheExpirationIntervalKey.
4021             if (interval <= 1800) {
4022                 load(cachedPage->documentLoader(), loadType, 0);   
4023                 inPageCache = true;
4024             } else {
4025                 LOG(PageCache, "Not restoring page for %s from back/forward cache because cache entry has expired", m_provisionalHistoryItem->url().url().ascii());
4026                 pageCache()->remove(item);
4027             }
4028         }
4029         
4030         if (!inPageCache) {
4031             ResourceRequest request(itemURL);
4032
4033             addExtraFieldsToRequest(request, true, formData);
4034
4035             // If this was a repost that failed the page cache, we might try to repost the form.
4036             NavigationAction action;
4037             if (formData) {
4038                 request.setHTTPMethod("POST");
4039                 request.setHTTPReferrer(item->formReferrer());
4040                 request.setHTTPBody(formData);
4041                 request.setHTTPContentType(item->formContentType());
4042         
4043                 // FIXME: Slight hack to test if the NSURL cache contains the page we're going to.
4044                 // We want to know this before talking to the policy delegate, since it affects whether 
4045                 // we show the DoYouReallyWantToRepost nag.
4046                 //
4047                 // This trick has a small bug (3123893) where we might find a cache hit, but then
4048                 // have the item vanish when we try to use it in the ensuing nav.  This should be
4049                 // extremely rare, but in that case the user will get an error on the navigation.
4050                 
4051                 if (ResourceHandle::willLoadFromCache(request))
4052                     action = NavigationAction(itemURL, loadType, false);
4053                 else {
4054                     request.setCachePolicy(ReloadIgnoringCacheData);
4055                     action = NavigationAction(itemURL, NavigationTypeFormResubmitted);
4056                 }
4057             } else {
4058                 switch (loadType) {
4059                     case FrameLoadTypeReload:
4060                         request.setCachePolicy(ReloadIgnoringCacheData);
4061                         break;
4062                     case FrameLoadTypeBack:
4063                     case FrameLoadTypeForward:
4064                     case FrameLoadTypeIndexedBackForward:
4065                         if (itemURL.protocol() == "https")
4066                             request.setCachePolicy(ReturnCacheDataElseLoad);
4067                         break;
4068                     case FrameLoadTypeStandard:
4069                     case FrameLoadTypeRedirectWithLockedHistory:
4070                         // no-op: leave as protocol default
4071                         // FIXME:  I wonder if we ever hit this case
4072                         break;
4073                     case FrameLoadTypeSame:
4074                     case FrameLoadTypeReloadAllowingStaleData:
4075                     default:
4076                         ASSERT_NOT_REACHED();
4077                 }
4078
4079                 action = NavigationAction(itemOriginalURL, loadType, false);
4080             }
4081
4082             load(request, action, loadType, 0);
4083         }
4084     }
4085 }
4086
4087 // Walk the frame tree and ensure that the URLs match the URLs in the item.
4088 bool FrameLoader::urlsMatchItem(HistoryItem* item) const
4089 {
4090     KURL currentURL = documentLoader()->URL();
4091     
4092     if (!equalIgnoringRef(currentURL, item->url()))
4093         return false;
4094     
4095     const HistoryItemVector& childItems = item->children();
4096     
4097     unsigned size = childItems.size();
4098     for (unsigned i = 0; i < size; ++i) {
4099         Frame* childFrame = m_frame->tree()->child(childItems[i]->target());
4100         if (childFrame && !childFrame->loader()->urlsMatchItem(childItems[i].get()))
4101             return false;
4102     }
4103
4104     return true;
4105 }
4106
4107 // Main funnel for navigating to a previous location (back/forward, non-search snap-back)
4108 // This includes recursion to handle loading into framesets properly
4109 void FrameLoader::goToItem(HistoryItem* targetItem, FrameLoadType type)
4110 {
4111     ASSERT(!m_frame->tree()->parent());
4112     
4113     // shouldGoToHistoryItem is a private delegate method. This is needed to fix:
4114     // <rdar://problem/3951283> can view pages from the back/forward cache that should be disallowed by Parental Controls
4115     // Ultimately, history item navigations should go through the policy delegate. That's covered in:
4116     // <rdar://problem/3979539> back/forward cache navigations should consult policy delegate
4117     if (Page* page = m_frame->page())
4118         if (m_client->shouldGoToHistoryItem(targetItem)) {
4119             BackForwardList* bfList = page->backForwardList();
4120             HistoryItem* currentItem = bfList->currentItem();
4121             
4122             // Set the BF cursor before commit, which lets the user quickly click back/forward again.
4123             // - plus, it only makes sense for the top level of the operation through the frametree,
4124             // as opposed to happening for some/one of the page commits that might happen soon
4125             bfList->goToItem(targetItem);
4126             recursiveGoToItem(targetItem, currentItem, type);
4127         }
4128 }
4129
4130 // The general idea here is to traverse the frame tree and the item tree in parallel,
4131 // tracking whether each frame already has the content the item requests.  If there is
4132 // a match (by URL), we just restore scroll position and recurse.  Otherwise we must
4133 // reload that frame, and all its kids.
4134 void FrameLoader::recursiveGoToItem(HistoryItem* item, HistoryItem* fromItem, FrameLoadType type)
4135 {
4136     ASSERT(item);
4137     ASSERT(fromItem);
4138     
4139     KURL itemURL = item->url();
4140     KURL currentURL;
4141     if (documentLoader())
4142         currentURL = documentLoader()->URL();
4143     
4144     // Always reload the target frame of the item we're going to.  This ensures that we will
4145     // do -some- load for the transition, which means a proper notification will be posted
4146     // to the app.
4147     // The exact URL has to match, including fragment.  We want to go through the _load
4148     // method, even if to do a within-page navigation.
4149     // The current frame tree and the frame tree snapshot in the item have to match.
4150     if (!item->isTargetItem() &&
4151         itemURL == currentURL &&
4152         ((m_frame->tree()->name().isEmpty() && item->target().isEmpty()) || m_frame->tree()->name() == item->target()) &&
4153         childFramesMatchItem(item))
4154     {
4155         // This content is good, so leave it alone and look for children that need reloading
4156         // Save form state (works from currentItem, since prevItem is nil)
4157         ASSERT(!m_previousHistoryItem);
4158         saveDocumentState();
4159         saveScrollPositionAndViewStateToItem(m_currentHistoryItem.get());
4160
4161         if (FrameView* view = m_frame->view())
4162             view->setWasScrolledByUser(false);
4163
4164         m_currentHistoryItem = item;
4165                 
4166         // Restore form state (works from currentItem)
4167         restoreDocumentState();
4168         
4169         // Restore the scroll position (we choose to do this rather than going back to the anchor point)
4170         restoreScrollPositionAndViewState();
4171         
4172         const HistoryItemVector& childItems = item->children();
4173         
4174         int size = childItems.size();
4175         for (int i = 0; i < size; ++i) {
4176             String childName = childItems[i]->target();
4177             HistoryItem* fromChildItem = fromItem->childItemWithName(childName);
4178             ASSERT(fromChildItem || fromItem->isTargetItem());
4179             Frame* childFrame = m_frame->tree()->child(childName);
4180             ASSERT(childFrame);
4181             childFrame->loader()->recursiveGoToItem(childItems[i].get(), fromChildItem, type);
4182         }
4183     } else {
4184         loadItem(item, type);
4185     }
4186 }
4187
4188 // helper method that determines whether the subframes described by the item's subitems
4189 // match our own current frameset
4190 bool FrameLoader::childFramesMatchItem(HistoryItem* item) const
4191 {
4192     const HistoryItemVector& childItems = item->children();
4193     if (childItems.size() != m_frame->tree()->childCount())
4194         return false;
4195     
4196     unsigned size = childItems.size();
4197     for (unsigned i = 0; i < size; ++i)
4198         if (!m_frame->tree()->child(childItems[i]->target()))
4199             return false;
4200     
4201     // Found matches for all item targets
4202     return true;
4203 }
4204
4205 void FrameLoader::addHistoryForCurrentLocation()
4206 {
4207     if (!m_frame->settings()->privateBrowsingEnabled()) {
4208         // FIXME: <rdar://problem/4880065> - This will be a hook into the WebCore global history, and this loader/client call will be removed
4209         m_client->updateGlobalHistoryForStandardLoad(documentLoader()->urlForHistory());
4210     }
4211     addBackForwardItemClippedAtTarget(true);