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