Stop blocking the parser on CSS stylesheet loads. We still block scriptexecution on them, however. Bug 84582, r+sr=sicking

This commit is contained in:
bzbarsky@mit.edu 2007-04-20 15:59:18 -07:00
parent 9375a2fa83
commit 75d0ec2b2f
24 changed files with 378 additions and 352 deletions

View File

@ -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

View File

@ -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);

View File

@ -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<nsIDocShell> mDocShell;
nsCOMPtr<nsICSSLoader> mCSSLoader;
nsRefPtr<nsNodeInfoManager> mNodeInfoManager;
nsRefPtr<nsScriptLoader> mScriptLoader;
nsCOMArray<nsIScriptElement> 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)
};

View File

@ -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, &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
@ -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<nsIParser> parser = mParser;
mParser = nsnull;
nsCOMPtr<nsIContent> 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;
}

View File

@ -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<nsIStyleSheet> mStyleSheet;
nsCOMPtr<nsIParser> mParser;
PRPackedBool mDontLoadStyle;
PRPackedBool mUpdatesEnabled;
PRUint32 mLineNumber;

View File

@ -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;

View File

@ -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<nsIDocument> 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;
}

View File

@ -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 <link rel="next" href="url">
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);
}
}
}

View File

@ -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<nsIDocument> 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;

View File

@ -111,7 +111,7 @@ nsXBLContentSink::Init(nsIDocument* aDoc,
}
void
nsXBLContentSink::MaybeStartLayout()
nsXBLContentSink::MaybeStartLayout(PRBool aIgnorePendingSheets)
{
return;
}

View File

@ -112,7 +112,7 @@ public:
protected:
// nsXMLContentSink overrides
void MaybeStartLayout();
virtual void MaybeStartLayout(PRBool aIgnorePendingSheets);
PRBool OnOpenContainer(const PRUnichar **aAtts,
PRUint32 aAttsCount,

View File

@ -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<nsIDocument> 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;
}

View File

@ -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<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);
@ -626,9 +626,12 @@ nsXMLContentSink::CloseElement(nsIContent* aContent)
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();
}
}
}
@ -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<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
@ -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<nsIStyleSheetLinkingElement> 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);
}
}
}

View File

@ -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);

View File

@ -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;
}

View File

@ -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<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();
}
}
}
@ -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<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();
}
}
@ -580,7 +575,7 @@ txMozillaXMLOutput::startElementInternal(nsIAtom* aPrefix,
nsCOMPtr<nsIStyleSheetLinkingElement> 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

View File

@ -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<nsIDocument> mDocument;
nsCOMPtr<nsITransformObserver> mObserver;
nsCOMArray<nsIScriptElement> mScriptElements;
nsCOMArray<nsIStyleSheet> mStylesheets;
PRUint32 mPendingStylesheetCount;
PRPackedBool mInTransform;
};

View File

@ -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)

View File

@ -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<nsICSSLoader> mCSSLoader; // [OWNER]
nsCOMPtr<nsICSSParser> mCSSParser; // [OWNER]
nsCOMPtr<nsIScriptSecurityManager> mSecMan;
};

View File

@ -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, "<html:style> doesn't implement "
"nsIStyleSheetLinkingElement?");
ssle->UpdateStyleSheet(nsnull, nsnull);
PRBool willNotify;
PRBool isAlternate;
ssle->UpdateStyleSheet(nsnull, &willNotify,
&isAlternate);
}
}

View File

@ -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<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.");
@ -1489,16 +1512,6 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus)
}
}
// 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) {
@ -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<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();
@ -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<SheetLoadData> evt =
new SheetLoadData(this, EmptyString(), // title doesn't matter here
aParserToUnblock,
aURI,
aSheet,
nsnull, // owning element doesn't matter here

View File

@ -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<nsIParser> mParserToUnblock;
// URI we're loading. Null for inline sheets
nsCOMPtr<nsIURI> 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<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
@ -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<nsRefPtr<SheetLoadData> > mPostedEvents;
LoadDataArray mPostedEvents;
};
#endif // nsCSSLoader_h__

View File

@ -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;

View File

@ -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);
}
}