Bug 559315 - [HTML5] nsContentSink::Init call is slow, r=hsivonen+sicking
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Tue, 27 Apr 2010 12:57:32 +0300
changeset 41408 592ab8ae551802ff8e957a51974241a479010fe4
parent 41407 44090f6670c7dbcbf3a7fb572708b5965be54ec9
child 41409 ca431b0a982c417fab797d0a2bf25e9f818aeb27
push idunknown
push userunknown
push dateunknown
reviewershsivonen
bugs559315
milestone1.9.3a5pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
Bug 559315 - [HTML5] nsContentSink::Init call is slow, r=hsivonen+sicking
content/base/public/nsContentUtils.h
content/base/src/nsContentSink.cpp
content/base/src/nsContentSink.h
content/base/src/nsContentUtils.cpp
layout/build/nsLayoutStatics.cpp
--- a/content/base/public/nsContentUtils.h
+++ b/content/base/public/nsContentUtils.h
@@ -578,18 +578,20 @@ public:
   static nsAdoptingString GetLocalizedStringPref(const char *aPref);
   static nsAdoptingString GetStringPref(const char *aPref);
   static void RegisterPrefCallback(const char *aPref,
                                    PrefChangedFunc aCallback,
                                    void * aClosure);
   static void UnregisterPrefCallback(const char *aPref,
                                      PrefChangedFunc aCallback,
                                      void * aClosure);
-  static void AddBoolPrefVarCache(const char* aPref, PRBool* aVariable);
-  static void AddIntPrefVarCache(const char* aPref, PRInt32* aVariable);
+  static void AddBoolPrefVarCache(const char* aPref, PRBool* aVariable,
+                                  PRBool aDefault = PR_FALSE);
+  static void AddIntPrefVarCache(const char* aPref, PRInt32* aVariable,
+                                 PRInt32 aDefault = 0);
   static nsIPrefBranch2 *GetPrefBranch()
   {
     return sPrefBranch;
   }
 
   static nsILineBreaker* LineBreaker()
   {
     return sLineBreaker;
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -211,16 +211,70 @@ 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);
+  // -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");
@@ -249,59 +303,24 @@ nsContentSink::Init(nsIDocument* aDoc,
   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);
+  mBackoffCount = sBackoffCount;
 
-  mInteractiveDeflectCount =
-    nsContentUtils::GetIntPref("content.sink.interactive_deflect_count", 0);
-  mPerfDeflectCount =
-    nsContentUtils::GetIntPref("content.sink.perf_deflect_count", 200);
-  mPendingEventMode =
-    nsContentUtils::GetIntPref("content.sink.pending_event_mode", 1);
-  mEventProbeRate =
-    nsContentUtils::GetIntPref("content.sink.event_probe_rate", 1);
-  mInteractiveParseTime =
-    nsContentUtils::GetIntPref("content.sink.interactive_parse_time", 3000);
-  mPerfParseTime =
-    nsContentUtils::GetIntPref("content.sink.perf_parse_time", 360000);
-  mInteractiveTime =
-    nsContentUtils::GetIntPref("content.sink.interactive_time", 750000);
-  mInitialPerfTime =
-    nsContentUtils::GetIntPref("content.sink.initial_perf_time", 2000000);
-  mEnablePerfMode =
-    nsContentUtils::GetIntPref("content.sink.enable_perf_mode", 0);
-
-  if (mEnablePerfMode != 0) {
-    mDynamicLowerValue = mEnablePerfMode == 1;
+  if (sEnablePerfMode != 0) {
+    mDynamicLowerValue = sEnablePerfMode == 1;
     FavorPerformanceHint(!mDynamicLowerValue, 0);
   }
 
-  mCanInterruptParser =
-    nsContentUtils::GetBoolPref("content.interrupt.parsing", PR_TRUE);
+  mCanInterruptParser = sCanInterruptParser;
 
   return NS_OK;
 
 }
 
 NS_IMETHODIMP
 nsContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet,
                                 PRBool aWasAlternate,
