diff --git a/mozilla/content/base/public/nsIStyleSheetLinkingElement.h b/mozilla/content/base/public/nsIStyleSheetLinkingElement.h index 57acca6c43f..6c76d29cd97 100644 --- a/mozilla/content/base/public/nsIStyleSheetLinkingElement.h +++ b/mozilla/content/base/public/nsIStyleSheetLinkingElement.h @@ -40,14 +40,13 @@ #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; @@ -73,29 +72,30 @@ public: 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 diff --git a/mozilla/content/base/src/nsContentSink.cpp b/mozilla/content/base/src/nsContentSink.cpp index ee743beb838..35215cdfe34 100644 --- a/mozilla/content/base/src/nsContentSink.cpp +++ b/mozilla/content/base/src/nsContentSink.cpp @@ -89,12 +89,6 @@ PRLogModuleInfo* gContentSinkLogModuleInfo; -#ifdef ALLOW_ASYNCH_STYLE_SHEETS -const PRBool kBlockByDefault = PR_FALSE; -#else -const PRBool kBlockByDefault = PR_TRUE; -#endif - class nsScriptLoaderObserverProxy : public nsIScriptLoaderObserver { public: @@ -162,6 +156,7 @@ nsContentSink::nsContentSink() 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) { @@ -204,9 +199,9 @@ nsContentSink::Init(nsIDocument* aDoc, 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(); @@ -265,6 +260,26 @@ 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; } @@ -482,7 +497,6 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, nsAutoString title; nsAutoString type; nsAutoString media; - PRBool didBlock = PR_FALSE; // copy to work buffer nsAutoString stringList(aLinkData); @@ -621,9 +635,6 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, if (!href.IsEmpty() && !rel.IsEmpty()) { rv = ProcessLink(aElement, href, rel, title, type, media); - if (rv == NS_ERROR_HTMLPARSER_BLOCK) { - didBlock = PR_TRUE; - } } href.Truncate(); @@ -638,10 +649,6 @@ nsContentSink::ProcessLinkHeader(nsIContent* aElement, 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; @@ -710,19 +717,17 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement, 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; } @@ -881,10 +886,25 @@ nsContentSink::RefreshIfEnabled(nsIViewManager* vm) } 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); diff --git a/mozilla/content/base/src/nsContentSink.h b/mozilla/content/base/src/nsContentSink.h index 8c24c4b8384..2a57b49c584 100644 --- a/mozilla/content/base/src/nsContentSink.h +++ b/mozilla/content/base/src/nsContentSink.h @@ -74,6 +74,7 @@ class nsIChannel; class nsIContent; class nsIViewManager; class nsNodeInfoManager; +class nsScriptLoader; #ifdef NS_DEBUG @@ -169,7 +170,11 @@ protected: 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(); @@ -219,6 +224,7 @@ protected: nsCOMPtr mDocShell; nsCOMPtr mCSSLoader; nsRefPtr mNodeInfoManager; + nsRefPtr mScriptLoader; nsCOMArray mScriptElements; @@ -231,6 +237,7 @@ protected: PRInt32 mNotificationInterval; // Time of last notification + // Note: mLastNotificationTime is only valid once mLayoutStarted is true. PRTime mLastNotificationTime; // Timer used for notification @@ -255,6 +262,8 @@ protected: 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; @@ -275,6 +284,8 @@ protected: PRInt32 mInNotification; + PRUint32 mPendingSheetCount; + // Measures content model creation time for current document MOZ_TIMER_DECLARE(mWatch) }; diff --git a/mozilla/content/base/src/nsStyleLinkElement.cpp b/mozilla/content/base/src/nsStyleLinkElement.cpp index 000dc426ecc..81de24ea769 100644 --- a/mozilla/content/base/src/nsStyleLinkElement.cpp +++ b/mozilla/content/base/src/nsStyleLinkElement.cpp @@ -110,10 +110,8 @@ nsStyleLinkElement::GetStyleSheet(nsIStyleSheet*& aStyleSheet) } NS_IMETHODIMP -nsStyleLinkElement::InitStyleLinkElement(nsIParser* aParser, - PRBool aDontLoadStyle) +nsStyleLinkElement::InitStyleLinkElement(PRBool aDontLoadStyle) { - mParser = aParser; mDontLoadStyle = aDontLoadStyle; return NS_OK; @@ -197,17 +195,33 @@ void nsStyleLinkElement::ParseLinkTypes(const nsAString& aTypes, } } -#ifdef ALLOW_ASYNCH_STYLE_SHEETS -const PRBool kBlockByDefault=PR_FALSE; -#else -const PRBool kBlockByDefault=PR_TRUE; -#endif - NS_IMETHODIMP -nsStyleLinkElement::UpdateStyleSheet(nsIDocument *aOldDocument, - nsICSSLoaderObserver* aObserver, - PRBool aForceUpdate) +nsStyleLinkElement::UpdateStyleSheet(nsICSSLoaderObserver* aObserver, + PRBool* aWillNotify, + PRBool* aIsAlternate) { + return DoUpdateStyleSheet(nsnull, aObserver, aWillNotify, aIsAlternate, + PR_FALSE); +} + +nsresult +nsStyleLinkElement::UpdateStyleSheetInternal(nsIDocument *aOldDocument, + PRBool aForceUpdate) +{ + PRBool notify, alternate; + return DoUpdateStyleSheet(aOldDocument, nsnull, ¬ify, &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 @@ -223,13 +237,6 @@ nsStyleLinkElement::UpdateStyleSheet(nsIDocument *aOldDocument, 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 parser = mParser; - mParser = nsnull; - nsCOMPtr thisContent; QueryInterface(NS_GET_IID(nsIContent), getter_AddRefs(thisContent)); @@ -278,11 +285,7 @@ nsStyleLinkElement::UpdateStyleSheet(nsIDocument *aOldDocument, return NS_OK; } - if (!kBlockByDefault) { - parser = nsnull; - } - - PRBool doneLoading; + PRBool doneLoading = PR_FALSE; nsresult rv = NS_OK; if (isInline) { nsAutoString content; @@ -299,20 +302,19 @@ nsStyleLinkElement::UpdateStyleSheet(nsIDocument *aOldDocument, // 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; } diff --git a/mozilla/content/base/src/nsStyleLinkElement.h b/mozilla/content/base/src/nsStyleLinkElement.h index 24cf851ee55..a7dd8ba9e40 100644 --- a/mozilla/content/base/src/nsStyleLinkElement.h +++ b/mozilla/content/base/src/nsStyleLinkElement.h @@ -50,7 +50,6 @@ #include "nsIDOMLinkStyle.h" #include "nsIStyleSheetLinkingElement.h" #include "nsIStyleSheet.h" -#include "nsIParser.h" #include "nsIURI.h" class nsIDocument; @@ -71,26 +70,10 @@ public: // 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); @@ -100,6 +83,17 @@ public: 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, @@ -107,9 +101,23 @@ protected: 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 mStyleSheet; - nsCOMPtr mParser; PRPackedBool mDontLoadStyle; PRPackedBool mUpdatesEnabled; PRUint32 mLineNumber; diff --git a/mozilla/content/html/content/src/nsHTMLLinkElement.cpp b/mozilla/content/html/content/src/nsHTMLLinkElement.cpp index 010361ee0f3..8729fe7e1c8 100644 --- a/mozilla/content/html/content/src/nsHTMLLinkElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLLinkElement.cpp @@ -205,7 +205,7 @@ nsHTMLLinkElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, 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 @@ -247,7 +247,7 @@ nsHTMLLinkElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) // event! CreateAndDispatchEvent(oldDoc, NS_LITERAL_STRING("DOMLinkRemoved")); nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); - UpdateStyleSheet(oldDoc); + UpdateStyleSheetInternal(oldDoc); } void @@ -296,12 +296,12 @@ nsHTMLLinkElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, 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; @@ -314,12 +314,12 @@ nsHTMLLinkElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, 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; diff --git a/mozilla/content/html/content/src/nsHTMLStyleElement.cpp b/mozilla/content/html/content/src/nsHTMLStyleElement.cpp index 94f8fd6765e..32a03e1c34d 100644 --- a/mozilla/content/html/content/src/nsHTMLStyleElement.cpp +++ b/mozilla/content/html/content/src/nsHTMLStyleElement.cpp @@ -196,7 +196,7 @@ nsHTMLStyleElement::CharacterDataChanged(nsIDocument* aDocument, nsIContent* aContent, CharacterDataChangeInfo* aInfo) { - UpdateStyleSheet(); + UpdateStyleSheetInternal(nsnull); } void @@ -204,7 +204,7 @@ nsHTMLStyleElement::ContentAppended(nsIDocument* aDocument, nsIContent* aContainer, PRInt32 aNewIndexInContainer) { - UpdateStyleSheet(); + UpdateStyleSheetInternal(nsnull); } void @@ -213,7 +213,7 @@ nsHTMLStyleElement::ContentInserted(nsIDocument* aDocument, nsIContent* aChild, PRInt32 aIndexInContainer) { - UpdateStyleSheet(); + UpdateStyleSheetInternal(nsnull); } void @@ -222,7 +222,7 @@ nsHTMLStyleElement::ContentRemoved(nsIDocument* aDocument, nsIContent* aChild, PRInt32 aIndexInContainer) { - UpdateStyleSheet(); + UpdateStyleSheetInternal(nsnull); } nsresult @@ -235,7 +235,7 @@ nsHTMLStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, aCompileEventHandlers); NS_ENSURE_SUCCESS(rv, rv); - UpdateStyleSheet(nsnull); + UpdateStyleSheetInternal(nsnull); return rv; } @@ -246,7 +246,7 @@ nsHTMLStyleElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) nsCOMPtr oldDoc = GetCurrentDoc(); nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); - UpdateStyleSheet(oldDoc); + UpdateStyleSheetInternal(oldDoc); } nsresult @@ -257,11 +257,11 @@ nsHTMLStyleElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, 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; @@ -274,11 +274,11 @@ nsHTMLStyleElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, 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; @@ -300,7 +300,7 @@ nsHTMLStyleElement::SetInnerHTML(const nsAString& aInnerHTML) SetEnableUpdates(PR_TRUE); - UpdateStyleSheet(); + UpdateStyleSheetInternal(nsnull); return rv; } diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index 33e24b03221..44570063f32 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -280,7 +280,7 @@ protected: nsresult FlushTags(); - void StartLayout(); + void StartLayout(PRBool aIgnorePendingSheets); /** * AddBaseTagInfo adds the "current" base URI and target to the content node @@ -786,11 +786,11 @@ SinkContext::OpenContainer(const nsIParserNode& aNode) // 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); @@ -1811,7 +1811,6 @@ HTMLContentSink::WillBuildModel(void) NS_IMETHODIMP HTMLContentSink::DidBuildModel(void) { - // NRA Dump stopwatch stop info here #ifdef MOZ_PERF_METRICS MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::DidBuildModel(), this=%p\n", @@ -1845,7 +1844,7 @@ HTMLContentSink::DidBuildModel(void) } if (!bDestroying) { - StartLayout(); + StartLayout(PR_FALSE); } } @@ -2095,7 +2094,7 @@ HTMLContentSink::OpenBody(const nsIParserNode& aNode) mCurrentContext->mStack[parentIndex].mNumFlushed = childCount; } - StartLayout(); + StartLayout(PR_FALSE); return NS_OK; } @@ -2293,7 +2292,7 @@ HTMLContentSink::CloseFrameset() MOZ_TIMER_STOP(mWatch); if (done && mFramesEnabled) { - StartLayout(); + StartLayout(PR_FALSE); } return rv; @@ -2810,7 +2809,7 @@ HTMLContentSink::NotifyTagObservers(nsIParserNode* aNode) } void -HTMLContentSink::StartLayout() +HTMLContentSink::StartLayout(PRBool aIgnorePendingSheets) { if (mLayoutStarted) { return; @@ -2818,7 +2817,7 @@ HTMLContentSink::StartLayout() mHTMLDocument->SetIsFrameset(mFrameset != nsnull); - nsContentSink::StartLayout(mFrameset != nsnull); + nsContentSink::StartLayout(aIgnorePendingSheets); } void @@ -2967,10 +2966,10 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode) 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); } } @@ -2985,7 +2984,13 @@ HTMLContentSink::ProcessLINKTag(const nsIParserNode& aNode) 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 nsAutoString relVal; @@ -3175,7 +3180,13 @@ HTMLContentSink::ProcessSTYLEEndTag(nsGenericHTMLElement* content) // 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; @@ -3196,7 +3207,7 @@ HTMLContentSink::FlushPendingNotifications(mozFlushType aType) if (aType & Flush_OnlyReflow) { // Make sure that layout has started so that the reflow flush // will actually happen. - StartLayout(); + StartLayout(PR_TRUE); } } } diff --git a/mozilla/content/svg/content/src/nsSVGStyleElement.cpp b/mozilla/content/svg/content/src/nsSVGStyleElement.cpp index 3eb7dcce2a4..78a6a12ce8f 100644 --- a/mozilla/content/svg/content/src/nsSVGStyleElement.cpp +++ b/mozilla/content/svg/content/src/nsSVGStyleElement.cpp @@ -149,7 +149,7 @@ nsSVGStyleElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, { nsresult rv = nsSVGStyleElementBase::InsertChildAt(aKid, aIndex, aNotify); if (NS_SUCCEEDED(rv)) { - UpdateStyleSheet(); + UpdateStyleSheetInternal(nsnull); } return rv; @@ -160,7 +160,7 @@ nsSVGStyleElement::RemoveChildAt(PRUint32 aIndex, PRBool aNotify) { nsresult rv = nsSVGStyleElementBase::RemoveChildAt(aIndex, aNotify); if (NS_SUCCEEDED(rv)) { - UpdateStyleSheet(); + UpdateStyleSheetInternal(nsnull); } return rv; @@ -176,7 +176,7 @@ nsSVGStyleElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, aCompileEventHandlers); NS_ENSURE_SUCCESS(rv, rv); - UpdateStyleSheet(nsnull); + UpdateStyleSheetInternal(nsnull); return rv; } @@ -187,7 +187,7 @@ nsSVGStyleElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) nsCOMPtr oldDoc = GetCurrentDoc(); nsSVGStyleElementBase::UnbindFromTree(aDeep, aNullParent); - UpdateStyleSheet(oldDoc); + UpdateStyleSheetInternal(oldDoc); } nsresult @@ -198,11 +198,11 @@ nsSVGStyleElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, 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; @@ -215,11 +215,11 @@ nsSVGStyleElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, 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; diff --git a/mozilla/content/xbl/src/nsXBLContentSink.cpp b/mozilla/content/xbl/src/nsXBLContentSink.cpp index 18a32d8788a..d917e9e374f 100644 --- a/mozilla/content/xbl/src/nsXBLContentSink.cpp +++ b/mozilla/content/xbl/src/nsXBLContentSink.cpp @@ -111,7 +111,7 @@ nsXBLContentSink::Init(nsIDocument* aDoc, } void -nsXBLContentSink::MaybeStartLayout() +nsXBLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets) { return; } diff --git a/mozilla/content/xbl/src/nsXBLContentSink.h b/mozilla/content/xbl/src/nsXBLContentSink.h index e55072bb9f9..582011c3173 100644 --- a/mozilla/content/xbl/src/nsXBLContentSink.h +++ b/mozilla/content/xbl/src/nsXBLContentSink.h @@ -112,7 +112,7 @@ public: protected: // nsXMLContentSink overrides - void MaybeStartLayout(); + virtual void MaybeStartLayout(PRBool aIgnorePendingSheets); PRBool OnOpenContainer(const PRUnichar **aAtts, PRUint32 aAttsCount, diff --git a/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp b/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp index 9458fd1b095..e9bcd263908 100644 --- a/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp +++ b/mozilla/content/xml/content/src/nsXMLStylesheetPI.cpp @@ -122,7 +122,7 @@ nsXMLStylesheetPI::BindToTree(nsIDocument* aDocument, nsIContent* aParent, aCompileEventHandlers); NS_ENSURE_SUCCESS(rv, rv); - UpdateStyleSheet(nsnull); + UpdateStyleSheetInternal(nsnull); return rv; } @@ -133,7 +133,7 @@ nsXMLStylesheetPI::UnbindFromTree(PRBool aDeep, PRBool aNullParent) nsCOMPtr oldDoc = GetCurrentDoc(); nsXMLProcessingInstruction::UnbindFromTree(aDeep, aNullParent); - UpdateStyleSheet(oldDoc); + UpdateStyleSheetInternal(oldDoc); } // nsIDOMNode @@ -143,7 +143,7 @@ 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; } diff --git a/mozilla/content/xml/document/src/nsXMLContentSink.cpp b/mozilla/content/xml/document/src/nsXMLContentSink.cpp index 39cba2054d9..e3ceda09ed0 100644 --- a/mozilla/content/xml/document/src/nsXMLContentSink.cpp +++ b/mozilla/content/xml/document/src/nsXMLContentSink.cpp @@ -343,7 +343,7 @@ nsXMLContentSink::DidBuildModel() // Check if we want to prettyprint MaybePrettyPrint(); - StartLayout(); + StartLayout(PR_FALSE); ScrollToRef(); @@ -424,7 +424,7 @@ nsXMLContentSink::OnTransformDone(nsresult aResult, } // Start the layout process - StartLayout(); + StartLayout(PR_FALSE); ScrollToRef(); @@ -520,7 +520,7 @@ nsXMLContentSink::CreateElement(const PRUnichar** aAtts, PRUint32 aAttsCount, aNodeInfo->Equals(nsGkAtoms::style, kNameSpaceID_SVG)) { nsCOMPtr 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); @@ -626,9 +626,12 @@ nsXMLContentSink::CloseElement(nsIContent* aContent) nsCOMPtr 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(); } } } @@ -747,13 +750,9 @@ nsXMLContentSink::ProcessStyleLink(nsIContent* aElement, 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; } @@ -874,32 +873,14 @@ nsXMLContentSink::PopContent() } 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 docShellAsItem(do_QueryInterface(mDocShell)); - if (docShellAsItem) { - nsCOMPtr root; - docShellAsItem->GetSameTypeRootTreeItem(getter_AddRefs(root)); - if(docShellAsItem == root) { - topLevelFrameset = PR_TRUE; - } - } - - nsContentSink::StartLayout(topLevelFrameset); - + StartLayout(aIgnorePendingSheets); } #ifdef MOZ_MATHML @@ -1055,7 +1036,7 @@ nsXMLContentSink::HandleStartElement(const PRUnichar *aName, mInMonolithicContainer++; } - MaybeStartLayout(); + MaybeStartLayout(PR_FALSE); return NS_SUCCEEDED(result) ? DidProcessATokenImpl() : result; } @@ -1251,7 +1232,7 @@ nsXMLContentSink::HandleProcessingInstruction(const PRUnichar *aTarget, nsCOMPtr ssle(do_QueryInterface(node)); if (ssle) { - ssle->InitStyleLinkElement(mParser, PR_FALSE); + ssle->InitStyleLinkElement(PR_FALSE); ssle->SetEnableUpdates(PR_FALSE); mPrettyPrintXML = PR_FALSE; } @@ -1261,14 +1242,22 @@ nsXMLContentSink::HandleProcessingInstruction(const PRUnichar *aTarget, 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); - - if (NS_FAILED(rv)) { - if (rv == NS_ERROR_HTMLPARSER_BLOCK && mParser) { - mParser->BlockParser(); + 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(); } - return rv; + + return NS_OK; } } @@ -1278,6 +1267,7 @@ nsXMLContentSink::HandleProcessingInstruction(const PRUnichar *aTarget, if (mState != eXMLContentSinkState_InProlog || !target.EqualsLiteral("xml-stylesheet") || + type.IsEmpty() || type.LowerCaseEqualsLiteral("text/css")) { return DidProcessATokenImpl(); } @@ -1520,7 +1510,7 @@ nsXMLContentSink::FlushPendingNotifications(mozFlushType aType) if (aType & Flush_OnlyReflow) { // Make sure that layout has started so that the reflow flush // will actually happen. - MaybeStartLayout(); + MaybeStartLayout(PR_TRUE); } } } diff --git a/mozilla/content/xml/document/src/nsXMLContentSink.h b/mozilla/content/xml/document/src/nsXMLContentSink.h index b17287f2f1d..5dbc8903c8a 100644 --- a/mozilla/content/xml/document/src/nsXMLContentSink.h +++ b/mozilla/content/xml/document/src/nsXMLContentSink.h @@ -106,8 +106,10 @@ public: 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); diff --git a/mozilla/content/xml/document/src/nsXMLFragmentContentSink.cpp b/mozilla/content/xml/document/src/nsXMLFragmentContentSink.cpp index 507079ac61d..7cbbcdce9cf 100644 --- a/mozilla/content/xml/document/src/nsXMLFragmentContentSink.cpp +++ b/mozilla/content/xml/document/src/nsXMLFragmentContentSink.cpp @@ -114,7 +114,7 @@ protected: nsIContent** aResult, PRBool* aAppendContent); virtual nsresult CloseElement(nsIContent* aContent); - void MaybeStartLayout(); + virtual void MaybeStartLayout(PRBool aIgnorePendingSheets); // nsContentSink overrides virtual nsresult ProcessStyleLink(nsIContent* aElement, @@ -265,7 +265,7 @@ nsXMLFragmentContentSink::CloseElement(nsIContent* aContent) } void -nsXMLFragmentContentSink::MaybeStartLayout() +nsXMLFragmentContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets) { return; } diff --git a/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.cpp b/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.cpp index d3e9fa65579..c125667535d 100644 --- a/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.cpp +++ b/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.cpp @@ -349,14 +349,12 @@ txMozillaXMLOutput::endElement() do_QueryInterface(mCurrentNode); if (ssle) { ssle->SetEnableUpdates(PR_TRUE); - if (ssle->UpdateStyleSheet(nsnull, mNotifier) == - NS_ERROR_HTMLPARSER_BLOCK) { - nsCOMPtr 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(); } } } @@ -421,7 +419,7 @@ txMozillaXMLOutput::processingInstruction(const nsString& aTarget, const nsStrin if (mCreatingNewDocument) { ssle = do_QueryInterface(pi); if (ssle) { - ssle->InitStyleLinkElement(nsnull, PR_FALSE); + ssle->InitStyleLinkElement(PR_FALSE); ssle->SetEnableUpdates(PR_FALSE); } } @@ -431,14 +429,11 @@ txMozillaXMLOutput::processingInstruction(const nsString& aTarget, const nsStrin if (ssle) { ssle->SetEnableUpdates(PR_TRUE); - rv = ssle->UpdateStyleSheet(nsnull, mNotifier); - if (rv == NS_ERROR_HTMLPARSER_BLOCK) { - nsCOMPtr 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(); } } @@ -580,7 +575,7 @@ txMozillaXMLOutput::startElementInternal(nsIAtom* aPrefix, nsCOMPtr ssle = do_QueryInterface(mOpenedElement); if (ssle) { - ssle->InitStyleLinkElement(nsnull, PR_FALSE); + ssle->InitStyleLinkElement(PR_FALSE); ssle->SetEnableUpdates(PR_FALSE); } } @@ -1003,8 +998,8 @@ txMozillaXMLOutput::createHTMLElement(nsIAtom* aName, } txTransformNotifier::txTransformNotifier() - : mInTransform(PR_FALSE) - + : mPendingStylesheetCount(0), + mInTransform(PR_FALSE) { } @@ -1048,15 +1043,19 @@ 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)) { - SignalTransformEnd(); + 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; } @@ -1073,11 +1072,10 @@ txTransformNotifier::AddScriptElement(nsIScriptElement* aElement) 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 @@ -1106,11 +1104,14 @@ 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 diff --git a/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.h b/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.h index 6062e1f4125..782224e402e 100644 --- a/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.h +++ b/mozilla/content/xslt/src/xslt/txMozillaXMLOutput.h @@ -76,7 +76,7 @@ public: 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); @@ -87,7 +87,7 @@ private: nsCOMPtr mDocument; nsCOMPtr mObserver; nsCOMArray mScriptElements; - nsCOMArray mStylesheets; + PRUint32 mPendingStylesheetCount; PRPackedBool mInTransform; }; diff --git a/mozilla/content/xul/document/src/nsXULContentSink.cpp b/mozilla/content/xul/document/src/nsXULContentSink.cpp index f227990e409..1d17907ae65 100644 --- a/mozilla/content/xul/document/src/nsXULContentSink.cpp +++ b/mozilla/content/xul/document/src/nsXULContentSink.cpp @@ -50,9 +50,6 @@ #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" @@ -369,10 +366,8 @@ XULContentSinkImpl::Init(nsIDocument* aDocument, 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) diff --git a/mozilla/content/xul/document/src/nsXULContentSink.h b/mozilla/content/xul/document/src/nsXULContentSink.h index 9506969d432..e7953d996cc 100644 --- a/mozilla/content/xul/document/src/nsXULContentSink.h +++ b/mozilla/content/xul/document/src/nsXULContentSink.h @@ -49,8 +49,6 @@ #include "nsVoidArray.h" #include "nsWeakPtr.h" -class nsICSSLoader; -class nsICSSParser; class nsIDocument; class nsIScriptSecurityManager; class nsAttrName; @@ -173,8 +171,6 @@ protected: // We use regular pointer b/c of funky exports on nsIParser: nsIParser* mParser; // [OWNER] - nsCOMPtr mCSSLoader; // [OWNER] - nsCOMPtr mCSSParser; // [OWNER] nsCOMPtr mSecMan; }; diff --git a/mozilla/content/xul/document/src/nsXULDocument.cpp b/mozilla/content/xul/document/src/nsXULDocument.cpp index 7fe87720652..ef0977f1682 100644 --- a/mozilla/content/xul/document/src/nsXULDocument.cpp +++ b/mozilla/content/xul/document/src/nsXULDocument.cpp @@ -2514,7 +2514,7 @@ nsXULDocument::InsertXMLStylesheetPI(const nsXULPrototypePI* aProtoPI, 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); @@ -2527,12 +2527,11 @@ nsXULDocument::InsertXMLStylesheetPI(const nsXULPrototypePI* aProtoPI, // 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; @@ -2878,7 +2877,10 @@ nsXULDocument::ResumeWalk() do_QueryInterface(element); NS_ASSERTION(ssle, " doesn't implement " "nsIStyleSheetLinkingElement?"); - ssle->UpdateStyleSheet(nsnull, nsnull); + PRBool willNotify; + PRBool isAlternate; + ssle->UpdateStyleSheet(nsnull, &willNotify, + &isAlternate); } } diff --git a/mozilla/layout/style/nsCSSLoader.cpp b/mozilla/layout/style/nsCSSLoader.cpp index 51a836f09c4..4a65f36828e 100644 --- a/mozilla/layout/style/nsCSSLoader.cpp +++ b/mozilla/layout/style/nsCSSLoader.cpp @@ -59,7 +59,6 @@ #include "nsUnicharUtils.h" #include "nsHashtable.h" #include "nsIURI.h" -#include "nsIParser.h" #include "nsIServiceManager.h" #include "nsNetUtil.h" #include "nsContentUtils.h" @@ -144,7 +143,6 @@ NS_IMPL_ISUPPORTS2(SheetLoadData, nsIUnicharStreamLoaderObserver, nsIRunnable) SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, const nsSubstring& aTitle, - nsIParser* aParserToUnblock, nsIURI* aURI, nsICSSStyleSheet* aSheet, nsIStyleSheetLinkingElement* aOwningElement, @@ -152,7 +150,6 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, nsICSSLoaderObserver* aObserver) : mLoader(aLoader), mTitle(aTitle), - mParserToUnblock(aParserToUnblock), mURI(aURI), mLineNumber(1), mSheet(aSheet), @@ -180,7 +177,6 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, SheetLoadData* aParentData, nsICSSLoaderObserver* aObserver) : mLoader(aLoader), - mParserToUnblock(nsnull), mURI(aURI), mLineNumber(1), mSheet(aSheet), @@ -216,7 +212,6 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, PRBool aAllowUnsafeRules, nsICSSLoaderObserver* aObserver) : mLoader(aLoader), - mParserToUnblock(nsnull), mURI(aURI), mLineNumber(1), mSheet(aSheet), @@ -1117,8 +1112,6 @@ CSSLoaderImpl::InsertSheetInDoc(nsICSSStyleSheet* aSheet, 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(); @@ -1466,6 +1459,36 @@ 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, 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."); @@ -1489,16 +1512,6 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) } } - - // This is a mess. If we have a document.write() that writes out - // two 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) { @@ -1506,20 +1519,12 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) 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 || @@ -1534,7 +1539,7 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) if (data->mParentData && --(data->mParentData->mPendingChildren) == 0 && mParsingDatas.IndexOf(data->mParentData) == -1) { - SheetComplete(data->mParentData, aStatus); + DoSheetComplete(data->mParentData, aStatus, aDatasToNotify); } data = data->mNext; @@ -1561,10 +1566,6 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) } 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 @@ -1573,11 +1574,9 @@ CSSLoaderImpl::LoadInlineStyle(nsIContent* aElement, 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!"); @@ -1612,9 +1611,9 @@ CSSLoaderImpl::LoadInlineStyle(nsIContent* aElement, 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(); @@ -1640,7 +1639,6 @@ CSSLoaderImpl::LoadStyleLink(nsIContent* aElement, const nsSubstring& aTitle, const nsSubstring& aMedia, PRBool aHasAlternateRel, - nsIParser* aParserToUnblock, nsICSSLoaderObserver* aObserver, PRBool* aIsAlternate) { @@ -1691,15 +1689,19 @@ CSSLoaderImpl::LoadStyleLink(nsIContent* aElement, 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 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(); @@ -1916,7 +1918,7 @@ CSSLoaderImpl::InternalLoadNonDocumentSheet(nsIURI* aURL, 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); @@ -1950,18 +1952,14 @@ 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 evt = new SheetLoadData(this, EmptyString(), // title doesn't matter here - aParserToUnblock, aURI, aSheet, nsnull, // owning element doesn't matter here diff --git a/mozilla/layout/style/nsCSSLoader.h b/mozilla/layout/style/nsCSSLoader.h index 489b4288316..9a23c99c196 100644 --- a/mozilla/layout/style/nsCSSLoader.h +++ b/mozilla/layout/style/nsCSSLoader.h @@ -53,7 +53,6 @@ class CSSLoaderImpl; class nsIURI; -class nsIParser; class nsICSSStyleSheet; class nsIStyleSheetLinkingElement; class nsICSSLoaderObserver; @@ -113,7 +112,6 @@ public: // Data for loading a sheet linked from a document SheetLoadData(CSSLoaderImpl* aLoader, const nsSubstring& aTitle, - nsIParser* aParserToUnblock, nsIURI* aURI, nsICSSStyleSheet* aSheet, nsIStyleSheetLinkingElement* aOwningElement, @@ -152,9 +150,6 @@ public: // Charset we decided to use for the sheet nsCString mCharset; - // Parser to be told to continue parsing once the load completes - nsCOMPtr mParserToUnblock; - // URI we're loading. Null for inline sheets nsCOMPtr mURI; @@ -261,17 +256,15 @@ public: 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); @@ -357,7 +350,6 @@ private: nsresult PostLoadEvent(nsIURI* aURI, nsICSSStyleSheet* aSheet, nsICSSLoaderObserver* aObserver, - nsIParser* aParserToUnblock, PRBool aWasAlternate); public: // Handle an event posted by PostLoadEvent @@ -371,17 +363,32 @@ 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 > 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* gParsers; // array of idle CSS parsers -protected: // the load data needs access to the document... nsIDocument* mDocument; // the document we live for @@ -389,7 +396,6 @@ protected: PRPackedBool mSyncCallback; #endif -private: PRPackedBool mCaseSensitive; // is document CSS case sensitive PRPackedBool mEnabled; // is enabled to load new styles nsCompatibility mCompatMode; @@ -405,7 +411,7 @@ private: // The array of posted stylesheet loaded events (SheetLoadDatas) we have. // Note that these are rare. - nsTArray > mPostedEvents; + LoadDataArray mPostedEvents; }; #endif // nsCSSLoader_h__ diff --git a/mozilla/layout/style/nsICSSLoader.h b/mozilla/layout/style/nsICSSLoader.h index 0c3bc161c6f..3df891c59d0 100644 --- a/mozilla/layout/style/nsICSSLoader.h +++ b/mozilla/layout/style/nsICSSLoader.h @@ -50,7 +50,6 @@ class nsICSSParser; class nsICSSStyleSheet; class nsPresContext; class nsIContent; -class nsIParser; class nsIDocument; class nsIUnicharInputStream; class nsICSSLoaderObserver; @@ -58,10 +57,10 @@ 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); @@ -98,9 +97,6 @@ public: * @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. @@ -112,7 +108,6 @@ public: PRUint32 aLineNumber, const nsSubstring& aTitle, const nsSubstring& aMedia, - nsIParser* aParserToUnblock, nsICSSLoaderObserver* aObserver, PRBool* aCompleted, PRBool* aIsAlternate) = 0; @@ -130,9 +125,6 @@ public: * @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 @@ -144,7 +136,6 @@ public: const nsSubstring& aTitle, const nsSubstring& aMedia, PRBool aHasAlternateRel, - nsIParser* aParserToUnblock, nsICSSLoaderObserver* aObserver, PRBool* aIsAlternate) = 0; diff --git a/mozilla/parser/htmlparser/src/nsViewSourceHTML.cpp b/mozilla/parser/htmlparser/src/nsViewSourceHTML.cpp index 72cdd4fe72f..23af1118ba0 100644 --- a/mozilla/parser/htmlparser/src/nsViewSourceHTML.cpp +++ b/mozilla/parser/htmlparser/src/nsViewSourceHTML.cpp @@ -392,8 +392,6 @@ NS_IMETHODIMP CViewSourceHTML::BuildModel(nsIParser* aParser,nsITokenizer* aToke 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); @@ -443,17 +441,13 @@ NS_IMETHODIMP CViewSourceHTML::BuildModel(nsIParser* aParser,nsITokenizer* aToke 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) { @@ -511,8 +505,7 @@ NS_IMETHODIMP CViewSourceHTML::BuildModel(nsIParser* aParser,nsITokenizer* aToke result = NS_ERROR_HTMLPARSER_INTERRUPTED; break; } - } - else if(NS_ERROR_HTMLPARSER_BLOCK!=result){ + } else { mTokenizer->PushTokenFront(theToken); } }