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