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