Bug 804120 - Offer a way to apply author stylesheet on a given document. r=bz
authorGabor Krizsanits <gkrizsanits@mozilla.com>
Mon, 29 Oct 2012 12:21:15 +0100
changeset 111801 169e189085e28253e113cb7b6b23e24c3d045e95
parent 111800 7869880fd020c77b5cc0f553516d263d6cd35e87
child 111802 0cbe3d87fa74ae867793a19b4e70fe69a4594ddd
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersbz
bugs804120
milestone19.0a1
Bug 804120 - Offer a way to apply author stylesheet on a given document. r=bz
content/base/public/nsIDocument.h
content/base/src/nsDocument.cpp
content/base/src/nsDocument.h
dom/base/nsDOMWindowUtils.cpp
dom/interfaces/base/nsIDOMWindowUtils.idl
layout/base/nsPresShell.cpp
layout/style/nsStyleSet.cpp
layout/style/nsStyleSet.h
layout/style/test/chrome/test_additional_sheets.html
--- a/content/base/public/nsIDocument.h
+++ b/content/base/public/nsIDocument.h
@@ -601,21 +601,23 @@ public:
   virtual int32_t GetNumberOfCatalogStyleSheets() const = 0;
   virtual nsIStyleSheet* GetCatalogStyleSheetAt(int32_t aIndex) const = 0;
   virtual void AddCatalogStyleSheet(nsIStyleSheet* aSheet) = 0;
   virtual void EnsureCatalogStyleSheet(const char *aStyleSheetURI) = 0;
 
   enum additionalSheetType {
     eAgentSheet,
     eUserSheet,
+    eAuthorSheet,
     SheetTypeCount
   };
 
   virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI) = 0;
   virtual void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI) = 0;
+  virtual nsIStyleSheet* FirstAdditionalAuthorSheet() = 0;
 
   /**
    * Get this document's CSSLoader.  This is guaranteed to not return null.
    */
   mozilla::css::Loader* CSSLoader() const {
     return mCSSLoader;
   }
 
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -1306,19 +1306,16 @@ nsIDocument::nsIDocument()
 // NOTE! nsDocument::operator new() zeroes out all members, so don't
 // bother initializing members to 0.
 
 nsDocument::nsDocument(const char* aContentType)
   : nsIDocument()
   , mAnimatingImages(true)
   , mVisibilityState(eHidden)
 {
-  MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(mAdditionalSheets) == SheetTypeCount,
-    "mAdditionalSheets array count is not correct");
-
   SetContentTypeInternal(nsDependentCString(aContentType));
 
 #ifdef PR_LOGGING
   if (!gDocumentLeakPRLog)
     gDocumentLeakPRLog = PR_NewLogModule("DocumentLeak");
 
   if (gDocumentLeakPRLog)
     PR_LOG(gDocumentLeakPRLog, PR_LOG_DEBUG,
@@ -2049,21 +2046,23 @@ nsDocument::ResetStylesheetsToURI(nsIURI
 {
   NS_PRECONDITION(aURI, "Null URI passed to ResetStylesheetsToURI");
 
   mozAutoDocUpdate upd(this, UPDATE_STYLE, true);
   RemoveStyleSheetsFromStyleSets(mStyleSheets, nsStyleSet::eDocSheet);
   RemoveStyleSheetsFromStyleSets(mCatalogSheets, nsStyleSet::eAgentSheet);
   RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAgentSheet], nsStyleSet::eAgentSheet);
   RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eUserSheet], nsStyleSet::eUserSheet);
+  RemoveStyleSheetsFromStyleSets(mAdditionalSheets[eAuthorSheet], nsStyleSet::eDocSheet);
 
   // Release all the sheets
   mStyleSheets.Clear();
