Stop blocking the parser on CSS stylesheet loads. We still block scriptexecution on them, however. Bug 84582, r+sr=sicking
authorbzbarsky@mit.edu
Fri, 20 Apr 2007 15:59:18 -0700
changeset 681 fb50922e48409e73e9a023871754252a78830ec9
parent 680 9540f037b7a998f6f72c7dad3133db2c72e438c7
child 682 f239f36b293915fe035222113092c7963cbbb318
push idunknown
push userunknown
push dateunknown
bugs84582
milestone1.9a4pre
Stop blocking the parser on CSS stylesheet loads. We still block scriptexecution on them, however. Bug 84582, r+sr=sicking
content/base/public/nsIStyleSheetLinkingElement.h
content/base/src/nsContentSink.cpp
content/base/src/nsContentSink.h
content/base/src/nsStyleLinkElement.cpp
content/base/src/nsStyleLinkElement.h
content/html/content/src/nsHTMLLinkElement.cpp
content/html/content/src/nsHTMLStyleElement.cpp
content/html/document/src/nsHTMLContentSink.cpp
content/svg/content/src/nsSVGStyleElement.cpp
content/xbl/src/nsXBLContentSink.cpp
content/xbl/src/nsXBLContentSink.h
content/xml/content/src/nsXMLStylesheetPI.cpp
content/xml/document/src/nsXMLContentSink.cpp
content/xml/document/src/nsXMLContentSink.h
content/xml/document/src/nsXMLFragmentContentSink.cpp
content/xslt/src/xslt/txMozillaXMLOutput.cpp
content/xslt/src/xslt/txMozillaXMLOutput.h
content/xul/document/src/nsXULContentSink.cpp
content/xul/document/src/nsXULContentSink.h
content/xul/document/src/nsXULDocument.cpp
layout/style/nsCSSLoader.cpp
layout/style/nsCSSLoader.h
layout/style/nsICSSLoader.h
parser/htmlparser/src/nsViewSourceHTML.cpp
--- a/content/base/public/nsIStyleSheetLinkingElement.h
+++ b/content/base/public/nsIStyleSheetLinkingElement.h
@@ -35,24 +35,23 @@
  *
  * ***** END LICENSE BLOCK ***** */
 #ifndef nsIStyleSheetLinkingElement_h__
 #define nsIStyleSheetLinkingElement_h__
 
 
 #include "nsISupports.h"
 
-class nsIParser;
 class nsIDocument;
 class nsICSSLoaderObserver;
 class nsIURI;
 
 #define NS_ISTYLESHEETLINKINGELEMENT_IID          \
-  {0x259f8226, 0x8dd7, 0x11db,                    \
-  {0x98, 0x5e, 0x92, 0xb7, 0x56, 0xd8, 0x95, 0x93}}
+{ 0xd753c84a, 0x17fd, 0x4d5f, \
+ { 0xb2, 0xe9, 0x63, 0x52, 0x8c, 0x87, 0x99, 0x7a } }
 
 class nsIStyleSheet;
 
 class nsIStyleSheetLinkingElement : public nsISupports {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISTYLESHEETLINKINGELEMENT_IID)
 
   /**
@@ -68,39 +67,40 @@ public:
    * Used to obtain the style sheet linked in by this element.
    *
    * @param aStyleSheet out parameter that returns the style
    *                    sheet associated with this element.
    */
   NS_IMETHOD GetStyleSheet(nsIStyleSheet*& aStyleSheet) = 0;
 
   /**
-   * Initialize the stylesheet linking element. This method passes
-   * in a parser that the element blocks if the stylesheet is
-   * a stylesheet that should be loaded with the parser blocked.
-   * If aDontLoadStyle is true the element will ignore the first
-   * modification to the element that would cause a stylesheet to
-   * be loaded. Subsequent modifications to the element will not
-   * be ignored.
+   * Initialize the stylesheet linking element. If aDontLoadStyle is
+   * true the element will ignore the first modification to the
+   * element that would cause a stylesheet to be loaded. Subsequent
+   * modifications to the element will not be ignored.
    */
-  NS_IMETHOD InitStyleLinkElement(nsIParser *aParser, PRBool aDontLoadStyle) = 0;
+  NS_IMETHOD InitStyleLinkElement(PRBool aDontLoadStyle) = 0;
 
   /**
    * Tells this element to update the stylesheet.
    *
-   * @param aOldDocument the document that this element was part
-   *                     of (nsnull if we're not moving the element
-   *                     from one document to another).
    * @param aObserver    observer to notify once the stylesheet is loaded.
-   *                     It might be notified before the function returns.
-   * @param aForceUpdate If true, force the update even if the URI did not change
+   *                     This will be passed to the CSSLoader
+   * @param [out] aWillNotify whether aObserver will be notified when the sheet
+   *                          loads.  If this is false, then either we didn't
+   *                          start the sheet load at all, the load failed, or
+   *                          this was an inline sheet that completely finished
+   *                          loading.  In the case when the load failed the
+   *                          failure code will be returned.
+   * @param [out] whether the sheet is an alternate sheet.  This value is only
+   *              meaningful if aWillNotify is true.
    */
-  NS_IMETHOD UpdateStyleSheet(nsIDocument *aOldDocument,
-                              nsICSSLoaderObserver* aObserver,
-                              PRBool aForceUpdate = PR_FALSE) = 0;
+  NS_IMETHOD UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
+                              PRBool *aWillNotify,
+                              PRBool *aIsAlternate) = 0;
 
   /**
    * Tells this element whether to update the stylesheet when the
    * element's properties change.
    *
    * @param aEnableUpdates update on changes or not.
    */
   NS_IMETHOD SetEnableUpdates(PRBool aEnableUpdates) = 0;
--- a/content/base/src/nsContentSink.cpp
+++ b/content/base/src/nsContentSink.cpp
@@ -84,22 +84,16 @@
 #include "nsIDOMNSDocument.h"
 #include "nsIRequest.h"
 #include "nsNodeUtils.h"
 #include "nsIDOMNode.h"
 #include "nsThreadUtils.h"
 
 PRLogModuleInfo* gContentSinkLogModuleInfo;
 
-#ifdef ALLOW_ASYNCH_STYLE_SHEETS
-const PRBool kBlockByDefault = PR_FALSE;
-#else
-const PRBool kBlockByDefault = PR_TRUE;
-#endif
-
 class nsScriptLoaderObserverProxy : public nsIScriptLoaderObserver
 {
 public:
   nsScriptLoaderObserverProxy(nsIScriptLoaderObserver* aInner)
     : mInner(do_GetWeakReference(aInner))
   {
   }
   virtual ~nsScriptLoaderObserverProxy()
@@ -157,16 +151,17 @@ nsContentSink::nsContentSink()
   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
 }
 
@@ -199,19 +194,19 @@ nsContentSink::Init(nsIDocument* aDoc,
       ((loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
   }
 
   // use this to avoid a circular reference sink->document->scriptloader->sink
   nsCOMPtr<nsIScriptLoaderObserver> proxy =
       new nsScriptLoaderObserverProxy(this);
   NS_ENSURE_TRUE(proxy, NS_ERROR_OUT_OF_MEMORY);
 
-  nsScriptLoader *loader = mDocument->GetScriptLoader();
-  NS_ENSURE_TRUE(loader, NS_ERROR_FAILURE);
-  loader->AddObserver(proxy);
+  mScriptLoader = mDocument->GetScriptLoader();
+  NS_ENSURE_TRUE(mScriptLoader, NS_ERROR_FAILURE);
+  mScriptLoader->AddObserver(proxy);
 
   mCSSLoader = aDoc->CSSLoader();
 
   ProcessHTTPHeaders(aChannel);
 
   mNodeInfoManager = aDoc->NodeInfoManager();
 
   mNotifyOnTimer =
@@ -260,16 +255,36 @@ nsContentSink::Init(nsIDocument* aDoc,
 
 }
 
 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) {
+      // 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,
@@ -477,17 +492,16 @@ nsContentSink::ProcessLinkHeader(nsICont
   nsresult rv = NS_OK;
 
   // parse link content and call process style link
   nsAutoString href;
   nsAutoString rel;
   nsAutoString title;
   nsAutoString type;
   nsAutoString media;
-  PRBool didBlock = PR_FALSE;
 
   // copy to work buffer
   nsAutoString stringList(aLinkData);
 
   // put an extra null at the end
   stringList.Append(kNullCh);
 
   PRUnichar* start = stringList.BeginWriting();
@@ -616,37 +630,30 @@ nsContentSink::ProcessLinkHeader(nsICont
       }
     }
 
     if (endCh == kCommaCh) {
       // hit a comma, process what we've got so far
 
       if (!href.IsEmpty() && !rel.IsEmpty()) {
         rv = ProcessLink(aElement, href, rel, title, type, media);
-        if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
-          didBlock = PR_TRUE;
-        }
       }
 
       href.Truncate();
       rel.Truncate();
       title.Truncate();
       type.Truncate();
       media.Truncate();
     }
 
     start = ++end;
   }
 
   if (!href.IsEmpty() && !rel.IsEmpty()) {
     rv = ProcessLink(aElement, href, rel, title, type, media);
-
-    if (NS_SUCCEEDED(rv) && didBlock) {
-      rv = NS_ERROR_HTMLPARSER_BLOCK;
-    }
   }
 
   return rv;
 }
 
 
 nsresult
 nsContentSink::ProcessLink(nsIContent* aElement,
@@ -705,29 +712,27 @@ nsContentSink::ProcessStyleLink(nsIConte
   nsCOMPtr<nsIURI> url;
   nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nsnull, mDocumentBaseURI);
   
   if (NS_FAILED(rv)) {
     // The URI is bad, move along, don't propagate the error (for now)
     return NS_OK;
   }
 
-  nsIParser* parser = nsnull;
-  if (kBlockByDefault) {
-    parser = mParser;
-  }
-  
   PRBool isAlternate;
   rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate,
-                                 parser, this, &isAlternate);
-  if (NS_SUCCEEDED(rv) && parser && !isAlternate) {
-    rv = NS_ERROR_HTMLPARSER_BLOCK;
+                                 this, &isAlternate);
+  NS_ENSURE_SUCCESS(rv, rv);
+  
+  if (!isAlternate) {
+    ++mPendingSheetCount;
+    mScriptLoader->AddExecuteBlocker();
   }
 
-  return rv;
+  return NS_OK;
 }
 
 
 nsresult
 nsContentSink::ProcessMETATag(nsIContent* aContent)
 {
   NS_ASSERTION(aContent, "missing base-element");
 
@@ -876,20 +881,35 @@ nsContentSink::RefreshIfEnabled(nsIViewM
       vm->EnableRefresh(NS_VMREFRESH_IMMEDIATE);
     }
   }
 
   return NS_OK;
 }
 
 void
-nsContentSink::StartLayout(PRBool aIsFrameset)
+nsContentSink::StartLayout(PRBool aIgnorePendingSheets)
 {
+  if (mLayoutStarted) {
+    // Nothing to do here
+    return;
+  }
+  
+  mDeferredLayoutStart = PR_TRUE;
+
+  if (!aIgnorePendingSheets && mPendingSheetCount > 0) {
+    // Bail out; we'll start layout when the sheets load
+    return;
+  }
+
+  mDeferredLayoutStart = PR_FALSE;
+
   mLayoutStarted = PR_TRUE;
   mLastNotificationTime = PR_Now();
+  
   PRUint32 i, ns = mDocument->GetNumberOfShells();
   for (i = 0; i < ns; i++) {
     nsIPresShell *shell = mDocument->GetShellAt(i);
 
     if (shell) {
       // Make sure we don't call InitialReflow() for a shell that has
       // already called it. This can happen when the layout frame for
       // an iframe is constructed *between* the Embed() call for the
--- a/content/base/src/nsContentSink.h
+++ b/content/base/src/nsContentSink.h
@@ -69,16 +69,17 @@ class nsIChannel;
 class nsIDocShell;
 class nsICSSLoader;
 class nsIParser;
 class nsIAtom;
 class nsIChannel;
 class nsIContent;
 class nsIViewManager;
 class nsNodeInfoManager;
+class nsScriptLoader;
 
 #ifdef NS_DEBUG
 
 extern PRLogModuleInfo* gContentSinkLogModuleInfo;
 
 #define SINK_TRACE_CALLS              0x1
 #define SINK_TRACE_REFLOW             0x2
 #define SINK_ALWAYS_REFLOW            0x4
@@ -164,17 +165,21 @@ protected:
                                     const nsSubstring& aTitle,
                                     const nsSubstring& aType,
                                     const nsSubstring& aMedia);
 
   void PrefetchHref(const nsAString &aHref, PRBool aExplicit, PRBool aOffline);
 
   void ScrollToRef();
   nsresult RefreshIfEnabled(nsIViewManager* vm);
-  void StartLayout(PRBool aIsFrameset);
+
+  // Start layout.  If aIgnorePendingSheets is true, this will happen even if
+  // we still have stylesheet loads pending.  Otherwise, we'll wait until the
+  // stylesheets are all done loading.
+  void StartLayout(PRBool aIgnorePendingSheets);
 
   PRBool IsTimeToNotify();
 
   void
   FavorPerformanceHint(PRBool perfOverStarvation, PRUint32 starvationDelay);
 
   inline PRInt32 GetNotificationInterval()
   {
@@ -214,28 +219,30 @@ protected:
 
   nsCOMPtr<nsIDocument>         mDocument;
   nsCOMPtr<nsIParser>           mParser;
   nsCOMPtr<nsIURI>              mDocumentURI;
   nsCOMPtr<nsIURI>              mDocumentBaseURI;
   nsCOMPtr<nsIDocShell>         mDocShell;
   nsCOMPtr<nsICSSLoader>        mCSSLoader;
   nsRefPtr<nsNodeInfoManager>   mNodeInfoManager;
+  nsRefPtr<nsScriptLoader>      mScriptLoader;
 
   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;
 
   // The number of tokens that have been processed while in the low
   // frequency parser interrupt mode without falling through to the
   // logic which decides whether to switch to the high frequency
@@ -250,16 +257,18 @@ protected:
   PRUint8 mLayoutStarted : 1;
   PRUint8 mScrolledToRefAlready : 1;
   PRUint8 mCanInterruptParser : 1;
   PRUint8 mDynamicLowerValue : 1;
   PRUint8 mParsing : 1;
   PRUint8 mDroppedTimer : 1;
   PRUint8 mInTitle : 1;
   PRUint8 mChangeScrollPosWhenScrollingToRef : 1;
+  // If true, we deferred starting layout until sheets load
+  PRUint8 mDeferredLayoutStart : 1;
   
   // -- Can interrupt parsing members --
   PRUint32 mDelayTimerStart;
 
   // Interrupt parsing during token procesing after # of microseconds
   PRInt32 mMaxTokenProcessingTime;
 
   // Switch between intervals when time is exceeded
@@ -270,16 +279,18 @@ protected:
   // Last mouse event or keyboard event time sampled by the content
   // sink
   PRUint32 mLastSampledUserEventTime;
 
   PRInt32 mInMonolithicContainer;
 
   PRInt32 mInNotification;
 
+  PRUint32 mPendingSheetCount;
+
   // Measures content model creation time for current document
   MOZ_TIMER_DECLARE(mWatch)
 };
 
 
 //
 // these two lists are used by the sanitizing fragment serializers
 // Thanks to Mark Pilgrim and Sam Ruby for the initial whitelist
--- a/content/base/src/nsStyleLinkElement.cpp
+++ b/content/base/src/nsStyleLinkElement.cpp
@@ -105,20 +105,18 @@ nsStyleLinkElement::GetStyleSheet(nsISty
 {
   aStyleSheet = mStyleSheet;
   NS_IF_ADDREF(aStyleSheet);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP 
-nsStyleLinkElement::InitStyleLinkElement(nsIParser* aParser,
-                                         PRBool aDontLoadStyle)
+nsStyleLinkElement::InitStyleLinkElement(PRBool aDontLoadStyle)
 {
-  mParser = aParser;
   mDontLoadStyle = aDontLoadStyle;
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsStyleLinkElement::GetSheet(nsIDOMStyleSheet** aSheet)
 {
@@ -192,49 +190,58 @@ void nsStyleLinkElement::ParseLinkTypes(
     ++current;
   }
   if (inString) {
     ToLowerCase(Substring(start, current), subString);
     aResult.AppendString(subString);
   }
 }
 
-#ifdef ALLOW_ASYNCH_STYLE_SHEETS
-const PRBool kBlockByDefault=PR_FALSE;
-#else
-const PRBool kBlockByDefault=PR_TRUE;
-#endif
+NS_IMETHODIMP
+nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
+                                     PRBool* aWillNotify,
+                                     PRBool* aIsAlternate)
+{
+  return DoUpdateStyleSheet(nsnull, aObserver, aWillNotify, aIsAlternate,
+                            PR_FALSE);
+}
 
-NS_IMETHODIMP
-nsStyleLinkElement::UpdateStyleSheet(nsIDocument *aOldDocument,
-                                     nsICSSLoaderObserver* aObserver,
-                                     PRBool aForceUpdate)
+nsresult
+nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument,
+                                             PRBool aForceUpdate)
 {
+  PRBool notify, alternate;
+  return DoUpdateStyleSheet(aOldDocument, nsnull, &notify, &alternate,
+                            aForceUpdate);
+}
+
+nsresult
+nsStyleLinkElement::DoUpdateStyleSheet(nsIDocument *aOldDocument,
+                                       nsICSSLoaderObserver* aObserver,
+                                       PRBool* aWillNotify,
+                                       PRBool* aIsAlternate,
+                                       PRBool aForceUpdate)
+{
+  *aWillNotify = PR_FALSE;
+
   if (mStyleSheet && aOldDocument) {
     // We're removing the link element from the document, unload the
     // stylesheet.  We want to do this even if updates are disabled, since
     // otherwise a sheet with a stale linking element pointer will be hanging
     // around -- not good!
     aOldDocument->BeginUpdate(UPDATE_STYLE);
     aOldDocument->RemoveStyleSheet(mStyleSheet);
     aOldDocument->EndUpdate(UPDATE_STYLE);
     mStyleSheet = nsnull;
   }
 
   if (mDontLoadStyle || !mUpdatesEnabled) {
     return NS_OK;
   }
 
-  // Keep a strong ref to the parser so it's still around when we pass it
-  // to the CSS loader. Release strong ref in mParser so we don't hang on
-  // to the parser once we start the load or if we fail to load the
-  // stylesheet.
-  nsCOMPtr<nsIParser> parser = mParser;
-  mParser = nsnull;
-
   nsCOMPtr<nsIContent> thisContent;
   QueryInterface(NS_GET_IID(nsIContent), getter_AddRefs(thisContent));
 
   NS_ENSURE_TRUE(thisContent, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDocument> doc = thisContent->GetDocument();
 
   if (!doc) {
@@ -273,46 +280,41 @@ nsStyleLinkElement::UpdateStyleSheet(nsI
   PRBool isAlternate;
 
   GetStyleSheetInfo(title, type, media, &isAlternate);
 
   if (!type.LowerCaseEqualsLiteral("text/css")) {
     return NS_OK;
   }
 
-  if (!kBlockByDefault) {
-    parser = nsnull;
-  }
-
-  PRBool doneLoading;
+  PRBool doneLoading = PR_FALSE;
   nsresult rv = NS_OK;
   if (isInline) {
     nsAutoString content;
     nsContentUtils::GetNodeTextContent(thisContent, PR_FALSE, content);
 
     nsCOMPtr<nsIUnicharInputStream> uin;
     rv = nsSimpleUnicharStreamFactory::GetInstance()->
       CreateInstanceFromString(content, getter_AddRefs(uin));
     if (NS_FAILED(rv)) {
       return rv;
     }
 
     // Now that we have a url and a unicode input stream, parse the
     // style sheet.
     rv = doc->CSSLoader()->
       LoadInlineStyle(thisContent, uin, mLineNumber, title, media,
-                      parser, aObserver, &doneLoading, &isAlternate);
+                      aObserver, &doneLoading, &isAlternate);
   }
   else {
-    doneLoading = PR_FALSE;  // If rv is success, we won't be done loading; if
-                             // it's not, this value doesn't matter.
     rv = doc->CSSLoader()->
-      LoadStyleLink(thisContent, uri, title, media, isAlternate,
-                    parser, aObserver, &isAlternate);
+      LoadStyleLink(thisContent, uri, title, media, isAlternate, aObserver,
+                    &isAlternate);
   }
 
-  if (NS_SUCCEEDED(rv) && !doneLoading && !isAlternate) {
-    rv = NS_ERROR_HTMLPARSER_BLOCK;
-  }
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  return rv;
+  *aWillNotify = !doneLoading;
+  *aIsAlternate = isAlternate;
+
+  return NS_OK;
 }
 
--- a/content/base/src/nsStyleLinkElement.h
+++ b/content/base/src/nsStyleLinkElement.h
@@ -45,17 +45,16 @@
 
 #ifndef nsStyleLinkElement_h___
 #define nsStyleLinkElement_h___
 
 #include "nsCOMPtr.h"
 #include "nsIDOMLinkStyle.h"
 #include "nsIStyleSheetLinkingElement.h"
 #include "nsIStyleSheet.h"
-#include "nsIParser.h"
 #include "nsIURI.h"
 
 class nsIDocument;
 class nsStringArray;
 
 class nsStyleLinkElement : public nsIDOMLinkStyle,
                            public nsIStyleSheetLinkingElement
 {
@@ -66,54 +65,63 @@ public:
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr) = 0;
 
   // nsIDOMLinkStyle
   NS_DECL_NSIDOMLINKSTYLE
 
   // nsIStyleSheetLinkingElement  
   NS_IMETHOD SetStyleSheet(nsIStyleSheet* aStyleSheet);
   NS_IMETHOD GetStyleSheet(nsIStyleSheet*& aStyleSheet);
-  NS_IMETHOD InitStyleLinkElement(nsIParser *aParser, PRBool aDontLoadStyle);
-  /**
-   * @param aForceUpdate when PR_TRUE, will force the update even if
-   * the URI has not changed.  This should be used in cases when
-   * something about the content that affects the resulting sheet
-   * changed but the URI may not have changed.
-   * @returns NS_ERROR_HTMLPARSER_BLOCK if a non-alternate style sheet
-   *          is being loaded asynchronously. In this case aObserver
-   *          will be notified at a later stage when the sheet is
-   *          loaded (if it is not null).
-   * @returns NS_OK in case when the update was successful, but the
-   *          caller doesn't have to wait for a notification to
-   *          aObserver. This can happen if there was no style sheet
-   *          to load, when it's inline, or when it's alternate. Note
-   *          that in the latter case aObserver is still notified about
-   *          the load when it's done.
-   */
-  NS_IMETHOD UpdateStyleSheet(nsIDocument *aOldDocument = nsnull,
-                              nsICSSLoaderObserver* aObserver = nsnull,
-                              PRBool aForceUpdate = PR_FALSE);
+  NS_IMETHOD InitStyleLinkElement(PRBool aDontLoadStyle);
+  NS_IMETHOD UpdateStyleSheet(nsICSSLoaderObserver* aObserver,
+                              PRBool* aWillNotify,
+                              PRBool* aIsAlternate);
   NS_IMETHOD SetEnableUpdates(PRBool aEnableUpdates);
   NS_IMETHOD GetCharset(nsAString& aCharset);
 
   virtual void OverrideBaseURI(nsIURI* aNewBaseURI);
   virtual void SetLineNumber(PRUint32 aLineNumber);
 
   static void ParseLinkTypes(const nsAString& aTypes, nsStringArray& aResult);
 
 protected:
+  /**
+   * @param aOldDocument should be non-null only if we're updating because we
+   *                     removed the node from the document.
+   * @param aForceUpdate PR_TRUE will force the update even if the URI has not
+   *                     changed.  This should be used in cases when something
+   *                     about the content that affects the resulting sheet
+   *                     changed but the URI may not have changed.
+   */
+  nsresult UpdateStyleSheetInternal(nsIDocument *aOldDocument,
+                                    PRBool aForceUpdate = PR_FALSE);
+
   virtual void GetStyleSheetURL(PRBool* aIsInline,
                                 nsIURI** aURI) = 0;
   virtual void GetStyleSheetInfo(nsAString& aTitle,
                                  nsAString& aType,
                                  nsAString& aMedia,
                                  PRBool* aIsAlternate) = 0;
 
+private:
+  /**
+   * @param aOldDocument should be non-null only if we're updating because we
+   *                     removed the node from the document.
+   * @param aForceUpdate PR_TRUE will force the update even if the URI has not
+   *                     changed.  This should be used in cases when something
+   *                     about the content that affects the resulting sheet
+   *                     changed but the URI may not have changed.
+   */
+  nsresult DoUpdateStyleSheet(nsIDocument *aOldDocument,
+                              nsICSSLoaderObserver* aObserver,
+                              PRBool* aWillNotify,
+                              PRBool* aIsAlternate,
+                              PRBool aForceUpdate);
 
+protected:
   nsCOMPtr<nsIStyleSheet> mStyleSheet;
-  nsCOMPtr<nsIParser> mParser;
   PRPackedBool mDontLoadStyle;
   PRPackedBool mUpdatesEnabled;
   PRUint32 mLineNumber;
 };
 
 #endif /* nsStyleLinkElement_h___ */
 
--- a/content/html/content/src/nsHTMLLinkElement.cpp
+++ b/content/html/content/src/nsHTMLLinkElement.cpp
@@ -200,17 +200,17 @@ nsHTMLLinkElement::BindToTree(nsIDocumen
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UpdateStyleSheet(nsnull);
+  UpdateStyleSheetInternal(nsnull);
 
   // XXXbz we really shouldn't fire the event until after we've finished with
   // the outermost BindToTree...  In particular, this can effectively cause us
   // to reenter this code, or for some part of the document to become unbound
   // inside the event!
   CreateAndDispatchEvent(aDocument, NS_LITERAL_STRING("DOMLinkAdded"));
 
   return rv;  
@@ -242,17 +242,17 @@ nsHTMLLinkElement::UnbindFromTree(PRBool
   }
 
   // XXXbz we really shouldn't fire the event until after we've finished with
   // the outermost UnbindFromTree...  In particular, this can effectively cause
   // us to reenter this code, or to be bound to a different tree inside the
   // event!
   CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved"));
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheet(oldDoc);
+  UpdateStyleSheetInternal(oldDoc);
 }
 
 void
 nsHTMLLinkElement::CreateAndDispatchEvent(nsIDocument* aDoc,
                                           const nsAString& aEventName)
 {
   if (!aDoc)
     return;
@@ -291,40 +291,40 @@ nsHTMLLinkElement::SetAttr(PRInt32 aName
         // to the link map if necessary.
     }
     SetLinkState(eLinkState_Unknown);
   }
 
   nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
                                               aValue, aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet(nsnull, nsnull,
-                     aNameSpaceID == kNameSpaceID_None &&
-                     (aName == nsGkAtoms::rel ||
-                      aName == nsGkAtoms::title ||
-                      aName == nsGkAtoms::media ||
-                      aName == nsGkAtoms::type));
+    UpdateStyleSheetInternal(nsnull,
+                             aNameSpaceID == kNameSpaceID_None &&
+                             (aName == nsGkAtoms::rel ||
+                              aName == nsGkAtoms::title ||
+                              aName == nsGkAtoms::media ||
+                              aName == nsGkAtoms::type));
   }
 
   return rv;
 }
 
 nsresult
 nsHTMLLinkElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                              PRBool aNotify)
 {
   nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
                                                 aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet(nsnull, nsnull,
-                     aNameSpaceID == kNameSpaceID_None &&
-                     (aAttribute == nsGkAtoms::rel ||
-                      aAttribute == nsGkAtoms::title ||
-                      aAttribute == nsGkAtoms::media ||
-                      aAttribute == nsGkAtoms::type));
+    UpdateStyleSheetInternal(nsnull,
+                             aNameSpaceID == kNameSpaceID_None &&
+                             (aAttribute == nsGkAtoms::rel ||
+                              aAttribute == nsGkAtoms::title ||
+                              aAttribute == nsGkAtoms::media ||
+                              aAttribute == nsGkAtoms::type));
   }
 
   return rv;
 }
 
 nsresult
 nsHTMLLinkElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
 {
--- a/content/html/content/src/nsHTMLStyleElement.cpp
+++ b/content/html/content/src/nsHTMLStyleElement.cpp
@@ -191,99 +191,99 @@ nsHTMLStyleElement::SetDisabled(PRBool a
 NS_IMPL_STRING_ATTR(nsHTMLStyleElement, Media, media)
 NS_IMPL_STRING_ATTR(nsHTMLStyleElement, Type, type)
 
 void
 nsHTMLStyleElement::CharacterDataChanged(nsIDocument* aDocument,
                                          nsIContent* aContent,
                                          CharacterDataChangeInfo* aInfo)
 {
-  UpdateStyleSheet();
+  UpdateStyleSheetInternal(nsnull);
 }
 
 void
 nsHTMLStyleElement::ContentAppended(nsIDocument* aDocument,
                                     nsIContent* aContainer,
                                     PRInt32 aNewIndexInContainer)
 {
-  UpdateStyleSheet();
+  UpdateStyleSheetInternal(nsnull);
 }
 
 void
 nsHTMLStyleElement::ContentInserted(nsIDocument* aDocument,
                                     nsIContent* aContainer,
                                     nsIContent* aChild,
                                     PRInt32 aIndexInContainer)
 {
-  UpdateStyleSheet();
+  UpdateStyleSheetInternal(nsnull);
 }
 
 void
 nsHTMLStyleElement::ContentRemoved(nsIDocument* aDocument,
                                    nsIContent* aContainer,
                                    nsIContent* aChild,
                                    PRInt32 aIndexInContainer)
 {
-  UpdateStyleSheet();
+  UpdateStyleSheetInternal(nsnull);
 }
 
 nsresult
 nsHTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                                nsIContent* aBindingParent,
                                PRBool aCompileEventHandlers)
 {
   nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent,
                                                  aBindingParent,
                                                  aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UpdateStyleSheet(nsnull);
+  UpdateStyleSheetInternal(nsnull);
 
   return rv;  
 }
 
 void
 nsHTMLStyleElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
 
   nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheet(oldDoc);
+  UpdateStyleSheetInternal(oldDoc);
 }
 
 nsresult
 nsHTMLStyleElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                             nsIAtom* aPrefix, const nsAString& aValue,
                             PRBool aNotify)
 {
   nsresult rv = nsGenericHTMLElement::SetAttr(aNameSpaceID, aName, aPrefix,
                                               aValue, aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet(nsnull, nsnull,
-                     aNameSpaceID == kNameSpaceID_None &&
-                     (aName == nsGkAtoms::title ||
-                      aName == nsGkAtoms::media ||
-                      aName == nsGkAtoms::type));
+    UpdateStyleSheetInternal(nsnull,
+                             aNameSpaceID == kNameSpaceID_None &&
+                             (aName == nsGkAtoms::title ||
+                              aName == nsGkAtoms::media ||
+                              aName == nsGkAtoms::type));
   }
 
   return rv;
 }
 
 nsresult
 nsHTMLStyleElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                               PRBool aNotify)
 {
   nsresult rv = nsGenericHTMLElement::UnsetAttr(aNameSpaceID, aAttribute,
                                                 aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet(nsnull, nsnull,
-                     aNameSpaceID == kNameSpaceID_None &&
-                     (aAttribute == nsGkAtoms::title ||
-                      aAttribute == nsGkAtoms::media ||
-                      aAttribute == nsGkAtoms::type));
+    UpdateStyleSheetInternal(nsnull,
+                             aNameSpaceID == kNameSpaceID_None &&
+                             (aAttribute == nsGkAtoms::title ||
+                              aAttribute == nsGkAtoms::media ||
+                              aAttribute == nsGkAtoms::type));
   }
 
   return rv;
 }
 
 nsresult
 nsHTMLStyleElement::GetInnerHTML(nsAString& aInnerHTML)
 {
@@ -295,17 +295,17 @@ nsresult
 nsHTMLStyleElement::SetInnerHTML(const nsAString& aInnerHTML)
 {
   SetEnableUpdates(PR_FALSE);
 
   nsresult rv = nsContentUtils::SetNodeTextContent(this, aInnerHTML, PR_TRUE);
   
   SetEnableUpdates(PR_TRUE);
   
-  UpdateStyleSheet();
+  UpdateStyleSheetInternal(nsnull);
   return rv;
 }
 
 void
 nsHTMLStyleElement::GetStyleSheetURL(PRBool* aIsInline,
                                      nsIURI** aURI)
 {
   *aURI = nsnull;
--- a/content/html/document/src/nsHTMLContentSink.cpp
+++ b/content/html/document/src/nsHTMLContentSink.cpp
@@ -275,17 +275,17 @@ protected:
   PRUint8 unused : 5;  // bits available if someone needs one
 
   nsCOMPtr<nsIObserverEntry> mObservers;
 
   nsINodeInfo* mNodeInfoCache[NS_HTML_TAG_MAX + 1];
 
   nsresult FlushTags();
 
-  void StartLayout();
+  void StartLayout(PRBool aIgnorePendingSheets);
 
   /**
    * AddBaseTagInfo adds the "current" base URI and target to the content node
    * in the form of bogo-attributes.  This MUST be called before attributes are
    * added to the content node, since the way URI attributes are treated may
    * depend on the value of the base URI
    */
   void AddBaseTagInfo(nsIContent* aContent);
@@ -781,21 +781,21 @@ SinkContext::OpenContainer(const nsIPars
   if (nodeType == eHTMLTag_style) {
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle = do_QueryInterface(content);
     NS_ASSERTION(ssle, "Style content isn't a style sheet?");
     ssle->SetLineNumber(aNode.GetSourceLineNumber());
 
     // Now disable updates so that every time we add an attribute or child
     // text token, we don't try to update the style sheet.
     if (!mSink->mInsideNoXXXTag) {
-      ssle->InitStyleLinkElement(mSink->mParser, PR_FALSE);
+      ssle->InitStyleLinkElement(PR_FALSE);
     }
     else {
       // We're not going to be evaluating this style anyway.
-      ssle->InitStyleLinkElement(nsnull, PR_TRUE);
+      ssle->InitStyleLinkElement(PR_TRUE);
     }
 
     ssle->SetEnableUpdates(PR_FALSE);
   }
 
   // Make sure to add base tag info, if needed, before setting any other
   // attributes -- what URI attrs do will depend on the base URI.  Only do this
   // for elements that have useful URI attributes.
@@ -1806,17 +1806,16 @@ HTMLContentSink::WillBuildModel(void)
   mDocument->BeginLoad();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 HTMLContentSink::DidBuildModel(void)
 {
-
   // NRA Dump stopwatch stop info here
 #ifdef MOZ_PERF_METRICS
   MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::DidBuildModel(), this=%p\n",
                       this));
   MOZ_TIMER_STOP(mWatch);
   MOZ_TIMER_LOG(("Content creation time (this=%p): ", this));
   MOZ_TIMER_PRINT(mWatch);
 #endif
@@ -1840,17 +1839,17 @@ HTMLContentSink::DidBuildModel(void)
     // likely cause us to crash, or at best waste a lot of time as we
     // are just going to tear it down anyway.
     PRBool bDestroying = PR_TRUE;
     if (mDocShell) {
       mDocShell->IsBeingDestroyed(&bDestroying);
     }
 
     if (!bDestroying) {
-      StartLayout();
+      StartLayout(PR_FALSE);
     }
   }
 
   ScrollToRef();
 
   nsScriptLoader *loader = mDocument->GetScriptLoader();
   if (loader) {
     loader->RemoveObserver(this);
@@ -2090,17 +2089,17 @@ HTMLContentSink::OpenBody(const nsIParse
     if (insertionPoint != -1) {
       NotifyInsert(parent, mBody, insertionPoint - 1);
     } else {
       NotifyAppend(parent, numFlushed);
     }
     mCurrentContext->mStack[parentIndex].mNumFlushed = childCount;
   }
 
-  StartLayout();
+  StartLayout(PR_FALSE);
 
   return NS_OK;
 }
 
 nsresult
 HTMLContentSink::CloseBody()
 {
   MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::CloseBody()\n"));
@@ -2288,17 +2287,17 @@ HTMLContentSink::CloseFrameset()
   }
 
   rv = sc->CloseContainer(eHTMLTag_frameset, PR_FALSE);    
 
   MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::CloseFrameset()\n"));
   MOZ_TIMER_STOP(mWatch);
 
   if (done && mFramesEnabled) {
-    StartLayout();
+    StartLayout(PR_FALSE);
   }
 
   return rv;
 }
 
 NS_IMETHODIMP
 HTMLContentSink::IsEnabled(PRInt32 aTag, PRBool* aReturn)
 {
@@ -2805,25 +2804,25 @@ HTMLContentSink::NotifyTagObservers(nsIP
   if (mHTMLDocument && mHTMLDocument->IsWriting()) {
     flag = nsIElementObserver::IS_DOCUMENT_WRITE;
   }
 
   return mObservers->Notify(aNode, mParser, mDocShell, flag);
 }
 
 void
-HTMLContentSink::StartLayout()
+HTMLContentSink::StartLayout(PRBool aIgnorePendingSheets)
 {
   if (mLayoutStarted) {
     return;
   }
 
   mHTMLDocument->SetIsFrameset(mFrameset != nsnull);
 
-  nsContentSink::StartLayout(mFrameset != nsnull);
+  nsContentSink::StartLayout(aIgnorePendingSheets);
 }
 
 void
 HTMLContentSink::AddBaseTagInfo(nsIContent* aContent)
 {
   nsresult rv;
   if (mBaseHref) {
     rv = aContent->SetProperty(nsGkAtoms::htmlBaseHref, mBaseHref,
@@ -2962,35 +2961,41 @@ HTMLContentSink::ProcessLINKTag(const ns
     result = NS_NewHTMLElement(getter_AddRefs(element), nodeInfo);
     NS_ENSURE_SUCCESS(result, result);
 
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(element));
 
     if (ssle) {
       // XXX need prefs. check here.
       if (!mInsideNoXXXTag) {
-        ssle->InitStyleLinkElement(mParser, PR_FALSE);
+        ssle->InitStyleLinkElement(PR_FALSE);
         ssle->SetEnableUpdates(PR_FALSE);
       } else {
-        ssle->InitStyleLinkElement(nsnull, PR_TRUE);
+        ssle->InitStyleLinkElement(PR_TRUE);
       }
     }
 
     // Add in the attributes and add the style content object to the
     // head container.
     AddBaseTagInfo(element);
     result = AddAttributes(aNode, element);
     if (NS_FAILED(result)) {
       return result;
     }
     parent->AppendChildTo(element, PR_FALSE);
 
     if (ssle) {
       ssle->SetEnableUpdates(PR_TRUE);
-      result = ssle->UpdateStyleSheet(nsnull, nsnull);
+      PRBool willNotify;
+      PRBool isAlternate;
+      result = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
+      if (NS_SUCCEEDED(result) && willNotify && !isAlternate) {
+        ++mPendingSheetCount;
+        mScriptLoader->AddExecuteBlocker();
+      }
 
       // look for <link rel="next" href="url">
       nsAutoString relVal;
       element->GetAttr(kNameSpaceID_None, nsGkAtoms::rel, relVal);
       if (!relVal.IsEmpty()) {
         // XXX seems overkill to generate this string array
         nsStringArray linkTypes;
         nsStyleLinkElement::ParseLinkTypes(relVal, linkTypes);
@@ -3170,17 +3175,23 @@ HTMLContentSink::ProcessSTYLEEndTag(nsGe
                "html:style doesn't implement nsIStyleSheetLinkingElement");
 
   nsresult rv = NS_OK;
 
   if (ssle) {
     // Note: if we are inside a noXXX tag, then we init'ed this style element
     // with mDontLoadStyle = PR_TRUE, so these two calls will have no effect.
     ssle->SetEnableUpdates(PR_TRUE);
-    rv = ssle->UpdateStyleSheet(nsnull, nsnull);
+    PRBool willNotify;
+    PRBool isAlternate;
+    rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
+    if (NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+      ++mPendingSheetCount;
+      mScriptLoader->AddExecuteBlocker();
+    }
   }
 
   return rv;
 }
 
 void
 HTMLContentSink::FlushPendingNotifications(mozFlushType aType)
 {
@@ -3191,17 +3202,17 @@ HTMLContentSink::FlushPendingNotificatio
       mCurrentContext->FlushTags();
     }
     else {
       mCurrentContext->FlushText();
     }
     if (aType & Flush_OnlyReflow) {
       // Make sure that layout has started so that the reflow flush
       // will actually happen.
-      StartLayout();
+      StartLayout(PR_TRUE);
     }
   }
 }
 
 nsresult
 HTMLContentSink::FlushTags()
 {
   return mCurrentContext ? mCurrentContext->FlushTags() : NS_OK;
--- a/content/svg/content/src/nsSVGStyleElement.cpp
+++ b/content/svg/content/src/nsSVGStyleElement.cpp
@@ -144,87 +144,87 @@ NS_IMPL_ELEMENT_CLONE_WITH_INIT(nsSVGSty
 // nsIContent methods
 
 nsresult
 nsSVGStyleElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex,
                                  PRBool aNotify)
 {
   nsresult rv = nsSVGStyleElementBase::InsertChildAt(aKid, aIndex, aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet();
+    UpdateStyleSheetInternal(nsnull);
   }
 
   return rv;
 }
 
 nsresult
 nsSVGStyleElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify)
 {
   nsresult rv = nsSVGStyleElementBase::RemoveChildAt(aIndex, aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet();
+    UpdateStyleSheetInternal(nsnull);
   }
 
   return rv;
 }
 
 nsresult
 nsSVGStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers)
 {
   nsresult rv = nsSVGStyleElementBase::BindToTree(aDocument, aParent,
                                                   aBindingParent,
                                                   aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UpdateStyleSheet(nsnull);
+  UpdateStyleSheetInternal(nsnull);
 
   return rv;  
 }
 
 void
 nsSVGStyleElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
 
   nsSVGStyleElementBase::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheet(oldDoc);
+  UpdateStyleSheetInternal(oldDoc);
 }
 
 nsresult
 nsSVGStyleElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
                            nsIAtom* aPrefix, const nsAString& aValue,
                            PRBool aNotify)
 {
   nsresult rv = nsSVGStyleElementBase::SetAttr(aNameSpaceID, aName, aPrefix,
                                                aValue, aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet(nsnull, nsnull,
-                     aNameSpaceID == kNameSpaceID_None &&
-                     (aName == nsGkAtoms::title ||
-                      aName == nsGkAtoms::media ||
-                      aName == nsGkAtoms::type));
+    UpdateStyleSheetInternal(nsnull,
+                             aNameSpaceID == kNameSpaceID_None &&
+                             (aName == nsGkAtoms::title ||
+                              aName == nsGkAtoms::media ||
+                              aName == nsGkAtoms::type));
   }
 
   return rv;
 }
 
 nsresult
 nsSVGStyleElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
                               PRBool aNotify)
 {
   nsresult rv = nsSVGStyleElementBase::UnsetAttr(aNameSpaceID, aAttribute,
                                                  aNotify);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet(nsnull, nsnull,
-                     aNameSpaceID == kNameSpaceID_None &&
-                     (aAttribute == nsGkAtoms::title ||
-                      aAttribute == nsGkAtoms::media ||
-                      aAttribute == nsGkAtoms::type));
+    UpdateStyleSheetInternal(nsnull,
+                             aNameSpaceID == kNameSpaceID_None &&
+                             (aAttribute == nsGkAtoms::title ||
+                              aAttribute == nsGkAtoms::media ||
+                              aAttribute == nsGkAtoms::type));
   }
 
   return rv;
 }
 
 //----------------------------------------------------------------------
 // nsIDOMSVGStyleElement methods
 
--- a/content/xbl/src/nsXBLContentSink.cpp
+++ b/content/xbl/src/nsXBLContentSink.cpp
@@ -106,17 +106,17 @@ nsXBLContentSink::Init(nsIDocument* aDoc
                        nsISupports* aContainer)
 {
   nsresult rv;
   rv = nsXMLContentSink::Init(aDoc, aURI, aContainer, nsnull);
   return rv;
 }
 
 void
-nsXBLContentSink::MaybeStartLayout()
+nsXBLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets)
 {
   return;
 }
 
 nsresult
 nsXBLContentSink::FlushText(PRBool aCreateTextNode,
                             PRBool* aDidFlush)
 {
--- a/content/xbl/src/nsXBLContentSink.h
+++ b/content/xbl/src/nsXBLContentSink.h
@@ -107,17 +107,17 @@ public:
 
   NS_IMETHOD HandleEndElement(const PRUnichar *aName);
   
   NS_IMETHOD HandleCDataSection(const PRUnichar *aData, 
                                 PRUint32 aLength);
 
 protected:
     // nsXMLContentSink overrides
-    void MaybeStartLayout();
+    virtual void MaybeStartLayout(PRBool aIgnorePendingSheets);
 
     PRBool OnOpenContainer(const PRUnichar **aAtts, 
                            PRUint32 aAttsCount, 
                            PRInt32 aNameSpaceID, 
                            nsIAtom* aTagName,
                            PRUint32 aLineNumber);
     
     nsresult CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
--- a/content/xml/content/src/nsXMLStylesheetPI.cpp
+++ b/content/xml/content/src/nsXMLStylesheetPI.cpp
@@ -117,38 +117,38 @@ nsXMLStylesheetPI::BindToTree(nsIDocumen
                               nsIContent* aBindingParent,
                               PRBool aCompileEventHandlers)
 {
   nsresult rv = nsXMLProcessingInstruction::BindToTree(aDocument, aParent,
                                                        aBindingParent,
                                                        aCompileEventHandlers);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  UpdateStyleSheet(nsnull);
+  UpdateStyleSheetInternal(nsnull);
 
   return rv;  
 }
 
 void
 nsXMLStylesheetPI::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
 {
   nsCOMPtr<nsIDocument> oldDoc = GetCurrentDoc();
 
   nsXMLProcessingInstruction::UnbindFromTree(aDeep, aNullParent);
-  UpdateStyleSheet(oldDoc);
+  UpdateStyleSheetInternal(oldDoc);
 }
 
 // nsIDOMNode
 
 NS_IMETHODIMP
 nsXMLStylesheetPI::SetNodeValue(const nsAString& aNodeValue)
 {
   nsresult rv = nsGenericDOMDataNode::SetNodeValue(aNodeValue);
   if (NS_SUCCEEDED(rv)) {
-    UpdateStyleSheet(nsnull, nsnull, PR_TRUE);
+    UpdateStyleSheetInternal(nsnull, PR_TRUE);
   }
   return rv;
 }
 
 // nsStyleLinkElement
 
 NS_IMETHODIMP
 nsXMLStylesheetPI::GetCharset(nsAString& aCharset)
--- a/content/xml/document/src/nsXMLContentSink.cpp
+++ b/content/xml/document/src/nsXMLContentSink.cpp
@@ -338,17 +338,17 @@ nsXMLContentSink::DidBuildModel()
       // documentElement?
       NS_ASSERTION(mDocument->IndexOf(mDocElement) != -1,
                    "mDocElement not in doc?");
     }
 
     // Check if we want to prettyprint
     MaybePrettyPrint();
 
