Replace nsIStyleSheet::AttributeAffectsStyle with nsIStyleRuleProcessor::HasAttributeDependentStyle. Strengthen the attribute optimization and apply it to HTML as well. b=163556 r+sr=bzbarsky

This commit is contained in:
dbaron%dbaron.org 2003-02-22 16:10:53 +00:00
parent ea93b55cc8
commit 4b4f8625f1
26 changed files with 657 additions and 803 deletions

View File

@ -145,6 +145,21 @@ struct StateRuleProcessorData : public RuleProcessorData {
// Constants defined in nsIEventStateManager.h .
};
struct AttributeRuleProcessorData : public RuleProcessorData {
AttributeRuleProcessorData(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIAtom* aAttribute,
PRInt32 aModType)
: RuleProcessorData(aPresContext, aContent, nsnull),
mAttribute(aAttribute),
mModType(aModType)
{
NS_PRECONDITION(aContent, "null pointer");
}
nsIAtom* mAttribute; // |HasAttributeDependentStyle| for which attribute?
PRInt32 mModType; // The type of modification (see nsIDOMMutationEvent).
};
// IID for the nsIStyleRuleProcessor interface {015575fe-7b6c-11d3-ba05-001083023c2b}
#define NS_ISTYLE_RULE_PROCESSOR_IID \
@ -172,6 +187,10 @@ public:
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult) = 0;
// Test if style is dependent on attribute
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult) = 0;
};
#endif /* nsIStyleRuleProcessor_h___ */

View File

@ -20,11 +20,6 @@ class nsIStyleRuleSupplier : public nsISupports {
NS_IMETHOD WalkRules(nsIStyleSet* aStyleSet,
nsISupportsArrayEnumFunc aFunc,
RuleProcessorData* aData)=0;
NS_IMETHOD AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc,
void* aData,
nsIContent* aContent,
PRBool* aAffects)=0;
};
#endif /* _nsIStyleRuleSupplier_h */

View File

@ -97,17 +97,9 @@ public:
NS_IMETHOD GetStyleRuleProcessor(nsIStyleRuleProcessor*& aProcessor,
nsIStyleRuleProcessor* aPrevProcessor) = 0;
// XXX style rule enumerations
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
#ifdef DEBUG
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0;
#endif
};
#endif /* nsIStyleSheet_h___ */

View File

@ -56,6 +56,10 @@ class nsIStyledContent : public nsIContent {
public:
NS_DEFINE_STATIC_IID_ACCESSOR(NS_ISTYLEDCONTENT_IID)
// XXX Currently callers (e.g., CSSStyleSheetImpl) assume that the ID
// corresponds to the attribute nsHTMLAtoms::id and that the Class
// corresponds to the attribute nsHTMLAtoms::kClass. If this becomes
// incorrect, then new methods need to be added here.
NS_IMETHOD GetID(nsIAtom*& aResult) const = 0;
NS_IMETHOD GetClasses(nsVoidArray& aArray) const = 0;
NS_IMETHOD_(PRBool) HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const = 0;

View File

@ -208,6 +208,12 @@ public:
PRInt32 aStateMask,
PRBool* aResult);
NS_IMETHOD HasAttributeDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIAtom* aAtribute,
PRInt32 aModType,
PRBool* aResult);
NS_IMETHOD ConstructRootFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame*& aFrameSubTree);
@ -296,9 +302,6 @@ public:
NS_DECL_NSITIMERECORDER
#endif
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
static nsrefcnt gInstances;
static nsIURI *gQuirkURI;
@ -1501,20 +1504,20 @@ struct StatefulData : public StateRuleProcessorData {
nsIContent* aContent, PRInt32 aStateMask)
: StateRuleProcessorData(aPresContext, aContent, aStateMask),
mMedium(aMedium),
mStateful(PR_FALSE)
mHasStyle(PR_FALSE)
{}
nsIAtom* mMedium;
PRBool mStateful;
PRBool mHasStyle;
};
static PRBool SheetHasStatefulStyle(nsISupports* aProcessor, void *aData)
{
nsIStyleRuleProcessor* processor = (nsIStyleRuleProcessor*)aProcessor;
StatefulData* data = (StatefulData*)aData;
PRBool hasStateful;
processor->HasStateDependentStyle(data, data->mMedium, &hasStateful);
if (hasStateful) {
data->mStateful = PR_TRUE;
PRBool hasStyle;
processor->HasStateDependentStyle(data, data->mMedium, &hasStyle);
if (hasStyle) {
data->mHasStyle = PR_TRUE;
// Stop iteration. Note that StyleSetImpl::WalkRuleProcessors uses
// this to stop its own iteration in some cases, but not all (the
// style rule supplier case). Since this optimization is only for
@ -1539,12 +1542,67 @@ StyleSetImpl::HasStateDependentStyle(nsIPresContext* aPresContext,
mUserRuleProcessors ||
mDocRuleProcessors ||
mOverrideRuleProcessors)) {
nsIAtom* medium = nsnull;
aPresContext->GetMedium(&medium);
nsCOMPtr<nsIAtom> medium;
aPresContext->GetMedium(getter_AddRefs(medium));
StatefulData data(aPresContext, medium, aContent, aStateMask);
WalkRuleProcessors(SheetHasStatefulStyle, &data);
NS_IF_RELEASE(medium);
*aResult = data.mStateful;
*aResult = data.mHasStyle;
} else {
*aResult = PR_FALSE;
}
return NS_OK;
}
struct AttributeData : public AttributeRuleProcessorData {
AttributeData(nsIPresContext* aPresContext, nsIAtom* aMedium,
nsIContent* aContent, nsIAtom* aAttribute, PRInt32 aModType)
: AttributeRuleProcessorData(aPresContext, aContent, aAttribute, aModType),
mMedium(aMedium),
mHasStyle(PR_FALSE)
{}
nsIAtom* mMedium;
PRBool mHasStyle;
};
static PRBool SheetHasAttributeStyle(nsISupports* aProcessor, void *aData)
{
nsIStyleRuleProcessor* processor = (nsIStyleRuleProcessor*)aProcessor;
AttributeData* data = (AttributeData*)aData;
PRBool hasStyle;
processor->HasAttributeDependentStyle(data, data->mMedium, &hasStyle);
if (hasStyle) {
data->mHasStyle = PR_TRUE;
// Stop iteration. Note that StyleSetImpl::WalkRuleProcessors uses
// this to stop its own iteration in some cases, but not all (the
// style rule supplier case). Since this optimization is only for
// the case where we have a lot more work to do, it's not worth the
// code needed to make the stopping perfect.
return PR_FALSE;
}
return PR_TRUE; // continue
}
// Test if style is dependent on content state
NS_IMETHODIMP
StyleSetImpl::HasAttributeDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIAtom* aAttribute,
PRInt32 aModType,
PRBool* aResult)
{
GatherRuleProcessors();
if (aContent->IsContentOfType(nsIContent::eELEMENT) &&
(mAgentRuleProcessors ||
mUserRuleProcessors ||
mDocRuleProcessors ||
mOverrideRuleProcessors)) {
nsCOMPtr<nsIAtom> medium;
aPresContext->GetMedium(getter_AddRefs(medium));
AttributeData data(aPresContext, medium, aContent, aAttribute, aModType);
WalkRuleProcessors(SheetHasAttributeStyle, &data);
*aResult = data.mHasStyle;
} else {
*aResult = PR_FALSE;
}
@ -1912,53 +1970,3 @@ void StyleSetImpl::ResetUniqueStyleItems(void)
UNIQUE_STYLE_ITEMS(uniqueItems);
uniqueItems->Clear();
}
struct AttributeContentPair {
nsIAtom *attribute;
nsIContent *content;
};
static PRBool
EnumAffectsStyle(nsISupports *aElement, void *aData)
{
nsIStyleSheet *sheet = NS_STATIC_CAST(nsIStyleSheet *, aElement);
AttributeContentPair *pair = (AttributeContentPair *)aData;
PRBool affects;
nsresult res =
sheet->AttributeAffectsStyle(pair->attribute, pair->content, affects);
if (NS_FAILED(res) || affects)
return PR_FALSE; // stop checking
return PR_TRUE;
}
NS_IMETHODIMP
StyleSetImpl::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
{
AttributeContentPair pair;
pair.attribute = aAttribute;
pair.content = aContent;
/* scoped sheets should be checked first, since - if present - they will contain
the bulk of the applicable rules for the content node. */
if (mStyleRuleSupplier)
mStyleRuleSupplier->AttributeAffectsStyle(EnumAffectsStyle, &pair, aContent, &aAffects);
if (!aAffects) {
/* check until we find a sheet that will be affected */
if ((mDocSheets && !mDocSheets->EnumerateForwards(EnumAffectsStyle, &pair)) ||
(mOverrideSheets && !mOverrideSheets->EnumerateForwards(EnumAffectsStyle,
&pair)) ||
(mUserSheets && !mUserSheets->EnumerateForwards(EnumAffectsStyle,
&pair)) ||
(mAgentSheets && !mAgentSheets->EnumerateForwards(EnumAffectsStyle,
&pair))) {
aAffects = PR_TRUE;
} else {
aAffects = PR_FALSE;
}
}
return NS_OK;
}

