diff --git a/chrome/src/nsChromeRegistry.cpp b/chrome/src/nsChromeRegistry.cpp index 693deb57f81..4714ec6fa9e 100644 --- a/chrome/src/nsChromeRegistry.cpp +++ b/chrome/src/nsChromeRegistry.cpp @@ -1057,7 +1057,7 @@ nsChromeRegistry::LoadStyleSheetWithURL(nsIURI* aURL, nsICSSStyleSheet** aSheet) nsCOMPtr cssLoader = do_GetService(kCSSLoaderCID); if (!cssLoader) return NS_ERROR_FAILURE; - return cssLoader->LoadAgentSheet(aURL, aSheet); + return cssLoader->LoadSheetSync(aURL, aSheet); } NS_IMETHODIMP diff --git a/content/base/src/nsContentSink.cpp b/content/base/src/nsContentSink.cpp index 3d0c62d1982..d1b75592363 100644 --- a/content/base/src/nsContentSink.cpp +++ b/content/base/src/nsContentSink.cpp @@ -191,8 +191,9 @@ nsContentSink::Init(nsIDocument* aDoc, } NS_IMETHODIMP -nsContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet, - PRBool aDidNotify) +nsContentSink::StyleSheetLoaded(nsICSSStyleSheet* aSheet, + PRBool aWasAlternate, + nsresult aStatus) { return NS_OK; } @@ -646,42 +647,15 @@ nsContentSink::ProcessStyleLink(nsIContent* aElement, return NS_OK; } - if (!aAlternate) { - // possibly preferred sheet - - if (!aTitle.IsEmpty()) { - nsAutoString preferredStyle; - mDocument->GetHeaderData(nsHTMLAtoms::headerDefaultStyle, - preferredStyle); - if (preferredStyle.IsEmpty()) { - mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle); - } - } - } - - PRBool blockParser = kBlockByDefault; - if (aAlternate) { - blockParser = PR_FALSE; - } - - // NOTE: no longer honoring the important keyword to indicate - // blocking as it is proprietary and unnecessary since all - // non-alternate will block the parser now -mja -#if 0 - if (linkTypes.IndexOf("important") != -1) { - blockParser = PR_TRUE; - } -#endif - - PRBool doneLoading; nsIParser* parser = nsnull; - if (blockParser) { + if (kBlockByDefault) { parser = mParser; } - rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, - parser, doneLoading, this); - - if (NS_SUCCEEDED(rv) && blockParser && !doneLoading) { + + PRBool isAlternate; + rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, aAlternate, + parser, this, &isAlternate); + if (NS_SUCCEEDED(rv) && parser && !isAlternate) { rv = NS_ERROR_HTMLPARSER_BLOCK; } diff --git a/content/base/src/nsContentSink.h b/content/base/src/nsContentSink.h index d4b5fb4bf0c..81e2d8668a9 100644 --- a/content/base/src/nsContentSink.h +++ b/content/base/src/nsContentSink.h @@ -68,7 +68,8 @@ class nsContentSink : public nsICSSLoaderObserver, NS_DECL_NSISCRIPTLOADEROBSERVER // nsICSSLoaderObserver - NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify); + NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aWasAlternate, + nsresult aStatus); protected: nsContentSink(); diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index b95fb2cf18b..6c1a373eded 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1985,7 +1985,7 @@ nsDocument::EnsureCatalogStyleSheet(const char *aStyleSheetURI) NS_NewURI(getter_AddRefs(uri), aStyleSheetURI); if (uri) { nsCOMPtr sheet; - cssLoader->LoadAgentSheet(uri, getter_AddRefs(sheet)); + cssLoader->LoadSheetSync(uri, getter_AddRefs(sheet)); if (sheet) { BeginUpdate(UPDATE_STYLE); AddCatalogStyleSheet(sheet); diff --git a/content/base/src/nsStyleLinkElement.cpp b/content/base/src/nsStyleLinkElement.cpp index 79895734271..4d0f52b38f6 100644 --- a/content/base/src/nsStyleLinkElement.cpp +++ b/content/base/src/nsStyleLinkElement.cpp @@ -261,26 +261,8 @@ nsStyleLinkElement::UpdateStyleSheet(nsIDocument *aOldDocument, return NS_OK; } - PRBool blockParser = kBlockByDefault; - if (isAlternate) { - blockParser = PR_FALSE; - } - - /* NOTE: no longer honoring the important keyword to indicate blocking - as it is proprietary and unnecessary since all non-alternate - will block the parser now -mja - if (-1 != linkTypes.IndexOf("important")) { - blockParser = PR_TRUE; - } - */ - - if (!isAlternate && !title.IsEmpty()) { // possibly preferred sheet - nsAutoString prefStyle; - doc->GetHeaderData(nsHTMLAtoms::headerDefaultStyle, prefStyle); - - if (prefStyle.IsEmpty()) { - doc->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, title); - } + if (!kBlockByDefault) { + parser = nsnull; } PRBool doneLoading; @@ -321,17 +303,17 @@ nsStyleLinkElement::UpdateStyleSheet(nsIDocument *aOldDocument, // style sheet. rv = doc->CSSLoader()-> LoadInlineStyle(thisContent, uin, mLineNumber, title, media, - ((blockParser) ? parser.get() : nsnull), - doneLoading, aObserver); + parser, 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, - ((blockParser) ? parser.get() : nsnull), - doneLoading, aObserver); + LoadStyleLink(thisContent, uri, title, media, isAlternate, + parser, aObserver, &isAlternate); } - if (NS_SUCCEEDED(rv) && blockParser && !doneLoading) { + if (NS_SUCCEEDED(rv) && parser && !doneLoading && !isAlternate) { rv = NS_ERROR_HTMLPARSER_BLOCK; } diff --git a/content/xbl/src/nsXBLPrototypeResources.cpp b/content/xbl/src/nsXBLPrototypeResources.cpp index 4e5087368e8..2cdfe012686 100644 --- a/content/xbl/src/nsXBLPrototypeResources.cpp +++ b/content/xbl/src/nsXBLPrototypeResources.cpp @@ -132,7 +132,7 @@ nsXBLPrototypeResources::FlushSkinSheets() nsCOMPtr newSheet; if (IsChromeURI(uri)) { - if (NS_FAILED(loader->LoadAgentSheet(uri, getter_AddRefs(newSheet)))) + if (NS_FAILED(loader->LoadSheetSync(uri, getter_AddRefs(newSheet)))) continue; } else { diff --git a/content/xbl/src/nsXBLResourceLoader.cpp b/content/xbl/src/nsXBLResourceLoader.cpp index 17858b54b1d..fccb4d842c6 100644 --- a/content/xbl/src/nsXBLResourceLoader.cpp +++ b/content/xbl/src/nsXBLResourceLoader.cpp @@ -132,24 +132,19 @@ nsXBLResourceLoader::LoadResources(PRBool* aResult) if (NS_SUCCEEDED(url->SchemeIs("chrome", &chrome)) && chrome) { nsCOMPtr sheet; - rv = cssLoader->LoadAgentSheet(url, getter_AddRefs(sheet)); + rv = cssLoader->LoadSheetSync(url, getter_AddRefs(sheet)); NS_ASSERTION(NS_SUCCEEDED(rv), "Load failed!!!"); if (NS_SUCCEEDED(rv)) { - rv = StyleSheetLoaded(sheet, PR_TRUE); + rv = StyleSheetLoaded(sheet, PR_FALSE, NS_OK); NS_ASSERTION(NS_SUCCEEDED(rv), "Processing the style sheet failed!!!"); } } else { - PRBool doneLoading; - NS_NAMED_LITERAL_STRING(empty, ""); - rv = cssLoader->LoadStyleLink(nsnull, url, empty, empty, - nsnull, doneLoading, this); - NS_ASSERTION(NS_SUCCEEDED(rv), "Load failed!!!"); - - if (!doneLoading) - mPendingSheets++; + rv = cssLoader->LoadSheet(url, this); + if (NS_SUCCEEDED(rv)) + ++mPendingSheets; } } } @@ -164,7 +159,9 @@ nsXBLResourceLoader::LoadResources(PRBool* aResult) // nsICSSLoaderObserver NS_IMETHODIMP -nsXBLResourceLoader::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify) +nsXBLResourceLoader::StyleSheetLoaded(nsICSSStyleSheet* aSheet, + PRBool aWasAlternate, + nsresult aStatus) { if (!mResources) { // Our resources got destroyed -- just bail out diff --git a/content/xbl/src/nsXBLResourceLoader.h b/content/xbl/src/nsXBLResourceLoader.h index f6566cfcdce..dea8fc1804d 100644 --- a/content/xbl/src/nsXBLResourceLoader.h +++ b/content/xbl/src/nsXBLResourceLoader.h @@ -77,7 +77,8 @@ public: NS_DECL_ISUPPORTS // nsICSSLoaderObserver - NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify); + NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aWasAlternate, + nsresult aStatus); void LoadResources(PRBool* aResult); void AddResource(nsIAtom* aResourceType, const nsAString& aSrc); @@ -100,6 +101,8 @@ public: nsXBLResource* mLastResource; PRPackedBool mLoadingResources; + // We need mInLoadResourcesFunc because we do a mixture of sync and + // async loads. PRPackedBool mInLoadResourcesFunc; PRInt16 mPendingSheets; // The number of stylesheets that have yet to load. diff --git a/content/xml/document/src/nsXMLContentSink.cpp b/content/xml/document/src/nsXMLContentSink.cpp index 92d3484a20a..48375d10b15 100644 --- a/content/xml/document/src/nsXMLContentSink.cpp +++ b/content/xml/document/src/nsXMLContentSink.cpp @@ -1105,7 +1105,7 @@ nsXMLContentSink::HandleDoctypeDecl(const nsAString & aSubset, nsCOMPtr uri(do_QueryInterface(aCatalogData)); if (uri) { nsCOMPtr sheet; - mCSSLoader->LoadAgentSheet(uri, getter_AddRefs(sheet)); + mCSSLoader->LoadSheetSync(uri, getter_AddRefs(sheet)); #ifdef NS_DEBUG nsCAutoString uriStr; diff --git a/content/xul/document/src/nsXULContentSink.cpp b/content/xul/document/src/nsXULContentSink.cpp index 48492718efd..64e76194490 100644 --- a/content/xul/document/src/nsXULContentSink.cpp +++ b/content/xul/document/src/nsXULContentSink.cpp @@ -232,7 +232,6 @@ protected: nsCOMPtr mPrototype; // [OWNER] nsIParser* mParser; // [OWNER] We use regular pointer b/c of funky exports on nsIParser - nsString mPreferredStyle; nsCOMPtr mCSSLoader; // [OWNER] nsCOMPtr mCSSParser; // [OWNER] nsCOMPtr mSecMan; @@ -469,33 +468,15 @@ XULContentSinkImpl::ProcessStyleLink(nsIContent* aElement, // Add the style sheet reference to the prototype mPrototype->AddStyleSheetReference(url); - // Nope, we need to load it asynchronously - PRBool blockParser = PR_FALSE; - if (! aAlternate) { - if (!aTitle.IsEmpty()) { // possibly preferred sheet - if (mPreferredStyle.IsEmpty()) { - mPreferredStyle = aTitle; - mCSSLoader->SetPreferredSheet(aTitle); - nsCOMPtr defaultStyle = do_GetAtom("default-style"); - if (defaultStyle) { - mPrototype->SetHeaderData(defaultStyle, aTitle); - } - } - } - else { // persistent sheet, block - blockParser = PR_TRUE; - } - } - nsCOMPtr doc = do_QueryReferent(mDocument); if (! doc) return NS_ERROR_FAILURE; // doc went away! - PRBool doneLoading; + PRBool isAlternate; rv = mCSSLoader->LoadStyleLink(aElement, url, aTitle, aMedia, - ((blockParser) ? mParser : nsnull), - doneLoading, nsnull); - if (NS_SUCCEEDED(rv) && blockParser && (! doneLoading)) { + aAlternate, mParser, nsnull, + &isAlternate); + if (NS_SUCCEEDED(rv) && !isAlternate) { rv = NS_ERROR_HTMLPARSER_BLOCK; } } @@ -543,16 +524,21 @@ XULContentSinkImpl::Init(nsIDocument* aDocument, nsIXULPrototypeDocument* aProto // XXX this presumes HTTP header info is already set in document // XXX if it isn't we need to set it here... - nsCOMPtr defaultStyle = do_GetAtom("default-style"); - if (! defaultStyle) - return NS_ERROR_OUT_OF_MEMORY; - - rv = mPrototype->GetHeaderData(defaultStyle, mPreferredStyle); + // XXXbz not like GetHeaderData on the proto doc _does_ anything.... + nsAutoString preferredStyle; + rv = mPrototype->GetHeaderData(nsHTMLAtoms::headerDefaultStyle, + preferredStyle); if (NS_FAILED(rv)) return rv; + if (!preferredStyle.IsEmpty()) { + aDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, + preferredStyle); + } + // Get the CSS loader from the document so we can load // stylesheets mCSSLoader = aDocument->CSSLoader(); + mCSSLoader->SetPreferredSheet(preferredStyle); mNodeInfoManager = aPrototype->GetNodeInfoManager(); if (! mNodeInfoManager) diff --git a/content/xul/document/src/nsXULDocument.cpp b/content/xul/document/src/nsXULDocument.cpp index 77bae7e8db9..8ed652aed70 100644 --- a/content/xul/document/src/nsXULDocument.cpp +++ b/content/xul/document/src/nsXULDocument.cpp @@ -717,7 +717,7 @@ nsXULDocument::EndLoad() mCurrentPrototype->AddStyleSheetReference(sheetURI); } - cssLoader->LoadAgentSheet(sheetURI, getter_AddRefs(sheet)); + cssLoader->LoadSheetSync(sheetURI, getter_AddRefs(sheet)); if (!sheet) { NS_WARNING("Couldn't load chrome style overlay."); continue; @@ -3786,10 +3786,10 @@ nsXULDocument::AddPrototypeSheets() // only system that partially invalidates the XUL cache). // - dwh //XXXbz we hit this code from fastload all the time. Bug 183505. - rv = CSSLoader()->LoadAgentSheet(uri, getter_AddRefs(sheet)); + rv = CSSLoader()->LoadSheetSync(uri, getter_AddRefs(sheet)); // XXXldb We need to prevent bogus sheets from being held in the // prototype's list, but until then, don't propagate the failure - // from LoadAgentSheet (and thus exit the loop). + // from LoadSheetSync (and thus exit the loop). if (NS_SUCCEEDED(rv)) { AddStyleSheet(sheet); } diff --git a/editor/libeditor/html/nsHTMLEditor.cpp b/editor/libeditor/html/nsHTMLEditor.cpp index 561a36f65b0..2ebf3cfb740 100644 --- a/editor/libeditor/html/nsHTMLEditor.cpp +++ b/editor/libeditor/html/nsHTMLEditor.cpp @@ -3534,8 +3534,7 @@ nsHTMLEditor::ReplaceStyleSheet(const nsAString& aURL) rv = NS_NewURI(getter_AddRefs(uaURI), aURL); NS_ENSURE_SUCCESS(rv, rv); - nsCOMPtr sheet; - rv = cssLoader->LoadAgentSheet(uaURI, this); + rv = cssLoader->LoadSheet(uaURI, this); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; @@ -3585,8 +3584,10 @@ nsHTMLEditor::AddOverrideStyleSheet(const nsAString& aURL) NS_ENSURE_SUCCESS(rv, rv); // We MUST ONLY load synchronous local files (no @import) + // XXXbz Except this will actually try to load remote files + // synchronously, of course.. nsCOMPtr sheet; - rv = cssLoader->LoadAgentSheet(uaURI, getter_AddRefs(sheet)); + rv = cssLoader->LoadSheetSync(uaURI, getter_AddRefs(sheet)); // Synchronous loads should ALWAYS return completed if (!sheet) @@ -4179,7 +4180,8 @@ nsHTMLEditor::GetReconversionString(nsReconversionEventReply* aReply) NS_IMETHODIMP -nsHTMLEditor::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify) +nsHTMLEditor::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aWasAlternate, + nsresult aStatus) { nsresult rv = NS_OK; nsAutoEditBatch batchIt(this); diff --git a/editor/libeditor/html/nsHTMLEditor.h b/editor/libeditor/html/nsHTMLEditor.h index ada3efcf2ef..6a512ee37de 100644 --- a/editor/libeditor/html/nsHTMLEditor.h +++ b/editor/libeditor/html/nsHTMLEditor.h @@ -371,7 +371,8 @@ public: PRUint32 aLength); /* ------------ nsICSSLoaderObserver -------------- */ - NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aNotify); + NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet*aSheet, PRBool aWasAlternate, + nsresult aStatus); /* ------------ Utility Routines, not part of public API -------------- */ NS_IMETHOD TypedText(const nsAString& aString, PRInt32 aAction); diff --git a/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp b/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp index f858b490b04..732e0817ff3 100644 --- a/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp +++ b/extensions/transformiix/source/xslt/txMozillaXMLOutput.cpp @@ -869,7 +869,9 @@ txTransformNotifier::ScriptEvaluated(nsresult aResult, } NS_IMETHODIMP -txTransformNotifier::StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify) +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 diff --git a/extensions/transformiix/source/xslt/txMozillaXMLOutput.h b/extensions/transformiix/source/xslt/txMozillaXMLOutput.h index 74e50c55630..e69de29bb2d 100644 --- a/extensions/transformiix/source/xslt/txMozillaXMLOutput.h +++ b/extensions/transformiix/source/xslt/txMozillaXMLOutput.h @@ -1,152 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/* ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is TransforMiiX XSLT processor code. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 2001 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Peter Van der Beken - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef TRANSFRMX_MOZILLA_XML_OUTPUT_H -#define TRANSFRMX_MOZILLA_XML_OUTPUT_H - -#include "txXMLEventHandler.h" -#include "nsAutoPtr.h" -#include "nsIScriptLoaderObserver.h" -#include "txOutputFormat.h" -#include "nsCOMArray.h" -#include "nsICSSLoaderObserver.h" -#include "txStack.h" - -class nsIContent; -class nsIDOMDocument; -class nsIAtom; -class nsIDOMDocumentFragment; -class nsIDOMElement; -class nsIStyleSheet; -class nsIDOMNode; -class nsITransformObserver; - -class txTransformNotifier : public nsIScriptLoaderObserver, - public nsICSSLoaderObserver -{ -public: - txTransformNotifier(); - virtual ~txTransformNotifier(); - - NS_DECL_ISUPPORTS - NS_DECL_NSISCRIPTLOADEROBSERVER - - // nsICSSLoaderObserver - NS_IMETHOD StyleSheetLoaded(nsICSSStyleSheet* aSheet, PRBool aNotify); - - void Init(nsITransformObserver* aObserver); - void AddScriptElement(nsIScriptElement* aElement); - void AddStyleSheet(nsIStyleSheet* aStyleSheet); - void OnTransformEnd(nsresult aResult = NS_OK); - void OnTransformStart(); - void SetOutputDocument(nsIDOMDocument* aDocument); - -private: - void SignalTransformEnd(nsresult aResult = NS_OK); - - nsCOMPtr mDocument; - nsCOMPtr mObserver; - nsCOMArray mScriptElements; - nsCOMArray mStylesheets; - PRPackedBool mInTransform; -}; - -class txMozillaXMLOutput : public txAOutputXMLEventHandler -{ -public: - txMozillaXMLOutput(const nsAString& aRootName, - PRInt32 aRootNsID, - txOutputFormat* aFormat, - nsIDOMDocument* aSourceDocument, - nsIDOMDocument* aResultDocument, - nsITransformObserver* aObserver); - txMozillaXMLOutput(txOutputFormat* aFormat, - nsIDOMDocumentFragment* aFragment); - virtual ~txMozillaXMLOutput(); - - TX_DECL_TXAXMLEVENTHANDLER - TX_DECL_TXAOUTPUTXMLEVENTHANDLER - -private: - void closePrevious(PRInt8 aAction); - void startHTMLElement(nsIDOMElement* aElement, PRBool aXHTML); - void endHTMLElement(nsIDOMElement* aElement); - void processHTTPEquiv(nsIAtom* aHeader, const nsAString& aValue); - nsresult createResultDocument(const nsAString& aName, PRInt32 aNsID, - nsIDOMDocument* aSourceDocument, - nsIDOMDocument* aResultDocument); - nsresult createHTMLElement(const nsAString& aName, - nsIDOMElement** aResult); - - nsCOMPtr mDocument; - nsCOMPtr mCurrentNode; - nsCOMPtr mParentNode; - nsCOMPtr mRootContent; - - nsCOMPtr mNonAddedParent; - nsCOMPtr mNonAddedNode; - - nsRefPtr mNotifier; - - PRUint32 mTreeDepth, mBadChildLevel; - nsCString mRefreshString; - - txStack mTableStateStack; - enum TableState { - NORMAL, // An element needing no special treatment - TABLE, // A HTML table element - ADDED_TBODY // An inserted tbody not coming from the stylesheet - }; - TableState mTableState; - - nsAutoString mText; - - txOutputFormat mOutputFormat; - - PRPackedBool mDontAddCurrent; - - PRPackedBool mHaveTitleElement; - PRPackedBool mHaveBaseElement; - - PRPackedBool mDocumentIsHTML; - PRPackedBool mCreatingNewDocument; - - enum txAction { eCloseElement = 1, eFlushText = 2 }; -}; - -#endif diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp index df9796d1872..9285fca5bae 100644 --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -2042,7 +2042,7 @@ DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument, baseURI); if (!uri) continue; - cssLoader->LoadAgentSheet(uri, getter_AddRefs(csssheet)); + cssLoader->LoadSheetSync(uri, getter_AddRefs(csssheet)); if (!sheet) continue; styleSet->PrependStyleSheet(nsStyleSet::eAgentSheet, csssheet); diff --git a/layout/base/nsStyleSheetService.cpp b/layout/base/nsStyleSheetService.cpp index 257d2481e57..36a7126c141 100644 --- a/layout/base/nsStyleSheetService.cpp +++ b/layout/base/nsStyleSheetService.cpp @@ -145,7 +145,7 @@ nsStyleSheetService::LoadAndRegisterSheet(nsIURI *aSheetURI, nsCOMPtr loader = do_CreateInstance(kCSSLoaderCID); nsCOMPtr sheet; - nsresult rv = loader->LoadAgentSheet(aSheetURI, getter_AddRefs(sheet)); + nsresult rv = loader->LoadSheetSync(aSheetURI, getter_AddRefs(sheet)); NS_ENSURE_SUCCESS(rv, rv); mSheets[aSheetType].AppendObject(sheet); diff --git a/layout/build/nsContentDLF.cpp b/layout/build/nsContentDLF.cpp index 81c3d1683fb..8674512a61a 100644 --- a/layout/build/nsContentDLF.cpp +++ b/layout/build/nsContentDLF.cpp @@ -642,7 +642,7 @@ nsContentDLF::EnsureUAStyleSheet() NS_NewCSSLoader(getter_AddRefs(cssLoader)); if (!cssLoader) return NS_ERROR_OUT_OF_MEMORY; - rv = cssLoader->LoadAgentSheet(uri, &gUAStyleSheet); + rv = cssLoader->LoadSheetSync(uri, &gUAStyleSheet); #ifdef DEBUG if (NS_FAILED(rv)) printf("*** open of %s failed: error=%x\n", UA_CSS_URL, rv); diff --git a/layout/html/tests/ParseCSS.cpp b/layout/html/tests/ParseCSS.cpp index adef9611b2c..f363ab7248f 100644 --- a/layout/html/tests/ParseCSS.cpp +++ b/layout/html/tests/ParseCSS.cpp @@ -76,7 +76,7 @@ ParseCSSFile(nsIURI *aSheetURI) { nsCOMPtr loader(do_CreateInstance(kCSSLoaderCID)); nsCOMPtr sheet; - loader->LoadAgentSheet(aSheetURI, getter_AddRefs(sheet)); + loader->LoadSheetSync(aSheetURI, getter_AddRefs(sheet)); NS_ASSERTION(sheet, "sheet load failed"); /* This can happen if the file can't be found (e.g. you * ask for a relative path and xpcom/io rejects it) diff --git a/layout/style/nsCSSLoader.cpp b/layout/style/nsCSSLoader.cpp index f3afbb69dda..7d9e6a640b9 100644 --- a/layout/style/nsCSSLoader.cpp +++ b/layout/style/nsCSSLoader.cpp @@ -55,7 +55,6 @@ #include "nsUnicharUtils.h" #include "nsHashtable.h" #include "nsIURI.h" -#include "nsIURL.h" #include "nsIParser.h" #include "nsIServiceManager.h" #include "nsNetUtil.h" @@ -76,6 +75,10 @@ #include "nsICSSLoader.h" #include "nsICSSParser.h" #include "nsICSSImportRule.h" +#include "plevent.h" +#include "nsIEventQueue.h" +#include "nsIEventQueueService.h" +#include "nsHTMLAtoms.h" #ifdef MOZ_XUL #include "nsIXULPrototypeCache.h" @@ -143,6 +146,7 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, nsIURI* aURI, nsICSSStyleSheet* aSheet, nsIStyleSheetLinkingElement* aOwningElement, + PRBool aIsAlternate, nsICSSLoaderObserver* aObserver) : mLoader(aLoader), mTitle(aTitle), @@ -154,9 +158,11 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, mParentData(nsnull), mPendingChildren(0), mSyncLoad(PR_FALSE), - mIsAgent(PR_FALSE), + mIsNonDocumentSheet(PR_FALSE), mIsLoading(PR_FALSE), mIsCancelled(PR_FALSE), + mMustNotify(PR_FALSE), + mWasAlternate(aIsAlternate), mOwningElement(aOwningElement), mObserver(aObserver) { @@ -179,9 +185,11 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, mParentData(aParentData), mPendingChildren(0), mSyncLoad(PR_FALSE), - mIsAgent(PR_FALSE), + mIsNonDocumentSheet(PR_FALSE), mIsLoading(PR_FALSE), mIsCancelled(PR_FALSE), + mMustNotify(PR_FALSE), + mWasAlternate(PR_FALSE), mOwningElement(nsnull), mObserver(aObserver) { @@ -191,7 +199,7 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, if (mParentData) { NS_ADDREF(mParentData); mSyncLoad = mParentData->mSyncLoad; - mIsAgent = mParentData->mIsAgent; + mIsNonDocumentSheet = mParentData->mIsNonDocumentSheet; ++(mParentData->mPendingChildren); } } @@ -210,9 +218,11 @@ SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader, mParentData(nsnull), mPendingChildren(0), mSyncLoad(aSyncLoad), - mIsAgent(PR_TRUE), + mIsNonDocumentSheet(PR_TRUE), mIsLoading(PR_FALSE), mIsCancelled(PR_FALSE), + mMustNotify(PR_FALSE), + mWasAlternate(PR_FALSE), mOwningElement(nsnull), mObserver(aObserver) { @@ -249,6 +259,9 @@ CSSLoaderImpl::~CSSLoaderImpl(void) "How did we get destroyed when there are loading data?"); NS_ASSERTION((!mPendingDatas.IsInitialized()) || mPendingDatas.Count() == 0, "How did we get destroyed when there are pending data?"); + // Note: no real need to revoke our stylesheet loaded events -- they + // hold strong references to us, so if we're going away that means + // they're all done. } NS_IMPL_ISUPPORTS1(CSSLoaderImpl, nsICSSLoader) @@ -312,7 +325,9 @@ StartNonAlternates(nsIURI *aKey, SheetLoadData* &aData, void* aClosure) NS_PRECONDITION(aClosure, "Must have a loader"); CSSLoaderImpl* loader = NS_STATIC_CAST(CSSLoaderImpl*, aClosure); - if (loader->IsAlternate(aData->mTitle)) { + // Note that we don't want to affect what the selected style set is, + // so use PR_TRUE for aHasAlternateRel. + if (loader->IsAlternate(aData->mTitle, PR_TRUE)) { return PL_DHASH_NEXT; } @@ -704,10 +719,10 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader, return NS_OK; } - if (!mLoader->mDocument && !mIsAgent) { + if (!mLoader->mDocument && !mIsNonDocumentSheet) { // Sorry, we don't care about this load anymore - LOG_WARN((" No document and not agent sheet; dropping load")); - mLoader->SheetComplete(this, PR_FALSE); + LOG_WARN((" No document and not non-document sheet; dropping load")); + mLoader->SheetComplete(this, NS_BINDING_ABORTED); return NS_OK; } @@ -742,7 +757,7 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader, result = httpChannel->GetRequestSucceeded(&requestSucceeded); if (NS_SUCCEEDED(result) && !requestSucceeded) { LOG((" Load returned an error page")); - mLoader->SheetComplete(this, PR_FALSE); + mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE); return NS_OK; } } @@ -789,13 +804,18 @@ SheetLoadData::OnStreamComplete(nsIUnicharStreamLoader* aLoader, } } - if (NS_FAILED(aStatus) || !aDataStream) { - LOG_WARN((" Load failed: status %u, data stream %p", - aStatus, aDataStream)); - mLoader->SheetComplete(this, PR_FALSE); + if (NS_FAILED(aStatus)) { + LOG_WARN((" Load failed: status 0x%x", aStatus)); + mLoader->SheetComplete(this, aStatus); return NS_OK; } + if (!aDataStream) { + LOG_WARN((" No data stream; bailing")); + mLoader->SheetComplete(this, NS_ERROR_NOT_AVAILABLE); + return NS_OK; + } + if (channelURI) { // Enough to set the URI on mSheet, since any sibling datas we have share // the same mInner as mSheet and will thus get the same URI. @@ -817,12 +837,29 @@ static PRBool IsChromeURI(nsIURI* aURI) #endif PRBool -CSSLoaderImpl::IsAlternate(const nsAString& aTitle) +CSSLoaderImpl::IsAlternate(const nsAString& aTitle, PRBool aHasAlternateRel) { - if (!aTitle.IsEmpty()) { - return PRBool(! aTitle.Equals(mPreferredSheet, nsCaseInsensitiveStringComparator())); + // A sheet is alternate if it has a nonempty title that doesn't match the + // currently selected style set. But if there _is_ no currently selected + // style set, the sheet wasn't marked as an alternate explicitly, and aTitle + // is nonempty, we should select the style set corresponding to aTitle, since + // that's a preferred sheet. + if (aTitle.IsEmpty()) { + return PR_FALSE; } - return PR_FALSE; + + if (!aHasAlternateRel && mDocument && mPreferredSheet.IsEmpty()) { + // There's no preferred set yet, and we now have a sheet with a title. + // Make that be the preferred set. + // XXXbz maybe this should be checking IsVoid(), actually, since the + // preferred set can be explicitly set to the empty string. Look into + // this. + mDocument->SetHeaderData(nsHTMLAtoms::headerDefaultStyle, aTitle); + // We're definitely not an alternate + return PR_FALSE; + } + + return !aTitle.Equals(mPreferredSheet, nsCaseInsensitiveStringComparator()); } /** @@ -987,13 +1024,16 @@ CSSLoaderImpl::CreateSheet(nsIURI* aURI, /** * PrepareSheet() handles setting the media and title on the sheet, as - * well as setting the enabled state based on the title + * well as setting the enabled state based on the title and whether + * the sheet had "alternate" in its rel. */ nsresult CSSLoaderImpl::PrepareSheet(nsICSSStyleSheet* aSheet, const nsSubstring& aTitle, const nsSubstring& aMediaString, - nsMediaList* aMediaList) + nsMediaList* aMediaList, + PRBool aHasAlternateRel, + PRBool *aIsAlternate) { NS_PRECONDITION(aSheet, "Must have a sheet!"); @@ -1020,7 +1060,11 @@ CSSLoaderImpl::PrepareSheet(nsICSSStyleSheet* aSheet, NS_ENSURE_SUCCESS(rv, rv); aSheet->SetTitle(aTitle); - aSheet->SetEnabled(! IsAlternate(aTitle)); + PRBool alternate = IsAlternate(aTitle, aHasAlternateRel); + aSheet->SetEnabled(! alternate); + if (aIsAlternate) { + *aIsAlternate = alternate; + } return NS_OK; } @@ -1177,15 +1221,16 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) nsresult rv = NS_OK; - if (!mDocument && !aLoadData->mIsAgent) { + if (!mDocument && !aLoadData->mIsNonDocumentSheet) { // No point starting the load; just release all the data and such. - LOG_WARN((" No document and not agent sheet; pre-dropping load")); - SheetComplete(aLoadData, PR_FALSE); - return NS_OK; + LOG_WARN((" No document and not non-document sheet; pre-dropping load")); + SheetComplete(aLoadData, NS_BINDING_ABORTED); + return NS_BINDING_ABORTED; } if (aLoadData->mSyncLoad) { LOG((" Synchronous load")); + NS_ASSERTION(!aLoadData->mObserver, "Observer for a sync load?"); NS_ASSERTION(aSheetState == eSheetNeedsParser, "Sync loads can't reuse existing async loads"); @@ -1194,7 +1239,7 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) rv = NS_OpenURI(getter_AddRefs(stream), aLoadData->mURI); if (NS_FAILED(rv)) { LOG_ERROR((" Failed to open URI synchronously")); - SheetComplete(aLoadData, PR_FALSE); + SheetComplete(aLoadData, rv); return rv; } @@ -1203,7 +1248,7 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) if (NS_FAILED(rv)) { LOG_ERROR((" Failed to create converter stream")); - SheetComplete(aLoadData, PR_FALSE); + SheetComplete(aLoadData, rv); return rv; } @@ -1219,7 +1264,7 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) if (NS_FAILED(rv)) { LOG_ERROR((" Failed to initialize converter stream")); - SheetComplete(aLoadData, PR_FALSE); + SheetComplete(aLoadData, rv); return rv; } @@ -1247,7 +1292,7 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) data = data->mNext; } data->mNext = aLoadData; // transfer ownership - if (aSheetState == eSheetPending && !IsAlternate(aLoadData->mTitle)) { + if (aSheetState == eSheetPending && !aLoadData->mWasAlternate) { // Kick the load off; someone cares about it right away #ifdef DEBUG @@ -1260,7 +1305,7 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) mPendingDatas.Remove(aLoadData->mURI); LOG((" Forcing load of pending data")); - LoadSheet(existingData, eSheetNeedsParser); + return LoadSheet(existingData, eSheetNeedsParser); } // All done here; once the load completes we'll be marked complete // automatically @@ -1289,7 +1334,7 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) if (NS_FAILED(rv)) { LOG_ERROR((" Failed to create channel")); - SheetComplete(aLoadData, PR_FALSE); + SheetComplete(aLoadData, rv); return rv; } @@ -1321,11 +1366,18 @@ CSSLoaderImpl::LoadSheet(SheetLoadData* aLoadData, StyleSheetState aSheetState) if (NS_FAILED(rv)) { LOG_ERROR((" Failed to create stream loader")); - SheetComplete(aLoadData, PR_FALSE); + SheetComplete(aLoadData, rv); return rv; } - mLoadingDatas.Put(aLoadData->mURI, aLoadData); + if (!mLoadingDatas.Put(aLoadData->mURI, aLoadData)) { + LOG_ERROR((" Failed to put data in loading table")); + aLoadData->mIsCancelled = PR_TRUE; + channel->Cancel(NS_ERROR_OUT_OF_MEMORY); + SheetComplete(aLoadData, NS_ERROR_OUT_OF_MEMORY); + return NS_ERROR_OUT_OF_MEMORY; + } + aLoadData->mIsLoading = PR_TRUE; return NS_OK; @@ -1353,7 +1405,7 @@ CSSLoaderImpl::ParseSheet(nsIUnicharInputStream* aStream, nsresult rv = GetParserFor(aLoadData->mSheet, getter_AddRefs(parser)); if (NS_FAILED(rv)) { LOG_ERROR((" Failed to get CSS parser")); - SheetComplete(aLoadData, PR_FALSE); + SheetComplete(aLoadData, rv); return rv; } @@ -1376,13 +1428,7 @@ CSSLoaderImpl::ParseSheet(nsIUnicharInputStream* aStream, if (aLoadData->mPendingChildren == 0) { LOG((" No pending kids from parse")); aCompleted = PR_TRUE; - if (!aLoadData->mURI) { - // inline sheet and we're all done with no kids, so we will not - // be blocking the parser - LOG((" Inline sheet with no pending kids; nulling out parser")); - aLoadData->mParserToUnblock = nsnull; - } - SheetComplete(aLoadData, PR_TRUE); + SheetComplete(aLoadData, NS_OK); } // Otherwise, the children are holding strong refs to the data and // will call SheetComplete() on it when they complete. @@ -1394,19 +1440,19 @@ CSSLoaderImpl::ParseSheet(nsIUnicharInputStream* aStream, * SheetComplete is the do-it-all cleanup function. It removes the * load data from the "loading" hashtable, adds the sheet to the * "completed" hashtable, massages the XUL cache, handles siblings of - * the load data (other loads for the same URI, handles unblocking + * the load data (other loads for the same URI), handles unblocking * blocked parent loads as needed, and most importantly calls * NS_RELEASE on the load data to destroy the whole mess. */ void -CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, PRBool aSucceeded) +CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, nsresult aStatus) { LOG(("CSSLoaderImpl::SheetComplete")); NS_PRECONDITION(aLoadData, "Must have a load data!"); NS_PRECONDITION(aLoadData->mSheet, "Must have a sheet"); NS_ASSERTION(mLoadingDatas.IsInitialized(),"mLoadingDatas should be initialized by now."); - LOG(("Load completed: %d", aSucceeded)); + LOG(("Load completed, status: 0x%x", aStatus)); // Twiddle the hashtables if (aLoadData->mURI) { @@ -1441,13 +1487,16 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, PRBool aSucceeded) data->mSheet->SetModified(PR_FALSE); // it's clean data->mSheet->SetComplete(); - if (data->mObserver) { - data->mObserver->StyleSheetLoaded(data->mSheet, PR_TRUE); + if (data->mMustNotify && data->mObserver) { + data->mObserver->StyleSheetLoaded(data->mSheet, data->mWasAlternate, + aStatus); } - + + // 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) { + if (!seenParser && data->mMustNotify && !data->mWasAlternate) { LOG(("Unblocking parser: %p", data->mParserToUnblock.get())); seenParser = PR_TRUE; data->mParserToUnblock->ContinueParsing(); @@ -1467,14 +1516,14 @@ CSSLoaderImpl::SheetComplete(SheetLoadData* aLoadData, PRBool aSucceeded) if (data->mParentData && --(data->mParentData->mPendingChildren) == 0 && mParsingDatas.IndexOf(data->mParentData) == -1) { - SheetComplete(data->mParentData, aSucceeded); + SheetComplete(data->mParentData, aStatus); } data = data->mNext; } // Now that it's marked complete, put the sheet in our cache - if (aSucceeded && aLoadData->mURI) { + if (NS_SUCCEEDED(aStatus) && aLoadData->mURI) { #ifdef MOZ_XUL if (IsChromeURI(aLoadData->mURI)) { nsCOMPtr cache(do_GetService("@mozilla.org/xul/xul-prototype-cache;1")); @@ -1510,17 +1559,19 @@ NS_IMETHODIMP CSSLoaderImpl::LoadInlineStyle(nsIContent* aElement, nsIUnicharInputStream* aStream, PRUint32 aLineNumber, - const nsSubstring& aTitle, - const nsSubstring& aMedia, + const nsSubstring& aTitle, + const nsSubstring& aMedia, nsIParser* aParserToUnblock, - PRBool& aCompleted, - nsICSSLoaderObserver* aObserver) + nsICSSLoaderObserver* aObserver, + PRBool* aCompleted, + PRBool* aIsAlternate) + { LOG(("CSSLoaderImpl::LoadInlineStyle")); NS_PRECONDITION(aStream, "Must have a stream to parse!"); NS_ASSERTION(mParsingDatas.Count() == 0, "We're in the middle of a parse?"); - aCompleted = PR_TRUE; + *aCompleted = PR_TRUE; if (!mEnabled) { LOG_WARN((" Not enabled")); @@ -1540,15 +1591,18 @@ CSSLoaderImpl::LoadInlineStyle(nsIContent* aElement, NS_ASSERTION(state == eSheetNeedsParser, "Inline sheets should not be cached"); - rv = PrepareSheet(sheet, aTitle, aMedia, nsnull); + rv = PrepareSheet(sheet, aTitle, aMedia, nsnull, PR_FALSE, + aIsAlternate); NS_ENSURE_SUCCESS(rv, rv); + LOG((" Sheet is alternate: %d", *aIsAlternate)); + rv = InsertSheetInDoc(sheet, aElement, mDocument); NS_ENSURE_SUCCESS(rv, rv); SheetLoadData* data = new SheetLoadData(this, aTitle, aParserToUnblock, nsnull, sheet, owningElement, - aObserver); + *aIsAlternate, aObserver); if (!data) { sheet->SetComplete(); @@ -1558,25 +1612,34 @@ CSSLoaderImpl::LoadInlineStyle(nsIContent* aElement, NS_ADDREF(data); data->mLineNumber = aLineNumber; // Parse completion releases the load data - return ParseSheet(aStream, data, aCompleted); + rv = ParseSheet(aStream, data, *aCompleted); + NS_ENSURE_SUCCESS(rv, rv); + + // If aCompleted is true, |data| may well be deleted by now. + if (!*aCompleted) { + data->mMustNotify = PR_TRUE; + } + return rv; } NS_IMETHODIMP CSSLoaderImpl::LoadStyleLink(nsIContent* aElement, nsIURI* aURL, - const nsSubstring& aTitle, - const nsSubstring& aMedia, + const nsSubstring& aTitle, + const nsSubstring& aMedia, + PRBool aHasAlternateRel, nsIParser* aParserToUnblock, - PRBool& aCompleted, - nsICSSLoaderObserver* aObserver) + nsICSSLoaderObserver* aObserver, + PRBool* aIsAlternate) { LOG(("CSSLoaderImpl::LoadStyleLink")); NS_PRECONDITION(aURL, "Must have URL to load"); NS_ASSERTION(mParsingDatas.Count() == 0, "We're in the middle of a parse?"); LOG_URI(" Link uri: '%s'", aURL); - - aCompleted = PR_TRUE; + LOG((" Link title: '%s'", NS_ConvertUTF16toUTF8(aTitle).get())); + LOG((" Link media: '%s'", NS_ConvertUTF16toUTF8(aMedia).get())); + LOG((" Link alternate rel: %d", aHasAlternateRel)); if (!mEnabled) { LOG_WARN((" Not enabled")); @@ -1604,49 +1667,53 @@ CSSLoaderImpl::LoadStyleLink(nsIContent* aElement, getter_AddRefs(sheet)); NS_ENSURE_SUCCESS(rv, rv); - rv = PrepareSheet(sheet, aTitle, aMedia, nsnull); + rv = PrepareSheet(sheet, aTitle, aMedia, nsnull, aHasAlternateRel, + aIsAlternate); NS_ENSURE_SUCCESS(rv, rv); + + LOG((" Sheet is alternate: %d", *aIsAlternate)); rv = InsertSheetInDoc(sheet, aElement, mDocument); NS_ENSURE_SUCCESS(rv, rv); if (state == eSheetComplete) { - LOG((" Sheet already complete")); - // We're completely done; this sheet is fully loaded, clean, and so forth - if (aObserver) { - aObserver->StyleSheetLoaded(sheet, PR_TRUE); - } - return NS_OK; + LOG((" Sheet already complete: 0x%p", + NS_STATIC_CAST(void*, sheet.get()))); + return PostLoadEvent(aURL, sheet, aObserver, aParserToUnblock, + *aIsAlternate); } nsCOMPtr owningElement(do_QueryInterface(aElement)); // Now we need to actually load it SheetLoadData* data = new SheetLoadData(this, aTitle, aParserToUnblock, aURL, - sheet, owningElement, aObserver); + sheet, owningElement, *aIsAlternate, + aObserver); if (!data) { sheet->SetComplete(); - if (aObserver) { - aObserver->StyleSheetLoaded(sheet, PR_TRUE); - } return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(data); - // Caller gets to wait for the sheet to load. - aCompleted = PR_FALSE; - // If we have to parse and it's an alternate non-inline, defer it if (aURL && state == eSheetNeedsParser && mLoadingDatas.Count() != 0 && - IsAlternate(aTitle)) { + *aIsAlternate) { LOG((" Deferring alternate sheet load")); - mPendingDatas.Put(aURL, data); + if (!mPendingDatas.Put(aURL, data)) { + return NS_ERROR_OUT_OF_MEMORY; + } + + data->mMustNotify = PR_TRUE; return NS_OK; } // Load completion will free the data - return LoadSheet(data, state); + rv = LoadSheet(data, state); + NS_ENSURE_SUCCESS(rv, rv); + + data->mMustNotify = PR_TRUE; + return rv; } NS_IMETHODIMP @@ -1766,37 +1833,42 @@ CSSLoaderImpl::LoadChildSheet(nsICSSStyleSheet* aParentSheet, NS_ADDREF(data); // Load completion will release the data - return LoadSheet(data, state); - + rv = LoadSheet(data, state); + NS_ENSURE_SUCCESS(rv, rv); + + data->mMustNotify = PR_TRUE; + return rv; } NS_IMETHODIMP -CSSLoaderImpl::LoadAgentSheet(nsIURI* aURL, - nsICSSStyleSheet** aSheet) +CSSLoaderImpl::LoadSheetSync(nsIURI* aURL, nsICSSStyleSheet** aSheet) { - LOG(("CSSLoaderImpl::LoadAgentSheet synchronous")); - return InternalLoadAgentSheet(aURL, aSheet, nsnull); + LOG(("CSSLoaderImpl::LoadSheetSync")); + return InternalLoadNonDocumentSheet(aURL, aSheet, nsnull); } NS_IMETHODIMP -CSSLoaderImpl::LoadAgentSheet(nsIURI* aURL, - nsICSSLoaderObserver* aObserver) +CSSLoaderImpl::LoadSheet(nsIURI* aURL, nsICSSLoaderObserver* aObserver) { - LOG(("CSSLoaderImpl::LoadAgentSheet asynchronous")); - return InternalLoadAgentSheet(aURL, nsnull, aObserver); + LOG(("CSSLoaderImpl::LoadSheet api call")); + return InternalLoadNonDocumentSheet(aURL, nsnull, aObserver); } nsresult -CSSLoaderImpl::InternalLoadAgentSheet(nsIURI* aURL, - nsICSSStyleSheet** aSheet, - nsICSSLoaderObserver* aObserver) +CSSLoaderImpl::InternalLoadNonDocumentSheet(nsIURI* aURL, + nsICSSStyleSheet** aSheet, + nsICSSLoaderObserver* aObserver) { NS_PRECONDITION(aURL, "Must have a URI to load"); NS_PRECONDITION((!aSheet || !aObserver) && (aSheet || aObserver), "One or the other please, at most one"); NS_ASSERTION(mParsingDatas.Count() == 0, "We're in the middle of a parse?"); - LOG_URI(" Agent uri: '%s'", aURL); + LOG_URI(" Non-document sheet uri: '%s'", aURL); + + if (aSheet) { + *aSheet = nsnull; + } if (!mEnabled) { LOG_WARN((" Not enabled")); @@ -1815,19 +1887,14 @@ CSSLoaderImpl::InternalLoadAgentSheet(nsIURI* aURL, rv = PrepareSheet(sheet, empty, empty, nsnull); NS_ENSURE_SUCCESS(rv, rv); - if (aSheet) { - *aSheet = nsnull; - } - if (state == eSheetComplete) { LOG((" Sheet already complete")); if (aSheet) { - *aSheet = sheet; - NS_ADDREF(*aSheet); + sheet.swap(*aSheet); } else { - aObserver->StyleSheetLoaded(sheet, PR_TRUE); + rv = PostLoadEvent(aURL, sheet, aObserver, nsnull, PR_FALSE); } - return NS_OK; + return rv; } SheetLoadData* data = new SheetLoadData(this, aURL, sheet, syncLoad, aObserver); @@ -1839,15 +1906,120 @@ CSSLoaderImpl::InternalLoadAgentSheet(nsIURI* aURL, NS_ADDREF(data); rv = LoadSheet(data, state); + NS_ENSURE_SUCCESS(rv, rv); - if (NS_SUCCEEDED(rv) && aSheet) { - *aSheet = sheet; - NS_ADDREF(*aSheet); + if (aSheet) { + sheet.swap(*aSheet); + } else { + data->mMustNotify = PR_TRUE; } return rv; } +PR_BEGIN_EXTERN_C +PR_STATIC_CALLBACK(void*) HandleStyleSheetLoadedEvent(PLEvent* aEvent); +PR_STATIC_CALLBACK(void) DestroyStyleSheetLoadedEvent(PLEvent* aEvent); +PR_END_EXTERN_C + +PR_STATIC_CALLBACK(void*) +HandleStyleSheetLoadedEvent(PLEvent* aEvent) +{ + SheetLoadData* data = NS_STATIC_CAST(SheetLoadData*, aEvent); + data->mLoader->HandleLoadEvent(data); + return nsnull; +} + +PR_STATIC_CALLBACK(void) +DestroyStyleSheetLoadedEvent(PLEvent* aEvent) +{ + SheetLoadData* data = NS_STATIC_CAST(SheetLoadData*, aEvent); + data->mLoader->DestroyLoadEvent(data); +} + +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"); + + nsCOMPtr eventQ; + nsresult rv = nsContentUtils::EventQueueService()-> + GetSpecialEventQueue(nsIEventQueueService::UI_THREAD_EVENT_QUEUE, + getter_AddRefs(eventQ)); + NS_ENSURE_TRUE(eventQ, rv); + + SheetLoadData* evt = + new SheetLoadData(this, EmptyString(), // title doesn't matter here + aParserToUnblock, + aURI, + aSheet, + nsnull, // owning element doesn't matter here + aWasAlternate, + aObserver); + NS_ENSURE_TRUE(evt, NS_ERROR_OUT_OF_MEMORY); + + NS_ADDREF(evt); + + PL_InitEvent(evt, this, ::HandleStyleSheetLoadedEvent, + ::DestroyStyleSheetLoadedEvent); + + // We'll unblock onload when we destroy the event, so make sure to block it + // now. We unblock from destruction, not firing, just in case events get + // revoked for some reason. + if (mDocument) { + mDocument->BlockOnload(); + } + + if (!mPostedEvents.AppendElement(evt)) { + PL_DestroyEvent(evt); + return NS_ERROR_OUT_OF_MEMORY; + } + + rv = eventQ->PostEvent(evt); + if (NS_FAILED(rv)) { + PL_DestroyEvent(evt); + } else { + // We want to notify the observer for this data. We didn't want to set + // this earlier, since we would have returned an error _and_ notified. + evt->mMustNotify = PR_TRUE; + } + + return rv; +} + +void +CSSLoaderImpl::HandleLoadEvent(SheetLoadData* aEvent) +{ + // XXXbz can't assert this yet.... May not have an observer because + // we're unblocking the parser + // NS_ASSERTION(aEvent->mObserver, "Must have observer"); + NS_ASSERTION(aEvent->mSheet, "Must have sheet"); + if (!aEvent->mIsCancelled) { + // SheetComplete will call Release(), but we want aEvent to survive to have + // DestroyStyleSheetLoadedEvent called on it! + NS_ADDREF(aEvent); + SheetComplete(aEvent, NS_OK); + } +} + +void +CSSLoaderImpl::DestroyLoadEvent(SheetLoadData* aEvent) +{ + mPostedEvents.RemoveElement(aEvent); + NS_RELEASE(aEvent); + if (mDocument) { + mDocument->UnblockOnload(PR_TRUE); + } +} + nsresult NS_NewCSSLoader(nsIDocument* aDocument, nsICSSLoader** aLoader) { CSSLoaderImpl* it = new CSSLoaderImpl(); @@ -1876,20 +2048,37 @@ StopLoadingSheetCallback(nsIURI* aKey, SheetLoadData*& aData, void* aClosure) aData->mIsLoading = PR_FALSE; // we will handle the removal right here aData->mIsCancelled = PR_TRUE; - NS_STATIC_CAST(CSSLoaderImpl*,aClosure)->SheetComplete(aData, PR_FALSE); + NS_STATIC_CAST(CSSLoaderImpl*,aClosure)->SheetComplete(aData, + NS_BINDING_ABORTED); return PL_DHASH_REMOVE; } +PR_STATIC_CALLBACK(PRBool) +CancelSheetEventCallback(void* aData, void* aClosure) +{ + NS_PRECONDITION(aData, "Must have data"); + SheetLoadData* data = NS_STATIC_CAST(SheetLoadData*, aData); + data->mIsCancelled = PR_TRUE; + // Addref to keep |data| from dying, since we're not removing it from the + // event queue but plan to call SheetComplete on it. + NS_ADDREF(data); + data->mLoader->SheetComplete(data, NS_BINDING_ABORTED); + + return PR_TRUE; +} + NS_IMETHODIMP CSSLoaderImpl::Stop() { - if (mLoadingDatas.Count() > 0) { + if (mLoadingDatas.IsInitialized() && mLoadingDatas.Count() > 0) { mLoadingDatas.Enumerate(StopLoadingSheetCallback, this); } - if (mPendingDatas.Count() > 0) { + if (mPendingDatas.IsInitialized() && mPendingDatas.Count() > 0) { mPendingDatas.Enumerate(StopLoadingSheetCallback, this); } + mPostedEvents.EnumerateForwards(CancelSheetEventCallback, nsnull); + mPostedEvents.Clear(); return NS_OK; } @@ -1897,24 +2086,41 @@ NS_IMETHODIMP CSSLoaderImpl::StopLoadingSheet(nsIURI* aURL) { NS_ENSURE_TRUE(aURL, NS_ERROR_NULL_POINTER); - if (mLoadingDatas.Count() > 0 || mPendingDatas.Count() > 0) { - - SheetLoadData* loadData = nsnull; + + SheetLoadData* loadData = nsnull; + if (mLoadingDatas.IsInitialized()) { mLoadingDatas.Get(aURL, &loadData); - if (!loadData) { - mPendingDatas.Get(aURL, &loadData); - if (loadData) { - // have to remove from mPendingDatas ourselves, since - // SheetComplete won't do that. - mPendingDatas.Remove(aURL); - } - } - + } + if (!loadData && mPendingDatas.IsInitialized()) { + mPendingDatas.Get(aURL, &loadData); if (loadData) { - loadData->mIsCancelled = PR_TRUE; - SheetComplete(loadData, PR_FALSE); + // have to remove from mPendingDatas ourselves, since + // SheetComplete won't do that. + mPendingDatas.Remove(aURL); } } + + if (!loadData) { + for (PRInt32 i = 0; i < mPostedEvents.Count(); ++i) { + SheetLoadData* curData = NS_STATIC_CAST(SheetLoadData*, mPostedEvents[i]); + PRBool equal; + if (curData->mURI && NS_SUCCEEDED(curData->mURI->Equals(aURL, &equal)) && + equal) { + loadData = curData; + // Addref to keep |curData| from dying, since we're not removing it + // from the event queue but plan to call SheetComplete on it. + NS_ADDREF(curData); + mPostedEvents.RemoveElementAt(i); + break; + } + } + } + + if (loadData) { + loadData->mIsCancelled = PR_TRUE; + SheetComplete(loadData, NS_BINDING_ABORTED); + } + return NS_OK; } diff --git a/layout/style/nsCSSLoader.h b/layout/style/nsCSSLoader.h index 14fdb58f1e6..93673484009 100644 --- a/layout/style/nsCSSLoader.h +++ b/layout/style/nsCSSLoader.h @@ -67,13 +67,14 @@ class nsMediaList; #include "nsURIHashKey.h" #include "nsInterfaceHashtable.h" #include "nsDataHashtable.h" +#include "plevent.h" /** * OVERALL ARCHITECTURE * * The CSS Loader gets requests to load various sorts of style sheets: * inline style from