-    StartLayout();
+    StartLayout(PR_FALSE);
 
     ScrollToRef();
 
     mDocument->RemoveObserver(this);
 
     mDocument->EndLoad();
   }
 
@@ -419,17 +419,17 @@ nsXMLContentSink::OnTransformDone(nsresu
                  "rootContent not in doc?");
     mDocument->BeginUpdate(UPDATE_CONTENT_MODEL);
     nsNodeUtils::ContentInserted(mDocument, rootContent,
                                  mDocument->IndexOf(rootContent));
     mDocument->EndUpdate(UPDATE_CONTENT_MODEL);
   }
   
   // Start the layout process
-  StartLayout();
+  StartLayout(PR_FALSE);
 
   ScrollToRef();
 
   originalDocument->EndLoad();
 
   return NS_OK;
 }
 
@@ -515,17 +515,17 @@ nsXMLContentSink::CreateElement(const PR
     }
   }
 #endif // MOZ_SVG
   else if (aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
            aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
            aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(content));
     if (ssle) {
-      ssle->InitStyleLinkElement(mParser, PR_FALSE);
+      ssle->InitStyleLinkElement(PR_FALSE);
       ssle->SetEnableUpdates(PR_FALSE);
       if (!aNodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML)) {
         ssle->SetLineNumber(aLineNumber);
       }
     }
   } 
 
   content.swap(*aResult);
@@ -621,19 +621,22 @@ nsXMLContentSink::CloseElement(nsIConten
     rv = ProcessMETATag(aContent);
   }
   else if (nodeInfo->Equals(nsGkAtoms::link, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_XHTML) ||
            nodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) {
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aContent));
     if (ssle) {
       ssle->SetEnableUpdates(PR_TRUE);
-      rv = ssle->UpdateStyleSheet(nsnull, nsnull);
-      if (rv == NS_ERROR_HTMLPARSER_BLOCK && mParser) {
-        mParser->BlockParser();
+      PRBool willNotify;
+      PRBool isAlternate;
+      rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
+      if (NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+        ++mPendingSheetCount;
+        mScriptLoader->AddExecuteBlocker();
       }
     }
   }
 
   return rv;
 }  
 
 nsresult
@@ -742,23 +745,19 @@ nsXMLContentSink::ProcessStyleLink(nsICo
 
     return LoadXSLStyleSheet(url);
   }
 
   // Let nsContentSink deal with css.
   rv = nsContentSink::ProcessStyleLink(aElement, aHref, aAlternate,
                                        aTitle, aType, aMedia);
 
-  if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
-    if (mParser) {
-      mParser->BlockParser();
-    }
-    return NS_OK;
-  }
-
+  // nsContentSink::ProcessStyleLink handles the bookkeeping here wrt
+  // pending sheets.
+  
   return rv;
 }
 
 nsresult
 nsXMLContentSink::ProcessBASETag(nsIContent* aContent)
 {
   NS_ASSERTION(aContent, "missing base-element");
 
@@ -869,42 +868,24 @@ nsXMLContentSink::PopContent()
     NS_WARNING("Popping empty stack");
     return;
   }
 
   mContentStack.RemoveElementAt(count - 1);
 }
 
 void
-nsXMLContentSink::MaybeStartLayout()
+nsXMLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets)
 {
+  // XXXbz if aIgnorePendingSheets is true, what should we do when
+  // mXSLTProcessor or CanStillPrettyPrint()?
   if (mLayoutStarted || mXSLTProcessor || CanStillPrettyPrint()) {
     return;
   }
-  StartLayout();
-}
-
-void
-nsXMLContentSink::StartLayout()
-{
-  if (mLayoutStarted) {
-    return;
-  }
-  PRBool topLevelFrameset = PR_FALSE;
-  nsCOMPtr<nsIDocShellTreeItem> docShellAsItem(do_QueryInterface(mDocShell));
-  if (docShellAsItem) {
-    nsCOMPtr<nsIDocShellTreeItem> root;
-    docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root));
-    if(docShellAsItem == root) {
-      topLevelFrameset = PR_TRUE;
-    }
-  }
-  
-  nsContentSink::StartLayout(topLevelFrameset);
-
+  StartLayout(aIgnorePendingSheets);
 }
 
 #ifdef MOZ_MATHML
 ////////////////////////////////////////////////////////////////////////
 // MathML Element Factory - temporary location for bug 132844
 // Will be factored out post 1.0
 
 nsresult
@@ -1050,17 +1031,17 @@ nsXMLContentSink::HandleStartElement(con
        nodeInfo->NameAtom() == nsGkAtoms::button)) {
     content->DoneCreatingElement();
   }
 
   if (IsMonolithicContainer(nodeInfo)) {
     mInMonolithicContainer++;
   }
 
-  MaybeStartLayout();
+  MaybeStartLayout(PR_FALSE);
 
   return NS_SUCCEEDED(result) ? DidProcessATokenImpl() : result;
 }
 
 NS_IMETHODIMP 
 nsXMLContentSink::HandleEndElement(const PRUnichar *aName)
 {
   nsresult result = NS_OK;
@@ -1246,43 +1227,52 @@ nsXMLContentSink::HandleProcessingInstru
   nsCOMPtr<nsIContent> node;
 
   nsresult rv = NS_NewXMLProcessingInstruction(getter_AddRefs(node),
                                                mNodeInfoManager, target, data);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(node));
   if (ssle) {
-    ssle->InitStyleLinkElement(mParser, PR_FALSE);
+    ssle->InitStyleLinkElement(PR_FALSE);
     ssle->SetEnableUpdates(PR_FALSE);
     mPrettyPrintXML = PR_FALSE;
   }
 
   rv = AddContentAsLeaf(node);
   NS_ENSURE_SUCCESS(rv, rv);
   DidAddContent();
 
   if (ssle) {
+    // This is an xml-stylesheet processing instruction... but it might not be
+    // a CSS one if the type is set to something else.
     ssle->SetEnableUpdates(PR_TRUE);
-    rv = ssle->UpdateStyleSheet(nsnull, nsnull);
+    PRBool willNotify;
+    PRBool isAlternate;
+    rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
+    NS_ENSURE_SUCCESS(rv, rv);
+    
+    if (willNotify) {
+      // Successfully started a stylesheet load
+      if (!isAlternate) {
+        ++mPendingSheetCount;
+        mScriptLoader->AddExecuteBlocker();
+      }
 
-    if (NS_FAILED(rv)) {
-      if (rv == NS_ERROR_HTMLPARSER_BLOCK && mParser) {
-        mParser->BlockParser();
-      }
-      return rv;
+      return NS_OK;
     }
   }
 
   // If it's not a CSS stylesheet PI...
   nsAutoString type;
   nsParserUtils::GetQuotedAttributeValue(data, nsGkAtoms::type, type);
 
   if (mState != eXMLContentSinkState_InProlog ||
       !target.EqualsLiteral("xml-stylesheet") ||
+      type.IsEmpty()                          ||
       type.LowerCaseEqualsLiteral("text/css")) {
     return DidProcessATokenImpl();
   }
 
   nsAutoString href, title, media;
   PRBool isAlternate = PR_FALSE;
   ParsePIData(data, href, title, media, isAlternate);
 
@@ -1515,17 +1505,17 @@ nsXMLContentSink::FlushPendingNotificati
       FlushTags();
     }
     else {
       FlushText();
     }
     if (aType & Flush_OnlyReflow) {
       // Make sure that layout has started so that the reflow flush
       // will actually happen.
-      MaybeStartLayout();
+      MaybeStartLayout(PR_TRUE);
     }
   }
 }
 
 /**
  * NOTE!! Forked from SinkContext. Please keep in sync.
  *
  * Flush all elements that have been seen so far such that
--- a/content/xml/document/src/nsXMLContentSink.h
+++ b/content/xml/document/src/nsXMLContentSink.h
@@ -101,18 +101,20 @@ public:
   NS_IMETHOD OnDocumentCreated(nsIDocument *aResultDocument);
   NS_IMETHOD OnTransformDone(nsresult aResult, nsIDocument *aResultDocument);
 
   static void ParsePIData(const nsString &aData, nsString &aHref,
                           nsString &aTitle, nsString &aMedia,
                           PRBool &aIsAlternate);
 
 protected:
-  virtual void MaybeStartLayout();
-  void StartLayout();
+  // Start layout.  If aIgnorePendingSheets is true, this will happen even if
+  // we still have stylesheet loads pending.  Otherwise, we'll wait until the
+  // stylesheets are all done loading.
+  virtual void MaybeStartLayout(PRBool aIgnorePendingSheets);
 
   virtual nsresult AddAttributes(const PRUnichar** aNode, nsIContent* aContent);
   nsresult AddText(const PRUnichar* aString, PRInt32 aLength);
 
   virtual PRBool OnOpenContainer(const PRUnichar **aAtts, 
                                  PRUint32 aAttsCount, 
                                  PRInt32 aNameSpaceID, 
                                  nsIAtom* aTagName,
--- a/content/xml/document/src/nsXMLFragmentContentSink.cpp
+++ b/content/xml/document/src/nsXMLFragmentContentSink.cpp
@@ -109,17 +109,17 @@ protected:
   virtual PRBool SetDocElement(PRInt32 aNameSpaceID, 
                                nsIAtom *aTagName,
                                nsIContent *aContent);
   virtual nsresult CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount,
                                  nsINodeInfo* aNodeInfo, PRUint32 aLineNumber,
                                  nsIContent** aResult, PRBool* aAppendContent);
   virtual nsresult CloseElement(nsIContent* aContent);
 
-  void MaybeStartLayout();
+  virtual void MaybeStartLayout(PRBool aIgnorePendingSheets);
 
   // nsContentSink overrides
   virtual nsresult ProcessStyleLink(nsIContent* aElement,
                                     const nsSubstring& aHref,
                                     PRBool aAlternate,
                                     const nsSubstring& aTitle,
                                     const nsSubstring& aType,
                                     const nsSubstring& aMedia);
@@ -260,17 +260,17 @@ nsXMLFragmentContentSink::CreateElement(
 nsresult
 nsXMLFragmentContentSink::CloseElement(nsIContent* aContent)
 {
   // don't do fancy stuff in nsXMLContentSink
   return NS_OK;
 }
 
 void
-nsXMLFragmentContentSink::MaybeStartLayout()
+nsXMLFragmentContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets)
 {
   return;
 }
 
 ////////////////////////////////////////////////////////////////////////
 
 NS_IMETHODIMP
 nsXMLFragmentContentSink::HandleDoctypeDecl(const nsAString & aSubset, 
--- a/content/xslt/src/xslt/txMozillaXMLOutput.cpp
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.cpp
@@ -344,24 +344,22 @@ txMozillaXMLOutput::endElement()
     }
 
     if (mCreatingNewDocument) {
         // Handle all sorts of stylesheets
         nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
             do_QueryInterface(mCurrentNode);
         if (ssle) {
             ssle->SetEnableUpdates(PR_TRUE);
-            if (ssle->UpdateStyleSheet(nsnull, mNotifier) ==
-                NS_ERROR_HTMLPARSER_BLOCK) {
-                nsCOMPtr<nsIStyleSheet> stylesheet;
-                ssle->GetStyleSheet(*getter_AddRefs(stylesheet));
-                if (mNotifier) {
-                    rv = mNotifier->AddStyleSheet(stylesheet);
-                    NS_ENSURE_SUCCESS(rv, rv);
-                }
+            PRBool willNotify;
+            PRBool isAlternate;
+            nsresult rv = ssle->UpdateStyleSheet(mNotifier, &willNotify,
+                                                 &isAlternate);
+            if (mNotifier && NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+                mNotifier->AddPendingStylesheet();
             }
         }
     }
 
     // Add the element to the tree if it wasn't added before and take one step
     // up the tree
     PRUint32 last = mCurrentNodeStack.Count() - 1;
     NS_ASSERTION(last != (PRUint32)-1, "empty stack");
@@ -416,34 +414,31 @@ txMozillaXMLOutput::processingInstructio
     rv = NS_NewXMLProcessingInstruction(getter_AddRefs(pi),
                                         mNodeInfoManager, aTarget, aData);
     NS_ENSURE_SUCCESS(rv, rv);
 
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle;
     if (mCreatingNewDocument) {
         ssle = do_QueryInterface(pi);
         if (ssle) {
-            ssle->InitStyleLinkElement(nsnull, PR_FALSE);
+            ssle->InitStyleLinkElement(PR_FALSE);
             ssle->SetEnableUpdates(PR_FALSE);
         }
     }
 
     rv = mCurrentNode->AppendChildTo(pi, PR_TRUE);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (ssle) {
         ssle->SetEnableUpdates(PR_TRUE);
-        rv = ssle->UpdateStyleSheet(nsnull, mNotifier);
-        if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
-            nsCOMPtr<nsIStyleSheet> stylesheet;
-            ssle->GetStyleSheet(*getter_AddRefs(stylesheet));
-            if (mNotifier) {
-                rv = mNotifier->AddStyleSheet(stylesheet);
-                NS_ENSURE_SUCCESS(rv, rv);
-            }
+        PRBool willNotify;
+        PRBool isAlternate;
+        rv = ssle->UpdateStyleSheet(mNotifier, &willNotify, &isAlternate);
+        if (mNotifier && NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
+            mNotifier->AddPendingStylesheet();
         }
     }
 
     return NS_OK;
 }
 
 nsresult
 txMozillaXMLOutput::startDocument()
@@ -575,17 +570,17 @@ txMozillaXMLOutput::startElementInternal
         }
     }
 
     if (mCreatingNewDocument) {
         // Handle all sorts of stylesheets
         nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
             do_QueryInterface(mOpenedElement);
         if (ssle) {
-            ssle->InitStyleLinkElement(nsnull, PR_FALSE);
+            ssle->InitStyleLinkElement(PR_FALSE);
             ssle->SetEnableUpdates(PR_FALSE);
         }
     }
 
     return NS_OK;
 }
 
 nsresult
@@ -998,18 +993,18 @@ txMozillaXMLOutput::createHTMLElement(ns
                                                 kNameSpaceID_None,
                                                 getter_AddRefs(ni));
     NS_ENSURE_SUCCESS(rv, rv);
 
     return NS_NewHTMLElement(aResult, ni);
 }
 
 txTransformNotifier::txTransformNotifier()
-    : mInTransform(PR_FALSE)
-      
+    : mPendingStylesheetCount(0),
+      mInTransform(PR_FALSE)      
 {
 }
 
 txTransformNotifier::~txTransformNotifier()
 {
 }
 
 NS_IMPL_ISUPPORTS2(txTransformNotifier,
@@ -1043,46 +1038,49 @@ txTransformNotifier::ScriptEvaluated(nsr
     return NS_OK;
 }
 
 NS_IMETHODIMP 
 txTransformNotifier::StyleSheetLoaded(nsICSSStyleSheet* aSheet,
                                       PRBool aWasAlternate,
                                       nsresult aStatus)
 {
-    // Check that the stylesheet was in the mStylesheets array, if not it is an
-    // alternate and we don't want to call SignalTransformEnd since we don't
-    // wait on alternates before calling OnTransformDone and so the load of the
-    // alternate could finish after we called OnTransformDone already.
-    // See http://bugzilla.mozilla.org/show_bug.cgi?id=215465.
-    if (mStylesheets.RemoveObject(aSheet)) {
+    if (mPendingStylesheetCount == 0) {
+        // We weren't waiting on this stylesheet anyway.  This can happen if
+        // SignalTransformEnd got called with an error aResult.  See
+        // http://bugzilla.mozilla.org/show_bug.cgi?id=215465.
+        return NS_OK;
+    }
+
+    // We're never waiting for alternate stylesheets
+    if (!aWasAlternate) {
+        --mPendingStylesheetCount;
         SignalTransformEnd();
     }
-
+    
     return NS_OK;
 }
 
 void
 txTransformNotifier::Init(nsITransformObserver* aObserver)
 {
     mObserver = aObserver;
 }
 
 nsresult
 txTransformNotifier::AddScriptElement(nsIScriptElement* aElement)
 {
     return mScriptElements.AppendObject(aElement) ? NS_OK :
                                                     NS_ERROR_OUT_OF_MEMORY;
 }
 
-nsresult
-txTransformNotifier::AddStyleSheet(nsIStyleSheet* aStyleSheet)
+void
+txTransformNotifier::AddPendingStylesheet()
 {
-    return mStylesheets.AppendObject(aStyleSheet) ? NS_OK :
-                                                    NS_ERROR_OUT_OF_MEMORY;
+    ++mPendingStylesheetCount;
 }
 
 void
 txTransformNotifier::OnTransformEnd(nsresult aResult)
 {
     mInTransform = PR_FALSE;
     SignalTransformEnd(aResult);
 }
@@ -1101,21 +1099,24 @@ txTransformNotifier::SetOutputDocument(n
     // Notify the contentsink that the document is created
     return mObserver->OnDocumentCreated(mDocument);
 }
 
 void
 txTransformNotifier::SignalTransformEnd(nsresult aResult)
 {
     if (mInTransform || (NS_SUCCEEDED(aResult) &&
-        mScriptElements.Count() > 0 || mStylesheets.Count() > 0)) {
+        mScriptElements.Count() > 0 || mPendingStylesheetCount > 0)) {
         return;
     }
 
-    mStylesheets.Clear();
+    // mPendingStylesheetCount is nonzero at this point only if aResult is an
+    // error.  Set it to 0 so we won't reenter this code when we stop the
+    // CSSLoader.
+    mPendingStylesheetCount = 0;
     mScriptElements.Clear();
 
     // Make sure that we don't get deleted while this function is executed and
     // we remove ourselfs from the scriptloader
     nsCOMPtr<nsIScriptLoaderObserver> kungFuDeathGrip(this);
 
     nsCOMPtr<nsIDocument> doc = do_QueryInterface(mDocument);
     if (doc) {
--- a/content/xslt/src/xslt/txMozillaXMLOutput.h
+++ b/content/xslt/src/xslt/txMozillaXMLOutput.h
@@ -71,28 +71,28 @@ public:
     
     // nsICSSLoaderObserver
     NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet* aSheet,
                                 PRBool aWasAlternate,
                                 nsresult aStatus);
 
     void Init(nsITransformObserver* aObserver);
     nsresult AddScriptElement(nsIScriptElement* aElement);
-    nsresult AddStyleSheet(nsIStyleSheet* aStyleSheet);
+    void AddPendingStylesheet();
     void OnTransformEnd(nsresult aResult = NS_OK);
     void OnTransformStart();
     nsresult SetOutputDocument(nsIDocument* aDocument);
 
 private:
     void SignalTransformEnd(nsresult aResult = NS_OK);
 
     nsCOMPtr<nsIDocument> mDocument;
     nsCOMPtr<nsITransformObserver> mObserver;
     nsCOMArray<nsIScriptElement> mScriptElements;
-    nsCOMArray<nsIStyleSheet> mStylesheets;
+    PRUint32 mPendingStylesheetCount;
     PRPackedBool mInTransform;
 };
 
 class txMozillaXMLOutput : public txAOutputXMLEventHandler
 {
 public:
     txMozillaXMLOutput(const nsSubstring& aRootName,
                        PRInt32 aRootNsID,
--- a/content/xul/document/src/nsXULContentSink.cpp
+++ b/content/xul/document/src/nsXULContentSink.cpp
@@ -45,19 +45,16 @@
  *
  * For more information on XUL,
  * see http://developer.mozilla.org/en/docs/XUL
  */
 
 #include "nsXULContentSink.h"
 #include "nsCOMPtr.h"
 #include "nsForwardReference.h"
