зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
ea93b55cc8
Коммит
4b4f8625f1
|
@ -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___ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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___ */
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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___ */
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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___ */
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче