/* -*- 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 "mozilla/css/Loader.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 "nsIApplicationCache.h" #include "nsIApplicationCacheContainer.h" #include "nsIApplicationCacheChannel.h" #include "nsIApplicationCacheService.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 "nsIAppShell.h" #include "nsIWidget.h" #include "nsWidgetsCID.h" #include "nsIDOMNSDocument.h" #include "nsIRequest.h" #include "nsNodeUtils.h" #include "nsIDOMNode.h" #include "nsThreadUtils.h" #include "nsPIDOMWindow.h" #include "mozAutoDocUpdate.h" #include "nsIWebNavigation.h" #include "nsIDocumentLoader.h" #include "nsICachingChannel.h" #include "nsICacheEntryDescriptor.h" #include "nsGenericHTMLElement.h" #include "nsHTMLDNSPrefetch.h" #include "nsISupportsPrimitives.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(nsIDocumentObserver) NS_INTERFACE_MAP_ENTRY(nsIMutationObserver) NS_INTERFACE_MAP_ENTRY(nsITimerCallback) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIScriptLoaderObserver) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink) NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink) if (tmp->mDocument) { tmp->mDocument->RemoveObserver(tmp); } NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mParser) NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mNodeInfoManager) NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mParser) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mNodeInfoManager, nsNodeInfoManager) NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END nsContentSink::nsContentSink() { // We have a zeroing operator new NS_ASSERTION(!mLayoutStarted, "What?"); NS_ASSERTION(!mDynamicLowerValue, "What?"); NS_ASSERTION(!mParsing, "What?"); NS_ASSERTION(mLastSampledUserEventTime == 0, "What?"); NS_ASSERTION(mDeflectedCount == 0, "What?"); NS_ASSERTION(!mDroppedTimer, "What?"); NS_ASSERTION(mInMonolithicContainer == 0, "What?"); NS_ASSERTION(mInNotification == 0, "What?"); NS_ASSERTION(!mDeferredLayoutStart, "What?"); #ifdef NS_DEBUG if (!gContentSinkLogModuleInfo) { gContentSinkLogModuleInfo = PR_NewLogModule("nscontentsink"); } #endif } nsContentSink::~nsContentSink() { if (mDocument) { // Remove ourselves just to be safe, though we really should have // been removed in DidBuildModel if everything worked right. mDocument->RemoveObserver(this); } } PRBool nsContentSink::sNotifyOnTimer; PRInt32 nsContentSink::sBackoffCount; PRInt32 nsContentSink::sNotificationInterval; PRInt32 nsContentSink::sInteractiveDeflectCount; PRInt32 nsContentSink::sPerfDeflectCount; PRInt32 nsContentSink::sPendingEventMode; PRInt32 nsContentSink::sEventProbeRate; PRInt32 nsContentSink::sInteractiveParseTime; PRInt32 nsContentSink::sPerfParseTime; PRInt32 nsContentSink::sInteractiveTime; PRInt32 nsContentSink::sInitialPerfTime; PRInt32 nsContentSink::sEnablePerfMode; PRBool nsContentSink::sCanInterruptParser; void nsContentSink::InitializeStatics() { nsContentUtils::AddBoolPrefVarCache("content.notify.ontimer", &sNotifyOnTimer, PR_TRUE); // -1 means never. nsContentUtils::AddIntPrefVarCache("content.notify.backoffcount", &sBackoffCount, -1); // The gNotificationInterval 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. nsContentUtils::AddIntPrefVarCache("content.notify.interval", &sNotificationInterval, 120000); nsContentUtils::AddIntPrefVarCache("content.sink.interactive_deflect_count", &sInteractiveDeflectCount, 0); nsContentUtils::AddIntPrefVarCache("content.sink.perf_deflect_count", &sPerfDeflectCount, 200); nsContentUtils::AddIntPrefVarCache("content.sink.pending_event_mode", &sPendingEventMode, 1); nsContentUtils::AddIntPrefVarCache("content.sink.event_probe_rate", &sEventProbeRate, 1); nsContentUtils::AddIntPrefVarCache("content.sink.interactive_parse_time", &sInteractiveParseTime, 3000); nsContentUtils::AddIntPrefVarCache("content.sink.perf_parse_time", &sPerfParseTime, 360000); nsContentUtils::AddIntPrefVarCache("content.sink.interactive_time", &sInteractiveTime, 750000); nsContentUtils::AddIntPrefVarCache("content.sink.initial_perf_time", &sInitialPerfTime, 2000000); nsContentUtils::AddIntPrefVarCache("content.sink.enable_perf_mode", &sEnablePerfMode, 0); nsContentUtils::AddBoolPrefVarCache("content.interrupt.parsing", &sCanInterruptParser, PR_TRUE); } 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; mDocShell = do_QueryInterface(aContainer); if (mDocShell) { PRUint32 loadType = 0; mDocShell->GetLoadType(&loadType); mDocument->SetChangeScrollPosWhenScrollingToRef( (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(); mBackoffCount = sBackoffCount; if (sEnablePerfMode != 0) { mDynamicLowerValue = sEnablePerfMode == 1; FavorPerformanceHint(!mDynamicLowerValue, 0); } mCanInterruptParser = sCanInterruptParser; return NS_OK; } NS_IMETHODIMP nsContentSink::StyleSheetLoaded(nsCSSStyleSheet* 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 ScrollToRef(); } mScriptLoader->RemoveExecuteBlocker(); } return NS_OK; } NS_IMETHODIMP nsContentSink::ScriptAvailable(nsresult aResult, nsIScriptElement *aElement, PRBool aIsInline, nsIURI *aURI, PRInt32 aLineNo) { PRUint32 count = mScriptElements.Count(); // aElement will not be in mScriptElements if a