diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 3e7e163b0136..544ef374c204 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2341,6 +2341,10 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId, NS_ENSURE_ARG_POINTER(aReturn); *aReturn = nsnull; + // 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, @@ -2349,6 +2353,31 @@ nsHTMLDocument::GetElementById(const nsAString& aElementId, nsIContent *e = entry->mIdContent; + if (e == ID_NOT_IN_DOCUMENT) { + // Now we have to flush. It could be that we have a cached "not in + // document" but more content has been added to the document since. Note + // that we have to flush notifications, so that the entry will get updated + // properly. + + // Make sure to stash away the current generation so we can check whether + // the table changes when we flush. + PRUint32 generation = mIdAndNameHashTable.generation; + + FlushPendingNotifications(Flush_ContentAndNotify); + + if (generation != mIdAndNameHashTable.generation) { + // Table changed, so the entry pointer is no longer valid; look up the + // entry again, adding if necessary (the adding may be necessary in case + // the flush actually deleted entries). + entry = + NS_STATIC_CAST(IdAndNameMapEntry *, + PL_DHashTableOperate(&mIdAndNameHashTable, &aElementId, + PL_DHASH_ADD)); + NS_ENSURE_TRUE(entry, NS_ERROR_OUT_OF_MEMORY); + e = entry->mIdContent; + } + } + if (e == ID_NOT_IN_DOCUMENT) { // We've looked for this id before and we didn't find it, so it // won't be in the document now either (since the @@ -3226,7 +3255,10 @@ nsHTMLDocument::ResolveName(const nsAString& aName, // table changes when we flush. PRUint32 generation = mIdAndNameHashTable.generation; - FlushPendingNotifications(Flush_Content); + // If we already have an entry->mContentList, we need to flush out + // notifications too, so that it will get updated properly. + FlushPendingNotifications(entry->mContentList ? + Flush_ContentAndNotify : Flush_Content); if (generation != mIdAndNameHashTable.generation) { // Table changed, so the entry pointer is no longer valid; look up the