Bug 499656. Make nsContentList have dual atoms (original case and lowercase) so that we can match non-HTML elements in HTML documents correctly. r=sicking
authorDavid Zbarsky <dzbarsky@gmail.com>
Tue, 31 Aug 2010 19:47:00 -0700
changeset 53966 3a418c95938d372184062c2529ebfffea545c10d
parent 53965 5cd99fd856d474ba22dcd27ae0b99618102cdfb1
child 53967 95ffc07b9f6ef333bcd7c1cd06b6c2e5eaeee088
push id15752
push userbzbarsky@mozilla.com
push dateWed, 15 Sep 2010 19:41:13 +0000
treeherdermozilla-central@6e0a42c4af82 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssicking
bugs499656
milestone2.0b7pre
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 499656. Make nsContentList have dual atoms (original case and lowercase) so that we can match non-HTML elements in HTML documents correctly. r=sicking
content/base/src/nsContentList.cpp
content/base/src/nsContentList.h
content/base/src/nsDocument.cpp
content/base/src/nsGenericElement.cpp
content/base/test/Makefile.in
content/base/test/test_bug499656.html
content/base/test/test_bug499656.xhtml
content/html/content/src/nsHTMLMapElement.cpp
content/html/content/src/nsHTMLTableElement.cpp
content/html/content/src/nsHTMLTableSectionElement.cpp
content/html/document/src/nsHTMLDocument.cpp
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -205,21 +205,27 @@ ContentListHashtableMatchEntry(PLDHashTa
     static_cast<const ContentListHashEntry *>(entry);
   const nsContentListKey* list1 = e->mContentList->GetKey();
   const nsContentListKey* list2 = static_cast<const nsContentListKey *>(key);
 
   return list1->Equals(*list2);
 }
 
 already_AddRefed<nsContentList>
