From 291a108475dc664f407fd58a4c57ed33a6c7d93c Mon Sep 17 00:00:00 2001 From: Shawn Wilsher Date: Thu, 18 Feb 2010 10:08:54 -0800 Subject: [PATCH] Backed out changeset 06b691e8cbcd --- content/base/src/nsAttrValue.cpp | 89 +++++++++++++++++++ content/base/src/nsAttrValue.h | 14 +++ .../html/content/src/nsGenericHTMLElement.cpp | 32 ++++++- .../html/content/src/nsHTMLAnchorElement.cpp | 42 +++++++-- 4 files changed, 168 insertions(+), 9 deletions(-) diff --git a/content/base/src/nsAttrValue.cpp b/content/base/src/nsAttrValue.cpp index 15b79c81c0c5..0a42f22a0018 100644 --- a/content/base/src/nsAttrValue.cpp +++ b/content/base/src/nsAttrValue.cpp @@ -51,6 +51,7 @@ #include "nsTPtrArray.h" #include "nsContentUtils.h" #include "nsReadableUtils.h" +#include "nsIURI.h" #include "prprf.h" #ifdef MOZ_SVG #include "nsISVGValue.h" @@ -259,6 +260,11 @@ nsAttrValue::SetTo(const nsAttrValue& aOther) cont->mFloatValue = otherCont->mFloatValue; break; } + case eLazyURIValue: + { + NS_IF_ADDREF(cont->mURI = otherCont->mURI); + break; + } default: { NS_NOTREACHED("unknown type stored in MiscContainer"); @@ -441,6 +447,16 @@ nsAttrValue::ToString(nsAString& aResult) const aResult = str; break; } + // No need to do for eLazyURIValue, since that always stores the + // original string. +#ifdef DEBUG + case eLazyURIValue: + { + NS_NOTREACHED("Shouldn't get here"); + aResult.Truncate(); + break; + } +#endif default: { aResult.Truncate(); @@ -576,6 +592,17 @@ nsAttrValue::HashValue() const // XXX this is crappy, but oh well return cont->mFloatValue; } + case eLazyURIValue: + { + NS_ASSERTION(static_cast(cont->mStringBits & + NS_ATTRVALUE_BASETYPE_MASK) == + eStringBase, + "Unexpected type"); + nsStringBuffer* str = static_cast(MISC_STR_PTR(cont)); + NS_ASSERTION(str, "How did that happen?"); + PRUint32 len = str->StorageSize()/sizeof(PRUnichar) - 1; + return nsCRT::BufferHashCode(static_cast(str->Data()), len); + } default: { NS_NOTREACHED("unknown type stored in MiscContainer"); @@ -678,6 +705,11 @@ nsAttrValue::Equals(const nsAttrValue& aOther) const { return thisCont->mFloatValue == otherCont->mFloatValue; } + case eLazyURIValue: + { + needsStringComparison = PR_TRUE; + break; + } default: { NS_NOTREACHED("unknown type stored in MiscContainer"); @@ -1139,6 +1171,58 @@ PRBool nsAttrValue::ParseFloatValue(const nsAString& aString) return PR_FALSE; } +PRBool nsAttrValue::ParseLazyURIValue(const nsAString& aString) +{ + ResetIfSet(); + + if (EnsureEmptyMiscContainer()) { + MiscContainer* cont = GetMiscContainer(); + cont->mURI = nsnull; + cont->mType = eLazyURIValue; + + // Don't use SetMiscAtomOrString because atomizing URIs is not + // likely to do us much good. + nsStringBuffer* buf = GetStringBuffer(aString); + if (!buf) { + return PR_FALSE; + } + cont->mStringBits = reinterpret_cast(buf) | eStringBase; + + return PR_TRUE; + } + + return PR_FALSE; +} + +void +nsAttrValue::CacheURIValue(nsIURI* aURI) +{ + NS_PRECONDITION(Type() == eLazyURIValue, "wrong type"); + NS_PRECONDITION(!GetMiscContainer()->mURI, "Why are we being called?"); + NS_IF_ADDREF(GetMiscContainer()->mURI = aURI); +} + +void +nsAttrValue::DropCachedURI() +{ + NS_PRECONDITION(Type() == eLazyURIValue, "wrong type"); + NS_IF_RELEASE(GetMiscContainer()->mURI); +} + +const nsCheapString +nsAttrValue::GetURIStringValue() const +{ + NS_PRECONDITION(Type() == eLazyURIValue, "wrong type"); + NS_PRECONDITION(static_cast(GetMiscContainer()->mStringBits & + NS_ATTRVALUE_BASETYPE_MASK) == + eStringBase, + "Unexpected type"); + NS_PRECONDITION(MISC_STR_PTR(GetMiscContainer()), + "Should have a string buffer here!"); + return nsCheapString(static_cast + (MISC_STR_PTR(GetMiscContainer()))); +} + void nsAttrValue::SetMiscAtomOrString(const nsAString* aValue) { @@ -1204,6 +1288,11 @@ nsAttrValue::EnsureEmptyMiscContainer() break; } #endif + case eLazyURIValue: + { + NS_IF_RELEASE(cont->mURI); + break; + } default: { break; diff --git a/content/base/src/nsAttrValue.h b/content/base/src/nsAttrValue.h index 0afec7530640..c18f927ecbab 100644 --- a/content/base/src/nsAttrValue.h +++ b/content/base/src/nsAttrValue.h @@ -54,6 +54,7 @@ typedef PRUptrdiff PtrBits; class nsAString; class nsIAtom; class nsICSSStyleRule; +class nsIURI; class nsISVGValue; class nsIDocument; template class nsCOMArray; @@ -120,6 +121,7 @@ public: ,eSVGValue = 0x12 #endif ,eFloatValue = 0x13 + ,eLazyURIValue = 0x14 }; ValueType Type() const; @@ -153,6 +155,10 @@ public: inline nsISVGValue* GetSVGValue() const; #endif inline float GetFloatValue() const; + inline nsIURI* GetURIValue() const; + const nsCheapString GetURIStringValue() const; + void CacheURIValue(nsIURI* aURI); + void DropCachedURI(); // Methods to get access to atoms we may have // Returns the number of atoms we have; 0 if we have none. It's OK @@ -291,6 +297,7 @@ private: nsISVGValue* mSVGValue; #endif float mFloatValue; + nsIURI* mURI; }; }; @@ -397,6 +404,13 @@ nsAttrValue::GetFloatValue() const return GetMiscContainer()->mFloatValue; } +inline nsIURI* +nsAttrValue::GetURIValue() const +{ + NS_PRECONDITION(Type() == eLazyURIValue, "wrong type"); + return GetMiscContainer()->mURI; +} + inline nsAttrValue::ValueBaseType nsAttrValue::BaseType() const { diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp index 171fb3aa86c0..185bb01d3523 100644 --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -2108,6 +2108,19 @@ nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, return PR_FALSE; } + PRBool isURIAttr = (attr->Type() == nsAttrValue::eLazyURIValue); + + if (isURIAttr && (*aURI = attr->GetURIValue())) { + if (aCloneIfCached) { + nsIURI* clone = nsnull; + (*aURI)->Clone(&clone); + *aURI = clone; + } else { + NS_ADDREF(*aURI); + } + return PR_TRUE; + } + nsCOMPtr baseURI = GetBaseURI(); if (aBaseAttr) { @@ -2128,8 +2141,18 @@ nsGenericHTMLElement::GetURIAttr(nsIAtom* aAttr, nsIAtom* aBaseAttr, // Don't care about return value. If it fails, we still want to // return PR_TRUE, and *aURI will be null. nsContentUtils::NewURIWithDocumentCharset(aURI, - attr->GetStringValue(), + isURIAttr ? + attr->GetURIStringValue() : + attr->GetStringValue(), GetOwnerDoc(), baseURI); + + // We may have to re-resolve all our cached hrefs when the document's base + // URI changes. The base URI depends on the owner document, but it's the + // current document that keeps track of links. If the two documents don't + // match, we shouldn't cache. + if (isURIAttr && GetOwnerDoc() == GetCurrentDoc()) { + const_cast(attr)->CacheURIValue(*aURI); + } return PR_TRUE; } @@ -2997,6 +3020,13 @@ nsGenericHTMLElement::SetHrefToURI(nsIURI* aURI) nsCAutoString newHref; aURI->GetSpec(newHref); SetAttrHelper(nsGkAtoms::href, NS_ConvertUTF8toUTF16(newHref)); + const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsGkAtoms::href); + // Might already have a URI value, if we didn't actually change the + // string value of our attribute. + if (attr && attr->Type() == nsAttrValue::eLazyURIValue && + !attr->GetURIValue()) { + const_cast(attr)->CacheURIValue(aURI); + } } nsresult diff --git a/content/html/content/src/nsHTMLAnchorElement.cpp b/content/html/content/src/nsHTMLAnchorElement.cpp index a8fb2666ff18..662b7147a49d 100644 --- a/content/html/content/src/nsHTMLAnchorElement.cpp +++ b/content/html/content/src/nsHTMLAnchorElement.cpp @@ -132,6 +132,9 @@ public: virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; virtual void DropCachedHref(); + +protected: + void ResetLinkCacheState(); }; @@ -219,9 +222,9 @@ nsHTMLAnchorElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent) { if (IsInDoc()) { RegUnRegAccessKey(PR_FALSE); - Link::ResetLinkState(); + ResetLinkCacheState(); } - + nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent); } @@ -436,7 +439,7 @@ nsHTMLAnchorElement::SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsAutoString val; GetHref(val); if (!val.Equals(aValue)) { - Link::ResetLinkState(); + ResetLinkCacheState(); } } @@ -460,7 +463,7 @@ nsHTMLAnchorElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRBool aNotify) { if (aAttribute == nsGkAtoms::href && kNameSpaceID_None == aNameSpaceID) { - Link::ResetLinkState(); + ResetLinkCacheState(); } if (aAttribute == nsGkAtoms::accesskey && @@ -473,10 +476,14 @@ nsHTMLAnchorElement::UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute, PRBool nsHTMLAnchorElement::ParseAttribute(PRInt32 aNamespaceID, - nsIAtom* aAttribute, - const nsAString& aValue, - nsAttrValue& aResult) + nsIAtom* aAttribute, + const nsAString& aValue, + nsAttrValue& aResult) { + if (aNamespaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::href) { + return aResult.ParseLazyURIValue(aValue); + } + return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue, aResult); } @@ -484,5 +491,24 @@ nsHTMLAnchorElement::ParseAttribute(PRInt32 aNamespaceID, void nsHTMLAnchorElement::DropCachedHref() { - Link::ResetLinkState(); + nsAttrValue* attr = + const_cast(mAttrsAndChildren.GetAttr(nsGkAtoms::href)); + + if (!attr || attr->Type() != nsAttrValue::eLazyURIValue) + return; + + attr->DropCachedURI(); +} + +void +nsHTMLAnchorElement::ResetLinkCacheState() +{ + Link::ResetLinkState(); + + // Clear our cached URI _after_ we ForgetLink(), since ForgetLink() + // wants that URI. + const nsAttrValue* attr = mAttrsAndChildren.GetAttr(nsGkAtoms::href); + if (attr && attr->Type() == nsAttrValue::eLazyURIValue) { + const_cast(attr)->DropCachedURI(); + } }