From 648161bb0edfc3d43db63caed5cc5213bc6cb78f Mon Sep 17 00:00:00 2001 From: The Android Open Source Project Date: Tue, 3 Mar 2009 18:28:41 -0800 Subject: auto import from //depot/cupcake/@135843 --- WebCore/loader/FrameLoader.cpp | 5283 ---------------------------------------- 1 file changed, 5283 deletions(-) delete mode 100644 WebCore/loader/FrameLoader.cpp (limited to 'WebCore/loader/FrameLoader.cpp') diff --git a/WebCore/loader/FrameLoader.cpp b/WebCore/loader/FrameLoader.cpp deleted file mode 100644 index 0285a8c..0000000 --- a/WebCore/loader/FrameLoader.cpp +++ /dev/null @@ -1,5283 +0,0 @@ -/* - * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. - * Copyright (C) 2008 Nokia Corporation and/or its subsidiary(-ies) - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of - * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY - * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF - * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "config.h" -#include "FrameLoader.h" - -#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size -#include "Archive.h" -#include "ArchiveFactory.h" -#endif -#include "CString.h" -#include "Cache.h" -#include "CachedPage.h" -#include "Chrome.h" -#include "DOMImplementation.h" -#include "DOMWindow.h" -#include "DocLoader.h" -#include "Document.h" -#include "DocumentLoader.h" -#include "Editor.h" -#include "EditorClient.h" -#include "Element.h" -#include "Event.h" -#include "EventNames.h" -#include "FloatRect.h" -#include "FormState.h" -#include "Frame.h" -#include "FrameLoadRequest.h" -#include "FrameLoaderClient.h" -#include "FramePrivate.h" -#include "FrameTree.h" -#include "FrameView.h" -#include "HTMLFormElement.h" -#include "HTMLFrameElement.h" -#include "HTMLNames.h" -#include "HTMLObjectElement.h" -#include "HTTPParsers.h" -#include "HistoryItem.h" -#include "IconDatabase.h" -#include "IconLoader.h" -#include "InspectorController.h" -#include "Logging.h" -#include "MIMETypeRegistry.h" -#include "MainResourceLoader.h" -#include "Page.h" -#include "PageCache.h" -#include "PageGroup.h" -#include "PluginData.h" -#include "ProgressTracker.h" -#include "RenderPart.h" -#include "RenderWidget.h" -#include "RenderView.h" -#include "ResourceHandle.h" -#include "ResourceRequest.h" -#include "SecurityOrigin.h" -#include "SegmentedString.h" -#include "Settings.h" -#include "SystemTime.h" -#include "TextResourceDecoder.h" -#include "WindowFeatures.h" -#include "XMLHttpRequest.h" -#include "XMLTokenizer.h" -#include "JSDOMBinding.h" -#include "ScriptController.h" -#include -#include - -#if ENABLE(OFFLINE_WEB_APPLICATIONS) -#include "ApplicationCache.h" -#include "ApplicationCacheResource.h" -#endif - -#if ENABLE(SVG) -#include "SVGDocument.h" -#include "SVGLocatable.h" -#include "SVGNames.h" -#include "SVGPreserveAspectRatio.h" -#include "SVGSVGElement.h" -#include "SVGViewElement.h" -#include "SVGViewSpec.h" -#endif - -#ifdef ANDROID_INSTRUMENT -#include "TimeCounter.h" -#endif - -using namespace JSC; - -namespace WebCore { - -#if ENABLE(SVG) -using namespace SVGNames; -#endif -using namespace HTMLNames; - -#if USE(LOW_BANDWIDTH_DISPLAY) -const unsigned int cMaxPendingSourceLengthInLowBandwidthDisplay = 128 * 1024; -#endif - -struct FormSubmission { - const char* action; - String url; - RefPtr data; - String target; - String contentType; - String boundary; - RefPtr event; - - FormSubmission(const char* a, const String& u, PassRefPtr d, const String& t, - const String& ct, const String& b, PassRefPtr e) - : action(a) - , url(u) - , data(d) - , target(t) - , contentType(ct) - , boundary(b) - , event(e) - { - } -}; - -struct ScheduledRedirection { - enum Type { redirection, locationChange, historyNavigation, locationChangeDuringLoad }; - Type type; - double delay; - String url; - String referrer; - int historySteps; - bool lockHistory; - bool wasUserGesture; - - ScheduledRedirection(double redirectDelay, const String& redirectURL, bool redirectLockHistory, bool userGesture) - : type(redirection) - , delay(redirectDelay) - , url(redirectURL) - , historySteps(0) - , lockHistory(redirectLockHistory) - , wasUserGesture(userGesture) - { - } - - ScheduledRedirection(Type locationChangeType, - const String& locationChangeURL, const String& locationChangeReferrer, - bool locationChangeLockHistory, bool locationChangeWasUserGesture) - : type(locationChangeType) - , delay(0) - , url(locationChangeURL) - , referrer(locationChangeReferrer) - , historySteps(0) - , lockHistory(locationChangeLockHistory) - , wasUserGesture(locationChangeWasUserGesture) - { - } - - explicit ScheduledRedirection(int historyNavigationSteps) - : type(historyNavigation) - , delay(0) - , historySteps(historyNavigationSteps) - , lockHistory(false) - , wasUserGesture(false) - { - } -}; - -static double storedTimeOfLastCompletedLoad; -static FrameLoader::LocalLoadPolicy localLoadPolicy = FrameLoader::AllowLocalLoadsForLocalOnly; - -static bool getString(JSValue* result, String& string) -{ - if (!result) - return false; - JSLock lock(false); - UString ustring; - if (!result->getString(ustring)) - return false; - string = ustring; - return true; -} - -bool isBackForwardLoadType(FrameLoadType type) -{ - switch (type) { - case FrameLoadTypeStandard: - case FrameLoadTypeReload: - case FrameLoadTypeReloadAllowingStaleData: - case FrameLoadTypeSame: - case FrameLoadTypeRedirectWithLockedHistory: - case FrameLoadTypeReplace: - return false; - case FrameLoadTypeBack: - case FrameLoadTypeForward: - case FrameLoadTypeIndexedBackForward: - return true; - } - ASSERT_NOT_REACHED(); - return false; -} - -static int numRequests(Document* document) -{ - if (!document) - return 0; - - return document->docLoader()->requestCount(); -} - -FrameLoader::FrameLoader(Frame* frame, FrameLoaderClient* client) - : m_frame(frame) - , m_client(client) - , m_state(FrameStateCommittedPage) - , m_loadType(FrameLoadTypeStandard) - , m_policyLoadType(FrameLoadTypeStandard) - , m_delegateIsHandlingProvisionalLoadError(false) - , m_delegateIsDecidingNavigationPolicy(false) - , m_delegateIsHandlingUnimplementablePolicy(false) - , m_firstLayoutDone(false) - , m_quickRedirectComing(false) - , m_sentRedirectNotification(false) - , m_inStopAllLoaders(false) - , m_navigationDuringLoad(false) - , m_cachePolicy(CachePolicyVerify) - , m_isExecutingJavaScriptFormAction(false) - , m_isRunningScript(false) - , m_didCallImplicitClose(false) - , m_wasUnloadEventEmitted(false) - , m_isComplete(false) - , m_isLoadingMainResource(false) - , m_cancellingWithLoadInProgress(false) - , m_needsClear(false) - , m_receivedData(false) - , m_encodingWasChosenByUser(false) - , m_containsPlugIns(false) - , m_redirectionTimer(this, &FrameLoader::redirectionTimerFired) - , m_checkCompletedTimer(this, &FrameLoader::checkCompletedTimerFired) - , m_checkLoadCompleteTimer(this, &FrameLoader::checkLoadCompleteTimerFired) - , m_opener(0) - , m_openedByDOM(false) - , m_creatingInitialEmptyDocument(false) - , m_isDisplayingInitialEmptyDocument(false) - , m_committedFirstRealDocumentLoad(false) - , m_didPerformFirstNavigation(false) -#ifndef NDEBUG - , m_didDispatchDidCommitLoad(false) -#endif -#if USE(LOW_BANDWIDTH_DISPLAY) - , m_useLowBandwidthDisplay(true) - , m_finishedParsingDuringLowBandwidthDisplay(false) - , m_needToSwitchOutLowBandwidthDisplay(false) -#endif -{ -} - -FrameLoader::~FrameLoader() -{ - setOpener(0); - - HashSet::iterator end = m_openedFrames.end(); - for (HashSet::iterator it = m_openedFrames.begin(); it != end; ++it) - (*it)->loader()->m_opener = 0; - - m_client->frameLoaderDestroyed(); -} - -void FrameLoader::init() -{ - // this somewhat odd set of steps is needed to give the frame an initial empty document - m_isDisplayingInitialEmptyDocument = false; - m_creatingInitialEmptyDocument = true; - setPolicyDocumentLoader(m_client->createDocumentLoader(ResourceRequest(String("")), SubstituteData()).get()); - setProvisionalDocumentLoader(m_policyDocumentLoader.get()); - setState(FrameStateProvisional); - m_provisionalDocumentLoader->setResponse(ResourceResponse(KURL(), "text/html", 0, String(), String())); - m_provisionalDocumentLoader->finishedLoading(); - begin(KURL(), false); - end(); - m_frame->document()->cancelParsing(); - m_creatingInitialEmptyDocument = false; - m_didCallImplicitClose = true; -} - -void FrameLoader::setDefersLoading(bool defers) -{ - if (m_documentLoader) - m_documentLoader->setDefersLoading(defers); - if (m_provisionalDocumentLoader) - m_provisionalDocumentLoader->setDefersLoading(defers); - if (m_policyDocumentLoader) - m_policyDocumentLoader->setDefersLoading(defers); -} - -Frame* FrameLoader::createWindow(FrameLoader* frameLoaderForFrameLookup, const FrameLoadRequest& request, const WindowFeatures& features, bool& created) -{ - ASSERT(!features.dialog || request.frameName().isEmpty()); - - if (!request.frameName().isEmpty() && request.frameName() != "_blank") { - Frame* frame = frameLoaderForFrameLookup->frame()->tree()->find(request.frameName()); - if (frame && shouldAllowNavigation(frame)) { - if (!request.resourceRequest().url().isEmpty()) - frame->loader()->loadFrameRequestWithFormAndValues(request, false, 0, 0, HashMap()); - if (Page* page = frame->page()) - page->chrome()->focus(); - created = false; - return frame; - } - } - - // FIXME: Setting the referrer should be the caller's responsibility. - FrameLoadRequest requestWithReferrer = request; - requestWithReferrer.resourceRequest().setHTTPReferrer(m_outgoingReferrer); - addHTTPOriginIfNeeded(requestWithReferrer.resourceRequest(), outgoingOrigin()); - - Page* oldPage = m_frame->page(); - if (!oldPage) - return 0; - - Page* page = oldPage->chrome()->createWindow(m_frame, requestWithReferrer, features); - if (!page) - return 0; - - Frame* frame = page->mainFrame(); - if (request.frameName() != "_blank") - frame->tree()->setName(request.frameName()); - - page->chrome()->setToolbarsVisible(features.toolBarVisible || features.locationBarVisible); - page->chrome()->setStatusbarVisible(features.statusBarVisible); - page->chrome()->setScrollbarsVisible(features.scrollbarsVisible); - page->chrome()->setMenubarVisible(features.menuBarVisible); - page->chrome()->setResizable(features.resizable); - - // 'x' and 'y' specify the location of the window, while 'width' and 'height' - // specify the size of the page. We can only resize the window, so - // adjust for the difference between the window size and the page size. - - FloatRect windowRect = page->chrome()->windowRect(); - FloatSize pageSize = page->chrome()->pageRect().size(); - if (features.xSet) - windowRect.setX(features.x); - if (features.ySet) - windowRect.setY(features.y); - if (features.widthSet) - windowRect.setWidth(features.width + (windowRect.width() - pageSize.width())); - if (features.heightSet) - windowRect.setHeight(features.height + (windowRect.height() - pageSize.height())); - page->chrome()->setWindowRect(windowRect); - - page->chrome()->show(); - - created = true; - return frame; -} - -bool FrameLoader::canHandleRequest(const ResourceRequest& request) -{ - return m_client->canHandleRequest(request); -} - -void FrameLoader::changeLocation(const String& url, const String& referrer, bool lockHistory, bool userGesture) -{ - changeLocation(completeURL(url), referrer, lockHistory, userGesture); -} - - -void FrameLoader::changeLocation(const KURL& url, const String& referrer, bool lockHistory, bool userGesture) -{ - RefPtr protect(m_frame); - - ResourceRequestCachePolicy policy = (m_cachePolicy == CachePolicyReload) || (m_cachePolicy == CachePolicyRefresh) - ? ReloadIgnoringCacheData : UseProtocolCachePolicy; - ResourceRequest request(url, referrer, policy); -#ifdef ANDROID_USER_GESTURE - request.setUserGesture(userGesture); -#endif - - if (executeIfJavaScriptURL(request.url(), userGesture)) - return; - - urlSelected(request, "_self", 0, lockHistory, userGesture); -} - -void FrameLoader::urlSelected(const FrameLoadRequest& request, Event* event, bool lockHistory) -{ - FrameLoadRequest copy = request; - if (copy.resourceRequest().httpReferrer().isEmpty()) - copy.resourceRequest().setHTTPReferrer(m_outgoingReferrer); - addHTTPOriginIfNeeded(copy.resourceRequest(), outgoingOrigin()); - - loadFrameRequestWithFormAndValues(copy, lockHistory, event, 0, HashMap()); -} - -void FrameLoader::urlSelected(const ResourceRequest& request, const String& _target, Event* triggeringEvent, bool lockHistory, bool userGesture) -{ - if (executeIfJavaScriptURL(request.url(), userGesture, false)) - return; - - String target = _target; - if (target.isEmpty() && m_frame->document()) - target = m_frame->document()->baseTarget(); - - FrameLoadRequest frameRequest(request, target); -#ifdef ANDROID_USER_GESTURE - frameRequest.setWasUserGesture(userGesture); -#endif - - urlSelected(frameRequest, triggeringEvent, lockHistory); -} - -bool FrameLoader::requestFrame(HTMLFrameOwnerElement* ownerElement, const String& urlString, const AtomicString& frameName) -{ -#if USE(LOW_BANDWIDTH_DISPLAY) - // don't create sub-frame during low bandwidth display - if (frame()->document()->inLowBandwidthDisplay()) { - m_needToSwitchOutLowBandwidthDisplay = true; - return false; - } -#endif - - // Support for - KURL scriptURL; - KURL url; - if (protocolIs(urlString, "javascript")) { - scriptURL = KURL(urlString); - url = blankURL(); - } else - url = completeURL(urlString); - - Frame* frame = ownerElement->contentFrame(); - if (frame) - frame->loader()->scheduleLocationChange(url.string(), m_outgoingReferrer, true, userGestureHint()); - else - frame = loadSubframe(ownerElement, url, frameName, m_outgoingReferrer); - - if (!frame) - return false; - - if (!scriptURL.isEmpty()) - frame->loader()->executeIfJavaScriptURL(scriptURL); - - return true; -} - -Frame* FrameLoader::loadSubframe(HTMLFrameOwnerElement* ownerElement, const KURL& url, const String& name, const String& referrer) -{ - bool allowsScrolling = true; - int marginWidth = -1; - int marginHeight = -1; - if (ownerElement->hasTagName(frameTag) || ownerElement->hasTagName(iframeTag)) { - HTMLFrameElementBase* o = static_cast(ownerElement); - allowsScrolling = o->scrollingMode() != ScrollbarAlwaysOff; - marginWidth = o->getMarginWidth(); - marginHeight = o->getMarginHeight(); - } - - if (!canLoad(url, referrer)) { - FrameLoader::reportLocalLoadFailed(m_frame, url.string()); - return 0; - } - - bool hideReferrer = shouldHideReferrer(url, referrer); - RefPtr frame = m_client->createFrame(url, name, ownerElement, hideReferrer ? String() : referrer, - allowsScrolling, marginWidth, marginHeight); - - if (!frame) { - checkCallImplicitClose(); - return 0; - } - - frame->loader()->m_isComplete = false; - - RenderObject* renderer = ownerElement->renderer(); - FrameView* view = frame->view(); - if (renderer && renderer->isWidget() && view) - static_cast(renderer)->setWidget(view); - - checkCallImplicitClose(); - - // In these cases, the synchronous load would have finished - // before we could connect the signals, so make sure to send the - // completed() signal for the child by hand - // FIXME: In this case the Frame will have finished loading before - // it's being added to the child list. It would be a good idea to - // create the child first, then invoke the loader separately. - if (url.isEmpty() || url == blankURL()) { - frame->loader()->completed(); - frame->loader()->checkCompleted(); - } - - return frame.get(); -} - -void FrameLoader::submitFormAgain() -{ - if (m_isRunningScript) - return; - OwnPtr form(m_deferredFormSubmission.release()); - if (form) - submitForm(form->action, form->url, form->data, form->target, - form->contentType, form->boundary, form->event.get()); -} - -void FrameLoader::submitForm(const char* action, const String& url, PassRefPtr formData, - const String& target, const String& contentType, const String& boundary, Event* event) -{ - ASSERT(formData); - - if (!m_frame->page()) - return; - - KURL u = completeURL(url.isNull() ? "" : url); - // FIXME: Do we really need to special-case an empty URL? - // Would it be better to just go on with the form submisson and let the I/O fail? - if (u.isEmpty()) - return; - - if (u.protocolIs("javascript")) { - m_isExecutingJavaScriptFormAction = true; - executeIfJavaScriptURL(u, false, false); - m_isExecutingJavaScriptFormAction = false; - return; - } - - if (m_isRunningScript) { - if (m_deferredFormSubmission) - return; - m_deferredFormSubmission.set(new FormSubmission(action, url, formData, target, - contentType, boundary, event)); - return; - } - - formData->generateFiles(m_frame->page()->chrome()->client()); - - FrameLoadRequest frameRequest; -#ifdef ANDROID_USER_GESTURE - frameRequest.setWasUserGesture(userGestureHint()); -#endif - - if (!m_outgoingReferrer.isEmpty()) - frameRequest.resourceRequest().setHTTPReferrer(m_outgoingReferrer); - - frameRequest.setFrameName(target.isEmpty() ? m_frame->document()->baseTarget() : target); - - // Handle mailto: forms - bool isMailtoForm = equalIgnoringCase(u.protocol(), "mailto"); - if (isMailtoForm && strcmp(action, "GET") != 0) { - // Append body= for POST mailto, replace the whole query string for GET one. - String body = formData->flattenToString(); - String query = u.query(); - if (!query.isEmpty()) - query.append('&'); - u.setQuery(query + body); - } - - if (strcmp(action, "GET") == 0) { - u.setQuery(formData->flattenToString()); - } else { - if (!isMailtoForm) - frameRequest.resourceRequest().setHTTPBody(formData.get()); - frameRequest.resourceRequest().setHTTPMethod("POST"); - - // construct some user headers if necessary - if (contentType.isNull() || contentType == "application/x-www-form-urlencoded") - frameRequest.resourceRequest().setHTTPContentType(contentType); - else // contentType must be "multipart/form-data" - frameRequest.resourceRequest().setHTTPContentType(contentType + "; boundary=" + boundary); - } - - frameRequest.resourceRequest().setURL(u); - addHTTPOriginIfNeeded(frameRequest.resourceRequest(), outgoingOrigin()); - - submitForm(frameRequest, event); -} - -void FrameLoader::stopLoading(bool sendUnload) -{ - if (m_frame->document() && m_frame->document()->tokenizer()) - m_frame->document()->tokenizer()->stopParsing(); - - if (sendUnload) { - if (m_frame->document()) { - if (m_didCallImplicitClose && !m_wasUnloadEventEmitted) { - Node* currentFocusedNode = m_frame->document()->focusedNode(); - if (currentFocusedNode) - currentFocusedNode->aboutToUnload(); - m_frame->document()->dispatchWindowEvent(eventNames().unloadEvent, false, false); - if (m_frame->document()) - m_frame->document()->updateRendering(); - m_wasUnloadEventEmitted = true; - if (m_frame->eventHandler()->pendingFrameUnloadEventCount()) - m_frame->eventHandler()->clearPendingFrameUnloadEventCount(); - if (m_frame->eventHandler()->pendingFrameBeforeUnloadEventCount()) - m_frame->eventHandler()->clearPendingFrameBeforeUnloadEventCount(); - } - } - if (m_frame->document() && !m_frame->document()->inPageCache()) - m_frame->document()->removeAllEventListenersFromAllNodes(); - } - - m_isComplete = true; // to avoid calling completed() in finishedParsing() (David) - m_isLoadingMainResource = false; - m_didCallImplicitClose = true; // don't want that one either - m_cachePolicy = CachePolicyVerify; // Why here? - - if (m_frame->document() && m_frame->document()->parsing()) { - finishedParsing(); - m_frame->document()->setParsing(false); - } - - m_workingURL = KURL(); - - if (Document* doc = m_frame->document()) { - if (DocLoader* docLoader = doc->docLoader()) - cache()->loader()->cancelRequests(docLoader); - - doc->stopActiveDOMObjects(); - -#if ENABLE(DATABASE) - doc->stopDatabases(); -#endif - } - - // tell all subframes to stop as well - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->stopLoading(sendUnload); - - cancelRedirection(); - -#if USE(LOW_BANDWIDTH_DISPLAY) - if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay()) { - // Since loading is forced to stop, reset the state without really switching. - m_needToSwitchOutLowBandwidthDisplay = false; - switchOutLowBandwidthDisplayIfReady(); - } -#endif -} - -void FrameLoader::stop() -{ - // http://bugs.webkit.org/show_bug.cgi?id=10854 - // The frame's last ref may be removed and it will be deleted by checkCompleted(). - RefPtr protector(m_frame); - - if (m_frame->document()) { - if (m_frame->document()->tokenizer()) - m_frame->document()->tokenizer()->stopParsing(); - m_frame->document()->finishParsing(); - } else - // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but - // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to - // become true. An example is when a subframe is a pure text doc, and that subframe is the - // last one to complete. - checkCompleted(); - if (m_iconLoader) - m_iconLoader->stopLoading(); -} - -bool FrameLoader::closeURL() -{ - saveDocumentState(); - stopLoading(true); - m_frame->editor()->clearUndoRedoOperations(); - return true; -} - -void FrameLoader::cancelRedirection(bool cancelWithLoadInProgress) -{ - m_cancellingWithLoadInProgress = cancelWithLoadInProgress; - - stopRedirectionTimer(); - - m_scheduledRedirection.clear(); -} - -KURL FrameLoader::iconURL() -{ - // If this isn't a top level frame, return nothing - if (m_frame->tree() && m_frame->tree()->parent()) - return KURL(); - - // If we have an iconURL from a Link element, return that - if (m_frame->document() && !m_frame->document()->iconURL().isEmpty()) - return KURL(m_frame->document()->iconURL()); - - // Don't return a favicon iconURL unless we're http or https - if (!m_URL.protocolIs("http") && !m_URL.protocolIs("https")) - return KURL(); - - KURL url; - url.setProtocol(m_URL.protocol()); - url.setHost(m_URL.host()); - if (int port = m_URL.port()) - url.setPort(port); - url.setPath("/favicon.ico"); - return url; -} - -bool FrameLoader::didOpenURL(const KURL& url) -{ - if (m_scheduledRedirection && m_scheduledRedirection->type == ScheduledRedirection::locationChangeDuringLoad) - // A redirect was scheduled before the document was created. - // This can happen when one frame changes another frame's location. - return false; - - cancelRedirection(); - m_frame->editor()->clearLastEditCommand(); - closeURL(); - - m_isComplete = false; - m_isLoadingMainResource = true; - m_didCallImplicitClose = false; - - m_frame->setJSStatusBarText(String()); - m_frame->setJSDefaultStatusBarText(String()); - - m_URL = url; - if ((m_URL.protocolIs("http") || m_URL.protocolIs("https")) && !m_URL.host().isEmpty() && m_URL.path().isEmpty()) - m_URL.setPath("/"); - m_workingURL = m_URL; - - started(); - - return true; -} - -void FrameLoader::didExplicitOpen() -{ - m_isComplete = false; - m_didCallImplicitClose = false; - - // Calling document.open counts as committing the first real document load. - m_committedFirstRealDocumentLoad = true; - - // Prevent window.open(url) -- eg window.open("about:blank") -- from blowing away results - // from a subsequent window.document.open / window.document.write call. - // Cancelling redirection here works for all cases because document.open - // implicitly precedes document.write. - cancelRedirection(); - if (m_frame->document()->url() != blankURL()) - m_URL = m_frame->document()->url(); -} - -bool FrameLoader::executeIfJavaScriptURL(const KURL& url, bool userGesture, bool replaceDocument) -{ - if (!url.protocolIs("javascript")) - return false; - - String script = decodeURLEscapeSequences(url.string().substring(strlen("javascript:"))); - JSValue* result = executeScript(script, userGesture); - - String scriptResult; - if (!getString(result, scriptResult)) - return true; - - SecurityOrigin* currentSecurityOrigin = 0; - if (m_frame->document()) - currentSecurityOrigin = m_frame->document()->securityOrigin(); - - // FIXME: We should always replace the document, but doing so - // synchronously can cause crashes: - // http://bugs.webkit.org/show_bug.cgi?id=16782 - if (replaceDocument) { - begin(m_URL, true, currentSecurityOrigin); - write(scriptResult); - end(); - } - - return true; -} - -JSValue* FrameLoader::executeScript(const String& script, bool forceUserGesture) -{ - return executeScript(forceUserGesture ? String() : m_URL.string(), 1, script); -} - -JSValue* FrameLoader::executeScript(const String& url, int baseLine, const String& script) -{ - if (!m_frame->script()->isEnabled() || m_frame->script()->isPaused()) - return noValue(); - - bool wasRunningScript = m_isRunningScript; - m_isRunningScript = true; - - JSValue* result = m_frame->script()->evaluate(url, baseLine, script); - - if (!wasRunningScript) { - m_isRunningScript = false; - submitFormAgain(); - Document::updateDocumentsRendering(); - } - - return result; -} - -void FrameLoader::cancelAndClear() -{ - cancelRedirection(); - - if (!m_isComplete) - closeURL(); - - clear(false); -} - -void FrameLoader::clear(bool clearWindowProperties, bool clearScriptObjects) -{ - // FIXME: Commenting out the below line causes , but putting it - // back causes a measurable performance regression which we will need to fix to restore the correct behavior - // urlsBridgeKnowsAbout.clear(); - - m_frame->editor()->clear(); - - if (!m_needsClear) - return; - m_needsClear = false; - - if (m_frame->document() && !m_frame->document()->inPageCache()) { - m_frame->document()->cancelParsing(); - if (m_frame->document()->attached()) { - m_frame->document()->willRemove(); - m_frame->document()->detach(); - - m_frame->document()->removeFocusedNodeOfSubtree(m_frame->document()); - } - } - - // Do this after detaching the document so that the unload event works. - if (clearWindowProperties) { - m_frame->clearDOMWindow(); - m_frame->script()->clearWindowShell(); - } - - m_frame->selection()->clear(); - m_frame->eventHandler()->clear(); - if (m_frame->view()) - m_frame->view()->clear(); - - m_frame->setSelectionGranularity(CharacterGranularity); - - // Do not drop the document before the ScriptController and view are cleared - // as some destructors might still try to access the document. - m_frame->setDocument(0); - m_decoder = 0; - - m_containsPlugIns = false; - - if (clearScriptObjects) - m_frame->script()->clearScriptObjects(); - - m_redirectionTimer.stop(); - m_scheduledRedirection.clear(); - - m_checkCompletedTimer.stop(); - m_checkLoadCompleteTimer.stop(); - - m_receivedData = false; - m_isDisplayingInitialEmptyDocument = false; - - if (!m_encodingWasChosenByUser) - m_encoding = String(); -} - -void FrameLoader::receivedFirstData() -{ - begin(m_workingURL, false); - - dispatchDidCommitLoad(); - dispatchWindowObjectAvailable(); - - String ptitle = m_documentLoader->title(); - // If we have a title let the WebView know about it. - if (!ptitle.isNull()) - m_client->dispatchDidReceiveTitle(ptitle); - - m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); - m_workingURL = KURL(); - - double delay; - String url; - if (!m_documentLoader) - return; - if (!parseHTTPRefresh(m_documentLoader->response().httpHeaderField("Refresh"), false, delay, url)) - return; - - if (url.isEmpty()) - url = m_URL.string(); - else - url = m_frame->document()->completeURL(url).string(); - - scheduleHTTPRedirection(delay, url); -} - -const String& FrameLoader::responseMIMEType() const -{ - return m_responseMIMEType; -} - -void FrameLoader::setResponseMIMEType(const String& type) -{ - m_responseMIMEType = type; -} - -void FrameLoader::begin() -{ - begin(KURL()); -} - -void FrameLoader::begin(const KURL& url, bool dispatch, SecurityOrigin* origin) -{ - // We need to take a reference to the security origin because |clear| - // might destroy the document that owns it. - RefPtr forcedSecurityOrigin = origin; - - bool resetScripting = !(m_isDisplayingInitialEmptyDocument && m_frame->document() && m_frame->document()->securityOrigin()->isSecureTransitionTo(url)); - clear(resetScripting, resetScripting); - if (dispatch) - dispatchWindowObjectAvailable(); - - m_needsClear = true; - m_isComplete = false; - m_didCallImplicitClose = false; - m_isLoadingMainResource = true; - m_isDisplayingInitialEmptyDocument = m_creatingInitialEmptyDocument; - - KURL ref(url); - ref.setUser(String()); - ref.setPass(String()); - ref.setRef(String()); - m_outgoingReferrer = ref.string(); - m_URL = url; - - RefPtr document = DOMImplementation::createDocument(m_responseMIMEType, m_frame, m_frame->inViewSourceMode()); - m_frame->setDocument(document); - - document->setURL(m_URL); - if (m_decoder) - document->setDecoder(m_decoder.get()); - if (forcedSecurityOrigin) - document->setSecurityOrigin(forcedSecurityOrigin.get()); - - m_frame->domWindow()->setURL(document->url()); - m_frame->domWindow()->setSecurityOrigin(document->securityOrigin()); - - updatePolicyBaseURL(); - - Settings* settings = document->settings(); - document->docLoader()->setAutoLoadImages(settings && settings->loadsImagesAutomatically()); -#ifdef ANDROID_BLOCK_NETWORK_IMAGE - document->docLoader()->setBlockNetworkImage(settings && settings->blockNetworkImage()); -#endif - - if (m_documentLoader) { - String dnsPrefetchControl = m_documentLoader->response().httpHeaderField("X-DNS-Prefetch-Control"); - if (!dnsPrefetchControl.isEmpty()) - document->parseDNSPrefetchControlHeader(dnsPrefetchControl); - } - -#if FRAME_LOADS_USER_STYLESHEET - KURL userStyleSheet = settings ? settings->userStyleSheetLocation() : KURL(); - if (!userStyleSheet.isEmpty()) - m_frame->setUserStyleSheetLocation(userStyleSheet); -#endif - - restoreDocumentState(); - - document->implicitOpen(); - - if (m_frame->view()) - m_frame->view()->setContentsSize(IntSize()); - -#if USE(LOW_BANDWIDTH_DISPLAY) - // Low bandwidth display is a first pass display without external resources - // used to give an instant visual feedback. We currently only enable it for - // HTML documents in the top frame. - if (document->isHTMLDocument() && !m_frame->tree()->parent() && m_useLowBandwidthDisplay) { - m_pendingSourceInLowBandwidthDisplay = String(); - m_finishedParsingDuringLowBandwidthDisplay = false; - m_needToSwitchOutLowBandwidthDisplay = false; - document->setLowBandwidthDisplay(true); - } -#endif -} - -void FrameLoader::write(const char* str, int len, bool flush) -{ - if (len == 0 && !flush) - return; - - if (len == -1) - len = strlen(str); - - Tokenizer* tokenizer = m_frame->document()->tokenizer(); - if (tokenizer && tokenizer->wantsRawData()) { - if (len > 0) - tokenizer->writeRawData(str, len); - return; - } - - if (!m_decoder) { - Settings* settings = m_frame->settings(); - m_decoder = TextResourceDecoder::create(m_responseMIMEType, settings ? settings->defaultTextEncodingName() : String()); - if (m_encoding.isEmpty()) { - Frame* parentFrame = m_frame->tree()->parent(); - if (parentFrame && parentFrame->document()->securityOrigin()->canAccess(m_frame->document()->securityOrigin())) - m_decoder->setEncoding(parentFrame->document()->inputEncoding(), TextResourceDecoder::DefaultEncoding); - } else { - m_decoder->setEncoding(m_encoding, - m_encodingWasChosenByUser ? TextResourceDecoder::UserChosenEncoding : TextResourceDecoder::EncodingFromHTTPHeader); - } - m_frame->document()->setDecoder(m_decoder.get()); - } - - String decoded = m_decoder->decode(str, len); - if (flush) - decoded += m_decoder->flush(); - if (decoded.isEmpty()) - return; - -#if USE(LOW_BANDWIDTH_DISPLAY) - if (m_frame->document()->inLowBandwidthDisplay()) - m_pendingSourceInLowBandwidthDisplay.append(decoded); - else // reset policy which is changed in switchOutLowBandwidthDisplayIfReady() - m_frame->document()->docLoader()->setCachePolicy(m_cachePolicy); -#endif - - if (!m_receivedData) { - m_receivedData = true; - if (m_decoder->encoding().usesVisualOrdering()) - m_frame->document()->setVisuallyOrdered(); - m_frame->document()->recalcStyle(Node::Force); - } - - if (tokenizer) { - ASSERT(!tokenizer->wantsRawData()); - tokenizer->write(decoded, true); - } -} - -void FrameLoader::write(const String& str) -{ - if (str.isNull()) - return; - - if (!m_receivedData) { - m_receivedData = true; - m_frame->document()->setParseMode(Document::Strict); - } - - if (Tokenizer* tokenizer = m_frame->document()->tokenizer()) - tokenizer->write(str, true); -} - -void FrameLoader::end() -{ - m_isLoadingMainResource = false; - endIfNotLoadingMainResource(); -} - -void FrameLoader::endIfNotLoadingMainResource() -{ - if (m_isLoadingMainResource || !m_frame->page()) - return; - - // http://bugs.webkit.org/show_bug.cgi?id=10854 - // The frame's last ref may be removed and it can be deleted by checkCompleted(), - // so we'll add a protective refcount - RefPtr protector(m_frame); - - // make sure nothing's left in there - if (m_frame->document()) { - write(0, 0, true); - m_frame->document()->finishParsing(); -#if USE(LOW_BANDWIDTH_DISPLAY) - if (m_frame->document()->inLowBandwidthDisplay()) { - m_finishedParsingDuringLowBandwidthDisplay = true; - switchOutLowBandwidthDisplayIfReady(); - } -#endif - } else - // WebKit partially uses WebCore when loading non-HTML docs. In these cases doc==nil, but - // WebCore is enough involved that we need to checkCompleted() in order for m_bComplete to - // become true. An example is when a subframe is a pure text doc, and that subframe is the - // last one to complete. - checkCompleted(); -} - -void FrameLoader::iconLoadDecisionAvailable() -{ - if (!m_mayLoadIconLater) - return; - LOG(IconDatabase, "FrameLoader %p was told a load decision is available for its icon", this); - startIconLoader(); - m_mayLoadIconLater = false; -} - -void FrameLoader::startIconLoader() -{ - // FIXME: We kick off the icon loader when the frame is done receiving its main resource. - // But we should instead do it when we're done parsing the head element. - if (!isLoadingMainFrame()) - return; - - if (!iconDatabase() || !iconDatabase()->isEnabled()) - return; - - KURL url(iconURL()); - String urlString(url.string()); - if (urlString.isEmpty()) - return; - - // If we're not reloading and the icon database doesn't say to load now then bail before we actually start the load - if (loadType() != FrameLoadTypeReload) { - IconLoadDecision decision = iconDatabase()->loadDecisionForIconURL(urlString, m_documentLoader.get()); - if (decision == IconLoadNo) { - LOG(IconDatabase, "FrameLoader::startIconLoader() - Told not to load this icon, committing iconURL %s to database for pageURL mapping", urlString.ascii().data()); - commitIconURLToIconDatabase(url); - - // We were told not to load this icon - that means this icon is already known by the database - // 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 - // has done it. This is after registering for the notification so the WebView can call the appropriate delegate method. - // Otherwise if the icon data *is* available, notify the delegate - if (!iconDatabase()->iconDataKnownForIconURL(urlString)) { - 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()); - m_client->registerForIconNotification(); - iconDatabase()->iconForPageURL(m_URL.string(), IntSize(0, 0)); - iconDatabase()->iconForPageURL(originalRequestURL().string(), IntSize(0, 0)); - } else - m_client->dispatchDidReceiveIcon(); - - return; - } - - if (decision == IconLoadUnknown) { - // In this case, we may end up loading the icon later, but we still want to commit the icon url mapping to the database - // 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 - // We also tell the client to register for the notification that the icon is received now so it isn't missed in case the - // icon is later read in from disk - LOG(IconDatabase, "FrameLoader %p might load icon %s later", this, urlString.ascii().data()); - m_mayLoadIconLater = true; - m_client->registerForIconNotification(); - commitIconURLToIconDatabase(url); - return; - } - } - - // This is either a reload or the icon database said "yes, load the icon", so kick off the load! - if (!m_iconLoader) - m_iconLoader.set(IconLoader::create(m_frame).release()); - - m_iconLoader->startLoading(); -} - -void FrameLoader::setLocalLoadPolicy(LocalLoadPolicy policy) -{ - localLoadPolicy = policy; -} - -bool FrameLoader::restrictAccessToLocal() -{ - return localLoadPolicy != FrameLoader::AllowLocalLoadsForAll; -} - -bool FrameLoader::allowSubstituteDataAccessToLocal() -{ - return localLoadPolicy != FrameLoader::AllowLocalLoadsForLocalOnly; -} - -static HashSet& localSchemes() -{ - static HashSet localSchemes; - - if (localSchemes.isEmpty()) { - localSchemes.add("file"); -#if PLATFORM(MAC) - localSchemes.add("applewebdata"); -#endif -#if PLATFORM(QT) - localSchemes.add("qrc"); -#endif - } - - return localSchemes; -} - -void FrameLoader::commitIconURLToIconDatabase(const KURL& icon) -{ - ASSERT(iconDatabase()); - LOG(IconDatabase, "Committing iconURL %s to database for pageURLs %s and %s", icon.string().ascii().data(), m_URL.string().ascii().data(), originalRequestURL().string().ascii().data()); - iconDatabase()->setIconURLForPageURL(icon.string(), m_URL.string()); - iconDatabase()->setIconURLForPageURL(icon.string(), originalRequestURL().string()); -} - -void FrameLoader::restoreDocumentState() -{ - Document* doc = m_frame->document(); - if (!doc) - return; - - HistoryItem* itemToRestore = 0; - - switch (loadType()) { - case FrameLoadTypeReload: -#ifndef ANDROID_HISTORY_CLIENT - case FrameLoadTypeReloadAllowingStaleData: -#endif - case FrameLoadTypeSame: - case FrameLoadTypeReplace: - break; - case FrameLoadTypeBack: - case FrameLoadTypeForward: - case FrameLoadTypeIndexedBackForward: - case FrameLoadTypeRedirectWithLockedHistory: - case FrameLoadTypeStandard: -#ifdef ANDROID_HISTORY_CLIENT - case FrameLoadTypeReloadAllowingStaleData: -#endif - itemToRestore = m_currentHistoryItem.get(); - } - - if (!itemToRestore) - return; - - doc->setStateForNewFormElements(itemToRestore->documentState()); -} - -void FrameLoader::gotoAnchor() -{ - // If our URL has no ref, then we have no place we need to jump to. - // OTOH If CSS target was set previously, we want to set it to 0, recalc - // and possibly repaint because :target pseudo class may have been - // set (see bug 11321). - if (!m_URL.hasRef() && !(m_frame->document() && m_frame->document()->getCSSTarget())) - return; - - String ref = m_URL.ref(); - if (gotoAnchor(ref)) - return; - - // Try again after decoding the ref, based on the document's encoding. - if (m_decoder) - gotoAnchor(decodeURLEscapeSequences(ref, m_decoder->encoding())); -} - -void FrameLoader::finishedParsing() -{ - if (m_creatingInitialEmptyDocument) - return; - - // This can be called from the Frame's destructor, in which case we shouldn't protect ourselves - // because doing so will cause us to re-enter the destructor when protector goes out of scope. - // Null-checking the FrameView indicates whether or not we're in the destructor. - RefPtr protector = m_frame->view() ? m_frame : 0; - - checkCompleted(); - - if (!m_frame->view()) - return; // We are being destroyed by something checkCompleted called. - - // Check if the scrollbars are really needed for the content. - // If not, remove them, relayout, and repaint. - m_frame->view()->restoreScrollbar(); - - m_client->dispatchDidFinishDocumentLoad(); - - gotoAnchor(); -} - -void FrameLoader::loadDone() -{ - if (m_frame->document()) - checkCompleted(); -} - -void FrameLoader::checkCompleted() -{ - // Any frame that hasn't completed yet? - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - if (!child->loader()->m_isComplete) - return; - - // Have we completed before? - if (m_isComplete) - return; - - // Are we still parsing? - if (m_frame->document() && m_frame->document()->parsing()) - return; - - // Still waiting for images/scripts? - if (m_frame->document()) - if (numRequests(m_frame->document())) - return; - -#if USE(LOW_BANDWIDTH_DISPLAY) - // as switch will be called, don't complete yet - if (m_frame->document() && m_frame->document()->inLowBandwidthDisplay() && m_needToSwitchOutLowBandwidthDisplay) - return; -#endif - - // OK, completed. - m_isComplete = true; - - RefPtr protect(m_frame); - checkCallImplicitClose(); // if we didn't do it before - - // Do not start a redirection timer for subframes here. - // That is deferred until the parent is completed. - if (m_scheduledRedirection && !m_frame->tree()->parent()) - startRedirectionTimer(); - - completed(); - if (m_frame->page()) - checkLoadComplete(); -} - -void FrameLoader::checkCompletedTimerFired(Timer*) -{ - checkCompleted(); -} - -void FrameLoader::scheduleCheckCompleted() -{ - if (!m_checkCompletedTimer.isActive()) - m_checkCompletedTimer.startOneShot(0); -} - -void FrameLoader::checkLoadCompleteTimerFired(Timer*) -{ - if (!m_frame->page()) - return; - checkLoadComplete(); -} - -void FrameLoader::scheduleCheckLoadComplete() -{ - if (!m_checkLoadCompleteTimer.isActive()) - m_checkLoadCompleteTimer.startOneShot(0); -} - -void FrameLoader::checkCallImplicitClose() -{ - if (m_didCallImplicitClose || !m_frame->document() || m_frame->document()->parsing()) - return; - - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - if (!child->loader()->m_isComplete) // still got a frame running -> too early - return; - - m_didCallImplicitClose = true; - m_wasUnloadEventEmitted = false; - if (m_frame->document()) - m_frame->document()->implicitClose(); -} - -KURL FrameLoader::baseURL() const -{ - ASSERT(m_frame->document()); - return m_frame->document()->baseURL(); -} - -String FrameLoader::baseTarget() const -{ - ASSERT(m_frame->document()); - return m_frame->document()->baseTarget(); -} - -KURL FrameLoader::completeURL(const String& url) -{ - ASSERT(m_frame->document()); - return m_frame->document()->completeURL(url); -} - -void FrameLoader::scheduleHTTPRedirection(double delay, const String& url) -{ - if (delay < 0 || delay > INT_MAX / 1000) - return; - - if (!m_frame->page()) - return; - - // We want a new history item if the refresh timeout is > 1 second. - if (!m_scheduledRedirection || delay <= m_scheduledRedirection->delay) -#ifdef ANDROID_USER_GESTURE - { - bool wasUserGesture = false; - DocumentLoader* docLoader = activeDocumentLoader(); - if (docLoader) - wasUserGesture = docLoader->request().userGesture(); - scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, wasUserGesture)); - } -#else - scheduleRedirection(new ScheduledRedirection(delay, url, delay <= 1, false)); -#endif -} - -void FrameLoader::scheduleLocationChange(const String& url, const String& referrer, bool lockHistory, bool wasUserGesture) -{ - if (!m_frame->page()) - return; - - // If the URL we're going to navigate to is the same as the current one, except for the - // fragment part, we don't need to schedule the location change. - KURL parsedURL(url); - if (parsedURL.hasRef() && equalIgnoringRef(m_URL, parsedURL)) { - changeLocation(url, referrer, lockHistory, wasUserGesture); - return; - } - - // Handle a location change of a page with no document as a special case. - // This may happen when a frame changes the location of another frame. - bool duringLoad = !m_committedFirstRealDocumentLoad; - - // If a redirect was scheduled during a load, then stop the current load. - // Otherwise when the current load transitions from a provisional to a - // committed state, pending redirects may be cancelled. - if (duringLoad) { - if (m_provisionalDocumentLoader) - m_provisionalDocumentLoader->stopLoading(); - stopLoading(true); - } - - ScheduledRedirection::Type type = duringLoad - ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange; - scheduleRedirection(new ScheduledRedirection(type, url, referrer, lockHistory, wasUserGesture)); -} - -void FrameLoader::scheduleRefresh(bool wasUserGesture) -{ - if (!m_frame->page()) - return; - - // Handle a location change of a page with no document as a special case. - // This may happen when a frame requests a refresh of another frame. - bool duringLoad = !m_frame->document(); - - // If a refresh was scheduled during a load, then stop the current load. - // Otherwise when the current load transitions from a provisional to a - // committed state, pending redirects may be cancelled. - if (duringLoad) - stopLoading(true); - - ScheduledRedirection::Type type = duringLoad - ? ScheduledRedirection::locationChangeDuringLoad : ScheduledRedirection::locationChange; - scheduleRedirection(new ScheduledRedirection(type, m_URL.string(), m_outgoingReferrer, true, wasUserGesture)); - m_cachePolicy = CachePolicyRefresh; -} - -bool FrameLoader::isLocationChange(const ScheduledRedirection& redirection) -{ - switch (redirection.type) { - case ScheduledRedirection::redirection: - return false; - case ScheduledRedirection::historyNavigation: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - return true; - } - ASSERT_NOT_REACHED(); - return false; -} - -void FrameLoader::scheduleHistoryNavigation(int steps) -{ - if (!m_frame->page()) - return; - - // navigation will always be allowed in the 0 steps case, which is OK because that's supposed to force a reload. - if (!canGoBackOrForward(steps)) { - cancelRedirection(); - return; - } - - // If the steps to navigate is not zero (which needs to force a reload), and if we think the navigation is going to be a fragment load - // (when the URL we're going to navigate to is the same as the current one, except for the fragment part - but not exactly the same because that's a reload), - // then we don't need to schedule the navigation. - if (steps != 0) { - KURL destination = historyURL(steps); - // FIXME: This doesn't seem like a reliable way to tell whether or not the load will be a fragment load. - if (equalIgnoringRef(m_URL, destination) && m_URL != destination) { - goBackOrForward(steps); - return; - } - } - - scheduleRedirection(new ScheduledRedirection(steps)); -} - -void FrameLoader::goBackOrForward(int distance) -{ - if (distance == 0) - return; - - Page* page = m_frame->page(); - if (!page) - return; - BackForwardList* list = page->backForwardList(); - if (!list) - return; - - HistoryItem* item = list->itemAtIndex(distance); - if (!item) { - if (distance > 0) { - int forwardListCount = list->forwardListCount(); - if (forwardListCount > 0) - item = list->itemAtIndex(forwardListCount); - } else { - int backListCount = list->backListCount(); - if (backListCount > 0) - item = list->itemAtIndex(-backListCount); - } - } - - ASSERT(item); // we should not reach this line with an empty back/forward list - if (item) - page->goToItem(item, FrameLoadTypeIndexedBackForward); -} - -void FrameLoader::redirectionTimerFired(Timer*) -{ - ASSERT(m_frame->page()); - - OwnPtr redirection(m_scheduledRedirection.release()); - - switch (redirection->type) { - case ScheduledRedirection::redirection: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - changeLocation(redirection->url, redirection->referrer, - redirection->lockHistory, redirection->wasUserGesture); - return; - case ScheduledRedirection::historyNavigation: - if (redirection->historySteps == 0) { - // Special case for go(0) from a frame -> reload only the frame - urlSelected(m_URL, "", 0, redirection->lockHistory, redirection->wasUserGesture); - return; - } - // go(i!=0) from a frame navigates into the history of the frame only, - // in both IE and NS (but not in Mozilla). We can't easily do that. - goBackOrForward(redirection->historySteps); - return; - } - - ASSERT_NOT_REACHED(); -} - -/* - In the case of saving state about a page with frames, we store a tree of items that mirrors the frame tree. - The item that was the target of the user's navigation is designated as the "targetItem". - When this method is called with doClip=YES we're able to create the whole tree except for the target's children, - which will be loaded in the future. That part of the tree will be filled out as the child loads are committed. -*/ -void FrameLoader::loadURLIntoChildFrame(const KURL& url, const String& referer, Frame* childFrame) -{ - ASSERT(childFrame); - HistoryItem* parentItem = currentHistoryItem(); - FrameLoadType loadType = this->loadType(); - FrameLoadType childLoadType = FrameLoadTypeRedirectWithLockedHistory; - - KURL workingURL = url; - - // If we're moving in the backforward list, we might want to replace the content - // of this child frame with whatever was there at that point. - // Reload will maintain the frame contents, LoadSame will not. - if (parentItem && parentItem->children().size() && - (isBackForwardLoadType(loadType) || loadType == FrameLoadTypeReloadAllowingStaleData)) - { - HistoryItem* childItem = parentItem->childItemWithName(childFrame->tree()->name()); - if (childItem) { - // Use the original URL to ensure we get all the side-effects, such as - // onLoad handlers, of any redirects that happened. An example of where - // this is needed is Radar 3213556. - workingURL = KURL(childItem->originalURLString()); - // These behaviors implied by these loadTypes should apply to the child frames - childLoadType = loadType; - - if (isBackForwardLoadType(loadType)) { - // For back/forward, remember this item so we can traverse any child items as child frames load - childFrame->loader()->setProvisionalHistoryItem(childItem); - } else { - // For reload, just reinstall the current item, since a new child frame was created but we won't be creating a new BF item - childFrame->loader()->setCurrentHistoryItem(childItem); - } - } - } - -#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size - RefPtr subframeArchive = activeDocumentLoader()->popArchiveForSubframe(childFrame->tree()->name()); - - if (subframeArchive) - childFrame->loader()->loadArchive(subframeArchive.release()); - else -#endif -#ifdef ANDROID_USER_GESTURE - childFrame->loader()->loadURL(workingURL, referer, String(), childLoadType, 0, 0, false); -#else - childFrame->loader()->loadURL(workingURL, referer, String(), childLoadType, 0, 0); -#endif -} - -#if ENABLE(ARCHIVE) // ANDROID extension: disabled to reduce code size -void FrameLoader::loadArchive(PassRefPtr prpArchive) -{ - RefPtr archive = prpArchive; - - ArchiveResource* mainResource = archive->mainResource(); - ASSERT(mainResource); - if (!mainResource) - return; - - SubstituteData substituteData(mainResource->data(), mainResource->mimeType(), mainResource->textEncoding(), KURL()); - - ResourceRequest request(mainResource->url()); -#if PLATFORM(MAC) - request.applyWebArchiveHackForMail(); -#endif - - RefPtr documentLoader = m_client->createDocumentLoader(request, substituteData); - documentLoader->addAllArchiveResources(archive.get()); - load(documentLoader.get()); -} -#endif - -String FrameLoader::encoding() const -{ - if (m_encodingWasChosenByUser && !m_encoding.isEmpty()) - return m_encoding; - if (m_decoder && m_decoder->encoding().isValid()) - return m_decoder->encoding().name(); - Settings* settings = m_frame->settings(); - return settings ? settings->defaultTextEncodingName() : String(); -} - -bool FrameLoader::gotoAnchor(const String& name) -{ - ASSERT(m_frame->document()); - - if (!m_frame->document()->haveStylesheetsLoaded()) { - m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(true); - return false; - } - - m_frame->document()->setGotoAnchorNeededAfterStylesheetsLoad(false); - - Node* anchorNode = m_frame->document()->getElementById(AtomicString(name)); - if (!anchorNode && !name.isEmpty()) - anchorNode = m_frame->document()->anchors()->namedItem(name, !m_frame->document()->inCompatMode()); - -#if ENABLE(SVG) - if (m_frame->document()->isSVGDocument()) { - if (name.startsWith("xpointer(")) { - // We need to parse the xpointer reference here - } else if (name.startsWith("svgView(")) { - RefPtr svg = static_cast(m_frame->document())->rootElement(); - if (!svg->currentView()->parseViewSpec(name)) - return false; - svg->setUseCurrentView(true); - } else { - if (anchorNode && anchorNode->hasTagName(SVGNames::viewTag)) { - RefPtr viewElement = anchorNode->hasTagName(SVGNames::viewTag) ? static_cast(anchorNode) : 0; - if (viewElement.get()) { - RefPtr svg = static_cast(SVGLocatable::nearestViewportElement(viewElement.get())); - svg->inheritViewAttributes(viewElement.get()); - } - } - } - // FIXME: need to decide which to focus on, and zoom to that one - // FIXME: need to actually "highlight" the viewTarget(s) - } -#endif - - m_frame->document()->setCSSTarget(anchorNode); // Setting to null will clear the current target. - - // Implement the rule that "" and "top" both mean top of page as in other browsers. - if (!anchorNode && !(name.isEmpty() || equalIgnoringCase(name, "top"))) - return false; - - // We need to update the layout before scrolling, otherwise we could - // really mess things up if an anchor scroll comes at a bad moment. - if (m_frame->document()) { - m_frame->document()->updateRendering(); - // Only do a layout if changes have occurred that make it necessary. - if (m_frame->view() && m_frame->contentRenderer() && m_frame->contentRenderer()->needsLayout()) - m_frame->view()->layout(); - } - - // Scroll nested layers and frames to reveal the anchor. - // Align to the top and to the closest side (this matches other browsers). - RenderObject* renderer; - IntRect rect; - if (!anchorNode) - renderer = m_frame->document()->renderer(); // top of document - else { - renderer = anchorNode->renderer(); - rect = anchorNode->getRect(); - } - if (renderer) - renderer->enclosingLayer()->scrollRectToVisible(rect, true, RenderLayer::gAlignToEdgeIfNeeded, RenderLayer::gAlignTopAlways); - - return true; -} - -bool FrameLoader::requestObject(RenderPart* renderer, const String& url, const AtomicString& frameName, - const String& mimeType, const Vector& paramNames, const Vector& paramValues) -{ - if (url.isEmpty() && mimeType.isEmpty()) - return false; - -#if USE(LOW_BANDWIDTH_DISPLAY) - // don't care object during low bandwidth display - if (frame()->document()->inLowBandwidthDisplay()) { - m_needToSwitchOutLowBandwidthDisplay = true; - return false; - } -#endif - - KURL completedURL; - if (!url.isEmpty()) - completedURL = completeURL(url); - - bool useFallback; - if (shouldUsePlugin(completedURL, mimeType, renderer->hasFallbackContent(), useFallback)) { - Settings* settings = m_frame->settings(); - if (!settings || !settings->arePluginsEnabled() || - (!settings->isJavaEnabled() && MIMETypeRegistry::isJavaAppletMIMEType(mimeType))) - return false; - return loadPlugin(renderer, completedURL, mimeType, paramNames, paramValues, useFallback); - } - - ASSERT(renderer->node()->hasTagName(objectTag) || renderer->node()->hasTagName(embedTag)); - HTMLPlugInElement* element = static_cast(renderer->node()); - - // FIXME: OK to always make a new frame? When does the old frame get removed? - return loadSubframe(element, completedURL, frameName, m_outgoingReferrer); -} - -bool FrameLoader::shouldUsePlugin(const KURL& url, const String& mimeType, bool hasFallback, bool& useFallback) -{ - // Allow other plug-ins to win over QuickTime because if the user has installed a plug-in that - // can handle TIFF (which QuickTime can also handle) they probably intended to override QT. - if (m_frame->page() && (mimeType == "image/tiff" || mimeType == "image/tif" || mimeType == "image/x-tiff")) { - String pluginName = m_frame->page()->pluginData()->pluginNameForMimeType(mimeType); - if (!pluginName.isEmpty() && !pluginName.contains("QuickTime", false)) - return true; - } - - ObjectContentType objectType = m_client->objectContentType(url, mimeType); - // If an object's content can't be handled and it has no fallback, let - // it be handled as a plugin to show the broken plugin icon. - useFallback = objectType == ObjectContentNone && hasFallback; - return objectType == ObjectContentNone || objectType == ObjectContentNetscapePlugin || objectType == ObjectContentOtherPlugin; -} - -bool FrameLoader::loadPlugin(RenderPart* renderer, const KURL& url, const String& mimeType, - const Vector& paramNames, const Vector& paramValues, bool useFallback) -{ - Widget* widget = 0; - - if (renderer && !useFallback) { - Element* pluginElement = 0; - if (renderer->node() && renderer->node()->isElementNode()) - pluginElement = static_cast(renderer->node()); - - if (!canLoad(url, String(), frame()->document())) { - FrameLoader::reportLocalLoadFailed(m_frame, url.string()); - return false; - } - - widget = m_client->createPlugin(IntSize(renderer->contentWidth(), renderer->contentHeight()), - pluginElement, url, paramNames, paramValues, mimeType, - m_frame->document()->isPluginDocument()); - if (widget) { - renderer->setWidget(widget); - m_containsPlugIns = true; - } - } - - return widget != 0; -} - -void FrameLoader::clearRecordedFormValues() -{ - m_formAboutToBeSubmitted = 0; - m_formValuesAboutToBeSubmitted.clear(); -} - -void FrameLoader::setFormAboutToBeSubmitted(PassRefPtr element) -{ - m_formAboutToBeSubmitted = element; -} - -void FrameLoader::recordFormValue(const String& name, const String& value) -{ - m_formValuesAboutToBeSubmitted.set(name, value); -} - -void FrameLoader::parentCompleted() -{ - if (m_scheduledRedirection && !m_redirectionTimer.isActive()) - startRedirectionTimer(); -} - -String FrameLoader::outgoingReferrer() const -{ - return m_outgoingReferrer; -} - -String FrameLoader::outgoingOrigin() const -{ - if (m_frame->document()) - return m_frame->document()->securityOrigin()->toString(); - - return SecurityOrigin::createEmpty()->toString(); -} - -Frame* FrameLoader::opener() -{ - return m_opener; -} - -void FrameLoader::setOpener(Frame* opener) -{ - if (m_opener) - m_opener->loader()->m_openedFrames.remove(m_frame); - if (opener) - opener->loader()->m_openedFrames.add(m_frame); - m_opener = opener; - - if (m_frame->document()) { - m_frame->document()->initSecurityContext(); - m_frame->domWindow()->setSecurityOrigin(m_frame->document()->securityOrigin()); - } -} - -bool FrameLoader::openedByDOM() const -{ - return m_openedByDOM; -} - -void FrameLoader::setOpenedByDOM() -{ - m_openedByDOM = true; -} - -void FrameLoader::handleFallbackContent() -{ - HTMLFrameOwnerElement* owner = m_frame->ownerElement(); - if (!owner || !owner->hasTagName(objectTag)) - return; - static_cast(owner)->renderFallbackContent(); -} - -void FrameLoader::provisionalLoadStarted() -{ -#ifdef ANDROID_INSTRUMENT - if (!m_frame->tree()->parent()) - android::TimeCounter::reset(); -#endif - - Page* page = m_frame->page(); - - // this is used to update the current history item - // in the event of a navigation aytime during loading - m_navigationDuringLoad = false; - if (page) { - Document *document = page->mainFrame()->document(); - m_navigationDuringLoad = !page->mainFrame()->loader()->isComplete() || (document && document->processingLoadEvent()); - } - - m_firstLayoutDone = false; - cancelRedirection(true); - m_client->provisionalLoadStarted(); -} - -bool FrameLoader::userGestureHint() -{ - Frame* rootFrame = m_frame; - while (rootFrame->tree()->parent()) - rootFrame = rootFrame->tree()->parent(); - - if (rootFrame->script()->isEnabled()) - return rootFrame->script()->processingUserGesture(); - - return true; // If JavaScript is disabled, a user gesture must have initiated the navigation -} - -void FrameLoader::didNotOpenURL(const KURL& url) -{ - if (m_submittedFormURL == url) - m_submittedFormURL = KURL(); -} - -void FrameLoader::resetMultipleFormSubmissionProtection() -{ - m_submittedFormURL = KURL(); -} - -void FrameLoader::setEncoding(const String& name, bool userChosen) -{ - if (!m_workingURL.isEmpty()) - receivedFirstData(); - m_encoding = name; - m_encodingWasChosenByUser = userChosen; -} - -void FrameLoader::addData(const char* bytes, int length) -{ - ASSERT(m_workingURL.isEmpty()); - ASSERT(m_frame->document()); - ASSERT(m_frame->document()->parsing()); - write(bytes, length); -} - -bool FrameLoader::canCachePage() -{ - // Cache the page, if possible. - // Don't write to the cache if in the middle of a redirect, since we will want to - // store the final page we end up on. - // No point writing to the cache on a reload or loadSame, since we will just write - // over it again when we leave that page. - // FIXME: - We should work out the complexities of caching pages with frames as they - // are the most interesting pages on the web, and often those that would benefit the most from caching! - FrameLoadType loadType = this->loadType(); - - return m_documentLoader - && m_documentLoader->mainDocumentError().isNull() - && !m_frame->tree()->childCount() - && !m_frame->tree()->parent() - // FIXME: If we ever change this so that pages with plug-ins will be cached, - // we need to make sure that we don't cache pages that have outstanding NPObjects - // (objects created by the plug-in). Since there is no way to pause/resume a Netscape plug-in, - // they would need to be destroyed and then recreated, and there is no way that we can recreate - // the right NPObjects. See for more information. - && !m_containsPlugIns - && !m_URL.protocolIs("https") - && m_frame->document() - && !m_frame->document()->hasWindowEventListener(eventNames().unloadEvent) -#if ENABLE(DATABASE) - && !m_frame->document()->hasOpenDatabases() -#endif - && !m_frame->document()->usingGeolocation() - && m_frame->page() - && m_frame->page()->backForwardList()->enabled() - && m_frame->page()->backForwardList()->capacity() > 0 - && m_frame->page()->settings()->usesPageCache() - && m_currentHistoryItem - && !isQuickRedirectComing() - && loadType != FrameLoadTypeReload - && loadType != FrameLoadTypeReloadAllowingStaleData - && loadType != FrameLoadTypeSame - && !m_documentLoader->isLoadingInAPISense() - && !m_documentLoader->isStopping() -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - // FIXME: We should investigating caching pages that have an associated - // application cache. tracks that work. - && !m_documentLoader->applicationCache() - && !m_documentLoader->candidateApplicationCacheGroup() -#endif - ; -} - -void FrameLoader::updatePolicyBaseURL() -{ - if (m_frame->tree()->parent() && m_frame->tree()->parent()->document()) - setPolicyBaseURL(m_frame->tree()->parent()->document()->policyBaseURL()); - else - setPolicyBaseURL(m_URL); -} - -void FrameLoader::setPolicyBaseURL(const KURL& url) -{ - if (m_frame->document()) - m_frame->document()->setPolicyBaseURL(url); - for (Frame* child = m_frame->tree()->firstChild(); child; child = child->tree()->nextSibling()) - child->loader()->setPolicyBaseURL(url); -} - -// This does the same kind of work that didOpenURL does, except it relies on the fact -// that a higher level already checked that the URLs match and the scrolling is the right thing to do. -void FrameLoader::scrollToAnchor(const KURL& url) -{ - m_URL = url; - updateHistoryForAnchorScroll(); - - // If we were in the autoscroll/panScroll mode we want to stop it before following the link to the anchor - m_frame->eventHandler()->stopAutoscrollTimer(); - started(); - gotoAnchor(); - - // It's important to model this as a load that starts and immediately finishes. - // Otherwise, the parent frame may think we never finished loading. - m_isComplete = false; - checkCompleted(); -} - -bool FrameLoader::isComplete() const -{ - return m_isComplete; -} - -void FrameLoader::scheduleRedirection(ScheduledRedirection* redirection) -{ - ASSERT(m_frame->page()); - - stopRedirectionTimer(); - m_scheduledRedirection.set(redirection); - if (!m_isComplete && redirection->type != ScheduledRedirection::redirection) - completed(); - if (m_isComplete || redirection->type != ScheduledRedirection::redirection) - startRedirectionTimer(); -} - -void FrameLoader::startRedirectionTimer() -{ - ASSERT(m_frame->page()); - ASSERT(m_scheduledRedirection); - - m_redirectionTimer.stop(); - m_redirectionTimer.startOneShot(m_scheduledRedirection->delay); - - switch (m_scheduledRedirection->type) { - case ScheduledRedirection::redirection: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - clientRedirected(KURL(m_scheduledRedirection->url), - m_scheduledRedirection->delay, - currentTime() + m_redirectionTimer.nextFireInterval(), - m_scheduledRedirection->lockHistory, - m_isExecutingJavaScriptFormAction); - return; - case ScheduledRedirection::historyNavigation: - // Don't report history navigations. - return; - } - ASSERT_NOT_REACHED(); -} - -void FrameLoader::stopRedirectionTimer() -{ - if (!m_redirectionTimer.isActive()) - return; - - m_redirectionTimer.stop(); - - if (m_scheduledRedirection) { - switch (m_scheduledRedirection->type) { - case ScheduledRedirection::redirection: - case ScheduledRedirection::locationChange: - case ScheduledRedirection::locationChangeDuringLoad: - clientRedirectCancelledOrFinished(m_cancellingWithLoadInProgress); - return; - case ScheduledRedirection::historyNavigation: - // Don't report history navigations. - return; - } - ASSERT_NOT_REACHED(); - } -} - -void FrameLoader::completed() -{ - RefPtr