Implement media queries, part 3: infrastructure for dynamic change handling at the rule processor and style set level. (Bug 156716) r+sr=bzbarsky

This commit is contained in:
L. David Baron 2008-07-26 09:14:48 -07:00
parent e513131988
commit b2fc2a6576
8 changed files with 111 additions and 14 deletions

View File

@ -731,8 +731,9 @@ RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
//
nsCSSRuleProcessor::nsCSSRuleProcessor(const nsCOMArray<nsICSSStyleSheet>& aSheets)
: mSheets(aSheets),
mRuleCascades(nsnull)
: mSheets(aSheets)
, mRuleCascades(nsnull)
, mLastPresContext(nsnull)
{
for (PRInt32 i = mSheets.Count() - 1; i >= 0; --i)
mSheets[i]->AddRuleProcessor(this);
@ -2085,6 +2086,16 @@ nsCSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData
return NS_OK;
}
NS_IMETHODIMP
nsCSSRuleProcessor::MediumFeaturesChanged(nsPresContext* aPresContext,
PRBool* aRulesChanged)
{
RuleCascadeData *old = mRuleCascades;
RefreshRuleCascade(aPresContext);
*aRulesChanged = (old != mRuleCascades);
return NS_OK;
}
nsresult
nsCSSRuleProcessor::ClearRuleCascades()
{
@ -2346,6 +2357,24 @@ FillWeightArray(PLDHashTable *table, PLDHashEntryHdr *hdr,
RuleCascadeData*
nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
{
// If anything changes about the presentation context, we will be
// notified. Otherwise, our cache is valid if mLastPresContext
// matches aPresContext. (The only rule processors used for multiple
// pres contexts are for XBL. These rule processors are probably less
// likely to have @media rules, and thus the cache is pretty likely to
// hit instantly even when we're switching between pres contexts.)
if (!mRuleCascades || aPresContext != mLastPresContext) {
RefreshRuleCascade(aPresContext);
}
mLastPresContext = aPresContext;
return mRuleCascades;
}
void
nsCSSRuleProcessor::RefreshRuleCascade(nsPresContext* aPresContext)
{
// Having RuleCascadeData objects be per-medium (over all variation
// caused by media queries, handled through mCacheKey) works for now
@ -2353,12 +2382,16 @@ nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
// set of stylesheets they can vary based on medium (@media) or
// document (@-moz-document).)
RuleCascadeData **cascadep = &mRuleCascades;
RuleCascadeData *cascade;
while ((cascade = *cascadep)) {
if (cascade->mCacheKey.Matches(aPresContext))
return cascade;
cascadep = &cascade->mNext;
for (RuleCascadeData **cascadep = &mRuleCascades, *cascade;
(cascade = *cascadep); cascadep = &cascade->mNext) {
if (cascade->mCacheKey.Matches(aPresContext)) {
// Ensure that the current one is always mRuleCascades.
*cascadep = cascade->mNext;
cascade->mNext = mRuleCascades;
mRuleCascades = cascade;
return;
}
}
if (mSheets.Count() != 0) {
@ -2369,9 +2402,9 @@ nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
CascadeEnumData data(aPresContext, newCascade->mCacheKey,
newCascade->mRuleHash.Arena());
if (!data.mRulesByWeight.ops)
return nsnull;
return; /* out of memory */
if (!mSheets.EnumerateForwards(CascadeSheetRulesInto, &data))
return nsnull;
return; /* out of memory */
// Sort the hash table of per-weight linked lists by weight.
PRUint32 weightCount = data.mRulesByWeight.entryCount;
@ -2393,16 +2426,17 @@ nsCSSRuleProcessor::GetRuleCascade(nsPresContext* aPresContext)
// Calling |AddRule| reuses mNext!
RuleValue *next = ruleValue->mNext;
if (!AddRule(ruleValue, newCascade))
return nsnull;
return; /* out of memory */
ruleValue = next;
} while (ruleValue);
}
*cascadep = newCascade;
cascade = newCascade.forget();
// Ensure that the current one is always mRuleCascades.
newCascade->mNext = mRuleCascades;
mRuleCascades = newCascade.forget();
}
}
return cascade;
return;
}
/* static */ PRBool

