/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=2 sw=2 et tw=78: */ /* ***** BEGIN LICENSE BLOCK ***** * Version: MPL 1.1/GPL 2.0/LGPL 2.1 * * The contents of this file are subject to the Mozilla Public License Version * 1.1 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * http://www.mozilla.org/MPL/ * * Software distributed under the License is distributed on an "AS IS" basis, * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License * for the specific language governing rights and limitations under the * License. * * The Original Code is mozilla.org code. * * The Initial Developer of the Original Code is * Netscape Communications Corporation. * Portions created by the Initial Developer are Copyright (C) 1998 * the Initial Developer. All Rights Reserved. * * Contributor(s): * Henri Sivonen * * Alternatively, the contents of this file may be used under the terms of * either the GNU General Public License Version 2 or later (the "GPL"), or * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), * in which case the provisions of the GPL or the LGPL are applicable instead * of those above. If you wish to allow use of your version of this file only * under the terms of either the GPL or the LGPL, and not to allow others to * use your version of this file under the terms of the MPL, indicate your * decision by deleting the provisions above and replace them with the notice * and other provisions required by the GPL or the LGPL. If you do not delete * the provisions above, a recipient may use your version of this file under * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ /* * Base class for the XML and HTML content sinks, which construct a * DOM based on information from the parser. */ #include "nsContentSink.h" #include "nsScriptLoader.h" #include "nsIDocument.h" #include "nsIDOMDocument.h" #include "nsICSSLoader.h" #include "nsStyleConsts.h" #include "nsStyleLinkElement.h" #include "nsINodeInfo.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" #include "nsCPrefetchService.h" #include "nsIURI.h" #include "nsNetUtil.h" #include "nsIHttpChannel.h" #include "nsIContent.h" #include "nsIScriptElement.h" #include "nsIParser.h" #include "nsContentErrors.h" #include "nsIPresShell.h" #include "nsPresContext.h" #include "nsIViewManager.h" #include "nsIContentViewer.h" #include "nsIAtom.h" #include "nsGkAtoms.h" #include "nsIDOMWindowInternal.h" #include "nsIPrincipal.h" #include "nsIScriptGlobalObject.h" #include "nsNetCID.h" #include "nsIOfflineCacheUpdate.h" #include "nsIScriptSecurityManager.h" #include "nsIDOMLoadStatus.h" #include "nsICookieService.h" #include "nsIPrompt.h" #include "nsServiceManagerUtils.h" #include "nsContentUtils.h" #include "nsParserUtils.h" #include "nsCRT.h" #include "nsEscape.h" #include "nsWeakReference.h" #include "nsUnicharUtils.h" #include "nsNodeInfoManager.h" #include "nsTimer.h" #include "nsIAppShell.h" #include "nsWidgetsCID.h" #include "nsIDOMNSDocument.h" #include "nsIRequest.h" #include "nsNodeUtils.h" #include "nsIDOMNode.h" #include "nsThreadUtils.h" #include "nsPresShellIterator.h" #include "nsPIDOMWindow.h" PRLogModuleInfo* gContentSinkLogModuleInfo; class nsScriptLoaderObserverProxy : public nsIScriptLoaderObserver { public: nsScriptLoaderObserverProxy(nsIScriptLoaderObserver* aInner) : mInner(do_GetWeakReference(aInner)) { } virtual ~nsScriptLoaderObserverProxy() { } NS_DECL_ISUPPORTS NS_DECL_NSISCRIPTLOADEROBSERVER nsWeakPtr mInner; }; NS_IMPL_ISUPPORTS1(nsScriptLoaderObserverProxy, nsIScriptLoaderObserver) NS_IMETHODIMP nsScriptLoaderObserverProxy::ScriptAvailable(nsresult aResult, nsIScriptElement *aElement, PRBool aIsInline, nsIURI *aURI, PRInt32 aLineNo) { nsCOMPtr inner = do_QueryReferent(mInner); if (inner) { return inner->ScriptAvailable(aResult, aElement, aIsInline, aURI, aLineNo); } return NS_OK; } NS_IMETHODIMP nsScriptLoaderObserverProxy::ScriptEvaluated(nsresult aResult, nsIScriptElement *aElement, PRBool aIsInline) { nsCOMPtr inner = do_QueryReferent(mInner); if (inner) { return inner->ScriptEvaluated(aResult, aElement, aIsInline); } return NS_OK; } NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink) NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver) NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference) NS_INTERFACE_MAP_ENTRY(nsIScriptLoaderObserver) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptLoaderObserver) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_2(nsContentSink, mDocument, mParser) nsContentSink::nsContentSink() { // We have a zeroing operator new NS_ASSERTION(mLayoutStarted == PR_FALSE, "What?"); NS_ASSERTION(mDynamicLowerValue == PR_FALSE, "What?"); NS_ASSERTION(mParsing == PR_FALSE, "What?"); NS_ASSERTION(mLastSampledUserEventTime == 0, "What?"); NS_ASSERTION(mDeflectedCount == 0, "What?"); NS_ASSERTION(mDroppedTimer == PR_FALSE, "What?"); NS_ASSERTION(mInMonolithicContainer == 0, "What?"); NS_ASSERTION(mInNotification == 0, "What?"); NS_ASSERTION(mDeferredLayoutStart == PR_FALSE, "What?"); #ifdef NS_DEBUG if (!gContentSinkLogModuleInfo) { gContentSinkLogModuleInfo = PR_NewLogModule("nscontentsink"); } #endif } nsContentSink::~nsContentSink() { } nsresult nsContentSink::Init(nsIDocument* aDoc, nsIURI* aURI, nsISupports* aContainer, nsIChannel* aChannel) { NS_PRECONDITION(aDoc, "null ptr"); NS_PRECONDITION(aURI, "null ptr"); if (!aDoc || !aURI) { return NS_ERROR_NULL_POINTER; } mDocument = aDoc; mDocumentURI = aURI; mDocumentBaseURI = aURI; mDocShell = do_QueryInterface(aContainer); if (mDocShell) { PRUint32 loadType = 0; mDocShell->GetLoadType(&loadType); mChangeScrollPosWhenScrollingToRef = ((loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0); } // use this to avoid a circular reference sink->document->scriptloader->sink nsCOMPtr proxy = new nsScriptLoaderObserverProxy(this); NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY); mScriptLoader = mDocument->ScriptLoader(); mScriptLoader->AddObserver(proxy); mCSSLoader = aDoc->CSSLoader(); ProcessHTTPHeaders(aChannel); mNodeInfoManager = aDoc->NodeInfoManager(); mNotifyOnTimer = nsContentUtils::GetBoolPref("content.notify.ontimer", PR_TRUE); // -1 means never mBackoffCount = nsContentUtils::GetIntPref("content.notify.backoffcount", -1); // The mNotificationInterval has a dramatic effect on how long it // takes to initially display content for slow connections. // The current value provides good // incremental display of content without causing an increase // in page load time. If this value is set below 1/10 of second // it starts to impact page load performance. // see bugzilla bug 72138 for more info. mNotificationInterval = nsContentUtils::GetIntPref("content.notify.interval", 120000); // The mMaxTokenProcessingTime controls how long we stay away from // the event loop when processing token. A lower value makes the app // more responsive, but may increase page load time. The content // sink mNotificationInterval gates how frequently the content is // processed so it will also affect how interactive the app is // during page load also. The mNotification prevents contents // flushes from happening too frequently. while // mMaxTokenProcessingTime prevents flushes from happening too // infrequently. // The current ratio of 3 to 1 was determined to be the lowest // mMaxTokenProcessingTime which does not impact page load // performance. See bugzilla bug 76722 for details. mMaxTokenProcessingTime = nsContentUtils::GetIntPref("content.max.tokenizing.time", mNotificationInterval * 3); // 3/4 second (750000us) default for switching mDynamicIntervalSwitchThreshold = nsContentUtils::GetIntPref("content.switch.threshold", 750000); mCanInterruptParser = nsContentUtils::GetBoolPref("content.interrupt.parsing", PR_TRUE); return NS_OK; } NS_IMETHODIMP nsContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aWasAlternate, nsresult aStatus) { if (!aWasAlternate) { NS_ASSERTION(mPendingSheetCount > 0, "How'd that happen?"); --mPendingSheetCount; if (mPendingSheetCount == 0 && (mDeferredLayoutStart || mDeferredFlushTags)) { if (mDeferredFlushTags) { FlushTags(); } if (mDeferredLayoutStart) { // We might not have really started layout, since this sheet was still // loading. Do it now. Probably doesn't matter whether we do this // before or after we unblock scripts, but before feels saner. Note // that if mDeferredLayoutStart is true, that means any subclass // StartLayout() stuff that needs to happen has already happened, so we // don't need to worry about it. StartLayout(PR_FALSE); } // Go ahead and try to scroll to our ref if we have one TryToScrollToRef(); } mScriptLoader->RemoveExecuteBlocker(); } return NS_OK; } NS_IMETHODIMP nsContentSink::ScriptAvailable(nsresult aResult, nsIScriptElement *aElement, PRBool aIsInline, nsIURI *aURI, PRInt32 aLineNo) { PRUint32 count = mScriptElements.Count(); if (count == 0) { return NS_OK; } // aElement will not be in mScriptElements if a