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