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