mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-14 05:45:37 +00:00
Bug 77999 - Part 3: Gather document rules and produce an nsDocumentRuleResultCacheKey in nsCSSRuleProcessors. r=dbaron
This commit is contained in:
parent
7c894d7982
commit
61f1cd54f1
@ -1017,7 +1017,11 @@ nsCSSRuleProcessor::nsCSSRuleProcessor(const sheet_array_type& aSheets,
|
||||
, mScopeElement(aScopeElement)
|
||||
, mSheetType(aSheetType)
|
||||
, mIsShared(aIsShared)
|
||||
, mMustGatherDocumentRules(aIsShared)
|
||||
, mInRuleProcessorCache(false)
|
||||
#ifdef DEBUG
|
||||
, mDocumentRulesAndCacheKeyValid(false)
|
||||
#endif
|
||||
{
|
||||
NS_ASSERTION(!!mScopeElement == (aSheetType == nsStyleSet::eScopedDocSheet),
|
||||
"aScopeElement must be specified iff aSheetType is "
|
||||
@ -3005,6 +3009,16 @@ nsCSSRuleProcessor::ClearRuleCascades()
|
||||
// cache key results).
|
||||
MOZ_ASSERT(!RuleProcessorCache::HasRuleProcessor(this));
|
||||
|
||||
#ifdef DEBUG
|
||||
// For shared rule processors, if we've already gathered document
|
||||
// rules, then they will now be out of date. We don't actually need
|
||||
// them to be up-to-date (see the comment in RefreshRuleCascade), so
|
||||
// record their invalidity so we can assert if we try to use them.
|
||||
if (!mMustGatherDocumentRules) {
|
||||
mDocumentRulesAndCacheKeyValid = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
// We rely on our caller (perhaps indirectly) to do something that
|
||||
// will rebuild style data and the user font set (either
|
||||
// nsIPresShell::ReconstructStyleData or
|
||||
@ -3302,17 +3316,23 @@ struct CascadeEnumData {
|
||||
nsTArray<nsCSSFontFeatureValuesRule*>& aFontFeatureValuesRules,
|
||||
nsTArray<nsCSSPageRule*>& aPageRules,
|
||||
nsTArray<nsCSSCounterStyleRule*>& aCounterStyleRules,
|
||||
nsTArray<css::DocumentRule*>& aDocumentRules,
|
||||
nsMediaQueryResultCacheKey& aKey,
|
||||
uint8_t aSheetType)
|
||||
nsDocumentRuleResultCacheKey& aDocumentKey,
|
||||
uint8_t aSheetType,
|
||||
bool aMustGatherDocumentRules)
|
||||
: mPresContext(aPresContext),
|
||||
mFontFaceRules(aFontFaceRules),
|
||||
mKeyframesRules(aKeyframesRules),
|
||||
mFontFeatureValuesRules(aFontFeatureValuesRules),
|
||||
mPageRules(aPageRules),
|
||||
mCounterStyleRules(aCounterStyleRules),
|
||||
mDocumentRules(aDocumentRules),
|
||||
mCacheKey(aKey),
|
||||
mDocumentCacheKey(aDocumentKey),
|
||||
mRulesByWeight(&gRulesByWeightOps, sizeof(RuleByWeightEntry), 32),
|
||||
mSheetType(aSheetType)
|
||||
mSheetType(aSheetType),
|
||||
mMustGatherDocumentRules(aMustGatherDocumentRules)
|
||||
{
|
||||
// Initialize our arena
|
||||
PL_INIT_ARENA_POOL(&mArena, "CascadeEnumDataArena",
|
||||
@ -3330,14 +3350,61 @@ struct CascadeEnumData {
|
||||
nsTArray<nsCSSFontFeatureValuesRule*>& mFontFeatureValuesRules;
|
||||
nsTArray<nsCSSPageRule*>& mPageRules;
|
||||
nsTArray<nsCSSCounterStyleRule*>& mCounterStyleRules;
|
||||
nsTArray<css::DocumentRule*>& mDocumentRules;
|
||||
nsMediaQueryResultCacheKey& mCacheKey;
|
||||
nsDocumentRuleResultCacheKey& mDocumentCacheKey;
|
||||
PLArenaPool mArena;
|
||||
// Hooray, a manual PLDHashTable since nsClassHashtable doesn't
|
||||
// provide a getter that gives me a *reference* to the value.
|
||||
PLDHashTable mRulesByWeight; // of PerWeightDataListItem linked lists
|
||||
uint8_t mSheetType;
|
||||
bool mMustGatherDocumentRules;
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively traverses rules in order to:
|
||||
* (1) add any @-moz-document rules into data->mDocumentRules.
|
||||
* (2) record any @-moz-document rules whose conditions evaluate to true
|
||||
* on data->mDocumentCacheKey.
|
||||
*
|
||||
* See also CascadeRuleEnumFunc below, which calls us via
|
||||
* EnumerateRulesForwards. If modifying this function you may need to
|
||||
* update CascadeRuleEnumFunc too.
|
||||
*/
|
||||
static bool
|
||||
GatherDocRuleEnumFunc(css::Rule* aRule, void* aData)
|
||||
{
|
||||
CascadeEnumData* data = (CascadeEnumData*)aData;
|
||||
int32_t type = aRule->GetType();
|
||||
|
||||
MOZ_ASSERT(data->mMustGatherDocumentRules,
|
||||
"should only call GatherDocRuleEnumFunc if "
|
||||
"mMustGatherDocumentRules is true");
|
||||
|
||||
if (css::Rule::MEDIA_RULE == type ||
|
||||
css::Rule::SUPPORTS_RULE == type) {
|
||||
css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
|
||||
if (!groupRule->EnumerateRulesForwards(GatherDocRuleEnumFunc, aData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (css::Rule::DOCUMENT_RULE == type) {
|
||||
css::DocumentRule* docRule = static_cast<css::DocumentRule*>(aRule);
|
||||
if (!data->mDocumentRules.AppendElement(docRule)) {
|
||||
return false;
|
||||
}
|
||||
if (docRule->UseForPresentation(data->mPresContext)) {
|
||||
if (!data->mDocumentCacheKey.AddMatchingRule(docRule)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!docRule->EnumerateRulesForwards(GatherDocRuleEnumFunc, aData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* This enumerates style rules in a sheet (and recursively into any
|
||||
* grouping rules) in order to:
|
||||
@ -3350,6 +3417,21 @@ struct CascadeEnumData {
|
||||
* into data->mFontFeatureValuesRules.
|
||||
* (5) add any @page rules, in order, into data->mPageRules.
|
||||
* (6) add any @counter-style rules, in order, into data->mCounterStyleRules.
|
||||
* (7) add any @-moz-document rules into data->mDocumentRules.
|
||||
* (8) record any @-moz-document rules whose conditions evaluate to true
|
||||
* on data->mDocumentCacheKey.
|
||||
*
|
||||
* See also GatherDocRuleEnumFunc above, which we call to traverse into
|
||||
* @-moz-document rules even if their (or an ancestor's) condition
|
||||
* fails. This means we might look at the result of some @-moz-document
|
||||
* rules that don't actually affect whether a RuleProcessorCache lookup
|
||||
* is a hit or a miss. The presence of @-moz-document rules inside
|
||||
* @media etc. rules should be rare, and looking at all of them in the
|
||||
* sheets lets us avoid the complication of having different document
|
||||
* cache key results for different media.
|
||||
*
|
||||
* If modifying this function you may need to update
|
||||
* GatherDocRuleEnumFunc too.
|
||||
*/
|
||||
static bool
|
||||
CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
|
||||
@ -3380,12 +3462,38 @@ CascadeRuleEnumFunc(css::Rule* aRule, void* aData)
|
||||
}
|
||||
}
|
||||
else if (css::Rule::MEDIA_RULE == type ||
|
||||
css::Rule::DOCUMENT_RULE == type ||
|
||||
css::Rule::SUPPORTS_RULE == type) {
|
||||
css::GroupRule* groupRule = static_cast<css::GroupRule*>(aRule);
|
||||
if (groupRule->UseForPresentation(data->mPresContext, data->mCacheKey))
|
||||
if (!groupRule->EnumerateRulesForwards(CascadeRuleEnumFunc, aData))
|
||||
const bool use =
|
||||
groupRule->UseForPresentation(data->mPresContext, data->mCacheKey);
|
||||
if (use || data->mMustGatherDocumentRules) {
|
||||
if (!groupRule->EnumerateRulesForwards(use ? CascadeRuleEnumFunc :
|
||||
GatherDocRuleEnumFunc,
|
||||
aData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (css::Rule::DOCUMENT_RULE == type) {
|
||||
css::DocumentRule* docRule = static_cast<css::DocumentRule*>(aRule);
|
||||
if (data->mMustGatherDocumentRules) {
|
||||
if (!data->mDocumentRules.AppendElement(docRule)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
const bool use = docRule->UseForPresentation(data->mPresContext);
|
||||
if (use && data->mMustGatherDocumentRules) {
|
||||
if (!data->mDocumentCacheKey.AddMatchingRule(docRule)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (use || data->mMustGatherDocumentRules) {
|
||||
if (!docRule->EnumerateRulesForwards(use ? CascadeRuleEnumFunc
|
||||
: GatherDocRuleEnumFunc,
|
||||
aData)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (css::Rule::FONT_FACE_RULE == type) {
|
||||
nsCSSFontFaceRule *fontFaceRule = static_cast<nsCSSFontFaceRule*>(aRule);
|
||||
@ -3508,8 +3616,12 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
|
||||
newCascade->mFontFeatureValuesRules,
|
||||
newCascade->mPageRules,
|
||||
newCascade->mCounterStyleRules,
|
||||
mDocumentRules,
|
||||
newCascade->mCacheKey,
|
||||
mSheetType);
|
||||
mDocumentCacheKey,
|
||||
mSheetType,
|
||||
mMustGatherDocumentRules);
|
||||
|
||||
for (uint32_t i = 0; i < mSheets.Length(); ++i) {
|
||||
if (!CascadeSheet(mSheets.ElementAt(i), &data))
|
||||
return; /* out of memory */
|
||||
@ -3553,6 +3665,40 @@ nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
|
||||
newCascade->mCounterStyleRuleTable.Put(rule->GetName(), rule);
|
||||
}
|
||||
|
||||
// mMustGatherDocumentRules controls whether we build mDocumentRules
|
||||
// and mDocumentCacheKey so that they can be used as keys by the
|
||||
// RuleProcessorCache, as obtained by TakeDocumentRulesAndCacheKey
|
||||
// later. We set it to false just below so that we only do this
|
||||
// the first time we build a RuleProcessorCache for a shared rule
|
||||
// processor.
|
||||
//
|
||||
// An up-to-date mDocumentCacheKey is only needed if we
|
||||
// are still in the RuleProcessorCache (as we store a copy of the
|
||||
// cache key in the RuleProcessorCache), and an up-to-date
|
||||
// mDocumentRules is only needed at the time TakeDocumentRulesAndCacheKey
|
||||
// is called, which is immediately after the rule processor is created
|
||||
// (by nsStyleSet).
|
||||
//
|
||||
// Note that when nsCSSRuleProcessor::ClearRuleCascades is called,
|
||||
// by CSSStyleSheet::ClearRuleCascades, we will have called
|
||||
// RuleProcessorCache::RemoveSheet, which will remove the rule
|
||||
// processor from the cache. (This is because the list of document
|
||||
// rules now may not match the one used as they key in the
|
||||
// RuleProcessorCache.)
|
||||
//
|
||||
// Thus, as we'll no longer be in the RuleProcessorCache, and we won't
|
||||
// have TakeDocumentRulesAndCacheKey called on us, we don't need to ensure
|
||||
// mDocumentCacheKey and mDocumentRules are up-to-date after the
|
||||
// first time GetRuleCascade is called.
|
||||
if (mMustGatherDocumentRules) {
|
||||
mDocumentRules.Sort();
|
||||
mDocumentCacheKey.Finalize();
|
||||
mMustGatherDocumentRules = false;
|
||||
#ifdef DEBUG
|
||||
mDocumentRulesAndCacheKeyValid = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
// Ensure that the current one is always mRuleCascades.
|
||||
newCascade->mNext = mRuleCascades;
|
||||
mRuleCascades = newCascade.forget();
|
||||
@ -3590,6 +3736,26 @@ nsCSSRuleProcessor::SelectorListMatches(Element* aElement,
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
nsCSSRuleProcessor::TakeDocumentRulesAndCacheKey(
|
||||
nsPresContext* aPresContext,
|
||||
nsTArray<css::DocumentRule*>& aDocumentRules,
|
||||
nsDocumentRuleResultCacheKey& aCacheKey)
|
||||
{
|
||||
MOZ_ASSERT(mIsShared);
|
||||
|
||||
GetRuleCascade(aPresContext);
|
||||
MOZ_ASSERT(mDocumentRulesAndCacheKeyValid);
|
||||
|
||||
aDocumentRules.Clear();
|
||||
aDocumentRules.SwapElements(mDocumentRules);
|
||||
aCacheKey.Swap(mDocumentCacheKey);
|
||||
|
||||
#ifdef DEBUG
|
||||
mDocumentRulesAndCacheKeyValid = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
// TreeMatchContext and AncestorFilter out of line methods
|
||||
void
|
||||
TreeMatchContext::InitAncestors(Element *aElement)
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "mozilla/EventStates.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
#include "nsIStyleRuleProcessor.h"
|
||||
#include "nsIMediaList.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsExpirationTracker.h"
|
||||
@ -36,6 +37,9 @@ class nsCSSCounterStyleRule;
|
||||
|
||||
namespace mozilla {
|
||||
class CSSStyleSheet;
|
||||
namespace css {
|
||||
class DocumentRule;
|
||||
} // namespace css
|
||||
} // namespace mozilla
|
||||
|
||||
/**
|
||||
@ -163,6 +167,11 @@ public:
|
||||
*/
|
||||
mozilla::dom::Element* GetScopeElement() const { return mScopeElement; }
|
||||
|
||||
void TakeDocumentRulesAndCacheKey(
|
||||
nsPresContext* aPresContext,
|
||||
nsTArray<mozilla::css::DocumentRule*>& aDocumentRules,
|
||||
nsDocumentRuleResultCacheKey& aDocumentRuleResultCacheKey);
|
||||
|
||||
bool IsShared() const { return mIsShared; }
|
||||
|
||||
nsExpirationState* GetExpirationState() { return &mExpirationState; }
|
||||
@ -226,14 +235,28 @@ private:
|
||||
// Only used if mSheetType == nsStyleSet::eScopedDocSheet.
|
||||
nsRefPtr<mozilla::dom::Element> mScopeElement;
|
||||
|
||||
nsTArray<mozilla::css::DocumentRule*> mDocumentRules;
|
||||
nsDocumentRuleResultCacheKey mDocumentCacheKey;
|
||||
|
||||
nsExpirationState mExpirationState;
|
||||
|
||||
// type of stylesheet using this processor
|
||||
uint8_t mSheetType; // == nsStyleSet::sheetType
|
||||
|
||||
const bool mIsShared;
|
||||
|
||||
// Whether we need to build up mDocumentCacheKey and mDocumentRules as
|
||||
// we build a RuleCascadeData. Is true only for shared rule processors
|
||||
// and only before we build the first RuleCascadeData. See comment in
|
||||
// RefreshRuleCascade for why.
|
||||
bool mMustGatherDocumentRules;
|
||||
|
||||
bool mInRuleProcessorCache;
|
||||
|
||||
#ifdef DEBUG
|
||||
bool mDocumentRulesAndCacheKeyValid;
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
static uint8_t sWinThemeId;
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user