-  mAdditionalSheets[eAgentSheet].Clear();
-  mAdditionalSheets[eUserSheet].Clear();
+  for (uint32_t i = 0; i < SheetTypeCount; ++i)
+    mAdditionalSheets[i].Clear();
+
   // NOTE:  We don't release the catalog sheets.  It doesn't really matter
   // now, but it could in the future -- in which case not releasing them
   // is probably the right thing to do.
 
   // Now reset our inline style and attribute sheets.
   if (mAttrStyleSheet) {
     // Remove this sheet from all style sets
     nsCOMPtr<nsIPresShell> shell = GetShell();
@@ -2110,16 +2109,27 @@ nsDocument::ResetStylesheetsToURI(nsIURI
 static bool
 AppendAuthorSheet(nsIStyleSheet *aSheet, void *aData)
 {
   nsStyleSet *styleSet = static_cast<nsStyleSet*>(aData);
   styleSet->AppendStyleSheet(nsStyleSet::eDocSheet, aSheet);
   return true;
 }
 
+static void
+AppendSheetsToStyleSet(nsStyleSet* aStyleSet,
+                       const nsCOMArray<nsIStyleSheet>& aSheets,
+                       nsStyleSet::sheetType aType) 
+{
+  for (int32_t i = aSheets.Count() - 1; i >= 0; --i) {
+    aStyleSet->AppendStyleSheet(aType, aSheets[i]);
+  }
+}
+
+
 void
 nsDocument::FillStyleSet(nsStyleSet* aStyleSet)
 {
   NS_PRECONDITION(aStyleSet, "Must have a style set");
   NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::ePresHintSheet) == 0,
                   "Style set already has a preshint sheet?");
   NS_PRECONDITION(aStyleSet->SheetCount(nsStyleSet::eDocSheet) == 0,
                   "Style set already has document sheets?");
@@ -2149,25 +2159,22 @@ nsDocument::FillStyleSet(nsStyleSet* aSt
 
   for (i = mCatalogSheets.Count() - 1; i >= 0; --i) {
     nsIStyleSheet* sheet = mCatalogSheets[i];
     if (sheet->IsApplicable()) {
       aStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
     }
   }
 
-  for (int32_t i = mAdditionalSheets[eAgentSheet].Count() - 1; i >= 0; --i) {
-    nsIStyleSheet* sheet = mAdditionalSheets[eAgentSheet][i];
-    aStyleSet->AppendStyleSheet(nsStyleSet::eAgentSheet, sheet);
-  }
-
-  for (int32_t i = mAdditionalSheets[eUserSheet].Count() - 1; i >= 0; --i) {
-    nsIStyleSheet* sheet = mAdditionalSheets[eUserSheet][i];
-    aStyleSet->AppendStyleSheet(nsStyleSet::eUserSheet, sheet);
-  }
+  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAgentSheet],
+                         nsStyleSet::eAgentSheet);
+  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eUserSheet],
+                         nsStyleSet::eUserSheet);
+  AppendSheetsToStyleSet(aStyleSet, mAdditionalSheets[eAuthorSheet],
+                         nsStyleSet::eDocSheet);
 }
 
 nsresult
 nsDocument::StartDocumentLoad(const char* aCommand, nsIChannel* aChannel,
                               nsILoadGroup* aLoadGroup,
                               nsISupports* aContainer,
                               nsIStreamListener **aDocListener,
                               bool aReset, nsIContentSink* aSink)
@@ -3595,16 +3602,33 @@ nsDocument::EnsureCatalogStyleSheet(cons
         BeginUpdate(UPDATE_STYLE);
         AddCatalogStyleSheet(sheet);
         EndUpdate(UPDATE_STYLE);
       }
     }
   }
 }
 