-#include "nsICSSLoader.h"
-#include "nsICSSParser.h"
-#include "nsICSSStyleSheet.h"
 #include "nsIContentSink.h"
 #include "nsIDOMDocument.h"
 #include "nsIDOMEventListener.h"
 #include "nsIDOMHTMLFormElement.h"
 #include "nsIDOMXULDocument.h"
 #include "nsIDocument.h"
 #include "nsIFormControl.h"
 #include "nsHTMLStyleSheet.h"
@@ -364,20 +361,18 @@ XULContentSinkImpl::Init(nsIDocument* aD
                                    preferredStyle);
     if (NS_FAILED(rv)) return rv;
 
     if (!preferredStyle.IsEmpty()) {
         aDocument->SetHeaderData(nsGkAtoms::headerDefaultStyle,
                                  preferredStyle);
     }
 
-    // Get the CSS loader from the document so we can load
-    // stylesheets
-    mCSSLoader = aDocument->CSSLoader();
-    mCSSLoader->SetPreferredSheet(preferredStyle);
+    // Set the right preferred style on the document's CSSLoader.
+    aDocument->CSSLoader()->SetPreferredSheet(preferredStyle);
 
     mNodeInfoManager = aPrototype->GetNodeInfoManager();
     if (! mNodeInfoManager)
         return NS_ERROR_UNEXPECTED;
 
     mState = eInProlog;
     return NS_OK;
 }
--- a/content/xul/document/src/nsXULContentSink.h
+++ b/content/xul/document/src/nsXULContentSink.h
@@ -44,18 +44,16 @@
 
 #include "nsIExpatSink.h"
 #include "nsIXMLContentSink.h"
 #include "nsAutoPtr.h"
 #include "nsNodeInfoManager.h"
 #include "nsVoidArray.h"
 #include "nsWeakPtr.h"
 
-class nsICSSLoader;
-class nsICSSParser;
 class nsIDocument;
 class nsIScriptSecurityManager;
 class nsAttrName;
 class nsXULPrototypeDocument;
 class nsXULPrototypeElement;
 class nsXULPrototypeNode;
 
 class XULContentSinkImpl : public nsIXMLContentSink,
@@ -168,14 +166,12 @@ protected:
 
     nsWeakPtr              mDocument;             // [OWNER]
     nsCOMPtr<nsIURI>       mDocumentURL;          // [OWNER]
 
     nsRefPtr<nsXULPrototypeDocument> mPrototype;  // [OWNER]
 
     // We use regular pointer b/c of funky exports on nsIParser:
     nsIParser*             mParser;               // [OWNER]
-    nsCOMPtr<nsICSSLoader> mCSSLoader;            // [OWNER]
-    nsCOMPtr<nsICSSParser> mCSSParser;            // [OWNER]
     nsCOMPtr<nsIScriptSecurityManager> mSecMan;
 };
 
 #endif /* nsXULContentSink_h__ */
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -2509,35 +2509,34 @@ nsXULDocument::InsertXMLStylesheetPI(con
                                      nsIContent* aPINode)
 {
     nsCOMPtr<nsIStyleSheetLinkingElement> ssle(do_QueryInterface(aPINode));
     NS_ASSERTION(ssle, "passed XML Stylesheet node does not "
                        "implement nsIStyleSheetLinkingElement!");
 
     nsresult rv;
 
-    ssle->InitStyleLinkElement(nsnull, PR_FALSE);
+    ssle->InitStyleLinkElement(PR_FALSE);
     // We want to be notified when the style sheet finishes loading, so
     // disable style sheet loading for now.
     ssle->SetEnableUpdates(PR_FALSE);
     ssle->OverrideBaseURI(mCurrentPrototype->GetURI());
 
     rv = aParent->InsertChildAt(aPINode, aIndex, PR_FALSE);
     if (NS_FAILED(rv)) return rv;
 
     ssle->SetEnableUpdates(PR_TRUE);
 
     // load the stylesheet if necessary, passing ourselves as
     // nsICSSObserver
-    rv = ssle->UpdateStyleSheet(nsnull, this);
-    if (rv == NS_ERROR_HTMLPARSER_BLOCK) {
+    PRBool willNotify;
+    PRBool isAlternate;
+    rv = ssle->UpdateStyleSheet(this, &willNotify, &isAlternate);
+    if (NS_SUCCEEDED(rv) && willNotify && !isAlternate) {
         ++mPendingSheets;
-        rv = NS_OK;
-    } else if (NS_FAILED(rv)) {
-        rv = NS_OK;
     }
 
     return rv;
 }
 
 nsresult
 nsXULDocument::InsertXULOverlayPI(const nsXULPrototypePI* aProtoPI,
                                   nsINode* aParent,
@@ -2873,17 +2872,20 @@ nsXULDocument::ResumeWalk()
                             element->NodeInfo()->Equals(nsGkAtoms::style,
                                                         kNameSpaceID_SVG)) {
                             // XXX sucks that we have to do this -
                             // see bug 370111
                             nsCOMPtr<nsIStyleSheetLinkingElement> ssle =
                                 do_QueryInterface(element);
                             NS_ASSERTION(ssle, "<html:style> doesn't implement "
                                                "nsIStyleSheetLinkingElement?");
-                            ssle->UpdateStyleSheet(nsnull, nsnull);
+                            PRBool willNotify;
+                            PRBool isAlternate;
+                            ssle->UpdateStyleSheet(nsnull, &willNotify,
+                                                   &isAlternate);
                         }
                     }
 
 #ifdef MOZ_XTF
                     if (element->GetNameSpaceID() > kNameSpaceID_LastBuiltin) {
                         element->DoneAddingChildren(PR_FALSE);
                     }
 #endif
--- a/layout/style/nsCSSLoader.cpp
+++ b/layout/style/nsCSSLoader.cpp
@@ -54,17 +54,16 @@
 #include "nsIDocument.h"
 #include "nsIDOMNSDocumentStyle.h"
 #include "nsIUnicharInputStream.h"
 #include "nsIConverterInputStream.h"
 #include "nsICharsetAlias.h"
 #include "nsUnicharUtils.h"
 #include "nsHashtable.h"
 #include "nsIURI.h"
-#include "nsIParser.h"
 #include "nsIServiceManager.h"
 #include "nsNetUtil.h"
 #include "nsContentUtils.h"
 #include "nsCRT.h"
 #include "nsIScriptSecurityManager.h"
 #include "nsContentPolicyUtils.h"
 #include "nsITimelineService.h"
 #include "nsIHttpChannel.h"
@@ -139,25 +138,23 @@ static const char* const gStateStrings[]
 
 /********************************
  * SheetLoadData implementation *
  ********************************/
 NS_IMPL_ISUPPORTS2(SheetLoadData, nsIUnicharStreamLoaderObserver, nsIRunnable)
 
 SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader,
                              const nsSubstring& aTitle,
-                             nsIParser* aParserToUnblock,
                              nsIURI* aURI,
                              nsICSSStyleSheet* aSheet,
                              nsIStyleSheetLinkingElement* aOwningElement,
                              PRBool aIsAlternate,
                              nsICSSLoaderObserver* aObserver)
   : mLoader(aLoader),
     mTitle(aTitle),
-    mParserToUnblock(aParserToUnblock),
     mURI(aURI),
     mLineNumber(1),
     mSheet(aSheet),
     mNext(nsnull),
     mParentData(nsnull),
     mPendingChildren(0),
     mSyncLoad(PR_FALSE),
     mIsNonDocumentSheet(PR_FALSE),
@@ -175,17 +172,16 @@ SheetLoadData::SheetLoadData(CSSLoaderIm
 }
 
 SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader,
                              nsIURI* aURI,
                              nsICSSStyleSheet* aSheet,
                              SheetLoadData* aParentData,
                              nsICSSLoaderObserver* aObserver)
   : mLoader(aLoader),
-    mParserToUnblock(nsnull),
     mURI(aURI),
     mLineNumber(1),
     mSheet(aSheet),
     mNext(nsnull),
     mParentData(aParentData),
     mPendingChildren(0),
     mSyncLoad(PR_FALSE),
     mIsNonDocumentSheet(PR_FALSE),
@@ -211,17 +207,16 @@ SheetLoadData::SheetLoadData(CSSLoaderIm
 
 SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader,
                              nsIURI* aURI,
                              nsICSSStyleSheet* aSheet,
                              PRBool aSyncLoad,
                              PRBool aAllowUnsafeRules,
                              nsICSSLoaderObserver* aObserver)
   : mLoader(aLoader),
-    mParserToUnblock(nsnull),
     mURI(aURI),
     mLineNumber(1),
     mSheet(aSheet),
     mNext(nsnull),
     mParentData(nsnull),
     mPendingChildren(0),
     mSyncLoad(aSyncLoad),
     mIsNonDocumentSheet(PR_TRUE),
