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