Implemented a timer for loading CSS style sheets to allow content to be displayed if the sheet is taking too long to load. b=17309 r=nisheeth

This commit is contained in:
attinasi%netscape.com 2000-03-31 01:57:54 +00:00
Родитель b1d5e9188b
Коммит 0735cef009
2 изменённых файлов: 202 добавлений и 54 удалений

Просмотреть файл

@ -102,6 +102,7 @@
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsIScrollable.h" #include "nsIScrollable.h"
// #define ALLOW_ASYNCH_STYLE_SHEETS
#ifdef ALLOW_ASYNCH_STYLE_SHEETS #ifdef ALLOW_ASYNCH_STYLE_SHEETS
const PRBool kBlock=PR_FALSE; const PRBool kBlock=PR_FALSE;
#else #else
@ -345,6 +346,11 @@ public:
PRInt32 mInsideNoXXXTag; PRInt32 mInsideNoXXXTag;
PRInt32 mInMonolithicContainer; PRInt32 mInMonolithicContainer;
nsCOMPtr<nsITimer> 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 StartLayout();
void ScrollToRef(); void ScrollToRef();
@ -2084,6 +2090,8 @@ HTMLContentSink::HTMLContentSink() {
mInNotification = 0; mInNotification = 0;
mInMonolithicContainer = 0; mInMonolithicContainer = 0;
mInsideNoXXXTag = 0; mInsideNoXXXTag = 0;
mStyleSheetTimerSet = PR_FALSE;
} }
HTMLContentSink::~HTMLContentSink() HTMLContentSink::~HTMLContentSink()
@ -2112,6 +2120,10 @@ HTMLContentSink::~HTMLContentSink()
mNotificationTimer->Cancel(); mNotificationTimer->Cancel();
} }
if (mStyleSheetTimer) {
mStyleSheetTimer->Cancel();
}
PRInt32 numContexts = mContextStack.Count(); PRInt32 numContexts = mContextStack.Count();
if(mCurrentContext==mHeadContext) { if(mCurrentContext==mHeadContext) {
@ -2205,6 +2217,11 @@ HTMLContentSink::Init(nsIDocument* aDoc,
mMaxTextRun = 8192; mMaxTextRun = 8192;
prefs->GetIntPref("content.maxtextrun", &mMaxTextRun); prefs->GetIntPref("content.maxtextrun", &mMaxTextRun);
mStyleSheetTimerSet = PR_FALSE;
mNumStyleSheetsLoading = 0;
mStyleSheetTimerInterval = (5*1000);
prefs->GetIntPref("content.notify.stylesheettimeout", &mStyleSheetTimerInterval);
nsIHTMLContentContainer* htmlContainer = nsnull; nsIHTMLContentContainer* htmlContainer = nsnull;
if (NS_SUCCEEDED(aDoc->QueryInterface(kIHTMLContentContainerIID, (void**)&htmlContainer))) { if (NS_SUCCEEDED(aDoc->QueryInterface(kIHTMLContentContainerIID, (void**)&htmlContainer))) {
htmlContainer->GetCSSLoader(mCSSLoader); htmlContainer->GetCSSLoader(mCSSLoader);
@ -2284,6 +2301,11 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
mNotificationTimer = 0; mNotificationTimer = 0;
} }
if (mStyleSheetTimer) {
mStyleSheetTimer->Cancel();
mStyleSheetTimer = 0;
}
if (nsnull == mTitle) { if (nsnull == mTitle) {
mHTMLDocument->SetTitle(""); mHTMLDocument->SetTitle("");
} }
@ -2320,8 +2342,15 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
HTMLContentSink::Notify(nsITimer *timer) HTMLContentSink::Notify(nsITimer *timer)
{ {
if (timer == mStyleSheetTimer.get()) {
// our first sheet timer has expired: resume the parser now
mStyleSheetTimer = 0;
ResumeParsing();
} else {
MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n")); MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n"));
MOZ_TIMER_START(mWatch); MOZ_TIMER_START(mWatch);
#ifdef MOZ_DEBUG #ifdef MOZ_DEBUG
PRTime now = PR_Now(); PRTime now = PR_Now();
PRInt64 diff, interval; PRInt64 diff, interval;
@ -2338,13 +2367,16 @@ HTMLContentSink::Notify(nsITimer *timer)
SINK_TRACE(SINK_TRACE_REFLOW, SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount)); ("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount));
#endif #endif
if (mCurrentContext) { if (mCurrentContext) {
mCurrentContext->FlushTags(PR_TRUE); mCurrentContext->FlushTags(PR_TRUE);
} }
mNotificationTimer = 0; mNotificationTimer = 0;
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n")); MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n"));
MOZ_TIMER_STOP(mWatch); MOZ_TIMER_STOP(mWatch);
} }
}
NS_IMETHODIMP NS_IMETHODIMP
HTMLContentSink::WillInterrupt() HTMLContentSink::WillInterrupt()
@ -2420,6 +2452,7 @@ HTMLContentSink::WillResume()
{ {
SINK_TRACE(SINK_TRACE_CALLS, SINK_TRACE(SINK_TRACE_CALLS,
("HTMLContentSink::WillResume: this=%p", this)); ("HTMLContentSink::WillResume: this=%p", this));
// Cancel a timer if we had one out there // Cancel a timer if we had one out there
if (mNotificationTimer) { if (mNotificationTimer) {
SINK_TRACE(SINK_TRACE_REFLOW, SINK_TRACE(SINK_TRACE_REFLOW,
@ -2427,7 +2460,6 @@ HTMLContentSink::WillResume()
mNotificationTimer->Cancel(); mNotificationTimer->Cancel();
mNotificationTimer = 0; mNotificationTimer = 0;
} }
return NS_OK; return NS_OK;
} }
@ -3659,6 +3691,14 @@ NS_IMETHODIMP
HTMLContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet, HTMLContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet,
PRBool aDidNotify) 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 // If there was a notification done for this style sheet, we know
// that frames have been created for all content seen so far // that frames have been created for all content seen so far
// (processing of a new style sheet causes recreation of the frame // (processing of a new style sheet causes recreation of the frame
@ -3719,6 +3759,9 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
} }
if (isStyleSheet) { if (isStyleSheet) {
PRBool blockParser = kBlock;
PRBool important = PR_FALSE;
PRBool alternate = PR_FALSE; // alternate (non-preferred) style sheet
nsIURI* url = nsnull; nsIURI* url = nsnull;
{ {
result = NS_NewURI(&url, aHref, mDocumentBaseURL); result = NS_NewURI(&url, aHref, mDocumentBaseURL);
@ -3733,14 +3776,19 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
mPreferredStyle = aTitle; mPreferredStyle = aTitle;
mCSSLoader->SetPreferredSheet(aTitle); mCSSLoader->SetPreferredSheet(aTitle);
mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle); mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle);
} else {
alternate = PR_TRUE;
} }
} }
} }
PRBool blockParser = kBlock;
if (-1 != linkTypes.IndexOf("important")) { if (-1 != linkTypes.IndexOf("important")) {
blockParser = PR_TRUE; blockParser = PR_TRUE;
important = PR_TRUE;
}
if (alternate && !important) {
blockParser = PR_FALSE;
} }
PRBool doneLoading; PRBool doneLoading;
@ -3750,10 +3798,36 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
doneLoading, doneLoading,
this); this);
NS_RELEASE(url); NS_RELEASE(url);
if (NS_SUCCEEDED(result) && blockParser && (! doneLoading)) { 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; result = NS_ERROR_HTMLPARSER_BLOCK;
} }
} }
}// if no stylesheet timer
}// if !important and blockParser
} // if important
} // if succeeded && !doneLoading
}
} }
return result; return result;
} }