View File

@ -93,13 +93,21 @@ public:
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsReStyleHint* aResult);
NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
PRBool* aRulesChanged);
protected:
RuleCascadeData* GetRuleCascade(nsPresContext* aPresContext);
void RefreshRuleCascade(nsPresContext* aPresContext);
// The sheet order here is the same as in nsStyleSet::mSheets
nsCOMArray<nsICSSStyleSheet> mSheets;
// active first, then cached (most recent first)
RuleCascadeData* mRuleCascades;
// The last pres context for which GetRuleCascades was called.
nsPresContext *mLastPresContext;
};
#endif /* nsCSSRuleProcessor_h_ */

View File

@ -366,6 +366,8 @@ public:
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsReStyleHint* aResult);
NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
PRBool* aResult);
#ifdef DEBUG
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
@ -492,6 +494,13 @@ HTMLCSSStyleSheetImpl::HasAttributeDependentStyle(AttributeRuleProcessorData* aD
return NS_OK;
}
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::MediumFeaturesChanged(nsPresContext* aPresContext,
PRBool* aRulesChanged)
{
*aRulesChanged = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP

View File

@ -562,6 +562,14 @@ nsHTMLStyleSheet::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
return NS_OK;
}
NS_IMETHODIMP
nsHTMLStyleSheet::MediumFeaturesChanged(nsPresContext* aPresContext,
PRBool* aRulesChanged)
{
*aRulesChanged = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
nsHTMLStyleSheet::RulesMatching(PseudoRuleProcessorData* aData)

View File

@ -83,6 +83,8 @@ public:
nsReStyleHint* aResult);
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsReStyleHint* aResult);
NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
PRBool* aRulesChanged);
nsresult Init(nsIURI* aURL, nsIDocument* aDocument);
nsresult Reset(nsIURI* aURL);

View File

@ -273,6 +273,14 @@ public:
*/
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsReStyleHint* aResult) = 0;
/**
* Do any processing that needs to happen as a result of a change in
* the characteristics of the medium, and return whether this rule
* processor's rules have changed (e.g., because of media queries).
*/
NS_IMETHOD MediumFeaturesChanged(nsPresContext* aPresContext,
PRBool* aRulesChanged) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleRuleProcessor,

View File

@ -22,6 +22,7 @@
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
* Brian Ryner <bryner@brianryner.com>
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -962,3 +963,22 @@ nsStyleSet::HasAttributeDependentStyle(nsPresContext* aPresContext,
return result;
}
PRBool
nsStyleSet::MediumFeaturesChanged(nsPresContext* aPresContext)
{
// We can't use WalkRuleProcessors without a content node.
// XXX We don't notify mBindingManager. Should we?
PRBool stylesChanged = PR_FALSE;
for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mRuleProcessors); ++i) {
nsIStyleRuleProcessor *processor = mRuleProcessors[i];
if (!processor) {
continue;
}
PRBool thisChanged = PR_FALSE;
processor->MediumFeaturesChanged(aPresContext, &thisChanged);
stylesChanged = stylesChanged || thisChanged;
}
return stylesChanged;
}

View File

@ -22,6 +22,7 @@
* Contributor(s):
* Daniel Glazman <glazman@netscape.com>
* Brian Ryner <bryner@brianryner.com>
* L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
@ -143,6 +144,13 @@ class nsStyleSet
PRInt32 aModType,
PRUint32 aStateMask);
/*
* Do any processing that needs to happen as a result of a change in
* the characteristics of the medium, and return whether style rules
* may have changed as a result.
*/
PRBool MediumFeaturesChanged(nsPresContext* aPresContext);
// APIs for registering objects that can supply additional
// rules during processing.
void SetBindingManager(nsBindingManager* aBindingManager)