From f83543b9eae0ced5911c9a0d71142bd3973e8a34 Mon Sep 17 00:00:00 2001 From: Gabor Krizsanits Date: Mon, 29 Oct 2012 12:21:15 +0100 Subject: [PATCH] Bug 804120 - Offer a way to apply author stylesheet on a given document. r=bz --- content/base/public/nsIDocument.h | 2 + content/base/src/nsDocument.cpp | 68 ++++++++++++++----- content/base/src/nsDocument.h | 3 +- dom/base/nsDOMWindowUtils.cpp | 33 ++++++--- dom/interfaces/base/nsIDOMWindowUtils.idl | 1 + layout/base/nsPresShell.cpp | 10 ++- layout/style/nsStyleSet.cpp | 31 ++++++++- layout/style/nsStyleSet.h | 2 + .../test/chrome/test_additional_sheets.html | 54 ++++++++++++--- 9 files changed, 163 insertions(+), 41 deletions(-) diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h index 475936397ed..210a744c901 100644 --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -606,11 +606,13 @@ public: 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. diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp index 131ceea7e19..f3058d49d0e 100644 --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -1311,9 +1311,6 @@ nsDocument::nsDocument(const char* aContentType) , mAnimatingImages(true) , mVisibilityState(eHidden) { - MOZ_STATIC_ASSERT(NS_ARRAY_LENGTH(mAdditionalSheets) == SheetTypeCount, - "mAdditionalSheets array count is not correct"); - SetContentTypeInternal(nsDependentCString(aContentType)); #ifdef PR_LOGGING @@ -2054,11 +2051,13 @@ nsDocument::ResetStylesheetsToURI(nsIURI* aURI) 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. @@ -2115,6 +2114,17 @@ AppendAuthorSheet(nsIStyleSheet *aSheet, void *aData) return true; } +static void +AppendSheetsToStyleSet(nsStyleSet* aStyleSet, + const nsCOMArray& aSheets, + nsStyleSet::sheetType aType) +{ + for (int32_t i = aSheets.Count() - 1; i >= 0; --i) { + aStyleSet->AppendStyleSheet(aType, aSheets[i]); + } +} + + void nsDocument::FillStyleSet(nsStyleSet* aStyleSet) { @@ -2154,15 +2164,12 @@ nsDocument::FillStyleSet(nsStyleSet* aStyleSet) } } - 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 @@ -3600,6 +3607,23 @@ nsDocument::EnsureCatalogStyleSheet(const char *aStyleSheetURI) } } +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& aSheets, nsIURI* aSheetURI) { @@ -3638,8 +3662,7 @@ nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetUR BeginUpdate(UPDATE_STYLE); nsCOMPtr shell = GetShell(); if (shell) { - nsStyleSet::sheetType type = aType == eAgentSheet ? nsStyleSet::eAgentSheet : - nsStyleSet::eUserSheet; + nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType); shell->StyleSet()->AppendStyleSheet(type, sheet); } @@ -3668,8 +3691,7 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet MOZ_ASSERT(sheetRef->IsApplicable()); nsCOMPtr shell = GetShell(); if (shell) { - nsStyleSet::sheetType type = aType == eAgentSheet ? nsStyleSet::eAgentSheet : - nsStyleSet::eUserSheet; + nsStyleSet::sheetType type = ConvertAdditionalSheetType(aType); shell->StyleSet()->RemoveStyleSheet(type, sheetRef); } } @@ -3683,6 +3705,12 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet } } +nsIStyleSheet* +nsDocument::FirstAdditionalAuthorSheet() +{ + return mAdditionalSheets[eAuthorSheet].SafeObjectAt(0); +} + nsIScriptGlobalObject* nsDocument::GetScriptGlobalObject() const { @@ -9609,6 +9637,10 @@ nsDocument::DocSizeOfExcludingThis(nsWindowSizes* aWindowSizes) const 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. diff --git a/content/base/src/nsDocument.h b/content/base/src/nsDocument.h index 130602f866a..a242ee09b39 100644 --- a/content/base/src/nsDocument.h +++ b/content/base/src/nsDocument.h @@ -601,6 +601,7 @@ public: virtual nsresult LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetURI); virtual void RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* sheetURI); + virtual nsIStyleSheet* FirstAdditionalAuthorSheet(); virtual nsIChannel* GetChannel() const { return mChannel; @@ -1124,7 +1125,7 @@ protected: nsCOMArray mStyleSheets; nsCOMArray mCatalogSheets; - nsCOMArray mAdditionalSheets[2]; + nsCOMArray mAdditionalSheets[SheetTypeCount]; // Array of observers nsTObserverArray mObservers; diff --git a/dom/base/nsDOMWindowUtils.cpp b/dom/base/nsDOMWindowUtils.cpp index 226049afd8c..d493cb7b675 100644 --- a/dom/base/nsDOMWindowUtils.cpp +++ b/dom/base/nsDOMWindowUtils.cpp @@ -2937,6 +2937,23 @@ nsDOMWindowUtils::SelectAtPoint(float aX, float aY, uint32_t aSelectBehavior, 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) { @@ -2945,7 +2962,9 @@ nsDOMWindowUtils::LoadSheet(nsIURI *aSheetURI, uint32_t aSheetType) } 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 window = do_QueryReferent(mWindow); NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG); @@ -2958,9 +2977,7 @@ nsDOMWindowUtils::LoadSheet(nsIURI *aSheetURI, uint32_t aSheetType) nsCOMPtr 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); @@ -2976,7 +2993,9 @@ nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType) } 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 window = do_QueryReferent(mWindow); NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG); @@ -2989,9 +3008,7 @@ nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType) nsCOMPtr 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; diff --git a/dom/interfaces/base/nsIDOMWindowUtils.idl b/dom/interfaces/base/nsIDOMWindowUtils.idl index 32e117a4011..72b1cd04a31 100644 --- a/dom/interfaces/base/nsIDOMWindowUtils.idl +++ b/dom/interfaces/base/nsIDOMWindowUtils.idl @@ -1262,6 +1262,7 @@ interface nsIDOMWindowUtils : nsISupports { 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. diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp index 6bb66c29c83..c8bf6fcb777 100644 --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1523,7 +1523,15 @@ PresShell::AddAuthorSheet(nsISupports* aSheet) 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(); } diff --git a/layout/style/nsStyleSet.cpp b/layout/style/nsStyleSet.cpp index 1612dae938f..92e38656dd9 100644 --- a/layout/style/nsStyleSet.cpp +++ b/layout/style/nsStyleSet.cpp @@ -331,6 +331,29 @@ nsStyleSet::ReplaceSheets(sheetType 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() { @@ -377,11 +400,13 @@ nsStyleSet::AddDocStyleSheet(nsIStyleSheet* aSheet, nsIDocument* aDocument) 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)) diff --git a/layout/style/nsStyleSet.h b/layout/style/nsStyleSet.h index d776d376422..070b469ca5d 100644 --- a/layout/style/nsStyleSet.h +++ b/layout/style/nsStyleSet.h @@ -233,6 +233,8 @@ class nsStyleSet nsresult RemoveStyleSheet(sheetType aType, nsIStyleSheet *aSheet); nsresult ReplaceSheets(sheetType aType, const nsCOMArray &aNewSheets); + nsresult InsertStyleSheetBefore(sheetType aType, nsIStyleSheet *aNewSheet, + nsIStyleSheet *aReferenceSheet); // Enable/Disable entire author style level (Doc & PresHint levels) bool GetAuthorStyleDisabled(); diff --git a/layout/style/test/chrome/test_additional_sheets.html b/layout/style/test/chrome/test_additional_sheets.html index a7ee282b4e8..c4b7b75e7a0 100644 --- a/layout/style/test/chrome/test_additional_sheets.html +++ b/layout/style/test/chrome/test_additional_sheets.html @@ -38,6 +38,11 @@ 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"); @@ -48,6 +53,11 @@ 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); @@ -162,15 +172,22 @@ var additionalUser = { 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 @@ -237,35 +254,52 @@ function run() 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, authorFromManager, additionalUser, + 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, 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(); }