Bug 558516. Make getAttribute faster in the cases when we have no prefix and are in the right case. r=smaug

This commit is contained in:
Boris Zbarsky 2012-07-13 19:29:14 -04:00
parent 83dc6c87d5
commit b09a7f11f3
10 changed files with 128 additions and 31 deletions

View File

@ -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();

View File

@ -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;
}

View File

@ -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);

View File

@ -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()

View File

@ -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;
}

View File

@ -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;
}
}

View File

@ -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

View File

@ -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);
}
}

View File

@ -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

View File

@ -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