+static nsStyleSet::sheetType
+ConvertAdditionalSheetType(nsIDocument::additionalSheetType aType)
+{
+  switch(aType) {
+    case nsIDocument::eAgentSheet:
+      return nsStyleSet::eAgentSheet;
+    case nsIDocument::eUserSheet:
+      return nsStyleSet::eUserSheet;
+    case nsIDocument::eAuthorSheet:
+      return nsStyleSet::eDocSheet;
+    default:
+      NS_ASSERTION(false, "wrong type");
+      // we must return something although this should never happen
+      return nsStyleSet::eSheetTypeCount;
+  }
+}
+
 static int32_t
 FindSheet(const nsCOMArray<nsIStyleSheet>& aSheets, nsIURI* aSheetURI)
 {
   for (int32_t i = aSheets.Count() - 1; i >= 0; i-- ) {
     bool bEqual;
     nsIURI* uri = aSheets[i]->GetSheetURI();
 
     if (uri && NS_SUCCEEDED(uri->Equals(aSheetURI, &bEqual)) && bEqual)
@@ -3633,18 +3657,17 @@ nsDocument::LoadAdditionalStyleSheet(add
 
   mAdditionalSheets[aType].AppendObject(sheet);
   sheet->SetOwningDocument(this);
   MOZ_ASSERT(sheet->IsApplicable());
 
   BeginUpdate(UPDATE_STYLE);
   nsCOMPtr<nsIPresShell> shell = GetShell();
   if (shell) {
-    nsStyleSet::sheetType type = aType == eAgentSheet ? nsStyleSet::eAgentSheet :
-                                                        nsStyleSet::eUserSheet;
+    nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType);
     shell->StyleSet()->AppendStyleSheet(type, sheet);
   }
 
   // Passing false, so documet.styleSheets.length will not be affected by
   // these additional sheets.
   NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetAdded, (this, sheet, false));
   EndUpdate(UPDATE_STYLE);
 
@@ -3663,31 +3686,36 @@ nsDocument::RemoveAdditionalStyleSheet(a
     nsCOMPtr<nsIStyleSheet> sheetRef = sheets[i];
     sheets.RemoveObjectAt(i);
 
     BeginUpdate(UPDATE_STYLE);
     if (!mIsGoingAway) {
       MOZ_ASSERT(sheetRef->IsApplicable());
       nsCOMPtr<nsIPresShell> shell = GetShell();
       if (shell) {
-        nsStyleSet::sheetType type = aType == eAgentSheet ? nsStyleSet::eAgentSheet :
-                                                            nsStyleSet::eUserSheet;
+        nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType);
         shell->StyleSet()->RemoveStyleSheet(type, sheetRef);
       }
     }
 
     // Passing false, so documet.styleSheets.length will not be affected by
     // these additional sheets.
     NS_DOCUMENT_NOTIFY_OBSERVERS(StyleSheetRemoved, (this, sheetRef, false));
     EndUpdate(UPDATE_STYLE);
 
     sheetRef->SetOwningDocument(nullptr);
   }
 }
 
+nsIStyleSheet*
+nsDocument::FirstAdditionalAuthorSheet()
+{
+  return mAdditionalSheets[eAuthorSheet].SafeObjectAt(0);
+}
+
 nsIScriptGlobalObject*
 nsDocument::GetScriptGlobalObject() const
 {
    // If we're going away, we've already released the reference to our
    // ScriptGlobalObject.  We can, however, try to obtain it for the
    // caller through our docshell.
 
    // We actually need to start returning the docshell's script global
@@ -9604,16 +9632,20 @@ nsDocument::DocSizeOfExcludingThis(nsWin
   aWindowSizes->mStyleSheets +=
     mAdditionalSheets[eAgentSheet].
       SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
                           aWindowSizes->mMallocSizeOf);
   aWindowSizes->mStyleSheets +=
     mAdditionalSheets[eUserSheet].
       SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
                           aWindowSizes->mMallocSizeOf);
+  aWindowSizes->mStyleSheets +=
+    mAdditionalSheets[eAuthorSheet].
+      SizeOfExcludingThis(SizeOfStyleSheetsElementIncludingThis,
+                          aWindowSizes->mMallocSizeOf);
   // Lumping in the loader with the style-sheets size is not ideal,
   // but most of the things in there are in fact stylesheets, so it
   // doesn't seem worthwhile to separate it out.
   aWindowSizes->mStyleSheets +=
     CSSLoader()->SizeOfIncludingThis(aWindowSizes->mMallocSizeOf);
 
   aWindowSizes->mDOMOther +=
     mAttrStyleSheet ?
--- a/content/base/src/nsDocument.h
+++ b/content/base/src/nsDocument.h
@@ -596,16 +596,17 @@ public:
 
   virtual int32_t GetNumberOfCatalogStyleSheets() const;
   virtual nsIStyleSheet* GetCatalogStyleSheetAt(int32_t aIndex) const;
   virtual void AddCatalogStyleSheet(nsIStyleSheet* aSheet);
   virtual void EnsureCatalogStyleSheet(const char *aStyleSheetURI);
 
   virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI);
   virtual void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI);
