diff --git a/mozilla/content/html/content/src/nsHTMLSelectElement.cpp b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
new file mode 100644
index 00000000000..9ef21b37c25
--- /dev/null
+++ b/mozilla/content/html/content/src/nsHTMLSelectElement.cpp
@@ -0,0 +1,2267 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: NPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Netscape Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/NPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Pierre Phaneuf
+ *
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the NPL, indicate your
+ * 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 NPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+#include "nsCOMPtr.h"
+#include "nsIDOMHTMLSelectElement.h"
+#include "nsIDOMNSHTMLSelectElement.h"
+#include "nsIDOMNSXBLFormControl.h"
+#include "nsIDOMHTMLFormElement.h"
+#include "nsIDOMEventReceiver.h"
+#include "nsIHTMLContent.h"
+#include "nsITextContent.h"
+#include "nsGenericHTMLElement.h"
+#include "nsHTMLAtoms.h"
+#include "nsHTMLIIDs.h"
+#include "nsIStyleContext.h"
+#include "nsStyleConsts.h"
+#include "nsIPresContext.h"
+#include "nsHTMLAttributes.h"
+#include "nsIForm.h"
+#include "nsIFormSubmission.h"
+#include "nsIDOMHTMLCollection.h"
+#include "nsIDOMHTMLOptionElement.h"
+#include "nsIDOMHTMLOptGroupElement.h"
+#include "nsIOptionElement.h"
+#include "nsIEventStateManager.h"
+#include "nsGenericDOMHTMLCollection.h"
+#include "nsISelectElement.h"
+#include "nsISelectControlFrame.h"
+#include "nsIDOMNSHTMLOptionCollectn.h"
+#include "nsGUIEvent.h"
+#include "nsIBoxObject.h"
+#include "nsIDOMNSDocument.h"
+#include "nsIDOMDocumentEvent.h"
+
+// PresState
+#include "nsVoidArray.h"
+#include "nsISupportsArray.h"
+#include "nsISupportsPrimitives.h"
+#include "nsIPresState.h"
+#include "nsIComponentManager.h"
+
+// Notify/query select frame for selectedIndex
+#include "nsIDocument.h"
+#include "nsIPresShell.h"
+#include "nsIFormControlFrame.h"
+#include "nsIFrame.h"
+
+#include "nsRuleNode.h"
+
+
+class nsHTMLSelectElement;
+
+
+// nsHTMLOptionCollection
+class nsHTMLOptionCollection: public nsIDOMNSHTMLOptionCollection,
+ public nsGenericDOMHTMLCollection
+{
+public:
+ nsHTMLOptionCollection(nsHTMLSelectElement* aSelect);
+ virtual ~nsHTMLOptionCollection();
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // nsIDOMNSHTMLOptionCollection interface, can't use the macro
+ // NS_DECL_NSIDOMNSHTMLOPTIONLIST here since GetLength() is defined
+ // in mode than one interface
+ NS_IMETHOD SetLength(PRUint32 aLength);
+ NS_IMETHOD GetSelectedIndex(PRInt32* aSelectedIndex);
+ NS_IMETHOD SetSelectedIndex(PRInt32 aSelectedIndex);
+ NS_IMETHOD SetOption(PRInt32 aIndex, nsIDOMHTMLOptionElement* aOption);
+
+ // nsIDOMHTMLCollection interface
+ NS_DECL_NSIDOMHTMLCOLLECTION
+
+ nsresult InsertElementAt(nsIDOMNode* aOption, PRInt32 aIndex);
+ nsresult RemoveElementAt(PRInt32 aIndex);
+ nsresult GetOption(PRInt32 aIndex, nsIDOMHTMLOptionElement** aReturn);
+ PRInt32 IndexOf(nsIContent* aOption);
+ nsresult ItemAsOption(PRInt32 aIndex, nsIDOMHTMLOptionElement **aReturn);
+
+ void DropReference();
+
+private:
+ nsCOMPtr mElements;
+ nsHTMLSelectElement* mSelect;
+};
+
+
+class nsHTMLSelectElement : public nsGenericHTMLContainerFormElement,
+ public nsIDOMHTMLSelectElement,
+ public nsIDOMNSHTMLSelectElement,
+ public nsIDOMNSXBLFormControl,
+ public nsISelectElement
+{
+public:
+ nsHTMLSelectElement(PRBool aFromParser);
+ virtual ~nsHTMLSelectElement();
+
+ // nsISupports
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // nsIDOMNode
+ NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsGenericHTMLContainerElement::)
+
+ // nsIDOMElement
+ NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLContainerElement::)
+
+ // nsIDOMHTMLElement
+ NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLContainerElement::)
+
+ // nsIDOMHTMLSelectElement
+ NS_DECL_NSIDOMHTMLSELECTELEMENT
+
+ // nsIDOMNSHTMLSelectElement
+ NS_DECL_NSIDOMNSHTMLSELECTELEMENT
+
+ // nsIDOMNSXBLFormControl
+ NS_DECL_NSIDOMNSXBLFORMCONTROL
+
+ // nsIContent
+ NS_IMETHOD InsertChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify,
+ PRBool aDeepSetDocument);
+ NS_IMETHOD ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex, PRBool aNotify,
+ PRBool aDeepSetDocument);
+ NS_IMETHOD AppendChildTo(nsIContent* aKid, PRBool aNotify,
+ PRBool aDeepSetDocument);
+ NS_IMETHOD RemoveChildAt(PRInt32 aIndex, PRBool aNotify);
+
+ NS_IMETHOD HandleDOMEvent(nsIPresContext* aPresContext,
+ nsEvent* aEvent,
+ nsIDOMEvent** aDOMEvent,
+ PRUint32 aFlags,
+ nsEventStatus* aEventStatus);
+
+#ifdef DEBUG
+ NS_IMETHOD SizeOf(nsISizeOfHandler* aSizer, PRUint32* aResult) const;
+#endif
+ NS_IMETHOD SetFocus(nsIPresContext* aPresContext);
+ NS_IMETHOD RemoveFocus(nsIPresContext* aPresContext);
+
+ // Overriden nsIFormControl methods
+ NS_IMETHOD GetType(PRInt32* aType);
+ NS_IMETHOD Reset();
+ NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
+ nsIContent* aSubmitElement);
+
+ // nsISelectElement
+ NS_DECL_NSISELECTELEMENT
+
+ NS_IMETHOD StringToAttribute(nsIAtom* aAttribute,
+ const nsAString& aValue,
+ nsHTMLValue& aResult);
+ NS_IMETHOD GetAttributeMappingFunction(nsMapRuleToAttributesFunc& aMapRuleFunc) const;
+ NS_IMETHOD GetMappedAttributeImpact(const nsIAtom* aAttribute,
+ PRInt32 aModType, PRInt32& aHint) const;
+
+
+protected:
+ // Helper Methods
+ nsresult GetOptionIndex(nsIDOMHTMLOptionElement* aOption,
+ PRInt32 * anIndex);
+ nsresult IsOptionSelectedByIndex(PRInt32 index, PRBool* aIsSelected);
+ nsresult FindSelectedIndex(PRInt32 aStartIndex);
+ nsresult SelectSomething();
+ nsresult CheckSelectSomething();
+ nsresult OnOptionSelected(nsISelectControlFrame* aSelectFrame,
+ nsIPresContext* aPresContext,
+ PRInt32 aIndex,
+ PRBool aSelected,
+ PRBool aNotify);
+ nsresult InitializeOption(nsIDOMHTMLOptionElement* aOption,
+ PRUint32* aNumOptions);
+ nsresult RestoreStateTo(nsAString* aNewSelected);
+
+#ifdef DEBUG_john
+ // Don't remove these, por favor. They're very useful in debugging
+ nsresult PrintOptions(nsIContent* aOptions, PRInt32 tabs);
+#endif
+
+ // Adding options
+ nsresult InsertOptionsIntoList(nsIContent* aOptions,
+ PRInt32 aListIndex,
+ PRInt32 aLevel);
+ nsresult RemoveOptionsFromList(nsIContent* aOptions,
+ PRInt32 aListIndex,
+ PRInt32 aLevel);
+ nsresult InsertOptionsIntoListRecurse(nsIContent* aOptions,
+ PRInt32* aInsertIndex,
+ PRInt32 aLevel);
+ nsresult RemoveOptionsFromListRecurse(nsIContent* aOptions,
+ PRInt32 aRemoveIndex,
+ PRInt32* aNumRemoved,
+ PRInt32 aLevel);
+ nsresult GetContentLevel(nsIContent* aContent, PRInt32* aLevel);
+ nsresult GetOptionAt(nsIContent* aOptions, PRInt32* aListIndex);
+ nsresult GetOptionAfter(nsIContent* aOptions, PRInt32* aListIndex);
+ nsresult GetFirstOptionIndex(nsIContent* aOptions, PRInt32* aListIndex);
+ nsresult GetFirstChildOptionIndex(nsIContent* aOptions,
+ PRInt32 aStartIndex,
+ PRInt32 aEndIndex,
+ PRInt32* aListIndex);
+
+ nsISelectControlFrame *GetSelectFrame();
+
+ nsHTMLOptionCollection* mOptions;
+ PRBool mIsDoneAddingChildren;
+ PRUint32 mArtifactsAtTopLevel;
+ PRInt32 mSelectedIndex;
+ nsString* mRestoreState;
+};
+
+
+//----------------------------------------------------------------------
+//
+// nsHTMLSelectElement
+//
+
+// construction, destruction
+
+nsresult
+NS_NewHTMLSelectElement(nsIHTMLContent** aInstancePtrResult,
+ nsINodeInfo *aNodeInfo,
+ PRBool aFromParser)
+{
+ NS_ENSURE_ARG_POINTER(aInstancePtrResult);
+
+ nsHTMLSelectElement* it = new nsHTMLSelectElement(aFromParser);
+
+ if (!it) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ nsresult rv = NS_STATIC_CAST(nsGenericHTMLElement *, it)->Init(aNodeInfo);
+
+ if (NS_FAILED(rv)) {
+ delete it;
+
+ return rv;
+ }
+
+ *aInstancePtrResult = NS_STATIC_CAST(nsIHTMLContent *, it);
+ NS_ADDREF(*aInstancePtrResult);
+
+ return NS_OK;
+}
+
+
+nsHTMLSelectElement::nsHTMLSelectElement(PRBool aFromParser)
+{
+ // DoneAddingChildren() will be called later if it's from the parser,
+ // otherwise it is
+ mIsDoneAddingChildren = !aFromParser;
+ mArtifactsAtTopLevel = 0;
+
+ mOptions = new nsHTMLOptionCollection(this);
+ NS_IF_ADDREF(mOptions);
+
+ mRestoreState = nsnull;
+ mSelectedIndex = -1;
+}
+
+nsHTMLSelectElement::~nsHTMLSelectElement()
+{
+ // Null out form's pointer to us - no ref counting here!
+ SetForm(nsnull);
+ if (mOptions) {
+ mOptions->DropReference();
+ NS_RELEASE(mOptions);
+ }
+ if (mRestoreState) {
+ delete mRestoreState;
+ mRestoreState = nsnull;
+ }
+}
+
+// ISupports
+
+NS_IMPL_ADDREF_INHERITED(nsHTMLSelectElement, nsGenericElement);
+NS_IMPL_RELEASE_INHERITED(nsHTMLSelectElement, nsGenericElement);
+
+
+// QueryInterface implementation for nsHTMLSelectElement
+NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLSelectElement,
+ nsGenericHTMLContainerFormElement)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLSelectElement)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLSelectElement)
+ NS_INTERFACE_MAP_ENTRY(nsIDOMNSXBLFormControl)
+ NS_INTERFACE_MAP_ENTRY(nsISelectElement)
+ NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLSelectElement)
+NS_HTML_CONTENT_INTERFACE_MAP_END
+
+
+// nsIDOMHTMLSelectElement
+
+nsresult
+nsHTMLSelectElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
+{
+ NS_ENSURE_ARG_POINTER(aReturn);
+ *aReturn = nsnull;
+
+ nsHTMLSelectElement* it = new nsHTMLSelectElement(PR_FALSE);
+
+ if (!it) {
+ return NS_ERROR_OUT_OF_MEMORY;
+ }
+
+ nsCOMPtr kungFuDeathGrip(it);
+
+ nsresult rv = NS_STATIC_CAST(nsGenericHTMLElement *, it)->Init(mNodeInfo);
+
+ if (NS_FAILED(rv))
+ return rv;
+
+ CopyInnerTo(this, it, aDeep);
+
+ *aReturn = NS_STATIC_CAST(nsIDOMNode *, it);
+
+ NS_ADDREF(*aReturn);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsHTMLSelectElement::GetForm(nsIDOMHTMLFormElement** aForm)
+{
+ return nsGenericHTMLContainerFormElement::GetForm(aForm);
+}
+
+
+// nsIContent
+NS_IMETHODIMP
+nsHTMLSelectElement::AppendChildTo(nsIContent* aKid, PRBool aNotify,
+ PRBool aDeepSetDocument)
+{
+ PRInt32 count = 0;
+ ChildCount(count);
+ WillAddOptions(aKid, this, count);
+
+ // Actually perform the append
+ return nsGenericHTMLContainerFormElement::AppendChildTo(aKid,
+ aNotify,
+ aDeepSetDocument);
+}
+
+NS_IMETHODIMP
+nsHTMLSelectElement::InsertChildAt(nsIContent* aKid, PRInt32 aIndex,
+ PRBool aNotify, PRBool aDeepSetDocument)
+{
+ WillAddOptions(aKid, this, aIndex);
+
+ return nsGenericHTMLContainerFormElement::InsertChildAt(aKid,
+ aIndex,
+ aNotify,
+ aDeepSetDocument);
+}
+
+NS_IMETHODIMP
+nsHTMLSelectElement::ReplaceChildAt(nsIContent* aKid, PRInt32 aIndex,
+ PRBool aNotify, PRBool aDeepSetDocument)
+{
+ WillRemoveOptions(this, aIndex);
+ WillAddOptions(aKid, this, aIndex);
+
+ return nsGenericHTMLContainerFormElement::ReplaceChildAt(aKid,
+ aIndex,
+ aNotify,
+ aDeepSetDocument);
+}
+
+NS_IMETHODIMP
+nsHTMLSelectElement::RemoveChildAt(PRInt32 aIndex, PRBool aNotify)
+{
+ WillRemoveOptions(this, aIndex);
+
+ return nsGenericHTMLContainerFormElement::RemoveChildAt(aIndex,
+ aNotify);
+}
+
+
+// SelectElement methods
+
+nsresult
+nsHTMLSelectElement::InsertOptionsIntoList(nsIContent* aOptions,
+ PRInt32 aListIndex,
+ PRInt32 aLevel)
+{
+ PRInt32 insertIndex = aListIndex;
+ InsertOptionsIntoListRecurse(aOptions, &insertIndex, aLevel);
+
+ // Deal with the selected list
+ if (insertIndex - aListIndex) {
+ // Fix the currently selected index
+ if (aListIndex <= mSelectedIndex) {
+ mSelectedIndex += (insertIndex - aListIndex);
+ }
+
+ // Get the frame stuff for notification. No need to flush here
+ // since if there's no frame for the select yet the select will
+ // get into the right state once it's created.
+ nsISelectControlFrame* selectFrame = GetSelectFrame();
+
+ nsCOMPtr presContext;
+ if (selectFrame) {
+ GetPresContext(this, getter_AddRefs(presContext));
+ }
+
+ // Actually select the options if the added options warrant it
+ nsCOMPtr optionNode;
+ nsCOMPtr option;
+ for (PRInt32 i=aListIndex;iAddOption(presContext, i);
+ }
+
+ Item(i, getter_AddRefs(optionNode));
+ option = do_QueryInterface(optionNode);
+ if (option) {
+ PRBool selected;
+ option->GetSelected(&selected);
+ if (selected) {
+ // Clear all other options
+ PRBool isMultiple;
+ GetMultiple(&isMultiple);
+ if (!isMultiple) {
+ SetOptionsSelectedByIndex(i, i, PR_TRUE, PR_TRUE, PR_TRUE, PR_TRUE, nsnull);
+ }
+
+ // This is sort of a hack ... we need to notify that the option was
+ // set and change selectedIndex even though we didn't really change
+ // its value.
+ OnOptionSelected(selectFrame, presContext, i, PR_TRUE, PR_TRUE);
+ }
+ }
+ }
+
+ CheckSelectSomething();
+ }
+
+ return NS_OK;
+}
+
+#ifdef DEBUG_john
+nsresult
+nsHTMLSelectElement::PrintOptions(nsIContent* aOptions, PRInt32 tabs)
+{
+ for (PRInt32 i=0;i elem(do_QueryInterface(aOptions));
+ if (elem) {
+ nsAutoString s;
+ elem->GetTagName(s);
+ printf("<%s>\n", NS_ConvertUCS2toUTF8(s).get());
+ } else {
+ printf(">>text\n");
+ }
+
+ // Recurse down into optgroups
+ //
+ // I *would* put a restriction in here to only search under
+ // optgroups (and not, for example, ), but it really
+ // doesn't *hurt* to search under other stuff and it's more
+ // efficient in the normal only-optgroup-and-option case
+ // (one less QueryInterface).
+ PRInt32 numChildren;
+ aOptions->ChildCount(numChildren);
+ nsCOMPtr child;
+ for (PRInt32 i=0;iChildAt(i,*getter_AddRefs(child));
+ PrintOptions(child, tabs+1);
+ }
+
+ return NS_OK;
+}
+#endif
+
+nsresult
+nsHTMLSelectElement::RemoveOptionsFromList(nsIContent* aOptions,
+ PRInt32 aListIndex,
+ PRInt32 aLevel)
+{
+ PRInt32 numRemoved = 0;
+ RemoveOptionsFromListRecurse(aOptions, aListIndex, &numRemoved, aLevel);
+ if (numRemoved) {
+ // Tell the widget we removed the options
+ nsISelectControlFrame* selectFrame = GetSelectFrame();
+ if (selectFrame) {
+ nsCOMPtr presContext;
+ GetPresContext(this, getter_AddRefs(presContext));
+ for (int i=aListIndex;iRemoveOption(presContext, i);
+ }
+ }
+
+ // Fix the selected index
+ if (aListIndex <= mSelectedIndex) {
+ if (mSelectedIndex < (aListIndex+numRemoved)) {
+ // aListIndex <= mSelectedIndex < aListIndex+numRemoved
+ // Find a new selected index if it was one of the ones removed.
+ FindSelectedIndex(aListIndex);
+ } else {
+ // Shift the selected index if something in front of it was removed
+ // aListIndex+numRemoved <= mSelectedIndex
+ mSelectedIndex -= numRemoved;
+ }
+ }
+
+ // Select something in case we removed the selected option on a
+ // single select
+ CheckSelectSomething();
+ }
+
+ return NS_OK;
+}
+
+// If the document is such that recursing over these options gets us
+// deeper than four levels, there is something terribly wrong with the
+// world.
+nsresult
+nsHTMLSelectElement::InsertOptionsIntoListRecurse(nsIContent* aOptions,
+ PRInt32* aInsertIndex,
+ PRInt32 aLevel)
+{
+ // We *assume* here that someone's brain has not gone horribly
+ // wrong by putting