Speed up matching class rules by caching the class attribute, rather than looking it up for each rule. Remove HasClass now that it's no longer needed. Bug 310236, r+sr=dbaron.

This commit is contained in:
bryner%brianryner.com 2005-10-08 23:06:27 +00:00
parent d1b0778bd9
commit 48082c9284
16 changed files with 62 additions and 113 deletions

View File

@ -47,10 +47,10 @@ class nsRuleWalker;
class nsAttrValue;
// IID for the nsIStyledContent class
// c59f05f5-6e39-4e98-a1ea-6c555cb7813c
// b3edce42-2a58-4b05-a679-eae3ddbd1edd
#define NS_ISTYLEDCONTENT_IID \
{ 0xc59f05f5, 0x6e39, 0x4e98, \
{ 0xa1, 0xea, 0x6c, 0x55, 0x5c, 0xb7, 0x81, 0x3c } }
{ 0xb3edc342, 0x2a58, 0x4b05, \
{ 0xa6, 0x79, 0xea, 0xe3, 0xdd, 0xbd, 0x1e, 0xdd } }
// Abstract interface for all styled content (that supports ID, CLASS, STYLE, and
// the ability to specify style hints on an attribute change).
@ -69,7 +69,6 @@ public:
// incorrect, then new methods need to be added here.
virtual nsIAtom* GetID() const = 0;
virtual const nsAttrValue* GetClasses() const = 0;
NS_IMETHOD_(PRBool) HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const = 0;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker) = 0;

View File

@ -673,6 +673,48 @@ nsAttrValue::Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
return aValue->Equals(val);
}
PRBool
nsAttrValue::Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const
{
switch (BaseType()) {
case eAtomBase:
{
nsIAtom* atom = GetAtomValue();
if (aCaseSensitive == eCaseMatters) {
return aValue == atom;
}
const char *val1, *val2;
aValue->GetUTF8String(&val1);
atom->GetUTF8String(&val2);
return nsCRT::strcasecmp(val1, val2) == 0;
}
default:
{
if (Type() == eAtomArray) {
nsCOMArray<nsIAtom>* array = GetAtomArrayValue();
if (aCaseSensitive == eCaseMatters) {
return array->IndexOf(aValue) >= 0;
}
const char *val1, *val2;
aValue->GetUTF8String(&val1);
for (PRInt32 i = 0, count = array->Count(); i < count; ++i) {
array->ObjectAt(i)->GetUTF8String(&val2);
if (nsCRT::strcasecmp(val1, val2) == 0) {
return PR_TRUE;
}
}
}
}
}
return PR_FALSE;
}
void
nsAttrValue::ParseAtom(const nsAString& aValue)
{

View File

@ -159,6 +159,12 @@ public:
PRBool Equals(const nsAString& aValue, nsCaseTreatment aCaseSensitive) const;
PRBool Equals(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const;
/**
* Returns true if this AttrValue is equal to the given atom, or is an
* array which contains the given atom.
*/
PRBool Contains(nsIAtom* aValue, nsCaseTreatment aCaseSensitive) const;
void ParseAtom(const nsAString& aValue);
void ParseAtomArray(const nsAString& aValue);
void ParseStringOrAtom(const nsAString& aValue);

View File

@ -2295,12 +2295,6 @@ nsGenericElement::GetClasses() const
return nsnull;
}
NS_IMETHODIMP_(PRBool)
nsGenericElement::HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const
{
return PR_FALSE;
}
NS_IMETHODIMP
nsGenericElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{

View File

@ -449,7 +449,6 @@ public:
// nsIStyledContent interface methods
virtual nsIAtom* GetID() const;
virtual const nsAttrValue* GetClasses() const;
NS_IMETHOD_(PRBool) HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
virtual nsICSSStyleRule* GetInlineStyleRule();
NS_IMETHOD SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify);

View File

@ -1915,44 +1915,6 @@ nsGenericHTMLElement::GetClassAttributeName() const
return nsHTMLAtoms::kClass;
}
NS_IMETHODIMP_(PRBool)
nsGenericHTMLElement::HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const
{
const nsAttrValue* val = mAttrsAndChildren.GetAttr(nsHTMLAtoms::kClass);
if (val) {
if (val->Type() == nsAttrValue::eAtom) {
if (aCaseSensitive) {
return aClass == val->GetAtomValue();
}
const char *class1, *class2;
aClass->GetUTF8String(&class1);
val->GetAtomValue()->GetUTF8String(&class2);
return nsCRT::strcasecmp(class1, class2) == 0;
}
if (val->Type() == nsAttrValue::eAtomArray) {
nsCOMArray<nsIAtom>* array = val->GetAtomArrayValue();
if (aCaseSensitive) {
return array->IndexOf(aClass) >= 0;
}
const char *class1, *class2;
aClass->GetUTF8String(&class1);
PRInt32 i, count = array->Count();
for (i = 0; i < count; ++i) {
array->ObjectAt(i)->GetUTF8String(&class2);
if (nsCRT::strcasecmp(class1, class2) == 0) {
return PR_TRUE;
}
}
}
}
return PR_FALSE;
}
nsresult
nsGenericHTMLElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{

View File

@ -251,7 +251,6 @@ public:
virtual const nsAttrValue* GetClasses() const;
virtual nsIAtom *GetIDAttributeName() const;
virtual nsIAtom *GetClassAttributeName() const;
NS_IMETHOD_(PRBool) HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
virtual nsICSSStyleRule* GetInlineStyleRule();
NS_IMETHOD SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify);