-NS_GetContentList(nsINode* aRootNode, nsIAtom* aMatchAtom,
-                  PRInt32 aMatchNameSpaceId)
+NS_GetContentList(nsINode* aRootNode, 
+                  PRInt32  aMatchNameSpaceId,
+                  nsIAtom* aHTMLMatchAtom,
+                  nsIAtom* aXMLMatchAtom)
+                  
 {
   NS_ASSERTION(aRootNode, "content list has to have a root");
 
+  if(!aXMLMatchAtom)
+    aXMLMatchAtom = aHTMLMatchAtom;
+
   nsContentList* list = nsnull;
 
   static PLDHashTableOps hash_table_ops =
   {
     PL_DHashAllocTable,
     PL_DHashFreeTable,
     ContentListHashtableHashKey,
     ContentListHashtableMatchEntry,
@@ -238,42 +244,37 @@ NS_GetContentList(nsINode* aRootNode, ns
     if (!success) {
       gContentListHashTable.ops = nsnull;
     }
   }
   
   ContentListHashEntry *entry = nsnull;
   // First we look in our hashtable.  Then we create a content list if needed
   if (gContentListHashTable.ops) {
-    nsContentListKey hashKey(aRootNode, aMatchAtom,
-                             aMatchNameSpaceId);
+    nsContentListKey hashKey(aRootNode, aHTMLMatchAtom,
+                             aXMLMatchAtom, aMatchNameSpaceId);
     
     // A PL_DHASH_ADD is equivalent to a PL_DHASH_LOOKUP for cases
     // when the entry is already in the hashtable.
     entry = static_cast<ContentListHashEntry *>
                        (PL_DHashTableOperate(&gContentListHashTable,
                                                 &hashKey,
                                                 PL_DHASH_ADD));
     if (entry)
       list = entry->mContentList;
   }
 
   if (!list) {
     // We need to create a ContentList and add it to our new entry, if
     // we have an entry
-    list = new nsContentList(aRootNode, aMatchAtom,
-                             aMatchNameSpaceId);
+    list = new nsContentList(aRootNode, aMatchNameSpaceId,
+                             aHTMLMatchAtom, aXMLMatchAtom);
     if (entry) {
-      if (list)
-        entry->mContentList = list;
-      else
-        PL_DHashTableRawRemove(&gContentListHashTable, entry);
+      entry->mContentList = list;
     }
-
-    NS_ENSURE_TRUE(list, nsnull);
   }
 
   NS_ADDREF(list);
 
   return list;
 }
 
 // Hashtable for storing nsCacheableFuncStringContentList
@@ -380,30 +381,32 @@ NS_GetFuncStringContentList(nsINode* aRo
   // Don't cache these lists globally
 
   return list;
 }
 
 // nsContentList implementation
 
 nsContentList::nsContentList(nsINode* aRootNode,
-                             nsIAtom* aMatchAtom,
                              PRInt32 aMatchNameSpaceId,
+                             nsIAtom* aHTMLMatchAtom,
+                             nsIAtom* aXMLMatchAtom,
                              PRBool aDeep)
   : nsBaseContentList(),
-    nsContentListKey(aRootNode, aMatchAtom, aMatchNameSpaceId),
+    nsContentListKey(aRootNode, aHTMLMatchAtom, aXMLMatchAtom, aMatchNameSpaceId),
     mFunc(nsnull),
     mDestroyFunc(nsnull),
     mData(nsnull),
     mState(LIST_DIRTY),
     mDeep(aDeep),
     mFuncMayDependOnAttr(PR_FALSE)
 {
   NS_ASSERTION(mRootNode, "Must have root");
-  if (nsGkAtoms::_asterix == mMatchAtom) {
+  if (nsGkAtoms::_asterix == mHTMLMatchAtom) {
+    NS_ASSERTION(mXMLMatchAtom == nsGkAtoms::_asterix, "HTML atom and XML atom are not both asterix?");
     mMatchAll = PR_TRUE;
   }
   else {
     mMatchAll = PR_FALSE;
   }
   mRootNode->AddMutationObserver(this);
 }
 
@@ -411,17 +414,17 @@ nsContentList::nsContentList(nsINode* aR
                              nsContentListMatchFunc aFunc,
                              nsContentListDestroyFunc aDestroyFunc,
                              void* aData,
                              PRBool aDeep,
                              nsIAtom* aMatchAtom,
                              PRInt32 aMatchNameSpaceId,
                              PRBool aFuncMayDependOnAttr)
   : nsBaseContentList(),
-    nsContentListKey(aRootNode, aMatchAtom, aMatchNameSpaceId),
+    nsContentListKey(aRootNode, aMatchAtom, aMatchAtom, aMatchNameSpaceId),
     mFunc(aFunc),
     mDestroyFunc(aDestroyFunc),
     mData(aData),
     mMatchAll(PR_FALSE),
     mState(LIST_DIRTY),
     mDeep(aDeep),
     mFuncMayDependOnAttr(aFuncMayDependOnAttr)
 {
@@ -768,35 +771,49 @@ nsContentList::ContentRemoved(nsIDocumen
 
   ASSERT_IN_SYNC;
 }
 
 PRBool
 nsContentList::Match(Element *aElement)
 {
   if (mFunc) {
-    return (*mFunc)(aElement, mMatchNameSpaceId, mMatchAtom, mData);
+    return (*mFunc)(aElement, mMatchNameSpaceId, mXMLMatchAtom, mData);
   }
 
-  if (mMatchAtom) {
-    nsINodeInfo *ni = aElement->NodeInfo();
+  if (!mXMLMatchAtom)
+    return PR_FALSE;
 
-    if (mMatchNameSpaceId == kNameSpaceID_Unknown) {
-      return (mMatchAll || ni->QualifiedNameEquals(mMatchAtom));
-    }
+  nsINodeInfo *ni = aElement->NodeInfo();
+ 
+  PRBool unknown = mMatchNameSpaceId == kNameSpaceID_Unknown;
+  PRBool wildcard = mMatchNameSpaceId == kNameSpaceID_Wildcard;
+  PRBool toReturn = mMatchAll;
+  if (!unknown && !wildcard)
+    toReturn &= ni->NamespaceEquals(mMatchNameSpaceId);
+
+  if (toReturn)
+    return toReturn;
 
-    if (mMatchNameSpaceId == kNameSpaceID_Wildcard) {
-      return (mMatchAll || ni->Equals(mMatchAtom));
-    }
-
-    return ((mMatchAll && ni->NamespaceEquals(mMatchNameSpaceId)) ||
-            ni->Equals(mMatchAtom, mMatchNameSpaceId));
+  nsIDocument* doc = aElement->GetOwnerDoc();
+  PRBool matchHTML = aElement->GetNameSpaceID() == kNameSpaceID_XHTML &&
+    doc && doc->IsHTML();
+ 
+  if (unknown) {
+    return matchHTML ? ni->QualifiedNameEquals(mHTMLMatchAtom) :
+                       ni->QualifiedNameEquals(mXMLMatchAtom);
   }
-
-  return PR_FALSE;
+  
+  if (wildcard) {
+    return matchHTML ? ni->Equals(mHTMLMatchAtom) :
+                       ni->Equals(mXMLMatchAtom);
+  }
+  
+  return matchHTML ? ni->Equals(mHTMLMatchAtom, mMatchNameSpaceId) :
+                     ni->Equals(mXMLMatchAtom, mMatchNameSpaceId);
 }
 
 PRBool 
 nsContentList::MatchSelf(nsIContent *aContent)
 {
   NS_PRECONDITION(aContent, "Can't match null stuff, you know");
   NS_PRECONDITION(mDeep || aContent->GetNodeParent() == mRootNode,
                   "MatchSelf called on a node that we can't possibly match");
--- a/content/base/src/nsContentList.h
+++ b/content/base/src/nsContentList.h
@@ -139,48 +139,57 @@ public:
 /**
  * Class that's used as the key to hash nsContentList implementations
  * for fast retrieval
  */
 class nsContentListKey
 {
 public:
   nsContentListKey(nsINode* aRootNode,
-                   nsIAtom* aMatchAtom, 
+                   nsIAtom* aHTMLMatchAtom,
+                   nsIAtom* aXMLMatchAtom,
                    PRInt32 aMatchNameSpaceId)
-    : mMatchAtom(aMatchAtom),
+    : mHTMLMatchAtom(aHTMLMatchAtom),
+      mXMLMatchAtom(aXMLMatchAtom),
       mMatchNameSpaceId(aMatchNameSpaceId),
       mRootNode(aRootNode)
   {
+    NS_ASSERTION(!aXMLMatchAtom == !aHTMLMatchAtom, "Either neither or both atoms should be null");
   }
   
   nsContentListKey(const nsContentListKey& aContentListKey)
-    : mMatchAtom(aContentListKey.mMatchAtom),
+    : mHTMLMatchAtom(aContentListKey.mHTMLMatchAtom),
+      mXMLMatchAtom(aContentListKey.mXMLMatchAtom),
       mMatchNameSpaceId(aContentListKey.mMatchNameSpaceId),
       mRootNode(aContentListKey.mRootNode)
   {
   }
 
   PRBool Equals(const nsContentListKey& aContentListKey) const
   {
+    NS_ASSERTION(mHTMLMatchAtom == aContentListKey.mHTMLMatchAtom 
+                 || mXMLMatchAtom != aContentListKey.mXMLMatchAtom, "HTML atoms should match if XML atoms match");
+
     return
-      mMatchAtom == aContentListKey.mMatchAtom &&
+      mXMLMatchAtom == aContentListKey.mXMLMatchAtom &&
       mMatchNameSpaceId == aContentListKey.mMatchNameSpaceId &&
       mRootNode == aContentListKey.mRootNode;
   }
+
   inline PRUint32 GetHash(void) const
   {
     return
-      NS_PTR_TO_INT32(mMatchAtom.get()) ^
+      NS_PTR_TO_INT32(mXMLMatchAtom.get()) ^
       (NS_PTR_TO_INT32(mRootNode) << 12) ^
       (mMatchNameSpaceId << 24);
   }
   
 protected:
-  nsCOMPtr<nsIAtom> mMatchAtom;
+  nsCOMPtr<nsIAtom> mHTMLMatchAtom;
+  nsCOMPtr<nsIAtom> mXMLMatchAtom;
   PRInt32 mMatchNameSpaceId;
   nsINode* mRootNode; // Weak ref
 };
 
 /**
  * LIST_UP_TO_DATE means that the list is up to date and need not do
  * any walking to be able to answer any questions anyone may have.
  */
@@ -225,18 +234,19 @@ public:
    *                          Otherwise we match nodes whose namespace is
    *                          aMatchNameSpaceId and localName matches
    *                          aMatchAtom.
    * @param aDeep If false, then look only at children of the root, nothing
    *              deeper.  If true, then look at the whole subtree rooted at
    *              our root.
    */  
   nsContentList(nsINode* aRootNode,
-                nsIAtom* aMatchAtom, 
                 PRInt32 aMatchNameSpaceId,
+                nsIAtom* aHTMLMatchAtom,
+                nsIAtom* aXMLMatchAtom,
                 PRBool aDeep = PR_TRUE);
 
   /**
    * @param aRootNode The node under which to limit our search.
    * @param aFunc the function to be called to determine whether we match.
    *              This function MUST NOT ever cause mutation of the DOM.
    *              The nsContentList implementation guarantees that everything
    *              passed to the function will be IsElement().
@@ -480,18 +490,20 @@ protected:
     RemoveFromFuncStringHashtable();
   }
   void RemoveFromFuncStringHashtable();
 
   nsString mString;
 };
 
 already_AddRefed<nsContentList>
-NS_GetContentList(nsINode* aRootNode, nsIAtom* aMatchAtom,
-                  PRInt32 aMatchNameSpaceId);
+NS_GetContentList(nsINode* aRootNode,
+                  PRInt32 aMatchNameSpaceId,
+                  nsIAtom* aHTMLMatchAtom,
+                  nsIAtom* aXMLMatchAtom = nsnull);
 
 already_AddRefed<nsContentList>
 NS_GetFuncStringContentList(nsINode* aRootNode,
                             nsContentListMatchFunc aFunc,
                             nsContentListDestroyFunc aDestroyFunc,
                             nsFuncStringContentListDataAllocator aDataAllocator,
                             const nsAString& aString);
 #endif // nsContentList_h___
--- a/content/base/src/nsDocument.cpp
+++ b/content/base/src/nsDocument.cpp
@@ -4591,28 +4591,22 @@ nsDocument::CreateEntityReference(const 
 
   *aReturn = nsnull;
   return NS_OK;
 }
 
 already_AddRefed<nsContentList>
 nsDocument::GetElementsByTagName(const nsAString& aTagname)
 {
-  nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aTagname);
-  if (IsHTML()) {
-    nsAutoString tmp(aTagname);
-    ToLowerCase(tmp); // HTML elements are lower case internally.
-    nameAtom = do_GetAtom(tmp);
-  }
-  else {
-    nameAtom = do_GetAtom(aTagname);
-  }
-  NS_ENSURE_TRUE(nameAtom, nsnull);
-
-  return NS_GetContentList(this, nameAtom, kNameSpaceID_Unknown);
+  nsAutoString lowercaseName;
+  nsContentUtils::ASCIIToLower(aTagname, lowercaseName);
+  nsCOMPtr<nsIAtom> xmlAtom = do_GetAtom(aTagname);
+  nsCOMPtr<nsIAtom> htmlAtom = do_GetAtom(lowercaseName);
+
+  return NS_GetContentList(this, kNameSpaceID_Unknown, htmlAtom, xmlAtom);
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementsByTagName(const nsAString& aTagname,
                                  nsIDOMNodeList** aReturn)
 {
   nsRefPtr<nsContentList> list = GetElementsByTagName(aTagname);
   NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
@@ -4631,19 +4625,18 @@ nsDocument::GetElementsByTagNameNS(const
   if (!aNamespaceURI.EqualsLiteral("*")) {
     nsresult rv =
       nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
                                                             nameSpaceId);
     NS_ENSURE_SUCCESS(rv, nsnull);
   }
 
   nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aLocalName);
-  NS_ENSURE_TRUE(nameAtom, nsnull);
-
-  return NS_GetContentList(this, nameAtom, nameSpaceId);
+
+  return NS_GetContentList(this, nameSpaceId, nameAtom);
 }
 
 NS_IMETHODIMP
 nsDocument::GetElementsByTagNameNS(const nsAString& aNamespaceURI,
                                    const nsAString& aLocalName,
                                    nsIDOMNodeList** aReturn)
 {
   nsRefPtr<nsContentList> list = GetElementsByTagNameNS(aNamespaceURI,
@@ -5200,19 +5193,17 @@ nsDocument::GetTitleContent(PRUint32 aNa
   // <title> element has been bound to this document. So if it's false,
   // we know there is nothing to do here. This avoids us having to search
   // the whole DOM if someone calls document.title on a large document
   // without a title.
   if (!mMayHaveTitleElement)
     return nsnull;
 
   nsRefPtr<nsContentList> list =
-    NS_GetContentList(this, nsGkAtoms::title, aNamespace);
-  if (!list)
-    return nsnull;
+    NS_GetContentList(this, aNamespace, nsGkAtoms::title);
 
   return list->Item(0, PR_FALSE);
 }
 
 void
 nsDocument::GetTitleFromElement(PRUint32 aNamespace, nsAString& aTitle)
 {
   nsIContent* title = GetTitleContent(aNamespace);
@@ -7403,26 +7394,24 @@ nsDocument::OnPageShow(PRBool aPersisted
 
   EnumerateFreezableElements(NotifyActivityChanged, nsnull);
   EnumerateExternalResources(NotifyPageShow, &aPersisted);
 
   Element* root = GetRootElement();
   if (aPersisted && root) {
     // Send out notifications that our <link> elements are attached.
     nsRefPtr<nsContentList> links = NS_GetContentList(root,
-                                                      nsGkAtoms::link,
-                                                      kNameSpaceID_Unknown);
-
-    if (links) {
-      PRUint32 linkCount = links->Length(PR_TRUE);
-      for (PRUint32 i = 0; i < linkCount; ++i) {
-        nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
-        if (link) {
-          link->LinkAdded();
-        }
+                                                      kNameSpaceID_Unknown,
+                                                      nsGkAtoms::link);
+
+    PRUint32 linkCount = links->Length(PR_TRUE);
+    for (PRUint32 i = 0; i < linkCount; ++i) {
+      nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
+      if (link) {
+        link->LinkAdded();
       }
     }
   }
 
   // See nsIDocument
   if (!aDispatchStartTarget) {
     // Set mIsShowing before firing events, in case those event handlers
     // move us around.
@@ -7457,26 +7446,24 @@ void
 nsDocument::OnPageHide(PRBool aPersisted,
                        nsIDOMEventTarget* aDispatchStartTarget)
 {
   // Send out notifications that our <link> elements are detached,
   // but only if this is not a full unload.
   Element* root = GetRootElement();
   if (aPersisted && root) {
     nsRefPtr<nsContentList> links = NS_GetContentList(root,
-                                                      nsGkAtoms::link,
-                                                      kNameSpaceID_Unknown);
-
-    if (links) {
-      PRUint32 linkCount = links->Length(PR_TRUE);
-      for (PRUint32 i = 0; i < linkCount; ++i) {
-        nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
-        if (link) {
-          link->LinkRemoved();
-        }
+                                                      kNameSpaceID_Unknown,
+                                                      nsGkAtoms::link);
+
+    PRUint32 linkCount = links->Length(PR_TRUE);
+    for (PRUint32 i = 0; i < linkCount; ++i) {
+      nsCOMPtr<nsILink> link = do_QueryInterface(links->Item(i, PR_FALSE));
+      if (link) {
+        link->LinkRemoved();
       }
     }
   }
 
   // See nsIDocument
   if (!aDispatchStartTarget) {
     // Set mIsShowing before firing events, in case those event handlers
     // move us around.
--- a/content/base/src/nsGenericElement.cpp
+++ b/content/base/src/nsGenericElement.cpp
@@ -1360,18 +1360,19 @@ nsNSElementTearoff::GetNextElementSiblin
 
 nsContentList*
 nsGenericElement::GetChildrenList()
 {
   nsGenericElement::nsDOMSlots *slots = GetDOMSlots();
   NS_ENSURE_TRUE(slots, nsnull);
 
   if (!slots->mChildrenList) {
-    slots->mChildrenList = new nsContentList(this, nsGkAtoms::_asterix,
-                                             kNameSpaceID_Wildcard, PR_FALSE);
+    slots->mChildrenList = new nsContentList(this, kNameSpaceID_Wildcard, 
+                                             nsGkAtoms::_asterix, nsGkAtoms::_asterix,
+                                             PR_FALSE);
   }
 
   return slots->mChildrenList;
 }
 
 NS_IMETHODIMP
 nsNSElementTearoff::GetChildElementCount(PRUint32* aResult)
 {
@@ -2490,22 +2491,23 @@ nsGenericElement::RemoveAttributeNode(ns
 
   return rv;
 }
 
 nsresult
 nsGenericElement::GetElementsByTagName(const nsAString& aTagname,
                                        nsIDOMNodeList** aReturn)
 {
-  nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aTagname);
-  NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
-
-  nsContentList *list = NS_GetContentList(this, nameAtom,
-                                          kNameSpaceID_Unknown).get();
-  NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
+  nsAutoString lowercaseName;
+  nsContentUtils::ASCIIToLower(aTagname, lowercaseName);
+  nsCOMPtr<nsIAtom> XMLAtom = do_GetAtom(aTagname);
+  nsCOMPtr<nsIAtom> HTMLAtom = do_GetAtom(lowercaseName);
+
+  nsContentList *list = NS_GetContentList(this, kNameSpaceID_Unknown, 
+                                          HTMLAtom, XMLAtom).get();
 
   // transfer ref to aReturn
   *aReturn = list;
   return NS_OK;
 }
 
 nsresult
 nsGenericElement::GetAttributeNS(const nsAString& aNamespaceURI,
@@ -2622,20 +2624,18 @@ nsGenericElement::GetElementsByTagNameNS
   if (!aNamespaceURI.EqualsLiteral("*")) {
     nsresult rv =
       nsContentUtils::NameSpaceManager()->RegisterNameSpace(aNamespaceURI,
                                                             nameSpaceId);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   nsCOMPtr<nsIAtom> nameAtom = do_GetAtom(aLocalName);
-  NS_ENSURE_TRUE(nameAtom, NS_ERROR_OUT_OF_MEMORY);
-
-  nsContentList *list = NS_GetContentList(this, nameAtom, nameSpaceId).get();
-  NS_ENSURE_TRUE(list, NS_ERROR_OUT_OF_MEMORY);
+
+  nsContentList *list = NS_GetContentList(this, nameSpaceId, nameAtom).get();
 
   // transfer ref to aReturn
   *aReturn = list;
   return NS_OK;
 }
 
 nsresult
 nsGenericElement::HasAttribute(const nsAString& aName, PRBool* aReturn)
--- a/content/base/test/Makefile.in
+++ b/content/base/test/Makefile.in
@@ -170,16 +170,18 @@ include $(topsrcdir)/config/rules.mk
 		test_bug417384.html \
 		test_bug418214.html \
 		test_bug419527.xhtml \
 		test_bug420609.xhtml \
 		test_bug420700.html \
 		test_bug421602.html \
 		test_bug422537.html \
 		test_bug424359-1.html \
+		test_bug499656.html \
+		test_bug499656.xhtml \
 		file_htmlserializer_1.html \
 		file_htmlserializer_1_bodyonly.html \
 		file_htmlserializer_1_format.html \
 		file_htmlserializer_1_linebreak.html \
 		file_htmlserializer_1_links.html \
 		file_htmlserializer_1_noflag.html \
 		file_htmlserializer_1_noformatpre.html \
 		file_htmlserializer_1_raw.html \
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug499656.html
@@ -0,0 +1,58 @@
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=499656
+-->
+<head>
+  <title>Test for Bug 499656</title>
+  <script type="text/javascript" src="/MochiKit/packed.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>        
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=499656">Mozilla Bug 499655</a>
+<p id="display"></p>
+<div id="content">
+</div>
+<pre id="test">
+<script class="testbody" type="text/javascript">
+
+/** Test for Bug 499655 **/
+
+div1 = document.createElementNS("http://www.w3.org/1999/xhtml","test");
+div2 = document.createElementNS("http://www.w3.org/1999/xhtml","TEst");
+div3 = document.createElementNS("test","test");
+div4 = document.createElementNS("test","TEst");
+div5 = document.createElement("test");
+div6 = document.createElement("TEst");
+
+content = document.getElementById("content");
+
+content.appendChild(div1);
+content.appendChild(div2);
+content.appendChild(div3);
+content.appendChild(div4);
+content.appendChild(div5);
+content.appendChild(div6);
+
+list = document.getElementsByTagName('test');
+is(list.length, 4, "Number of elements found");
+ok(list[0] == div1, "First element didn't match");
+ok(list[1] == div3, "Third element didn't match");
+ok(list[2] == div5, "Fifth element didn't match");
+ok(list[3] == div6, "Sixth element didn't match");
+
+list = document.getElementsByTagName('TEst');
+is(list.length, 4, "Wrong number of elements found");
+ok(list[0] == div1, "First element didn't match");
+ok(list[1] == div4, "Fourth element didn't match");
+ok(list[2] == div5, "Fifth element didn't match");
+ok(list[3] == div6, "Sixth element didn't match");
+
+list = document.getElementsByTagNameNS('test', 'test');
+is(list.length, 1, "Wrong number of elements found");
+ok(list[0] == div3, "Third element didn't match");
+
+</script>
+</pre>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/content/base/test/test_bug499656.xhtml
@@ -0,0 +1,58 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=499655
+-->
+<head>
+  <title>Test for Bug 499655</title>
+  <script type="application/javascript" src="/MochiKit/packed.js"></script>
+  <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=499655">Mozilla Bug 499655</a>
+<p id="display"></p>
+<div id="content" style="display: none">
+  
+</div>
+<pre id="test">
+<script type="application/javascript">
+<![CDATA[
+
+div1 = document.createElementNS("http://www.w3.org/1999/xhtml","test");
+div2 = document.createElementNS("http://www.w3.org/1999/xhtml","TEst");
+div3 = document.createElementNS("test","test");
+div4 = document.createElementNS("test","TEst");
+div5 = document.createElement("test");
+div6 = document.createElement("TEst");
+
+content = document.getElementById("content");
+
+content.appendChild(div1);
+content.appendChild(div2);
+content.appendChild(div3);
+content.appendChild(div4);
+content.appendChild(div5);
+content.appendChild(div6);
+
+
+list = document.getElementsByTagName('test');
+is(list.length, 3, "Number of elements found");
+ok(list[0] == div1, "First element didn't match");
+ok(list[1] == div3, "Third element didn't match");
+ok(list[2] == div5, "Fifth element didn't match");
+
+list = document.getElementsByTagName('TEst');
+is(list.length, 3, "Number of elements found");
+ok(list[0] == div2, "Second element didn't match");
+ok(list[1] == div4, "Fourth element didn't match");
+ok(list[2] == div6, "Sixth element didn't match");
+
+list = document.getElementsByTagNameNS('test', 'test');
+is(list.length, 1, "Wrong number of elements found");
+ok(list[0] == div3, "Third element didn't match");
+
+]]>
+</script>
+</pre>
+</body>
+</html>
--- a/content/html/content/src/nsHTMLMapElement.cpp
+++ b/content/html/content/src/nsHTMLMapElement.cpp
@@ -111,23 +111,20 @@ NS_IMPL_ELEMENT_CLONE(nsHTMLMapElement)
 NS_IMETHODIMP
 nsHTMLMapElement::GetAreas(nsIDOMHTMLCollection** aAreas)
 {
   NS_ENSURE_ARG_POINTER(aAreas);
 
   if (!mAreas) {
     // Not using NS_GetContentList because this should not be cached
     mAreas = new nsContentList(this,
+                               mNodeInfo->NamespaceID(),
                                nsGkAtoms::area,
-                               mNodeInfo->NamespaceID(),
+                               nsGkAtoms::area,
                                PR_FALSE);
-
-    if (!mAreas) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
   }
 
   NS_ADDREF(*aAreas = mAreas);
   return NS_OK;
 }
 
 
 NS_IMPL_STRING_ATTR(nsHTMLMapElement, Name, name)
--- a/content/html/content/src/nsHTMLTableElement.cpp
+++ b/content/html/content/src/nsHTMLTableElement.cpp
@@ -164,20 +164,21 @@ NS_INTERFACE_TABLE_HEAD(TableRowsCollect
   NS_INTERFACE_TABLE_TO_MAP_SEGUE_CYCLE_COLLECTION(TableRowsCollection)
   NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(HTMLCollection)
 NS_INTERFACE_MAP_END
 
 nsresult
 TableRowsCollection::Init()
 {
   mOrphanRows = new nsContentList(mParent,
+                                  mParent->NodeInfo()->NamespaceID(),
                                   nsGkAtoms::tr,
-                                  mParent->NodeInfo()->NamespaceID(),
+                                  nsGkAtoms::tr,
                                   PR_FALSE);
-  return mOrphanRows ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
+  return NS_OK;
 }
 
 // Macro that can be used to avoid copy/pasting code to iterate over the
 // rowgroups.  _code should be the code to execute for each rowgroup.  The
 // rowgroup's rows will be in the nsIDOMHTMLCollection* named "rows".  Note
 // that this may be null at any time.  This macro assumes an nsresult named
 // |rv| is in scope.
 #define DO_FOR_EACH_ROWGROUP(_code)                                  \
@@ -594,21 +595,20 @@ nsHTMLTableElement::GetRows(nsIDOMHTMLCo
 }
 
 NS_IMETHODIMP
 nsHTMLTableElement::GetTBodies(nsIDOMHTMLCollection** aValue)
 {
   if (!mTBodies) {
     // Not using NS_GetContentList because this should not be cached
     mTBodies = new nsContentList(this,
+                                 mNodeInfo->NamespaceID(),
                                  nsGkAtoms::tbody,
-                                 mNodeInfo->NamespaceID(),
+                                 nsGkAtoms::tbody,
                                  PR_FALSE);
-
-    NS_ENSURE_TRUE(mTBodies, NS_ERROR_OUT_OF_MEMORY);
   }
 
   NS_ADDREF(*aValue = mTBodies);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLTableElement::CreateTHead(nsIDOMHTMLElement** aValue)
--- a/content/html/content/src/nsHTMLTableSectionElement.cpp
+++ b/content/html/content/src/nsHTMLTableSectionElement.cpp
@@ -128,18 +128,19 @@ NS_IMPL_STRING_ATTR(nsHTMLTableSectionEl
 
 NS_IMETHODIMP
 nsHTMLTableSectionElement::GetRows(nsIDOMHTMLCollection** aValue)
 {
   *aValue = nsnull;
 
   if (!mRows) {
     mRows = new nsContentList(this,
+                              mNodeInfo->NamespaceID(),
                               nsGkAtoms::tr,
-                              mNodeInfo->NamespaceID(),
+                              nsGkAtoms::tr,
                               PR_FALSE);
 
     NS_ENSURE_TRUE(mRows, NS_ERROR_OUT_OF_MEMORY);
   }
 
   NS_ADDREF(*aValue = mRows);
   return NS_OK;
 }
--- a/content/html/document/src/nsHTMLDocument.cpp
+++ b/content/html/document/src/nsHTMLDocument.cpp
@@ -1169,19 +1169,18 @@ nsHTMLDocument::SetTitle(const nsAString
 {
   return nsDocument::SetTitle(aTitle);
 }
 
 nsIDOMHTMLMapElement *
 nsHTMLDocument::GetImageMap(const nsAString& aMapName)
 {
   if (!mImageMaps) {
-    mImageMaps = new nsContentList(this, nsGkAtoms::map, kNameSpaceID_XHTML);
+    mImageMaps = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::map, nsGkAtoms::map);
   }
-  NS_ASSERTION(mImageMaps, "Infallible malloc failed.");
 
   nsIDOMHTMLMapElement* firstMatch = nsnull;
   nsAutoString name;
   PRUint32 i, n = mImageMaps->Length(PR_TRUE);
   for (i = 0; i < n; ++i) {
     nsCOMPtr<nsIDOMHTMLMapElement> map(
       do_QueryInterface(mImageMaps->GetNodeAt(i)));
 
@@ -1545,22 +1544,17 @@ nsHTMLDocument::GetBody(nsresult *aResul
   if (body) {
     // There is a body element, return that as the body.
     return body;
   }
 
   // The document is most likely a frameset document so look for the
   // outer most frameset element
   nsRefPtr<nsContentList> nodeList =
-    NS_GetContentList(this, nsGkAtoms::frameset, kNameSpaceID_XHTML);
-  if (!nodeList) {
-    *aResult = NS_ERROR_OUT_OF_MEMORY;
-
-    return nsnull;
-  }
+    NS_GetContentList(this, kNameSpaceID_XHTML, nsGkAtoms::frameset);
 
   return nodeList->GetNodeAt(0);
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetBody(nsIDOMHTMLElement** aBody)
 {
   *aBody = nsnull;
@@ -1608,36 +1602,30 @@ nsHTMLDocument::GetHead(nsIDOMHTMLHeadEl
 
   return head ? CallQueryInterface(head, aHead) : NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetImages(nsIDOMHTMLCollection** aImages)
 {
   if (!mImages) {
-    mImages = new nsContentList(this, nsGkAtoms::img, kNameSpaceID_XHTML);
-    if (!mImages) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+    mImages = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::img, nsGkAtoms::img);
   }
 
   *aImages = mImages;
   NS_ADDREF(*aImages);
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetApplets(nsIDOMHTMLCollection** aApplets)
 {
   if (!mApplets) {
-    mApplets = new nsContentList(this, nsGkAtoms::applet, kNameSpaceID_XHTML);
-    if (!mApplets) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+    mApplets = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::applet, nsGkAtoms::applet);
   }
 
   *aApplets = mApplets;
   NS_ADDREF(*aApplets);
 
   return NS_OK;
 }
 
@@ -1673,19 +1661,16 @@ nsHTMLDocument::MatchLinks(nsIContent *a
   return PR_FALSE;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetLinks(nsIDOMHTMLCollection** aLinks)
 {
   if (!mLinks) {
     mLinks = new nsContentList(this, MatchLinks, nsnull, nsnull);
-    if (!mLinks) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
   }
 
   *aLinks = mLinks;
   NS_ADDREF(*aLinks);
 
   return NS_OK;
 }
 
@@ -1713,19 +1698,16 @@ nsHTMLDocument::MatchAnchors(nsIContent 
   return PR_FALSE;
 }
 
 NS_IMETHODIMP
 nsHTMLDocument::GetAnchors(nsIDOMHTMLCollection** aAnchors)
 {
   if (!mAnchors) {
     mAnchors = new nsContentList(this, MatchAnchors, nsnull, nsnull);
-    if (!mAnchors) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
   }
 
   *aAnchors = mAnchors;
   NS_ADDREF(*aAnchors);
 
   return NS_OK;
 }
 
@@ -2511,20 +2493,17 @@ nsHTMLDocument::SetFgColor(const nsAStri
   return NS_OK;
 }
 
 
 NS_IMETHODIMP
 nsHTMLDocument::GetEmbeds(nsIDOMHTMLCollection** aEmbeds)
 {
   if (!mEmbeds) {
-    mEmbeds = new nsContentList(this, nsGkAtoms::embed, kNameSpaceID_XHTML);
-    if (!mEmbeds) {
-      return NS_ERROR_OUT_OF_MEMORY;
-    }
+    mEmbeds = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::embed, nsGkAtoms::embed);
   }
 
   *aEmbeds = mEmbeds;
   NS_ADDREF(*aEmbeds);
 
   return NS_OK;
 }
 
@@ -2804,18 +2783,19 @@ nsHTMLDocument::GetForms(nsIDOMHTMLColle
 
   NS_ADDREF(*aForms = forms);
   return NS_OK;
 }
 
 nsContentList*
 nsHTMLDocument::GetForms()
 {
-  if (!mForms)
-    mForms = new nsContentList(this, nsGkAtoms::form, kNameSpaceID_XHTML);
+  if (!mForms) {
+    mForms = new nsContentList(this, kNameSpaceID_XHTML, nsGkAtoms::form, nsGkAtoms::form);
+  }
 
   return mForms;
 }
 
 static PRBool MatchFormControls(nsIContent* aContent, PRInt32 aNamespaceID,
                                 nsIAtom* aAtom, void* aData)
 {
   return aContent->IsNodeOfType(nsIContent::eHTML_FORM_CONTROL);