Part 2 of fix for bug 564266 (DOMCI GetItemAt/GetNamedItem should return nsWrapperCache) - store nsHTMLOptionElement in nsHTMLOptionCollection instead of nsIDOMHTMLOptionElement. r=jst.
authorPeter Van der Beken <peterv@propagandism.org>
Sun, 09 May 2010 20:32:57 +0200
changeset 47801 b33cf100643543be53fcc1f91863caf93e4a163d
parent 47800 5fdc1c421b2808ee4e6b7ae7742151ca0588cfd5
child 47802 8951841a4cdad53edea3f4a2379987b3e19fb3b0
push id14424
push userpvanderbeken@mozilla.com
push dateFri, 16 Jul 2010 13:09:01 +0000
treeherdermozilla-central@8951841a4cda [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjst
bugs564266
milestone2.0b2pre
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
Part 2 of fix for bug 564266 (DOMCI GetItemAt/GetNamedItem should return nsWrapperCache) - store nsHTMLOptionElement in nsHTMLOptionCollection instead of nsIDOMHTMLOptionElement. r=jst.
content/base/src/nsContentList.cpp
content/base/src/nsContentUtils.cpp
content/html/content/public/nsIFormControl.h
content/html/content/src/nsGenericHTMLElement.cpp
content/html/content/src/nsGenericHTMLElement.h
content/html/content/src/nsHTMLOptionElement.cpp
content/html/content/src/nsHTMLOptionElement.h
content/html/content/src/nsHTMLSelectElement.cpp
content/html/content/src/nsHTMLSelectElement.h
dom/base/nsDOMClassInfo.cpp
--- a/content/base/src/nsContentList.cpp
+++ b/content/base/src/nsContentList.cpp
@@ -165,25 +165,21 @@ void nsBaseContentList::InsertElementAt(
 nsFormContentList::nsFormContentList(nsIDOMHTMLFormElement *aForm,
                                      nsBaseContentList& aContentList)
   : nsBaseContentList()
 {
 
   // move elements that belong to mForm into this content list
 
   PRUint32 i, length = 0;
-  nsCOMPtr<nsIDOMNode> item;
 
   aContentList.GetLength(&length);
 
   for (i = 0; i < length; i++) {
-    aContentList.Item(i, getter_AddRefs(item));
-
-    nsCOMPtr<nsIContent> c(do_QueryInterface(item));
-
+    nsIContent *c = aContentList.GetNodeAt(i);
     if (c && nsContentUtils::BelongsInForm(aForm, c)) {
       AppendElement(c);
     }
   }
 }
 
 // Hashtable for storing nsContentLists
 static PLDHashTable gContentListHashTable;
--- a/content/base/src/nsContentUtils.cpp
+++ b/content/base/src/nsContentUtils.cpp
@@ -1916,21 +1916,20 @@ static inline void KeyAppendInt(PRInt32 
 
 static inline void KeyAppendAtom(nsIAtom* aAtom, nsACString& aKey)
 {
   NS_PRECONDITION(aAtom, "KeyAppendAtom: aAtom can not be null!\n");
 
   KeyAppendString(nsAtomCString(aAtom), aKey);
 }
 
-static inline PRBool IsAutocompleteOff(nsIDOMElement* aElement)
-{
-  nsAutoString autocomplete;
-  aElement->GetAttribute(NS_LITERAL_STRING("autocomplete"), autocomplete);
-  return autocomplete.LowerCaseEqualsLiteral("off");
+static inline PRBool IsAutocompleteOff(nsIContent* aElement)
+{
+  return aElement->AttrValueIs(kNameSpaceID_None, nsGkAtoms::autocomplete,
+                               NS_LITERAL_STRING("off"), eIgnoreCase);
 }
 
 /*static*/ nsresult
 nsContentUtils::GenerateStateKey(nsIContent* aContent,
                                  nsIDocument* aDocument,
                                  nsIStatefulFrame::SpecialStateID aID,
                                  nsACString& aKey)
 {
@@ -1949,18 +1948,17 @@ nsContentUtils::GenerateStateKey(nsICont
   // We must have content if we're not using a special state id
   NS_ENSURE_TRUE(aContent, NS_ERROR_FAILURE);
 
   // Don't capture state for anonymous content
   if (aContent->IsInAnonymousSubtree()) {
     return NS_OK;
   }
 
-  nsCOMPtr<nsIDOMElement> element(do_QueryInterface(aContent));
-  if (element && IsAutocompleteOff(element)) {
+  if (IsAutocompleteOff(aContent)) {
     return NS_OK;
   }
 
   nsCOMPtr<nsIHTMLDocument> htmlDocument(do_QueryInterface(aContent->GetCurrentDoc()));
 
   KeyAppendInt(partID, aKey);  // first append a partID
   // Make sure we can't possibly collide with an nsIStatefulFrame
   // special id of some sort
@@ -1996,30 +1994,27 @@ nsContentUtils::GenerateStateKey(nsICont
     nsCOMPtr<nsIFormControl> control(do_QueryInterface(aContent));
     if (control && htmlFormControls && htmlForms) {
 
       // Append the control type
       KeyAppendInt(control->GetType(), aKey);
 
       // If in a form, add form name / index of form / index in form
       PRInt32 index = -1;
-      nsCOMPtr<nsIDOMHTMLFormElement> formElement;
-      control->GetForm(getter_AddRefs(formElement));
+      Element *formElement = control->GetFormElement();
       if (formElement) {
-
         if (IsAutocompleteOff(formElement)) {
           aKey.Truncate();
           return NS_OK;
         }
 
         KeyAppendString(NS_LITERAL_CSTRING("f"), aKey);
 
         // Append the index of the form in the document
-        nsCOMPtr<nsIContent> formContent(do_QueryInterface(formElement));
-        index = htmlForms->IndexOf(formContent, PR_FALSE);
+        index = htmlForms->IndexOf(formElement, PR_FALSE);
         if (index <= -1) {
           //
           // XXX HACK this uses some state that was dumped into the document
           // specifically to fix bug 138892.  What we are trying to do is *guess*
           // which form this control's state is found in, with the highly likely
           // guess that the highest form parsed so far is the one.
           // This code should not be on trunk, only branch.
           //
@@ -2035,17 +2030,17 @@ nsContentUtils::GenerateStateKey(nsICont
           if (index > -1) {
             KeyAppendInt(index, aKey);
             generatedUniqueKey = PR_TRUE;
           }
         }
 
         // Append the form name
         nsAutoString formName;
-        formElement->GetName(formName);
+        formElement->GetAttr(kNameSpaceID_None, nsGkAtoms::name, formName);
         KeyAppendString(formName, aKey);
 
       } else {
 
         KeyAppendString(NS_LITERAL_CSTRING("d"), aKey);
 
         // If not in a form, add index of control in document
         // Less desirable than indexing by form info.
--- a/content/html/content/public/nsIFormControl.h
+++ b/content/html/content/public/nsIFormControl.h
@@ -40,16 +40,22 @@
 #include "nsISupports.h"
 class nsIDOMHTMLFormElement;
 class nsPresState;
 class nsIContent;
 class nsString;
 class nsIFormProcessor;
 class nsFormSubmission;
 
+namespace mozilla {
+namespace dom {
+class Element;
+} // namespace dom
+} // namespace mozilla
+
 enum FormControlsTypes {
   NS_FORM_FIELDSET = 1,
   NS_FORM_LABEL,
   NS_FORM_OUTPUT,
   NS_FORM_SELECT,
   NS_FORM_TEXTAREA,
   NS_FORM_OBJECT,
   eFormControlsWithoutSubTypesMax,
@@ -88,35 +94,35 @@ enum InputElementTypes {
   eInputElementTypesMax
 };
 
 PR_STATIC_ASSERT((PRUint32)eFormControlsWithoutSubTypesMax < (PRUint32)NS_FORM_BUTTON_ELEMENT);
 PR_STATIC_ASSERT((PRUint32)eButtonElementTypesMax < (PRUint32)NS_FORM_INPUT_ELEMENT);
 PR_STATIC_ASSERT((PRUint32)eInputElementTypesMax  < 1<<8);
 
 #define NS_IFORMCONTROL_IID   \
-{ 0x52dc1f0d, 0x1683, 0x4dd7, \
- { 0xae, 0x0a, 0xc4, 0x76, 0x10, 0x64, 0x2f, 0xa8 } }
+{ 0x0dc5083b, 0xb0a8, 0x48c4, \
+ { 0xb2, 0xeb, 0xc2, 0x4f, 0xfb, 0x7e, 0xc2, 0x8e } }
 
 /**
  * Interface which all form controls (e.g. buttons, checkboxes, text,
  * radio buttons, select, etc) implement in addition to their dom specific
  * interface.
  */
 class nsIFormControl : public nsISupports
 {
 public:
 
   NS_DECLARE_STATIC_IID_ACCESSOR(NS_IFORMCONTROL_IID)
 
   /**
    * Get the form for this form control.
-   * @param aForm the form [OUT]
+   * @return the form
    */
-  NS_IMETHOD GetForm(nsIDOMHTMLFormElement** aForm) = 0;
+  virtual mozilla::dom::Element *GetFormElement() = 0;
 
   /**
    * Set the form for this form control.
    * @param aForm the form.  This must not be null.
    *
    * @note that when setting the form the control is not added to the
    * form.  It adds itself when it gets bound to the tree thereafter,
    * so that it can be properly sorted with the other controls in the
--- a/content/html/content/src/nsGenericHTMLElement.cpp
+++ b/content/html/content/src/nsGenericHTMLElement.cpp
@@ -106,16 +106,19 @@
 #include "nsIEditor.h"
 #include "nsIEditorIMESupport.h"
 #include "nsEventDispatcher.h"
 #include "nsLayoutUtils.h"
 #include "nsContentCreatorFunctions.h"
 #include "mozAutoDocUpdate.h"
 #include "nsHtml5Module.h"
 #include "nsITextControlElement.h"
+#include "mozilla/dom/Element.h"
+
+using namespace mozilla::dom;
 
 #include "nsThreadUtils.h"
 
 class nsINodeInfo;
 class nsIDOMNodeList;
 class nsRuleWalker;
 
 // XXX todo: add in missing out-of-memory checks
@@ -2374,17 +2377,23 @@ nsGenericHTMLFormElement::ClearForm(PRBo
       mForm->RemoveElementFromTable(this, idVal);
     }
   }
 
   UnsetFlags(ADDED_TO_FORM);
   mForm = nsnull;
 }
 
-NS_IMETHODIMP
+Element*
+nsGenericHTMLFormElement::GetFormElement()
+{
+  return mForm;
+}
+
+nsresult
 nsGenericHTMLFormElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
   NS_ENSURE_ARG_POINTER(aForm);
   NS_IF_ADDREF(*aForm = mForm);
   return NS_OK;
 }
 
 PRUint32
--- a/content/html/content/src/nsGenericHTMLElement.h
+++ b/content/html/content/src/nsGenericHTMLElement.h
@@ -798,20 +798,22 @@ public:
   virtual ~nsGenericHTMLFormElement();
 
   NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr);
 
   virtual PRBool IsNodeOfType(PRUint32 aFlags) const;
   virtual void SaveSubtreeState();
 
   // nsIFormControl
-  NS_IMETHOD GetForm(nsIDOMHTMLFormElement** aForm);
+  virtual mozilla::dom::Element* GetFormElement();
   virtual void SetForm(nsIDOMHTMLFormElement* aForm);
   virtual void ClearForm(PRBool aRemoveFromForm, PRBool aNotify);
 
+  nsresult GetForm(nsIDOMHTMLFormElement** aForm);
+
   NS_IMETHOD SaveState()
   {
     return NS_OK;
   }
   
   virtual PRBool RestoreState(nsPresState* aState)
   {
     return PR_FALSE;
--- a/content/html/content/src/nsHTMLOptionElement.cpp
+++ b/content/html/content/src/nsHTMLOptionElement.cpp
@@ -129,17 +129,18 @@ NS_IMPL_ELEMENT_CLONE(nsHTMLOptionElemen
 
 
 NS_IMETHODIMP
 nsHTMLOptionElement::GetForm(nsIDOMHTMLFormElement** aForm)
 {
   NS_ENSURE_ARG_POINTER(aForm);
   *aForm = nsnull;
 
-  nsCOMPtr<nsIFormControl> selectControl = do_QueryInterface(GetSelect());
+  nsCOMPtr<nsIDOMHTMLSelectElement> selectControl =
+    do_QueryInterface(GetSelect());
 
   if (selectControl) {
     selectControl->GetForm(aForm);
   }
 
   return NS_OK;
 }
 
--- a/content/html/content/src/nsHTMLOptionElement.h
+++ b/content/html/content/src/nsHTMLOptionElement.h
@@ -50,16 +50,24 @@ class nsHTMLOptionElement : public nsGen
                             public nsIDOMHTMLOptionElement,
                             public nsIDOMNSHTMLOptionElement,
                             public nsIJSNativeInitializer
 {
 public:
   nsHTMLOptionElement(nsINodeInfo *aNodeInfo);
   virtual ~nsHTMLOptionElement();
 
+  /** Typesafe, non-refcounting cast from nsIContent.  Cheaper than QI. **/
+  static nsHTMLOptionElement* FromContent(nsIContent *aContent)
+  {
+    if (aContent->NodeInfo()->Equals(nsGkAtoms::option, kNameSpaceID_XHTML))
+      return static_cast<nsHTMLOptionElement*>(aContent);
+    return nsnull;
+  }
+
   // nsISupports
   NS_DECL_ISUPPORTS_INHERITED
 
   // nsIDOMNode
   NS_FORWARD_NSIDOMNODE(nsGenericHTMLElement::)
 
   // nsIDOMElement
   NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLElement::)
--- a/content/html/content/src/nsHTMLSelectElement.cpp
+++ b/content/html/content/src/nsHTMLSelectElement.cpp
@@ -33,16 +33,17 @@
  * decision by deleting the provisions above and replace them with the notice
  * and other provisions required by the GPL or the LGPL. If you do not delete
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHTMLSelectElement.h"
+#include "nsHTMLOptionElement.h"
 #include "nsIDOMEventTarget.h"
 #include "nsContentCreatorFunctions.h"
 #include "nsGkAtoms.h"
 #include "nsStyleConsts.h"
 #include "nsLayoutUtils.h"
 #include "nsMappedAttributes.h"
 #include "nsIForm.h"
 #include "nsFormSubmission.h"
@@ -64,16 +65,19 @@
 #include "nsIComboboxControlFrame.h"
 #include "nsIListControlFrame.h"
 #include "nsIFrame.h"
 
 #include "nsDOMError.h"
 #include "nsServiceManagerUtils.h"
 #include "nsRuleData.h"
 #include "nsEventDispatcher.h"
+#include "mozilla/dom/Element.h"
+
+using namespace mozilla::dom;
 
 NS_IMPL_ISUPPORTS1(nsSelectState, nsSelectState)
 NS_DEFINE_STATIC_IID_ACCESSOR(nsSelectState, NS_SELECT_STATE_IID)
 
 //----------------------------------------------------------------------
 //
 // nsSafeOptionListMutation
 //
@@ -346,17 +350,17 @@ nsHTMLSelectElement::InsertOptionsIntoLi
                                                   PRInt32* aInsertIndex,
                                                   PRInt32 aDepth)
 {
   // We *assume* here that someone's brain has not gone horribly
   // wrong by putting <option> inside of <option>.  I'm sorry, I'm
   // just not going to look for an option inside of an option.
   // Sue me.
 
-  nsCOMPtr<nsIDOMHTMLOptionElement> optElement(do_QueryInterface(aOptions));
+  nsHTMLOptionElement *optElement = nsHTMLOptionElement::FromContent(aOptions);
   if (optElement) {
     nsresult rv = mOptions->InsertOptionAt(optElement, *aInsertIndex);
     NS_ENSURE_SUCCESS(rv, rv);
     (*aInsertIndex)++;
     return NS_OK;
   }
 
   // If it's at the top level, then we just found out there are non-options
@@ -564,17 +568,17 @@ nsHTMLSelectElement::GetOptionIndexAfter
 
   return retval;
 }
 
 PRInt32
 nsHTMLSelectElement::GetFirstOptionIndex(nsIContent* aOptions)
 {
   PRInt32 listIndex = -1;
-  nsCOMPtr<nsIDOMHTMLOptionElement> optElement(do_QueryInterface(aOptions));
+  nsHTMLOptionElement *optElement = nsHTMLOptionElement::FromContent(aOptions);
   if (optElement) {
     GetOptionIndex(optElement, 0, PR_TRUE, &listIndex);
     // If you nested stuff under the option, you're just plain
     // screwed.  *I'm* not going to aid and abet your evil deed.
     return listIndex;
   }
 
   listIndex = GetFirstChildOptionIndex(aOptions, 0, aOptions->GetChildCount());
@@ -666,18 +670,17 @@ nsHTMLSelectElement::Remove(PRInt32 aInd
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLSelectElement::GetOptions(nsIDOMHTMLOptionsCollection** aValue)
 {
-  *aValue = mOptions;
-  NS_IF_ADDREF(*aValue);
+  NS_IF_ADDREF(*aValue = GetOptions());
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLSelectElement::GetType(nsAString& aType)
 {
   PRBool isMultiple;
@@ -790,17 +793,18 @@ nsHTMLSelectElement::SetSelectedIndex(PR
   return rv;
 }
 
 NS_IMETHODIMP
 nsHTMLSelectElement::GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
                                     PRInt32 aStartIndex, PRBool aForward,
                                     PRInt32* aIndex)
 {
-  return mOptions->GetOptionIndex(aOption, aStartIndex, aForward, aIndex);
+  nsCOMPtr<Element> option = do_QueryInterface(aOption);
+  return mOptions->GetOptionIndex(option, aStartIndex, aForward, aIndex);
 }
 
 PRBool
 nsHTMLSelectElement::IsOptionSelectedByIndex(PRInt32 aIndex)
 {
   nsIDOMHTMLOptionElement *option = mOptions->ItemAsOption(aIndex);
   PRBool isSelected = PR_FALSE;
   if (option) {
@@ -1695,17 +1699,17 @@ void nsHTMLSelectElement::DispatchConten
   }
 }
 
 static void
 AddOptionsRecurse(nsIContent* aRoot, nsHTMLOptionCollection* aArray)
 {
   nsIContent* child;
   for(PRUint32 i = 0; (child = aRoot->GetChildAt(i)); ++i) {
-    nsCOMPtr<nsIDOMHTMLOptionElement> opt = do_QueryInterface(child);
+    nsHTMLOptionElement *opt = nsHTMLOptionElement::FromContent(child);
     if (opt) {
       // If we fail here, then at least we've tried our best
       aArray->AppendOption(opt);
     }
     else if (IsOptGroup(child)) {
       AddOptionsRecurse(child, aArray);
     }
   }
@@ -1768,17 +1772,17 @@ nsHTMLOptionCollection::~nsHTMLOptionCol
 void
 nsHTMLOptionCollection::DropReference()
 {
   // Drop our (non ref-counted) reference
   mSelect = nsnull;
 }
 
 nsresult
-nsHTMLOptionCollection::GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
+nsHTMLOptionCollection::GetOptionIndex(mozilla::dom::Element* aOption,
                                        PRInt32 aStartIndex,
                                        PRBool aForward,
                                        PRInt32* aIndex)
 {
   PRInt32 index;
 
   // Make the common case fast
   if (aStartIndex == 0 && aForward) {
@@ -1786,36 +1790,42 @@ nsHTMLOptionCollection::GetOptionIndex(n
     if (index == -1) {
       return NS_ERROR_FAILURE;
     }
     
     *aIndex = index;
     return NS_OK;
   }
 
-  PRInt32 high = mElements.Count();
+  PRInt32 high = mElements.Length();
   PRInt32 step = aForward ? 1 : -1;
 
   for (index = aStartIndex; index < high && index > -1; index += step) {
     if (mElements[index] == aOption) {
       *aIndex = index;
       return NS_OK;
     }
   }
 
   return NS_ERROR_FAILURE;
 }
 
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLOptionCollection)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsHTMLOptionCollection)
-  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mElements)
+  NS_IMPL_CYCLE_COLLECTION_UNLINK_NSTARRAY(mElements)
 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsHTMLOptionCollection)
-  NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mElements)
+    {
+      PRUint32 i;
+      for (i = 0; i < tmp->mElements.Length(); ++i) {
+        NS_CYCLE_COLLECTION_NOTE_EDGE_NAME(cb, "mElements[i]");
+        cb.NoteXPCOMChild(static_cast<Element*>(tmp->mElements[i]));
+      }
+    }
 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 // nsISupports
 
 DOMCI_DATA(HTMLOptionsCollection, nsHTMLOptionCollection)
 
 // QueryInterface implementation for nsHTMLOptionCollection
 NS_INTERFACE_TABLE_HEAD(nsHTMLOptionCollection)
@@ -1835,17 +1845,17 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE_AMBIGUO
                                            nsIHTMLCollection)
 
 
 // nsIDOMNSHTMLOptionCollection interface
 
 NS_IMETHODIMP
 nsHTMLOptionCollection::GetLength(PRUint32* aLength)
 {
-  *aLength = mElements.Count();
+  *aLength = mElements.Length();
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsHTMLOptionCollection::SetLength(PRUint32 aLength)
 {
   if (!mSelect) {
@@ -1857,45 +1867,47 @@ nsHTMLOptionCollection::SetLength(PRUint
 
 NS_IMETHODIMP
 nsHTMLOptionCollection::SetOption(PRInt32 aIndex,
                                   nsIDOMHTMLOptionElement *aOption)
 {
   if (aIndex < 0 || !mSelect) {
     return NS_OK;
   }
-  
+
   // if the new option is null, just remove this option.  Note that it's safe
   // to pass a too-large aIndex in here.
   if (!aOption) {
     mSelect->Remove(aIndex);
 
     // We're done.
     return NS_OK;
   }
 
   nsresult rv = NS_OK;
 
+  PRUint32 index = PRUint32(aIndex);
+
   // Now we're going to be setting an option in our collection
-  if (aIndex > mElements.Count()) {
+  if (index > mElements.Length()) {
     // Fill our array with blank options up to (but not including, since we're
     // about to change it) aIndex, for compat with other browsers.
-    rv = SetLength(aIndex);
+    rv = SetLength(index);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
-  NS_ASSERTION(aIndex <= mElements.Count(), "SetLength lied");
+  NS_ASSERTION(index <= mElements.Length(), "SetLength lied");
   
   nsCOMPtr<nsIDOMNode> ret;
-  if (aIndex == mElements.Count()) {
+  if (index == mElements.Length()) {
     rv = mSelect->AppendChild(aOption, getter_AddRefs(ret));
   } else {
     // Find the option they're talking about and replace it
     // hold a strong reference to follow COM rules.
-    nsCOMPtr<nsIDOMHTMLOptionElement> refChild = mElements.SafeObjectAt(aIndex);
+    nsCOMPtr<nsIDOMHTMLOptionElement> refChild = ItemAsOption(index);
     NS_ENSURE_TRUE(refChild, NS_ERROR_UNEXPECTED);
 
     nsCOMPtr<nsIDOMNode> parent;
     refChild->GetParentNode(getter_AddRefs(parent));
     if (parent) {
       rv = parent->ReplaceChild(aOption, refChild, getter_AddRefs(ret));
     }
   }
@@ -1929,23 +1941,31 @@ nsHTMLOptionCollection::Item(PRUint32 aI
 
     return rv;
   }
 
   return CallQueryInterface(item, aReturn);
 }
 
 nsISupports*
+nsHTMLOptionCollection::GetNodeAt(PRUint32 aIndex, nsresult* aResult)
+{
+  *aResult = NS_OK;
+
+  return static_cast<Element*>(ItemAsOption(aIndex));
+}
+
+nsISupports*
 nsHTMLOptionCollection::GetNamedItem(const nsAString& aName, nsresult* aResult)
 {
   *aResult = NS_OK;
 
-  PRInt32 count = mElements.Count();
-  for (PRInt32 i = 0; i < count; i++) {
-    nsCOMPtr<nsIContent> content = do_QueryInterface(mElements.ObjectAt(i));
+  PRUint32 count = mElements.Length();
+  for (PRUint32 i = 0; i < count; i++) {
+    nsIContent *content = ItemAsOption(i);
     if (content &&
         (content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::name, aName,
                               eCaseMatters) ||
          content->AttrValueIs(kNameSpaceID_None, nsGkAtoms::id, aName,
                               eCaseMatters))) {
       return content;
     }
   }
--- a/content/html/content/src/nsHTMLSelectElement.h
+++ b/content/html/content/src/nsHTMLSelectElement.h
@@ -55,17 +55,17 @@
 #include "nsIHTMLCollection.h"
 
 // PresState
 #include "nsXPCOM.h"
 #include "nsPresState.h"
 #include "nsIComponentManager.h"
 #include "nsCheapSets.h"
 #include "nsLayoutErrors.h"
-
+#include "nsHTMLOptionElement.h"
 
 class nsHTMLSelectElement;
 
 /**
  * The collection of options in the select (what you get back when you do
  * select.options in DOM)
  */
 class nsHTMLOptionCollection: public nsIDOMHTMLOptionsCollection,
@@ -82,88 +82,83 @@ public:
   NS_DECL_NSIDOMHTMLOPTIONSCOLLECTION
 
   // nsIDOMNSHTMLOptionCollection interface
   NS_DECL_NSIDOMNSHTMLOPTIONCOLLECTION
 
   // nsIDOMHTMLCollection interface, all its methods are defined in
   // nsIDOMHTMLOptionsCollection
 
-  virtual nsISupports* GetNodeAt(PRUint32 aIndex, nsresult* aResult)
-  {
-    *aResult = NS_OK;
-
-    return mElements.SafeObjectAt(aIndex);
-  }
+  virtual nsISupports* GetNodeAt(PRUint32 aIndex, nsresult* aResult);
   virtual nsISupports* GetNamedItem(const nsAString& aName, nsresult* aResult);
 
   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(nsHTMLOptionCollection,
                                            nsIHTMLCollection)
 
   // Helpers for nsHTMLSelectElement
   /**
    * Insert an option
    * @param aOption the option to insert
    * @param aIndex the index to insert at
    */
-  PRBool InsertOptionAt(nsIDOMHTMLOptionElement* aOption, PRInt32 aIndex)
+  PRBool InsertOptionAt(nsHTMLOptionElement* aOption, PRUint32 aIndex)
   {
-    return mElements.InsertObjectAt(aOption, aIndex);
+    return !!mElements.InsertElementAt(aIndex, aOption);
   }
 
   /**
    * Remove an option
    * @param aIndex the index of the option to remove
    */
-  void RemoveOptionAt(PRInt32 aIndex)
+  void RemoveOptionAt(PRUint32 aIndex)
   {
-    mElements.RemoveObjectAt(aIndex);
+    mElements.RemoveElementAt(aIndex);
   }
 
   /**
    * Get the option at the index
    * @param aIndex the index
    * @param aReturn the option returned [OUT]
    */
-  nsIDOMHTMLOptionElement *ItemAsOption(PRInt32 aIndex)
+  nsHTMLOptionElement *ItemAsOption(PRUint32 aIndex)
   {
-    return mElements.SafeObjectAt(aIndex);
+    return mElements.SafeElementAt(aIndex, nsRefPtr<nsHTMLOptionElement>());
   }
 
   /**
    * Clears out all options
    */
   void Clear()
   {
     mElements.Clear();
   }
 
   /**
    * Append an option to end of array
    */
-  PRBool AppendOption(nsIDOMHTMLOptionElement* aOption)
+  PRBool AppendOption(nsHTMLOptionElement* aOption)
   {
-    return mElements.AppendObject(aOption);
+    return !!mElements.AppendElement(aOption);
   }
 
   /**
    * Drop the reference to the select.  Called during select destruction.
    */
   void DropReference();
 
   /**
    * See nsISelectElement.idl for documentation on this method
    */
-  nsresult GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
+  nsresult GetOptionIndex(mozilla::dom::Element* aOption,
                           PRInt32 aStartIndex, PRBool aForward,
                           PRInt32* aIndex);
 
 private:
   /** The list of options (holds strong references) */
-  nsCOMArray<nsIDOMHTMLOptionElement> mElements;
+  nsTArray<nsRefPtr<nsHTMLOptionElement> > mElements;
   /** The select element that contains this array */
   nsHTMLSelectElement* mSelect;
 };
 
 #define NS_SELECT_STATE_IID                        \
 { /* 4db54c7c-d159-455f-9d8e-f60ee466dbf3 */       \
   0x4db54c7c,                                      \
   0xd159,                                          \
@@ -304,16 +299,26 @@ public:
                                               PRInt32 aModType) const;
   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
 
   virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
 
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLSelectElement,
                                                      nsGenericHTMLFormElement)
 
+  nsHTMLOptionCollection *GetOptions()
+  {
+    return mOptions;
+  }
+
+  static nsHTMLSelectElement *FromSupports(nsISupports *aSupports)
+  {
+    return static_cast<nsHTMLSelectElement*>(static_cast<nsINode*>(aSupports));
+  }
+
 protected:
   friend class nsSafeOptionListMutation;
 
   // Helper Methods
   /**
    * Check whether the option specified by the index is selected
    * @param aIndex the index
    * @return whether the option at the index is selected
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -471,16 +471,17 @@
 // Simple gestures include
 #include "nsIDOMSimpleGestureEvent.h"
 
 #include "nsIDOMNSMouseEvent.h"
 
 #include "nsIEventListenerService.h"
 #include "nsIFrameMessageManager.h"
 #include "mozilla/dom/Element.h"
+#include "nsHTMLSelectElement.h"
 
 using namespace mozilla::dom;
 
 #include "mozilla/dom/indexedDB/IDBFactory.h"
 #include "mozilla/dom/indexedDB/IDBRequest.h"
 #include "mozilla/dom/indexedDB/IDBDatabase.h"
 #include "mozilla/dom/indexedDB/IDBEvents.h"
 #include "mozilla/dom/indexedDB/IDBObjectStore.h"
@@ -7494,18 +7495,17 @@ nsNodeSH::PreCreate(nsISupports *nativeO
     native_parent = doc;
 
     // But for HTML form controls, use the form as scope parent.
     if (nodeIsElement) {
       if (node->IsNodeOfType(nsINode::eHTML_FORM_CONTROL)) {
         nsCOMPtr<nsIFormControl> form_control(do_QueryInterface(node));
 
         if (form_control) {
-          nsCOMPtr<nsIDOMHTMLFormElement> form;
-          form_control->GetForm(getter_AddRefs(form));
+          Element *form = form_control->GetFormElement();
 
           if (form) {
             // Found a form, use it.
             native_parent = form;
           }
         }
       // Legend isn't an HTML form control but should have its fieldset form
       // as scope parent at least for backward compatibility.
@@ -9522,25 +9522,23 @@ NS_IMETHODIMP
 nsHTMLSelectElementSH::GetProperty(nsIXPConnectWrappedNative *wrapper,
                                    JSContext *cx, JSObject *obj, jsval id,
                                    jsval *vp, PRBool *_retval)
 {
   PRInt32 n = GetArrayIndexFromId(cx, id);
 
   nsresult rv = NS_OK;
   if (n >= 0) {
-    nsCOMPtr<nsIDOMHTMLSelectElement> s = do_QueryWrappedNative(wrapper, obj);
-
-    nsCOMPtr<nsIDOMHTMLOptionsCollection> options;
-    s->GetOptions(getter_AddRefs(options));
+    nsHTMLSelectElement *s =
+      nsHTMLSelectElement::FromSupports(GetNative(wrapper, obj));
+
+    nsHTMLOptionCollection *options = s->GetOptions();
 
     if (options) {
-      nsCOMPtr<nsIDOMNode> node;
-
-      options->Item(n, getter_AddRefs(node));
+      nsISupports *node = options->GetNodeAt(n, &rv);
 
       rv = WrapNative(cx, obj, node, &NS_GET_IID(nsIDOMNode), PR_TRUE, vp);
       if (NS_SUCCEEDED(rv)) {
         rv = NS_SUCCESS_I_DID_SOMETHING;
       }
       return rv;
     }
   }