+  virtual nsIStyleSheet* FirstAdditionalAuthorSheet();
 
   virtual nsIChannel* GetChannel() const {
     return mChannel;
   }
 
   /**
    * Get this document's inline style sheet.  May return null if there
    * isn't one
@@ -1119,17 +1120,17 @@ protected:
 
   // Weak reference to our sink for in case we no longer have a parser.  This
   // will allow us to flush out any pending stuff from the sink even if
   // EndLoad() has already happened.
   nsWeakPtr mWeakSink;
 
   nsCOMArray<nsIStyleSheet> mStyleSheets;
   nsCOMArray<nsIStyleSheet> mCatalogSheets;
-  nsCOMArray<nsIStyleSheet> mAdditionalSheets[2];
+  nsCOMArray<nsIStyleSheet> mAdditionalSheets[SheetTypeCount];
 
   // Array of observers
   nsTObserverArray<nsIDocumentObserver*> mObservers;
 
   // If document is created for example using
   // document.implementation.createDocument(...), mScriptObject points to
   // the script global object of the original document.
   nsWeakPtr mScriptObject;
--- a/dom/base/nsDOMWindowUtils.cpp
+++ b/dom/base/nsDOMWindowUtils.cpp
@@ -2932,71 +2932,88 @@ nsDOMWindowUtils::SelectAtPoint(float aX
   nsresult rv =
     static_cast<nsFrame*>(targetFrame)->
       SelectByTypeAtPoint(GetPresContext(), relPoint, amount, amount,
                           nsFrame::SELECT_ACCUMULATE);
   *_retval = !NS_FAILED(rv);
   return NS_OK;
 }
 
+static nsIDocument::additionalSheetType
+convertSheetType(uint32_t aSheetType)
+{
+  switch(aSheetType) {
+    case nsDOMWindowUtils::AGENT_SHEET:
+      return nsIDocument::eAgentSheet;
+    case nsDOMWindowUtils::USER_SHEET:
+      return nsIDocument::eUserSheet;
+    case nsDOMWindowUtils::AUTHOR_SHEET:
+      return nsIDocument::eAuthorSheet;
+    default:
+      NS_ASSERTION(false, "wrong type");
+      // we must return something although this should never happen
+      return nsIDocument::SheetTypeCount;
+  }
+}
+
 NS_IMETHODIMP
 nsDOMWindowUtils::LoadSheet(nsIURI *aSheetURI, uint32_t aSheetType)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   NS_ENSURE_ARG_POINTER(aSheetURI);
-  NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
+  NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
+                aSheetType == USER_SHEET ||
+                aSheetType == AUTHOR_SHEET);
 
   nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
   
   nsCOMPtr<nsIDOMDocument> ddoc;
   nsresult rv = window->GetDocument(getter_AddRefs(ddoc));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(ddoc, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(ddoc);
   NS_ENSURE_TRUE(doc, NS_ERROR_INVALID_ARG);
 
-  nsIDocument::additionalSheetType type = 
-    aSheetType == AGENT_SHEET ? nsIDocument::eAgentSheet :
-                                nsIDocument::eUserSheet;
+  nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
 
   rv = doc->LoadAdditionalStyleSheet(type, aSheetURI);
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType)
 {
   if (!nsContentUtils::IsCallerChrome()) {
     return NS_ERROR_DOM_SECURITY_ERR;
   }
 
   NS_ENSURE_ARG_POINTER(aSheetURI);
-  NS_ENSURE_ARG(aSheetType == AGENT_SHEET || aSheetType == USER_SHEET);
+  NS_ENSURE_ARG(aSheetType == AGENT_SHEET ||
+                aSheetType == USER_SHEET ||
+                aSheetType == AUTHOR_SHEET);
 
   nsCOMPtr<nsIDOMWindow> window = do_QueryReferent(mWindow);
   NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
 
   nsCOMPtr<nsIDOMDocument> ddoc;
   nsresult rv = window->GetDocument(getter_AddRefs(ddoc));
   NS_ENSURE_SUCCESS(rv, rv);
   NS_ENSURE_TRUE(ddoc, NS_ERROR_FAILURE);
 
   nsCOMPtr<nsIDocument> doc = do_QueryInterface(ddoc);
   NS_ENSURE_TRUE(doc, NS_ERROR_INVALID_ARG);
 
-  nsIDocument::additionalSheetType type = 
-    aSheetType == AGENT_SHEET ? nsIDocument::eAgentSheet :
-                                nsIDocument::eUserSheet;
+  nsIDocument::additionalSheetType type = convertSheetType(aSheetType);
 
   doc->RemoveAdditionalStyleSheet(type, aSheetURI);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMWindowUtils::GetIsHandlingUserInput(bool* aHandlingUserInput)
 {
--- a/dom/interfaces/base/nsIDOMWindowUtils.idl
+++ b/dom/interfaces/base/nsIDOMWindowUtils.idl
@@ -1257,16 +1257,17 @@ interface nsIDOMWindowUtils : nsISupport
   /**
    * Prevent this window (and any child windows) from displaying any further
    * dialogs (e.g. window.alert()).
    */
   void preventFurtherDialogs();
 
   const unsigned long AGENT_SHEET = 0;
   const unsigned long USER_SHEET = 1;