@@ -1112,18 +1107,16 @@ nsresult
 CSSLoaderImpl::InsertSheetInDoc(nsICSSStyleSheet* aSheet,
                                 nsIContent* aLinkingContent,
                                 nsIDocument* aDocument)
 {
   LOG(("CSSLoaderImpl::InsertSheetInDoc"));
   NS_PRECONDITION(aSheet, "Nothing to insert");
   NS_PRECONDITION(aDocument, "Must have a document to insert into");
 
-  // all nodes that link in sheets should be implementing nsIDOM3Node
-
   // XXX Need to cancel pending sheet loads for this element, if any
 
   PRInt32 sheetCount = aDocument->GetNumberOfStyleSheets();
 
   /*
    * Start the walk at the _end_ of the list, since in the typical
    * case we'll just want to append anyway.  We want to break out of
    * the loop when insertionPoint points to just before the index we
@@ -1461,16 +1454,46 @@ CSSLoaderImpl::ParseSheet(nsIUnicharInpu
  * the load data (other loads for the same URI), handles unblocking
  * blocked parent loads as needed, and most importantly calls
  * NS_RELEASE on the load data to destroy the whole mess.
  */
 void
 CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus)
 {
   LOG(("CSSLoaderImpl::SheetComplete"));
+
+  // 8 is probably big enough for all our common cases.  It's not likely that
+  // imports will nest more than 8 deep, and multiple sheets with the same URI
+  // are rare.
+  nsAutoTArray<nsRefPtr<SheetLoadData>, 8> datasToNotify;
+  DoSheetComplete(aLoadData, aStatus, datasToNotify);
+
+  // Now it's safe to go ahead and notify observers
+  PRUint32 count = datasToNotify.Length();
+  for (PRUint32 i = 0; i < count; ++i) {
+    SheetLoadData* data = datasToNotify[i];
+    NS_ASSERTION(data && data->mMustNotify && data->mObserver,
+                 "How did this data get here?");
+    LOG(("  Notifying observer 0x%x for data 0x%s.  wasAlternate: %d",
+         data->mObserver.get(), data, data->mWasAlternate));
+    data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate,
+                                      aStatus);
+  }
+
+  if (mLoadingDatas.Count() == 0 && mPendingDatas.Count() > 0) {
+    LOG(("  No more loading sheets; starting alternates"));
+    mPendingDatas.Enumerate(StartAlternateLoads, this);
+  }
+}
+
+void
+CSSLoaderImpl::DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
+                               LoadDataArray& aDatasToNotify)
+{
+  LOG(("CSSLoaderImpl::DoSheetComplete"));
   NS_PRECONDITION(aLoadData, "Must have a load data!");
   NS_PRECONDITION(aLoadData->mSheet, "Must have a sheet");
   NS_ASSERTION(mLoadingDatas.IsInitialized(),"mLoadingDatas should be initialized by now.");
 
   LOG(("Load completed, status: 0x%x", aStatus));
 
   // Twiddle the hashtables
   if (aLoadData->mURI) {
@@ -1484,62 +1507,44 @@ CSSLoaderImpl::SheetComplete(SheetLoadDa
                    "Bad loading table");
 #endif
 
       mLoadingDatas.Remove(aLoadData->mURI);
       aLoadData->mIsLoading = PR_FALSE;
     }
   }
   
-
-  // This is a mess.  If we have a document.write() that writes out
-  // two <link> elements pointing to the same url, we will actually
-  // end up blocking the same parser twice.  This seems very wrong --
-  // if we blocked it the first time, why is more stuff getting
-  // written??  In any case, we only want to unblock it once.
-  // Otherwise we get icky things like crashes in layout...  We need
-  // to stop blocking the parser.  We really do.
-  PRBool seenParser = PR_FALSE;
-
   // Go through and deal with the whole linked list.
   SheetLoadData* data = aLoadData;
   while (data) {
 
     data->mSheet->SetModified(PR_FALSE); // it's clean
     data->mSheet->SetComplete();
     if (data->mMustNotify && data->mObserver) {
-      data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate,
-                                        aStatus);
-    }
+      // Don't notify here so we don't trigger script.  Remember the
+      // info we need to notify, then do it later when it's safe.
+      aDatasToNotify.AppendElement(data);
 
-    // Only unblock the parser if mMustNotify is true (so we're not being
-    // called synchronously from LoadSheet) and mWasAlternate is false.
-    if (data->mParserToUnblock) {
-      LOG(("Parser to unblock: %p", data->mParserToUnblock.get()));
-      if (!seenParser && data->mMustNotify && !data->mWasAlternate) {
-        LOG(("Unblocking parser: %p", data->mParserToUnblock.get()));
-        seenParser = PR_TRUE;
-        data->mParserToUnblock->ContinueParsing();
-      }
-      data->mParserToUnblock = nsnull; // drop the ref, just in case
+      // On append failure, just press on.  We'll fail to notify the observer,
+      // but not much we can do about that....
     }
 
     NS_ASSERTION(!data->mParentData ||
                  data->mParentData->mPendingChildren != 0,
                  "Broken pending child count on our parent");
 
     // If we have a parent, our parent is no longer being parsed, and
     // we are the last pending child, then our load completion
     // completes the parent too.  Note that the parent _can_ still be
     // being parsed (eg if the child (us) failed to open the channel
     // or some such).
     if (data->mParentData &&
         --(data->mParentData->mPendingChildren) == 0 &&
         mParsingDatas.IndexOf(data->mParentData) == -1) {
-      SheetComplete(data->mParentData, aStatus);
+      DoSheetComplete(data->mParentData, aStatus, aDatasToNotify);
     }
     
     data = data->mNext;
   }
 
   // Now that it's marked complete, put the sheet in our cache
   if (NS_SUCCEEDED(aStatus) && aLoadData->mURI) {
 #ifdef MOZ_XUL
@@ -1556,33 +1561,27 @@ CSSLoaderImpl::SheetComplete(SheetLoadDa
 #endif
       mCompleteSheets.Put(aLoadData->mURI, aLoadData->mSheet);
 #ifdef MOZ_XUL
     }
 #endif
   }
 
   NS_RELEASE(aLoadData);  // this will release parents and siblings and all that
-  if (mLoadingDatas.Count() == 0 && mPendingDatas.Count() > 0) {
-    LOG(("  No more loading sheets; starting alternates"));
-    mPendingDatas.Enumerate(StartAlternateLoads, this);
-  }
 }
 
 NS_IMETHODIMP
 CSSLoaderImpl::LoadInlineStyle(nsIContent* aElement,
                                nsIUnicharInputStream* aStream, 
                                PRUint32 aLineNumber,
                                const nsSubstring& aTitle,
                                const nsSubstring& aMedia,
-                               nsIParser* aParserToUnblock,
                                nsICSSLoaderObserver* aObserver,
                                PRBool* aCompleted,
                                PRBool* aIsAlternate)
