Switch the name and id hashtable from strings to atoms. Atomize names in

general.  Bug 315771, r=sicking, sr=jst
This commit is contained in:
bzbarsky%mit.edu 2005-11-16 02:55:29 +00:00
parent 776e34abab
commit b7345ce6a8
6 changed files with 125 additions and 140 deletions

View File

@ -203,6 +203,12 @@ public:
static nsIContent* MatchElementId(nsIContent *aContent,
const nsAString& aId);
/**
* Similar to above, but to be used if one already has an atom for the ID
*/
static nsIContent* MatchElementId(nsIContent *aContent,
nsIAtom* aId);
/**
* Given a URI containing an element reference (#whatever),
* resolve it to the target content element with the given ID.

View File

@ -449,9 +449,7 @@ nsContentList::NamedItem(const nsAString& aName, PRBool aDoFlush)
PRInt32 i, count = mElements.Count();
// Typically IDs are atomized and names are not
// XXXbz this might change if we start atomizing more random attr
// values in HTML like we do in XUL!
// Typically IDs and names are atomized
nsCOMPtr<nsIAtom> name = do_GetAtom(aName);
NS_ENSURE_TRUE(name, nsnull);
@ -461,7 +459,7 @@ nsContentList::NamedItem(const nsAString& aName, PRBool aDoFlush)
// XXX Should this pass eIgnoreCase?
if (content &&
(content->AttrValueIs(kNameSpaceID_None, nsHTMLAtoms::name,
aName, eCaseMatters) ||
name, eCaseMatters) ||
content->AttrValueIs(kNameSpaceID_None, nsHTMLAtoms::id,
name, eCaseMatters))) {
return content;

View File

@ -2493,12 +2493,11 @@ nsContentUtils::DispatchTrustedEvent(nsIDocument* aDoc, nsISupports* aTarget,
return target->DispatchEvent(event, aDefaultAction ? aDefaultAction : &dummy);
}
static nsIContent*
MatchElementId(nsIContent *aContent, nsIAtom* aId)
/* static */
nsIContent*
nsContentUtils::MatchElementId(nsIContent *aContent, nsIAtom* aId)
{
nsIAtom* idAttrName = aContent->GetIDAttributeName();
if (idAttrName && aContent->AttrValueIs(kNameSpaceID_None, idAttrName, aId,
eCaseMatters)) {
if (aId == aContent->GetID()) {
return aContent;
}
@ -2527,7 +2526,7 @@ nsContentUtils::MatchElementId(nsIContent *aContent, const nsAString& aId)
return nsnull;
}
return ::MatchElementId(aContent, id);
return MatchElementId(aContent, id);
}
// Convert the string from the given charset to Unicode.

View File

@ -2049,6 +2049,13 @@ nsGenericHTMLElement::ParseAttribute(nsIAtom* aAttribute,
return aResult.ParseIntWithBounds(aValue, -32768, 32767);
}
if (aAttribute == nsHTMLAtoms::name && !aValue.IsEmpty()) {
// Store name as an atom. name="" means that the element has no name,
// not that it has an emptystring as the name.
aResult.ParseAtom(aValue);
return PR_TRUE;
}
return nsGenericElement::ParseAttribute(aAttribute, aValue, aResult);
}

View File

