Bug 485012. Allow passing a charset hint (e.g. the element's 'charset' attribute for preloads) to nsICSSLoader::LoadSheet. r+sr=peterv
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 10 Apr 2009 10:29:08 -0400
changeset 27188 d20912121684029a56b5e7232dd08e05bdad1ae2
parent 27187 5e2dd420c2df371c7c48d69a23a6f609fcf8944d
child 27189 6b0948c4355b766927fef75b77647911df77192b
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs485012
milestone1.9.2a1pre
Bug 485012. Allow passing a charset hint (e.g. the element's 'charset' attribute for preloads) to nsICSSLoader::LoadSheet. r+sr=peterv
content/xbl/src/nsXBLResourceLoader.cpp
content/xul/document/src/nsXULDocument.cpp
editor/libeditor/html/nsHTMLEditor.cpp
layout/reftests/bugs/485012-1-ref.html
layout/reftests/bugs/485012-1.html
layout/reftests/bugs/reftest.list
layout/style/nsCSSLoader.cpp
layout/style/nsCSSLoader.h
layout/style/nsICSSLoader.h
parser/htmlparser/src/nsParser.cpp
--- a/content/xbl/src/nsXBLResourceLoader.cpp
+++ b/content/xbl/src/nsXBLResourceLoader.cpp
@@ -160,17 +160,17 @@ nsXBLResourceLoader::LoadResources(PRBoo
           {
             rv = StyleSheetLoaded(sheet, PR_FALSE, NS_OK);
             NS_ASSERTION(NS_SUCCEEDED(rv), "Processing the style sheet failed!!!");
           }
         }
       }
       else
       {
-        rv = cssLoader->LoadSheet(url, docPrincipal, this);
+        rv = cssLoader->LoadSheet(url, docPrincipal, EmptyCString(), this);
         if (NS_SUCCEEDED(rv))
           ++mPendingSheets;
       }
     }
   }
 
   *aResult = (mPendingSheets == 0);
   mInLoadResourcesFunc = PR_FALSE;
