From 0babbffbf2c9a684726bab52edcaa3acdc556961 Mon Sep 17 00:00:00 2001 From: Boris Zbarsky Date: Fri, 13 Jul 2012 19:29:14 -0400 Subject: [PATCH] Bug 558516. Make getAttribute faster in the cases when we have no prefix and are in the right case. r=smaug --- content/base/public/nsContentUtils.h | 5 +++ content/base/src/nsAttrAndChildArray.cpp | 37 ++++++++++++++++++- content/base/src/nsAttrAndChildArray.h | 5 +++ content/base/src/nsContentUtils.cpp | 17 +++++++++ content/base/src/nsGenericElement.cpp | 28 +++++++++----- content/base/src/nsMappedAttributes.cpp | 37 ++++++++++--------- content/base/src/nsMappedAttributes.h | 3 +- .../html/content/src/nsGenericHTMLElement.cpp | 2 +- content/xul/content/src/nsXULElement.cpp | 23 ++++++++++++ content/xul/content/src/nsXULElement.h | 2 + 10 files changed, 128 insertions(+), 31 deletions(-) diff --git a/content/base/public/nsContentUtils.h b/content/base/public/nsContentUtils.h index df818d70dbd..4aea5f43851 100644 --- a/content/base/public/nsContentUtils.h +++ b/content/base/public/nsContentUtils.h @@ -1631,6 +1631,11 @@ public: static nsresult ASCIIToUpper(nsAString& aStr); static nsresult ASCIIToUpper(const nsAString& aSource, nsAString& aDest); + /** + * Return whether aStr contains an ASCII uppercase character. + */ + static bool StringContainsASCIIUpper(const nsAString& aStr); + // Returns NS_OK for same origin, error (NS_ERROR_DOM_BAD_URI) if not. static nsresult CheckSameOrigin(nsIChannel *aOldChannel, nsIChannel *aNewChannel); static nsIInterfaceRequestor* GetSameOriginChecker(); diff --git a/content/base/src/nsAttrAndChildArray.cpp b/content/base/src/nsAttrAndChildArray.cpp index d68c47349ad..82701bd8bf8 100644 --- a/content/base/src/nsAttrAndChildArray.cpp +++ b/content/base/src/nsAttrAndChildArray.cpp @@ -319,6 +319,39 @@ nsAttrAndChildArray::GetAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const return nsnull; } +const nsAttrValue* +nsAttrAndChildArray::GetAttr(const nsAString& aName, + nsCaseTreatment aCaseSensitive) const +{ + PRUint32 i, slotCount = AttrSlotCount(); + for (i = 0; i < slotCount && AttrSlotIsTaken(i); ++i) { + if (ATTRS(mImpl)[i].mName.QualifiedNameEquals(aName)) { + return &ATTRS(mImpl)[i].mValue; + } + } + + if (mImpl && mImpl->mMappedAttrs) { + const nsAttrValue* val = + mImpl->mMappedAttrs->GetAttr(aName); + if (val) { + return val; + } + } + + // Now check whether someone is being silly and passing + // non-lowercase attr names. + if (aCaseSensitive == eIgnoreCase && + nsContentUtils::StringContainsASCIIUpper(aName)) { + // Try again, but make sure we can't reenter this block by passing + // eCaseSensitive for aCaseSensitive. + nsAutoString lowercase; + nsContentUtils::ASCIIToLower(aName, lowercase); + return GetAttr(lowercase, eCaseMatters); + } + + return nsnull; +} + const nsAttrValue* nsAttrAndChildArray::AttrAt(PRUint32 aPos) const { @@ -490,8 +523,8 @@ PRInt32 nsAttrAndChildArray::IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const { PRInt32 idx; - if (mImpl && mImpl->mMappedAttrs) { - idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName, aNamespaceID); + if (mImpl && mImpl->mMappedAttrs && aNamespaceID == kNameSpaceID_None) { + idx = mImpl->mMappedAttrs->IndexOfAttr(aLocalName); if (idx >= 0) { return idx; } diff --git a/content/base/src/nsAttrAndChildArray.h b/content/base/src/nsAttrAndChildArray.h index ccc0cbedc62..390571f74ca 100644 --- a/content/base/src/nsAttrAndChildArray.h +++ b/content/base/src/nsAttrAndChildArray.h @@ -16,6 +16,7 @@ #include "nscore.h" #include "nsAttrName.h" #include "nsAttrValue.h" +#include "nsCaseTreatment.h" class nsINode; class nsIContent; @@ -71,6 +72,10 @@ public: PRUint32 AttrCount() const; const nsAttrValue* GetAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID = kNameSpaceID_None) const; + // Get an nsAttrValue by qualified name. Can optionally do + // ASCII-case-insensitive name matching. + const nsAttrValue* GetAttr(const nsAString& aName, + nsCaseTreatment aCaseSensitive) const; const nsAttrValue* AttrAt(PRUint32 aPos) const; nsresult SetAndTakeAttr(nsIAtom* aLocalName, nsAttrValue& aValue); nsresult SetAndTakeAttr(nsINodeInfo* aName, nsAttrValue& aValue); diff --git a/content/base/src/nsContentUtils.cpp b/content/base/src/nsContentUtils.cpp index 3bd27f9f222..57b7ae00231 100644 --- a/content/base/src/nsContentUtils.cpp +++ b/content/base/src/nsContentUtils.cpp @@ -5635,6 +5635,23 @@ nsContentUtils::EqualsLiteralIgnoreASCIICase(const nsAString& aStr1, return true; } +/* static */ +bool +nsContentUtils::StringContainsASCIIUpper(const nsAString& aStr) +{ + const PRUnichar* iter = aStr.BeginReading(); + const PRUnichar* end = aStr.EndReading(); + while (iter != end) { + PRUnichar c = *iter; + if (c >= 'A' && c <= 'Z') { + return true; + } + ++iter; + } + + return false; +} + /* static */ nsIInterfaceRequestor* nsContentUtils::GetSameOriginChecker() diff --git a/content/base/src/nsGenericElement.cpp b/content/base/src/nsGenericElement.cpp index 826cbf1ba63..41e3419345d 100644 --- a/content/base/src/nsGenericElement.cpp +++ b/content/base/src/nsGenericElement.cpp @@ -1536,22 +1536,30 @@ nsresult nsGenericElement::GetAttribute(const nsAString& aName, nsAString& aReturn) { - const nsAttrName* name = InternalGetExistingAttrNameFromQName(aName); - - if (!name) { - if (mNodeInfo->NamespaceID() == kNameSpaceID_XUL) { + // I hate XUL + if (IsXUL()) { + const nsAttrValue* val = + nsXULElement::FromContent(this)->GetAttrValue(aName); + if (val) { + val->ToString(aReturn); + } + else { // XXX should be SetDOMStringToNull(aReturn); // See bug 232598 aReturn.Truncate(); } - else { - SetDOMStringToNull(aReturn); - } - return NS_OK; } - - GetAttr(name->NamespaceID(), name->LocalName(), aReturn); + + const nsAttrValue* val = + mAttrsAndChildren.GetAttr(aName, + IsHTML() && IsInHTMLDocument() ? + eIgnoreCase : eCaseMatters); + if (val) { + val->ToString(aReturn); + } else { + SetDOMStringToNull(aReturn); + } return NS_OK; } diff --git a/content/base/src/nsMappedAttributes.cpp b/content/base/src/nsMappedAttributes.cpp index 2aa8d4b1c70..e2945f89f5f 100644 --- a/content/base/src/nsMappedAttributes.cpp +++ b/content/base/src/nsMappedAttributes.cpp @@ -113,9 +113,22 @@ nsMappedAttributes::GetAttr(nsIAtom* aAttrName) const { NS_PRECONDITION(aAttrName, "null name"); - PRInt32 i = IndexOfAttr(aAttrName, kNameSpaceID_None); - if (i >= 0) { - return &Attrs()[i].mValue; + for (PRUint32 i = 0; i < mAttrCount; ++i) { + if (Attrs()[i].mName.Equals(aAttrName)) { + return &Attrs()[i].mValue; + } + } + + return nsnull; +} + +const nsAttrValue* +nsMappedAttributes::GetAttr(const nsAString& aAttrName) const +{ + for (PRUint32 i = 0; i < mAttrCount; ++i) { + if (Attrs()[i].mName.Atom()->Equals(aAttrName)) { + return &Attrs()[i].mValue; + } } return nsnull; @@ -228,22 +241,12 @@ nsMappedAttributes::GetExistingAttrNameFromQName(const nsAString& aName) const } PRInt32 -nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const +nsMappedAttributes::IndexOfAttr(nsIAtom* aLocalName) const { PRUint32 i; - if (aNamespaceID == kNameSpaceID_None) { - // This should be the common case so lets make an optimized loop - for (i = 0; i < mAttrCount; ++i) { - if (Attrs()[i].mName.Equals(aLocalName)) { - return i; - } - } - } - else { - for (i = 0; i < mAttrCount; ++i) { - if (Attrs()[i].mName.Equals(aLocalName, aNamespaceID)) { - return i; - } + for (i = 0; i < mAttrCount; ++i) { + if (Attrs()[i].mName.Equals(aLocalName)) { + return i; } } diff --git a/content/base/src/nsMappedAttributes.h b/content/base/src/nsMappedAttributes.h index 3a771f48d47..5eebd64411e 100644 --- a/content/base/src/nsMappedAttributes.h +++ b/content/base/src/nsMappedAttributes.h @@ -34,6 +34,7 @@ public: nsresult SetAndTakeAttr(nsIAtom* aAttrName, nsAttrValue& aValue); const nsAttrValue* GetAttr(nsIAtom* aAttrName) const; + const nsAttrValue* GetAttr(const nsAString& aAttrName) const; PRUint32 Count() const { @@ -67,7 +68,7 @@ public: // aValue; any value that was already in aValue is destroyed. void RemoveAttrAt(PRUint32 aPos, nsAttrValue& aValue); const nsAttrName* GetExistingAttrNameFromQName(const nsAString& aName) const; - PRInt32 IndexOfAttr(nsIAtom* aLocalName, PRInt32 aNamespaceID) const; + PRInt32 IndexOfAttr(nsIAtom* aLocalName) const; // nsIStyleRule diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 480a37a9972..4b3645e5670 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -2449,7 +2449,7 @@ nsGenericHTMLElement::MapCommonAttributesInto(const nsMappedAttributes* aAttribu if (aData->mSIDs & NS_STYLE_INHERIT_BIT(Display)) { nsCSSValue* display = aData->ValueForDisplay(); if (display->GetUnit() == eCSSUnit_Null) { - if (aAttributes->IndexOfAttr(nsGkAtoms::hidden, kNameSpaceID_None) >= 0) { + if (aAttributes->IndexOfAttr(nsGkAtoms::hidden) >= 0) { display->SetIntValue(NS_STYLE_DISPLAY_NONE, eCSSUnit_Enumerated); } } diff --git a/content/xul/content/src/nsXULElement.cpp b/content/xul/content/src/nsXULElement.cpp index 0b41f98d42d..d1920c0f137 100644 --- a/content/xul/content/src/nsXULElement.cpp +++ b/content/xul/content/src/nsXULElement.cpp @@ -1160,6 +1160,29 @@ nsXULElement::InternalGetExistingAttrNameFromQName(const nsAString& aStr) const return nsnull; } +const nsAttrValue* +nsXULElement::GetAttrValue(const nsAString& aName) +{ + MOZ_ASSERT(!IsXUL(), "XUL does its own thing here"); + const nsAttrValue* val = + mAttrsAndChildren.GetAttr(aName, eCaseMatters); + if (val) { + return val; + } + + if (mPrototype) { + PRUint32 i, count = mPrototype->mNumAttributes; + for (i = 0; i < count; ++i) { + nsXULPrototypeAttribute *protoAttr = &mPrototype->mAttributes[i]; + if (protoAttr->mName.QualifiedNameEquals(aName)) { + return &protoAttr->mValue; + } + } + } + + return nsnull; +} + bool nsXULElement::GetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsAString& aResult) const diff --git a/content/xul/content/src/nsXULElement.h b/content/xul/content/src/nsXULElement.h index 0c281277680..6230367519c 100644 --- a/content/xul/content/src/nsXULElement.h +++ b/content/xul/content/src/nsXULElement.h @@ -488,6 +488,8 @@ public: mBindingParent = aBindingParent; } + const nsAttrValue* GetAttrValue(const nsAString& aName); + /** * Get the attr info for the given namespace ID and attribute name. * The namespace ID must not be kNameSpaceID_Unknown and the name