View File

@ -92,22 +92,6 @@ nsSVGStylableElement::GetClasses() const
return mClassName->GetAttrValue();
}
NS_IMETHODIMP_(PRBool)
nsSVGStylableElement::HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const
{
NS_ASSERTION(aCaseSensitive, "svg should always be casesensitive");
const nsAttrValue* val = mClassName->GetAttrValue();
if (val->Type() == nsAttrValue::eAtom) {
return aClass == val->GetAtomValue();
}
if (val->Type() == nsAttrValue::eAtomArray) {
return val->GetAtomArrayValue()->IndexOf(aClass) >= 0;
}
return PR_FALSE;
}
//----------------------------------------------------------------------
// nsIDOMSVGStylable methods

View File

@ -61,7 +61,6 @@ public:
// nsIStyledContent
virtual const nsAttrValue* GetClasses() const;
NS_IMETHOD_(PRBool) HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const;
protected:
nsRefPtr<nsSVGClassValue> mClassName;

View File

@ -44,10 +44,10 @@
class nsIDocShell;
// ded21e95-2484-4735-a29a-af778335ecfe
// 37eff125-80a9-49ce-a0f7-1617a21ce745
#define NS_IXMLCONTENT_IID \
{ 0xded21e95, 0x2484, 0x4735, \
{ 0xa2, 0x9a, 0xaf, 0x77, 0x83, 0x35, 0xec, 0xfe } }
{ 0x37eff125, 0x80a9, 0x49ce, \
{ 0xa0, 0xf7, 0x16, 0x17, 0xa2, 0x1c, 0xe7, 0x45 } }
/**
* XML content extensions to nsIContent

View File

@ -810,22 +810,6 @@ nsXTFStyledElementWrapper::GetClasses() const
return val;
}
PRBool
nsXTFStyledElementWrapper::HasClass(nsIAtom* aClass, PRBool /*aCaseSensitive*/) const
{
const nsAttrValue* val = GetClasses();
if (val) {
if (val->Type() == nsAttrValue::eAtom) {
return aClass == val->GetAtomValue();
}
if (val->Type() == nsAttrValue::eAtomArray) {
return val->GetAtomArrayValue()->IndexOf(aClass) >= 0;
}
}
return PR_FALSE;
}
nsresult
nsXTFStyledElementWrapper::SetClassAttributeName(nsIAtom* aName)
{

View File

@ -159,7 +159,6 @@ public:
// for nsIStyledContent
virtual nsIAtom *GetClassAttributeName() const;
virtual const nsAttrValue* GetClasses() const;
NS_IMETHOD_(PRBool) HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const;
nsresult SetClassAttributeName(nsIAtom* aName);
protected:

View File

@ -2282,22 +2282,6 @@ nsXULElement::GetClasses() const
return FindLocalOrProtoAttr(kNameSpaceID_None, nsXULAtoms::clazz);
}
NS_IMETHODIMP_(PRBool)
nsXULElement::HasClass(nsIAtom* aClass, PRBool /*aCaseSensitive*/) const
{
const nsAttrValue* val = FindLocalOrProtoAttr(kNameSpaceID_None, nsXULAtoms::clazz);
if (val) {
if (val->Type() == nsAttrValue::eAtom) {
return aClass == val->GetAtomValue();
}
if (val->Type() == nsAttrValue::eAtomArray) {
return val->GetAtomArrayValue()->IndexOf(aClass) >= 0;
}
}
return PR_FALSE;
}
NS_IMETHODIMP
nsXULElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
{

View File

@ -531,7 +531,6 @@ public:
// nsIStyledContent
virtual nsIAtom* GetID() const;
virtual const nsAttrValue* GetClasses() const;
NS_IMETHOD_(PRBool) HasClass(nsIAtom* aClass, PRBool aCaseSensitive) const;
NS_IMETHOD WalkContentStyleRules(nsRuleWalker* aRuleWalker);
virtual nsICSSStyleRule* GetInlineStyleRule();

View File

@ -2663,6 +2663,7 @@ RuleProcessorData::RuleProcessorData(nsPresContext* aPresContext,
mPreviousSiblingData = nsnull;
mParentData = nsnull;
mLanguage = nsnull;
mClasses = nsnull;
// get the compat. mode (unless it is provided)
if(!aCompat) {
@ -2687,6 +2688,7 @@ RuleProcessorData::RuleProcessorData(nsPresContext* aPresContext,
if (aContent->IsContentOfType(nsIContent::eELEMENT)) {
mStyledContent = NS_STATIC_CAST(nsIStyledContent*, aContent);
mContentID = mStyledContent->GetID();
mClasses = mStyledContent->GetClasses();
}
NS_ASSERTION(nsCOMPtr<nsIStyledContent>(do_QueryInterface(aContent)) == mStyledContent,
@ -3291,9 +3293,8 @@ static PRBool SelectorMatches(RuleProcessorData &data,
do {
const char* id2Str;
IDList->mAtom->GetUTF8String(&id2Str);
nsDependentCString id2(id2Str);
if (localTrue !=
id1.Equals(id2, nsCaseInsensitiveCStringComparator())) {
id1.Equals(id2Str, nsCaseInsensitiveCStringComparator())) {
result = PR_FALSE;
break;
}
@ -3305,8 +3306,9 @@ static PRBool SelectorMatches(RuleProcessorData &data,
if (result &&
(!aAttribute || aAttribute != data.mStyledContent->GetClassAttributeName())) {
nsAtomList* classList = aSelector->mClassList;
const nsAttrValue *elementClasses = data.mClasses;
while (nsnull != classList) {
if (localTrue == (!data.mStyledContent->HasClass(classList->mAtom, isCaseSensitive))) {
if (localTrue == (!(elementClasses && elementClasses->Contains(classList->mAtom, isCaseSensitive ? eCaseMatters : eIgnoreCase)))) {
result = PR_FALSE;
break;
}
@ -3448,15 +3450,10 @@ nsCSSRuleProcessor::RulesMatching(ElementRuleProcessorData *aData)
RuleCascadeData* cascade = GetRuleCascade(aData->mPresContext);
if (cascade) {
nsIStyledContent* styledContent = aData->mStyledContent;
const nsAttrValue* classes = nsnull;
if (styledContent)
classes = styledContent->GetClasses();
cascade->mRuleHash.EnumerateAllRules(aData->mNameSpaceID,
aData->mContentTag,
aData->mContentID,
classes,
aData->mClasses,
ContentEnumFunc,
aData);
}

View File

@ -53,6 +53,7 @@ class nsISupportsArray;
class nsIAtom;
class nsICSSPseudoComparator;
class nsRuleWalker;
class nsAttrValue;
// The implementation of the constructor and destructor are currently in
// nsCSSStyleSheet.cpp.
@ -93,6 +94,7 @@ struct RuleProcessorData {
nsLinkState mLinkState; // if a link, this is the state, otherwise unknown
PRInt32 mEventState; // if content, eventStateMgr->GetContentState()
PRInt32 mNameSpaceID; // if content, content->GetNameSapce()
const nsAttrValue* mClasses; // if styled content, styledcontent->GetClasses()
RuleProcessorData* mPreviousSiblingData;
RuleProcessorData* mParentData;