diff --git a/mozilla/content/html/document/src/nsHTMLContentSink.cpp b/mozilla/content/html/document/src/nsHTMLContentSink.cpp index a438d444bd8..808d113d6c6 100644 --- a/mozilla/content/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/content/html/document/src/nsHTMLContentSink.cpp @@ -102,6 +102,7 @@ #include "nsDOMError.h" #include "nsIScrollable.h" +// #define ALLOW_ASYNCH_STYLE_SHEETS #ifdef ALLOW_ASYNCH_STYLE_SHEETS const PRBool kBlock=PR_FALSE; #else @@ -345,6 +346,11 @@ public: PRInt32 mInsideNoXXXTag; PRInt32 mInMonolithicContainer; + nsCOMPtr mStyleSheetTimer; // timer used to prevent infinite wait for style sheet + PRBool mStyleSheetTimerSet; // TRUE if a timer has been set since Init + PRInt32 mStyleSheetTimerInterval; // interval in milliseconds + PRUint32 mNumStyleSheetsLoading; // number of style sheets still loading + void StartLayout(); void ScrollToRef(); @@ -1862,7 +1868,7 @@ nsresult SinkContext::FlushTags(PRBool aNotify) { nsresult result = NS_OK; - + // Don't release last text node in case we need to add to it again FlushText(); @@ -2084,6 +2090,8 @@ HTMLContentSink::HTMLContentSink() { mInNotification = 0; mInMonolithicContainer = 0; mInsideNoXXXTag = 0; + + mStyleSheetTimerSet = PR_FALSE; } HTMLContentSink::~HTMLContentSink() @@ -2112,6 +2120,10 @@ HTMLContentSink::~HTMLContentSink() mNotificationTimer->Cancel(); } + if (mStyleSheetTimer) { + mStyleSheetTimer->Cancel(); + } + PRInt32 numContexts = mContextStack.Count(); if(mCurrentContext==mHeadContext) { @@ -2205,6 +2217,11 @@ HTMLContentSink::Init(nsIDocument* aDoc, mMaxTextRun = 8192; prefs->GetIntPref("content.maxtextrun", &mMaxTextRun); + mStyleSheetTimerSet = PR_FALSE; + mNumStyleSheetsLoading = 0; + mStyleSheetTimerInterval = (5*1000); + prefs->GetIntPref("content.notify.stylesheettimeout", &mStyleSheetTimerInterval); + nsIHTMLContentContainer* htmlContainer = nsnull; if (NS_SUCCEEDED(aDoc->QueryInterface(kIHTMLContentContainerIID, (void**)&htmlContainer))) { htmlContainer->GetCSSLoader(mCSSLoader); @@ -2284,6 +2301,11 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel) mNotificationTimer = 0; } + if (mStyleSheetTimer) { + mStyleSheetTimer->Cancel(); + mStyleSheetTimer = 0; + } + if (nsnull == mTitle) { mHTMLDocument->SetTitle(""); } @@ -2320,30 +2342,40 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel) NS_IMETHODIMP_(void) HTMLContentSink::Notify(nsITimer *timer) { - MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n")); - MOZ_TIMER_START(mWatch); -#ifdef MOZ_DEBUG - PRTime now = PR_Now(); - PRInt64 diff, interval; - PRInt32 delay; + if (timer == mStyleSheetTimer.get()) { + // our first sheet timer has expired: resume the parser now + mStyleSheetTimer = 0; + ResumeParsing(); + } else { - LL_I2L(interval, mNotificationInterval); - LL_SUB(diff, now, mLastNotificationTime); + MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n")); + MOZ_TIMER_START(mWatch); + + #ifdef MOZ_DEBUG + PRTime now = PR_Now(); + PRInt64 diff, interval; + PRInt32 delay; - LL_SUB(diff, diff, interval); - LL_L2I(delay, diff); - delay /= PR_USEC_PER_MSEC; + LL_I2L(interval, mNotificationInterval); + LL_SUB(diff, now, mLastNotificationTime); - mBackoffCount--; - SINK_TRACE(SINK_TRACE_REFLOW, - ("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount)); -#endif - if (mCurrentContext) { - mCurrentContext->FlushTags(PR_TRUE); + LL_SUB(diff, diff, interval); + LL_L2I(delay, diff); + delay /= PR_USEC_PER_MSEC; + + mBackoffCount--; + SINK_TRACE(SINK_TRACE_REFLOW, + ("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount)); + #endif + + if (mCurrentContext) { + mCurrentContext->FlushTags(PR_TRUE); + } + mNotificationTimer = 0; + + MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n")); + MOZ_TIMER_STOP(mWatch); } - mNotificationTimer = 0; - MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n")); - MOZ_TIMER_STOP(mWatch); } NS_IMETHODIMP @@ -2420,6 +2452,7 @@ HTMLContentSink::WillResume() { SINK_TRACE(SINK_TRACE_CALLS, ("HTMLContentSink::WillResume: this=%p", this)); + // Cancel a timer if we had one out there if (mNotificationTimer) { SINK_TRACE(SINK_TRACE_REFLOW, @@ -2427,7 +2460,6 @@ HTMLContentSink::WillResume() mNotificationTimer->Cancel(); mNotificationTimer = 0; } - return NS_OK; } @@ -3659,6 +3691,14 @@ NS_IMETHODIMP HTMLContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aDidNotify) { + mNumStyleSheetsLoading--; + + // if out timer is still pending, cancel it. + if (mNumStyleSheetsLoading==0 && mStyleSheetTimer) { + mStyleSheetTimer->Cancel(); + mStyleSheetTimer = 0; + } + // If there was a notification done for this style sheet, we know // that frames have been created for all content seen so far // (processing of a new style sheet causes recreation of the frame @@ -3719,6 +3759,9 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement, } if (isStyleSheet) { + PRBool blockParser = kBlock; + PRBool important = PR_FALSE; + PRBool alternate = PR_FALSE; // alternate (non-preferred) style sheet nsIURI* url = nsnull; { result = NS_NewURI(&url, aHref, mDocumentBaseURL); @@ -3733,14 +3776,19 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement, mPreferredStyle = aTitle; mCSSLoader->SetPreferredSheet(aTitle); mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle); + } else { + alternate = PR_TRUE; } } } - PRBool blockParser = kBlock; - if (-1 != linkTypes.IndexOf("important")) { blockParser = PR_TRUE; + important = PR_TRUE; + } + + if (alternate && !important) { + blockParser = PR_FALSE; } PRBool doneLoading; @@ -3750,9 +3798,35 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement, doneLoading, this); NS_RELEASE(url); - if (NS_SUCCEEDED(result) && blockParser && (! doneLoading)) { - result = NS_ERROR_HTMLPARSER_BLOCK; - } + if (NS_SUCCEEDED(result) && (!doneLoading)) { + // we are loading another one, so increment the counter + mNumStyleSheetsLoading++; + // if important, then just block + if (important) { + NS_ASSERTION(blockParser, "Must block for important styleSheets"); + result = NS_ERROR_HTMLPARSER_BLOCK; + } else { + // if not blocking the parser absolutely (!important) + // then setup a notification timer so we can locally + // unblock the parser if it takes too long + // bug=17309 + if (blockParser) { + NS_ASSERTION(!alternate, "Alternates should not block parser"); + // if no stylesheet timer, and none was previously set (ie. first one), then start one + if (!mStyleSheetTimer && !mStyleSheetTimerSet) { + result = NS_NewTimer(getter_AddRefs(mStyleSheetTimer)); + if (NS_SUCCEEDED(result)) { + result = mStyleSheetTimer->Init(this, mStyleSheetTimerInterval); + if( NS_SUCCEEDED(result)) { + mStyleSheetTimerSet = PR_TRUE; + // block the parser: we will unblock it when the timer expires + result = NS_ERROR_HTMLPARSER_BLOCK; + } + } + }// if no stylesheet timer + }// if !important and blockParser + } // if important + } // if succeeded && !doneLoading } } return result; diff --git a/mozilla/layout/html/document/src/nsHTMLContentSink.cpp b/mozilla/layout/html/document/src/nsHTMLContentSink.cpp index a438d444bd8..808d113d6c6 100644 --- a/mozilla/layout/html/document/src/nsHTMLContentSink.cpp +++ b/mozilla/layout/html/document/src/nsHTMLContentSink.cpp @@ -102,6 +102,7 @@ #include "nsDOMError.h" #include "nsIScrollable.h" +// #define ALLOW_ASYNCH_STYLE_SHEETS #ifdef ALLOW_ASYNCH_STYLE_SHEETS const PRBool kBlock=PR_FALSE; #else @@ -345,6 +346,11 @@ public: PRInt32 mInsideNoXXXTag; PRInt32 mInMonolithicContainer; + nsCOMPtr mStyleSheetTimer; // timer used to prevent infinite wait for style sheet + PRBool mStyleSheetTimerSet; // TRUE if a timer has been set since Init + PRInt32 mStyleSheetTimerInterval; // interval in milliseconds + PRUint32 mNumStyleSheetsLoading; // number of style sheets still loading + void StartLayout(); void ScrollToRef(); @@ -1862,7 +1868,7 @@ nsresult SinkContext::FlushTags(PRBool aNotify) { nsresult result = NS_OK; - + // Don't release last text node in case we need to add to it again FlushText(); @@ -2084,6 +2090,8 @@ HTMLContentSink::HTMLContentSink() { mInNotification = 0; mInMonolithicContainer = 0; mInsideNoXXXTag = 0; + + mStyleSheetTimerSet = PR_FALSE; } HTMLContentSink::~HTMLContentSink() @@ -2112,6 +2120,10 @@ HTMLContentSink::~HTMLContentSink() mNotificationTimer->Cancel(); } + if (mStyleSheetTimer) { + mStyleSheetTimer->Cancel(); + } + PRInt32 numContexts = mContextStack.Count(); if(mCurrentContext==mHeadContext) { @@ -2205,6 +2217,11 @@ HTMLContentSink::Init(nsIDocument* aDoc, mMaxTextRun = 8192; prefs->GetIntPref("content.maxtextrun", &mMaxTextRun); + mStyleSheetTimerSet = PR_FALSE; + mNumStyleSheetsLoading = 0; + mStyleSheetTimerInterval = (5*1000); + prefs->GetIntPref("content.notify.stylesheettimeout", &mStyleSheetTimerInterval); + nsIHTMLContentContainer* htmlContainer = nsnull; if (NS_SUCCEEDED(aDoc->QueryInterface(kIHTMLContentContainerIID, (void**)&htmlContainer))) { htmlContainer->GetCSSLoader(mCSSLoader); @@ -2284,6 +2301,11 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel) mNotificationTimer = 0; } + if (mStyleSheetTimer) { + mStyleSheetTimer->Cancel(); + mStyleSheetTimer = 0; + } + if (nsnull == mTitle) { mHTMLDocument->SetTitle(""); } @@ -2320,30 +2342,40 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel) NS_IMETHODIMP_(void) HTMLContentSink::Notify(nsITimer *timer) { - MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n")); - MOZ_TIMER_START(mWatch); -#ifdef MOZ_DEBUG - PRTime now = PR_Now(); - PRInt64 diff, interval; - PRInt32 delay; + if (timer == mStyleSheetTimer.get()) { + // our first sheet timer has expired: resume the parser now + mStyleSheetTimer = 0; + ResumeParsing(); + } else { - LL_I2L(interval, mNotificationInterval); - LL_SUB(diff, now, mLastNotificationTime); + MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n")); + MOZ_TIMER_START(mWatch); + + #ifdef MOZ_DEBUG + PRTime now = PR_Now(); + PRInt64 diff, interval; + PRInt32 delay; - LL_SUB(diff, diff, interval); - LL_L2I(delay, diff); - delay /= PR_USEC_PER_MSEC; + LL_I2L(interval, mNotificationInterval); + LL_SUB(diff, now, mLastNotificationTime); - mBackoffCount--; - SINK_TRACE(SINK_TRACE_REFLOW, - ("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount)); -#endif - if (mCurrentContext) { - mCurrentContext->FlushTags(PR_TRUE); + LL_SUB(diff, diff, interval); + LL_L2I(delay, diff); + delay /= PR_USEC_PER_MSEC; + + mBackoffCount--; + SINK_TRACE(SINK_TRACE_REFLOW, + ("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount)); + #endif + + if (mCurrentContext) { + mCurrentContext->FlushTags(PR_TRUE); + } + mNotificationTimer = 0; + + MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n")); + MOZ_TIMER_STOP(mWatch); } - mNotificationTimer = 0; - MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n")); - MOZ_TIMER_STOP(mWatch); } NS_IMETHODIMP @@ -2420,6 +2452,7 @@ HTMLContentSink::WillResume() { SINK_TRACE(SINK_TRACE_CALLS, ("HTMLContentSink::WillResume: this=%p", this)); + // Cancel a timer if we had one out there if (mNotificationTimer) { SINK_TRACE(SINK_TRACE_REFLOW, @@ -2427,7 +2460,6 @@ HTMLContentSink::WillResume() mNotificationTimer->Cancel(); mNotificationTimer = 0; } - return NS_OK; } @@ -3659,6 +3691,14 @@ NS_IMETHODIMP HTMLContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aDidNotify) { + mNumStyleSheetsLoading--; + + // if out timer is still pending, cancel it. + if (mNumStyleSheetsLoading==0 && mStyleSheetTimer) { + mStyleSheetTimer->Cancel(); + mStyleSheetTimer = 0; + } + // If there was a notification done for this style sheet, we know // that frames have been created for all content seen so far // (processing of a new style sheet causes recreation of the frame @@ -3719,6 +3759,9 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement, } if (isStyleSheet) { + PRBool blockParser = kBlock; + PRBool important = PR_FALSE; + PRBool alternate = PR_FALSE; // alternate (non-preferred) style sheet nsIURI* url = nsnull; { result = NS_NewURI(&url, aHref, mDocumentBaseURL); @@ -3733,14 +3776,19 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement, mPreferredStyle = aTitle; mCSSLoader->SetPreferredSheet(aTitle); mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle); + } else { + alternate = PR_TRUE; } } } - PRBool blockParser = kBlock; - if (-1 != linkTypes.IndexOf("important")) { blockParser = PR_TRUE; + important = PR_TRUE; + } + + if (alternate && !important) { + blockParser = PR_FALSE; } PRBool doneLoading; @@ -3750,9 +3798,35 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement, doneLoading, this); NS_RELEASE(url); - if (NS_SUCCEEDED(result) && blockParser && (! doneLoading)) { - result = NS_ERROR_HTMLPARSER_BLOCK; - } + if (NS_SUCCEEDED(result) && (!doneLoading)) { + // we are loading another one, so increment the counter + mNumStyleSheetsLoading++; + // if important, then just block + if (important) { + NS_ASSERTION(blockParser, "Must block for important styleSheets"); + result = NS_ERROR_HTMLPARSER_BLOCK; + } else { + // if not blocking the parser absolutely (!important) + // then setup a notification timer so we can locally + // unblock the parser if it takes too long + // bug=17309 + if (blockParser) { + NS_ASSERTION(!alternate, "Alternates should not block parser"); + // if no stylesheet timer, and none was previously set (ie. first one), then start one + if (!mStyleSheetTimer && !mStyleSheetTimerSet) { + result = NS_NewTimer(getter_AddRefs(mStyleSheetTimer)); + if (NS_SUCCEEDED(result)) { + result = mStyleSheetTimer->Init(this, mStyleSheetTimerInterval); + if( NS_SUCCEEDED(result)) { + mStyleSheetTimerSet = PR_TRUE; + // block the parser: we will unblock it when the timer expires + result = NS_ERROR_HTMLPARSER_BLOCK; + } + } + }// if no stylesheet timer + }// if !important and blockParser + } // if important + } // if succeeded && !doneLoading } } return result;