--- a/content/xul/document/src/nsXULDocument.cpp
+++ b/content/xul/document/src/nsXULDocument.cpp
@@ -3894,17 +3894,18 @@ nsXULDocument::AddPrototypeSheets()
     const nsCOMArray<nsIURI>& sheets = mCurrentPrototype->GetStyleSheetReferences();
 
     for (PRInt32 i = 0; i < sheets.Count(); i++) {
         nsCOMPtr<nsIURI> uri = sheets[i];
 
         nsCOMPtr<nsICSSStyleSheet> incompleteSheet;
         rv = CSSLoader()->LoadSheet(uri,
                                     mCurrentPrototype->DocumentPrincipal(),
-                                    this, getter_AddRefs(incompleteSheet));
+                                    EmptyCString(), this,
+                                    getter_AddRefs(incompleteSheet));
 
         // XXXldb We need to prevent bogus sheets from being held in the
         // prototype's list, but until then, don't propagate the failure
         // from LoadSheet (and thus exit the loop).
         if (NS_SUCCEEDED(rv)) {
             ++mPendingSheets;
             if (!mOverlaySheets.AppendObject(incompleteSheet)) {
                 return NS_ERROR_OUT_OF_MEMORY;
--- a/editor/libeditor/html/nsHTMLEditor.cpp
+++ b/editor/libeditor/html/nsHTMLEditor.cpp
@@ -3396,17 +3396,17 @@ nsHTMLEditor::ReplaceStyleSheet(const ns
   if (!ps) return NS_ERROR_NOT_INITIALIZED;
   nsIDocument *document = ps->GetDocument();
   if (!document)     return NS_ERROR_NULL_POINTER;
 
   nsCOMPtr<nsIURI> uaURI;
   rv = NS_NewURI(getter_AddRefs(uaURI), aURL);
   NS_ENSURE_SUCCESS(rv, rv);
 
-  rv = cssLoader->LoadSheet(uaURI, nsnull, this);
+  rv = cssLoader->LoadSheet(uaURI, nsnull, EmptyCString(), this);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLEditor::RemoveStyleSheet(const nsAString &aURL)
 {
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/485012-1-ref.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      body { color: green }
+    </style>
+  </head>
+  <body>
+    This should be green
+  </body>
+</html>
+  
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/485012-1.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <style>
+      body { color: red }
+    </style>
+    <script src="data:application/javascript,"></script>
+    <link rel="stylesheet" type="text/css"
+          charset="UTF-16BE"
+          href="data:text/css,%00b%00o%00d%00y%00{%00c%00o%00l%00o%00r%00:%00g%00r%00e%00e%00n}">
+  </head>
+  <body>
+    This should be green
+  </body>
+</html>
+  
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -1187,16 +1187,17 @@ fails == 472020-2.xul 472020-2-ref.xul
 == 480880-2c.html about:blank
 == 482592-1a.xhtml 482592-1-ref.html
 == 482592-1b.xhtml 482592-1-ref.html
 == 482659-1a.html 482659-1-ref.html
 == 482659-1b.html 482659-1-ref.html
 == 482659-1c.html 482659-1-ref.html
 == 482659-1d.html 482659-1-ref.html
 == 483565.xul 483565-ref.xul
+== 485012-1.html 485012-1-ref.html
 == 485275-1.html 485275-1-ref.html
 == 485275-1.svg 485275-1-ref.html
 == 486052-1.html 486052-1-ref.html
 == 486052-2a.html 486052-2-ref.html
 == 486052-2b.html 486052-2-ref.html
 == 486052-2c.html 486052-2-ref.html
 == 486052-2d.html 486052-2-ref.html
 == 486052-2e.html 486052-2-ref.html
--- a/layout/style/nsCSSLoader.cpp
+++ b/layout/style/nsCSSLoader.cpp
@@ -216,16 +216,17 @@ SheetLoadData::SheetLoadData(CSSLoaderIm
 }
 
 SheetLoadData::SheetLoadData(CSSLoaderImpl* aLoader,
                              nsIURI* aURI,
                              nsICSSStyleSheet* aSheet,
                              PRBool aSyncLoad,
                              PRBool aAllowUnsafeRules,
                              PRBool aUseSystemPrincipal,
+                             const nsCString& aCharset,
                              nsICSSLoaderObserver* aObserver,
                              nsIPrincipal* aLoaderPrincipal)
   : mLoader(aLoader),
     mURI(aURI),
     mLineNumber(1),
     mSheet(aSheet),
     mNext(nsnull),
     mParentData(nsnull),
@@ -235,17 +236,18 @@ SheetLoadData::SheetLoadData(CSSLoaderIm
     mIsLoading(PR_FALSE),
     mIsCancelled(PR_FALSE),
     mMustNotify(PR_FALSE),
     mWasAlternate(PR_FALSE),
     mAllowUnsafeRules(aAllowUnsafeRules),
     mUseSystemPrincipal(aUseSystemPrincipal),
     mOwningElement(nsnull),
     mObserver(aObserver),
-    mLoaderPrincipal(aLoaderPrincipal)
+    mLoaderPrincipal(aLoaderPrincipal),
+    mCharsetHint(aCharset)
 {
   NS_PRECONDITION(mLoader, "Must have a loader!");
   NS_ADDREF(mLoader);
 
   NS_POSTCONDITION(!mUseSystemPrincipal || mSyncLoad,
                    "Shouldn't use system principal for async loads");
 }
 
@@ -602,16 +604,19 @@ static nsresult GetCharsetFromData(const
 
 NS_IMETHODIMP
 SheetLoadData::OnDetermineCharset(nsIUnicharStreamLoader* aLoader,
                                   nsISupports* aContext,
                                   const char* aData,
                                   PRUint32 aDataLength,
                                   nsACString& aCharset)
 {
+  NS_PRECONDITION(!mOwningElement || mCharsetHint.IsEmpty(),
+                  "Can't have element _and_ charset hint");
+
   LOG_URI("SheetLoadData::OnDetermineCharset for '%s'", mURI);
   nsCOMPtr<nsIChannel> channel;
   nsresult result = aLoader->GetChannel(getter_AddRefs(channel));
   if (NS_FAILED(result))
     channel = nsnull;
 
   aCharset.Truncate();
 
@@ -657,16 +662,19 @@ SheetLoadData::OnDetermineCharset(nsIUni
       mOwningElement->GetCharset(elementCharset);
       LossyCopyUTF16toASCII(elementCharset, aCharset);
 #ifdef PR_LOGGING
       if (! aCharset.IsEmpty()) {
         LOG(("  Setting from property on element: %s",
              PromiseFlatCString(aCharset).get()));
       }
 #endif
+    } else {
+      // If mCharsetHint is empty, that's ok; aCharset is known empty here
+      aCharset = mCharsetHint;
     }
   }
 
   if (aCharset.IsEmpty() && mParentData) {
     aCharset = mParentData->mCharset;
 #ifdef PR_LOGGING
     if (! aCharset.IsEmpty()) {
       LOG(("  Setting from parent sheet: %s",
@@ -1990,48 +1998,51 @@ CSSLoaderImpl::LoadChildSheet(nsICSSStyl
 NS_IMETHODIMP
 CSSLoaderImpl::LoadSheetSync(nsIURI* aURL, PRBool aAllowUnsafeRules,
                              PRBool aUseSystemPrincipal,
                              nsICSSStyleSheet** aSheet)
 {
   LOG(("CSSLoaderImpl::LoadSheetSync"));
   return InternalLoadNonDocumentSheet(aURL, aAllowUnsafeRules,
                                       aUseSystemPrincipal, nsnull,
-                                      aSheet, nsnull);
+                                      EmptyCString(), aSheet, nsnull);
 }
 
 NS_IMETHODIMP
 CSSLoaderImpl::LoadSheet(nsIURI* aURL,
                          nsIPrincipal* aOriginPrincipal,
+                         const nsCString& aCharset,
                          nsICSSLoaderObserver* aObserver,
                          nsICSSStyleSheet** aSheet)
 {
   LOG(("CSSLoaderImpl::LoadSheet(aURL, aObserver, aSheet) api call"));
   NS_PRECONDITION(aSheet, "aSheet is null");
   return InternalLoadNonDocumentSheet(aURL, PR_FALSE, PR_FALSE,
-                                      aOriginPrincipal,
+                                      aOriginPrincipal, aCharset,
                                       aSheet, aObserver);
 }
 
 NS_IMETHODIMP
 CSSLoaderImpl::LoadSheet(nsIURI* aURL,
                          nsIPrincipal* aOriginPrincipal,
+                         const nsCString& aCharset,
                          nsICSSLoaderObserver* aObserver)
 {
   LOG(("CSSLoaderImpl::LoadSheet(aURL, aObserver) api call"));
   return InternalLoadNonDocumentSheet(aURL, PR_FALSE, PR_FALSE,
-                                      aOriginPrincipal,
+                                      aOriginPrincipal, aCharset,
                                       nsnull, aObserver);
 }
 
 nsresult
 CSSLoaderImpl::InternalLoadNonDocumentSheet(nsIURI* aURL, 
                                             PRBool aAllowUnsafeRules,
                                             PRBool aUseSystemPrincipal,
                                             nsIPrincipal* aOriginPrincipal,
+                                            const nsCString& aCharset,
                                             nsICSSStyleSheet** aSheet,
                                             nsICSSLoaderObserver* aObserver)
 {
   NS_PRECONDITION(aURL, "Must have a URI to load");
   NS_PRECONDITION(aSheet || aObserver, "Sheet and observer can't both be null");
   NS_PRECONDITION(!aUseSystemPrincipal || !aObserver,
                   "Shouldn't load system-principal sheets async");
   NS_ASSERTION(mParsingDatas.Length() == 0, "We're in the middle of a parse?");
@@ -2072,17 +2083,18 @@ CSSLoaderImpl::InternalLoadNonDocumentSh
     if (aSheet) {
       sheet.swap(*aSheet);
     }
     return rv;
   }
 
   SheetLoadData* data =
     new SheetLoadData(this, aURL, sheet, syncLoad, aAllowUnsafeRules,
-                      aUseSystemPrincipal, aObserver, aOriginPrincipal);
+                      aUseSystemPrincipal, aCharset, aObserver,
+                      aOriginPrincipal);
 
   if (!data) {
     sheet->SetComplete();
     return NS_ERROR_OUT_OF_MEMORY;
   }
   
   NS_ADDREF(data);
   rv = LoadSheet(data, state);
--- a/layout/style/nsCSSLoader.h
+++ b/layout/style/nsCSSLoader.h
@@ -131,16 +131,17 @@ public:
 
   // Data for loading a non-document sheet
   SheetLoadData(CSSLoaderImpl* aLoader,
                 nsIURI* aURI,
                 nsICSSStyleSheet* aSheet,
                 PRBool aSyncLoad,
                 PRBool aAllowUnsafeRules,
                 PRBool aUseSystemPrincipal,
+                const nsCString& aCharset,
                 nsICSSLoaderObserver* aObserver,
                 nsIPrincipal* aLoaderPrincipal);
 
   already_AddRefed<nsIURI> GetReferrerURI();
   
   NS_DECL_ISUPPORTS
   NS_DECL_NSIRUNNABLE
   NS_DECL_NSIUNICHARSTREAMLOADEROBSERVER
@@ -218,16 +219,20 @@ public:
   // charset set on it.
   nsCOMPtr<nsIStyleSheetLinkingElement> mOwningElement;
 
   // The observer that wishes to be notified of load completion
   nsCOMPtr<nsICSSLoaderObserver>        mObserver;
 
   // The principal that identifies who started loading us.
   nsCOMPtr<nsIPrincipal> mLoaderPrincipal;
+
+  // The charset to use if the transport and sheet don't indicate one.
+  // May be empty.  Must be empty if mOwningElement is non-null.
+  nsCString mCharsetHint;
 };
 
 class nsURIAndPrincipalHashKey : public nsURIHashKey
 {
 public:
   typedef nsURIAndPrincipalHashKey* KeyType;
   typedef const nsURIAndPrincipalHashKey* KeyTypePointer;
 
@@ -345,21 +350,23 @@ public:
                             nsICSSImportRule* aRule);
 
   NS_IMETHOD LoadSheetSync(nsIURI* aURL, PRBool aAllowUnsafeRules,
                            PRBool aUseSystemPrincipal,
                            nsICSSStyleSheet** aSheet);
 
   NS_IMETHOD LoadSheet(nsIURI* aURL,
                        nsIPrincipal* aOriginPrincipal,
+                       const nsCString& aCharset,
                        nsICSSLoaderObserver* aObserver,
                        nsICSSStyleSheet** aSheet);
 
   NS_IMETHOD LoadSheet(nsIURI* aURL,
                        nsIPrincipal* aOriginPrincipal,
+                       const nsCString& aCharset,
                        nsICSSLoaderObserver* aObserver);
 
   // stop loading all sheets
   NS_IMETHOD Stop(void);
 
   // stop loading one sheet
   NS_IMETHOD StopLoadingSheet(nsIURI* aURL);
 
@@ -419,16 +426,17 @@ private:
   nsresult InsertChildSheet(nsICSSStyleSheet* aSheet,
                             nsICSSStyleSheet* aParentSheet,
                             nsICSSImportRule* aParentRule);
 
   nsresult InternalLoadNonDocumentSheet(nsIURI* aURL,
                                         PRBool aAllowUnsafeRules,
                                         PRBool aUseSystemPrincipal,
                                         nsIPrincipal* aOriginPrincipal,
+                                        const nsCString& aCharset,
                                         nsICSSStyleSheet** aSheet,
                                         nsICSSLoaderObserver* aObserver);
 
   // Post a load event for aObserver to be notified about aSheet.  The
   // notification will be sent with status NS_OK unless the load event is
   // canceled at some point (in which case it will be sent with
   // NS_BINDING_ABORTED).  aWasAlternate indicates the state when the load was
   // initiated, not the state at some later time.  aURI should be the URI the
--- a/layout/style/nsICSSLoader.h
+++ b/layout/style/nsICSSLoader.h
@@ -204,32 +204,39 @@ public:
    * returned, aObserver is guaranteed to be notified asynchronously once the
    * sheet is loaded and marked complete.  This method can be used to load
    * sheets not associated with a document.
    *
    * @param aURL the URL of the sheet to load
    * @param aOriginPrincipal the principal to use for security checks.  This
    *                         can be null to indicate that these checks should
    *                         be skipped.
+   * @param aCharset the encoding to use for converting the sheet data
+   *        from bytes to Unicode.  May be empty to indicate that the
+   *        charset of the CSSLoader's document should be used.  This
+   *        is only used if neither the network transport nor the
+   *        sheet itself indicate an encoding.
    * @param aObserver the observer to notify when the load completes.
    *                  Must not be null.
    * @param [out] aSheet the sheet to load. Note that the sheet may well
    *              not be loaded by the time this method returns.
    */
   NS_IMETHOD LoadSheet(nsIURI* aURL,
                        nsIPrincipal* aOriginPrincipal,
+                       const nsCString& aCharset,
                        nsICSSLoaderObserver* aObserver,
                        nsICSSStyleSheet** aSheet) = 0;
 
   /**
    * Same as above, to be used when the caller doesn't care about the
    * not-yet-loaded sheet.
    */
   NS_IMETHOD LoadSheet(nsIURI* aURL,
                        nsIPrincipal* aOriginPrincipal,
+                       const nsCString& aCharset,
                        nsICSSLoaderObserver* aObserver) = 0;
 
   /**
    * Stop loading all sheets.  All nsICSSLoaderObservers involved will be
    * notified with NS_BINDING_ABORTED as the status, possibly synchronously.
    */
   NS_IMETHOD Stop(void) = 0;
 
--- a/parser/htmlparser/src/nsParser.cpp
+++ b/parser/htmlparser/src/nsParser.cpp
@@ -379,17 +379,19 @@ nsPreloadURIs::PreloadURIs(const nsAutoT
     alreadyPreloaded.Put(spec, PR_TRUE);
 
     switch (pe.type) {
       case nsSpeculativeScriptThread::SCRIPT:
         doc->ScriptLoader()->PreloadURI(uri, pe.charset, pe.elementType);
         break; 
       case nsSpeculativeScriptThread::STYLESHEET:
         nsCOMPtr<nsICSSLoaderObserver> obs = new nsDummyCSSLoaderObserver();
-        doc->CSSLoader()->LoadSheet(uri, doc->NodePrincipal(), obs);
+        doc->CSSLoader()->LoadSheet(uri, doc->NodePrincipal(),
+                                    NS_LossyConvertUTF16toASCII(pe.charset),
+                                    obs);
         break;
     }
   }
 }
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsSpeculativeScriptThread, nsIRunnable)
 
 NS_IMETHODIMP