Bug 394442, Optimize ID, class and style getters, r=bz+sicking, sr=sicking, a=jst

This commit is contained in:
Olli.Pettay@helsinki.fi 2007-09-18 01:38:24 -07:00
parent cc6784b030
commit 2e21d3ae6d
6 changed files with 66 additions and 4 deletions

View File

@ -92,8 +92,14 @@ enum {
NODE_IS_EDITABLE = 0x00000100U,
// Optimizations to quickly check whether element may have ID, class or style
// attributes. Not all element implementations may use these!
NODE_MAY_HAVE_ID = 0x00000200U,
NODE_MAY_HAVE_CLASS = 0x00000400U,
NODE_MAY_HAVE_STYLE = 0x00000800U,
// Four bits for the script-type ID
NODE_SCRIPT_TYPE_OFFSET = 9,
NODE_SCRIPT_TYPE_OFFSET = 12,
NODE_SCRIPT_TYPE_SIZE = 4,

View File

@ -2268,6 +2268,10 @@ nsGenericElement::DispatchDOMEvent(nsEvent* aEvent,
nsIAtom*
nsGenericElement::GetID() const
{
if (!HasFlag(NODE_MAY_HAVE_ID)) {
return nsnull;
}
nsIAtom* IDName = GetIDAttributeName();
if (IDName) {
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(IDName);
@ -3683,6 +3687,7 @@ nsGenericElement::ParseAttribute(PRInt32 aNamespaceID,
{
if (aNamespaceID == kNameSpaceID_None &&
aAttribute == GetIDAttributeName() && !aValue.IsEmpty()) {
SetFlags(NODE_MAY_HAVE_ID);
// Store id as an atom. id="" means that the element has no id,
// not that it has an emptystring as the id.
aResult.ParseAtom(aValue);

View File

@ -73,6 +73,9 @@ nsStyledElement::GetIDAttributeName() const
const nsAttrValue*
nsStyledElement::GetClasses() const
{
if (!HasFlag(NODE_MAY_HAVE_CLASS)) {
return nsnull;
}
return mAttrsAndChildren.GetAttr(nsGkAtoms::_class);
}
@ -82,10 +85,12 @@ nsStyledElement::ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
{
if (aNamespaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::style) {
SetFlags(NODE_MAY_HAVE_STYLE);
ParseStyleAttribute(this, aValue, aResult);
return PR_TRUE;
}
if (aAttribute == nsGkAtoms::_class) {
SetFlags(NODE_MAY_HAVE_CLASS);
#ifdef MOZ_SVG
NS_ASSERTION(!nsCOMPtr<nsIDOMSVGStylable>(do_QueryInterface(this)),
"SVG code should have handled this 'class' attribute!");
@ -102,6 +107,7 @@ nsStyledElement::ParseAttribute(PRInt32 aNamespaceID, nsIAtom* aAttribute,
NS_IMETHODIMP
nsStyledElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
{
SetFlags(NODE_MAY_HAVE_STYLE);
PRBool modification = PR_FALSE;
nsAutoString oldValueStr;
@ -135,6 +141,9 @@ nsStyledElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
nsICSSStyleRule*
nsStyledElement::GetInlineStyleRule()
{
if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
return nsnull;
}
const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
if (attrVal && attrVal->Type() == nsAttrValue::eCSSStyleRule) {
@ -186,6 +195,7 @@ nsStyledElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
rv = gCSSOMFactory->CreateDOMCSSAttributeDeclaration(this,
getter_AddRefs(slots->mStyle));
NS_ENSURE_SUCCESS(rv, rv);
SetFlags(NODE_MAY_HAVE_STYLE);
}
// Why bother with QI?
@ -196,6 +206,9 @@ nsStyledElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
nsresult
nsStyledElement::ReparseStyleAttribute()
{
if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
return NS_OK;
}
const nsAttrValue* oldVal = mAttrsAndChildren.GetAttr(nsGkAtoms::style);
if (oldVal && oldVal->Type() != nsAttrValue::eCSSStyleRule) {

View File

@ -275,6 +275,15 @@ nsXULElement::Create(nsXULPrototypeElement* aPrototype, nsINodeInfo *aNodeInfo,
NS_ADDREF(element);
element->mPrototype = aPrototype;
if (aPrototype->mHasIdAttribute) {
element->SetFlags(NODE_MAY_HAVE_ID);
}
if (aPrototype->mHasClassAttribute) {
element->SetFlags(NODE_MAY_HAVE_CLASS);
}
if (aPrototype->mHasStyleAttribute) {
element->SetFlags(NODE_MAY_HAVE_STYLE);
}
NS_ASSERTION(aPrototype->mScriptTypeID != nsIProgrammingLanguage::UNKNOWN,
"Need to know the language!");
@ -1069,11 +1078,13 @@ nsXULElement::ParseAttribute(PRInt32 aNamespaceID,
// Any changes should be made to both functions.
if (aNamespaceID == kNameSpaceID_None) {
if (aAttribute == nsGkAtoms::style) {
SetFlags(NODE_MAY_HAVE_STYLE);
nsStyledElement::ParseStyleAttribute(this, aValue, aResult);
return PR_TRUE;
}
if (aAttribute == nsGkAtoms::_class) {
SetFlags(NODE_MAY_HAVE_CLASS);
aResult.ParseAtomArray(aValue);
return PR_TRUE;
}
@ -1632,6 +1643,10 @@ nsXULElement::InsertChildAt(nsIContent* aKid, PRUint32 aIndex, PRBool aNotify)
nsIAtom*
nsXULElement::GetID() const
{
if (!HasFlag(NODE_MAY_HAVE_ID)) {
return nsnull;
}
const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::id);
NS_ASSERTION(!attrVal ||
@ -1649,6 +1664,9 @@ nsXULElement::GetID() const
const nsAttrValue*
nsXULElement::GetClasses() const
{
if (!HasFlag(NODE_MAY_HAVE_CLASS)) {
return nsnull;
}
return FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::_class);
}
@ -1661,6 +1679,9 @@ nsXULElement::WalkContentStyleRules(nsRuleWalker* aRuleWalker)
nsICSSStyleRule*
nsXULElement::GetInlineStyleRule()
{
if (!HasFlag(NODE_MAY_HAVE_STYLE)) {
return nsnull;
}
// Fetch the cached style rule from the attributes.
const nsAttrValue* attrVal = FindLocalOrProtoAttr(kNameSpaceID_None, nsGkAtoms::style);
@ -1674,6 +1695,7 @@ nsXULElement::GetInlineStyleRule()
NS_IMETHODIMP
nsXULElement::SetInlineStyleRule(nsICSSStyleRule* aStyleRule, PRBool aNotify)
{
SetFlags(NODE_MAY_HAVE_STYLE);
PRBool modification = PR_FALSE;
nsAutoString oldValueStr;
@ -1887,6 +1909,7 @@ nsXULElement::GetStyle(nsIDOMCSSStyleDeclaration** aStyle)
rv = gCSSOMFactory->CreateDOMCSSAttributeDeclaration(this,
getter_AddRefs(slots->mStyle));
NS_ENSURE_SUCCESS(rv, rv);
SetFlags(NODE_MAY_HAVE_STYLE);
}
NS_IF_ADDREF(*aStyle = slots->mStyle);
@ -2470,7 +2493,10 @@ nsXULPrototypeElement::Deserialize(nsIObjectInputStream* aStream,
nsresult rv;
// Read script language
rv = aStream->Read32(&mScriptTypeID);
PRUint32 scriptId = 0;
rv = aStream->Read32(&scriptId);
mScriptTypeID = scriptId;
// Read Node Info
PRUint32 number;
rv |= aStream->Read32(&number);
@ -2610,6 +2636,7 @@ nsXULPrototypeElement::SetAttrAt(PRUint32 aPos, const nsAString& aValue,
if (mAttributes[aPos].mName.Equals(nsGkAtoms::id) &&
!aValue.IsEmpty()) {
mHasIdAttribute = PR_TRUE;
// Store id as atom.
// id="" means that the element has no id. Not that it has
// emptystring as id.
@ -2618,12 +2645,14 @@ nsXULPrototypeElement::SetAttrAt(PRUint32 aPos, const nsAString& aValue,
return NS_OK;
}
else if (mAttributes[aPos].mName.Equals(nsGkAtoms::_class)) {
mHasClassAttribute = PR_TRUE;
// Compute the element's class list
mAttributes[aPos].mValue.ParseAtomArray(aValue);
return NS_OK;
}
else if (mAttributes[aPos].mName.Equals(nsGkAtoms::style)) {
mHasStyleAttribute = PR_TRUE;
// Parse the element's 'style' attribute
nsCOMPtr<nsICSSStyleRule> rule;
nsICSSParser* parser = GetCSSParser();

View File

@ -246,6 +246,9 @@ public:
mChildren(nsnull),
mNumAttributes(0),
mAttributes(nsnull),
mHasIdAttribute(PR_FALSE),
mHasClassAttribute(PR_FALSE),
mHasStyleAttribute(PR_FALSE),
mScriptTypeID(nsIProgrammingLanguage::UNKNOWN)
{
NS_LOG_ADDREF(this, 1, ClassName(), ClassSize());
@ -298,12 +301,16 @@ public:
PRUint32 mNumAttributes;
nsXULPrototypeAttribute* mAttributes; // [OWNER]
PRPackedBool mHasIdAttribute:1;
PRPackedBool mHasClassAttribute:1;
PRPackedBool mHasStyleAttribute:1;
// The language ID can not be set on a per-node basis, but is tracked
// so that the language ID from the originating root can be used
// (eg, when a node from an overlay ends up in our document, that node
// must use its original script language, not our document's default.
PRUint32 mScriptTypeID;
PRUint16 mScriptTypeID;
static void ReleaseGlobals()
{
NS_IF_RELEASE(sCSSParser);

View File

@ -855,7 +855,9 @@ XULContentSinkImpl::SetElementScriptType(nsXULPrototypeElement* element,
// Ask the top-node for its script type (which has already
// had this function called for it - so no need to recurse
// until we find it)
rv = mContextStack.GetTopNodeScriptType(&element->mScriptTypeID);
PRUint32 scriptId = 0;
rv = mContextStack.GetTopNodeScriptType(&scriptId);
element->mScriptTypeID = scriptId;
}
}
return rv;