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