@ -154,8 +154,9 @@ static NS_DEFINE_CID(kCookieServiceCID, NS_COOKIESERVICE_CID);
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
static NS_DEFINE_CID(kCharsetAliasCID, NS_CHARSETALIAS_CID);
static PRBool
IsNamedItem(nsIContent* aContent, nsIAtom *aTag, nsAString& aName);
// Returns the name atom of aContent, if the content is a named item
// and has a name atom.
static nsIAtom* IsNamedItem(nsIContent* aContent);
static NS_DEFINE_CID(kCParserCID, NS_PARSER_CID);
@ -206,8 +207,8 @@ NS_NewHTMLDocument(nsIDocument** aInstancePtrResult)
class IdAndNameMapEntry : public PLDHashEntryHdr
{
public:
IdAndNameMapEntry(const nsAString& aString) :
mKey(aString), mNameContentList(nsnull), mIdContentList()
IdAndNameMapEntry(nsIAtom* aKey) :
mKey(aKey), mNameContentList(nsnull), mIdContentList()
{
}
@ -238,7 +239,7 @@ public:
mIdContentList.AppendElement(ID_NOT_IN_DOCUMENT);
}
nsString mKey;
nsCOMPtr<nsIAtom> mKey;
nsBaseContentList *mNameContentList;
private:
nsSmallVoidArray mIdContentList;
@ -275,15 +276,14 @@ IdAndNameHashGetKey(PLDHashTable *table, PLDHashEntryHdr *entry)
{
IdAndNameMapEntry *e = NS_STATIC_CAST(IdAndNameMapEntry *, entry);
return NS_STATIC_CAST(const nsAString *, &e->mKey);
return NS_STATIC_CAST(const nsIAtom *, e->mKey);
}
PR_STATIC_CALLBACK(PLDHashNumber)
IdAndNameHashHashKey(PLDHashTable *table, const void *key)
{
const nsAString *str = NS_STATIC_CAST(const nsAString *, key);
return HashString(*str);
// Our key is an nsIAtom*, so just shift it and use that as the hash.
return NS_PTR_TO_INT32(key) >> 2;
}
PR_STATIC_CALLBACK(PRBool)
@ -292,9 +292,9 @@ IdAndNameHashMatchEntry(PLDHashTable *table, const PLDHashEntryHdr *entry,
{
const IdAndNameMapEntry *e =
NS_STATIC_CAST(const IdAndNameMapEntry *, entry);
const nsAString *str = NS_STATIC_CAST(const nsAString *, key);
const nsIAtom *atom = NS_STATIC_CAST(const nsIAtom *, key);
return str->Equals(e->mKey);
return atom == e->mKey;
}
PR_STATIC_CALLBACK(void)
@ -310,10 +310,11 @@ PR_STATIC_CALLBACK(PRBool)
IdAndNameHashInitEntry(PLDHashTable *table, PLDHashEntryHdr *entry,
const void *key)
{
const nsAString *keyStr = NS_STATIC_CAST(const nsAString *, key);
nsIAtom *atom = NS_CONST_CAST(nsIAtom *,
NS_STATIC_CAST(const nsIAtom*, key));
// Inititlize the entry with placement new
new (entry) IdAndNameMapEntry(*keyStr);
new (entry) IdAndNameMapEntry(atom);
return PR_TRUE;
}
@ -1182,10 +1183,9 @@ nsHTMLDocument::AttributeWillChange(nsIContent* aContent, PRInt32 aNameSpaceID,
if (!IsXHTML() && aAttribute == nsHTMLAtoms::name &&
aNameSpaceID == kNameSpaceID_None) {
nsAutoString value;
if (IsNamedItem(aContent, aContent->Tag(), value)) {
nsresult rv = RemoveFromNameTable(value, aContent);
nsIAtom* name = IsNamedItem(aContent);
if (name) {
nsresult rv = RemoveFromNameTable(name, aContent);
if (NS_FAILED(rv)) {
return;
@ -1212,10 +1212,10 @@ nsHTMLDocument::AttributeChanged(nsIContent* aContent, PRInt32 aNameSpaceID,
if (!IsXHTML() && aAttribute == nsHTMLAtoms::name &&
aNameSpaceID == kNameSpaceID_None) {
nsAutoString value;
if (IsNamedItem(aContent, aContent->Tag(), value)) {
nsresult rv = UpdateNameTableEntry(value, aContent);
nsIAtom* name = IsNamedItem(aContent);
if (name) {
nsresult rv = UpdateNameTableEntry(name, aContent);
if (NS_FAILED(rv)) {
return;
@ -1223,14 +1223,9 @@ nsHTMLDocument::AttributeChanged(nsIContent* aContent, PRInt32 aNameSpaceID,
}
} else if (aAttribute == aContent->GetIDAttributeName() &&
aNameSpaceID == kNameSpaceID_None) {
nsAutoString value;
aContent->GetAttr(aNameSpaceID,
aContent->GetIDAttributeName(),
value);
if (!value.IsEmpty()) {
nsresult rv = AddToIdTable(value, aContent);
nsIAtom* id = aContent->GetID();
if (id) {
nsresult rv = UpdateIdTableEntry(id, aContent);
if (NS_FAILED(rv)) {
return;
@ -2368,13 +2363,16 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId,
NS_ENSURE_ARG_POINTER(aReturn);
*aReturn = nsnull;
nsCOMPtr<nsIAtom> idAtom(do_GetAtom(aElementId));
NS_ENSURE_TRUE(idAtom, NS_ERROR_OUT_OF_MEMORY);
// We don't have to flush before we do the initial hashtable lookup, since if
// the id is already in the hashtable it couldn't have been removed without
// us being notified (all removals notify immediately, as far as I can tell).
// So do the lookup first.
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aElementId,
PL_DHashTableOperate(&mIdAndNameHashTable, idAtom,
PL_DHASH_ADD));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
@ -2398,7 +2396,7 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId,
// the flush actually deleted entries).
entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aElementId,
PL_DHashTableOperate(&mIdAndNameHashTable, idAtom,
PL_DHASH_ADD));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
}
@ -2434,7 +2432,7 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId,
"getElementById(\"\") called, fix caller?");
if (mRootContent && !aElementId.IsEmpty()) {
e = nsContentUtils::MatchElementId(mRootContent, aElementId);
e = nsContentUtils::MatchElementId(mRootContent, idAtom);
}
}
@ -2444,7 +2442,7 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId,
// we'd have done just that already
if (IdTableIsLive() && mRootContent && !aElementId.IsEmpty()) {
nsIContent* eDebug =
nsContentUtils::MatchElementId(mRootContent, aElementId);
nsContentUtils::MatchElementId(mRootContent, idAtom);
NS_ASSERTION(!eDebug,
"We got null for |e| but MatchElementId found something?");
}
@ -2944,11 +2942,14 @@ nsHTMLDocument::InvalidateHashTables()
}
static nsresult
ReserveNameInHash(const nsAString& aName, PLDHashTable *aHash)
ReserveNameInHash(const char* aName, PLDHashTable *aHash)
{
nsCOMPtr<nsIAtom> atom(do_GetAtom(aName));
NS_ENSURE_TRUE(atom, NS_ERROR_OUT_OF_MEMORY);
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(aHash, &aName, PL_DHASH_ADD));
PL_DHashTableOperate(aHash, atom, PL_DHASH_ADD));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
@ -2966,65 +2967,70 @@ nsHTMLDocument::PrePopulateHashTables()
{
nsresult rv = NS_OK;
rv = ReserveNameInHash(NS_LITERAL_STRING("write"), &mIdAndNameHashTable);
rv = ReserveNameInHash("write", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("writeln"), &mIdAndNameHashTable);
rv = ReserveNameInHash("writeln", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("open"), &mIdAndNameHashTable);
rv = ReserveNameInHash("open", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("close"), &mIdAndNameHashTable);
rv = ReserveNameInHash("close", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("forms"), &mIdAndNameHashTable);
rv = ReserveNameInHash("forms", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("elements"), &mIdAndNameHashTable);
rv = ReserveNameInHash("elements", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("characterSet"),
&mIdAndNameHashTable);
rv = ReserveNameInHash("characterSet", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("nodeType"), &mIdAndNameHashTable);
rv = ReserveNameInHash("nodeType", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("parentNode"),
&mIdAndNameHashTable);
rv = ReserveNameInHash("parentNode", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
rv = ReserveNameInHash(NS_LITERAL_STRING("cookie"), &mIdAndNameHashTable);
rv = ReserveNameInHash("cookie", &mIdAndNameHashTable);
NS_ENSURE_SUCCESS(rv, rv);
return rv;
}
static PRBool
IsNamedItem(nsIContent* aContent, nsIAtom *aTag, nsAString& aName)
static nsIAtom*
IsNamedItem(nsIContent* aContent)
{
// Only the content types reflected in Level 0 with a NAME
// attribute are registered. Images, layers and forms always get
// reflected up to the document. Applets and embeds only go
// to the closest container (which could be a form).
if (aTag == nsHTMLAtoms::img ||
aTag == nsHTMLAtoms::form ||
aTag == nsHTMLAtoms::applet ||
aTag == nsHTMLAtoms::embed ||
aTag == nsHTMLAtoms::object) {
aContent->GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, aName);
if (!aName.IsEmpty()) {
return PR_TRUE;
}
nsGenericHTMLElement* elm = nsGenericHTMLElement::FromContent(aContent);
if (!elm) {
return nsnull;
}
return PR_FALSE;
nsIAtom* tag = elm->Tag();
if (tag != nsHTMLAtoms::img &&
tag != nsHTMLAtoms::form &&
tag != nsHTMLAtoms::applet &&
tag != nsHTMLAtoms::embed &&
tag != nsHTMLAtoms::object) {
return nsnull;
}
const nsAttrValue* val = elm->GetParsedAttr(nsHTMLAtoms::name);
if (val && val->Type() == nsAttrValue::eAtom) {
return val->GetAtomValue();
}
return nsnull;
}
nsresult
nsHTMLDocument::UpdateNameTableEntry(const nsAString& aName,
nsHTMLDocument::UpdateNameTableEntry(nsIAtom* aName,
nsIContent *aContent)
{
NS_ASSERTION(!IsXHTML(),
@ -3032,7 +3038,7 @@ nsHTMLDocument::UpdateNameTableEntry(const nsAString& aName,
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aName,
PL_DHashTableOperate(&mIdAndNameHashTable, aName,
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
@ -3057,29 +3063,13 @@ nsHTMLDocument::UpdateNameTableEntry(const nsAString& aName,
}
nsresult
nsHTMLDocument::AddToIdTable(const nsAString& aId, nsIContent *aContent)
{
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aId,
PL_DHASH_ADD));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
if (NS_LIKELY(entry->AddIdContent(aContent))) {
return NS_OK;
}
return NS_ERROR_OUT_OF_MEMORY;
}
nsresult
nsHTMLDocument::UpdateIdTableEntry(const nsAString& aId, nsIContent *aContent)
nsHTMLDocument::UpdateIdTableEntry(nsIAtom* aId, nsIContent *aContent)
{
PRBool liveTable = IdTableIsLive();
PLDHashOperator op = liveTable ? PL_DHASH_ADD : PL_DHASH_LOOKUP;
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aId,
PL_DHashTableOperate(&mIdAndNameHashTable, aId,
op));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
@ -3094,15 +3084,14 @@ nsHTMLDocument::UpdateIdTableEntry(const nsAString& aId, nsIContent *aContent)
}
nsresult
nsHTMLDocument::RemoveFromNameTable(const nsAString& aName,
nsIContent *aContent)
nsHTMLDocument::RemoveFromNameTable(nsIAtom* aName, nsIContent *aContent)
{
NS_ASSERTION(!IsXHTML(),
"nsHTMLDocument::RemoveFromNameTable Don't call me on an XHTML document!!!");
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aName,
PL_DHashTableOperate(&mIdAndNameHashTable, aName,
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_BUSY(entry) && entry->mNameContentList &&
@ -3116,24 +3105,15 @@ nsHTMLDocument::RemoveFromNameTable(const nsAString& aName,
nsresult
nsHTMLDocument::RemoveFromIdTable(nsIContent *aContent)
{
nsIAtom* idAttr = aContent->GetIDAttributeName();
if (!idAttr || !aContent->HasAttr(kNameSpaceID_None, idAttr)) {
return NS_OK;
}
nsIAtom* id = aContent->GetID();
nsAutoString value;
aContent->GetAttr(kNameSpaceID_None, idAttr, value);
if (value.IsEmpty()) {
if (!id) {
return NS_OK;
}
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable,
NS_STATIC_CAST(const nsAString *,
&value),
PL_DHashTableOperate(&mIdAndNameHashTable, id,
PL_DHASH_LOOKUP));
if (PL_DHASH_ENTRY_IS_FREE(entry)) {
@ -3155,14 +3135,16 @@ nsHTMLDocument::UnregisterNamedItems(nsIContent *aContent)
return NS_OK;
}
nsAutoString value;
nsresult rv = NS_OK;
if (!IsXHTML() && IsNamedItem(aContent, aContent->Tag(), value)) {
rv = RemoveFromNameTable(value, aContent);
if (!IsXHTML()) {
nsIAtom* name = IsNamedItem(aContent);
if (name) {
rv = RemoveFromNameTable(name, aContent);
if (NS_FAILED(rv)) {
return rv;
if (NS_FAILED(rv)) {
return rv;
}
}
}
@ -3189,21 +3171,19 @@ nsHTMLDocument::RegisterNamedItems(nsIContent *aContent)
return NS_OK;
}
nsAutoString value;
if (!IsXHTML() && IsNamedItem(aContent, aContent->Tag(), value)) {
UpdateNameTableEntry(value, aContent);
if (!IsXHTML()) {
nsIAtom* name = IsNamedItem(aContent);
if (name) {
UpdateNameTableEntry(name, aContent);
}
}
nsIAtom* idAttr = aContent->GetIDAttributeName();
if (idAttr) {
aContent->GetAttr(kNameSpaceID_None, idAttr, value);
if (!value.IsEmpty()) {
nsresult rv = UpdateIdTableEntry(value, aContent);
nsIAtom* id = aContent->GetID();
if (id) {
nsresult rv = UpdateIdTableEntry(id, aContent);
if (NS_FAILED(rv)) {
return rv;
}
if (NS_FAILED(rv)) {
return rv;
}
}
@ -3217,7 +3197,7 @@ nsHTMLDocument::RegisterNamedItems(nsIContent *aContent)
}
static void
FindNamedItems(const nsAString& aName, nsIContent *aContent,
FindNamedItems(nsIAtom* aName, nsIContent *aContent,
IdAndNameMapEntry& aEntry, PRBool aIsXHTML)
{
NS_ASSERTION(aEntry.mNameContentList,
@ -3232,19 +3212,14 @@ FindNamedItems(const nsAString& aName, nsIContent *aContent,
nsAutoString value;
if (!aIsXHTML && IsNamedItem(aContent, aContent->Tag(), value) &&
value.Equals(aName)) {
if (!aIsXHTML && aName == IsNamedItem(aContent)) {
aEntry.mNameContentList->AppendElement(aContent);
}
if (!aEntry.GetIdContent()) {
// Maybe this node has the right id?
nsIAtom* idAttr = aContent->GetIDAttributeName();
if (idAttr &&
aContent->AttrValueIs(kNameSpaceID_None, idAttr,
aName, eCaseMatters)) {
aEntry.AddIdContent(aContent);
}
if (!aEntry.GetIdContent() &&
// Maybe this node has the right id?
aName == aContent->GetID()) {
aEntry.AddIdContent(aContent);
}
PRUint32 i, count = aContent->GetChildCount();
@ -3267,12 +3242,14 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
return NS_OK;
}
nsCOMPtr<nsIAtom> name(do_GetAtom(aName));
// We have built a table and cache the named items. The table will
// be updated as content is added and removed.
IdAndNameMapEntry *entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aName,
PL_DHashTableOperate(&mIdAndNameHashTable, name,
PL_DHASH_ADD));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
@ -3301,7 +3278,7 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
// the flush actually deleted entries).
entry =
NS_STATIC_CAST(IdAndNameMapEntry *,
PL_DHashTableOperate(&mIdAndNameHashTable, &aName,
PL_DHashTableOperate(&mIdAndNameHashTable, name,
PL_DHASH_ADD));
NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY);
}
@ -3326,7 +3303,7 @@ nsHTMLDocument::ResolveName(const nsAString& aName,
if (mRootContent && !aName.IsEmpty()) {
// We'll never get here if !IsXHTML(), so we can just pass
// PR_FALSE to FindNamedItems().
FindNamedItems(aName, mRootContent, *entry, PR_FALSE);
FindNamedItems(name, mRootContent, *entry, PR_FALSE);
}
}

View File

@ -210,11 +210,9 @@ protected:
nsresult RegisterNamedItems(nsIContent *aContent);
nsresult UnregisterNamedItems(nsIContent *aContent);
nsresult UpdateNameTableEntry(const nsAString& aName,
nsIContent *aContent);
nsresult AddToIdTable(const nsAString& aId, nsIContent *aContent);
nsresult UpdateIdTableEntry(const nsAString& aId, nsIContent *aContent);
nsresult RemoveFromNameTable(const nsAString& aName, nsIContent *aContent);
nsresult UpdateNameTableEntry(nsIAtom* aName, nsIContent *aContent);
nsresult UpdateIdTableEntry(nsIAtom* aId, nsIContent *aContent);
nsresult RemoveFromNameTable(nsIAtom* aName, nsIContent *aContent);
nsresult RemoveFromIdTable(nsIContent *aContent);
void InvalidateHashTables();