+  const unsigned long AUTHOR_SHEET = 2;
   /**
    * Synchronously loads a style sheet from |sheetURI| and adds it to the list
    * of additional style sheets of the document.
    *
    * These additional style sheets are very much like user/agent sheets loaded 
    * with loadAndRegisterSheet. The only difference is that they are applied only
    * on the document owned by this window.
    *
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -1518,17 +1518,25 @@ PresShell::AddAgentSheet(nsISupports* aS
 void
 PresShell::AddAuthorSheet(nsISupports* aSheet)
 {
   nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
   if (!sheet) {
     return;
   }
 
-  mStyleSet->AppendStyleSheet(nsStyleSet::eDocSheet, sheet);
+  // Document specific "additional" Author sheets should be stronger than the ones
+  // added with the StyleSheetService.
+  nsIStyleSheet* firstAuthorSheet = mDocument->FirstAdditionalAuthorSheet();
+  if (firstAuthorSheet) {
+    mStyleSet->InsertStyleSheetBefore(nsStyleSet::eDocSheet, sheet, firstAuthorSheet);
+  } else {
+    mStyleSet->AppendStyleSheet(nsStyleSet::eDocSheet, sheet);  
+  }
+
   ReconstructStyleData();
 }
 
 void
 PresShell::RemoveSheet(nsStyleSet::sheetType aType, nsISupports* aSheet)
 {
   nsCOMPtr<nsIStyleSheet> sheet = do_QueryInterface(aSheet);
   if (!sheet) {
--- a/layout/style/nsStyleSet.cpp
+++ b/layout/style/nsStyleSet.cpp
@@ -326,16 +326,39 @@ nsStyleSet::ReplaceSheets(sheetType aTyp
 
   if (!mBatching)
     return GatherRuleProcessors(aType);
 
   mDirty |= 1 << aType;
   return NS_OK;
 }
 
+nsresult
+nsStyleSet::InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
+                                   nsIStyleSheet *aReferenceSheet)
+{
+  NS_PRECONDITION(aNewSheet && aReferenceSheet, "null arg");
+  NS_ASSERTION(aNewSheet->IsApplicable(),
+               "Inapplicable sheet being placed in style set");
+
+  mSheets[aType].RemoveObject(aNewSheet);
+  int32_t idx = mSheets[aType].IndexOf(aReferenceSheet);
+  if (idx < 0)
+    return NS_ERROR_INVALID_ARG;
+  
+  if (!mSheets[aType].InsertObjectAt(aNewSheet, idx))
+    return NS_ERROR_OUT_OF_MEMORY;
+
+  if (!mBatching)
+    return GatherRuleProcessors(aType);
+
+  mDirty |= 1 << aType;
+  return NS_OK;
+}
+
 bool
 nsStyleSet::GetAuthorStyleDisabled()
 {
   return mAuthorStyleDisabled;
 }
 
 nsresult
 nsStyleSet::SetAuthorStyleDisabled(bool aStyleDisabled)
@@ -372,21 +395,23 @@ nsStyleSet::AddDocStyleSheet(nsIStyleShe
   int32_t index;
   for (index = 0; index < count; index++) {
     nsIStyleSheet* sheet = docSheets.ObjectAt(index);
     int32_t sheetDocIndex = aDocument->GetIndexOfStyleSheet(sheet);
     if (sheetDocIndex > newDocIndex)
       break;
 
     // If the sheet is not owned by the document it can be an author
-    // sheet registered at nsStyleSheetService, which means the new 
+    // sheet registered at nsStyleSheetService or an additional author
+    // sheet on the document, which means the new 
     // doc sheet should end up before it.
     if (sheetDocIndex < 0 &&
-        sheetService &&
-        sheetService->AuthorStyleSheets()->IndexOf(sheet) >= 0)
+        ((sheetService &&
+        sheetService->AuthorStyleSheets()->IndexOf(sheet) >= 0) ||
+        sheet == aDocument->FirstAdditionalAuthorSheet()))
         break;
   }
   if (!docSheets.InsertObjectAt(aSheet, index))
     return NS_ERROR_OUT_OF_MEMORY;
   if (!mBatching)
     return GatherRuleProcessors(eDocSheet);
 
   mDirty |= 1 << eDocSheet;
--- a/layout/style/nsStyleSet.h
+++ b/layout/style/nsStyleSet.h
@@ -228,16 +228,18 @@ class nsStyleSet
 
   // APIs to manipulate the style sheet lists.  The sheets in each
   // list are stored with the most significant sheet last.
   nsresult AppendStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
   nsresult PrependStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
   nsresult RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet);
   nsresult ReplaceSheets(sheetType aType,
                          const nsCOMArray<nsIStyleSheet> &aNewSheets);
+  nsresult InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet,
+                                  nsIStyleSheet *aReferenceSheet);
 
   // Enable/Disable entire author style level (Doc & PresHint levels)
   bool GetAuthorStyleDisabled();
   nsresult SetAuthorStyleDisabled(bool aStyleDisabled);
 
   int32_t SheetCount(sheetType aType) const {
     return mSheets[aType].Count();
   }
--- a/layout/style/test/chrome/test_additional_sheets.html
+++ b/layout/style/test/chrome/test_additional_sheets.html
@@ -33,26 +33,36 @@ function loadUserSheet(win, style)
   loadSheet(win, style, "USER_SHEET");
 }
 
 function loadAgentSheet(win, style)
 {
   loadSheet(win, style, "AGENT_SHEET");
 }
 
+function loadAuthorSheet(win, style)
+{
+  loadSheet(win, style, "AUTHOR_SHEET");
+}
+
 function removeUserSheet(win, style)
 {
   removeSheet(win, style, "USER_SHEET");
 }
 
 function removeAgentSheet(win, style)
 {
   removeSheet(win, style, "AGENT_SHEET");
 }
 
+function removeAuthorSheet(win, style)
+{
+  removeSheet(win, style, "AUTHOR_SHEET");
+}
+
 function loadSheet(win, style, type)
 {
   var uri = gIOService.newURI(getUri(style), null, null);
   var windowUtils = win.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
     .getInterface(Components.interfaces.nsIDOMWindowUtils);
   windowUtils.loadSheet(uri, windowUtils[type]);
 }
 
@@ -157,25 +167,32 @@ var additionalAgent = {
 
 var additionalUser = {
   type: 'additionalUser',
   color: 'rgb(255, 255, 0)',
   addRules: loadUserSheet,
   removeRules: removeUserSheet
 };
 
-var author = {
-  type: 'author',
+var additionalAuthor = {
+  type: 'additionalAuthor',
+  color: 'rgb(255, 255, 0)',
+  addRules: loadAuthorSheet,
+  removeRules: removeAuthorSheet
+};
+
+var doc = {
+  type: 'doc',
   color: 'rgb(0, 255, 255)',
   addRules: setDocSheet,
   removeRules: removeDocSheet
 };
 
-var authorFromManager = {
-  type: 'authorFromManager',
+var author = {
+  type: 'author',
   color: 'rgb(255, 0, 255)',
   addRules: loadAndRegisterAuthorSheet,
   removeRules: unregisterAuthorSheet
 };
 
 function loadAndCheck(win, firstType, secondType, swap, result1, result2)
 {
   var firstStyle = getStyle(firstType.color, false);
@@ -232,46 +249,63 @@ function run()
 // if there is an important rule in both for let's say color (ii)
 // the rule specified in the agent style will lead (AB.ii == 0)
 // If both rules would be just regular rules the one specified in the user style
 // would lead. (AB.rr == 1). If we would load/add the rules in reverse order that
 // would not change that (BA.rr == 1)
   testStyleVsStyle(win, agent, user,
                    {AB:{rr:1, ii:0, ri:1, ir:0}, BA:{rr:1, ii:0, ri:1, ir:0}});
 
-  testStyleVsStyle(win, agent, author,
+  testStyleVsStyle(win, agent, doc,
                    {AB:{rr:1, ii:0, ri:1, ir:0}, BA:{rr:1, ii:0, ri:1, ir:0}});
 
 
   testStyleVsStyle(win, additionalUser, agent,
                    {AB:{rr:0, ii:1, ri:1, ir:0}, BA:{rr:0, ii:1, ri:1, ir:0}});
 
-  testStyleVsStyle(win, additionalUser, author,
+  testStyleVsStyle(win, additionalUser, doc,
                    {AB:{rr:1, ii:0, ri:1, ir:0}, BA:{rr:1, ii:0, ri:1, ir:0}});
 
   testStyleVsStyle(win, additionalAgent, user,
                    {AB:{rr:1, ii:0, ri:1, ir:0}, BA:{rr:1, ii:0, ri:1, ir:0}});
 
-  testStyleVsStyle(win, additionalAgent, author,
+  testStyleVsStyle(win, additionalAgent, doc,
                    {AB:{rr:1, ii:0, ri:1, ir:0}, BA:{rr:1, ii:0, ri:1, ir:0}});
 
 
   testStyleVsStyle(win, additionalAgent, additionalUser,
                    {AB:{rr:1, ii:0, ri:1, ir:0}, BA:{rr:1, ii:0, ri:1, ir:0}});
 
-  testStyleVsStyle(win, authorFromManager, author,
+  testStyleVsStyle(win, author, doc,
                    {AB:{rr:0, ii:0, ri:1, ir:0}, BA:{rr:0, ii:0, ri:1, ir:0}});
 
-  testStyleVsStyle(win, authorFromManager, user,
+  testStyleVsStyle(win, author, user,
+                   {AB:{rr:0, ii:1, ri:1, ir:0}, BA:{rr:0, ii:1, ri:1, ir:0}});
+
+  testStyleVsStyle(win, author, agent,
+                   {AB:{rr:0, ii:1, ri:1, ir:0}, BA:{rr:0, ii:1, ri:1, ir:0}});
+
+  testStyleVsStyle(win, author, additionalUser,
                    {AB:{rr:0, ii:1, ri:1, ir:0}, BA:{rr:0, ii:1, ri:1, ir:0}});
 
-  testStyleVsStyle(win, authorFromManager, additionalUser,
+  testStyleVsStyle(win, additionalAuthor, doc,
+                   {AB:{rr:0, ii:0, ri:1, ir:0}, BA:{rr:0, ii:0, ri:1, ir:0}});
+
+  testStyleVsStyle(win, additionalAuthor, author,
+                   {AB:{rr:0, ii:0, ri:1, ir:0}, BA:{rr:0, ii:0, ri:1, ir:0}});
+
+  testStyleVsStyle(win, additionalAuthor, user,
+                     {AB:{rr:0, ii:1, ri:1, ir:0}, BA:{rr:0, ii:1, ri:1, ir:0}});
+
+  testStyleVsStyle(win, additionalAuthor, agent,
+                     {AB:{rr:0, ii:1, ri:1, ir:0}, BA:{rr:0, ii:1, ri:1, ir:0}});
+
+  testStyleVsStyle(win, additionalAuthor, additionalUser,
                    {AB:{rr:0, ii:1, ri:1, ir:0}, BA:{rr:0, ii:1, ri:1, ir:0}});
 
-
   SimpleTest.finish();
 }
 
 SimpleTest.waitForExplicitFinish();
 
 </script>
 </pre>
 </body>