Просмотреть файл

@ -102,6 +102,7 @@
#include "nsDOMError.h" #include "nsDOMError.h"
#include "nsIScrollable.h" #include "nsIScrollable.h"
// #define ALLOW_ASYNCH_STYLE_SHEETS
#ifdef ALLOW_ASYNCH_STYLE_SHEETS #ifdef ALLOW_ASYNCH_STYLE_SHEETS
const PRBool kBlock=PR_FALSE; const PRBool kBlock=PR_FALSE;
#else #else
@ -345,6 +346,11 @@ public:
PRInt32 mInsideNoXXXTag; PRInt32 mInsideNoXXXTag;
PRInt32 mInMonolithicContainer; PRInt32 mInMonolithicContainer;
nsCOMPtr<nsITimer> 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 StartLayout();
void ScrollToRef(); void ScrollToRef();
@ -2084,6 +2090,8 @@ HTMLContentSink::HTMLContentSink() {
mInNotification = 0; mInNotification = 0;
mInMonolithicContainer = 0; mInMonolithicContainer = 0;
mInsideNoXXXTag = 0; mInsideNoXXXTag = 0;
mStyleSheetTimerSet = PR_FALSE;
} }
HTMLContentSink::~HTMLContentSink() HTMLContentSink::~HTMLContentSink()
@ -2112,6 +2120,10 @@ HTMLContentSink::~HTMLContentSink()
mNotificationTimer->Cancel(); mNotificationTimer->Cancel();
} }
if (mStyleSheetTimer) {
mStyleSheetTimer->Cancel();
}
PRInt32 numContexts = mContextStack.Count(); PRInt32 numContexts = mContextStack.Count();
if(mCurrentContext==mHeadContext) { if(mCurrentContext==mHeadContext) {
@ -2205,6 +2217,11 @@ HTMLContentSink::Init(nsIDocument* aDoc,
mMaxTextRun = 8192; mMaxTextRun = 8192;
prefs->GetIntPref("content.maxtextrun", &mMaxTextRun); prefs->GetIntPref("content.maxtextrun", &mMaxTextRun);
mStyleSheetTimerSet = PR_FALSE;
mNumStyleSheetsLoading = 0;
mStyleSheetTimerInterval = (5*1000);
prefs->GetIntPref("content.notify.stylesheettimeout", &mStyleSheetTimerInterval);
nsIHTMLContentContainer* htmlContainer = nsnull; nsIHTMLContentContainer* htmlContainer = nsnull;
if (NS_SUCCEEDED(aDoc->QueryInterface(kIHTMLContentContainerIID, (void**)&htmlContainer))) { if (NS_SUCCEEDED(aDoc->QueryInterface(kIHTMLContentContainerIID, (void**)&htmlContainer))) {
htmlContainer->GetCSSLoader(mCSSLoader); htmlContainer->GetCSSLoader(mCSSLoader);
@ -2284,6 +2301,11 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
mNotificationTimer = 0; mNotificationTimer = 0;
} }
if (mStyleSheetTimer) {
mStyleSheetTimer->Cancel();
mStyleSheetTimer = 0;
}
if (nsnull == mTitle) { if (nsnull == mTitle) {
mHTMLDocument->SetTitle(""); mHTMLDocument->SetTitle("");
} }
@ -2320,8 +2342,15 @@ HTMLContentSink::DidBuildModel(PRInt32 aQualityLevel)
NS_IMETHODIMP_(void) NS_IMETHODIMP_(void)
HTMLContentSink::Notify(nsITimer *timer) HTMLContentSink::Notify(nsITimer *timer)
{ {
if (timer == mStyleSheetTimer.get()) {
// our first sheet timer has expired: resume the parser now
mStyleSheetTimer = 0;
ResumeParsing();
} else {
MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n")); MOZ_TIMER_DEBUGLOG(("Start: nsHTMLContentSink::Notify()\n"));
MOZ_TIMER_START(mWatch); MOZ_TIMER_START(mWatch);
#ifdef MOZ_DEBUG #ifdef MOZ_DEBUG
PRTime now = PR_Now(); PRTime now = PR_Now();
PRInt64 diff, interval; PRInt64 diff, interval;
@ -2338,13 +2367,16 @@ HTMLContentSink::Notify(nsITimer *timer)
SINK_TRACE(SINK_TRACE_REFLOW, SINK_TRACE(SINK_TRACE_REFLOW,
("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount)); ("HTMLContentSink::Notify: reflow on a timer: %d milliseconds late, backoff count: %d", delay, mBackoffCount));
#endif #endif
if (mCurrentContext) { if (mCurrentContext) {
mCurrentContext->FlushTags(PR_TRUE); mCurrentContext->FlushTags(PR_TRUE);
} }
mNotificationTimer = 0; mNotificationTimer = 0;
MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n")); MOZ_TIMER_DEBUGLOG(("Stop: nsHTMLContentSink::Notify()\n"));
MOZ_TIMER_STOP(mWatch); MOZ_TIMER_STOP(mWatch);
} }
}
NS_IMETHODIMP NS_IMETHODIMP
HTMLContentSink::WillInterrupt() HTMLContentSink::WillInterrupt()
@ -2420,6 +2452,7 @@ HTMLContentSink::WillResume()
{ {
SINK_TRACE(SINK_TRACE_CALLS, SINK_TRACE(SINK_TRACE_CALLS,
("HTMLContentSink::WillResume: this=%p", this)); ("HTMLContentSink::WillResume: this=%p", this));
// Cancel a timer if we had one out there // Cancel a timer if we had one out there
if (mNotificationTimer) { if (mNotificationTimer) {
SINK_TRACE(SINK_TRACE_REFLOW, SINK_TRACE(SINK_TRACE_REFLOW,
@ -2427,7 +2460,6 @@ HTMLContentSink::WillResume()
mNotificationTimer->Cancel(); mNotificationTimer->Cancel();
mNotificationTimer = 0; mNotificationTimer = 0;
} }
return NS_OK; return NS_OK;
} }
@ -3659,6 +3691,14 @@ NS_IMETHODIMP
HTMLContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet, HTMLContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet,
PRBool aDidNotify) 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 // If there was a notification done for this style sheet, we know
// that frames have been created for all content seen so far // that frames have been created for all content seen so far
// (processing of a new style sheet causes recreation of the frame // (processing of a new style sheet causes recreation of the frame
@ -3719,6 +3759,9 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
} }
if (isStyleSheet) { if (isStyleSheet) {
PRBool blockParser = kBlock;
PRBool important = PR_FALSE;
PRBool alternate = PR_FALSE; // alternate (non-preferred) style sheet
nsIURI* url = nsnull; nsIURI* url = nsnull;
{ {
result = NS_NewURI(&url, aHref, mDocumentBaseURL); result = NS_NewURI(&url, aHref, mDocumentBaseURL);
@ -3733,14 +3776,19 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
mPreferredStyle = aTitle; mPreferredStyle = aTitle;
mCSSLoader->SetPreferredSheet(aTitle); mCSSLoader->SetPreferredSheet(aTitle);
mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle); mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle);
} else {
alternate = PR_TRUE;
} }
} }
} }
PRBool blockParser = kBlock;
if (-1 != linkTypes.IndexOf("important")) { if (-1 != linkTypes.IndexOf("important")) {
blockParser = PR_TRUE; blockParser = PR_TRUE;
important = PR_TRUE;
}
if (alternate && !important) {
blockParser = PR_FALSE;
} }
PRBool doneLoading; PRBool doneLoading;
@ -3750,10 +3798,36 @@ HTMLContentSink::ProcessStyleLink(nsIHTMLContent* aElement,
doneLoading, doneLoading,
this); this);
NS_RELEASE(url); NS_RELEASE(url);
if (NS_SUCCEEDED(result) && blockParser && (! doneLoading)) { 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; result = NS_ERROR_HTMLPARSER_BLOCK;
} }
} }
}// if no stylesheet timer
}// if !important and blockParser
} // if important
} // if succeeded && !doneLoading
}
} }
return result; return result;
} }