@@ -390,17 +409,17 @@ nsContentSink::ScriptAvailable(nsresult 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsContentSink::ScriptEvaluated(nsresult aResult,
                                nsIScriptElement *aElement,
                                PRBool aIsInline)
 {
-  mDeflectedCount = mPerfDeflectCount;
+  mDeflectedCount = sPerfDeflectCount;
 
   // Check if this is the element we were waiting for
   PRInt32 count = mScriptElements.Count();
   if (count == 0 || aElement != mScriptElements[count - 1]) {
     return NS_OK;
   }
 
   NS_ASSERTION(!aElement->GetScriptDeferred(), "defer script was in mScriptElements");
@@ -1396,17 +1415,17 @@ nsContentSink::Notify(nsITimer *timer)
 
   mNotificationTimer = nsnull;
   return NS_OK;
 }
 
 PRBool
 nsContentSink::IsTimeToNotify()
 {
-  if (!mNotifyOnTimer || !mLayoutStarted || !mBackoffCount ||
+  if (!sNotifyOnTimer || !mLayoutStarted || !mBackoffCount ||
       mInMonolithicContainer) {
     return PR_FALSE;
   }
 
   if (WaitForPendingSheets()) {
     mDeferredFlushTags = PR_TRUE;
     return PR_FALSE;
   }
@@ -1430,17 +1449,17 @@ nsContentSink::WillInterruptImpl()
 {
   nsresult result = NS_OK;
 
   SINK_TRACE(gContentSinkLogModuleInfo, SINK_TRACE_CALLS,
              ("nsContentSink::WillInterrupt: this=%p", this));
 #ifndef SINK_NO_INCREMENTAL
   if (WaitForPendingSheets()) {
     mDeferredFlushTags = PR_TRUE;
-  } else if (mNotifyOnTimer && mLayoutStarted) {
+  } else if (sNotifyOnTimer && mLayoutStarted) {
     if (mBackoffCount && !mInMonolithicContainer) {
       PRInt64 now = PR_Now();
       PRInt64 interval = GetNotificationInterval();
       PRInt64 diff = now - mLastNotificationTime;
 
       // If it's already time for us to have a notification
       if (diff > interval || mDroppedTimer) {
         mBackoffCount--;
@@ -1509,37 +1528,37 @@ nsContentSink::DidProcessATokenImpl()
   // Get the current user event time
   nsIPresShell *shell = mDocument->GetPrimaryShell();
   if (!shell) {
     // If there's no pres shell in the document, return early since
     // we're not laying anything out here.
     return NS_OK;
   }
 
-  // Increase before comparing to mEventProbeRate
+  // Increase before comparing to gEventProbeRate
   ++mDeflectedCount;
 
   // Check if there's a pending event
-  if (mPendingEventMode != 0 && !mHasPendingEvent &&
-      (mDeflectedCount % mEventProbeRate) == 0) {
+  if (sPendingEventMode != 0 && !mHasPendingEvent &&
+      (mDeflectedCount % sEventProbeRate) == 0) {
     nsIViewManager* vm = shell->GetViewManager();
     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
     nsCOMPtr<nsIWidget> widget;
     vm->GetRootWidget(getter_AddRefs(widget));
     mHasPendingEvent = widget && widget->HasPendingInputEvent();
   }
 
-  if (mHasPendingEvent && mPendingEventMode == 2) {
+  if (mHasPendingEvent && sPendingEventMode == 2) {
     return NS_ERROR_HTMLPARSER_INTERRUPTED;
   }
 
   // Have we processed enough tokens to check time?
   if (!mHasPendingEvent &&
-      mDeflectedCount < (mDynamicLowerValue ? mInteractiveDeflectCount :
-                                              mPerfDeflectCount)) {
+      mDeflectedCount < PRUint32(mDynamicLowerValue ? sInteractiveDeflectCount :
+                                                      sPerfDeflectCount)) {
     return NS_OK;
   }
 
   mDeflectedCount = 0;
 
   // Check if it's time to return to the main event loop
   if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime) {
     return NS_ERROR_HTMLPARSER_INTERRUPTED;
@@ -1677,37 +1696,37 @@ nsContentSink::WillParseImpl(void)
 
   nsIPresShell *shell = mDocument->GetPrimaryShell();
   if (!shell) {
     return NS_OK;
   }
 
   PRUint32 currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
 
-  if (mEnablePerfMode == 0) {
+  if (sEnablePerfMode == 0) {
     nsIViewManager* vm = shell->GetViewManager();
     NS_ENSURE_TRUE(vm, NS_ERROR_FAILURE);
     PRUint32 lastEventTime;
     vm->GetLastUserEventTime(lastEventTime);
 
     PRBool newDynLower =
-      (currentTime - mBeginLoadTime) > mInitialPerfTime &&
-      (currentTime - lastEventTime) < mInteractiveTime;
+      (currentTime - mBeginLoadTime) > PRUint32(sInitialPerfTime) &&
+      (currentTime - lastEventTime) < PRUint32(sInteractiveTime);
     
     if (mDynamicLowerValue != newDynLower) {
       FavorPerformanceHint(!newDynLower, 0);
       mDynamicLowerValue = newDynLower;
     }
   }
   
   mDeflectedCount = 0;
   mHasPendingEvent = PR_FALSE;
 
   mCurrentParseEndTime = currentTime +
-    (mDynamicLowerValue ? mInteractiveParseTime : mPerfParseTime);
+    (mDynamicLowerValue ? sInteractiveParseTime : sPerfParseTime);
 
   return NS_OK;
 }
 
 void
 nsContentSink::WillBuildModelImpl()
 {
   if (mCanInterruptParser) {
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -147,16 +147,18 @@ class nsContentSink : public nsICSSLoade
   // nsIDocumentObserver
   virtual void BeginUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType);
   virtual void EndUpdate(nsIDocument *aDocument, nsUpdateType aUpdateType);
 
   virtual void UpdateChildCounts() = 0;
 
   PRBool IsTimeToNotify();
 
+  static void InitializeStatics();
+
 protected:
   nsContentSink();
   virtual ~nsContentSink();
 
   enum CacheSelectionAction {
     // There is no offline cache manifest specified by the document,
     // or the document was loaded from a cache other than the one it
     // specifies via its manifest attribute and IS NOT a top-level
@@ -273,17 +275,17 @@ protected:
   FavorPerformanceHint(PRBool perfOverStarvation, PRUint32 starvationDelay);
 
   inline PRInt32 GetNotificationInterval()
   {
     if (mDynamicLowerValue) {
       return 1000;
     }
 
-    return mNotificationInterval;
+    return sNotificationInterval;
   }
 
   // Overridable hooks into script evaluation
   virtual void PreEvaluateScript()                            {return;}
   virtual void PostEvaluateScript(nsIScriptElement *aElement) {return;}
 
   virtual nsresult FlushTags() = 0;
 
@@ -313,29 +315,23 @@ protected:
 
   nsCOMArray<nsIScriptElement> mScriptElements;
 
   nsCString mRef; // ScrollTo #ref
 
   // back off timer notification after count
   PRInt32 mBackoffCount;
 
-  // Notification interval in microseconds
-  PRInt32 mNotificationInterval;
-
   // Time of last notification
   // Note: mLastNotificationTime is only valid once mLayoutStarted is true.
   PRTime mLastNotificationTime;
 
   // Timer used for notification
   nsCOMPtr<nsITimer> mNotificationTimer;
 
-  // Do we notify based on time?
-  PRPackedBool mNotifyOnTimer;
-
   // Have we already called BeginUpdate for this set of content changes?
   PRUint8 mBeganUpdate : 1;
   PRUint8 mLayoutStarted : 1;
   PRUint8 mScrolledToRefAlready : 1;
   PRUint8 mCanInterruptParser : 1;
   PRUint8 mDynamicLowerValue : 1;
   PRUint8 mParsing : 1;
   PRUint8 mDroppedTimer : 1;
@@ -352,61 +348,63 @@ protected:
   //
   // -- Can interrupt parsing members --
   //
 
   // The number of tokens that have been processed since we measured
   // if it's time to return to the main event loop.
   PRUint32 mDeflectedCount;
 
-  // How many times to deflect in interactive/perf modes
-  PRUint32 mInteractiveDeflectCount;
-  PRUint32 mPerfDeflectCount;
-
-  // 0 = don't check for pending events
-  // 1 = don't deflect if there are pending events
-  // 2 = bail if there are pending events
-  PRUint32 mPendingEventMode;
-
-  // How often to probe for pending events. 1=every token
-  PRUint32 mEventProbeRate;
-
   // Is there currently a pending event?
   PRBool mHasPendingEvent;
 
   // When to return to the main event loop
   PRUint32 mCurrentParseEndTime;
 
-  // How long to stay off the event loop in interactive/perf modes
-  PRUint32 mInteractiveParseTime;
-  PRUint32 mPerfParseTime;
-
-  // How long to be in interactive mode after an event
-  PRUint32 mInteractiveTime;
-  // How long to stay in perf mode after initial loading
-  PRUint32 mInitialPerfTime;
-
-  // Should we switch between perf-mode and interactive-mode
-  PRBool mEnablePerfMode;
-
   PRInt32 mBeginLoadTime;
 
   // Last mouse event or keyboard event time sampled by the content
   // sink
   PRUint32 mLastSampledUserEventTime;
 
   PRInt32 mInMonolithicContainer;
 
   PRInt32 mInNotification;
   PRUint32 mUpdatesInNotification;
 
   PRUint32 mPendingSheetCount;
 
   nsRevocableEventPtr<nsRunnableMethod<nsContentSink, void, false> >
     mProcessLinkHeaderEvent;
+
+  // Do we notify based on time?
+  static PRBool sNotifyOnTimer;
+  // Back off timer notification after count.
+  static PRInt32 sBackoffCount;
+  // Notification interval in microseconds
+  static PRInt32 sNotificationInterval;
+  // How many times to deflect in interactive/perf modes
+  static PRInt32 sInteractiveDeflectCount;
+  static PRInt32 sPerfDeflectCount;
+  // 0 = don't check for pending events
+  // 1 = don't deflect if there are pending events
+  // 2 = bail if there are pending events
+  static PRInt32 sPendingEventMode;
+  // How often to probe for pending events. 1=every token
+  static PRInt32 sEventProbeRate;
+  // How long to stay off the event loop in interactive/perf modes
+  static PRInt32 sInteractiveParseTime;
+  static PRInt32 sPerfParseTime;
+  // How long to be in interactive mode after an event
+  static PRInt32 sInteractiveTime;
+  // How long to stay in perf mode after initial loading
+  static PRInt32 sInitialPerfTime;
+  // Should we switch between perf-mode and interactive-mode
+  static PRInt32 sEnablePerfMode;
+  static PRBool sCanInterruptParser;
 };
 
 // sanitizing content sink whitelists
 extern PRBool IsAttrURI(nsIAtom *aName);
 extern nsIAtom** const kDefaultAllowedTags [];
 extern nsIAtom** const kDefaultAllowedAttributes [];
 
 #endif // _nsContentSink_h_
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -326,26 +326,38 @@ nsPrefOldCallback::Observe(nsISupports  
 {
   NS_ASSERTION(!strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID),
                "invalid topic");
   mCallback(NS_LossyConvertUTF16toASCII(aData).get(), mClosure);
 
   return NS_OK;
 }
 
+struct PrefCacheData {
+  void* cacheLocation;
+  union {
+    PRBool defaultValueBool;
+    PRInt32 defaultValueInt;
+  };
+};
+
+nsTArray<nsAutoPtr<PrefCacheData> >* sPrefCacheData = nsnull;
+
 // static
 nsresult
 nsContentUtils::Init()
 {
   if (sInitialized) {
     NS_WARNING("Init() called twice");
 
     return NS_OK;
   }
 
+  sPrefCacheData = new nsTArray<nsAutoPtr<PrefCacheData> >();
+
   nsresult rv = CallGetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID,
                                &sSecurityManager);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // It's ok to not have a pref service.
   CallGetService(NS_PREFSERVICE_CONTRACTID, &sPrefBranch);
 
   rv = NS_GetNameSpaceManager(&sNameSpaceManager);
@@ -949,16 +961,19 @@ nsContentUtils::Shutdown()
       if (sPrefBranch)
         sPrefBranch->RemoveObserver(callback->mPref.get(), callback);
       sPrefCallbackList->RemoveObject(callback);
     }
     delete sPrefCallbackList;
     sPrefCallbackList = nsnull;
   }
 
+  delete sPrefCacheData;
+  sPrefCacheData = nsnull;
+
   NS_IF_RELEASE(sStringBundleService);
   NS_IF_RELEASE(sConsoleService);
   NS_IF_RELEASE(sDOMScriptObjectFactory);
   if (sJSGCThingRootCount == 0 && sXPConnect)
     NS_RELEASE(sXPConnect);
   NS_IF_RELEASE(sSecurityManager);
   NS_IF_RELEASE(sThreadJSContextStack);
   NS_IF_RELEASE(sNameSpaceManager);
@@ -2691,45 +2706,57 @@ nsContentUtils::UnregisterPrefCallback(c
       }
     }
   }
 }
 
 static int
 BoolVarChanged(const char *aPref, void *aClosure)
 {
-  PRBool* cache = static_cast<PRBool*>(aClosure);
-  *cache = nsContentUtils::GetBoolPref(aPref, PR_FALSE);
+  PrefCacheData* cache = static_cast<PrefCacheData*>(aClosure);
+  *((PRBool*)cache->cacheLocation) =
+    nsContentUtils::GetBoolPref(aPref, cache->defaultValueBool);
   
   return 0;
 }
 
 void
 nsContentUtils::AddBoolPrefVarCache(const char *aPref,
-                                    PRBool* aCache)
-{
-  *aCache = GetBoolPref(aPref, PR_FALSE);
-  RegisterPrefCallback(aPref, BoolVarChanged, aCache);
+                                    PRBool* aCache,
+                                    PRBool aDefault)
+{
+  *aCache = GetBoolPref(aPref, aDefault);
+  PrefCacheData* data = new PrefCacheData;
+  data->cacheLocation = aCache;
+  data->defaultValueBool = aDefault;
+  sPrefCacheData->AppendElement(data);
+  RegisterPrefCallback(aPref, BoolVarChanged, data);
 }
 
 static int
 IntVarChanged(const char *aPref, void *aClosure)
 {
-  PRInt32* cache = static_cast<PRInt32*>(aClosure);
-  *cache = nsContentUtils::GetIntPref(aPref, 0);
+  PrefCacheData* cache = static_cast<PrefCacheData*>(aClosure);
+  *((PRInt32*)cache->cacheLocation) =
+    nsContentUtils::GetIntPref(aPref, cache->defaultValueInt);
   
   return 0;
 }
 
 void
 nsContentUtils::AddIntPrefVarCache(const char *aPref,
-                                   PRInt32* aCache)
-{
-  *aCache = GetIntPref(aPref, PR_FALSE);
-  RegisterPrefCallback(aPref, IntVarChanged, aCache);
+                                   PRInt32* aCache,
+                                   PRInt32 aDefault)
+{
+  *aCache = GetIntPref(aPref, aDefault);
+  PrefCacheData* data = new PrefCacheData;
+  data->cacheLocation = aCache;
+  data->defaultValueInt = aDefault;
+  sPrefCacheData->AppendElement(data);
+  RegisterPrefCallback(aPref, IntVarChanged, data);
 }
 
 static const char *gEventNames[] = {"event"};
 static const char *gSVGEventNames[] = {"evt"};
 // for b/w compat, the first name to onerror is still 'event', even though it
 // is actually the error message.  (pre this code, the other 2 were not avail.)
 // XXXmarkh - a quick lxr shows no affected code - should we correct this?
 static const char *gOnErrorNames[] = {"event", "source", "lineno"};
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -125,16 +125,17 @@ PRBool NS_SVGEnabled();
 #include "nsAudioStream.h"
 #endif
 
 #include "nsError.h"
 #include "nsTraceRefcnt.h"
 
 #include "nsCycleCollector.h"
 #include "nsJSEnvironment.h"
+#include "nsContentSink.h"
 
 extern void NS_ShutdownChainItemPool();
 
 static nsrefcnt sLayoutStaticRefcnt;
 
 nsresult
 nsLayoutStatics::Initialize()
 {
@@ -278,16 +279,17 @@ nsLayoutStatics::Initialize()
 #ifdef MOZ_MEDIA
   nsHTMLMediaElement::InitMediaTypes();
 #endif
 
 #ifdef MOZ_SYDNEYAUDIO
   nsAudioStream::InitLibrary();
 #endif
 
+  nsContentSink::InitializeStatics();
   nsHtml5Module::InitializeStatics();
   
   nsCrossSiteListenerProxy::Startup();
 
   rv = nsFrameList::Init();
   if (NS_FAILED(rv)) {
     NS_ERROR("Could not initialize nsFrameList");
     return rv;