Bug 804120 - Offer a way to apply author stylesheet on a given document. r=bz

This commit is contained in:
Gabor Krizsanits 2012-10-29 12:21:15 +01:00
parent 78fac44a14
commit f83543b9ea
9 changed files with 163 additions and 41 deletions

View File

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

View File

@ -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<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)
{
@ -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<nsIStyleSheet>& aSheets, nsIURI* aSheetURI)
{
@ -3638,8 +3662,7 @@ nsDocument::LoadAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheetUR
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);
}
@ -3668,8 +3691,7 @@ nsDocument::RemoveAdditionalStyleSheet(additionalSheetType aType, nsIURI* aSheet
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);
}
}
@ -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.

View File

@ -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<nsIStyleSheet> mStyleSheets;
nsCOMArray<nsIStyleSheet> mCatalogSheets;
nsCOMArray<nsIStyleSheet> mAdditionalSheets[2];
nsCOMArray<nsIStyleSheet> mAdditionalSheets[SheetTypeCount];
// Array of observers
nsTObserverArray<nsIDocumentObserver*> mObservers;

View File

@ -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<nsIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
@ -2958,9 +2977,7 @@ nsDOMWindowUtils::LoadSheet(nsIURI *aSheetURI, uint32_t aSheetType)
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);
@ -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<nsIDOMWindow> window = do_QueryReferent(mWindow);
NS_ENSURE_TRUE(window, NS_ERROR_INVALID_ARG);
@ -2989,9 +3008,7 @@ nsDOMWindowUtils::RemoveSheet(nsIURI *aSheetURI, uint32_t aSheetType)
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;

View File

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

View File

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

View File

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

View File

@ -233,6 +233,8 @@ class nsStyleSet
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();

View File

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