View File

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim:cindent:tabstop=2:expandtab:shiftwidth=2:
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@ -107,87 +108,6 @@
#include "nsIJSContextStack.h"
#include "nsIScriptSecurityManager.h"
// An |AtomKey| is to be used for storage in the hashtable, and a
// |DependentAtomKey| should be used on the stack to avoid the performance
// cost of refcounting an atom that one is assured to own for the lifetime
// of the key.
class AtomKey_base : public nsHashKey {
public:
virtual PRUint32 HashCode(void) const;
virtual PRBool Equals(const nsHashKey *aKey) const;
nsIAtom* mAtom;
};
class AtomKey : public AtomKey_base {
public:
AtomKey(nsIAtom* aAtom);
AtomKey(const AtomKey_base& aKey);
virtual ~AtomKey();
virtual nsHashKey *Clone(void) const;
};
class DependentAtomKey : public AtomKey_base {
public:
DependentAtomKey(nsIAtom* aAtom)
{
mAtom = aAtom;
}
DependentAtomKey(const DependentAtomKey& aKey);
virtual ~DependentAtomKey(void);
virtual nsHashKey *Clone(void) const;
};
PRUint32 AtomKey_base::HashCode(void) const
{
return NS_PTR_TO_INT32(mAtom);
}
PRBool AtomKey_base::Equals(const nsHashKey* aKey) const
{
return NS_STATIC_CAST(const AtomKey_base*, aKey)->mAtom == mAtom;
}
AtomKey::AtomKey(nsIAtom* aAtom)
{
mAtom = aAtom;
NS_ADDREF(mAtom);
}
AtomKey::AtomKey(const AtomKey_base& aKey)
{
mAtom = aKey.mAtom;
NS_ADDREF(mAtom);
}
AtomKey::~AtomKey()
{
NS_RELEASE(mAtom);
}
nsHashKey* AtomKey::Clone(void) const
{
return new AtomKey(*this);
}
DependentAtomKey::DependentAtomKey(const DependentAtomKey& aKey)
{
NS_NOTREACHED("Should never clone to a dependent atom key.");
mAtom = aKey.mAtom;
}
DependentAtomKey::~DependentAtomKey()
{
}
nsHashKey* DependentAtomKey::Clone(void) const
{
return new AtomKey(*this); // return a non-dependent key
}
struct RuleValue {
RuleValue(nsICSSStyleRule* aRule, PRInt32 aIndex, RuleValue *aNext)
: mRule(aRule), mIndex(aIndex), mNext(aNext) {}
@ -708,6 +628,35 @@ void RuleHash::EnumerateTagRules(nsIAtom* aTag, RuleEnumFunc aFunc, void* aData)
}
}
//--------------------------------
// Attribute selectors hash table.
struct AttributeSelectorEntry : public PLDHashEntryHdr {
nsIAtom *mAttribute;
nsVoidArray *mSelectors;
};
PR_STATIC_CALLBACK(void)
AttributeSelectorClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
{
AttributeSelectorEntry *entry = NS_STATIC_CAST(AttributeSelectorEntry*, hdr);
delete entry->mSelectors;
memset(entry, 0, table->entrySize);
}
static PLDHashTableOps AttributeSelectorOps = {
PL_DHashAllocTable,
PL_DHashFreeTable,
PL_DHashGetKeyStub,
PL_DHashVoidPtrKeyStub,
PL_DHashMatchEntryStub,
PL_DHashMoveEntryStub,
AttributeSelectorClearEntry,
PL_DHashFinalizeStub,
NULL
};
//--------------------------------
struct RuleCascadeData {
@ -719,20 +668,45 @@ struct RuleCascadeData {
mNext(nsnull)
{
NS_NewISupportsArray(&mWeightedRules);
PL_DHashTableInit(&mAttributeSelectors, &AttributeSelectorOps, nsnull,
sizeof(AttributeSelectorEntry), 16);
}
~RuleCascadeData(void)
{
NS_IF_RELEASE(mWeightedRules);
PL_DHashTableFinish(&mAttributeSelectors);
}
nsISupportsArray* mWeightedRules;
RuleHash mRuleHash;
nsVoidArray mStateSelectors;
PLDHashTable mAttributeSelectors; // nsIAtom* -> nsVoidArray*
// Looks up or creates the appropriate list in |mAttributeSelectors|.
// Returns null only on allocation failure.
nsVoidArray* AttributeListFor(nsIAtom* aAttribute);
nsCOMPtr<nsIAtom> mMedium;
RuleCascadeData* mNext; // for a different medium
};
nsVoidArray*
RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
{
AttributeSelectorEntry *entry = NS_STATIC_CAST(AttributeSelectorEntry*,
PL_DHashTableOperate(&mAttributeSelectors, aAttribute, PL_DHASH_ADD));
if (!entry)
return nsnull;
if (!entry->mSelectors) {
if (!(entry->mSelectors = new nsVoidArray)) {
PL_DHashTableRawRemove(&mAttributeSelectors, entry);
return nsnull;
}
entry->mAttribute = aAttribute;
}
return entry->mSelectors;
}
// -------------------------------
// CSS Style Rule processor
//
@ -761,6 +735,10 @@ public:
nsIAtom* aMedium,
PRBool* aResult);
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult);
protected:
RuleCascadeData* GetRuleCascade(nsIPresContext* aPresContext, nsIAtom* aMedium);
@ -795,7 +773,6 @@ public:
nsCOMPtr<nsINameSpace> mNameSpace;
PRInt32 mDefaultNameSpaceID;
nsHashtable mRelevantAttributes;
PRPackedBool mComplete;
};
@ -855,15 +832,6 @@ public:
NS_IMETHOD AppendStyleSheet(nsICSSStyleSheet* aSheet);
NS_IMETHOD InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
// Find attributes in selector for rule, for use with AttributeAffectsStyle
NS_IMETHOD CheckRuleForAttributes(nsICSSRule* aRule);
// XXX do these belong here or are they generic?
NS_IMETHOD PrependStyleRule(nsICSSRule* aRule);
NS_IMETHOD AppendStyleRule(nsICSSRule* aRule);
@ -1473,7 +1441,6 @@ CSSStyleSheetInner::CSSStyleSheetInner(nsICSSStyleSheet* aParentSheet)
mOrderedRules(nsnull),
mNameSpace(nsnull),
mDefaultNameSpaceID(kNameSpaceID_None),
mRelevantAttributes(),
mComplete(PR_FALSE)
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
@ -1494,24 +1461,12 @@ CloneRuleInto(nsISupports* aRule, void* aArray)
return PR_TRUE;
}
static PRBool PR_CALLBACK
CopyRelevantAttributes(nsHashKey *aAttrKey, void *aAtom, void *aTable)
{
nsHashtable *table = NS_STATIC_CAST(nsHashtable *, aTable);
AtomKey *key = NS_STATIC_CAST(AtomKey *, aAttrKey);
table->Put(key, key->mAtom);
// we don't need to addref the atom here, because we're also copying the
// rules when we clone, and that will add a ref for us
return PR_TRUE;
}
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
nsICSSStyleSheet* aParentSheet)
: mSheets(),
mURL(aCopy.mURL),
mNameSpace(nsnull),
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID),
mRelevantAttributes(),
mComplete(aCopy.mComplete)
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
@ -1527,8 +1482,6 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
else {
mOrderedRules = nsnull;
}
aCopy.mRelevantAttributes.Enumerate(CopyRelevantAttributes,
&mRelevantAttributes);
RebuildNameSpaces();
}
@ -2104,21 +2057,6 @@ CSSStyleSheetImpl::InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex)
return result;
}
NS_IMETHODIMP
CSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
DependentAtomKey key(aAttribute);
aAffects = !!mInner->mRelevantAttributes.Get(&key);
for (CSSStyleSheetImpl *child = mFirstChild;
child && !aAffects;
child = child->mNext) {
child->AttributeAffectsStyle(aAttribute, aContent, aAffects);
}
return NS_OK;
}
NS_IMETHODIMP
CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
{
@ -2138,8 +2076,6 @@ CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
if (nsICSSRule::NAMESPACE_RULE == type) {
// no api to prepend a namespace (ugh), release old ones and re-create them all
mInner->RebuildNameSpaces();
} else {
CheckRuleForAttributes(aRule);
}
}
}
@ -2181,8 +2117,6 @@ CSSStyleSheetImpl::AppendStyleRule(nsICSSRule* aRule)
mInner->mNameSpace = newNameSpace;
}
}
} else {
CheckRuleForAttributes(aRule);
}
}
@ -2190,68 +2124,6 @@ CSSStyleSheetImpl::AppendStyleRule(nsICSSRule* aRule)
return NS_OK;
}
static PRBool
CheckRuleForAttributesEnum(nsISupports *aRule, void *aData)
{
nsICSSRule *rule = NS_STATIC_CAST(nsICSSRule *, aRule);
CSSStyleSheetImpl *sheet = NS_STATIC_CAST(CSSStyleSheetImpl *, aData);
return NS_SUCCEEDED(sheet->CheckRuleForAttributes(rule));
}
NS_IMETHODIMP
CSSStyleSheetImpl::CheckRuleForAttributes(nsICSSRule *aRule)
{
PRInt32 ruleType = nsICSSRule::UNKNOWN_RULE;
aRule->GetType(ruleType);
switch (ruleType) {
case nsICSSRule::MEDIA_RULE: {
nsICSSMediaRule *mediaRule = (nsICSSMediaRule *)aRule;
return mediaRule->EnumerateRulesForwards(CheckRuleForAttributesEnum,
(void *)this);
}
case nsICSSRule::STYLE_RULE: {
nsICSSStyleRule *styleRule = NS_STATIC_CAST(nsICSSStyleRule *, aRule);
nsCSSSelector *iter;
for (iter = styleRule->FirstSelector(); iter; iter = iter->mNext) {
/* P.classname means we have to check the attribute "class" */
if (iter->mIDList) {
DependentAtomKey idKey(nsHTMLAtoms::id);
mInner->mRelevantAttributes.Put(&idKey, nsHTMLAtoms::id);
}
if (iter->mClassList) {
DependentAtomKey classKey(nsHTMLAtoms::kClass);
mInner->mRelevantAttributes.Put(&classKey, nsHTMLAtoms::kClass);
}
for (nsAttrSelector *sel = iter->mAttrList; sel; sel = sel->mNext) {
/* store it in this sheet's attributes-that-matter table */
/* XXX store tag name too, but handle collisions */
#ifdef DEBUG_shaver_off
nsAutoString str;
sel->mAttr->ToString(str);
char * chars = ToNewCString(str);
fprintf(stderr, "[%s@%p]", chars, this);
nsMemory::Free(chars);
#endif
DependentAtomKey key(sel->mAttr);
mInner->mRelevantAttributes.Put(&key, sel->mAttr);
}
// Search for the :lang() pseudo class. If it is there add
// the lang attribute to the relevant attribute list.
for (nsAtomStringList* p = iter->mPseudoClassList; p; p = p->mNext) {
if (p->mAtom == nsCSSPseudoClasses::lang) {
DependentAtomKey langKey(nsHTMLAtoms::lang);
mInner->mRelevantAttributes.Put(&langKey, nsHTMLAtoms::lang);
break;
}
}
}
} /* fall-through */
default:
return NS_OK;
}
}
NS_IMETHODIMP
CSSStyleSheetImpl::StyleRuleCount(PRInt32& aCount) const
{
@ -2843,9 +2715,6 @@ CSSStyleSheetImpl::InsertRule(const nsAString& aRule,
mInner->mNameSpace = newNameSpace;
}
}
else {
CheckRuleForAttributes(cssRule);
}
// We don't notify immediately for @import rules, but rather when
// the sheet the rule is importing is loaded
@ -3048,7 +2917,6 @@ CSSStyleSheetImpl::InsertRuleIntoGroup(const nsAString & aRule, nsICSSGroupRule*
DidDirty();
for (counter = 0; counter < rulecount; counter++) {
rule = dont_AddRef((nsICSSRule*)rules->ElementAt(counter));
CheckRuleForAttributes(rule);
if (mDocument) {
result = mDocument->StyleRuleAdded(this, rule);
@ -3516,6 +3384,7 @@ DashMatchCompare(const nsAString& aAttributeValue,
static PRBool SelectorMatches(RuleProcessorData &data,
nsCSSSelector* aSelector,
PRInt32 aStateMask, // states NOT to test
nsIAtom* aAttribute, // attribute NOT to test
PRInt8 aNegationIndex)
{
@ -3746,15 +3615,20 @@ static PRBool SelectorMatches(RuleProcessorData &data,
}
// namespace/tag match
if (result && aSelector->mAttrList) { // test for attribute match
// if no attributes on the content, no match
if(!data.mHasAttributes) {
if (result && aSelector->mAttrList) {
// test for attribute match
if (!data.mHasAttributes && !aAttribute) {
// if no attributes on the content, no match
result = localFalse;
} else {
result = localTrue;
nsAttrSelector* attr = aSelector->mAttrList;
do {
if (!data.mContent->HasAttr(attr->mNameSpace, attr->mAttr)) {
if (attr->mAttr == aAttribute) {
result = PR_TRUE;
}
else if (!data.mContent->HasAttr(attr->mNameSpace, attr->mAttr)) {
result = localFalse;
}
else if (attr->mFunction != NS_ATTR_FUNC_SET) {
@ -3826,7 +3700,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// case sensitivity: bug 93371
PRBool isCaseSensitive = data.mCompatMode != eCompatibility_NavQuirks;
nsAtomList* IDList = aSelector->mIDList;
if (nsnull == IDList) {
if (nsnull == IDList || aAttribute == nsHTMLAtoms::id) {
result = PR_TRUE;
}
else if (nsnull != data.mContentID) {
@ -3857,7 +3731,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
}
}
if (result) {
if (result && aAttribute != nsHTMLAtoms::kClass) {
nsAtomList* classList = aSelector->mClassList;
while (nsnull != classList) {
if (localTrue == (!data.mStyledContent->HasClass(classList->mAtom, isCaseSensitive))) {
@ -3873,7 +3747,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// apply SelectorMatches to the negated selectors in the chain
if (result && (nsnull != aSelector->mNegations)) {
result = SelectorMatches(data, aSelector->mNegations, aStateMask,
aNegationIndex+1);
aAttribute, aNegationIndex+1);
}
return result;
}
@ -3948,7 +3822,7 @@ static PRBool SelectorMatchesTree(RuleProcessorData &data,
NS_ASSERTION(!content, "content must be null");
break;
}
if (SelectorMatches(*newdata, selector, 0, 0)) {
if (SelectorMatches(*newdata, selector, 0, nsnull, 0)) {
// to avoid greedy matching, we need to recurse if this is a
// descendant combinator and the next combinator is not
if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
@ -3992,7 +3866,7 @@ static void ContentEnumFunc(nsICSSStyleRule* aRule, void* aData)
ElementRuleProcessorData* data = (ElementRuleProcessorData*)aData;
nsCSSSelector* selector = aRule->FirstSelector();
if (SelectorMatches(*data, selector, 0, 0)) {
if (SelectorMatches(*data, selector, 0, nsnull, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
// for performance, require that every implementation of
@ -4048,7 +3922,7 @@ static void PseudoEnumFunc(nsICSSStyleRule* aRule, void* aData)
if (PRUnichar('+') == selector->mOperator) {
return; // not valid here, can't match
}
if (SelectorMatches(*data, selector, 0, 0)) {
if (SelectorMatches(*data, selector, 0, nsnull, 0)) {
selector = selector->mNext;
}
else {
@ -4093,19 +3967,17 @@ CSSRuleProcessor::RulesMatching(PseudoRuleProcessorData* aData,
return NS_OK;
}
static
PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
{
StateRuleProcessorData* data = (StateRuleProcessorData*)aData;
nsCSSSelector* selector = (nsCSSSelector*)aSelector;
if (SelectorMatches(*data, selector, data->mStateMask, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
return PR_FALSE;
}
}
return PR_TRUE;
PR_STATIC_CALLBACK(PRBool) StateEnumFunc(void* aSelector, void* aData)
{
StateRuleProcessorData* data =
NS_STATIC_CAST(StateRuleProcessorData*, aData);
nsCSSSelector* selector = NS_STATIC_CAST(nsCSSSelector*, aSelector);
// Return whether we want to halt the enumeration, which is the
// negation of whether we find a match (ignoring the event state mask).
return !( SelectorMatches(*data, selector, data->mStateMask, nsnull, 0) &&
SelectorMatchesTree(*data, selector->mNext) );
}
NS_IMETHODIMP
@ -4135,6 +4007,46 @@ CSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData,
return NS_OK;
}
PR_STATIC_CALLBACK(PRBool) AttributeEnumFunc(void* aSelector, void* aData)
{
AttributeRuleProcessorData* data =
NS_STATIC_CAST(AttributeRuleProcessorData*, aData);
nsCSSSelector* selector = NS_STATIC_CAST(nsCSSSelector*, aSelector);
// Return whether we want to halt the enumeration, which is the
// negation of whether we find a match (ignoring the event state mask).
return !( SelectorMatches(*data, selector, 0, data->mAttribute, 0) &&
SelectorMatchesTree(*data, selector->mNext) );
}
NS_IMETHODIMP
CSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult)
{
NS_PRECONDITION(aData->mContent->IsContentOfType(nsIContent::eELEMENT),
"content must be element");
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext, aMedium);
// We do the same thing for attributes that we do for state selectors
// (see HasStateDependentStyle), except that instead of one big list
// we have a hashtable with a per-attribute list.
*aResult = PR_FALSE;
if (cascade) {
AttributeSelectorEntry *entry = NS_STATIC_CAST(AttributeSelectorEntry*,
PL_DHashTableOperate(&cascade->mAttributeSelectors, aData->mAttribute,
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
*aResult =
!entry->mSelectors->EnumerateForwards(AttributeEnumFunc, aData);
}
}
return NS_OK;
}
NS_IMETHODIMP
CSSRuleProcessor::ClearRuleCascades(void)
{
@ -4170,18 +4082,41 @@ PRBool IsStateSelector(nsCSSSelector& aSelector)
}
static PRBool
BuildRuleHashAndStateSelectors(nsISupports* aRule, void* aCascade)
AddRule(nsISupports* aRule, void* aCascade)
{
nsICSSStyleRule* rule = NS_STATIC_CAST(nsICSSStyleRule*, aRule);
RuleCascadeData *cascade = NS_STATIC_CAST(RuleCascadeData*, aCascade);
// Build the rule hash.
cascade->mRuleHash.PrependRule(rule);
nsVoidArray* array = &cascade->mStateSelectors;
nsVoidArray* stateArray = &cascade->mStateSelectors;
for (nsCSSSelector* selector = rule->FirstSelector();
selector; selector = selector->mNext)
selector; selector = selector->mNext) {
// Build mStateSelectors.
if (IsStateSelector(*selector))
stateArray->AppendElement(selector);
// Build mAttributeSelectors.
if (selector->mIDList) {
nsVoidArray *array = cascade->AttributeListFor(nsHTMLAtoms::id);
if (!array)
return PR_FALSE;
array->AppendElement(selector);
}
if (selector->mClassList) {
nsVoidArray *array = cascade->AttributeListFor(nsHTMLAtoms::kClass);
if (!array)
return PR_FALSE;
array->AppendElement(selector);
}
for (nsAttrSelector *attr = selector->mAttrList; attr; attr = attr->mNext) {
nsVoidArray *array = cascade->AttributeListFor(attr->mAttr);
if (!array)
return PR_FALSE;
array->AppendElement(selector);
}
}
return PR_TRUE;
}
@ -4328,14 +4263,16 @@ CSSRuleProcessor::GetRuleCascade(nsIPresContext* aPresContext, nsIAtom* aMedium)
cascade = new RuleCascadeData(aMedium,
eCompatibility_NavQuirks == quirkMode);
if (cascade) {
*cascadep = cascade;
CascadeEnumData data(aMedium);
mSheets->EnumerateForwards(CascadeSheetRulesInto, &data);
PutRulesInList(&data.mRuleArrays, cascade->mWeightedRules);
cascade->mWeightedRules->EnumerateBackwards(
BuildRuleHashAndStateSelectors, cascade);
if (!cascade->mWeightedRules->EnumerateBackwards(AddRule, cascade)) {
delete cascade;
cascade = nsnull;
}
*cascadep = cascade;
}
}
return cascade;

View File

@ -384,36 +384,9 @@ nsHTMLMappedAttributes::~nsHTMLMappedAttributes(void)
Reset();
}
NS_IMPL_ADDREF(nsHTMLMappedAttributes);
NS_IMPL_RELEASE(nsHTMLMappedAttributes);
nsresult
nsHTMLMappedAttributes::QueryInterface(const nsIID& aIID,
void** aInstancePtrResult)
{
NS_PRECONDITION(nsnull != aInstancePtrResult, "null pointer");
if (nsnull == aInstancePtrResult) {
return NS_ERROR_NULL_POINTER;
}
static NS_DEFINE_IID(kISupportsIID, NS_ISUPPORTS_IID);
if (aIID.Equals(NS_GET_IID(nsIHTMLMappedAttributes))) {
*aInstancePtrResult = (void*) ((nsIHTMLMappedAttributes*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(NS_GET_IID(nsIStyleRule))) {
*aInstancePtrResult = (void*) ((nsIStyleRule*)this);
NS_ADDREF_THIS();
return NS_OK;
}
if (aIID.Equals(kISupportsIID)) {
*aInstancePtrResult = (void*) ((nsIHTMLMappedAttributes*)this);
NS_ADDREF_THIS();
return NS_OK;
}
return NS_NOINTERFACE;
}
NS_IMPL_ISUPPORTS2(nsHTMLMappedAttributes,
nsIHTMLMappedAttributes,
nsIStyleRule)
NS_IMETHODIMP
nsHTMLMappedAttributes::Init(nsIHTMLStyleSheet* aSheet,

View File

@ -181,16 +181,14 @@ public:
nsIAtom* aMedium,
PRBool* aResult);
// XXX style rule enumerations
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult);
#ifdef DEBUG
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLCSSStyleSheetImpl(const HTMLCSSStyleSheetImpl& aCopy);
@ -321,6 +319,16 @@ HTMLCSSStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
return NS_OK;
}
// Test if style is dependent on attribute
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult)
{
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
@ -447,16 +455,6 @@ void HTMLCSSStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const
}
#endif
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX can attributes affect rules in these?
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For backwards compatibility and convenience
NS_EXPORT nsresult
NS_NewHTMLCSSStyleSheet(nsIHTMLCSSStyleSheet** aInstancePtrResult, nsIURI* aURL,

View File

@ -646,6 +646,10 @@ public:
nsIAtom* aMedium,
PRBool* aResult);
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult);
// nsIHTMLStyleSheet api
NS_IMETHOD Init(nsIURI* aURL, nsIDocument* aDocument);
NS_IMETHOD Reset(nsIURI* aURL);
@ -665,10 +669,6 @@ public:
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy);
@ -919,6 +919,43 @@ HTMLStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
return NS_OK;
}
NS_IMETHODIMP
HTMLStyleSheetImpl::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult)
{
// Result is true for |href| changes on HTML links if we have link rules.
nsIStyledContent *styledContent = aData->mStyledContent;
if (aData->mAttribute == nsHTMLAtoms::href &&
(mLinkRule || mVisitedRule || mActiveRule) &&
styledContent &&
styledContent->IsContentOfType(nsIContent::eHTML) &&
aData->mContentTag == nsHTMLAtoms::a) {
*aResult = PR_TRUE;
return NS_OK;
}
// Don't worry about the HTMLDocumentColorRule since it only applies
// to descendants of body, when we're already reresolving.
// Handle the content style rules.
if (styledContent) {
nsChangeHint hint = NS_STYLE_HINT_NONE;
styledContent->GetMappedAttributeImpact(aData->mAttribute,
aData->mModType, hint);
// This is the same test that nsGenericHTMLElement uses when calling
// nsHTMLAttributes::SetAttributeFor.
if ((hint & ~(nsChangeHint_AttrChange | nsChangeHint_Aural |
nsChangeHint_Content)) != 0) {
*aResult = PR_TRUE;
return NS_OK;
}
}
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
HTMLStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData,
@ -1223,17 +1260,6 @@ void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const
}
#endif
NS_IMETHODIMP
HTMLStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX we should be checking to see if this is an href on an <A> being
// XXX tweaked, in which case we really want to restyle
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For convenience and backwards compatibility
NS_EXPORT nsresult
NS_NewHTMLStyleSheet(nsIHTMLStyleSheet** aInstancePtrResult, nsIURI* aURL,

View File

@ -118,7 +118,6 @@ public:
NS_IMETHOD InheritsStyle(PRBool* aResult)=0;
NS_IMETHOD WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData)=0;
NS_IMETHOD AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc, void* aData, PRBool* aAffects)=0;
NS_IMETHOD MarkForDeath()=0;
NS_IMETHOD MarkedForDeath(PRBool* aResult)=0;

View File

@ -423,9 +423,6 @@ public:
NS_IMETHOD WalkRules(nsIStyleSet* aStyleSet,
nsISupportsArrayEnumFunc aFunc,
RuleProcessorData* aData);
NS_IMETHOD AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc,
void* aData, nsIContent* aContent,
PRBool* aAffects);
// nsIDocumentObserver
NS_DECL_NSIDOCUMENTOBSERVER
@ -437,9 +434,6 @@ protected:
void WalkRules(nsISupportsArrayEnumFunc aFunc, RuleProcessorData* aData,
nsIContent* aParent, nsIContent* aCurrContent);
void AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc, void* aData,
nsIContent* aParent, nsIContent* aCurrContent, PRBool* aAffects);
nsresult GetNestedInsertionPoint(nsIContent* aParent, nsIContent* aChild, nsIContent** aResult);
// MEMBER VARIABLES
@ -1387,47 +1381,6 @@ nsBindingManager::WalkRules(nsIStyleSet* aStyleSet,
return NS_OK;
}
void
nsBindingManager::AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc, void* aData,
nsIContent* aParent, nsIContent* aCurrContent, PRBool* aAffects)
{
nsCOMPtr<nsIXBLBinding> binding;
GetBinding(aCurrContent, getter_AddRefs(binding));
if (binding) {
binding->AttributeAffectsStyle(aFunc, aData, aAffects);
}
if (*aAffects)
return;
if (aParent != aCurrContent) {
nsCOMPtr<nsIContent> par;
GetEnclosingScope(aCurrContent, getter_AddRefs(par));
if (par)
AttributeAffectsStyle(aFunc, aData, aParent, par, aAffects);
}
}
NS_IMETHODIMP
nsBindingManager::AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc, void* aData,
nsIContent* aContent, PRBool* aAffects)
{
*aAffects = PR_FALSE;
if (!aContent)
return NS_OK;
nsCOMPtr<nsIContent> parent;
GetOutermostStyleScope(aContent, getter_AddRefs(parent));
AttributeAffectsStyle(aFunc, aData, parent, aContent, aAffects);
if (*aAffects)
return NS_OK;
return NS_OK;
}
NS_IMETHODIMP
nsBindingManager::ShouldBuildChildFrames(nsIContent* aContent, PRBool* aResult)
{

View File

@ -1207,31 +1207,6 @@ nsXBLBinding::WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData)
return rv;
}
NS_IMETHODIMP
nsXBLBinding::AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc, void* aData, PRBool* aAffects)
{
nsresult rv = NS_OK;
if (mNextBinding) {
rv = mNextBinding->AttributeAffectsStyle(aFunc, aData, aAffects);
if (NS_FAILED(rv))
return rv;
if (*aAffects)
return NS_OK;
}
nsCOMPtr<nsISupportsArray> sheets;
mPrototypeBinding->GetStyleSheets(getter_AddRefs(sheets));
if (sheets) {
if (!sheets->EnumerateForwards(aFunc, aData))
*aAffects = PR_TRUE;
else
*aAffects = PR_FALSE;
}
return rv;
}
// Internal helper methods ////////////////////////////////////////////////////////////////
// static

View File

@ -112,7 +112,6 @@ class nsXBLBinding: public nsIXBLBinding
NS_IMETHOD InheritsStyle(PRBool* aResult);
NS_IMETHOD WalkRules(nsISupportsArrayEnumFunc aFunc, void* aData);
NS_IMETHOD AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc, void* aData, PRBool* aAffects);
NS_IMETHOD MarkForDeath();
NS_IMETHOD MarkedForDeath(PRBool* aResult);

View File

@ -10731,7 +10731,8 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext,
shell->GetFrameManager(getter_AddRefs(frameManager));
PRBool affects;
frameManager->AttributeAffectsStyle(aAttribute, aContent, affects);
frameManager->HasAttributeDependentStyle(aPresContext, aContent,
aAttribute, aModType, &affects);
if (affects) {
#ifdef DEBUG_shaver
fputc('+', stderr);

View File

@ -346,8 +346,11 @@ public:
nsStyleChangeList& aChangeList,
nsChangeHint aMinChange,
nsChangeHint& aTopLevelChange);
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
NS_IMETHOD HasAttributeDependentStyle(nsIPresContext *aPresContext,
nsIContent *aContent,
nsIAtom *aAttribute,
PRInt32 aModType,
PRBool *aResult);
// Capture state from the entire frame heirarchy and store in aState
NS_IMETHOD CaptureFrameState(nsIPresContext* aPresContext,
@ -2066,31 +2069,25 @@ FrameManager::ComputeStyleChangeFor(nsIPresContext* aPresContext,
NS_IMETHODIMP
FrameManager::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
FrameManager::HasAttributeDependentStyle(nsIPresContext *aPresContext,
nsIContent *aContent,
nsIAtom *aAttribute,
PRInt32 aModType,
PRBool *aResult)
{
nsresult rv = NS_OK;
NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE);
if (aAttribute == nsHTMLAtoms::style) {
// Perhaps should check that it's XUL, SVG, (or HTML) namespace, but
// it doesn't really matter.
aAffects = PR_TRUE;
// it doesn't really matter. Or we could even let
// HTMLCSSStyleSheetImpl::HasAttributeDependentStyle handle it.
*aResult = PR_TRUE;
return NS_OK;
}
nsCOMPtr<nsIXMLContent> xml(do_QueryInterface(aContent));
if (xml) {
rv = mStyleSet->AttributeAffectsStyle(aAttribute, aContent, aAffects);
} else {
// not an XML element, so assume it is an HTML element and further assume that
// any attribute may affect style
// NOTE: we could list all of the presentation-hint attributes and check them,
// but there are a lot of them and this is safer.
aAffects = PR_TRUE;
rv = NS_OK;
}
return rv;
return mStyleSet->HasAttributeDependentStyle(aPresContext, aContent,
aAttribute, aModType,
aResult);
}
// Capture state for a given frame.

View File

@ -162,8 +162,11 @@ public:
nsChangeHint& aTopLevelChange) = 0;
// Determine whether an attribute affects style
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
NS_IMETHOD HasAttributeDependentStyle(nsIPresContext* aPresContext,
nsIContent *aContent,
nsIAtom *aAttribute,
PRInt32 aModType,
PRBool *aResult) = 0;
/**
* Capture/restore frame state for the frame subtree rooted at aFrame.

View File

@ -203,6 +203,13 @@ public:
PRInt32 aStateMask,
PRBool* aResult) = 0;
// Test if style is dependent on the presence of an attribute.
NS_IMETHOD HasAttributeDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIAtom* aAttribute,
PRInt32 aModType,
PRBool* aResult) = 0;
// Create frames for the root content element and its child content
NS_IMETHOD ConstructRootFrame(nsIPresContext* aPresContext,
nsIContent* aDocElement,
@ -316,11 +323,6 @@ public:
#endif
virtual void ResetUniqueStyleItems(void) = 0;
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
};
extern NS_EXPORT nsresult

View File

@ -346,8 +346,11 @@ public:
nsStyleChangeList& aChangeList,
nsChangeHint aMinChange,
nsChangeHint& aTopLevelChange);
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
NS_IMETHOD HasAttributeDependentStyle(nsIPresContext *aPresContext,
nsIContent *aContent,
nsIAtom *aAttribute,
PRInt32 aModType,
PRBool *aResult);
// Capture state from the entire frame heirarchy and store in aState
NS_IMETHOD CaptureFrameState(nsIPresContext* aPresContext,
@ -2066,31 +2069,25 @@ FrameManager::ComputeStyleChangeFor(nsIPresContext* aPresContext,
NS_IMETHODIMP
FrameManager::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
FrameManager::HasAttributeDependentStyle(nsIPresContext *aPresContext,
nsIContent *aContent,
nsIAtom *aAttribute,
PRInt32 aModType,
PRBool *aResult)
{
nsresult rv = NS_OK;
NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_AVAILABLE);
if (aAttribute == nsHTMLAtoms::style) {
// Perhaps should check that it's XUL, SVG, (or HTML) namespace, but
// it doesn't really matter.
aAffects = PR_TRUE;
// it doesn't really matter. Or we could even let
// HTMLCSSStyleSheetImpl::HasAttributeDependentStyle handle it.
*aResult = PR_TRUE;
return NS_OK;
}
nsCOMPtr<nsIXMLContent> xml(do_QueryInterface(aContent));
if (xml) {
rv = mStyleSet->AttributeAffectsStyle(aAttribute, aContent, aAffects);
} else {
// not an XML element, so assume it is an HTML element and further assume that
// any attribute may affect style
// NOTE: we could list all of the presentation-hint attributes and check them,
// but there are a lot of them and this is safer.
aAffects = PR_TRUE;
rv = NS_OK;
}
return rv;
return mStyleSet->HasAttributeDependentStyle(aPresContext, aContent,
aAttribute, aModType,
aResult);
}
// Capture state for a given frame.

View File

@ -10731,7 +10731,8 @@ nsCSSFrameConstructor::AttributeChanged(nsIPresContext* aPresContext,
shell->GetFrameManager(getter_AddRefs(frameManager));
PRBool affects;
frameManager->AttributeAffectsStyle(aAttribute, aContent, affects);
frameManager->HasAttributeDependentStyle(aPresContext, aContent,
aAttribute, aModType, &affects);
if (affects) {
#ifdef DEBUG_shaver
fputc('+', stderr);

View File

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
// vim:cindent:tabstop=2:expandtab:shiftwidth=2:
/* ***** BEGIN LICENSE BLOCK *****
* Version: NPL 1.1/GPL 2.0/LGPL 2.1
*
@ -107,87 +108,6 @@
#include "nsIJSContextStack.h"
#include "nsIScriptSecurityManager.h"
// An |AtomKey| is to be used for storage in the hashtable, and a
// |DependentAtomKey| should be used on the stack to avoid the performance
// cost of refcounting an atom that one is assured to own for the lifetime
// of the key.
class AtomKey_base : public nsHashKey {
public:
virtual PRUint32 HashCode(void) const;
virtual PRBool Equals(const nsHashKey *aKey) const;
nsIAtom* mAtom;
};
class AtomKey : public AtomKey_base {
public:
AtomKey(nsIAtom* aAtom);
AtomKey(const AtomKey_base& aKey);
virtual ~AtomKey();
virtual nsHashKey *Clone(void) const;
};
class DependentAtomKey : public AtomKey_base {
public:
DependentAtomKey(nsIAtom* aAtom)
{
mAtom = aAtom;
}
DependentAtomKey(const DependentAtomKey& aKey);
virtual ~DependentAtomKey(void);
virtual nsHashKey *Clone(void) const;
};
PRUint32 AtomKey_base::HashCode(void) const
{
return NS_PTR_TO_INT32(mAtom);
}
PRBool AtomKey_base::Equals(const nsHashKey* aKey) const
{
return NS_STATIC_CAST(const AtomKey_base*, aKey)->mAtom == mAtom;
}
AtomKey::AtomKey(nsIAtom* aAtom)
{
mAtom = aAtom;
NS_ADDREF(mAtom);
}
AtomKey::AtomKey(const AtomKey_base& aKey)
{
mAtom = aKey.mAtom;
NS_ADDREF(mAtom);
}
AtomKey::~AtomKey()
{
NS_RELEASE(mAtom);
}
nsHashKey* AtomKey::Clone(void) const
{
return new AtomKey(*this);
}
DependentAtomKey::DependentAtomKey(const DependentAtomKey& aKey)
{
NS_NOTREACHED("Should never clone to a dependent atom key.");
mAtom = aKey.mAtom;
}
DependentAtomKey::~DependentAtomKey()
{
}
nsHashKey* DependentAtomKey::Clone(void) const
{
return new AtomKey(*this); // return a non-dependent key
}
struct RuleValue {
RuleValue(nsICSSStyleRule* aRule, PRInt32 aIndex, RuleValue *aNext)
: mRule(aRule), mIndex(aIndex), mNext(aNext) {}
@ -708,6 +628,35 @@ void RuleHash::EnumerateTagRules(nsIAtom* aTag, RuleEnumFunc aFunc, void* aData)
}
}
//--------------------------------
// Attribute selectors hash table.
struct AttributeSelectorEntry : public PLDHashEntryHdr {
nsIAtom *mAttribute;
nsVoidArray *mSelectors;
};
PR_STATIC_CALLBACK(void)
AttributeSelectorClearEntry(PLDHashTable *table, PLDHashEntryHdr *hdr)
{
AttributeSelectorEntry *entry = NS_STATIC_CAST(AttributeSelectorEntry*, hdr);
delete entry->mSelectors;
memset(entry, 0, table->entrySize);
}
static PLDHashTableOps AttributeSelectorOps = {
PL_DHashAllocTable,
PL_DHashFreeTable,
PL_DHashGetKeyStub,
PL_DHashVoidPtrKeyStub,
PL_DHashMatchEntryStub,
PL_DHashMoveEntryStub,
AttributeSelectorClearEntry,
PL_DHashFinalizeStub,
NULL
};
//--------------------------------
struct RuleCascadeData {
@ -719,20 +668,45 @@ struct RuleCascadeData {
mNext(nsnull)
{
NS_NewISupportsArray(&mWeightedRules);
PL_DHashTableInit(&mAttributeSelectors, &AttributeSelectorOps, nsnull,
sizeof(AttributeSelectorEntry), 16);
}
~RuleCascadeData(void)
{
NS_IF_RELEASE(mWeightedRules);
PL_DHashTableFinish(&mAttributeSelectors);
}
nsISupportsArray* mWeightedRules;
RuleHash mRuleHash;
nsVoidArray mStateSelectors;
PLDHashTable mAttributeSelectors; // nsIAtom* -> nsVoidArray*
// Looks up or creates the appropriate list in |mAttributeSelectors|.
// Returns null only on allocation failure.
nsVoidArray* AttributeListFor(nsIAtom* aAttribute);
nsCOMPtr<nsIAtom> mMedium;
RuleCascadeData* mNext; // for a different medium
};
nsVoidArray*
RuleCascadeData::AttributeListFor(nsIAtom* aAttribute)
{
AttributeSelectorEntry *entry = NS_STATIC_CAST(AttributeSelectorEntry*,
PL_DHashTableOperate(&mAttributeSelectors, aAttribute, PL_DHASH_ADD));
if (!entry)
return nsnull;
if (!entry->mSelectors) {
if (!(entry->mSelectors = new nsVoidArray)) {
PL_DHashTableRawRemove(&mAttributeSelectors, entry);
return nsnull;
}
entry->mAttribute = aAttribute;
}
return entry->mSelectors;
}
// -------------------------------
// CSS Style Rule processor
//
@ -761,6 +735,10 @@ public:
nsIAtom* aMedium,
PRBool* aResult);
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult);
protected:
RuleCascadeData* GetRuleCascade(nsIPresContext* aPresContext, nsIAtom* aMedium);
@ -795,7 +773,6 @@ public:
nsCOMPtr<nsINameSpace> mNameSpace;
PRInt32 mDefaultNameSpaceID;
nsHashtable mRelevantAttributes;
PRPackedBool mComplete;
};
@ -855,15 +832,6 @@ public:
NS_IMETHOD AppendStyleSheet(nsICSSStyleSheet* aSheet);
NS_IMETHOD InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex);
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
// Find attributes in selector for rule, for use with AttributeAffectsStyle
NS_IMETHOD CheckRuleForAttributes(nsICSSRule* aRule);
// XXX do these belong here or are they generic?
NS_IMETHOD PrependStyleRule(nsICSSRule* aRule);
NS_IMETHOD AppendStyleRule(nsICSSRule* aRule);
@ -1473,7 +1441,6 @@ CSSStyleSheetInner::CSSStyleSheetInner(nsICSSStyleSheet* aParentSheet)
mOrderedRules(nsnull),
mNameSpace(nsnull),
mDefaultNameSpaceID(kNameSpaceID_None),
mRelevantAttributes(),
mComplete(PR_FALSE)
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
@ -1494,24 +1461,12 @@ CloneRuleInto(nsISupports* aRule, void* aArray)
return PR_TRUE;
}
static PRBool PR_CALLBACK
CopyRelevantAttributes(nsHashKey *aAttrKey, void *aAtom, void *aTable)
{
nsHashtable *table = NS_STATIC_CAST(nsHashtable *, aTable);
AtomKey *key = NS_STATIC_CAST(AtomKey *, aAttrKey);
table->Put(key, key->mAtom);
// we don't need to addref the atom here, because we're also copying the
// rules when we clone, and that will add a ref for us
return PR_TRUE;
}
CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
nsICSSStyleSheet* aParentSheet)
: mSheets(),
mURL(aCopy.mURL),
mNameSpace(nsnull),
mDefaultNameSpaceID(aCopy.mDefaultNameSpaceID),
mRelevantAttributes(),
mComplete(aCopy.mComplete)
{
MOZ_COUNT_CTOR(CSSStyleSheetInner);
@ -1527,8 +1482,6 @@ CSSStyleSheetInner::CSSStyleSheetInner(CSSStyleSheetInner& aCopy,
else {
mOrderedRules = nsnull;
}
aCopy.mRelevantAttributes.Enumerate(CopyRelevantAttributes,
&mRelevantAttributes);
RebuildNameSpaces();
}
@ -2104,21 +2057,6 @@ CSSStyleSheetImpl::InsertStyleSheetAt(nsICSSStyleSheet* aSheet, PRInt32 aIndex)
return result;
}
NS_IMETHODIMP
CSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
DependentAtomKey key(aAttribute);
aAffects = !!mInner->mRelevantAttributes.Get(&key);
for (CSSStyleSheetImpl *child = mFirstChild;
child && !aAffects;
child = child->mNext) {
child->AttributeAffectsStyle(aAttribute, aContent, aAffects);
}
return NS_OK;
}
NS_IMETHODIMP
CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
{
@ -2138,8 +2076,6 @@ CSSStyleSheetImpl::PrependStyleRule(nsICSSRule* aRule)
if (nsICSSRule::NAMESPACE_RULE == type) {
// no api to prepend a namespace (ugh), release old ones and re-create them all
mInner->RebuildNameSpaces();
} else {
CheckRuleForAttributes(aRule);
}
}
}
@ -2181,8 +2117,6 @@ CSSStyleSheetImpl::AppendStyleRule(nsICSSRule* aRule)
mInner->mNameSpace = newNameSpace;
}
}
} else {
CheckRuleForAttributes(aRule);
}
}
@ -2190,68 +2124,6 @@ CSSStyleSheetImpl::AppendStyleRule(nsICSSRule* aRule)
return NS_OK;
}
static PRBool
CheckRuleForAttributesEnum(nsISupports *aRule, void *aData)
{
nsICSSRule *rule = NS_STATIC_CAST(nsICSSRule *, aRule);
CSSStyleSheetImpl *sheet = NS_STATIC_CAST(CSSStyleSheetImpl *, aData);
return NS_SUCCEEDED(sheet->CheckRuleForAttributes(rule));
}
NS_IMETHODIMP
CSSStyleSheetImpl::CheckRuleForAttributes(nsICSSRule *aRule)
{
PRInt32 ruleType = nsICSSRule::UNKNOWN_RULE;
aRule->GetType(ruleType);
switch (ruleType) {
case nsICSSRule::MEDIA_RULE: {
nsICSSMediaRule *mediaRule = (nsICSSMediaRule *)aRule;
return mediaRule->EnumerateRulesForwards(CheckRuleForAttributesEnum,
(void *)this);
}
case nsICSSRule::STYLE_RULE: {
nsICSSStyleRule *styleRule = NS_STATIC_CAST(nsICSSStyleRule *, aRule);
nsCSSSelector *iter;
for (iter = styleRule->FirstSelector(); iter; iter = iter->mNext) {
/* P.classname means we have to check the attribute "class" */
if (iter->mIDList) {
DependentAtomKey idKey(nsHTMLAtoms::id);
mInner->mRelevantAttributes.Put(&idKey, nsHTMLAtoms::id);
}
if (iter->mClassList) {
DependentAtomKey classKey(nsHTMLAtoms::kClass);
mInner->mRelevantAttributes.Put(&classKey, nsHTMLAtoms::kClass);
}
for (nsAttrSelector *sel = iter->mAttrList; sel; sel = sel->mNext) {
/* store it in this sheet's attributes-that-matter table */
/* XXX store tag name too, but handle collisions */
#ifdef DEBUG_shaver_off
nsAutoString str;
sel->mAttr->ToString(str);
char * chars = ToNewCString(str);
fprintf(stderr, "[%s@%p]", chars, this);
nsMemory::Free(chars);
#endif
DependentAtomKey key(sel->mAttr);
mInner->mRelevantAttributes.Put(&key, sel->mAttr);
}
// Search for the :lang() pseudo class. If it is there add
// the lang attribute to the relevant attribute list.
for (nsAtomStringList* p = iter->mPseudoClassList; p; p = p->mNext) {
if (p->mAtom == nsCSSPseudoClasses::lang) {
DependentAtomKey langKey(nsHTMLAtoms::lang);
mInner->mRelevantAttributes.Put(&langKey, nsHTMLAtoms::lang);
break;
}
}
}
} /* fall-through */
default:
return NS_OK;
}
}
NS_IMETHODIMP
CSSStyleSheetImpl::StyleRuleCount(PRInt32& aCount) const
{
@ -2843,9 +2715,6 @@ CSSStyleSheetImpl::InsertRule(const nsAString& aRule,
mInner->mNameSpace = newNameSpace;
}
}
else {
CheckRuleForAttributes(cssRule);
}
// We don't notify immediately for @import rules, but rather when
// the sheet the rule is importing is loaded
@ -3048,7 +2917,6 @@ CSSStyleSheetImpl::InsertRuleIntoGroup(const nsAString & aRule, nsICSSGroupRule*
DidDirty();
for (counter = 0; counter < rulecount; counter++) {
rule = dont_AddRef((nsICSSRule*)rules->ElementAt(counter));
CheckRuleForAttributes(rule);
if (mDocument) {
result = mDocument->StyleRuleAdded(this, rule);
@ -3516,6 +3384,7 @@ DashMatchCompare(const nsAString& aAttributeValue,
static PRBool SelectorMatches(RuleProcessorData &data,
nsCSSSelector* aSelector,
PRInt32 aStateMask, // states NOT to test
nsIAtom* aAttribute, // attribute NOT to test
PRInt8 aNegationIndex)
{
@ -3746,15 +3615,20 @@ static PRBool SelectorMatches(RuleProcessorData &data,
}
// namespace/tag match
if (result && aSelector->mAttrList) { // test for attribute match
// if no attributes on the content, no match
if(!data.mHasAttributes) {
if (result && aSelector->mAttrList) {
// test for attribute match
if (!data.mHasAttributes && !aAttribute) {
// if no attributes on the content, no match
result = localFalse;
} else {
result = localTrue;
nsAttrSelector* attr = aSelector->mAttrList;
do {
if (!data.mContent->HasAttr(attr->mNameSpace, attr->mAttr)) {
if (attr->mAttr == aAttribute) {
result = PR_TRUE;
}
else if (!data.mContent->HasAttr(attr->mNameSpace, attr->mAttr)) {
result = localFalse;
}
else if (attr->mFunction != NS_ATTR_FUNC_SET) {
@ -3826,7 +3700,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// case sensitivity: bug 93371
PRBool isCaseSensitive = data.mCompatMode != eCompatibility_NavQuirks;
nsAtomList* IDList = aSelector->mIDList;
if (nsnull == IDList) {
if (nsnull == IDList || aAttribute == nsHTMLAtoms::id) {
result = PR_TRUE;
}
else if (nsnull != data.mContentID) {
@ -3857,7 +3731,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
}
}
if (result) {
if (result && aAttribute != nsHTMLAtoms::kClass) {
nsAtomList* classList = aSelector->mClassList;
while (nsnull != classList) {
if (localTrue == (!data.mStyledContent->HasClass(classList->mAtom, isCaseSensitive))) {
@ -3873,7 +3747,7 @@ static PRBool SelectorMatches(RuleProcessorData &data,
// apply SelectorMatches to the negated selectors in the chain
if (result && (nsnull != aSelector->mNegations)) {
result = SelectorMatches(data, aSelector->mNegations, aStateMask,
aNegationIndex+1);
aAttribute, aNegationIndex+1);
}
return result;
}
@ -3948,7 +3822,7 @@ static PRBool SelectorMatchesTree(RuleProcessorData &data,
NS_ASSERTION(!content, "content must be null");
break;
}
if (SelectorMatches(*newdata, selector, 0, 0)) {
if (SelectorMatches(*newdata, selector, 0, nsnull, 0)) {
// to avoid greedy matching, we need to recurse if this is a
// descendant combinator and the next combinator is not
if ((NS_IS_GREEDY_OPERATOR(selector->mOperator)) &&
@ -3992,7 +3866,7 @@ static void ContentEnumFunc(nsICSSStyleRule* aRule, void* aData)
ElementRuleProcessorData* data = (ElementRuleProcessorData*)aData;
nsCSSSelector* selector = aRule->FirstSelector();
if (SelectorMatches(*data, selector, 0, 0)) {
if (SelectorMatches(*data, selector, 0, nsnull, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
// for performance, require that every implementation of
@ -4048,7 +3922,7 @@ static void PseudoEnumFunc(nsICSSStyleRule* aRule, void* aData)
if (PRUnichar('+') == selector->mOperator) {
return; // not valid here, can't match
}
if (SelectorMatches(*data, selector, 0, 0)) {
if (SelectorMatches(*data, selector, 0, nsnull, 0)) {
selector = selector->mNext;
}
else {
@ -4093,19 +3967,17 @@ CSSRuleProcessor::RulesMatching(PseudoRuleProcessorData* aData,
return NS_OK;
}
static
PRBool PR_CALLBACK StateEnumFunc(void* aSelector, void* aData)
{
StateRuleProcessorData* data = (StateRuleProcessorData*)aData;
nsCSSSelector* selector = (nsCSSSelector*)aSelector;
if (SelectorMatches(*data, selector, data->mStateMask, 0)) {
selector = selector->mNext;
if (SelectorMatchesTree(*data, selector)) {
return PR_FALSE;
}
}
return PR_TRUE;
PR_STATIC_CALLBACK(PRBool) StateEnumFunc(void* aSelector, void* aData)
{
StateRuleProcessorData* data =
NS_STATIC_CAST(StateRuleProcessorData*, aData);
nsCSSSelector* selector = NS_STATIC_CAST(nsCSSSelector*, aSelector);
// Return whether we want to halt the enumeration, which is the
// negation of whether we find a match (ignoring the event state mask).
return !( SelectorMatches(*data, selector, data->mStateMask, nsnull, 0) &&
SelectorMatchesTree(*data, selector->mNext) );
}
NS_IMETHODIMP
@ -4135,6 +4007,46 @@ CSSRuleProcessor::HasStateDependentStyle(StateRuleProcessorData* aData,
return NS_OK;
}
PR_STATIC_CALLBACK(PRBool) AttributeEnumFunc(void* aSelector, void* aData)
{
AttributeRuleProcessorData* data =
NS_STATIC_CAST(AttributeRuleProcessorData*, aData);
nsCSSSelector* selector = NS_STATIC_CAST(nsCSSSelector*, aSelector);
// Return whether we want to halt the enumeration, which is the
// negation of whether we find a match (ignoring the event state mask).
return !( SelectorMatches(*data, selector, 0, data->mAttribute, 0) &&
SelectorMatchesTree(*data, selector->mNext) );
}
NS_IMETHODIMP
CSSRuleProcessor::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult)
{
NS_PRECONDITION(aData->mContent->IsContentOfType(nsIContent::eELEMENT),
"content must be element");
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext, aMedium);
// We do the same thing for attributes that we do for state selectors
// (see HasStateDependentStyle), except that instead of one big list
// we have a hashtable with a per-attribute list.
*aResult = PR_FALSE;
if (cascade) {
AttributeSelectorEntry *entry = NS_STATIC_CAST(AttributeSelectorEntry*,
PL_DHashTableOperate(&cascade->mAttributeSelectors, aData->mAttribute,
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_BUSY(entry)) {
*aResult =
!entry->mSelectors->EnumerateForwards(AttributeEnumFunc, aData);
}
}
return NS_OK;
}
NS_IMETHODIMP
CSSRuleProcessor::ClearRuleCascades(void)
{
@ -4170,18 +4082,41 @@ PRBool IsStateSelector(nsCSSSelector& aSelector)
}
static PRBool
BuildRuleHashAndStateSelectors(nsISupports* aRule, void* aCascade)
AddRule(nsISupports* aRule, void* aCascade)
{
nsICSSStyleRule* rule = NS_STATIC_CAST(nsICSSStyleRule*, aRule);
RuleCascadeData *cascade = NS_STATIC_CAST(RuleCascadeData*, aCascade);
// Build the rule hash.
cascade->mRuleHash.PrependRule(rule);
nsVoidArray* array = &cascade->mStateSelectors;
nsVoidArray* stateArray = &cascade->mStateSelectors;
for (nsCSSSelector* selector = rule->FirstSelector();
selector; selector = selector->mNext)
selector; selector = selector->mNext) {
// Build mStateSelectors.
if (IsStateSelector(*selector))
stateArray->AppendElement(selector);
// Build mAttributeSelectors.
if (selector->mIDList) {
nsVoidArray *array = cascade->AttributeListFor(nsHTMLAtoms::id);
if (!array)
return PR_FALSE;
array->AppendElement(selector);
}
if (selector->mClassList) {
nsVoidArray *array = cascade->AttributeListFor(nsHTMLAtoms::kClass);
if (!array)
return PR_FALSE;
array->AppendElement(selector);
}
for (nsAttrSelector *attr = selector->mAttrList; attr; attr = attr->mNext) {
nsVoidArray *array = cascade->AttributeListFor(attr->mAttr);
if (!array)
return PR_FALSE;
array->AppendElement(selector);
}
}
return PR_TRUE;
}
@ -4328,14 +4263,16 @@ CSSRuleProcessor::GetRuleCascade(nsIPresContext* aPresContext, nsIAtom* aMedium)
cascade = new RuleCascadeData(aMedium,
eCompatibility_NavQuirks == quirkMode);
if (cascade) {
*cascadep = cascade;
CascadeEnumData data(aMedium);
mSheets->EnumerateForwards(CascadeSheetRulesInto, &data);
PutRulesInList(&data.mRuleArrays, cascade->mWeightedRules);
cascade->mWeightedRules->EnumerateBackwards(
BuildRuleHashAndStateSelectors, cascade);
if (!cascade->mWeightedRules->EnumerateBackwards(AddRule, cascade)) {
delete cascade;
cascade = nsnull;
}
*cascadep = cascade;
}
}
return cascade;

View File

@ -181,16 +181,14 @@ public:
nsIAtom* aMedium,
PRBool* aResult);
// XXX style rule enumerations
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult);
#ifdef DEBUG
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLCSSStyleSheetImpl(const HTMLCSSStyleSheetImpl& aCopy);
@ -321,6 +319,16 @@ HTMLCSSStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
return NS_OK;
}
// Test if style is dependent on attribute
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult)
{
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
@ -447,16 +455,6 @@ void HTMLCSSStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const
}
#endif
NS_IMETHODIMP
HTMLCSSStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX can attributes affect rules in these?
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For backwards compatibility and convenience
NS_EXPORT nsresult
NS_NewHTMLCSSStyleSheet(nsIHTMLCSSStyleSheet** aInstancePtrResult, nsIURI* aURL,

View File

@ -646,6 +646,10 @@ public:
nsIAtom* aMedium,
PRBool* aResult);
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult);
// nsIHTMLStyleSheet api
NS_IMETHOD Init(nsIURI* aURL, nsIDocument* aDocument);
NS_IMETHOD Reset(nsIURI* aURL);
@ -665,10 +669,6 @@ public:
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const;
#endif
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
// These are not supported and are not implemented!
HTMLStyleSheetImpl(const HTMLStyleSheetImpl& aCopy);
@ -919,6 +919,43 @@ HTMLStyleSheetImpl::HasStateDependentStyle(StateRuleProcessorData* aData,
return NS_OK;
}
NS_IMETHODIMP
HTMLStyleSheetImpl::HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult)
{
// Result is true for |href| changes on HTML links if we have link rules.
nsIStyledContent *styledContent = aData->mStyledContent;
if (aData->mAttribute == nsHTMLAtoms::href &&
(mLinkRule || mVisitedRule || mActiveRule) &&
styledContent &&
styledContent->IsContentOfType(nsIContent::eHTML) &&
aData->mContentTag == nsHTMLAtoms::a) {
*aResult = PR_TRUE;
return NS_OK;
}
// Don't worry about the HTMLDocumentColorRule since it only applies
// to descendants of body, when we're already reresolving.
// Handle the content style rules.
if (styledContent) {
nsChangeHint hint = NS_STYLE_HINT_NONE;
styledContent->GetMappedAttributeImpact(aData->mAttribute,
aData->mModType, hint);
// This is the same test that nsGenericHTMLElement uses when calling
// nsHTMLAttributes::SetAttributeFor.
if ((hint & ~(nsChangeHint_AttrChange | nsChangeHint_Aural |
nsChangeHint_Content)) != 0) {
*aResult = PR_TRUE;
return NS_OK;
}
}
*aResult = PR_FALSE;
return NS_OK;
}
NS_IMETHODIMP
HTMLStyleSheetImpl::RulesMatching(PseudoRuleProcessorData* aData,
@ -1223,17 +1260,6 @@ void HTMLStyleSheetImpl::List(FILE* out, PRInt32 aIndent) const
}
#endif
NS_IMETHODIMP
HTMLStyleSheetImpl::AttributeAffectsStyle(nsIAtom *aAttribute,
nsIContent *aContent,
PRBool &aAffects)
{
// XXX we should be checking to see if this is an href on an <A> being
// XXX tweaked, in which case we really want to restyle
aAffects = PR_FALSE;
return NS_OK;
}
// XXX For convenience and backwards compatibility
NS_EXPORT nsresult
NS_NewHTMLStyleSheet(nsIHTMLStyleSheet** aInstancePtrResult, nsIURI* aURL,

View File

@ -145,6 +145,21 @@ struct StateRuleProcessorData : public RuleProcessorData {
// Constants defined in nsIEventStateManager.h .
};
struct AttributeRuleProcessorData : public RuleProcessorData {
AttributeRuleProcessorData(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIAtom* aAttribute,
PRInt32 aModType)
: RuleProcessorData(aPresContext, aContent, nsnull),
mAttribute(aAttribute),
mModType(aModType)
{
NS_PRECONDITION(aContent, "null pointer");
}
nsIAtom* mAttribute; // |HasAttributeDependentStyle| for which attribute?
PRInt32 mModType; // The type of modification (see nsIDOMMutationEvent).
};
// IID for the nsIStyleRuleProcessor interface {015575fe-7b6c-11d3-ba05-001083023c2b}
#define NS_ISTYLE_RULE_PROCESSOR_IID \
@ -172,6 +187,10 @@ public:
NS_IMETHOD HasStateDependentStyle(StateRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult) = 0;
// Test if style is dependent on attribute
NS_IMETHOD HasAttributeDependentStyle(AttributeRuleProcessorData* aData,
nsIAtom* aMedium,
PRBool* aResult) = 0;
};
#endif /* nsIStyleRuleProcessor_h___ */

View File

@ -20,11 +20,6 @@ class nsIStyleRuleSupplier : public nsISupports {
NS_IMETHOD WalkRules(nsIStyleSet* aStyleSet,
nsISupportsArrayEnumFunc aFunc,
RuleProcessorData* aData)=0;
NS_IMETHOD AttributeAffectsStyle(nsISupportsArrayEnumFunc aFunc,
void* aData,
nsIContent* aContent,
PRBool* aAffects)=0;
};
#endif /* _nsIStyleRuleSupplier_h */

View File

@ -97,17 +97,9 @@ public:
NS_IMETHOD GetStyleRuleProcessor(nsIStyleRuleProcessor*& aProcessor,
nsIStyleRuleProcessor* aPrevProcessor) = 0;
// XXX style rule enumerations
// If changing the given attribute cannot affect style context, aAffects
// will be PR_FALSE on return.
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects) = 0;
#ifdef DEBUG
virtual void List(FILE* out = stdout, PRInt32 aIndent = 0) const = 0;
#endif
};
#endif /* nsIStyleSheet_h___ */

View File

@ -208,6 +208,12 @@ public:
PRInt32 aStateMask,
PRBool* aResult);
NS_IMETHOD HasAttributeDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIAtom* aAtribute,
PRInt32 aModType,
PRBool* aResult);
NS_IMETHOD ConstructRootFrame(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIFrame*& aFrameSubTree);
@ -296,9 +302,6 @@ public:
NS_DECL_NSITIMERECORDER
#endif
NS_IMETHOD AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects);
private:
static nsrefcnt gInstances;
static nsIURI *gQuirkURI;
@ -1501,20 +1504,20 @@ struct StatefulData : public StateRuleProcessorData {
nsIContent* aContent, PRInt32 aStateMask)
: StateRuleProcessorData(aPresContext, aContent, aStateMask),
mMedium(aMedium),
mStateful(PR_FALSE)
mHasStyle(PR_FALSE)
{}
nsIAtom* mMedium;
PRBool mStateful;
PRBool mHasStyle;
};
static PRBool SheetHasStatefulStyle(nsISupports* aProcessor, void *aData)
{
nsIStyleRuleProcessor* processor = (nsIStyleRuleProcessor*)aProcessor;
StatefulData* data = (StatefulData*)aData;
PRBool hasStateful;
processor->HasStateDependentStyle(data, data->mMedium, &hasStateful);
if (hasStateful) {
data->mStateful = PR_TRUE;
PRBool hasStyle;
processor->HasStateDependentStyle(data, data->mMedium, &hasStyle);
if (hasStyle) {
data->mHasStyle = PR_TRUE;
// Stop iteration. Note that StyleSetImpl::WalkRuleProcessors uses
// this to stop its own iteration in some cases, but not all (the
// style rule supplier case). Since this optimization is only for
@ -1539,12 +1542,67 @@ StyleSetImpl::HasStateDependentStyle(nsIPresContext* aPresContext,
mUserRuleProcessors ||
mDocRuleProcessors ||
mOverrideRuleProcessors)) {
nsIAtom* medium = nsnull;
aPresContext->GetMedium(&medium);
nsCOMPtr<nsIAtom> medium;
aPresContext->GetMedium(getter_AddRefs(medium));
StatefulData data(aPresContext, medium, aContent, aStateMask);
WalkRuleProcessors(SheetHasStatefulStyle, &data);
NS_IF_RELEASE(medium);
*aResult = data.mStateful;
*aResult = data.mHasStyle;
} else {
*aResult = PR_FALSE;
}
return NS_OK;
}
struct AttributeData : public AttributeRuleProcessorData {
AttributeData(nsIPresContext* aPresContext, nsIAtom* aMedium,
nsIContent* aContent, nsIAtom* aAttribute, PRInt32 aModType)
: AttributeRuleProcessorData(aPresContext, aContent, aAttribute, aModType),
mMedium(aMedium),
mHasStyle(PR_FALSE)
{}
nsIAtom* mMedium;
PRBool mHasStyle;
};
static PRBool SheetHasAttributeStyle(nsISupports* aProcessor, void *aData)
{
nsIStyleRuleProcessor* processor = (nsIStyleRuleProcessor*)aProcessor;
AttributeData* data = (AttributeData*)aData;
PRBool hasStyle;
processor->HasAttributeDependentStyle(data, data->mMedium, &hasStyle);
if (hasStyle) {
data->mHasStyle = PR_TRUE;
// Stop iteration. Note that StyleSetImpl::WalkRuleProcessors uses
// this to stop its own iteration in some cases, but not all (the
// style rule supplier case). Since this optimization is only for
// the case where we have a lot more work to do, it's not worth the
// code needed to make the stopping perfect.
return PR_FALSE;
}
return PR_TRUE; // continue
}
// Test if style is dependent on content state
NS_IMETHODIMP
StyleSetImpl::HasAttributeDependentStyle(nsIPresContext* aPresContext,
nsIContent* aContent,
nsIAtom* aAttribute,
PRInt32 aModType,
PRBool* aResult)
{
GatherRuleProcessors();
if (aContent->IsContentOfType(nsIContent::eELEMENT) &&
(mAgentRuleProcessors ||
mUserRuleProcessors ||
mDocRuleProcessors ||
mOverrideRuleProcessors)) {
nsCOMPtr<nsIAtom> medium;
aPresContext->GetMedium(getter_AddRefs(medium));
AttributeData data(aPresContext, medium, aContent, aAttribute, aModType);
WalkRuleProcessors(SheetHasAttributeStyle, &data);
*aResult = data.mHasStyle;
} else {
*aResult = PR_FALSE;
}
@ -1912,53 +1970,3 @@ void StyleSetImpl::ResetUniqueStyleItems(void)
UNIQUE_STYLE_ITEMS(uniqueItems);
uniqueItems->Clear();
}
struct AttributeContentPair {
nsIAtom *attribute;
nsIContent *content;
};
static PRBool
EnumAffectsStyle(nsISupports *aElement, void *aData)
{
nsIStyleSheet *sheet = NS_STATIC_CAST(nsIStyleSheet *, aElement);
AttributeContentPair *pair = (AttributeContentPair *)aData;
PRBool affects;
nsresult res =
sheet->AttributeAffectsStyle(pair->attribute, pair->content, affects);
if (NS_FAILED(res) || affects)
return PR_FALSE; // stop checking
return PR_TRUE;
}
NS_IMETHODIMP
StyleSetImpl::AttributeAffectsStyle(nsIAtom *aAttribute, nsIContent *aContent,
PRBool &aAffects)
{
AttributeContentPair pair;
pair.attribute = aAttribute;
pair.content = aContent;
/* scoped sheets should be checked first, since - if present - they will contain
the bulk of the applicable rules for the content node. */
if (mStyleRuleSupplier)
mStyleRuleSupplier->AttributeAffectsStyle(EnumAffectsStyle, &pair, aContent, &aAffects);
if (!aAffects) {
/* check until we find a sheet that will be affected */
if ((mDocSheets && !mDocSheets->EnumerateForwards(EnumAffectsStyle, &pair)) ||
(mOverrideSheets && !mOverrideSheets->EnumerateForwards(EnumAffectsStyle,
&pair)) ||
(mUserSheets && !mUserSheets->EnumerateForwards(EnumAffectsStyle,
&pair)) ||
(mAgentSheets && !mAgentSheets->EnumerateForwards(EnumAffectsStyle,
&pair))) {
aAffects = PR_TRUE;
} else {
aAffects = PR_FALSE;
}
}
return NS_OK;
}