2 * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
3 * Copyright (C) 2007 Trolltech ASA
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15 * its contributors may be used to endorse or promote products derived
16 * from this software without specific prior written permission.
18 * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "FrameLoader.h"
35 #include "CachedPage.h"
37 #include "DOMImplementation.h"
38 #include "DocLoader.h"
40 #include "DocumentLoader.h"
41 #include "EditCommand.h"
43 #include "EditorClient.h"
46 #include "EventNames.h"
47 #include "FloatRect.h"
48 #include "FormState.h"
50 #include "FrameLoadRequest.h"
51 #include "FrameLoaderClient.h"
52 #include "FramePrivate.h"
53 #include "FrameTree.h"
54 #include "FrameView.h"
55 #include "HTMLFormElement.h"
56 #include "HTMLFrameElement.h"
57 #include "HTMLNames.h"
58 #include "HTMLObjectElement.h"
59 #include "HTTPParsers.h"
60 #include "HistoryItem.h"
61 #include "IconDatabase.h"
62 #include "IconLoader.h"
63 #include "InspectorController.h"
65 #include "MIMETypeRegistry.h"
66 #include "MainResourceLoader.h"
68 #include "PageCache.h"
69 #include "ProgressTracker.h"
70 #include "RenderPart.h"
71 #include "RenderWidget.h"
72 #include "ResourceHandle.h"
73 #include "ResourceRequest.h"
74 #include "SecurityOrigin.h"
75 #include "SegmentedString.h"
77 #include "SystemTime.h"
78 #include "TextResourceDecoder.h"
79 #include "WindowFeatures.h"
80 #include "XMLHttpRequest.h"
81 #include "XMLTokenizer.h"
82 #include "kjs_binding.h"
83 #include "kjs_proxy.h"
84 #include "kjs_window.h"
85 #include <kjs/JSLock.h>
86 #include <kjs/object.h>
89 #include "SVGDocument.h"
90 #include "SVGLocatable.h"
92 #include "SVGPreserveAspectRatio.h"
93 #include "SVGSVGElement.h"
94 #include "SVGViewElement.h"
95 #include "SVGViewSpec.h"
105 using namespace SVGNames;
107 using namespace HTMLNames;
108 using namespace EventNames;
110 #if USE(LOW_BANDWIDTH_DISPLAY)
111 const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024;
114 struct FormSubmission {
117 RefPtr<FormData> data;
123 FormSubmission(const char* a, const String& u, PassRefPtr<FormData> d, const String& t,
124 const String& ct, const String& b, PassRefPtr<Event> e)
136 struct ScheduledRedirection {
137 enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad };
146 ScheduledRedirection(double redirectDelay, const String& redirectURL, bool redirectLockHistory, bool userGesture)
148 , delay(redirectDelay)
151 , lockHistory(redirectLockHistory)
152 , wasUserGesture(userGesture)
156 ScheduledRedirection(Type locationChangeType,
157 const String& locationChangeURL, const String& locationChangeReferrer,
158 bool locationChangeLockHistory, bool locationChangeWasUserGesture)
159 : type(locationChangeType)
161 , URL(locationChangeURL)
162 , referrer(locationChangeReferrer)
164 , lockHistory(locationChangeLockHistory)
165 , wasUserGesture(locationChangeWasUserGesture)
169 explicit ScheduledRedirection(int historyNavigationSteps)
170 : type(historyNavigation)
172 , historySteps(historyNavigationSteps)
174 , wasUserGesture(false)
179 static double storedTimeOfLastCompletedLoad;
180 static bool m_restrictAccessToLocal = false;
182 static bool getString(JSValue* result, String& string)
188 if (!result->getString(ustring))
194 bool isBackForwardLoadType(FrameLoadType type)
197 case FrameLoadTypeStandard:
198 case FrameLoadTypeReload:
199 case FrameLoadTypeReloadAllowingStaleData:
200 case FrameLoadTypeSame:
201 case FrameLoadTypeRedirectWithLockedHistory:
202 case FrameLoadTypeReplace:
204 case FrameLoadTypeBack:
205 case FrameLoadTypeForward:
206 case FrameLoadTypeIndexedBackForward:
209 ASSERT_NOT_REACHED();
213 static int numRequests(Document* document)
218 return document->docLoader()->requestCount();
221 FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client)
224 , m_state(FrameStateCommittedPage)
225 , m_loadType(FrameLoadTypeStandard)
226 , m_policyLoadType(FrameLoadTypeStandard)
227 , m_delegateIsHandlingProvisionalLoadError(false)
228 , m_delegateIsDecidingNavigationPolicy(false)
229 , m_delegateIsHandlingUnimplementablePolicy(false)
230 , m_firstLayoutDone(false)
231 , m_quickRedirectComing(false)
232 , m_sentRedirectNotification(false)
233 , m_inStopAllLoaders(false)
234 , m_navigationDuringLoad(false)
235 , m_cachePolicy(CachePolicyVerify)
236 , m_isExecutingJavaScriptFormAction(false)
237 , m_isRunningScript(false)
238 , m_didCallImplicitClose(false)
239 , m_wasUnloadEventEmitted(false)
240 , m_isComplete(false)
241 , m_isLoadingMainResource(false)
242 , m_cancellingWithLoadInProgress(false)
243 , m_needsClear(false)
244 , m_receivedData(false)
245 , m_encodingWasChosenByUser(false)
246 , m_containsPlugIns(false)
247 , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired)
248 , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired)
249 , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired)
251 , m_openedByDOM(false)
252 , m_creatingInitialEmptyDocument(false)
253 , m_isDisplayingInitialEmptyDocument(false)
254 , m_committedFirstRealDocumentLoad(false)
255 , m_didPerformFirstNavigation(false)
256 #if USE(LOW_BANDWIDTH_DISPLAY)
257 , m_useLowBandwidthDisplay(true)
258 , m_finishedParsingDuringLowBandwidthDisplay(false)
259 , m_needToSwitchOutLowBandwidthDisplay(false)
264 FrameLoader::~FrameLoader()
268 HashSet<Frame*>::iterator end = m_openedFrames.end();
269 for (HashSet<Frame*>::iterator it = m_openedFrames.begin(); it != end; ++it)
270 (*it)->loader()->m_opener = 0;
272 m_client->frameLoaderDestroyed();
275 void FrameLoader::init()
277 // this somewhat odd set of steps is needed to give the frame an initial empty document
278 m_isDisplayingInitialEmptyDocument = false;
279 m_creatingInitialEmptyDocument = true;
280 setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(String("")), SubstituteData()).get());
281 setProvisionalDocumentLoader(m_policyDocumentLoader.get());
282 setState(FrameStateProvisional);
283 m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String()));
284 m_provisionalDocumentLoader->finishedLoading();
285 begin(KURL(), false);
287 m_frame->document()->cancelParsing();
288 m_creatingInitialEmptyDocument = false;
289 m_didCallImplicitClose = true;
292 void FrameLoader::setDefersLoading(bool defers)
294 if (m_documentLoader)
295 m_documentLoader->setDefersLoading(defers);
296 if (m_provisionalDocumentLoader)
297 m_provisionalDocumentLoader->setDefersLoading(defers);
298 if (m_policyDocumentLoader)
299 m_policyDocumentLoader->setDefersLoading(defers);
300 m_client->setDefersLoading(defers);
303 Frame* FrameLoader::createWindow(const FrameLoadRequest& request, const WindowFeatures& features, bool& created)
305 ASSERT(!features.dialog || request.frameName().isEmpty());
307 if (!request.frameName().isEmpty() && request.frameName() != "_blank")
308 if (Frame* frame = m_frame->tree()->find(request.frameName())) {
309 if (!shouldAllowNavigation(frame))
311 if (!request.resourceRequest().url().isEmpty())
312 frame->loader()->load(request, false, true, 0, 0, HashMap<String, String>());
313 if (Page* page = frame->page())
314 page->chrome()->focus();
319 // FIXME: Setting the referrer should be the caller's responsibility.
320 FrameLoadRequest requestWithReferrer = request;
321 requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
323 Page* page = m_frame->page();
325 page = page->chrome()->createWindow(m_frame, requestWithReferrer, features);
329 Frame* frame = page->mainFrame();
330 if (request.frameName() != "_blank")
331 frame->tree()->setName(request.frameName());
333 page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible);
334 page->chrome()->setStatusbarVisible(features.statusBarVisible);
335 page->chrome()->setScrollbarsVisible(features.scrollbarsVisible);
336 page->chrome()->setMenubarVisible(features.menuBarVisible);
337 page->chrome()->setResizable(features.resizable);
339 // 'x' and 'y' specify the location of the window, while 'width' and 'height'
340 // specify the size of the page. We can only resize the window, so
341 // adjust for the difference between the window size and the page size.
343 FloatRect windowRect = page->chrome()->windowRect();
344 FloatSize pageSize = page->chrome()->pageRect().size();
346 windowRect.setX(features.x);
348 windowRect.setY(features.y);
349 if (features.widthSet)
350 windowRect.setWidth(features.width + (windowRect.width() - pageSize.width()));
351 if (features.heightSet)
352 windowRect.setHeight(features.height + (windowRect.height() - pageSize.height()));
353 page->chrome()->setWindowRect(windowRect);
355 page->chrome()->show();
361 bool FrameLoader::canHandleRequest(const ResourceRequest& request)
363 return m_client->canHandleRequest(request);
366 void FrameLoader::changeLocation(const String& URL, const String& referrer, bool lockHistory, bool userGesture)
368 changeLocation(completeURL(URL), referrer, lockHistory, userGesture);
371 void FrameLoader::changeLocation(const KURL& URL, const String& referrer, bool lockHistory, bool userGesture)
373 if (URL.url().find("javascript:", 0, false) == 0) {
374 String script = KURL::decode_string(URL.url().mid(strlen("javascript:")));
375 JSValue* result = executeScript(script, userGesture);
377 if (getString(result, scriptResult)) {
385 ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh)
386 ? ReloadIgnoringCacheData : UseProtocolCachePolicy;
387 ResourceRequest request(URL, referrer, policy);
389 urlSelected(request, "_self", 0, lockHistory, userGesture);
392 void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool userGesture)
394 String target = _target;
395 if (target.isEmpty() && m_frame->document())
396 target = m_frame->document()->baseTarget();
398 const KURL& url = request.url();
399 if (url.url().startsWith("javascript:", false)) {
400 executeScript(KURL::decode_string(url.url().mid(strlen("javascript:"))), true);
404 FrameLoadRequest frameRequest(request, target);
406 if (frameRequest.resourceRequest().httpReferrer().isEmpty())
407 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
409 urlSelected(frameRequest, triggeringEvent, lockHistory, userGesture);
412 bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName)
414 #if USE(LOW_BANDWIDTH_DISPLAY)
415 // don't create sub-frame during low bandwidth display
416 if (frame()->document()->inLowBandwidthDisplay()) {
417 m_needToSwitchOutLowBandwidthDisplay = true;
422 // Support for <frame src="javascript:string">
425 if (urlString.startsWith("javascript:", false)) {
426 scriptURL = urlString.deprecatedString();
429 url = completeURL(urlString);
431 Frame* frame = ownerElement->contentFrame();
433 frame->loader()->scheduleLocationChange(url.url(), m_outgoingReferrer, true, userGestureHint());
435 frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer);
440 if (!scriptURL.isEmpty())
441 frame->loader()->replaceContentsWithScriptResult(scriptURL);
446 Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer)
448 bool allowsScrolling = true;
449 int marginWidth = -1;
450 int marginHeight = -1;
451 if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) {
452 HTMLFrameElementBase* o = static_cast<HTMLFrameElementBase*>(ownerElement);
453 allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff;
454 marginWidth = o->getMarginWidth();
455 marginHeight = o->getMarginHeight();
458 if (!canLoad(url, referrer)) {
459 FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
463 bool hideReferrer = shouldHideReferrer(url, referrer);
464 RefPtr<Frame> frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer,
465 allowsScrolling, marginWidth, marginHeight);
468 checkCallImplicitClose();
472 frame->loader()->m_isComplete = false;
474 if (ownerElement->renderer() && frame->view())
475 static_cast<RenderWidget*>(ownerElement->renderer())->setWidget(frame->view());
477 checkCallImplicitClose();
479 // In these cases, the synchronous load would have finished
480 // before we could connect the signals, so make sure to send the
481 // completed() signal for the child by hand
482 // FIXME: In this case the Frame will have finished loading before
483 // it's being added to the child list. It would be a good idea to
484 // create the child first, then invoke the loader separately.
485 if (url.isEmpty() || url == "about:blank") {
486 frame->loader()->completed();
487 frame->loader()->checkCompleted();
493 void FrameLoader::submitFormAgain()
495 if (m_isRunningScript)
497 OwnPtr<FormSubmission> form(m_deferredFormSubmission.release());
499 submitForm(form->action, form->URL, form->data, form->target,
500 form->contentType, form->boundary, form->event.get());
503 void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr<FormData> formData,
504 const String& target, const String& contentType, const String& boundary, Event* event)
506 ASSERT(formData.get());
508 KURL u = completeURL(url.isNull() ? "" : url);
509 // FIXME: Do we really need to special-case an empty URL?
510 // Would it be better to just go on with the form submisson and let the I/O fail?
514 DeprecatedString urlString = u.url();
515 if (urlString.startsWith("javascript:", false)) {
516 m_isExecutingJavaScriptFormAction = true;
517 executeScript(KURL::decode_string(urlString.mid(strlen("javascript:"))));
518 m_isExecutingJavaScriptFormAction = false;
522 if (m_isRunningScript) {
523 if (m_deferredFormSubmission)
525 m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target,
526 contentType, boundary, event));
530 FrameLoadRequest frameRequest;
532 if (!m_outgoingReferrer.isEmpty())
533 frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
535 frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target);
537 // Handle mailto: forms
538 bool mailtoForm = u.protocol() == "mailto";
542 if (equalIgnoringCase(contentType, "multipart/form-data"))
543 // FIXME: is this correct? I suspect not, but what site can we test this on?
544 body = formData->flattenToString();
545 else if (equalIgnoringCase(contentType, "text/plain"))
546 // Convention seems to be to decode, and s/&/\n/
547 body = KURL::decode_string(
548 formData->flattenToString().replace('&', '\n')
549 .replace('+', ' ').deprecatedString()); // Recode for the URL
551 body = formData->flattenToString();
553 String query = u.query();
554 if (!query.isEmpty())
556 u.setQuery((query + "body=" + KURL::encode_string(body.deprecatedString())).deprecatedString());
559 if (strcmp(action, "GET") == 0) {
561 u.setQuery(formData->flattenToString().deprecatedString());
563 frameRequest.resourceRequest().setHTTPBody(formData.get());
564 frameRequest.resourceRequest().setHTTPMethod("POST");
566 // construct some user headers if necessary
567 if (contentType.isNull() || contentType == "application/x-www-form-urlencoded")
568 frameRequest.resourceRequest().setHTTPContentType(contentType);
569 else // contentType must be "multipart/form-data"
570 frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary);
573 frameRequest.resourceRequest().setURL(u);
575 submitForm(frameRequest, event);
578 void FrameLoader::stopLoading(bool sendUnload)
580 if (m_frame->document() && m_frame->document()->tokenizer())
581 m_frame->document()->tokenizer()->stopParsing();
584 if (m_frame->document()) {
585 if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) {
586 Node* currentFocusedNode = m_frame->document()->focusedNode();
587 if (currentFocusedNode)
588 currentFocusedNode->aboutToUnload();
589 m_frame->document()->dispatchWindowEvent(unloadEvent, false, false);
590 if (m_frame->document())
591 m_frame->document()->updateRendering();
592 m_wasUnloadEventEmitted = true;
595 if (m_frame->document() && !m_frame->document()->inPageCache())
596 m_frame->document()->removeAllEventListenersFromAllNodes();
599 m_isComplete = true; // to avoid calling completed() in finishedParsing() (David)
600 m_isLoadingMainResource = false;
601 m_didCallImplicitClose = true; // don't want that one either
602 m_cachePolicy = CachePolicyVerify; // Why here?
604 if (m_frame->document() && m_frame->document()->parsing()) {
606 m_frame->document()->setParsing(false);
609 m_workingURL = KURL();
611 if (Document* doc = m_frame->document()) {
612 if (DocLoader* docLoader = doc->docLoader())
613 cache()->loader()->cancelRequests(docLoader);
614 XMLHttpRequest::cancelRequests(doc);
617 // tell all subframes to stop as well
618 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
619 child->loader()->stopLoading(sendUnload);
623 #if USE(LOW_BANDWIDTH_DISPLAY)
624 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) {
625 // Since loading is forced to stop, reset the state without really switching.
626 m_needToSwitchOutLowBandwidthDisplay = false;
627 switchOutLowBandwidthDisplayIfReady();
632 void FrameLoader::stop()
634 // http://bugs.webkit.org/show_bug.cgi?id=10854
635 // The frame's last ref may be removed and it will be deleted by checkCompleted().
636 RefPtr<Frame> protector(m_frame);
638 if (m_frame->document()) {
639 if (m_frame->document()->tokenizer())
640 m_frame->document()->tokenizer()->stopParsing();
641 m_frame->document()->finishParsing();
643 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
644 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
645 // become true. An example is when a subframe is a pure text doc, and that subframe is the
646 // last one to complete.
649 m_iconLoader->stopLoading();
652 bool FrameLoader::closeURL()
656 m_frame->editor()->clearUndoRedoOperations();
660 void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress)
662 m_cancellingWithLoadInProgress = cancelWithLoadInProgress;
664 stopRedirectionTimer();
666 m_scheduledRedirection.clear();
669 KURL FrameLoader::iconURL()
671 // If this isn't a top level frame, return nothing
672 if (m_frame->tree() && m_frame->tree()->parent())
675 // If we have an iconURL from a Link element, return that
676 if (m_frame->document() && !m_frame->document()->iconURL().isEmpty())
677 return m_frame->document()->iconURL().deprecatedString();
679 // Don't return a favicon iconURL unless we're http or https
680 if (m_URL.protocol() != "http" && m_URL.protocol() != "https")
684 url.setProtocol(m_URL.protocol());
685 url.setHost(m_URL.host());
686 if (int port = m_URL.port())
688 url.setPath("/favicon.ico");
692 bool FrameLoader::didOpenURL(const KURL& url)
694 if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad)
695 // A redirect was scheduled before the document was created.
696 // This can happen when one frame changes another frame's location.
700 m_frame->editor()->setLastEditCommand(0);
703 m_isComplete = false;
704 m_isLoadingMainResource = true;
705 m_didCallImplicitClose = false;
707 m_frame->setJSStatusBarText(String());
708 m_frame->setJSDefaultStatusBarText(String());
711 if (m_URL.protocol().startsWith("http") && !m_URL.host().isEmpty() && m_URL.path().isEmpty())
713 m_workingURL = m_URL;
720 void FrameLoader::didExplicitOpen()
722 m_isComplete = false;
723 m_didCallImplicitClose = false;
725 // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results
726 // from a subsequent window.document.open / window.document.write call.
727 // Cancelling redirection here works for all cases because document.open
728 // implicitly precedes document.write.
730 if (m_frame->document()->URL() != "about:blank")
731 m_URL = m_frame->document()->URL();
734 void FrameLoader::replaceContentsWithScriptResult(const KURL& url)
736 JSValue* result = executeScript(KURL::decode_string(url.url().mid(strlen("javascript:"))));
738 if (!getString(result, scriptResult))
745 JSValue* FrameLoader::executeScript(const String& script, bool forceUserGesture)
747 return executeScript(forceUserGesture ? String() : String(m_URL.url()), 0, script);
750 JSValue* FrameLoader::executeScript(const String& URL, int baseLine, const String& script)
752 KJSProxy* proxy = m_frame->scriptProxy();
756 bool wasRunningScript = m_isRunningScript;
757 m_isRunningScript = true;
759 JSValue* result = proxy->evaluate(URL, baseLine, script);
761 if (!wasRunningScript) {
762 m_isRunningScript = false;
764 Document::updateDocumentsRendering();
770 void FrameLoader::cancelAndClear()
780 void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects)
782 // FIXME: Commenting out the below line causes <http://bugs.webkit.org/show_bug.cgi?id=11212>, but putting it
783 // back causes a measurable performance regression which we will need to fix to restore the correct behavior
784 // urlsBridgeKnowsAbout.clear();
786 m_frame->editor()->clear();
790 m_needsClear = false;
792 if (m_frame->document() && !m_frame->document()->inPageCache()) {
793 m_frame->document()->cancelParsing();
794 if (m_frame->document()->attached()) {
795 m_frame->document()->willRemove();
796 m_frame->document()->detach();
800 // Do this after detaching the document so that the unload event works.
801 if (clearWindowProperties) {
802 m_frame->clearScriptProxy();
803 m_frame->clearDOMWindow();
806 m_frame->selectionController()->clear();
807 m_frame->eventHandler()->clear();
809 m_frame->view()->clear();
811 // Do not drop the document before the script proxy and view are cleared, as some destructors
812 // might still try to access the document.
813 m_frame->setDocument(0);
816 m_containsPlugIns = false;
818 if (clearScriptObjects)
819 m_frame->clearScriptObjects();
821 m_redirectionTimer.stop();
822 m_scheduledRedirection.clear();
824 m_checkCompletedTimer.stop();
825 m_checkLoadCompleteTimer.stop();
827 m_receivedData = false;
828 m_isDisplayingInitialEmptyDocument = false;
830 if (!m_encodingWasChosenByUser)
831 m_encoding = String();
834 void FrameLoader::receivedFirstData()
836 begin(m_workingURL, false);
838 dispatchDidCommitLoad();
839 dispatchWindowObjectAvailable();
841 String ptitle = m_documentLoader->title();
842 // If we have a title let the WebView know about it.
843 if (!ptitle.isNull())
844 m_client->dispatchDidReceiveTitle(ptitle);
846 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
847 m_workingURL = KURL();
851 if (!m_documentLoader)
853 if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, URL))
859 URL = m_frame->document()->completeURL(URL);
861 scheduleHTTPRedirection(delay, URL);
864 const String& FrameLoader::responseMIMEType() const
866 return m_responseMIMEType;
869 void FrameLoader::setResponseMIMEType(const String& type)
871 m_responseMIMEType = type;
874 void FrameLoader::begin()
879 void FrameLoader::begin(const KURL& url, bool dispatch)
881 bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document() && m_frame->document()->securityOrigin().isSecureTransitionTo(url));
882 clear(resetScripting, resetScripting);
884 dispatchWindowObjectAvailable();
887 m_isComplete = false;
888 m_didCallImplicitClose = false;
889 m_isLoadingMainResource = true;
890 m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument;
893 ref.setUser(DeprecatedString());
894 ref.setPass(DeprecatedString());
895 ref.setRef(DeprecatedString());
896 m_outgoingReferrer = ref.url();
900 if (!m_URL.isEmpty())
903 RefPtr<Document> document = DOMImplementation::instance()->createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode());
904 m_frame->setDocument(document);
906 document->setURL(m_URL.url());
907 // We prefer m_baseURL over m_URL because m_URL changes when we are
908 // about to load a new page.
909 document->setBaseURL(baseurl.url());
911 document->setDecoder(m_decoder.get());
913 updatePolicyBaseURL();
915 Settings* settings = document->settings();
916 document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically());
917 KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL();
918 if (!userStyleSheet.isEmpty())
919 m_frame->setUserStyleSheetLocation(userStyleSheet);
921 restoreDocumentState();
923 document->implicitOpen();
926 m_frame->view()->resizeContents(0, 0);
928 #if USE(LOW_BANDWIDTH_DISPLAY)
929 // Low bandwidth display is a first pass display without external resources
930 // used to give an instant visual feedback. We currently only enable it for
931 // HTML documents in the top frame.
932 if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) {
933 m_pendingSourceInLowBandwidthDisplay = String();
934 m_finishedParsingDuringLowBandwidthDisplay = false;
935 m_needToSwitchOutLowBandwidthDisplay = false;
936 document->setLowBandwidthDisplay(true);
941 void FrameLoader::write(const char* str, int len, bool flush)
943 if (len == 0 && !flush)
949 Tokenizer* tokenizer = m_frame->document()->tokenizer();
950 if (tokenizer && tokenizer->wantsRawData()) {
952 tokenizer->writeRawData(str, len);
957 Settings* settings = m_frame->settings();
958 m_decoder = new TextResourceDecoder(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String());
959 if (!m_encoding.isNull())
960 m_decoder->setEncoding(m_encoding,
961 m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader);
962 if (m_frame->document())
963 m_frame->document()->setDecoder(m_decoder.get());
966 String decoded = m_decoder->decode(str, len);
968 decoded += m_decoder->flush();
969 if (decoded.isEmpty())
972 #if USE(LOW_BANDWIDTH_DISPLAY)
973 if (m_frame->document()->inLowBandwidthDisplay())
974 m_pendingSourceInLowBandwidthDisplay.append(decoded);
975 else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady()
976 m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy);
979 if (!m_receivedData) {
980 m_receivedData = true;
981 m_frame->document()->determineParseMode(decoded);
982 if (m_decoder->encoding().usesVisualOrdering())
983 m_frame->document()->setVisuallyOrdered();
984 m_frame->document()->recalcStyle(Node::Force);
988 ASSERT(!tokenizer->wantsRawData());
989 tokenizer->write(decoded, true);
993 void FrameLoader::write(const String& str)
998 if (!m_receivedData) {
999 m_receivedData = true;
1000 m_frame->document()->setParseMode(Document::Strict);
1003 if (Tokenizer* tokenizer = m_frame->document()->tokenizer())
1004 tokenizer->write(str, true);
1007 void FrameLoader::end()
1009 m_isLoadingMainResource = false;
1010 endIfNotLoadingMainResource();
1013 void FrameLoader::endIfNotLoadingMainResource()
1015 if (m_isLoadingMainResource)
1018 // http://bugs.webkit.org/show_bug.cgi?id=10854
1019 // The frame's last ref may be removed and it can be deleted by checkCompleted(),
1020 // so we'll add a protective refcount
1021 RefPtr<Frame> protector(m_frame);
1023 // make sure nothing's left in there
1024 if (m_frame->document()) {
1026 m_frame->document()->finishParsing();
1027 #if USE(LOW_BANDWIDTH_DISPLAY)
1028 if (m_frame->document()->inLowBandwidthDisplay()) {
1029 m_finishedParsingDuringLowBandwidthDisplay = true;
1030 switchOutLowBandwidthDisplayIfReady();
1034 // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but
1035 // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to
1036 // become true. An example is when a subframe is a pure text doc, and that subframe is the
1037 // last one to complete.
1040 if (m_documentLoader && !m_documentLoader->isLoadingFromCachedPage())
1044 void FrameLoader::iconLoadDecisionAvailable()
1046 if (!m_mayLoadIconLater)
1048 LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this);
1050 m_mayLoadIconLater = false;
1053 void FrameLoader::startIconLoader()
1055 // FIXME: We kick off the icon loader when the frame is done receiving its main resource.
1056 // But we should instead do it when we're done parsing the head element.
1057 if (!isLoadingMainFrame())
1060 if (!iconDatabase() || !iconDatabase()->isEnabled())
1063 KURL url(iconURL());
1064 String urlString(url.url());
1065 if (urlString.isEmpty())
1068 // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load
1069 if (loadType() != FrameLoadTypeReload) {
1070 IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get());
1071 if (decision == IconLoadNo) {
1072 LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data());
1073 commitIconURLToIconDatabase(url);
1075 // We were told not to load this icon - that means this icon is already known by the database
1076 // 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
1077 // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method.
1078 // Otherwise if the icon data *is* available, notify the delegate
1079 if (!iconDatabase()->iconDataKnownForIconURL(urlString)) {
1080 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());
1081 m_client->registerForIconNotification();
1082 iconDatabase()->iconForPageURL(m_URL.url(), IntSize(0, 0));
1083 iconDatabase()->iconForPageURL(originalRequestURL().url(), IntSize(0, 0));
1085 m_client->dispatchDidReceiveIcon();
1090 if (decision == IconLoadUnknown) {
1091 // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database
1092 // 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
1093 // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the
1094 // icon is later read in from disk
1095 LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data());
1096 m_mayLoadIconLater = true;
1097 m_client->registerForIconNotification();
1098 commitIconURLToIconDatabase(url);
1103 // This is either a reload or the icon database said "yes, load the icon", so kick off the load!
1105 m_iconLoader.set(IconLoader::create(m_frame).release());
1107 m_iconLoader->startLoading();
1110 bool FrameLoader::restrictAccessToLocal()
1112 return m_restrictAccessToLocal;
1115 void FrameLoader::setRestrictAccessToLocal(bool access)
1117 m_restrictAccessToLocal = access;
1120 static HashSet<String, CaseInsensitiveHash<String> >& localSchemes()
1122 static HashSet<String, CaseInsensitiveHash<String> > localSchemes;
1124 if (localSchemes.isEmpty()) {
1125 localSchemes.add("file");
1126 localSchemes.add("applewebdata");
1129 return localSchemes;
1132 void FrameLoader::commitIconURLToIconDatabase(const KURL& icon)
1134 ASSERT(iconDatabase());
1135 LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.url().ascii(), m_URL.url().ascii(), originalRequestURL().url().ascii());
1136 iconDatabase()->setIconURLForPageURL(icon.url(), m_URL.url());
1137 iconDatabase()->setIconURLForPageURL(icon.url(), originalRequestURL().url());
1140 void FrameLoader::restoreDocumentState()
1142 Document* doc = m_frame->document();
1146 HistoryItem* itemToRestore = 0;
1148 switch (loadType()) {
1149 case FrameLoadTypeReload:
1150 case FrameLoadTypeReloadAllowingStaleData:
1151 case FrameLoadTypeSame:
1152 case FrameLoadTypeReplace:
1154 case FrameLoadTypeBack:
1155 case FrameLoadTypeForward:
1156 case FrameLoadTypeIndexedBackForward:
1157 case FrameLoadTypeRedirectWithLockedHistory:
1158 case FrameLoadTypeStandard:
1159 itemToRestore = m_currentHistoryItem.get();
1165 doc->setStateForNewFormElements(itemToRestore->documentState());
1168 void FrameLoader::gotoAnchor()
1170 // If our URL has no ref, then we have no place we need to jump to.
1171 // OTOH if css target was set previously, we want to set it to 0, recalc
1172 // and possibly repaint because :target pseudo class may have been
1173 // set(See bug 11321)
1174 if (!m_URL.hasRef() &&
1175 !(m_frame->document() && m_frame->document()->getCSSTarget()))
1178 DeprecatedString ref = m_URL.encodedHtmlRef();
1179 if (!gotoAnchor(ref)) {
1180 // Can't use htmlRef() here because it doesn't know which encoding to use to decode.
1181 // Decoding here has to match encoding in completeURL, which means it has to use the
1182 // page's encoding rather than UTF-8.
1184 gotoAnchor(KURL::decode_string(ref, m_decoder->encoding()));
1188 void FrameLoader::finishedParsing()
1190 if (m_creatingInitialEmptyDocument)
1193 // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves
1194 // because doing so will cause us to re-enter the destructor when protector goes out of scope.
1195 RefPtr<Frame> protector = m_frame->refCount() > 0 ? m_frame : 0;
1199 if (!m_frame->view())
1200 return; // We are being destroyed by something checkCompleted called.
1202 // Check if the scrollbars are really needed for the content.
1203 // If not, remove them, relayout, and repaint.
1204 m_frame->view()->restoreScrollbar();
1206 m_client->dispatchDidFinishDocumentLoad();
1211 void FrameLoader::loadDone()
1213 if (m_frame->document())
1217 void FrameLoader::checkCompleted()
1219 // Any frame that hasn't completed yet?
1220 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1221 if (!child->loader()->m_isComplete)
1224 // Have we completed before?
1228 // Are we still parsing?
1229 if (m_frame->document() && m_frame->document()->parsing())
1232 // Still waiting for images/scripts?
1233 if (m_frame->document())
1234 if (numRequests(m_frame->document()))
1237 #if USE(LOW_BANDWIDTH_DISPLAY)
1238 // as switch will be called, don't complete yet
1239 if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay() && m_needToSwitchOutLowBandwidthDisplay)
1244 m_isComplete = true;
1246 RefPtr<Frame> protect(m_frame);
1247 checkCallImplicitClose(); // if we didn't do it before
1249 // Do not start a redirection timer for subframes here.
1250 // That is deferred until the parent is completed.
1251 if (m_scheduledRedirection && !m_frame->tree()->parent())
1252 startRedirectionTimer();
1255 if (m_frame->page())
1256 checkLoadComplete();
1259 void FrameLoader::checkCompletedTimerFired(Timer<FrameLoader>*)
1264 void FrameLoader::scheduleCheckCompleted()
1266 if (!m_checkCompletedTimer.isActive())
1267 m_checkCompletedTimer.startOneShot(0);
1270 void FrameLoader::checkLoadCompleteTimerFired(Timer<FrameLoader>*)
1272 if (m_frame->page())
1273 checkLoadComplete();
1276 void FrameLoader::scheduleCheckLoadComplete()
1278 if (!m_checkLoadCompleteTimer.isActive())
1279 m_checkLoadCompleteTimer.startOneShot(0);
1282 void FrameLoader::checkCallImplicitClose()
1284 if (m_didCallImplicitClose || !m_frame->document() || m_frame->document()->parsing())
1287 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1288 if (!child->loader()->m_isComplete) // still got a frame running -> too early
1291 // All frames completed -> set their domain to the frameset's domain
1292 // This must only be done when loading the frameset initially (#22039),
1293 // not when following a link in a frame (#44162).
1294 if (m_frame->document()) {
1295 String domain = m_frame->document()->domain();
1296 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1297 if (child->document())
1298 child->document()->setDomainInternal(domain);
1301 m_didCallImplicitClose = true;
1302 m_wasUnloadEventEmitted = false;
1303 if (m_frame->document())
1304 m_frame->document()->implicitClose();
1307 KURL FrameLoader::baseURL() const
1309 ASSERT(m_frame->document());
1310 return m_frame->document()->baseURL();
1313 String FrameLoader::baseTarget() const
1315 ASSERT(m_frame->document());
1316 return m_frame->document()->baseTarget();
1319 KURL FrameLoader::completeURL(const String& url)
1321 ASSERT(m_frame->document());
1322 return m_frame->document()->completeURL(url).deprecatedString();
1325 void FrameLoader::scheduleHTTPRedirection(double delay, const String& url)
1327 if (delay < 0 || delay > INT_MAX / 1000)
1330 // We want a new history item if the refresh timeout is > 1 second.
1331 if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay)
1332 scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, false));
1335 void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool wasUserGesture)
1337 // If the URL we're going to navigate to is the same as the current one, except for the
1338 // fragment part, we don't need to schedule the location change.
1339 KURL u(url.deprecatedString());
1340 if (u.hasRef() && equalIgnoringRef(m_URL, u)) {
1341 changeLocation(url, referrer, lockHistory, wasUserGesture);
1345 // Handle a location change of a page with no document as a special case.
1346 // This may happen when a frame changes the location of another frame.
1347 bool duringLoad = !m_committedFirstRealDocumentLoad;
1349 // If a redirect was scheduled during a load, then stop the current load.
1350 // Otherwise when the current load transitions from a provisional to a
1351 // committed state, pending redirects may be cancelled.
1353 if (m_provisionalDocumentLoader)
1354 m_provisionalDocumentLoader->stopLoading();
1358 ScheduledRedirection::Type type = duringLoad
1359 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1360 scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, wasUserGesture));
1363 void FrameLoader::scheduleRefresh(bool wasUserGesture)
1365 // Handle a location change of a page with no document as a special case.
1366 // This may happen when a frame requests a refresh of another frame.
1367 bool duringLoad = !m_frame->document();
1369 // If a refresh was scheduled during a load, then stop the current load.
1370 // Otherwise when the current load transitions from a provisional to a
1371 // committed state, pending redirects may be cancelled.
1375 ScheduledRedirection::Type type = duringLoad
1376 ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange;
1377 scheduleRedirection(new ScheduledRedirection(type, m_URL.url(), m_outgoingReferrer, true, wasUserGesture));
1378 m_cachePolicy = CachePolicyRefresh;
1381 bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection)
1383 switch (redirection.type) {
1384 case ScheduledRedirection::redirection:
1386 case ScheduledRedirection::historyNavigation:
1387 case ScheduledRedirection::locationChange:
1388 case ScheduledRedirection::locationChangeDuringLoad:
1391 ASSERT_NOT_REACHED();
1395 void FrameLoader::scheduleHistoryNavigation(int steps)
1397 // navigation will always be allowed in the 0 steps case, which is OK because
1398 // that's supposed to force a reload.
1399 if (!canGoBackOrForward(steps)) {
1400 cancelRedirection();
1404 // If the steps to navigate is not zero (which needs to force a reload), and if the URL we're going to navigate
1405 // to is the same as the current one, except for the fragment part, we don't need to schedule the navigation.
1406 if (steps != 0 && equalIgnoringRef(m_URL, historyURL(steps))) {
1407 goBackOrForward(steps);
1411 scheduleRedirection(new ScheduledRedirection(steps));
1414 void FrameLoader::goBackOrForward(int distance)
1419 Page* page = m_frame->page();
1422 BackForwardList* list = page->backForwardList();
1426 HistoryItem* item = list->itemAtIndex(distance);
1429 int forwardListCount = list->forwardListCount();
1430 if (forwardListCount > 0)
1431 item = list->itemAtIndex(forwardListCount);
1433 int backListCount = list->backListCount();
1434 if (backListCount > 0)
1435 item = list->itemAtIndex(-backListCount);
1439 ASSERT(item); // we should not reach this line with an empty back/forward list
1441 page->goToItem(item, FrameLoadTypeIndexedBackForward);
1444 void FrameLoader::redirectionTimerFired(Timer<FrameLoader>*)
1446 OwnPtr<ScheduledRedirection> redirection(m_scheduledRedirection.release());
1448 switch (redirection->type) {
1449 case ScheduledRedirection::redirection:
1450 case ScheduledRedirection::locationChange:
1451 case ScheduledRedirection::locationChangeDuringLoad:
1452 changeLocation(redirection->URL, redirection->referrer,
1453 redirection->lockHistory, redirection->wasUserGesture);
1455 case ScheduledRedirection::historyNavigation:
1456 if (redirection->historySteps == 0) {
1457 // Special case for go(0) from a frame -> reload only the frame
1458 urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->wasUserGesture);
1461 // go(i!=0) from a frame navigates into the history of the frame only,
1462 // in both IE and NS (but not in Mozilla). We can't easily do that.
1463 goBackOrForward(redirection->historySteps);
1466 ASSERT_NOT_REACHED();
1469 String FrameLoader::encoding() const
1471 if (m_encodingWasChosenByUser && !m_encoding.isEmpty())
1473 if (m_decoder && m_decoder->encoding().isValid())
1474 return m_decoder->encoding().name();
1475 Settings* settings = m_frame->settings();
1476 return settings ? settings->defaultTextEncodingName() : String();
1479 bool FrameLoader::gotoAnchor(const String& name)
1481 ASSERT(m_frame->document());
1483 if (!m_frame->document()->haveStylesheetsLoaded()) {
1484 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true);
1488 m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false);
1490 Node* anchorNode = m_frame->document()->getElementById(AtomicString(name));
1492 anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->document()->inCompatMode());
1495 if (m_frame->document()->isSVGDocument()) {
1496 if (name.startsWith("xpointer(")) {
1497 // We need to parse the xpointer reference here
1498 } else if (name.startsWith("svgView(")) {
1499 RefPtr<SVGSVGElement> svg = static_cast<SVGDocument*>(m_frame->document())->rootElement();
1500 if (!svg->currentView()->parseViewSpec(name))
1502 svg->setUseCurrentView(true);
1504 if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) {
1505 RefPtr<SVGViewElement> viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast<SVGViewElement*>(anchorNode) : 0;
1506 if (viewElement.get()) {
1507 RefPtr<SVGSVGElement> svg = static_cast<SVGSVGElement*>(SVGLocatable::nearestViewportElement(viewElement.get()));
1508 svg->inheritViewAttributes(viewElement.get());
1512 // FIXME: need to decide which <svg> to focus on, and zoom to that one
1513 // FIXME: need to actually "highlight" the viewTarget(s)
1517 m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target.
1519 // Implement the rule that "" and "top" both mean top of page as in other browsers.
1520 if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top")))
1523 // We need to update the layout before scrolling, otherwise we could
1524 // really mess things up if an anchor scroll comes at a bad moment.
1525 if (m_frame->document()) {
1526 m_frame->document()->updateRendering();
1527 // Only do a layout if changes have occurred that make it necessary.
1528 if (m_frame->view() && m_frame->document()->renderer() && m_frame->document()->renderer()->needsLayout())
1529 m_frame->view()->layout();
1532 // Scroll nested layers and frames to reveal the anchor.
1533 // Align to the top and to the closest side (this matches other browsers).
1534 RenderObject* renderer;
1537 renderer = m_frame->document()->renderer(); // top of document
1539 renderer = anchorNode->renderer();
1540 rect = anchorNode->getRect();
1543 renderer->enclosingLayer()->scrollRectToVisible(rect, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways);
1548 bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName,
1549 const String& mimeType, const Vector<String>& paramNames, const Vector<String>& paramValues)
1551 if (url.isEmpty() && mimeType.isEmpty())
1554 #if USE(LOW_BANDWIDTH_DISPLAY)
1555 // don't care object during low bandwidth display
1556 if (frame()->document()->inLowBandwidthDisplay()) {
1557 m_needToSwitchOutLowBandwidthDisplay = true;
1564 completedURL = completeURL(url);
1567 if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) {
1568 Settings* settings = m_frame->settings();
1569 if (!settings || !settings->arePluginsEnabled() ||
1570 (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType)))
1572 return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback);
1575 ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag));
1576 HTMLPlugInElement* element = static_cast<HTMLPlugInElement*>(renderer->node());
1578 // FIXME: OK to always make a new frame? When does the old frame get removed?
1579 return loadSubframe(element, completedURL, frameName, m_outgoingReferrer);
1582 bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback)
1584 ObjectContentType objectType = m_client->objectContentType(url, mimeType);
1585 // If an object's content can't be handled and it has no fallback, let
1586 // it be handled as a plugin to show the broken plugin icon.
1587 useFallback = objectType == ObjectContentNone && hasFallback;
1588 return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin;
1591 bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType,
1592 const Vector<String>& paramNames, const Vector<String>& paramValues, bool useFallback)
1596 if (renderer && !useFallback) {
1597 Element* pluginElement = 0;
1598 if (renderer->node() && renderer->node()->isElementNode())
1599 pluginElement = static_cast<Element*>(renderer->node());
1601 if (!canLoad(url, frame()->document())) {
1602 FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
1606 widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()),
1607 pluginElement, url, paramNames, paramValues, mimeType,
1608 m_frame->document()->isPluginDocument());
1610 renderer->setWidget(widget);
1611 m_containsPlugIns = true;
1618 void FrameLoader::clearRecordedFormValues()
1620 m_formAboutToBeSubmitted = 0;
1621 m_formValuesAboutToBeSubmitted.clear();
1624 void FrameLoader::recordFormValue(const String& name, const String& value, PassRefPtr<HTMLFormElement> element)
1626 m_formAboutToBeSubmitted = element;
1627 m_formValuesAboutToBeSubmitted.set(name, value);
1630 void FrameLoader::parentCompleted()
1632 if (m_scheduledRedirection && !m_redirectionTimer.isActive())
1633 startRedirectionTimer();
1636 String FrameLoader::outgoingReferrer() const
1638 return m_outgoingReferrer;
1641 Frame* FrameLoader::opener()
1646 void FrameLoader::setOpener(Frame* opener)
1649 m_opener->loader()->m_openedFrames.remove(m_frame);
1651 opener->loader()->m_openedFrames.add(m_frame);
1654 if (m_frame->document())
1655 m_frame->document()->initSecurityOrigin();
1658 bool FrameLoader::openedByDOM() const
1660 return m_openedByDOM;
1663 void FrameLoader::setOpenedByDOM()
1665 m_openedByDOM = true;
1668 void FrameLoader::handleFallbackContent()
1670 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
1671 if (!owner || !owner->hasTagName(objectTag))
1673 static_cast<HTMLObjectElement*>(owner)->renderFallbackContent();
1676 void FrameLoader::provisionalLoadStarted()
1678 Page* page = m_frame->page();
1680 // this is used to update the current history item
1681 // in the event of a navigation aytime during loading
1682 m_navigationDuringLoad = false;
1684 Document *document = page->mainFrame()->document();
1685 m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent());
1688 m_firstLayoutDone = false;
1689 cancelRedirection(true);
1690 m_client->provisionalLoadStarted();
1692 if (canCachePage() && m_client->canCachePage() && !m_currentHistoryItem->isInPageCache())
1693 cachePageForHistoryItem(m_currentHistoryItem.get());
1696 bool FrameLoader::userGestureHint()
1698 Frame* rootFrame = m_frame;
1699 while (rootFrame->tree()->parent())
1700 rootFrame = rootFrame->tree()->parent();
1702 if (rootFrame->scriptProxy())
1703 return rootFrame->scriptProxy()->interpreter()->wasRunByUserGesture();
1705 return true; // If JavaScript is disabled, a user gesture must have initiated the navigation
1708 void FrameLoader::didNotOpenURL(const KURL& URL)
1710 if (m_submittedFormURL == URL)
1711 m_submittedFormURL = KURL();
1714 void FrameLoader::resetMultipleFormSubmissionProtection()
1716 m_submittedFormURL = KURL();
1719 void FrameLoader::setEncoding(const String& name, bool userChosen)
1721 if (!m_workingURL.isEmpty())
1722 receivedFirstData();
1724 m_encodingWasChosenByUser = userChosen;
1727 void FrameLoader::addData(const char* bytes, int length)
1729 ASSERT(m_workingURL.isEmpty());
1730 ASSERT(m_frame->document());
1731 ASSERT(m_frame->document()->parsing());
1732 write(bytes, length);
1735 bool FrameLoader::canCachePage()
1737 // Cache the page, if possible.
1738 // Don't write to the cache if in the middle of a redirect, since we will want to
1739 // store the final page we end up on.
1740 // No point writing to the cache on a reload or loadSame, since we will just write
1741 // over it again when we leave that page.
1742 // FIXME: <rdar://problem/4886592> - We should work out the complexities of caching pages with frames as they
1743 // are the most interesting pages on the web, and often those that would benefit the most from caching!
1744 FrameLoadType loadType = this->loadType();
1746 return m_documentLoader
1747 && m_documentLoader->mainDocumentError().isNull()
1748 && !m_frame->tree()->childCount()
1749 && !m_frame->tree()->parent()
1750 // FIXME: If we ever change this so that pages with plug-ins will be cached,
1751 // we need to make sure that we don't cache pages that have outstanding NPObjects
1752 // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in,
1753 // they would need to be destroyed and then recreated, and there is no way that we can recreate
1754 // the right NPObjects. See <rdar://problem/5197041> for more information.
1755 && !m_containsPlugIns
1756 && !m_URL.protocol().startsWith("https")
1757 && m_frame->document()
1758 && !m_frame->document()->applets()->length()
1759 && !m_frame->document()->hasWindowEventListener(unloadEvent)
1761 && m_frame->page()->backForwardList()->enabled()
1762 && m_frame->page()->backForwardList()->capacity() > 0
1763 && m_frame->page()->settings()->usesPageCache()
1764 && m_currentHistoryItem
1765 && !isQuickRedirectComing()
1766 && loadType != FrameLoadTypeReload
1767 && loadType != FrameLoadTypeReloadAllowingStaleData
1768 && loadType != FrameLoadTypeSame
1769 && !m_documentLoader->isLoadingInAPISense()
1770 && !m_documentLoader->isStopping();
1773 void FrameLoader::updatePolicyBaseURL()
1775 if (m_frame->tree()->parent() && m_frame->tree()->parent()->document())
1776 setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL());
1778 setPolicyBaseURL(m_URL.url());
1781 void FrameLoader::setPolicyBaseURL(const String& s)
1783 if (m_frame->document())
1784 m_frame->document()->setPolicyBaseURL(s);
1785 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1786 child->loader()->setPolicyBaseURL(s);
1789 // This does the same kind of work that FrameLoader::openURL does, except it relies on the fact
1790 // that a higher level already checked that the URLs match and the scrolling is the right thing to do.
1791 void FrameLoader::scrollToAnchor(const KURL& URL)
1798 // It's important to model this as a load that starts and immediately finishes.
1799 // Otherwise, the parent frame may think we never finished loading.
1800 m_isComplete = false;
1804 bool FrameLoader::isComplete() const
1806 return m_isComplete;
1809 void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection)
1811 stopRedirectionTimer();
1812 m_scheduledRedirection.set(redirection);
1813 if (!m_isComplete && redirection->type != ScheduledRedirection::redirection)
1815 if (m_isComplete || redirection->type != ScheduledRedirection::redirection)
1816 startRedirectionTimer();
1819 void FrameLoader::startRedirectionTimer()
1821 ASSERT(m_scheduledRedirection);
1823 m_redirectionTimer.stop();
1824 m_redirectionTimer.startOneShot(m_scheduledRedirection->delay);
1826 switch (m_scheduledRedirection->type) {
1827 case ScheduledRedirection::redirection:
1828 case ScheduledRedirection::locationChange:
1829 case ScheduledRedirection::locationChangeDuringLoad:
1830 clientRedirected(m_scheduledRedirection->URL.deprecatedString(),
1831 m_scheduledRedirection->delay,
1832 currentTime() + m_redirectionTimer.nextFireInterval(),
1833 m_scheduledRedirection->lockHistory,
1834 m_isExecutingJavaScriptFormAction);
1836 case ScheduledRedirection::historyNavigation:
1837 // Don't report history navigations.
1840 ASSERT_NOT_REACHED();
1843 void FrameLoader::stopRedirectionTimer()
1845 if (!m_redirectionTimer.isActive())
1848 m_redirectionTimer.stop();
1850 if (m_scheduledRedirection) {
1851 switch (m_scheduledRedirection->type) {
1852 case ScheduledRedirection::redirection:
1853 case ScheduledRedirection::locationChange:
1854 case ScheduledRedirection::locationChangeDuringLoad:
1855 clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress);
1857 case ScheduledRedirection::historyNavigation:
1858 // Don't report history navigations.
1861 ASSERT_NOT_REACHED();
1865 void FrameLoader::completed()
1867 RefPtr<Frame> protect(m_frame);
1868 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
1869 child->loader()->parentCompleted();
1870 if (Frame* parent = m_frame->tree()->parent())
1871 parent->loader()->checkCompleted();
1875 void FrameLoader::started()
1877 for (Frame* frame = m_frame; frame; frame = frame->tree()->parent())
1878 frame->loader()->m_isComplete = false;
1881 bool FrameLoader::containsPlugins() const
1883 return m_containsPlugIns;
1886 void FrameLoader::prepareForLoadStart()
1888 if (Page* page = m_frame->page())
1889 page->progress()->progressStarted(m_frame);
1890 m_client->dispatchDidStartProvisionalLoad();
1893 void FrameLoader::setupForReplace()
1895 setState(FrameStateProvisional);
1896 m_provisionalDocumentLoader = m_documentLoader;
1897 m_documentLoader = 0;
1901 void FrameLoader::setupForReplaceByMIMEType(const String& newMIMEType)
1903 activeDocumentLoader()->setupForReplaceByMIMEType(newMIMEType);
1906 void FrameLoader::finalSetupForReplace(DocumentLoader* loader)
1908 m_client->clearUnarchivingState(loader);
1911 void FrameLoader::load(const KURL& URL, Event* event)
1913 load(ResourceRequest(URL), false, true, event, 0, HashMap<String, String>());
1916 void FrameLoader::load(const FrameLoadRequest& request, bool lockHistory, bool userGesture, Event* event,
1917 HTMLFormElement* submitForm, const HashMap<String, String>& formValues)
1919 KURL url = request.resourceRequest().url();
1922 String argsReferrer = request.resourceRequest().httpReferrer();
1923 if (!argsReferrer.isEmpty())
1924 referrer = argsReferrer;
1926 referrer = m_outgoingReferrer;
1928 ASSERT(frame()->document());
1929 if (url.url().startsWith("file:", false)) {
1930 if (!canLoad(url, frame()->document()) && !canLoad(url, referrer)) {
1931 FrameLoader::reportLocalLoadFailed(m_frame->page(), url.url());
1936 if (shouldHideReferrer(url, referrer))
1937 referrer = String();
1939 Frame* targetFrame = m_frame->tree()->find(request.frameName());
1940 if (!shouldAllowNavigation(targetFrame))
1943 if (request.resourceRequest().httpMethod() != "POST") {
1944 FrameLoadType loadType;
1945 if (request.resourceRequest().cachePolicy() == ReloadIgnoringCacheData)
1946 loadType = FrameLoadTypeReload;
1947 else if (lockHistory)
1948 loadType = FrameLoadTypeRedirectWithLockedHistory;
1950 loadType = FrameLoadTypeStandard;
1952 RefPtr<FormState> formState;
1953 if (submitForm && !formValues.isEmpty())
1954 formState = FormState::create(submitForm, formValues, m_frame);
1956 load(request.resourceRequest().url(), referrer, loadType,
1957 request.frameName(), event, formState.release());
1959 post(request.resourceRequest().url(), referrer, request.frameName(),
1960 request.resourceRequest().httpBody(), request.resourceRequest().httpContentType(), event, submitForm, formValues);
1962 if (targetFrame && targetFrame != m_frame)
1963 if (Page* page = targetFrame->page())
1964 page->chrome()->focus();
1967 void FrameLoader::load(const KURL& URL, const String& referrer, FrameLoadType newLoadType,
1968 const String& frameName, Event* event, PassRefPtr<FormState> formState)
1970 bool isFormSubmission = formState;
1972 ResourceRequest request(URL);
1973 if (!referrer.isEmpty())
1974 request.setHTTPReferrer(referrer);
1975 addExtraFieldsToRequest(request, true, event || isFormSubmission);
1976 if (newLoadType == FrameLoadTypeReload)
1977 request.setCachePolicy(ReloadIgnoringCacheData);
1979 ASSERT(newLoadType != FrameLoadTypeSame);
1981 NavigationAction action(URL, newLoadType, isFormSubmission, event);
1983 if (!frameName.isEmpty()) {
1984 if (Frame* targetFrame = m_frame->tree()->find(frameName))
1985 targetFrame->loader()->load(URL, referrer, newLoadType, String(), event, formState);
1987 checkNewWindowPolicy(action, request, formState, frameName);
1991 RefPtr<DocumentLoader> oldDocumentLoader = m_documentLoader;
1993 bool sameURL = shouldTreatURLAsSameAsCurrent(URL);
1995 // Make sure to do scroll to anchor processing even if the URL is
1996 // exactly the same so pages with '#' links and DHTML side effects
1998 if (!isFormSubmission
1999 && newLoadType != FrameLoadTypeReload
2000 && newLoadType != FrameLoadTypeSame
2001 && !shouldReload(URL, url())
2002 // We don't want to just scroll if a link from within a
2003 // frameset is trying to reload the frameset into _top.
2004 && !m_frame->isFrameSet()) {
2006 // Just do anchor navigation within the existing content.
2008 // We don't do this if we are submitting a form, explicitly reloading,
2009 // currently displaying a frameset, or if the new URL does not have a fragment.
2010 // These rules are based on what KHTML was doing in KHTMLPart::openURL.
2012 // FIXME: What about load types other than Standard and Reload?
2014 oldDocumentLoader->setTriggeringAction(action);
2016 checkNavigationPolicy(request, oldDocumentLoader.get(), formState,
2017 callContinueFragmentScrollAfterNavigationPolicy, this);
2019 // must grab this now, since this load may stop the previous load and clear this flag
2020 bool isRedirect = m_quickRedirectComing;
2021 load(request, action, newLoadType, formState);
2023 m_quickRedirectComing = false;
2024 if (m_provisionalDocumentLoader)
2025 m_provisionalDocumentLoader->setIsClientRedirect(true);
2027 // Example of this case are sites that reload the same URL with a different cookie
2028 // driving the generated content, or a master frame with links that drive a target
2029 // frame, where the user has clicked on the same link repeatedly.
2030 m_loadType = FrameLoadTypeSame;
2034 void FrameLoader::load(const ResourceRequest& request)
2036 load(request, SubstituteData());
2039 void FrameLoader::load(const ResourceRequest& request, const SubstituteData& substituteData)
2041 if (m_inStopAllLoaders)
2044 // FIXME: is this the right place to reset loadType? Perhaps this should be done after loading is finished or aborted.
2045 m_loadType = FrameLoadTypeStandard;
2046 load(m_client->createDocumentLoader(request, substituteData).get());
2049 void FrameLoader::load(const ResourceRequest& request, const String& frameName)
2051 if (frameName.isEmpty()) {
2056 Frame* frame = m_frame->tree()->find(frameName);
2058 frame->loader()->load(request);
2062 checkNewWindowPolicy(NavigationAction(request.url(), NavigationTypeOther), request, 0, frameName);
2065 void FrameLoader::load(const ResourceRequest& request, const NavigationAction& action, FrameLoadType type, PassRefPtr<FormState> formState)
2067 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2069 loader->setTriggeringAction(action);
2070 if (m_documentLoader)
2071 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2073 load(loader.get(), type, formState);
2076 void FrameLoader::load(DocumentLoader* newDocumentLoader)
2078 ResourceRequest& r = newDocumentLoader->request();
2079 addExtraFieldsToRequest(r, true, false);
2082 if (shouldTreatURLAsSameAsCurrent(newDocumentLoader->originalRequest().url())) {
2083 r.setCachePolicy(ReloadIgnoringCacheData);
2084 type = FrameLoadTypeSame;
2086 type = FrameLoadTypeStandard;
2088 if (m_documentLoader)
2089 newDocumentLoader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2091 // When we loading alternate content for an unreachable URL that we're
2092 // visiting in the b/f list, we treat it as a reload so the b/f list
2093 // is appropriately maintained.
2094 if (shouldReloadToHandleUnreachableURL(newDocumentLoader)) {
2095 ASSERT(type == FrameLoadTypeStandard);
2096 type = FrameLoadTypeReload;
2099 load(newDocumentLoader, type, 0);
2102 void FrameLoader::load(DocumentLoader* loader, FrameLoadType type, PassRefPtr<FormState> formState)
2104 ASSERT(m_client->hasWebView());
2106 // Unfortunately the view must be non-nil, this is ultimately due
2107 // to parser requiring a FrameView. We should fix this dependency.
2109 ASSERT(m_client->hasFrameView());
2111 m_policyLoadType = type;
2113 if (Frame* parent = m_frame->tree()->parent())
2114 loader->setOverrideEncoding(parent->loader()->documentLoader()->overrideEncoding());
2117 setPolicyDocumentLoader(loader);
2119 checkNavigationPolicy(loader->request(), loader, formState,
2120 callContinueLoadAfterNavigationPolicy, this);
2123 // FIXME: It would be nice if we could collapse these into one or two functions.
2124 bool FrameLoader::canLoad(const KURL& url, const String& referrer)
2126 if (!shouldTreatURLAsLocal(url.url()))
2129 return shouldTreatURLAsLocal(referrer);
2132 bool FrameLoader::canLoad(const KURL& url, const Document* doc)
2134 if (!shouldTreatURLAsLocal(url.url()))
2137 return doc && doc->isAllowedToLoadLocalResources();
2140 bool FrameLoader::canLoad(const CachedResource& resource, const Document* doc)
2142 if (!resource.treatAsLocal())
2145 return doc && doc->isAllowedToLoadLocalResources();
2148 void FrameLoader::reportLocalLoadFailed(const Page* page, const String& url)
2150 ASSERT(!url.isEmpty());
2152 page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, "Not allowed to load local resource: " + url, 0, String());
2155 bool FrameLoader::shouldHideReferrer(const KURL& url, const String& referrer)
2157 bool referrerIsSecureURL = referrer.startsWith("https:", false);
2158 bool referrerIsWebURL = referrerIsSecureURL || referrer.startsWith("http:", false);
2160 if (!referrerIsWebURL)
2163 if (!referrerIsSecureURL)
2166 bool URLIsSecureURL = url.url().startsWith("https:", false);
2168 return !URLIsSecureURL;
2171 const ResourceRequest& FrameLoader::initialRequest() const
2173 return activeDocumentLoader()->initialRequest();
2176 void FrameLoader::receivedData(const char* data, int length)
2178 activeDocumentLoader()->receivedData(data, length);
2181 bool FrameLoader::willUseArchive(ResourceLoader* loader, const ResourceRequest& request, const KURL& originalURL) const
2183 return m_client->willUseArchive(loader, request, originalURL);
2186 void FrameLoader::handleUnimplementablePolicy(const ResourceError& error)
2188 m_delegateIsHandlingUnimplementablePolicy = true;
2189 m_client->dispatchUnableToImplementPolicy(error);
2190 m_delegateIsHandlingUnimplementablePolicy = false;
2193 void FrameLoader::cannotShowMIMEType(const ResourceResponse& response)
2195 handleUnimplementablePolicy(m_client->cannotShowMIMETypeError(response));
2198 ResourceError FrameLoader::interruptionForPolicyChangeError(const ResourceRequest& request)
2200 return m_client->interruptForPolicyChangeError(request);
2203 void FrameLoader::checkNavigationPolicy(const ResourceRequest& newRequest, NavigationPolicyDecisionFunction function, void* argument)
2205 checkNavigationPolicy(newRequest, activeDocumentLoader(), 0, function, argument);
2208 void FrameLoader::checkContentPolicy(const String& MIMEType, ContentPolicyDecisionFunction function, void* argument)
2210 ASSERT(activeDocumentLoader());
2212 // Always show content with valid substitute data.
2213 if (activeDocumentLoader()->substituteData().isValid()) {
2214 function(argument, PolicyUse);
2219 // Respect the hidden FTP Directory Listing pref so it can be tested even if the policy delegate might otherwise disallow it
2220 Settings* settings = m_frame->settings();
2221 if (settings && settings->forceFTPDirectoryListings() && MIMEType == "application/x-ftp-directory") {
2222 function(argument, PolicyUse);
2227 m_policyCheck.set(function, argument);
2228 m_client->dispatchDecidePolicyForMIMEType(&FrameLoader::continueAfterContentPolicy,
2229 MIMEType, activeDocumentLoader()->request());
2232 bool FrameLoader::shouldReloadToHandleUnreachableURL(DocumentLoader* docLoader)
2234 KURL unreachableURL = docLoader->unreachableURL();
2236 if (unreachableURL.isEmpty())
2239 if (!isBackForwardLoadType(m_policyLoadType))
2242 // We only treat unreachableURLs specially during the delegate callbacks
2243 // for provisional load errors and navigation policy decisions. The former
2244 // case handles well-formed URLs that can't be loaded, and the latter
2245 // case handles malformed URLs and unknown schemes. Loading alternate content
2246 // at other times behaves like a standard load.
2247 DocumentLoader* compareDocumentLoader = 0;
2248 if (m_delegateIsDecidingNavigationPolicy || m_delegateIsHandlingUnimplementablePolicy)
2249 compareDocumentLoader = m_policyDocumentLoader.get();
2250 else if (m_delegateIsHandlingProvisionalLoadError)
2251 compareDocumentLoader = m_provisionalDocumentLoader.get();
2253 return compareDocumentLoader && unreachableURL == compareDocumentLoader->request().url();
2256 void FrameLoader::reloadAllowingStaleData(const String& encoding)
2258 if (!m_documentLoader)
2261 ResourceRequest request = m_documentLoader->request();
2262 KURL unreachableURL = m_documentLoader->unreachableURL();
2263 if (!unreachableURL.isEmpty())
2264 request.setURL(unreachableURL);
2266 request.setCachePolicy(ReturnCacheDataElseLoad);
2268 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(request, SubstituteData());
2269 setPolicyDocumentLoader(loader.get());
2271 loader->setOverrideEncoding(encoding);
2273 load(loader.get(), FrameLoadTypeReloadAllowingStaleData, 0);
2276 void FrameLoader::reload()
2278 if (!m_documentLoader)
2281 ResourceRequest& initialRequest = m_documentLoader->request();
2283 // If a window is created by javascript, its main frame can have an empty but non-nil URL.
2284 // Reloading in this case will lose the current contents (see 4151001).
2285 if (initialRequest.url().isEmpty())
2288 // Replace error-page URL with the URL we were trying to reach.
2289 KURL unreachableURL = m_documentLoader->unreachableURL();
2290 if (!unreachableURL.isEmpty())
2291 initialRequest = ResourceRequest(unreachableURL);
2293 RefPtr<DocumentLoader> loader = m_client->createDocumentLoader(initialRequest, SubstituteData());
2295 ResourceRequest& request = loader->request();
2297 request.setCachePolicy(ReloadIgnoringCacheData);
2298 request.setHTTPHeaderField("Cache-Control", "max-age=0");
2300 // If we're about to re-post, set up action so the application can warn the user.
2301 if (request.httpMethod() == "POST")
2302 loader->setTriggeringAction(NavigationAction(request.url(), NavigationTypeFormResubmitted));
2304 loader->setOverrideEncoding(m_documentLoader->overrideEncoding());
2306 load(loader.get(), FrameLoadTypeReload, 0);
2309 bool FrameLoader::shouldAllowNavigation(Frame* targetFrame) const
2311 // The navigation change is safe if the active frame is:
2312 // - in the same security origin as the target or one of the target's ancestors
2313 // Or the target frame is:
2314 // - a top-level frame in the frame hierarchy
2319 if (m_frame == targetFrame)
2322 if (!targetFrame->tree()->parent())
2325 Document* activeDocument = m_frame->document();
2326 ASSERT(activeDocument);
2327 const SecurityOrigin& activeSecurityOrigin = activeDocument->securityOrigin();
2328 for (Frame* ancestorFrame = targetFrame; ancestorFrame; ancestorFrame = ancestorFrame->tree()->parent()) {
2329 Document* ancestorDocument = ancestorFrame->document();
2330 if (!ancestorDocument)
2333 const SecurityOrigin& ancestorSecurityOrigin = ancestorDocument->securityOrigin();
2334 if (activeSecurityOrigin.canAccess(ancestorSecurityOrigin))
2338 if (!targetFrame->settings()->privateBrowsingEnabled()) {
2339 Document* targetDocument = targetFrame->document();
2340 // FIXME: this error message should contain more specifics of why the navigation change is not allowed.
2341 String message = String::format("Unsafe JavaScript attempt to initiate a navigation change for frame with URL %s from frame with URL %s.\n",
2342 targetDocument->URL().utf8().data(), activeDocument->URL().utf8().data());
2344 if (KJS::Interpreter::shouldPrintExceptions())
2345 printf("%s", message.utf8().data());
2347 // FIXME: should we print to the console of the activeFrame as well?
2348 if (Page* page = targetFrame->page())
2349 page->chrome()->addMessageToConsole(JSMessageSource, ErrorMessageLevel, message, 1, String());
2355 void FrameLoader::stopLoadingSubframes()
2357 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2358 child->loader()->stopAllLoaders();
2361 void FrameLoader::stopAllLoaders()
2363 // If this method is called from within this method, infinite recursion can occur (3442218). Avoid this.
2364 if (m_inStopAllLoaders)
2367 m_inStopAllLoaders = true;
2371 stopLoadingSubframes();
2372 if (m_provisionalDocumentLoader)
2373 m_provisionalDocumentLoader->stopLoading();
2374 if (m_documentLoader)
2375 m_documentLoader->stopLoading();
2376 setProvisionalDocumentLoader(0);
2377 m_client->clearArchivedResources();
2379 m_inStopAllLoaders = false;
2382 void FrameLoader::stopForUserCancel(bool deferCheckLoadComplete)
2386 if (deferCheckLoadComplete)
2387 scheduleCheckLoadComplete();
2388 else if (m_frame->page())
2389 checkLoadComplete();
2392 void FrameLoader::cancelPendingArchiveLoad(ResourceLoader* loader)
2394 m_client->cancelPendingArchiveLoad(loader);
2397 DocumentLoader* FrameLoader::activeDocumentLoader() const
2399 if (m_state == FrameStateProvisional)
2400 return m_provisionalDocumentLoader.get();
2401 return m_documentLoader.get();
2404 bool FrameLoader::isLoading() const
2406 DocumentLoader* docLoader = activeDocumentLoader();
2409 return docLoader->isLoadingMainResource() || docLoader->isLoadingSubresources() || docLoader->isLoadingPlugIns();
2412 bool FrameLoader::frameHasLoaded() const
2414 return m_committedFirstRealDocumentLoad || (m_provisionalDocumentLoader && !m_creatingInitialEmptyDocument);
2417 void FrameLoader::setDocumentLoader(DocumentLoader* loader)
2419 if (!loader && !m_documentLoader)
2422 ASSERT(loader != m_documentLoader);
2423 ASSERT(!loader || loader->frameLoader() == this);
2425 m_client->prepareForDataSourceReplacement();
2427 if (m_documentLoader)
2428 m_documentLoader->detachFromFrame();
2430 m_documentLoader = loader;
2433 DocumentLoader* FrameLoader::documentLoader() const
2435 return m_documentLoader.get();
2438 void FrameLoader::setPolicyDocumentLoader(DocumentLoader* loader)
2440 if (m_policyDocumentLoader == loader)
2445 loader->setFrame(m_frame);
2446 if (m_policyDocumentLoader
2447 && m_policyDocumentLoader != m_provisionalDocumentLoader
2448 && m_policyDocumentLoader != m_documentLoader)
2449 m_policyDocumentLoader->detachFromFrame();
2451 m_policyDocumentLoader = loader;
2454 DocumentLoader* FrameLoader::provisionalDocumentLoader()
2456 return m_provisionalDocumentLoader.get();
2459 void FrameLoader::setProvisionalDocumentLoader(DocumentLoader* loader)
2461 ASSERT(!loader || !m_provisionalDocumentLoader);
2462 ASSERT(!loader || loader->frameLoader() == this);
2464 if (m_provisionalDocumentLoader && m_provisionalDocumentLoader != m_documentLoader)
2465 m_provisionalDocumentLoader->detachFromFrame();
2467 m_provisionalDocumentLoader = loader;
2470 FrameState FrameLoader::state() const
2475 double FrameLoader::timeOfLastCompletedLoad()
2477 return storedTimeOfLastCompletedLoad;
2480 void FrameLoader::setState(FrameState newState)
2484 if (newState == FrameStateProvisional)
2485 provisionalLoadStarted();
2486 else if (newState == FrameStateComplete) {
2487 frameLoadCompleted();
2488 storedTimeOfLastCompletedLoad = currentTime();
2489 if (m_documentLoader)
2490 m_documentLoader->stopRecordingResponses();
2494 void FrameLoader::clearProvisionalLoad()
2496 setProvisionalDocumentLoader(0);
2497 if (Page* page = m_frame->page())
2498 page->progress()->progressCompleted(m_frame);
2499 setState(FrameStateComplete);
2502 void FrameLoader::markLoadComplete()
2504 setState(FrameStateComplete);
2507 void FrameLoader::commitProvisionalLoad(PassRefPtr<CachedPage> prpCachedPage)
2509 RefPtr<CachedPage> cachedPage = prpCachedPage;
2510 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2512 if (m_loadType != FrameLoadTypeReplace)
2513 closeOldDataSources();
2515 if (!cachedPage && !m_creatingInitialEmptyDocument)
2516 m_client->makeRepresentation(pdl.get());
2518 transitionToCommitted(cachedPage);
2520 // Call clientRedirectCancelledOrFinished() here so that the frame load delegate is notified that the redirect's
2521 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
2522 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are
2523 // just about to commit a new page, there cannot possibly be a pending redirect at this point.
2524 if (m_sentRedirectNotification)
2525 clientRedirectCancelledOrFinished(false);
2527 if (cachedPage && cachedPage->document()) {
2529 cachedPage->clear();
2531 KURL url = pdl->substituteData().responseURL();
2535 url = pdl->responseURL();
2537 url = "about:blank";
2544 void FrameLoader::transitionToCommitted(PassRefPtr<CachedPage> cachedPage)
2546 ASSERT(m_client->hasWebView());
2547 ASSERT(m_state == FrameStateProvisional);
2549 if (m_state != FrameStateProvisional)
2552 m_client->setCopiesOnScroll();
2553 updateHistoryForCommit();
2555 // The call to closeURL() invokes the unload event handler, which can execute arbitrary
2556 // JavaScript. If the script initiates a new load, we need to abandon the current load,
2557 // or the two will stomp each other.
2558 DocumentLoader* pdl = m_provisionalDocumentLoader.get();
2559 if (m_documentLoader)
2561 if (pdl != m_provisionalDocumentLoader)
2564 // Nothing else can interupt this commit - set the Provisional->Committed transition in stone
2565 if (m_documentLoader)
2566 m_documentLoader->stopLoadingSubresources();
2567 if (m_documentLoader)
2568 m_documentLoader->stopLoadingPlugIns();
2570 setDocumentLoader(m_provisionalDocumentLoader.get());
2571 setProvisionalDocumentLoader(0);
2572 setState(FrameStateCommittedPage);
2574 // Handle adding the URL to the back/forward list.
2575 DocumentLoader* dl = m_documentLoader.get();
2576 String ptitle = dl->title();
2578 switch (m_loadType) {
2579 case FrameLoadTypeForward:
2580 case FrameLoadTypeBack:
2581 case FrameLoadTypeIndexedBackForward:
2582 if (Page* page = m_frame->page())
2583 if (page->backForwardList()) {
2584 updateHistoryForBackForwardNavigation();
2586 // Create a document view for this document, or used the cached view.
2588 m_client->setDocumentViewFromCachedPage(cachedPage.get());
2590 m_client->makeDocumentView();
2594 case FrameLoadTypeReload:
2595 case FrameLoadTypeSame:
2596 case FrameLoadTypeReplace:
2597 updateHistoryForReload();
2598 m_client->makeDocumentView();
2601 // FIXME - just get rid of this case, and merge FrameLoadTypeReloadAllowingStaleData with the above case
2602 case FrameLoadTypeReloadAllowingStaleData:
2603 m_client->makeDocumentView();
2606 case FrameLoadTypeStandard:
2607 updateHistoryForStandardLoad();
2608 #ifndef BUILDING_ON_TIGER
2609 // This code was originally added for a Leopard performance imporvement. We decided to
2610 // ifdef it to fix correctness issues on Tiger documented in <rdar://problem/5441823>.
2611 if (m_frame->view())
2612 m_frame->view()->suppressScrollbars(true);
2614 m_client->makeDocumentView();
2617 case FrameLoadTypeRedirectWithLockedHistory:
2618 updateHistoryForRedirectWithLockedHistory();
2619 m_client->makeDocumentView();
2622 // FIXME Remove this check when dummy ds is removed (whatever "dummy ds" is).
2623 // An exception should be thrown if we're in the FrameLoadTypeUninitialized state.
2625 ASSERT_NOT_REACHED();
2628 m_responseMIMEType = dl->responseMIMEType();
2630 // Tell the client we've committed this URL.
2631 ASSERT(m_client->hasFrameView());
2633 if (m_creatingInitialEmptyDocument)
2636 m_committedFirstRealDocumentLoad = true;
2638 // For non-cached HTML pages, these methods are called in FrameLoader::begin.
2639 if (cachedPage || !m_client->hasHTMLView()) {
2640 dispatchDidCommitLoad();
2642 // If we have a title let the WebView know about it.
2643 if (!ptitle.isNull())
2644 m_client->dispatchDidReceiveTitle(ptitle);
2648 bool FrameLoader::privateBrowsingEnabled() const
2650 return m_client->privateBrowsingEnabled();
2653 void FrameLoader::clientRedirectCancelledOrFinished(bool cancelWithLoadInProgress)
2655 // Note that -webView:didCancelClientRedirectForFrame: is called on the frame load delegate even if
2656 // the redirect succeeded. We should either rename this API, or add a new method, like
2657 // -webView:didFinishClientRedirectForFrame:
2658 m_client->dispatchDidCancelClientRedirect();
2660 if (!cancelWithLoadInProgress)
2661 m_quickRedirectComing = false;
2663 m_sentRedirectNotification = false;
2666 void FrameLoader::clientRedirected(const KURL& URL, double seconds, double fireDate, bool lockHistory, bool isJavaScriptFormAction)
2668 m_client->dispatchWillPerformClientRedirect(URL, seconds, fireDate);
2670 // Remember that we sent a redirect notification to the frame load delegate so that when we commit
2671 // the next provisional load, we can send a corresponding -webView:didCancelClientRedirectForFrame:
2672 m_sentRedirectNotification = true;
2674 // If a "quick" redirect comes in an, we set a special mode so we treat the next
2675 // load as part of the same navigation. If we don't have a document loader, we have
2676 // no "original" load on which to base a redirect, so we treat the redirect as a normal load.
2677 m_quickRedirectComing = lockHistory && m_documentLoader && !isJavaScriptFormAction;
2680 bool FrameLoader::shouldReload(const KURL& currentURL, const KURL& destinationURL)
2682 // This function implements the rule: "Don't reload if navigating by fragment within
2683 // the same URL, but do reload if going to a new URL or to the same URL with no
2684 // fragment identifier at all."
2685 if (!currentURL.hasRef() && !destinationURL.hasRef())
2687 return !equalIgnoringRef(currentURL, destinationURL);
2690 void FrameLoader::closeOldDataSources()
2692 // FIXME: Is it important for this traversal to be postorder instead of preorder?
2693 // If so, add helpers for postorder traversal, and use them. If not, then lets not
2694 // use a recursive algorithm here.
2695 for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling())
2696 child->loader()->closeOldDataSources();
2698 if (m_documentLoader)
2699 m_client->dispatchWillClose();
2701 m_client->setMainFrameDocumentReady(false); // stop giving out the actual DOMDocument to observers
2704 void FrameLoader::open(CachedPage& cachedPage)
2706 ASSERT(m_frame->page());
2707 ASSERT(m_frame->page()->mainFrame() == m_frame);
2709 cancelRedirection();
2711 // We still have to close the previous part page.
2714 m_isComplete = false;
2716 // Don't re-emit the load event.
2717 m_didCallImplicitClose = true;
2719 // Delete old status bar messages (if it _was_ activated on last URL).
2720 Settings* settings = m_frame->settings();
2721 if (settings && settings->isJavaScriptEnabled()) {
2722 m_frame->setJSStatusBarText(String());
2723 m_frame->setJSDefaultStatusBarText(String());
2726 KURL URL = cachedPage.URL();
2728 if (URL.protocol().startsWith("http") && !URL.host().isEmpty() && URL.path().isEmpty())
2738 Document* document = cachedPage.document();
2740 document->setInPageCache(false);
2742 m_needsClear = true;
2743 m_isComplete = false;
2744 m_didCallImplicitClose = false;
2745 m_outgoingReferrer = URL.url();
2747 FrameView* view = cachedPage.view();
2749 view->setWasScrolledByUser(false);
2750 m_frame->setView(view);
2752 m_frame->setDocument(document);
2753 m_decoder = document->decoder();
2755 updatePolicyBaseURL();
2757 cachedPage.restore(m_frame->page());
2762 bool FrameLoader::isStopping() const
2764 return activeDocumentLoader()->isStopping();
2767 void FrameLoader::finishedLoading()
2769 // Retain because the stop may release the last reference to it.
2770 RefPtr<Frame> protect(m_frame);
2772 RefPtr<DocumentLoader> dl = activeDocumentLoader();
2773 dl->finishedLoading();
2774 if (!dl->mainDocumentError().isNull() || !dl->frameLoader())
2776 dl->setPrimaryLoadComplete(true);
2777 m_client->dispatchDidLoadMainResource(dl.get());
2778 checkLoadComplete();
2781 // FIXME: Which one of these URL methods is right?
2783 KURL FrameLoader::url() const
2788 KURL FrameLoader::URL() const
2790 return activeDocumentLoader()->URL();
2793 bool FrameLoader::isArchiveLoadPending(ResourceLoader* loader) const
2795 return m_client->isArchiveLoadPending(loader);
2798 bool FrameLoader::isHostedByObjectElement() const
2800 HTMLFrameOwnerElement* owner = m_frame->ownerElement();
2801 return owner && owner->hasTagName(objectTag);
2804 bool FrameLoader::isLoadingMainFrame() const
2806 Page* page = m_frame->page();
2807 return page && m_frame == page->mainFrame();
2810 bool FrameLoader::canShowMIMEType(const String& MIMEType) const
2812 return m_client->canShowMIMEType(MIMEType);
2815 bool FrameLoader::representationExistsForURLScheme(const String& URLScheme)
2817 return m_client->representationExistsForURLScheme(URLScheme);
2820 String FrameLoader::generatedMIMETypeForURLScheme(const String& URLScheme)
2822 return m_client->generatedMIMETypeForURLScheme(URLScheme);
2825 void FrameLoader::cancelContentPolicyCheck()
2827 m_client->cancelPolicyCheck();
2828 m_policyCheck.clear();
2831 void FrameLoader::didReceiveServerRedirectForProvisionalLoadForFrame()
2833 m_client->dispatchDidReceiveServerRedirectForProvisionalLoad();
2836 void FrameLoader::finishedLoadingDocument(DocumentLoader* loader)
2839 if (!m_creatingInitialEmptyDocument)
2841 m_client->finishedLoading(loader);
2844 bool FrameLoader::isReplacing() const
2846 return m_loadType == FrameLoadTypeReplace;
2849 void FrameLoader::setReplacing()
2851 m_loadType = FrameLoadTypeReplace;
2854 void FrameLoader::revertToProvisional(DocumentLoader* loader)
2856 m_client->revertToProvisionalState(loader);
2859 bool FrameLoader::subframeIsLoading() const
2861 // It's most likely that the last added frame is the last to load so we walk backwards.
2862 for (Frame* child = m_frame->tree()->lastChild(); child; child = child->tree()->previousSibling()) {
2863 FrameLoader* childLoader = child->loader();
2864 DocumentLoader* documentLoader = childLoader->documentLoader();
2865 if (documentLoader && documentLoader->isLoadingInAPISense())
2867 documentLoader = childLoader->provisionalDocumentLoader();
2868 if (documentLoader && documentLoader->isLoadingInAPISense())
2874 void FrameLoader::willChangeTitle(DocumentLoader* loader)
2876 m_client->willChangeTitle(loader);
2879 FrameLoadType FrameLoader::loadType() const
2884 void FrameLoader::stopPolicyCheck()
2886 m_client->cancelPolicyCheck();
2887 PolicyCheck check = m_policyCheck;
2888 m_policyCheck.clear();
2892 void FrameLoader::checkLoadCompleteForThisFrame()
2894 ASSERT(m_client->hasWebView());
2897 case FrameStateProvisional: {
2898 if (m_delegateIsHandlingProvisionalLoadError)
2901 RefPtr<DocumentLoader> pdl = m_provisionalDocumentLoader;
2905 // If we've received any errors we may be stuck in the provisional state and actually complete.
2906 const ResourceError& error = pdl->mainDocumentError();
2910 // Check all children first.
2911 RefPtr<HistoryItem> item;
2912 if (Page* page = m_frame->page())
2913 if (isBackForwardLoadType(loadType()) && m_frame == page->mainFrame())
2914 item = m_currentHistoryItem;
2916 bool shouldReset = true;
2917 if (!pdl->isLoadingInAPISense()) {
2918 m_delegateIsHandlingProvisionalLoadError = true;
2919 m_client->dispatchDidFailProvisionalLoad(error);
2920 m_delegateIsHandlingProvisionalLoadError = false;
2922 // FIXME: can stopping loading here possibly have any effect, if isLoading is false,
2923 // which it must be to be in this branch of the if? And is it OK to just do a full-on
2924 // stopAllLoaders instead of stopLoadingSubframes?
2925 stopLoadingSubframes();
2928 // Finish resetting the load state, but only if another load hasn't been started by the
2929 // delegate callback.
2930 if (pdl == m_provisionalDocumentLoader)
2931 clearProvisionalLoad();
2932 else if (m_provisionalDocumentLoader) {
2933 KURL unreachableURL = m_provisionalDocumentLoader->unreachableURL();
2934 if (!unreachableURL.isEmpty() && unreachableURL == pdl->request().url())
2935 shouldReset = false;
2938 if (shouldReset && item)
2939 if (Page* page = m_frame->page())
2940 page->backForwardList()->goToItem(item.get());
2944 case FrameStateCommittedPage: {
2945 DocumentLoader* dl = m_documentLoader.get();
2946 if (!dl || dl->isLoadingInAPISense())
2951 // FIXME: Is this subsequent work important if we already navigated away?
2952 // Maybe there are bugs because of that, or extra work we can skip because
2953 // the new page is ready.
2955 m_client->forceLayoutForNonHTML();
2957 // If the user had a scroll point, scroll to it, overriding the anchor point if any.
2958 if (Page* page = m_frame->page())
2959 if ((isBackForwardLoadType(m_loadType) || m_loadType == FrameLoadTypeReload) && page->backForwardList())
2960 restoreScrollPositionAndViewState();
2962 if (m_creatingInitialEmptyDocument || !m_committedFirstRealDocumentLoad)
2965 const ResourceError& error = dl->mainDocumentError();
2966 if (!error.isNull())
2967 m_client->dispatchDidFailLoad(error);
2969 m_client->dispatchDidFinishLoad();
2971 if (Page* page = m_frame->page())
2972 page->progress()->progressCompleted(m_frame);
2976 case FrameStateComplete:
2977 // Even if already complete, we might have set a previous item on a frame that
2978 // didn't do any data loading on the past transaction. Make sure to clear these out.
2979 m_client->frameLoadCompleted();
2983 ASSERT_NOT_REACHED();
2986 void FrameLoader::continueAfterContentPolicy(PolicyAction policy)
2988 PolicyCheck check = m_policyCheck;
2989 m_policyCheck.clear();
2993 void FrameLoader::continueLoadAfterWillSubmitForm(PolicyAction)
2995 if (!m_provisionalDocumentLoader)
2998 m_provisionalDocumentLoader->prepareForLoadStart();
3000 DocumentLoader* activeDocLoader = activeDocumentLoader();
3001 if (activeDocLoader && activeDocLoader->isLoadingMainResource())
3004 m_provisionalDocumentLoader->setLoadingFromCachedPage(false);
3006 unsigned long identifier = 0;
3008 if (Page* page = m_frame->page()) {
3009 identifier = page->progress()->createUniqueIdentifier();
3010 dispatchAssignIdentifierToInitialRequest(identifier, m_provisionalDocumentLoader.get(), m_provisionalDocumentLoader->originalRequest());
3013 if (!m_provisionalDocumentLoader->startLoadingMainResource(identifier))
3014 m_provisionalDocumentLoader->updateLoading();
3017 void FrameLoader::didFirstLayout()
3019 if (Page* page = m_frame->page())
3020 if (isBackForwardLoadType(m_loadType) && page->backForwardList())
3021 restoreScrollPositionAndViewState();
3023 m_firstLayoutDone = true;
3024 m_client->dispatchDidFirstLayout();
3027 void FrameLoader::frameLoadCompleted()
3029 m_client->frameLoadCompleted();
3031 // After a canceled provisional load, firstLayoutDone is false.
3032 // Reset it to true if we're displaying a page.
3033 if (m_documentLoader)
3034 m_firstLayoutDone = true;
3037 bool FrameLoader::firstLayoutDone() const
3039 return m_firstLayoutDone;
3042 bool FrameLoader::isQuickRedirectComing() const
3044 return m_quickRedirectComing;
3047 void FrameLoader::detachChildren()
3049 // FIXME: Is it really necessary to do this in reverse order?
3051 for (Frame* child = m_frame->tree()->lastChild(); child; child = previous) {
3052 previous = child->tree()->previousSibling();
3053 child->loader()->detachFromParent();
3057 void FrameLoader::recursiveCheckLoadComplete()
3059 Vector<RefPtr<Frame>, 10> frames;
3061 for (RefPtr<Frame> frame = m_frame->tree()->firstChild(); frame; frame = frame->tree()->nextSibling())
3062 frames.append(frame);
3064 unsigned size = frames.size();
3065 for (unsigned i = 0; i < size; i++)
3066 frames[i]->loader()->recursiveCheckLoadComplete();
3068 checkLoadCompleteForThisFrame();
3071 // Called every time a resource is completely loaded, or an error is received.
3072 void FrameLoader::checkLoadComplete()
3074 ASSERT(m_client->hasWebView());
3076 // FIXME: Always traversing the entire frame tree is a bit inefficient, but
3077 // is currently needed in order to null out the previous history item for all frames.
3078 if (Page* page = m_frame->page())
3079 page->mainFrame()->loader()->recursiveCheckLoadComplete();
3082 int FrameLoader::numPendingOrLoadingRequests(bool recurse) const
3085 return numRequests(m_frame->document());
3088 for (Frame* frame = m_frame; frame; frame = frame->tree()->traverseNext(m_frame))
3089 count += numRequests(frame->document());
3093 FrameLoaderClient* FrameLoader::client() const
3098 void FrameLoader::submitForm(const FrameLoadRequest& request, Event* event)
3100 // FIXME: We'd like to remove this altogether and fix the multiple form submission issue another way.
3101 // We do not want to submit more than one form from the same page,
3102 // nor do we want to submit a single form more than once.
3103 // This flag prevents these from happening; not sure how other browsers prevent this.
3104 // The flag is reset in each time we start handle a new mouse or key down event, and
3105 // also in setView since this part may get reused for a page from the back/forward cache.
3106 // The form multi-submit logic here is only needed when we are submitting a form that affects this frame.
3107 // FIXME: Frame targeting is only one of the ways the submission could end up doing something other
3108 // than replacing this frame's content, so this check is flawed. On the other hand, the check is hardly
3109 // needed any more now that we reset m_submittedFormURL on each mouse or key down event.
3110 Frame* target = m_frame->tree()->find(request.frameName());
3111 if (m_frame->tree()->isDescendantOf(target)) {
3112 if (m_submittedFormURL == request.resourceRequest().url())
3114 m_submittedFormURL = request.resourceRequest().url();
3117 // FIXME: We should probably call userGestureHint() to tell whether this form submission was the result of a user gesture.
3118 load(request, false, true, event, m_formAboutToBeSubmitted.get(), m_formValuesAboutToBeSubmitted);
3120 clearRecordedFormValues();
3123 void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory, bool userGesture)
3125 FrameLoadRequest copy = request;
3126 if (copy.resourceRequest().httpReferrer().isEmpty())
3127 copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer);
3129 load(copy, lockHistory, userGesture, event, 0, HashMap<String, String>());
3132 String FrameLoader::userAgent(const KURL& url) const
3134 return m_client->userAgent(url);
3137 void FrameLoader::tokenizerProcessedData()
3139 ASSERT(m_frame->page());
3140 ASSERT(m_frame->document());
3145 void FrameLoader::didTellBridgeAboutLoad(const String& URL)
3147 m_urlsBridgeKnowsAbout.add(URL);
3150 bool FrameLoader::haveToldBridgeAboutLoad(const String& URL)
3152 return m_urlsBridgeKnowsAbout.contains(URL);
3155 void FrameLoader::handledOnloadEvents()
3157 m_client->dispatchDidHandleOnloadEvents();
3160 void FrameLoader::frameDetached()
3166 void FrameLoader::detachFromParent()
3168 RefPtr<Frame> protect(m_frame);
3172 saveScrollPositionAndViewStateToItem(currentHistoryItem());
3175 if (Page* page = m_frame->page())
3176 page->inspectorController()->frameDetachedFromParent(m_frame);
3178 m_client->detachedFromParent2();
3179 setDocumentLoader(0);
3180 m_client->detachedFromParent3();
3181 if (Frame* parent = m_frame->tree()->parent()) {
3182 parent->tree()->removeChild(m_frame);
3183 parent->loader()->scheduleCheckCompleted();
3185 m_frame->setView(0);
3186 m_frame->pageDestroyed();
3189 [m_frame->bridge() close];
3191 m_client->detachedFromParent4();
3194 void FrameLoader::dispatchDidChangeLocationWithinPage()
3196 m_client->dispatchDidChangeLocationWithinPage();
3199 void FrameLoader::dispatchDidFinishLoadToClient()
3201 m_client->didFinishLoad();
3204 void FrameLoader::updateGlobalHistoryForStandardLoad(const KURL& url)
3206 m_client->updateGlobalHistoryForStandardLoad(url);
3209 void FrameLoader::updateGlobalHistoryForReload(const KURL& url)
3211 m_client->updateGlobalHistoryForReload(url);
3214 bool FrameLoader::shouldGoToHistoryItem(HistoryItem* item) const
3216 return m_client->shouldGoToHistoryItem(item);
3219 void FrameLoader::addExtraFieldsToRequest(ResourceRequest& request, bool mainResource, bool alwaysFromRequest)
3221 applyUserAgent(request);
3223 if (m_loadType == FrameLoadTypeReload) {
3224 request.setCachePolicy(ReloadIgnoringCacheData);
3225 request.setHTTPHeaderField("Cache-Control", "max-age=0");
3228 // Don't set the cookie policy URL if it's already been set.
3229 if (request.mainDocumentURL().isEmpty()) {
3230 if (mainResource && (isLoadingMainFrame() || alwaysFromRequest))
3231 request.setMainDocumentURL(request.url());
3232 else if (Page* page = m_frame->page())
3233 request.setMainDocumentURL(page->mainFrame()->loader()->url());
3237 request.setHTTPAccept("text/xml,application/xml,application/xhtml+xml,text/html;q=0.9,text/plain;q=0.8,image/png,*/*;q=0.5");
3240 void FrameLoader::committedLoad(DocumentLoader* loader, const char* data, int length)
3242 m_client->committedLoad(loader, data, length);
3245 void FrameLoader::post(const KURL& URL, const String& referrer, const String& frameName, PassRefPtr<FormData> formData,
3246 const String& contentType, Event* event, HTMLFormElement* form, const HashMap<String, String>& formValues)
3248 // When posting, use the NSURLRequestReloadIgnoringCacheData load flag.
3249 // This prevents a potential bug which may cause a page with a form that uses itself
3250 // as an action to be returned from the cache without submitting.
3252 // FIXME: Where's the code that implements what the comment above says?
3254 ResourceRequest request(URL);
3255 addExtraFieldsToRequest(request, true, true);
3257 if (!referrer.isEmpty())
3258 request.setHTTPReferrer(referrer);
3259 request.setHTTPMethod("POST");
3260 request.setHTTPBody(formData);
3261 request.setHTTPContentType(contentType);
3263 NavigationAction action(URL, FrameLoadTypeStandard, true, event);
3265 RefPtr<FormState> formState;
3266 if (form && !formValues.isEmpty())
3267 formState = FormState::create(form, formValues, m_frame);
3269 if (!frameName.isEmpty()) {
3270 if (Frame* targetFrame = m_frame->tree()->find(frameName))
3271 targetFrame->loader()->load(request, action, FrameLoadTypeStandard, formState.release());
3273 checkNewWindowPolicy(action, request, formState.release(), frameName);
3275 load(request, action, FrameLoadTypeStandard, formState.release());
3278 bool FrameLoader::isReloading() const
3280 return documentLoader()->request().cachePolicy() == ReloadIgnoringCacheData;
3283 void FrameLoader::loadEmptyDocumentSynchronously()
3285 ResourceRequest request(KURL(""));
3289 void FrameLoader::loadResourceSynchronously(const ResourceRequest& request, ResourceError& error, ResourceResponse& response, Vector<char>& data)
3291 // Since this is a subresource, we can load any URL (we ignore the return value).
3292 // But we still want to know whether we should hide the referrer or not, so we call the canLoad method.
3293 String referrer = m_outgoingReferrer;
3294 if (shouldHideReferrer(request.url(), referrer))
3295 referrer = String();
3297 ResourceRequest initialRequest = request;
3298 initialRequest.setTimeoutInterval(10);
3300 if (initialRequest.isConditional())
3301 initialRequest.setCachePolicy(ReloadIgnoringCacheData);
3303 initialRequest.setCachePolicy(documentLoader()->request().cachePolicy());
3305 if (!referrer.isEmpty())
3306 initialRequest.setHTTPReferrer(referrer);
3308 if (Page* page = m_frame->page())
3309 initialRequest.setMainDocumentURL(page->mainFrame()->loader()->documentLoader()->request().url());
3310 initialRequest.setHTTPUserAgent(client()->userAgent(request.url()));
3312 unsigned long identifier = 0;
3313 ResourceRequest newRequest(initialRequest);
3314 requestFromDelegate(newRequest, identifier, error);
3316 if (error.isNull()) {
3317 ASSERT(!newRequest.isNull());
3318 didTellBridgeAboutLoad(newRequest.url().url());
3319 ResourceHandle::loadResourceSynchronously(newRequest, error, response, data);
3322 sendRemainingDelegateMessages(identifier, response, data.size(), error);
3325 void FrameLoader::assignIdentifierToInitialRequest(unsigned long identifier, const ResourceRequest& clientRequest)
3327 return dispatchAssignIdentifierToInitialRequest(identifier, activeDocumentLoader(), clientRequest);
3330 void FrameLoader::willSendRequest(ResourceLoader* loader, ResourceRequest& clientRequest, const ResourceResponse& redirectResponse)
3332 applyUserAgent(clientRequest);
3333 dispatchWillSendRequest(loader->documentLoader(), loader->identifier(), clientRequest, redirectResponse);
3336 void FrameLoader::didReceiveResponse(ResourceLoader* loader, const ResourceResponse& r)
3338 activeDocumentLoader()->addResponse(r);
3340 if (Page* page = m_frame->page())
3341 page->progress()->incrementProgress(loader->identifier(), r);
3342 dispatchDidReceiveResponse(loader->documentLoader(), loader->identifier(), r);
3345 void FrameLoader::didReceiveData(ResourceLoader* loader, const char* data, int length, int lengthReceived)
3347 if (Page* page = m_frame->page())
3348 page->progress()->incrementProgress(loader->identifier(), data, length);
3349 dispatchDidReceiveContentLength(loader->documentLoader(), loader->identifier(), lengthReceived);
3352 void FrameLoader::didFailToLoad(ResourceLoader* loader, const ResourceError& error)
3354 if (Page* page = m_frame->page())
3355 page->progress()->completeProgress(loader->identifier());
3356 if (!error.isNull())
3357 m_client->dispatchDidFailLoading(loader->documentLoader(), loader->identifier(), error);
3360 const ResourceRequest& FrameLoader::originalRequest() const
3362 return activeDocumentLoader()->originalRequestCopy();
3365 void FrameLoader::receivedMainResourceError(const ResourceError& error, bool isComplete)
3367 // Retain because the stop may release the last reference to it.
3368 RefPtr<Frame> protect(m_frame);
3370 RefPtr<DocumentLoader> loader = activeDocumentLoader();
3373 // FIXME: Don't want to do this if an entirely new load is going, so should check
3374 // that both data sources on the frame are either this or nil.
3376 if (m_client->shouldFallBack(error))
3377 handleFallbackContent();
3380 if (m_state == FrameStateProvisional && m_provisionalDocumentLoader) {
3381 KURL failedURL = m_provisionalDocumentLoader->originalRequestCopy().url();
3382 didNotOpenURL(failedURL);
3384 // We might have made a page cache item, but now we're bailing out due to an error before we ever
3385 // transitioned to the new page (before WebFrameState == commit). The goal here is to restore any state
3386 // so that the existing view (that wenever got far enough to replace) can continue being used.
3387 invalidateCurrentItemCachedPage();
3389 // Call clientRedirectCancelledOrFinished here so that the frame load delegate is notified that the redirect's
3390 // status has changed, if there was a redirect. The frame load delegate may have saved some state about
3391 // the redirect in its -webView:willPerformClientRedirectToURL:delay:fireDate:forFrame:. Since we are definitely
3392 // not going to use this provisional resource, as it was cancelled, notify the frame load delegate that the redirect
3394 if (m_sentRedirectNotification)
3395 clientRedirectCancelledOrFinished(false);
3399 loader->mainReceivedError(error, isComplete);
3402 void FrameLoader::callContinueFragmentScrollAfterNavigationPolicy(void* argument,
3403 const ResourceRequest& request, PassRefPtr<FormState>, bool shouldContinue)
3405 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3406 loader->continueFragmentScrollAfterNavigationPolicy(request, shouldContinue);
3409 void FrameLoader::continueFragmentScrollAfterNavigationPolicy(const ResourceRequest& request, bool shouldContinue)
3412 // some functions check m_quickRedirectComing, and others check for
3413 // FrameLoadTypeRedirectWithLockedHistory.
3414 bool isRedirect = m_quickRedirectComing || m_policyLoadType == FrameLoadTypeRedirectWithLockedHistory;
3415 m_quickRedirectComing = false;
3417 if (!shouldContinue)
3420 KURL URL = request.url();
3422 m_documentLoader->replaceRequestURLForAnchorScroll(URL);
3423 if (!isRedirect && !shouldTreatURLAsSameAsCurrent(URL)) {
3424 // NB: must happen after _setURL, since we add based on the current request.
3425 // Must also happen before we openURL and displace the scroll position, since
3426 // adding the BF item will save away scroll state.
3428 // NB2: If we were loading a long, slow doc, and the user anchor nav'ed before
3429 // it was done, currItem is now set the that slow doc, and prevItem is whatever was
3430 // before it. Adding the b/f item will bump the slow doc down to prevItem, even
3431 // though its load is not yet done. I think this all works out OK, for one because
3432 // we have already saved away the scroll and doc state for the long slow load,
3433 // but it's not an obvious case.
3435 addHistoryItemForFragmentScroll();
3438 scrollToAnchor(URL);
3441 // This will clear previousItem from the rest of the frame tree that didn't
3442 // doing any loading. We need to make a pass on this now, since for anchor nav
3443 // we'll not go through a real load and reach Completed state.
3444 checkLoadComplete();
3446 dispatchDidChangeLocationWithinPage();
3447 m_client->didFinishLoad();
3450 void FrameLoader::opened()
3452 if (m_loadType == FrameLoadTypeStandard && m_documentLoader->isClientRedirect())
3453 updateHistoryForClientRedirect();
3455 if (m_documentLoader->isLoadingFromCachedPage()) {
3456 m_frame->document()->didRestoreFromCache();
3458 // Force a layout to update view size and thereby update scrollbars.
3459 m_client->forceLayout();
3461 const ResponseVector& responses = m_documentLoader->responses();
3462 size_t count = responses.size();
3463 for (size_t i = 0; i < count; i++) {
3464 const ResourceResponse& response = responses[i];
3465 // FIXME: If the WebKit client changes or cancels the request, this is not respected.
3466 ResourceError error;
3467 unsigned long identifier;
3468 ResourceRequest request(response.url());
3469 requestFromDelegate(request, identifier, error);
3470 // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
3471 // However, with today's computers and networking speeds, this won't happen in practice.
3472 // Could be an issue with a giant local file.
3473 sendRemainingDelegateMessages(identifier, response, static_cast<int>(response.expectedContentLength()), error);
3476 pageCache()->remove(m_currentHistoryItem.get());
3478 m_documentLoader->setPrimaryLoadComplete(true);
3480 // FIXME: Why only this frame and not parent frames?
3481 checkLoadCompleteForThisFrame();
3485 void FrameLoader::checkNewWindowPolicy(const NavigationAction& action, const ResourceRequest& request,
3486 PassRefPtr<FormState> formState, const String& frameName)
3488 m_policyCheck.set(request, formState, frameName,
3489 callContinueLoadAfterNewWindowPolicy, this);
3490 m_client->dispatchDecidePolicyForNewWindowAction(&FrameLoader::continueAfterNewWindowPolicy,
3491 action, request, frameName);
3494 void FrameLoader::continueAfterNewWindowPolicy(PolicyAction policy)
3496 PolicyCheck check = m_policyCheck;
3497 m_policyCheck.clear();
3501 check.clearRequest();
3503 case PolicyDownload:
3504 m_client->startDownload(check.request());
3505 check.clearRequest();
3511 check.call(policy == PolicyUse);
3514 void FrameLoader::checkNavigationPolicy(const ResourceRequest& request, DocumentLoader* loader,
3515 PassRefPtr<FormState> formState, NavigationPolicyDecisionFunction function, void* argument)
3517 NavigationAction action = loader->triggeringAction();
3518 if (action.isEmpty()) {
3519 action = NavigationAction(request.url(), NavigationTypeOther);
3520 loader->setTriggeringAction(action);
3523 // Don't ask more than once for the same request or if we are loading an empty URL.
3524 // This avoids confusion on the part of the client.
3525 if (equalIgnoringHeaderFields(request, loader->lastCheckedRequest()) || (!request.isNull() && request.url().isEmpty())) {
3526 function(argument, request, 0, true);
3527 loader->setLastCheckedRequest(request);
3531 // We are always willing to show alternate content for unreachable URLs;
3532 // treat it like a reload so it maintains the right state for b/f list.
3533 if (loader->substituteData().isValid() && !loader->substituteData().failingURL().isEmpty()) {
3534 if (isBackForwardLoadType(m_policyLoadType))
3535 m_policyLoadType = FrameLoadTypeReload;
3536 function(argument, request, 0, true);
3540 loader->setLastCheckedRequest(request);
3542 m_policyCheck.set(request, formState, function, argument);
3544 m_delegateIsDecidingNavigationPolicy = true;
3545 m_client->dispatchDecidePolicyForNavigationAction(&FrameLoader::continueAfterNavigationPolicy,
3547 m_delegateIsDecidingNavigationPolicy = false;
3550 void FrameLoader::continueAfterNavigationPolicy(PolicyAction policy)
3552 PolicyCheck check = m_policyCheck;
3553 m_policyCheck.clear();
3555 bool shouldContinue = policy == PolicyUse;
3559 check.clearRequest();
3561 case PolicyDownload:
3562 m_client->startDownload(check.request());
3563 check.clearRequest();
3566 ResourceRequest request(check.request());
3568 if (!m_client->canHandleRequest(request)) {
3569 handleUnimplementablePolicy(m_client->cannotShowURLError(check.request()));
3570 check.clearRequest();
3571 shouldContinue = false;
3577 check.call(shouldContinue);
3580 void FrameLoader::callContinueLoadAfterNavigationPolicy(void* argument,
3581 const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3583 FrameLoader* loader = static_cast<FrameLoader*>(argument);
3584 loader->continueLoadAfterNavigationPolicy(request, formState, shouldContinue);
3587 void FrameLoader::continueLoadAfterNavigationPolicy(const ResourceRequest& request, PassRefPtr<FormState> formState, bool shouldContinue)
3589 // If we loaded an alternate page to replace an unreachableURL, we'll get in here with a
3590 // nil policyDataSource because loading the alternate page will have passed
3591 // through this method already, nested; otherwise, policyDataSource should still be set.
3592 ASSERT(m_policyDocumentLoader || !m_provisionalDocumentLoader->unreachableURL().isEmpty());
3594 bool isTargetItem = m_provisionalHistoryItem ? m_provisionalHistoryItem->isTargetItem() : false;
3596 // Two reasons we can't continue:
3597 // 1) Navigation policy delegate said we can't so request is nil. A primary case of this
3598 // is the user responding Cancel to the form repost nag sheet.
3599 // 2) User responded Cancel to an alert popped up by the before unload event handler.
3600 // The "before unload" event handler runs only for the main frame.
3601 bool canContinue = shouldContinue && (!isLoadingMainFrame() || m_frame->shouldClose());
3604 // If we were waiting for a quick redirect, but the policy delegate decided to ignore it, then we
3605 // need to report that the client redirect was cancelled.
3606 if (m_quickRedirectComing)
3607 clientRedirectCancelledOrFinished(false);
3609 setPolicyDocumentLoader(0);
3611 // If the navigation request came from the back/forward menu, and we punt on it, we have the
3612 // problem that we have optimistically moved the b/f cursor already, so move it back. For sanity,
3613 // we only do this when punting a navigation for the target frame or top-level frame.
3614 if ((isTargetItem || isLoadingMainFrame()) && isBackForwardLoadType(m_policyLoadType))