Bug 508725 - Part 3: Create a rule processor for each style scope. r=dbaron

This commit is contained in:
Cameron McCormack 2013-01-08 19:09:22 +11:00
Родитель 894a529cc1
Коммит 6b90406bb3
6 изменённых файлов: 229 добавлений и 21 удалений

Просмотреть файл

@ -101,7 +101,8 @@ nsXBLPrototypeResources::FlushSkinSheets()
mStyleSheetList.AppendElement(newSheet);
}
mRuleProcessor = new nsCSSRuleProcessor(mStyleSheetList,
nsStyleSet::eDocSheet);
nsStyleSet::eDocSheet,
nullptr);
return NS_OK;
}

Просмотреть файл

@ -167,7 +167,8 @@ nsXBLResourceLoader::StyleSheetLoaded(nsCSSStyleSheet* aSheet,
// All stylesheets are loaded.
mResources->mRuleProcessor =
new nsCSSRuleProcessor(mResources->mStyleSheetList,
nsStyleSet::eDocSheet);
nsStyleSet::eDocSheet,
nullptr);
// XXX Check for mPendingScripts when scripts also come online.
if (!mInLoadResourcesFunc)

Просмотреть файл

@ -1051,12 +1051,17 @@ RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
//
nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets,
uint8_t aSheetType)
uint8_t aSheetType,
Element* aScopeElement)
: mSheets(aSheets)
, mRuleCascades(nullptr)
, mLastPresContext(nullptr)
, mSheetType(aSheetType)
, mScopeElement(aScopeElement)
{
NS_ASSERTION(!!mScopeElement == (aSheetType == nsStyleSet::eScopedDocSheet),
"aScopeElement must be specified iff aSheetType is "
"eScopedDocSheet");
for (sheet_array_type::size_type i = mSheets.Length(); i-- != 0; ) {
mSheets[i]->AddRuleProcessor(this);
}

Просмотреть файл

@ -43,7 +43,11 @@ class nsCSSRuleProcessor: public nsIStyleRuleProcessor {
public:
typedef nsTArray<nsRefPtr<nsCSSStyleSheet> > sheet_array_type;
nsCSSRuleProcessor(const sheet_array_type& aSheets, uint8_t aSheetType);
// aScopeElement must be non-null iff aSheetType is
// nsStyleSet::eScopedDocSheet.
nsCSSRuleProcessor(const sheet_array_type& aSheets,
uint8_t aSheetType,
mozilla::dom::Element* aScopeElement);
virtual ~nsCSSRuleProcessor();
NS_DECL_ISUPPORTS
@ -124,6 +128,13 @@ public:
bool AppendPageRules(nsPresContext* aPresContext,
nsTArray<nsCSSPageRule*>& aArray);
/**
* Returns the scope element for the scoped style sheets this rule
* processor is for. If this is not a rule processor for scoped style
* sheets, it returns null.
*/
mozilla::dom::Element* GetScopeElement() const { return mScopeElement; }
#ifdef DEBUG
void AssertQuirksChangeOK() {
NS_ASSERTION(!mRuleCascades, "can't toggle quirks style sheet without "
@ -163,7 +174,11 @@ private:
// The last pres context for which GetRuleCascades was called.
nsPresContext *mLastPresContext;
// The scope element for this rule processor's scoped style sheets.
// Only used if mSheetType == nsStyleSet::eScopedDocSheet.
nsRefPtr<mozilla::dom::Element> mScopeElement;
// type of stylesheet using this processor
uint8_t mSheetType; // == nsStyleSet::sheetType

Просмотреть файл

@ -21,6 +21,7 @@
#include "nsCSSAnonBoxes.h"
#include "nsCSSPseudoElements.h"
#include "nsCSSRuleProcessor.h"
#include "nsDataHashtable.h"
#include "nsIContent.h"
#include "nsRuleData.h"
#include "nsRuleProcessorData.h"
@ -209,11 +210,95 @@ nsStyleSet::SetQuirkStyleSheet(nsIStyleSheet* aQuirkStyleSheet)
mQuirkStyleSheet = aQuirkStyleSheet;
}
typedef nsDataHashtable<nsPtrHashKey<nsINode>, uint32_t> ScopeDepthCache;
// Returns the depth of a style scope element, with 1 being the depth of
// a style scope element that has no ancestor style scope elements. The
// depth does not count intervening non-scope elements.
static uint32_t
GetScopeDepth(nsINode* aScopeElement, ScopeDepthCache& aCache)
{
nsINode* parent = aScopeElement->GetParent();
if (!parent || !parent->IsElementInStyleScope()) {
return 1;
}
uint32_t depth = aCache.Get(aScopeElement);
if (!depth) {
for (nsINode* n = parent; n; n = n->GetParent()) {
if (n->IsScopedStyleRoot()) {
depth = GetScopeDepth(n, aCache) + 1;
aCache.Put(aScopeElement, depth);
break;
}
}
}
return depth;
}
struct ScopedSheetOrder
{
nsCSSStyleSheet* mSheet;
uint32_t mDepth;
uint32_t mOrder;
bool operator==(const ScopedSheetOrder& aRHS) const
{
return mDepth == aRHS.mDepth &&
mOrder == aRHS.mOrder;
}
bool operator<(const ScopedSheetOrder& aRHS) const
{
if (mDepth != aRHS.mDepth) {
return mDepth < aRHS.mDepth;
}
return mOrder < aRHS.mOrder;
}
};
// Sorts aSheets such that style sheets for ancestor scopes come
// before those for descendant scopes, and with sheets for a single
// scope in document order.
static void
SortStyleSheetsByScope(nsTArray<nsCSSStyleSheet*>& aSheets)
{
uint32_t n = aSheets.Length();
if (n == 1) {
return;
}
ScopeDepthCache cache;
cache.Init();
nsTArray<ScopedSheetOrder> sheets;
sheets.SetLength(n);
// For each sheet, record the depth of its scope element and its original
// document order.
for (uint32_t i = 0; i < n; i++) {
sheets[i].mSheet = aSheets[i];
sheets[i].mDepth = GetScopeDepth(aSheets[i]->GetScopeElement(), cache);
sheets[i].mOrder = i;
}
// Sort by depth first, then document order.
sheets.Sort();
for (uint32_t i = 0; i < n; i++) {
aSheets[i] = sheets[i].mSheet;
}
}
nsresult
nsStyleSet::GatherRuleProcessors(sheetType aType)
{
mRuleProcessors[aType] = nullptr;
if (aType == eScopedDocSheet) {
mScopedDocSheetRuleProcessors.Clear();
}
if (mAuthorStyleDisabled && (aType == eDocSheet ||
aType == eScopedDocSheet ||
aType == ePresHintSheet ||
aType == eStyleAttrSheet)) {
//don't regather if this level is disabled
@ -233,13 +318,54 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
mRuleProcessors[aType] = PresContext()->TransitionManager();
return NS_OK;
}
if (aType == eScopedDocSheet) {
// Create a rule processor for each scope.
uint32_t count = mSheets[eScopedDocSheet].Count();
if (count) {
// Gather the scoped style sheets into an array as
// nsCSSStyleSheets, and mark all of their scope elements
// as scoped style roots.
nsTArray<nsCSSStyleSheet*> sheets(count);
for (int32_t i = 0; i < count; i++) {
nsRefPtr<nsCSSStyleSheet> sheet =
do_QueryObject(mSheets[eScopedDocSheet].ObjectAt(i));
sheets.AppendElement(sheet);
Element* scope = sheet->GetScopeElement();
scope->SetIsScopedStyleRoot();
}
// Sort the scoped style sheets so that those for the same scope are
// adjacent and that ancestor scopes come before descendent scopes.
SortStyleSheetsByScope(sheets);
uint32_t start = 0, end;
do {
// Find the range of style sheets with the same scope.
Element* scope = sheets[start]->GetScopeElement();
end = start + 1;
while (end < count && sheets[end]->GetScopeElement() == scope) {
end++;
}
// Create a rule processor for the scope.
nsTArray< nsRefPtr<nsCSSStyleSheet> > sheetsForScope;
sheetsForScope.AppendElements(sheets.Elements() + start, end - start);
mScopedDocSheetRuleProcessors.AppendElement
(new nsCSSRuleProcessor(sheetsForScope, uint8_t(aType), scope));
start = end;
} while (start < count);
}
return NS_OK;
}
if (mSheets[aType].Count()) {
switch (aType) {
case eAgentSheet:
case eUserSheet:
case eDocSheet:
case eOverrideSheet: {
// levels containing CSS stylesheets
// levels containing CSS stylesheets (apart from eScopedDocSheet)
nsCOMArray<nsIStyleSheet>& sheets = mSheets[aType];
nsTArray<nsRefPtr<nsCSSStyleSheet> > cssSheets(sheets.Count());
for (int32_t i = 0, i_end = sheets.Count(); i < i_end; ++i) {
@ -247,8 +373,8 @@ nsStyleSet::GatherRuleProcessors(sheetType aType)
NS_ASSERTION(cssSheet, "not a CSS sheet");
cssSheets.AppendElement(cssSheet);
}
mRuleProcessors[aType] = new nsCSSRuleProcessor(cssSheets,
uint8_t(aType));
mRuleProcessors[aType] =
new nsCSSRuleProcessor(cssSheets, uint8_t(aType), nullptr);
} break;
default:
@ -815,15 +941,34 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
static_cast<ElementDependentRuleProcessorData*>(aData),
&cutOffInheritance);
}
if (!skipUserStyles && !cutOffInheritance &&
mRuleProcessors[eDocSheet]) // NOTE: different
if (!skipUserStyles && !cutOffInheritance && // NOTE: different
mRuleProcessors[eDocSheet])
(*aCollectorFunc)(mRuleProcessors[eDocSheet], aData);
aRuleWalker->SetLevel(eStyleAttrSheet, false,
aRuleWalker->GetCheckForImportantRules());
if (mRuleProcessors[eStyleAttrSheet])
(*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
nsRuleNode* lastDocRN = aRuleWalker->CurrentNode();
bool haveImportantDocRules = !aRuleWalker->GetCheckForImportantRules();
nsTArray<nsRuleNode*> lastScopedRNs;
nsTArray<bool> haveImportantScopedRules;
bool haveAnyImportantScopedRules = false;
if (!skipUserStyles && !cutOffInheritance &&
aElement && aElement->IsElementInStyleScope()) {
lastScopedRNs.SetLength(mScopedDocSheetRuleProcessors.Length());
haveImportantScopedRules.SetLength(mScopedDocSheetRuleProcessors.Length());
for (int32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++) {
aRuleWalker->SetLevel(eScopedDocSheet, false, true);
nsCSSRuleProcessor* processor =
static_cast<nsCSSRuleProcessor*>(mScopedDocSheetRuleProcessors[i].get());
(*aCollectorFunc)(mScopedDocSheetRuleProcessors[i], aData);
lastScopedRNs[i] = aRuleWalker->CurrentNode();
haveImportantScopedRules[i] = !aRuleWalker->GetCheckForImportantRules();
haveAnyImportantScopedRules = haveAnyImportantScopedRules || haveImportantScopedRules[i];
}
}
nsRuleNode* lastScopedRN = aRuleWalker->CurrentNode();
aRuleWalker->SetLevel(eStyleAttrSheet, false, true);
if (mRuleProcessors[eStyleAttrSheet])
(*aCollectorFunc)(mRuleProcessors[eStyleAttrSheet], aData);
nsRuleNode* lastStyleAttrRN = aRuleWalker->CurrentNode();
bool haveImportantStyleAttrRules = !aRuleWalker->GetCheckForImportantRules();
aRuleWalker->SetLevel(eOverrideSheet, false, true);
if (mRuleProcessors[eOverrideSheet])
@ -835,6 +980,27 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
aRuleWalker->SetLevel(eAnimationSheet, false, false);
(*aCollectorFunc)(mRuleProcessors[eAnimationSheet], aData);
if (haveAnyImportantScopedRules) {
for (uint32_t i = lastScopedRNs.Length(); i-- != 0; ) {
aRuleWalker->SetLevel(eScopedDocSheet, true, false);
nsRuleNode* startRN = lastScopedRNs[i];
nsRuleNode* endRN = i == 0 ? lastDocRN : lastScopedRNs[i - 1];
if (haveImportantScopedRules[i]) {
AddImportantRules(startRN, endRN, aRuleWalker); // scoped
}
#ifdef DEBUG
else {
AssertNoImportantRules(startRN, endRN);
}
#endif
}
}
#ifdef DEBUG
else {
AssertNoImportantRules(lastScopedRN, lastDocRN);
}
#endif
if (haveImportantDocRules) {
aRuleWalker->SetLevel(eDocSheet, true, false);
AddImportantRules(lastDocRN, lastPresHintRN, aRuleWalker); // doc
@ -845,13 +1011,23 @@ nsStyleSet::FileRules(nsIStyleRuleProcessor::EnumFunc aCollectorFunc,
}
#endif
if (haveImportantOverrideRules) {
aRuleWalker->SetLevel(eOverrideSheet, true, false);
AddImportantRules(lastOvrRN, lastDocRN, aRuleWalker); // override
if (haveImportantStyleAttrRules) {
aRuleWalker->SetLevel(eStyleAttrSheet, true, false);
AddImportantRules(lastStyleAttrRN, lastScopedRN, aRuleWalker); // style attr
}
#ifdef DEBUG
else {
AssertNoImportantRules(lastOvrRN, lastDocRN);
AssertNoImportantRules(lastStyleAttrRN, lastScopedRN);
}
#endif
if (haveImportantOverrideRules) {
aRuleWalker->SetLevel(eOverrideSheet, true, false);
AddImportantRules(lastOvrRN, lastStyleAttrRN, aRuleWalker); // override
}
#ifdef DEBUG
else {
AssertNoImportantRules(lastOvrRN, lastStyleAttrRN);
}
#endif
@ -920,9 +1096,14 @@ nsStyleSet::WalkRuleProcessors(nsIStyleRuleProcessor::EnumFunc aFunc,
mBindingManager->WalkRules(aFunc, aData, &cutOffInheritance);
}
}
if (!skipUserStyles && !cutOffInheritance &&
mRuleProcessors[eDocSheet]) // NOTE: different
(*aFunc)(mRuleProcessors[eDocSheet], aData);
if (!skipUserStyles && !cutOffInheritance) {
if (mRuleProcessors[eDocSheet]) // NOTE: different
(*aFunc)(mRuleProcessors[eDocSheet], aData);
if (aData->mElement->IsElementInStyleScope()) {
for (int32_t i = 0; i < mScopedDocSheetRuleProcessors.Length(); i++)
(*aFunc)(mScopedDocSheetRuleProcessors[i], aData);
}
}
if (mRuleProcessors[eStyleAttrSheet])
(*aFunc)(mRuleProcessors[eStyleAttrSheet], aData);
if (mRuleProcessors[eOverrideSheet])

Просмотреть файл

@ -374,8 +374,13 @@ class nsStyleSet
// sheet last.
nsCOMArray<nsIStyleSheet> mSheets[eSheetTypeCount];
// mRuleProcessors[eScopedDocSheet] is always null; rule processors
// for scoped style sheets are stored in mScopedDocSheetRuleProcessors.
nsCOMPtr<nsIStyleRuleProcessor> mRuleProcessors[eSheetTypeCount];
// Rule processors for HTML5 scoped style sheets, one per scope.
nsTArray<nsCOMPtr<nsIStyleRuleProcessor> > mScopedDocSheetRuleProcessors;
// cached instance for enabling/disabling
nsCOMPtr<nsIStyleSheet> mQuirkStyleSheet;