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