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