-
 {
   LOG(("CSSLoaderImpl::LoadInlineStyle"));
   NS_PRECONDITION(aStream, "Must have a stream to parse!");
   NS_ASSERTION(mParsingDatas.Count() == 0, "We're in the middle of a parse?");
 
   *aCompleted = PR_TRUE;
 
   if (!mEnabled) {
@@ -1607,19 +1606,19 @@ CSSLoaderImpl::LoadInlineStyle(nsIConten
                     aIsAlternate);
   NS_ENSURE_SUCCESS(rv, rv);
   
   LOG(("  Sheet is alternate: %d", *aIsAlternate));
   
   rv = InsertSheetInDoc(sheet, aElement, mDocument);
   NS_ENSURE_SUCCESS(rv, rv);
   
-  SheetLoadData* data = new SheetLoadData(this, aTitle, aParserToUnblock,
-                                          nsnull, sheet, owningElement,
-                                          *aIsAlternate, aObserver);
+  SheetLoadData* data = new SheetLoadData(this, aTitle, nsnull, sheet,
+                                          owningElement, *aIsAlternate,
+                                          aObserver);
 
   if (!data) {
     sheet->SetComplete();
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   NS_ADDREF(data);
   data->mLineNumber = aLineNumber;
@@ -1635,17 +1634,16 @@ CSSLoaderImpl::LoadInlineStyle(nsIConten
 }        
 
 NS_IMETHODIMP
 CSSLoaderImpl::LoadStyleLink(nsIContent* aElement,
                              nsIURI* aURL, 
                              const nsSubstring& aTitle,
                              const nsSubstring& aMedia,
                              PRBool aHasAlternateRel,
-                             nsIParser* aParserToUnblock,
                              nsICSSLoaderObserver* aObserver,
                              PRBool* aIsAlternate)
 {
   LOG(("CSSLoaderImpl::LoadStyleLink"));
   NS_PRECONDITION(aURL, "Must have URL to load");
   NS_ASSERTION(mParsingDatas.Count() == 0, "We're in the middle of a parse?");
 
   LOG_URI("  Link uri: '%s'", aURL);
@@ -1686,25 +1684,29 @@ CSSLoaderImpl::LoadStyleLink(nsIContent*
   LOG(("  Sheet is alternate: %d", *aIsAlternate));
   
   rv = InsertSheetInDoc(sheet, aElement, mDocument);
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (state == eSheetComplete) {
     LOG(("  Sheet already complete: 0x%p",
          NS_STATIC_CAST(void*, sheet.get())));
-    return PostLoadEvent(aURL, sheet, aObserver, aParserToUnblock,
-                         *aIsAlternate);
+    if (aObserver) {
+      rv = PostLoadEvent(aURL, sheet, aObserver, *aIsAlternate);
+      return rv;
+    }
+
+    return NS_OK;
   }
 
   nsCOMPtr<nsIStyleSheetLinkingElement> owningElement(do_QueryInterface(aElement));
 
   // Now we need to actually load it
-  SheetLoadData* data = new SheetLoadData(this, aTitle, aParserToUnblock, aURL,
-                                          sheet, owningElement, *aIsAlternate,
+  SheetLoadData* data = new SheetLoadData(this, aTitle, aURL, sheet,
+                                          owningElement, *aIsAlternate,
                                           aObserver);
   if (!data) {
     sheet->SetComplete();
     return NS_ERROR_OUT_OF_MEMORY;
   }
 
   NS_ADDREF(data);
 
@@ -1911,17 +1913,17 @@ CSSLoaderImpl::InternalLoadNonDocumentSh
 
   const nsSubstring& empty = EmptyString();
   rv = PrepareSheet(sheet, empty, empty, nsnull);
   NS_ENSURE_SUCCESS(rv, rv);
   
   if (state == eSheetComplete) {
     LOG(("  Sheet already complete"));
     if (aObserver) {
-      rv = PostLoadEvent(aURL, sheet, aObserver, nsnull, PR_FALSE);
+      rv = PostLoadEvent(aURL, sheet, aObserver, PR_FALSE);
     }
     if (aSheet) {
       sheet.swap(*aSheet);
     }
     return rv;
   }
 
   SheetLoadData* data =
@@ -1945,28 +1947,24 @@ CSSLoaderImpl::InternalLoadNonDocumentSh
 
   return rv;
 }
 
 nsresult
 CSSLoaderImpl::PostLoadEvent(nsIURI* aURI,
                              nsICSSStyleSheet* aSheet,
                              nsICSSLoaderObserver* aObserver,
-                             nsIParser* aParserToUnblock,
                              PRBool aWasAlternate)
 {
   LOG(("nsCSSLoader::PostLoadEvent"));
   NS_PRECONDITION(aSheet, "Must have sheet");
-  // XXXbz can't assert this yet; have to post even with a null
-  // observer, since we may need to unblock the parser
-  // NS_PRECONDITION(aObserver, "Must have observer");
+  NS_PRECONDITION(aObserver, "Must have observer");
 
   nsRefPtr<SheetLoadData> evt =
     new SheetLoadData(this, EmptyString(), // title doesn't matter here
-                      aParserToUnblock,
                       aURI,
                       aSheet,
                       nsnull,  // owning element doesn't matter here
                       aWasAlternate,
                       aObserver);
   NS_ENSURE_TRUE(evt, NS_ERROR_OUT_OF_MEMORY);
 
   if (!mPostedEvents.AppendElement(evt)) {
--- a/layout/style/nsCSSLoader.h
+++ b/layout/style/nsCSSLoader.h
@@ -48,17 +48,16 @@
 
 /* loading of CSS style sheets using the network APIs */
 
 #ifndef nsCSSLoader_h__
 #define nsCSSLoader_h__
 
 class CSSLoaderImpl;
 class nsIURI;
-class nsIParser;
 class nsICSSStyleSheet;
 class nsIStyleSheetLinkingElement;
 class nsICSSLoaderObserver;
 class nsICSSParser;
 class nsICSSImportRule;
 class nsMediaList;
 
 #include "nsICSSLoader.h"
@@ -108,17 +107,16 @@ class nsMediaList;
 class SheetLoadData : public nsIRunnable,
                       public nsIUnicharStreamLoaderObserver
 {
 public:
   virtual ~SheetLoadData(void);
   // Data for loading a sheet linked from a document
   SheetLoadData(CSSLoaderImpl* aLoader,
                 const nsSubstring& aTitle,
-                nsIParser* aParserToUnblock,
                 nsIURI* aURI,
                 nsICSSStyleSheet* aSheet,
                 nsIStyleSheetLinkingElement* aOwningElement,
                 PRBool aIsAlternate,
                 nsICSSLoaderObserver* aObserver);                 
 
   // Data for loading a sheet linked from an @import rule
   SheetLoadData(CSSLoaderImpl* aLoader,
@@ -147,19 +145,16 @@ public:
 
   // Title needed to pull datas out of the pending datas table when
   // the preferred title is changed
   nsString                   mTitle;
 
   // Charset we decided to use for the sheet
   nsCString                  mCharset;
 
-  // Parser to be told to continue parsing once the load completes
-  nsCOMPtr<nsIParser>        mParserToUnblock;
-
   // URI we're loading.  Null for inline sheets
   nsCOMPtr<nsIURI>           mURI;
 
   // Should be 1 for non-inline sheets.
   PRUint32                   mLineNumber;
 
   // The sheet we're loading data for
   nsCOMPtr<nsICSSStyleSheet> mSheet;
@@ -256,27 +251,25 @@ public:
                           nsICSSParser** aParser);
   NS_IMETHOD RecycleParser(nsICSSParser* aParser);
 
   NS_IMETHOD LoadInlineStyle(nsIContent* aElement,
                              nsIUnicharInputStream* aStream, 
                              PRUint32 aLineNumber,
                              const nsSubstring& aTitle,
                              const nsSubstring& aMedia,
-                             nsIParser* aParserToUnblock,
                              nsICSSLoaderObserver* aObserver,
                              PRBool* aCompleted,
                              PRBool* aIsAlternate);
 
   NS_IMETHOD LoadStyleLink(nsIContent* aElement,
                            nsIURI* aURL, 
-                           const nsSubstring& aTitle, 
+                           const nsSubstring& aTitle,
                            const nsSubstring& aMedia,
                            PRBool aHasAlternateRel,
-                           nsIParser* aParserToUnblock,
                            nsICSSLoaderObserver* aObserver,
                            PRBool* aIsAlternate);
 
   NS_IMETHOD LoadChildSheet(nsICSSStyleSheet* aParentSheet,
                             nsIURI* aURL, 
                             nsMediaList* aMedia,
                             nsICSSImportRule* aRule);
 
@@ -352,60 +345,73 @@ private:
   // notification will be sent with status NS_OK unless the load event is
   // canceled at some point (in which case it will be sent with
   // NS_BINDING_ABORTED).  aWasAlternate indicates the state when the load was
   // initiated, not the state at some later time.  aURI should be the URI the
   // sheet was loaded from (may be null for inline sheets).
   nsresult PostLoadEvent(nsIURI* aURI,
                          nsICSSStyleSheet* aSheet,
                          nsICSSLoaderObserver* aObserver,
-                         nsIParser* aParserToUnblock,
                          PRBool aWasAlternate);
 public:
   // Handle an event posted by PostLoadEvent
   void HandleLoadEvent(SheetLoadData* aEvent);
 
   // Note: LoadSheet is responsible for releasing aLoadData and setting the
   // sheet to complete on failure.
   nsresult LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState);
 
 protected:
   friend class SheetLoadData;
 
   // Protected functions and members are ones that SheetLoadData needs
-  // access to
+  // access to.
+
+  // Parse the stylesheet in aLoadData.  The sheet data comes from aStream.
+  // Set aCompleted to true if the parse finished, false otherwise (e.g. if the
+  // sheet had an @import).  If aCompleted is true when this returns, then
+  // ParseSheet also called SheetComplete on aLoadData
   nsresult ParseSheet(nsIUnicharInputStream* aStream,
                       SheetLoadData* aLoadData,
                       PRBool& aCompleted);
 
 public:
+  // The load of the sheet in aLoadData is done, one way or another.  Do final
+  // cleanup, including releasing aLoadData.
   void SheetComplete(SheetLoadData* aLoadData, nsresult aStatus);
 
+private:
+  typedef nsTArray<nsRefPtr<SheetLoadData> > LoadDataArray;
+  
+  // The guts of SheetComplete.  This may be called recursively on parent datas
+  // or datas that had glommed on to a single load.  The array is there so load
+  // datas whose observers need to be notified can be added to it.
+  void DoSheetComplete(SheetLoadData* aLoadData, nsresult aStatus,
+                       LoadDataArray& aDatasToNotify);
+
   static nsCOMArray<nsICSSParser>* gParsers;  // array of idle CSS parsers
 
-protected:
   // the load data needs access to the document...
   nsIDocument*      mDocument;  // the document we live for
 
 #ifdef DEBUG
   PRPackedBool            mSyncCallback;
 #endif
 
-private:
   PRPackedBool      mCaseSensitive; // is document CSS case sensitive
   PRPackedBool      mEnabled; // is enabled to load new styles
   nsCompatibility   mCompatMode;
   nsString          mPreferredSheet;  // title of preferred sheet
 
   nsInterfaceHashtable<nsURIHashKey,nsICSSStyleSheet> mCompleteSheets;
   nsDataHashtable<nsURIHashKey,SheetLoadData*> mLoadingDatas; // weak refs
   nsDataHashtable<nsURIHashKey,SheetLoadData*> mPendingDatas; // weak refs
   
   // We're not likely to have many levels of @import...  But likely to have
   // some.  Allocate some storage, what the hell.
   nsAutoVoidArray   mParsingDatas;
 
   // The array of posted stylesheet loaded events (SheetLoadDatas) we have.
   // Note that these are rare.
-  nsTArray<nsRefPtr<SheetLoadData> > mPostedEvents;
+  LoadDataArray mPostedEvents;
 };
 
 #endif // nsCSSLoader_h__
--- a/layout/style/nsICSSLoader.h
+++ b/layout/style/nsICSSLoader.h
@@ -45,28 +45,27 @@
 #include "nsCompatibility.h"
 
 class nsIAtom;
 class nsIURI;
 class nsICSSParser;
 class nsICSSStyleSheet;
 class nsPresContext;
 class nsIContent;
-class nsIParser;
 class nsIDocument;
 class nsIUnicharInputStream;
 class nsICSSLoaderObserver;
 class nsMediaList;
 class nsICSSImportRule;
 
 // IID for the nsICSSLoader interface
-// 446711e6-ad01-4702-8a9b-ce3f5e5d30f0
+// 5da3a869-270c-4f10-97d1-99eaa150eb4e
 #define NS_ICSS_LOADER_IID     \
-{ 0x446711e6, 0xad01, 0x4702, \
- { 0x8a, 0x9b, 0xce, 0x3f, 0x5e, 0x5d, 0x30, 0xf0 } }
+{ 0x5da3a869, 0x270c, 0x4f10, \
+ { 0x97, 0xd1, 0x99, 0xea, 0xa1, 0x50, 0xeb, 0x4e } }
 
 typedef void (*nsCSSLoaderCallbackFunc)(nsICSSStyleSheet* aSheet, void *aData, PRBool aDidNotify);
 
 class nsICSSLoader : public nsISupports {
 public:
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ICSS_LOADER_IID)
 
   NS_IMETHOD Init(nsIDocument* aDocument) = 0;
@@ -93,31 +92,27 @@ public:
    * stylesheet list of this CSSLoader's document.
    *
    * @param aElement the element linking to the stylesheet.  This must not be
    *                 null and must implement nsIStyleSheetLinkingElement.
    * @param aStream the character stream that holds the stylesheet data.
    * @param aLineNumber the line number at which the stylesheet data started.
    * @param aTitle the title of the sheet.
    * @param aMedia the media string for the sheet.
-   * @param aParserToUnblock the parser to unblock when the load completes.
-   *        Only loads that returned false for both aIsAlternate and
-   *        aCompleted will unblock the parser.
    * @param aObserver the observer to notify when the load completes.
    *        May be null.
    * @param [out] aCompleted whether parsing of the sheet completed.
    * @param [out] aIsAlternate whether the stylesheet ended up being an
    *        alternate sheet.
    */
   NS_IMETHOD LoadInlineStyle(nsIContent* aElement,
                              nsIUnicharInputStream* aStream, 
                              PRUint32 aLineNumber,
                              const nsSubstring& aTitle,
                              const nsSubstring& aMedia,
-                             nsIParser* aParserToUnblock,
                              nsICSSLoaderObserver* aObserver,
                              PRBool* aCompleted,
                              PRBool* aIsAlternate) = 0;
 
   /**
    * Load a linked (document) stylesheet.  If a successful result is returned,
    * aObserver is guaranteed to be notified asynchronously once the sheet is
    * loaded and marked complete.  If an error is returned, aObserver will not
@@ -125,31 +120,27 @@ public:
    * into the stylesheet list of this CSSLoader's document.
    *
    * @param aElement the element linking to the the stylesheet.  May be null.
    * @param aURL the URL of the sheet.
    * @param aTitle the title of the sheet.
    * @param aMedia the media string for the sheet.
    * @param aHasAlternateRel whether the rel for this link included
    *        "alternate".
-   * @param aParserToUnblock the parser to unblock when the load completes.
-   *        Only loads that returned false for aIsAlternate will unblock
-   *        the parser.
    * @param aObserver the observer to notify when the load completes.
    *                  May be null.
    * @param [out] aIsAlternate whether the stylesheet actually ended up beinga
    *        an alternate sheet.  Note that this need not match
    *        aHasAlternateRel.
    */
   NS_IMETHOD LoadStyleLink(nsIContent* aElement,
                            nsIURI* aURL, 
                            const nsSubstring& aTitle,
                            const nsSubstring& aMedia,
                            PRBool aHasAlternateRel,
-                           nsIParser* aParserToUnblock,
                            nsICSSLoaderObserver* aObserver,
                            PRBool* aIsAlternate) = 0;
 
   /**
    * Load a child (@import-ed) style sheet.  In addition to loading the sheet,
    * this method will insert it into the child sheet list of aParentSheet.  If
    * there is no sheet currently being parsed and the child sheet is not
    * complete when this method returns, then when the child sheet becomes
--- a/parser/htmlparser/src/nsViewSourceHTML.cpp
+++ b/parser/htmlparser/src/nsViewSourceHTML.cpp
@@ -387,18 +387,16 @@ NS_IMETHODIMP CViewSourceHTML::BuildMode
 
     nsITokenizer*  oldTokenizer=mTokenizer;
     mTokenizer=aTokenizer;
     nsTokenAllocator* theAllocator=mTokenizer->GetTokenAllocator();
 
     if(!mHasOpenRoot) {
       // For the stack-allocated tokens below, it's safe to pass a null
       // token allocator, because there are no attributes on the tokens.
-      PRBool didBlock = PR_FALSE;
-
       CStartToken htmlToken(NS_LITERAL_STRING("HTML"), eHTMLTag_html);
       nsCParserNode htmlNode(&htmlToken, 0/*stack token*/);
       mSink->OpenContainer(htmlNode);
 
       CStartToken headToken(NS_LITERAL_STRING("HEAD"), eHTMLTag_head);
       nsCParserNode headNode(&headToken, 0/*stack token*/);
       mSink->OpenContainer(headNode);
 
@@ -438,27 +436,23 @@ NS_IMETHODIMP CViewSourceHTML::BuildMode
           AddAttrToNode(theNode, theAllocator,
                         NS_LITERAL_STRING("type"),
                         NS_LITERAL_STRING("text/css"));
 
           AddAttrToNode(theNode, theAllocator,
                         NS_LITERAL_STRING("href"),
                         NS_LITERAL_STRING("resource://gre/res/viewsource.css"));
           
-          result = mSink->AddLeaf(theNode);
-          didBlock = result == NS_ERROR_HTMLPARSER_BLOCK;
+          mSink->AddLeaf(theNode);
         }
       }
 
       result = mSink->CloseContainer(eHTMLTag_head);
       if(NS_SUCCEEDED(result)) {
         mHasOpenRoot = PR_TRUE;
-        if (didBlock) {
-          result = NS_ERROR_HTMLPARSER_BLOCK;
-        }
       }
     }
     if (NS_SUCCEEDED(result) && !mHasOpenBody) {
       if (theAllocator) {
         CStartToken* bodyToken=
           NS_STATIC_CAST(CStartToken*,
                          theAllocator->CreateTokenOfType(eToken_start,
                                                          eHTMLTag_body,
@@ -506,18 +500,17 @@ NS_IMETHODIMP CViewSourceHTML::BuildMode
         result=HandleToken(theToken,aParser);
         if(NS_SUCCEEDED(result)) {
           IF_FREE(theToken, mTokenizer->GetTokenAllocator());
           if (mParser->CanInterrupt() &&
               mSink->DidProcessAToken() == NS_ERROR_HTMLPARSER_INTERRUPTED) {
             result = NS_ERROR_HTMLPARSER_INTERRUPTED;
             break;
           }
-        }
-        else if(NS_ERROR_HTMLPARSER_BLOCK!=result){
+        } else {
           mTokenizer->PushTokenFront(theToken);
         }
       }
       else break;
     }//while
    
     mTokenizer=oldTokenizer;
   }