Back to index

lightning-sunbird  0.9+nobinonly
nsHTMLInputElement.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
00002 /* ***** BEGIN LICENSE BLOCK *****
00003  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
00004  *
00005  * The contents of this file are subject to the Mozilla Public License Version
00006  * 1.1 (the "License"); you may not use this file except in compliance with
00007  * the License. You may obtain a copy of the License at
00008  * http://www.mozilla.org/MPL/
00009  *
00010  * Software distributed under the License is distributed on an "AS IS" basis,
00011  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
00012  * for the specific language governing rights and limitations under the
00013  * License.
00014  *
00015  * The Original Code is Mozilla Communicator client code.
00016  *
00017  * The Initial Developer of the Original Code is
00018  * Netscape Communications Corporation.
00019  * Portions created by the Initial Developer are Copyright (C) 1998
00020  * the Initial Developer. All Rights Reserved.
00021  *
00022  * Contributor(s):
00023  *   Pierre Phaneuf <pp@ludusdesign.com>
00024  *
00025  * Alternatively, the contents of this file may be used under the terms of
00026  * either of the GNU General Public License Version 2 or later (the "GPL"),
00027  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
00028  * in which case the provisions of the GPL or the LGPL are applicable instead
00029  * of those above. If you wish to allow use of your version of this file only
00030  * under the terms of either the GPL or the LGPL, and not to allow others to
00031  * use your version of this file under the terms of the MPL, indicate your
00032  * decision by deleting the provisions above and replace them with the notice
00033  * and other provisions required by the GPL or the LGPL. If you do not delete
00034  * the provisions above, a recipient may use your version of this file under
00035  * the terms of any one of the MPL, the GPL or the LGPL.
00036  *
00037  * ***** END LICENSE BLOCK ***** */
00038 #include "nsCOMPtr.h"
00039 #include "nsIDOMHTMLInputElement.h"
00040 #include "nsIDOMNSHTMLInputElement.h"
00041 #include "nsITextControlElement.h"
00042 #include "nsIFileControlElement.h"
00043 #include "nsIDOMNSEditableElement.h"
00044 #include "nsIRadioControlElement.h"
00045 #include "nsIRadioVisitor.h"
00046 #include "nsIPhonetic.h"
00047 
00048 #include "nsIControllers.h"
00049 #include "nsIFocusController.h"
00050 #include "nsPIDOMWindow.h"
00051 #include "nsIScriptGlobalObject.h"
00052 #include "nsContentCID.h"
00053 #include "nsIComponentManager.h"
00054 #include "nsIDOMHTMLFormElement.h"
00055 #include "nsIDOMEventReceiver.h"
00056 #include "nsGenericHTMLElement.h"
00057 #include "nsHTMLAtoms.h"
00058 #include "nsStyleConsts.h"
00059 #include "nsPresContext.h"
00060 #include "nsMappedAttributes.h"
00061 #include "nsIFormControl.h"
00062 #include "nsIForm.h"
00063 #include "nsIFormSubmission.h"
00064 #include "nsITextControlFrame.h"
00065 #include "nsIRadioControlFrame.h"
00066 #include "nsIDocument.h"
00067 #include "nsIPresShell.h"
00068 #include "nsIFormControlFrame.h"
00069 #include "nsIFrame.h"
00070 #include "nsIEventStateManager.h"
00071 #include "nsIServiceManager.h"
00072 #include "nsIScriptSecurityManager.h"
00073 #include "nsDOMError.h"
00074 #include "nsIPrivateDOMEvent.h"
00075 #include "nsIEditor.h"
00076 #include "nsGUIEvent.h"
00077 
00078 #include "nsPresState.h"
00079 #include "nsLayoutErrors.h"
00080 #include "nsIDOMEvent.h"
00081 #include "nsIDOMNSEvent.h"
00082 #include "nsIDOMNodeList.h"
00083 #include "nsIDOMHTMLCollection.h"
00084 #include "nsICheckboxControlFrame.h"
00085 #include "nsIImageControlFrame.h"
00086 #include "nsLinebreakConverter.h" //to strip out carriage returns
00087 #include "nsReadableUtils.h"
00088 #include "nsUnicharUtils.h"
00089 
00090 #include "nsIDOMMutationEvent.h"
00091 #include "nsIDOMEventReceiver.h"
00092 #include "nsMutationEvent.h"
00093 
00094 #include "nsRuleData.h"
00095 
00096 // input type=radio
00097 #include "nsIRadioControlFrame.h"
00098 #include "nsIRadioGroupContainer.h"
00099 
00100 // input type=file
00101 #include "nsIMIMEService.h"
00102 #include "nsCExternalHandlerService.h"
00103 #include "nsIFile.h"
00104 #include "nsILocalFile.h"
00105 #include "nsIFileStreams.h"
00106 #include "nsNetUtil.h"
00107 
00108 // input type=image
00109 #include "nsImageLoadingContent.h"
00110 #include "nsIDOMWindowInternal.h"
00111 
00112 // XXX align=left, hspace, vspace, border? other nav4 attrs
00113 
00114 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
00115 //
00116 // Accessors for mBitField
00117 //
00118 #define BF_DISABLED_CHANGED 0
00119 #define BF_HANDLING_CLICK 1
00120 #define BF_VALUE_CHANGED 2
00121 #define BF_CHECKED_CHANGED 3
00122 #define BF_CHECKED 4
00123 #define BF_HANDLING_SELECT_EVENT 5
00124 #define BF_SHOULD_INIT_CHECKED 6
00125 #define BF_PARSER_CREATING 7
00126 #define BF_IN_INTERNAL_ACTIVATE 8
00127 #define BF_CHECKED_IS_TOGGLED 9
00128 #define BF_SETTING_FILE_FOCUS 10
00129 
00130 #define GET_BOOLBIT(bitfield, field) (((bitfield) & (0x01 << (field))) \
00131                                         ? PR_TRUE : PR_FALSE)
00132 #define SET_BOOLBIT(bitfield, field, b) ((b) \
00133                                         ? ((bitfield) |=  (0x01 << (field))) \
00134                                         : ((bitfield) &= ~(0x01 << (field))))
00135 
00136 static const char* kWhitespace = "\n\r\t\b";
00137 
00138 class nsHTMLInputElement : public nsGenericHTMLFormElement,
00139                            public nsImageLoadingContent,
00140                            public nsIDOMHTMLInputElement,
00141                            public nsIDOMNSHTMLInputElement,
00142                            public nsITextControlElement,
00143                            public nsIRadioControlElement,
00144                            public nsIPhonetic,
00145                            public nsIDOMNSEditableElement,
00146                            public nsIFileControlElement
00147 {
00148 public:
00149   nsHTMLInputElement(nsINodeInfo *aNodeInfo, PRBool aFromParser);
00150   virtual ~nsHTMLInputElement();
00151 
00152   // nsISupports
00153   NS_DECL_ISUPPORTS_INHERITED
00154 
00155   // nsIDOMNode
00156   NS_FORWARD_NSIDOMNODE_NO_CLONENODE(nsGenericHTMLFormElement::)
00157 
00158   // nsIDOMElement
00159   NS_FORWARD_NSIDOMELEMENT(nsGenericHTMLFormElement::)
00160 
00161   // nsIDOMHTMLElement
00162   NS_FORWARD_NSIDOMHTMLELEMENT(nsGenericHTMLFormElement::)
00163 
00164   // nsIDOMHTMLInputElement
00165   NS_DECL_NSIDOMHTMLINPUTELEMENT
00166 
00167   // nsIDOMNSHTMLInputElement
00168   NS_DECL_NSIDOMNSHTMLINPUTELEMENT
00169 
00170   // nsIPhonetic
00171   NS_DECL_NSIPHONETIC
00172 
00173   // nsIDOMNSEditableElement
00174   NS_FORWARD_NSIDOMNSEDITABLEELEMENT(nsGenericHTMLElement::)
00175 
00176   // Overriden nsIFormControl methods
00177   NS_IMETHOD_(PRInt32) GetType() const { return mType; }
00178   NS_IMETHOD Reset();
00179   NS_IMETHOD SubmitNamesValues(nsIFormSubmission* aFormSubmission,
00180                                nsIContent* aSubmitElement);
00181   NS_IMETHOD SaveState();
00182   virtual PRBool RestoreState(nsPresState* aState);
00183   virtual PRBool AllowDrop();
00184 
00185   // nsIContent
00186   virtual void SetFocus(nsPresContext* aPresContext);
00187   virtual PRBool IsFocusable(PRInt32 *aTabIndex = nsnull);
00188 
00189   virtual PRBool ParseAttribute(nsIAtom* aAttribute,
00190                                 const nsAString& aValue,
00191                                 nsAttrValue& aResult);
00192   virtual nsChangeHint GetAttributeChangeHint(const nsIAtom* aAttribute,
00193                                               PRInt32 aModType) const;
00194   NS_IMETHOD_(PRBool) IsAttributeMapped(const nsIAtom* aAttribute) const;
00195   virtual nsMapRuleToAttributesFunc GetAttributeMappingFunction() const;
00196   virtual nsresult HandleDOMEvent(nsPresContext* aPresContext,
00197                                   nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
00198                                   PRUint32 aFlags,
00199                                   nsEventStatus* aEventStatus);
00200   virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent,
00201                               nsIContent* aBindingParent,
00202                               PRBool aCompileEventHandlers);
00203   virtual void UnbindFromTree(PRBool aDeep = PR_TRUE,
00204                               PRBool aNullParent = PR_TRUE);
00205   
00206   nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
00207                    const nsAString& aValue, PRBool aNotify)
00208   {
00209     return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify);
00210   }
00211   virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
00212                            nsIAtom* aPrefix, const nsAString& aValue,
00213                            PRBool aNotify)
00214   {
00215     BeforeSetAttr(aNameSpaceID, aName, &aValue, aNotify);
00216 
00217     nsresult rv = nsGenericHTMLFormElement::SetAttr(aNameSpaceID, aName,
00218                                                     aPrefix, aValue, aNotify);
00219     return rv;
00220   }
00221 
00222   virtual nsresult UnsetAttr(PRInt32 aNameSpaceID, nsIAtom* aAttribute,
00223                              PRBool aNotify)
00224   {
00225     BeforeSetAttr(aNameSpaceID, aAttribute, nsnull, aNotify);
00226 
00227     nsresult rv = nsGenericHTMLFormElement::UnsetAttr(aNameSpaceID, aAttribute,
00228                                                       aNotify);
00229     return rv;
00230   }
00231 
00232   virtual void DoneCreatingElement();
00233 
00234   virtual PRInt32 IntrinsicState() const;
00235 
00236   // nsITextControlElement
00237   NS_IMETHOD TakeTextFrameValue(const nsAString& aValue);
00238   NS_IMETHOD SetValueChanged(PRBool aValueChanged);
00239   
00240   // nsIFileControlElement
00241   virtual void GetFileName(nsAString& aFileName);
00242   virtual void SetFileName(const nsAString& aFileName, PRBool aUpdateFrame);
00243 
00244   // nsIRadioControlElement
00245   NS_IMETHOD RadioSetChecked(PRBool aNotify);
00246   NS_IMETHOD SetCheckedChanged(PRBool aCheckedChanged);
00247   NS_IMETHOD SetCheckedChangedInternal(PRBool aCheckedChanged);
00248   NS_IMETHOD GetCheckedChanged(PRBool* aCheckedChanged);
00249   NS_IMETHOD AddedToRadioGroup(PRBool aNotify = PR_TRUE);
00250   NS_IMETHOD WillRemoveFromRadioGroup();
00255   virtual already_AddRefed<nsIRadioGroupContainer> GetRadioGroupContainer();
00256 
00257 protected:
00258   // Helper method
00259   nsresult SetValueInternal(const nsAString& aValue,
00260                             nsITextControlFrame* aFrame);
00261 
00262   nsresult GetSelectionRange(PRInt32* aSelectionStart, PRInt32* aSelectionEnd);
00263 
00269   PRBool GetNameIfExists(nsAString& aName) {
00270     return GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, aName) !=
00271            NS_CONTENT_ATTR_NOT_THERE;
00272   }
00273 
00277   void BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
00278                      const nsAString* aValue, PRBool aNotify);
00282   virtual void AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
00283                             const nsAString* aValue, PRBool aNotify);
00284 
00285   void SelectAll(nsPresContext* aPresContext);
00286   PRBool IsImage() const
00287   {
00288     nsAutoString tmp;
00289 
00290     GetAttr(kNameSpaceID_None, nsHTMLAtoms::type, tmp);
00291 
00292     return tmp.LowerCaseEqualsLiteral("image");
00293   }
00294 
00298   void FireOnChange();
00299 
00304   nsresult VisitGroup(nsIRadioVisitor* aVisitor);
00305 
00310   nsresult DoSetChecked(PRBool aValue, PRBool aNotify = PR_TRUE);
00311 
00316   nsresult SetCheckedInternal(PRBool aValue, PRBool aNotify);
00317 
00322   nsresult MaybeSubmitForm(nsPresContext* aPresContext);
00323 
00324   void FocusFileInputButton(nsIFormControlFrame* aFormControlFrame,
00325                             nsPresContext* aPresContext);
00326 
00333   void MaybeClearFilename(nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
00334                           PRInt32 aOldType);
00335 
00336   nsCOMPtr<nsIControllers> mControllers;
00337 
00342   PRInt8                   mType;
00347   PRInt16                  mBitField;
00351   char*                    mValue;
00362   nsAutoPtr<nsString>      mFileName;
00363 
00364   PRBool                   mHasBeenDisabled;
00365 };
00366 
00367 #ifdef ACCESSIBILITY
00368 //Helper method
00369 static nsresult FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
00370                                           nsPresContext* aPresContext,
00371                                           const nsAString& aEventType);
00372 #endif
00373 
00374 //
00375 // construction, destruction
00376 //
00377 
00378 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Input)
00379 
00380 nsHTMLInputElement::nsHTMLInputElement(nsINodeInfo *aNodeInfo,
00381                                        PRBool aFromParser)
00382   : nsGenericHTMLFormElement(aNodeInfo),
00383     mType(NS_FORM_INPUT_TEXT), // default value
00384     mBitField(0),
00385     mValue(nsnull),
00386     mHasBeenDisabled(PR_FALSE)
00387 {
00388   SET_BOOLBIT(mBitField, BF_PARSER_CREATING, aFromParser);
00389 }
00390 
00391 nsHTMLInputElement::~nsHTMLInputElement()
00392 {
00393   DestroyImageLoadingContent();
00394   if (mValue) {
00395     nsMemory::Free(mValue);
00396   }
00397 }
00398 
00399 
00400 // nsISupports
00401 
00402 NS_IMPL_ADDREF_INHERITED(nsHTMLInputElement, nsGenericElement) 
00403 NS_IMPL_RELEASE_INHERITED(nsHTMLInputElement, nsGenericElement) 
00404 
00405 
00406 // QueryInterface implementation for nsHTMLInputElement
00407 NS_HTML_CONTENT_INTERFACE_MAP_BEGIN(nsHTMLInputElement,
00408                                     nsGenericHTMLFormElement)
00409   NS_INTERFACE_MAP_ENTRY(nsIDOMHTMLInputElement)
00410   NS_INTERFACE_MAP_ENTRY(nsIDOMNSHTMLInputElement)
00411   NS_INTERFACE_MAP_ENTRY(nsITextControlElement)
00412   NS_INTERFACE_MAP_ENTRY(nsIFileControlElement)
00413   NS_INTERFACE_MAP_ENTRY(nsIRadioControlElement)
00414   NS_INTERFACE_MAP_ENTRY(nsIPhonetic)
00415   NS_INTERFACE_MAP_ENTRY(imgIDecoderObserver)
00416   NS_INTERFACE_MAP_ENTRY(imgIDecoderObserver_MOZILLA_1_8_BRANCH)
00417   NS_INTERFACE_MAP_ENTRY(nsIImageLoadingContent)
00418   NS_INTERFACE_MAP_ENTRY(nsIDOMNSEditableElement)
00419   NS_INTERFACE_MAP_ENTRY_CONTENT_CLASSINFO(HTMLInputElement)
00420 NS_HTML_CONTENT_INTERFACE_MAP_END
00421 
00422 
00423 // nsIDOMNode
00424 
00425 nsresult
00426 nsHTMLInputElement::CloneNode(PRBool aDeep, nsIDOMNode** aReturn)
00427 {
00428   *aReturn = nsnull;
00429 
00430   nsHTMLInputElement* it = new nsHTMLInputElement(mNodeInfo, PR_FALSE);
00431   if (!it) {
00432     return NS_ERROR_OUT_OF_MEMORY;
00433   }
00434 
00435   nsCOMPtr<nsIDOMNode> kungFuDeathGrip(it);
00436 
00437   CopyInnerTo(it, aDeep);
00438 
00439   switch (mType) {
00440     case NS_FORM_INPUT_TEXT:
00441     case NS_FORM_INPUT_PASSWORD:
00442       if (GET_BOOLBIT(mBitField, BF_VALUE_CHANGED)) {
00443         // We don't have our default value anymore.  Set our value on
00444         // the clone.
00445         nsAutoString value;
00446         GetValue(value);
00447         // SetValueInternal handles setting the VALUE_CHANGED bit for us
00448         it->SetValueInternal(value, nsnull);
00449       }
00450       break;
00451     case NS_FORM_INPUT_FILE:
00452       if (mFileName) {
00453         it->mFileName = new nsString(*mFileName);
00454       }
00455       break;
00456     case NS_FORM_INPUT_RADIO:
00457     case NS_FORM_INPUT_CHECKBOX:
00458       if (GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED)) {
00459         // We no longer have our original checked state.  Set our
00460         // checked state on the clone.
00461         PRBool checked;
00462         GetChecked(&checked);
00463         it->DoSetChecked(checked, PR_FALSE);
00464       }
00465       break;
00466     default:
00467       break;
00468   }
00469           
00470   kungFuDeathGrip.swap(*aReturn);
00471 
00472   return NS_OK;
00473 }
00474 
00475 
00476 void
00477 nsHTMLInputElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
00478                                   const nsAString* aValue,
00479                                   PRBool aNotify)
00480 {
00481   if (aNameSpaceID != kNameSpaceID_None) {
00482     return;
00483   }
00484 
00485   //
00486   // When name or type changes, radio should be removed from radio group.
00487   // (type changes are handled in the form itself currently)
00488   // If the parser is not done creating the radio, we also should not do it.
00489   //
00490   if ((aName == nsHTMLAtoms::name || (aName == nsHTMLAtoms::type && !mForm)) &&
00491       mType == NS_FORM_INPUT_RADIO &&
00492       (mForm || !(GET_BOOLBIT(mBitField, BF_PARSER_CREATING)))) {
00493     WillRemoveFromRadioGroup();
00494   } else if (aNotify && aName == nsHTMLAtoms::src &&
00495              aValue && mType == NS_FORM_INPUT_IMAGE) {
00496     // Null value means the attr got unset; don't trigger on that
00497     ImageURIChanged(*aValue, PR_TRUE);
00498   } else if (aNotify && aName == nsHTMLAtoms::disabled) {
00499     SET_BOOLBIT(mBitField, BF_DISABLED_CHANGED, PR_TRUE);
00500   }
00501 }
00502 
00503 void
00504 nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
00505                                  const nsAString* aValue,
00506                                  PRBool aNotify)
00507 {
00508   nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify);
00509 
00510   if (aNameSpaceID != kNameSpaceID_None) {
00511     return;
00512   }
00513 
00514   if (aName == nsHTMLAtoms::disabled && !mHasBeenDisabled) {
00515     GetDisabled(&mHasBeenDisabled);
00516   }
00517   //
00518   // When name or type changes, radio should be added to radio group.
00519   // (type changes are handled in the form itself currently)
00520   // If the parser is not done creating the radio, we also should not do it.
00521   //
00522   if ((aName == nsHTMLAtoms::name || (aName == nsHTMLAtoms::type && !mForm)) &&
00523       mType == NS_FORM_INPUT_RADIO &&
00524       (mForm || !(GET_BOOLBIT(mBitField, BF_PARSER_CREATING)))) {
00525     AddedToRadioGroup();
00526   }
00527 
00528   //
00529   // Some elements have to change their value when the value and checked
00530   // attributes change (but they only do so when ValueChanged() and
00531   // CheckedChanged() are false--i.e. the value has not been changed by the
00532   // user or by JS)
00533   //
00534   // We only really need to call reset for the value so that the text control
00535   // knows the new value.  No other reason.
00536   //
00537   if (aName == nsHTMLAtoms::value &&
00538       !GET_BOOLBIT(mBitField, BF_VALUE_CHANGED) &&
00539       (mType == NS_FORM_INPUT_TEXT ||
00540        mType == NS_FORM_INPUT_PASSWORD ||
00541        mType == NS_FORM_INPUT_FILE)) {
00542     Reset();
00543   }
00544   //
00545   // Checked must be set no matter what type of control it is, since
00546   // GetChecked() must reflect the new value
00547   //
00548   if (aName == nsHTMLAtoms::checked &&
00549       !GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED)) {
00550     // Delay setting checked if the parser is creating this element (wait until
00551     // everything is set)
00552     if (GET_BOOLBIT(mBitField, BF_PARSER_CREATING)) {
00553       SET_BOOLBIT(mBitField, BF_SHOULD_INIT_CHECKED, PR_TRUE);
00554     } else {
00555       PRBool defaultChecked;
00556       GetDefaultChecked(&defaultChecked);
00557       DoSetChecked(defaultChecked);
00558       SetCheckedChanged(PR_FALSE);
00559     }
00560   }
00561 
00562   if (aName == nsHTMLAtoms::type) {
00563     if (!aValue) {
00564       // We're now a text input.  Note that we have to handle this manually,
00565       // since removing an attribute (which is what happened, since aValue is
00566       // null) doesn't call ParseAttribute.
00567       mType = NS_FORM_INPUT_TEXT;
00568     }
00569     
00570     // If we are changing type from File/Text/Passwd to other input types
00571     // we need save the mValue into value attribute
00572     if (mValue &&
00573         mType != NS_FORM_INPUT_TEXT &&
00574         mType != NS_FORM_INPUT_PASSWORD &&
00575         mType != NS_FORM_INPUT_FILE) {
00576       SetAttr(kNameSpaceID_None, nsHTMLAtoms::value,
00577               NS_ConvertUTF8toUCS2(mValue), PR_FALSE);
00578       if (mValue) {
00579         nsMemory::Free(mValue);
00580         mValue = nsnull;
00581       }
00582     }
00583 
00584     if (mType != NS_FORM_INPUT_IMAGE) {
00585       // We're no longer an image input.  Cancel our image requests, if we have
00586       // any.  Note that doing this when we already weren't an image is ok --
00587       // just does nothing.
00588       CancelImageRequests();
00589     }
00590     
00591     if (aNotify && mType == NS_FORM_INPUT_IMAGE && !mCurrentRequest) {
00592       // We just got switched to be an image input; we should see
00593       // whether we have an image to load;
00594       nsAutoString src;
00595       nsresult rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, src);
00596       if (rv == NS_CONTENT_ATTR_HAS_VALUE) {
00597         ImageURIChanged(src, PR_FALSE);
00598       }
00599     }
00600   }
00601 }
00602 
00603 // nsIDOMHTMLInputElement
00604 
00605 NS_IMETHODIMP
00606 nsHTMLInputElement::GetForm(nsIDOMHTMLFormElement** aForm)
00607 {
00608   return nsGenericHTMLFormElement::GetForm(aForm);
00609 }
00610 
00611 //NS_IMPL_STRING_ATTR(nsHTMLInputElement, DefaultValue, value)
00612 NS_IMPL_BOOL_ATTR(nsHTMLInputElement, DefaultChecked, checked)
00613 NS_IMPL_STRING_ATTR(nsHTMLInputElement, Accept, accept)
00614 NS_IMPL_STRING_ATTR(nsHTMLInputElement, AccessKey, accesskey)
00615 NS_IMPL_STRING_ATTR(nsHTMLInputElement, Align, align)
00616 NS_IMPL_STRING_ATTR(nsHTMLInputElement, Alt, alt)
00617 //NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Checked, checked)
00618 NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Disabled, disabled)
00619 NS_IMPL_INT_ATTR(nsHTMLInputElement, MaxLength, maxlength)
00620 NS_IMPL_STRING_ATTR(nsHTMLInputElement, Name, name)
00621 NS_IMPL_BOOL_ATTR(nsHTMLInputElement, ReadOnly, readonly)
00622 NS_IMPL_URI_ATTR(nsHTMLInputElement, Src, src)
00623 NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLInputElement, TabIndex, tabindex, 0)
00624 NS_IMPL_STRING_ATTR(nsHTMLInputElement, UseMap, usemap)
00625 //NS_IMPL_STRING_ATTR(nsHTMLInputElement, Value, value)
00626 //NS_IMPL_INT_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Size, size, 0)
00627 //NS_IMPL_STRING_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Type, type, "text")
00628 
00629 NS_IMETHODIMP
00630 nsHTMLInputElement::GetDefaultValue(nsAString& aValue)
00631 {
00632   GetAttrHelper(nsHTMLAtoms::value, aValue);
00633 
00634   if (mType != NS_FORM_INPUT_HIDDEN) {
00635     // Bug 114997: trim \n, etc. for non-hidden inputs
00636     aValue = nsContentUtils::TrimCharsInSet(kWhitespace, aValue);
00637   }
00638 
00639   return NS_OK;
00640 }
00641 
00642 NS_IMETHODIMP
00643 nsHTMLInputElement::SetDefaultValue(const nsAString& aValue)
00644 {
00645   return SetAttrHelper(nsHTMLAtoms::value, aValue);
00646 }
00647 
00648 NS_IMETHODIMP
00649 nsHTMLInputElement::GetSize(PRUint32* aValue)
00650 {
00651   const nsAttrValue* attrVal = mAttrsAndChildren.GetAttr(nsHTMLAtoms::size);
00652   if (attrVal && attrVal->Type() == nsAttrValue::eInteger) {
00653     *aValue = attrVal->GetIntegerValue();
00654   }
00655   else {
00656     *aValue = 0;
00657   }
00658 
00659   return NS_OK;
00660 }
00661 
00662 NS_IMETHODIMP
00663 nsHTMLInputElement::SetSize(PRUint32 aValue)
00664 {
00665   nsAutoString val;
00666   val.AppendInt(aValue);
00667 
00668   return SetAttr(kNameSpaceID_None, nsHTMLAtoms::size, val, PR_TRUE);
00669 }
00670 
00671 NS_IMETHODIMP 
00672 nsHTMLInputElement::GetValue(nsAString& aValue)
00673 {
00674   if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) {
00675     // No need to flush here, if there's no frame created for this
00676     // input yet, there won't be a value in it (that we don't already
00677     // have) even if we force it to be created
00678     nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
00679 
00680     PRBool frameOwnsValue = PR_FALSE;
00681     if (formControlFrame) {
00682       nsITextControlFrame* textControlFrame = nsnull;
00683       CallQueryInterface(formControlFrame, &textControlFrame);
00684 
00685       if (textControlFrame) {
00686         textControlFrame->OwnsValue(&frameOwnsValue);
00687       } else {
00688         // We assume if it's not a text control frame that it owns the value
00689         frameOwnsValue = PR_TRUE;
00690       }
00691     }
00692 
00693     if (frameOwnsValue) {
00694       formControlFrame->GetProperty(nsHTMLAtoms::value, aValue);
00695     } else {
00696       if (!GET_BOOLBIT(mBitField, BF_VALUE_CHANGED) || !mValue) {
00697         GetDefaultValue(aValue);
00698       } else {
00699         CopyUTF8toUTF16(mValue, aValue);
00700       }
00701     }
00702 
00703     return NS_OK;
00704   }
00705 
00706   if (mType == NS_FORM_INPUT_FILE) {
00707     if (mFileName) {
00708       aValue = *mFileName;
00709     }
00710     else {
00711       aValue.Truncate();
00712     }
00713 
00714     return NS_OK;
00715   }
00716   
00717   // Treat value == defaultValue for other input elements
00718   nsresult rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::value, aValue);
00719 
00720   if (mType != NS_FORM_INPUT_HIDDEN) {
00721     aValue = nsContentUtils::TrimCharsInSet(kWhitespace, aValue);
00722   }
00723 
00724   if (rv == NS_CONTENT_ATTR_NOT_THERE &&
00725       (mType == NS_FORM_INPUT_RADIO || mType == NS_FORM_INPUT_CHECKBOX)) {
00726     // The default value of a radio or checkbox input is "on".
00727     aValue.AssignLiteral("on");
00728 
00729     return NS_OK;
00730   }
00731 
00732   return rv;
00733 }
00734 
00735 NS_IMETHODIMP 
00736 nsHTMLInputElement::SetValue(const nsAString& aValue)
00737 {
00738   // check security.  Note that setting the value to the empty string is always
00739   // OK and gives pages a way to clear a file input if necessary.
00740   if (mType == NS_FORM_INPUT_FILE) {
00741     if (!aValue.IsEmpty()) {
00742       nsIScriptSecurityManager *securityManager =
00743         nsContentUtils::GetSecurityManager();
00744 
00745       PRBool enabled;
00746       nsresult rv =
00747         securityManager->IsCapabilityEnabled("UniversalFileRead", &enabled);
00748       NS_ENSURE_SUCCESS(rv, rv);
00749 
00750       if (!enabled) {
00751         // setting the value of a "FILE" input widget requires the
00752         // UniversalFileRead privilege
00753         return NS_ERROR_DOM_SECURITY_ERR;
00754       }
00755     }
00756     SetFileName(aValue, PR_TRUE);
00757   }
00758   else {
00759     SetValueInternal(aValue, nsnull);
00760   }
00761 
00762   return NS_OK;
00763 }
00764 
00765 NS_IMETHODIMP
00766 nsHTMLInputElement::TakeTextFrameValue(const nsAString& aValue)
00767 {
00768   if (mValue) {
00769     nsMemory::Free(mValue);
00770   }
00771   mValue = ToNewUTF8String(aValue);
00772   SetValueChanged(PR_TRUE);
00773   return NS_OK;
00774 }
00775 
00776 void
00777 nsHTMLInputElement::GetFileName(nsAString& aValue)
00778 {
00779   if (mFileName) {
00780     aValue = *mFileName;
00781   }
00782   else {
00783     aValue.Truncate();
00784   }
00785 }
00786 
00787 void
00788 nsHTMLInputElement::SetFileName(const nsAString& aValue, PRBool aUpdateFrame)
00789 {
00790   // No big deal if |new| fails, we simply won't submit the file
00791   mFileName = aValue.IsEmpty() ? nsnull : new nsString(aValue);
00792 
00793   SetValueChanged(PR_TRUE);
00794 
00795   if (aUpdateFrame) {
00796     nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
00797     if (formControlFrame) {
00798       nsCOMPtr<nsPresContext> presContext = GetPresContext();
00799       formControlFrame->SetProperty(presContext, nsHTMLAtoms::filename, aValue);
00800     }
00801   }
00802 }
00803 
00804 nsresult
00805 nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
00806                                      nsITextControlFrame* aFrame)
00807 {
00808   NS_PRECONDITION(mType != NS_FORM_INPUT_FILE,
00809                   "Don't call SetValueInternal for file inputs");
00810 
00811   if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) {
00812 
00813     nsITextControlFrame* textControlFrame = aFrame;
00814     nsIFormControlFrame* formControlFrame = textControlFrame;
00815     if (!textControlFrame) {
00816       // No need to flush here, if there's no frame at this point we
00817       // don't need to force creation of one just to tell it about this
00818       // new value.
00819       formControlFrame = GetFormControlFrame(PR_FALSE);
00820 
00821       if (formControlFrame) {
00822         CallQueryInterface(formControlFrame, &textControlFrame);
00823       }
00824     }
00825 
00826     // File frames always own the value (if the frame is there).
00827     // Text frames have a bit that says whether they own the value.
00828     PRBool frameOwnsValue = PR_FALSE;
00829     if (textControlFrame) {
00830       textControlFrame->OwnsValue(&frameOwnsValue);
00831     }
00832     // If the frame owns the value, set the value in the frame
00833     if (frameOwnsValue) {
00834       nsCOMPtr<nsPresContext> presContext = GetPresContext();
00835       formControlFrame->SetProperty(presContext, nsHTMLAtoms::value, aValue);
00836       return NS_OK;
00837     }
00838 
00839     // If the frame does not own the value, set mValue
00840     if (mValue) {
00841       nsMemory::Free(mValue);
00842     }
00843 
00844     mValue = ToNewUTF8String(aValue);
00845 
00846     SetValueChanged(PR_TRUE);
00847     return mValue ? NS_OK : NS_ERROR_OUT_OF_MEMORY;
00848   }
00849 
00850   if (mType == NS_FORM_INPUT_FILE) {
00851     return NS_ERROR_UNEXPECTED;
00852   }
00853 
00854   // If the value of a hidden input was changed, we mark it changed so that we
00855   // will know we need to save / restore the value.  Yes, we are overloading
00856   // the meaning of ValueChanged just a teensy bit to save a measly byte of
00857   // storage space in nsHTMLInputElement.  Yes, you are free to make a new flag,
00858   // NEED_TO_SAVE_VALUE, at such time as mBitField becomes a 16-bit value.
00859   if (mType == NS_FORM_INPUT_HIDDEN) {
00860     SetValueChanged(PR_TRUE);
00861   }
00862 
00863   // Treat value == defaultValue for other input elements.
00864   return nsGenericHTMLFormElement::SetAttr(kNameSpaceID_None,
00865                                            nsHTMLAtoms::value, aValue,
00866                                            PR_TRUE);
00867 }
00868 
00869 NS_IMETHODIMP
00870 nsHTMLInputElement::SetValueChanged(PRBool aValueChanged)
00871 {
00872   SET_BOOLBIT(mBitField, BF_VALUE_CHANGED, aValueChanged);
00873   if (!aValueChanged) {
00874     if (mValue) {
00875       nsMemory::Free(mValue);
00876       mValue = nsnull;
00877     }
00878   }
00879   return NS_OK;
00880 }
00881 
00882 NS_IMETHODIMP 
00883 nsHTMLInputElement::GetChecked(PRBool* aChecked)
00884 {
00885   *aChecked = GET_BOOLBIT(mBitField, BF_CHECKED);
00886   return NS_OK;
00887 }
00888 
00889 NS_IMETHODIMP
00890 nsHTMLInputElement::SetCheckedChanged(PRBool aCheckedChanged)
00891 {
00892   if (mType == NS_FORM_INPUT_RADIO) {
00893     if (GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED) != aCheckedChanged) {
00894       nsCOMPtr<nsIRadioVisitor> visitor;
00895       NS_GetRadioSetCheckedChangedVisitor(aCheckedChanged,
00896                                           getter_AddRefs(visitor));
00897       VisitGroup(visitor);
00898     }
00899   } else {
00900     SetCheckedChangedInternal(aCheckedChanged);
00901   }
00902   return NS_OK;
00903 }
00904 
00905 NS_IMETHODIMP
00906 nsHTMLInputElement::SetCheckedChangedInternal(PRBool aCheckedChanged)
00907 {
00908   SET_BOOLBIT(mBitField, BF_CHECKED_CHANGED, aCheckedChanged);
00909   return NS_OK;
00910 }
00911 
00912 
00913 NS_IMETHODIMP
00914 nsHTMLInputElement::GetCheckedChanged(PRBool* aCheckedChanged)
00915 {
00916   *aCheckedChanged = GET_BOOLBIT(mBitField, BF_CHECKED_CHANGED);
00917   return NS_OK;
00918 }
00919 
00920 NS_IMETHODIMP
00921 nsHTMLInputElement::SetChecked(PRBool aChecked)
00922 {
00923   return DoSetChecked(aChecked);
00924 }
00925 
00926 nsresult
00927 nsHTMLInputElement::DoSetChecked(PRBool aChecked, PRBool aNotify)
00928 {
00929   nsresult rv = NS_OK;
00930 
00931   //
00932   // If the user or JS attempts to set checked, whether it actually changes the
00933   // value or not, we say the value was changed so that defaultValue don't
00934   // affect it no more.
00935   //
00936   SetCheckedChanged(PR_TRUE);
00937 
00938   //
00939   // Don't do anything if we're not changing whether it's checked (it would
00940   // screw up state actually, especially when you are setting radio button to
00941   // false)
00942   //
00943   PRBool checked = PR_FALSE;
00944   GetChecked(&checked);
00945   if (checked == aChecked) {
00946     return NS_OK;
00947   }
00948 
00949   //
00950   // Set checked
00951   //
00952   if (mType == NS_FORM_INPUT_RADIO) {
00953     //
00954     // For radio button, we need to do some extra fun stuff
00955     //
00956     if (aChecked) {
00957       rv = RadioSetChecked(aNotify);
00958     } else {
00959       rv = SetCheckedInternal(PR_FALSE, aNotify);
00960       nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
00961       if (container) {
00962         nsAutoString name;
00963         if (GetNameIfExists(name)) {
00964           container->SetCurrentRadioButton(name, nsnull);
00965         }
00966       }
00967     }
00968   } else {
00969     rv = SetCheckedInternal(aChecked, aNotify);
00970   }
00971 
00972   return rv;
00973 }
00974 
00975 NS_IMETHODIMP
00976 nsHTMLInputElement::RadioSetChecked(PRBool aNotify)
00977 {
00978   nsresult rv = NS_OK;
00979 
00980   //
00981   // Find the selected radio button so we can deselect it
00982   //
00983   nsCOMPtr<nsIDOMHTMLInputElement> currentlySelected;
00984   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
00985   // This is ONLY INITIALIZED IF container EXISTS
00986   nsAutoString name;
00987   PRBool nameExists = PR_FALSE;
00988   if (container) {
00989     nameExists = GetNameIfExists(name);
00990     if (nameExists) {
00991       container->GetCurrentRadioButton(name, getter_AddRefs(currentlySelected));
00992     }
00993   }
00994 
00995   //
00996   // Deselect the currently selected radio button
00997   //
00998   if (currentlySelected) {
00999     // Pass PR_TRUE for the aNotify parameter since the currently selected
01000     // button is already in the document.
01001     rv = NS_STATIC_CAST(nsHTMLInputElement*,
01002                         NS_STATIC_CAST(nsIDOMHTMLInputElement*, currentlySelected)
01003          )->SetCheckedInternal(PR_FALSE, PR_TRUE);
01004   }
01005 
01006   //
01007   // Actually select this one
01008   //
01009   if (NS_SUCCEEDED(rv)) {
01010     rv = SetCheckedInternal(PR_TRUE, aNotify);
01011   }
01012 
01013   //
01014   // Let the group know that we are now the One True Radio Button
01015   //
01016   NS_ENSURE_SUCCESS(rv, rv);
01017   if (container && nameExists) {
01018     rv = container->SetCurrentRadioButton(name, this);
01019   }
01020 
01021   return rv;
01022 }
01023 
01024 /* virtual */ already_AddRefed<nsIRadioGroupContainer>
01025 nsHTMLInputElement::GetRadioGroupContainer()
01026 {
01027   nsIRadioGroupContainer* retval = nsnull;
01028   if (mForm) {
01029     CallQueryInterface(mForm, &retval);
01030   } else {
01031     nsIDocument* currentDoc = GetCurrentDoc();
01032     if (currentDoc) {
01033       CallQueryInterface(currentDoc, &retval);
01034     }
01035   }
01036   return retval;
01037 }
01038 
01039 nsresult
01040 nsHTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext)
01041 {
01042   if (!mForm) {
01043     // Nothing to do here.
01044     return NS_OK;
01045   }
01046   
01047   // Find the first submit control in elements[]
01048   // and also check how many text controls we have in the form
01049   nsCOMPtr<nsIContent> submitControl;
01050   PRInt32 numTextControlsFound = 0;
01051 
01052   nsCOMPtr<nsISimpleEnumerator> formControls;
01053   mForm->GetControlEnumerator(getter_AddRefs(formControls));
01054 
01055   nsCOMPtr<nsISupports> currentControlSupports;
01056   nsCOMPtr<nsIFormControl> currentControl;
01057   PRBool hasMoreElements;
01058   nsresult rv;
01059   while (NS_SUCCEEDED(rv = formControls->HasMoreElements(&hasMoreElements)) &&
01060          hasMoreElements) {
01061     rv = formControls->GetNext(getter_AddRefs(currentControlSupports));
01062     NS_ENSURE_SUCCESS(rv, rv);
01063 
01064     currentControl = do_QueryInterface(currentControlSupports);
01065     if (currentControl) {
01066       PRInt32 type = currentControl->GetType();
01067       if (!submitControl &&
01068           (type == NS_FORM_INPUT_SUBMIT ||
01069            type == NS_FORM_BUTTON_SUBMIT ||
01070            type == NS_FORM_INPUT_IMAGE)) {
01071         submitControl = do_QueryInterface(currentControl);
01072         // We know as soon as we find a submit control that it no
01073         // longer matters how many text controls there are--we are
01074         // going to fire the onClick handler.
01075         break;
01076       } else if (type == NS_FORM_INPUT_TEXT ||
01077                  type == NS_FORM_INPUT_PASSWORD) {
01078         numTextControlsFound++;
01079       }
01080     }
01081   }
01082   NS_ENSURE_SUCCESS(rv, rv);
01083             
01084   nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
01085   if (shell) {
01086     if (submitControl) {
01087       // Fire the button's onclick handler and let the button handle
01088       // submitting the form.
01089       nsMouseEvent event(PR_TRUE, NS_MOUSE_LEFT_CLICK, nsnull,
01090                          nsMouseEvent::eReal);
01091       nsEventStatus status = nsEventStatus_eIgnore;
01092       shell->HandleDOMEventWithTarget(submitControl, &event, &status);
01093     } else if (numTextControlsFound == 1) {
01094       // If there's only one text control, just submit the form
01095       nsCOMPtr<nsIContent> form = do_QueryInterface(mForm);
01096       nsFormEvent event(PR_TRUE, NS_FORM_SUBMIT);
01097       nsEventStatus status  = nsEventStatus_eIgnore;
01098       shell->HandleDOMEventWithTarget(form, &event, &status);
01099     }
01100   }
01101 
01102   return NS_OK;
01103 }
01104 
01105 nsresult
01106 nsHTMLInputElement::SetCheckedInternal(PRBool aChecked, PRBool aNotify)
01107 {
01108   //
01109   // Set the value
01110   //
01111   SET_BOOLBIT(mBitField, BF_CHECKED, aChecked);
01112 
01113   //
01114   // Notify the frame
01115   //
01116   nsIFrame* frame = GetPrimaryFrame(PR_FALSE);
01117   if (frame) {
01118     nsPresContext *presContext = GetPresContext();
01119 
01120     if (mType == NS_FORM_INPUT_CHECKBOX) {
01121       nsICheckboxControlFrame* checkboxFrame = nsnull;
01122       CallQueryInterface(frame, &checkboxFrame);
01123       if (checkboxFrame) {
01124         checkboxFrame->OnChecked(presContext, aChecked);
01125       }
01126     } else if (mType == NS_FORM_INPUT_RADIO) {
01127       nsIRadioControlFrame* radioFrame = nsnull;
01128       CallQueryInterface(frame, &radioFrame);
01129       if (radioFrame) {
01130         radioFrame->OnChecked(presContext, aChecked);
01131       }
01132     }
01133   }
01134 
01135   // Notify the document that the CSS :checked pseudoclass for this element
01136   // has changed state.
01137   if (aNotify) {
01138     nsIDocument* document = GetCurrentDoc();
01139     if (document) {
01140       mozAutoDocUpdate(document, UPDATE_CONTENT_STATE, aNotify);
01141       document->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_CHECKED);
01142     }
01143   }
01144 
01145   return NS_OK;
01146 }
01147 
01148 
01149 void
01150 nsHTMLInputElement::FireOnChange()
01151 {
01152   //
01153   // Since the value is changing, send out an onchange event (bug 23571)
01154   //
01155   nsEventStatus status = nsEventStatus_eIgnore;
01156   nsEvent event(PR_TRUE, NS_FORM_CHANGE);
01157   nsCOMPtr<nsPresContext> presContext = GetPresContext();
01158   HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status);
01159 }
01160 
01161 NS_IMETHODIMP
01162 nsHTMLInputElement::Blur()
01163 {
01164   if (ShouldFocus(this)) {
01165     SetElementFocus(PR_FALSE);
01166   }
01167 
01168   return NS_OK;
01169 }
01170 
01171 NS_IMETHODIMP
01172 nsHTMLInputElement::Focus()
01173 {
01174   if (ShouldFocus(this) && !GET_BOOLBIT(mBitField, BF_SETTING_FILE_FOCUS)) {
01175     if (mType == NS_FORM_INPUT_FILE) {
01176       SET_BOOLBIT(mBitField, BF_SETTING_FILE_FOCUS, PR_TRUE);
01177     }
01178     SetElementFocus(PR_TRUE);
01179     SET_BOOLBIT(mBitField, BF_SETTING_FILE_FOCUS, PR_FALSE);
01180   }
01181 
01182   return NS_OK;
01183 }
01184 
01185 void
01186 nsHTMLInputElement::FocusFileInputButton(nsIFormControlFrame* aFormControlFrame,
01187                                          nsPresContext* aPresContext)
01188 {
01189   NS_ASSERTION(mType == NS_FORM_INPUT_FILE, "Wrong type of input element!");
01190   nsIFrame* frame = nsnull;
01191   CallQueryInterface(aFormControlFrame, &frame);
01192   if (frame) {
01193     for (frame = frame->GetFirstChild(nsnull);
01194          frame;
01195          frame = frame->GetNextSibling()) {
01196       nsCOMPtr<nsIFormControl> control = do_QueryInterface(frame->GetContent());
01197       if (control && control->GetType() == NS_FORM_INPUT_BUTTON) {
01198         frame->GetContent()->SetFocus(aPresContext);
01199         return;
01200       }
01201     }
01202   }
01203 }
01204 
01205 void
01206 nsHTMLInputElement::SetFocus(nsPresContext* aPresContext)
01207 {
01208   if (!aPresContext)
01209     return;
01210 
01211   // We can't be focus'd if we aren't in a document
01212   nsIDocument* doc = GetCurrentDoc();
01213   if (!doc)
01214     return;
01215 
01216   // first see if we are disabled or not. If disabled then do nothing.
01217   nsAutoString disabled;
01218   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttr(kNameSpaceID_None,
01219                                            nsHTMLAtoms::disabled, disabled)) {
01220     return;
01221   }
01222  
01223   // If the window is not active, do not allow the focus to bring the
01224   // window to the front.  We update the focus controller, but do
01225   // nothing else.
01226   nsCOMPtr<nsPIDOMWindow> win =
01227     do_QueryInterface(doc->GetScriptGlobalObject());
01228   if (win) {
01229     nsIFocusController *focusController = win->GetRootFocusController();
01230     if (focusController) {
01231       PRBool isActive = PR_FALSE;
01232       focusController->GetActive(&isActive);
01233       if (!isActive) {
01234         focusController->SetFocusedWindow(win);
01235         focusController->SetFocusedElement(this);
01236 
01237         return;
01238       }
01239     }
01240   }
01241 
01242   aPresContext->EventStateManager()->SetContentState(this,
01243                                                      NS_EVENT_STATE_FOCUS);
01244 
01245   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
01246 
01247   if (formControlFrame) {
01248     if (mType == NS_FORM_INPUT_FILE &&
01249         GET_BOOLBIT(mBitField, BF_SETTING_FILE_FOCUS)) {
01250       FocusFileInputButton(formControlFrame, aPresContext);
01251       return;
01252     }
01253     formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
01254     formControlFrame->ScrollIntoView(aPresContext);
01255     // Could call SelectAll(aPresContext) here to automatically
01256     // select text when we receive focus - only for text and password!
01257   }
01258 }
01259 
01260 NS_IMETHODIMP
01261 nsHTMLInputElement::Select()
01262 {
01263   nsresult rv = NS_OK;
01264 
01265   nsIDocument* doc = GetCurrentDoc();
01266   if (!doc)
01267     return NS_OK;
01268 
01269   // first see if we are disabled or not. If disabled then do nothing.
01270   nsAutoString disabled;
01271   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttr(kNameSpaceID_None,
01272                                            nsHTMLAtoms::disabled, disabled)) {
01273     return rv;
01274   }
01275 
01276   if (mType == NS_FORM_INPUT_PASSWORD || mType == NS_FORM_INPUT_TEXT) {
01277     // XXX Bug?  We have to give the input focus before contents can be
01278     // selected
01279 
01280     nsCOMPtr<nsPresContext> presContext = GetPresContext();
01281 
01282     // If the window is not active, do not allow the select to bring the
01283     // window to the front.  We update the focus controller, but do
01284     // nothing else.
01285     nsCOMPtr<nsPIDOMWindow> win =
01286       do_QueryInterface(doc->GetScriptGlobalObject());
01287     if (win) {
01288       nsIFocusController *focusController = win->GetRootFocusController();
01289       if (focusController) {
01290         PRBool isActive = PR_FALSE;
01291         focusController->GetActive(&isActive);
01292         if (!isActive) {
01293           focusController->SetFocusedWindow(win);
01294           focusController->SetFocusedElement(this);
01295           SelectAll(presContext);
01296           return NS_OK;
01297         }
01298       }
01299     }
01300 
01301     // Just like SetFocus() but without the ScrollIntoView()!
01302     nsEventStatus status = nsEventStatus_eIgnore;
01303     
01304     //If already handling select event, don't dispatch a second.
01305     if (!GET_BOOLBIT(mBitField, BF_HANDLING_SELECT_EVENT)) {
01306       nsEvent event(nsContentUtils::IsCallerChrome(), NS_FORM_SELECTED);
01307 
01308       SET_BOOLBIT(mBitField, BF_HANDLING_SELECT_EVENT, PR_TRUE);
01309       rv = HandleDOMEvent(presContext, &event, nsnull, NS_EVENT_FLAG_INIT,
01310                           &status);
01311       SET_BOOLBIT(mBitField, BF_HANDLING_SELECT_EVENT, PR_FALSE);
01312     }
01313 
01314     // If the DOM event was not canceled (e.g. by a JS event handler
01315     // returning false)
01316     if (status == nsEventStatus_eIgnore) {
01317       PRBool shouldFocus = ShouldFocus(this);
01318 
01319       if (presContext && shouldFocus) {
01320         nsIEventStateManager *esm = presContext->EventStateManager();
01321         // XXX Fix for bug 135345 - ESM currently does not check to see if we
01322         // have focus before attempting to set focus again and may cause
01323         // infinite recursion.  For now check if we have focus and do not set
01324         // focus again if already focused.
01325         PRInt32 currentState;
01326         esm->GetContentState(this, currentState);
01327         if (!(currentState & NS_EVENT_STATE_FOCUS)) {
01328           esm->SetContentState(this, NS_EVENT_STATE_FOCUS);
01329         }
01330       }
01331 
01332       nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
01333 
01334       if (formControlFrame) {
01335         if (shouldFocus) {
01336           formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
01337         }
01338 
01339         // Now Select all the text!
01340         SelectAll(presContext);
01341       }
01342     }
01343   }
01344 
01345   return rv;
01346 }
01347 
01348 void
01349 nsHTMLInputElement::SelectAll(nsPresContext* aPresContext)
01350 {
01351   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
01352 
01353   if (formControlFrame) {
01354     formControlFrame->SetProperty(aPresContext, nsHTMLAtoms::select,
01355                                   EmptyString());
01356   }
01357 }
01358 
01359 NS_IMETHODIMP
01360 nsHTMLInputElement::Click()
01361 {
01362   nsresult rv = NS_OK;
01363 
01364   if (GET_BOOLBIT(mBitField, BF_HANDLING_CLICK)) // Fixes crash as in bug 41599
01365       return rv;                      // --heikki@netscape.com
01366 
01367   // first see if we are disabled or not. If disabled then do nothing.
01368   nsAutoString disabled;
01369   if (NS_CONTENT_ATTR_HAS_VALUE == GetAttr(kNameSpaceID_None,
01370                                            nsHTMLAtoms::disabled, disabled)) {
01371     return rv;
01372   }
01373 
01374   // see what type of input we are.  Only click button, checkbox, radio,
01375   // reset, submit, & image
01376   if (mType == NS_FORM_INPUT_BUTTON   ||
01377       mType == NS_FORM_INPUT_CHECKBOX ||
01378       mType == NS_FORM_INPUT_RADIO    ||
01379       mType == NS_FORM_INPUT_RESET    ||
01380       mType == NS_FORM_INPUT_SUBMIT   ||
01381       mType == NS_FORM_INPUT_IMAGE) {
01382 
01383     // Strong in case the event kills it
01384     nsCOMPtr<nsIDocument> doc = GetCurrentDoc();
01385     if (!doc) {
01386       return rv;
01387     }
01388     
01389     nsIPresShell *shell = doc->GetShellAt(0);
01390 
01391     if (shell) {
01392       nsCOMPtr<nsPresContext> context = shell->GetPresContext();
01393 
01394       if (context) {
01395         // Click() is never called from native code, but it may be
01396         // called from chrome JS. Mark this event trusted if Click()
01397         // is called from chrome code.
01398         nsMouseEvent event(nsContentUtils::IsCallerChrome(),
01399                            NS_MOUSE_LEFT_CLICK, nsnull,
01400                            nsMouseEvent::eReal);
01401         nsEventStatus status = nsEventStatus_eIgnore;
01402 
01403         SET_BOOLBIT(mBitField, BF_HANDLING_CLICK, PR_TRUE);
01404 
01405         rv = HandleDOMEvent(context, &event, nsnull, NS_EVENT_FLAG_INIT,
01406                             &status);
01407 
01408         SET_BOOLBIT(mBitField, BF_HANDLING_CLICK, PR_FALSE);
01409       }
01410     }
01411   }
01412   
01413   return NS_OK;
01414 }
01415 
01416 nsresult
01417 nsHTMLInputElement::HandleDOMEvent(nsPresContext* aPresContext,
01418                                    nsEvent* aEvent,
01419                                    nsIDOMEvent** aDOMEvent,
01420                                    PRUint32 aFlags,
01421                                    nsEventStatus* aEventStatus)
01422 {
01423   NS_ENSURE_ARG_POINTER(aEventStatus);
01424 
01425   // Do not process any DOM events if the element is disabled
01426   PRBool disabled;
01427   nsresult rv = GetDisabled(&disabled);
01428   NS_ENSURE_SUCCESS(rv, rv);
01429   if (disabled) {
01430     return NS_OK;
01431   }
01432   
01433   // For some reason or another we also need to check if the style shows us
01434   // as disabled.
01435   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
01436   if (formControlFrame) {
01437     nsIFrame* formFrame = nsnull;
01438     CallQueryInterface(formControlFrame, &formFrame);
01439     if (formFrame) {
01440       const nsStyleUserInterface* uiStyle = formFrame->GetStyleUserInterface();
01441 
01442       if (uiStyle->mUserInput == NS_STYLE_USER_INPUT_NONE ||
01443           uiStyle->mUserInput == NS_STYLE_USER_INPUT_DISABLED) {
01444         return NS_OK;
01445       }
01446     }
01447   }
01448 
01449   // Don't allow mutation events which are targeted somewhere inside
01450   // <input>, except if they are dispatched to the element itself.
01451   if (!(NS_EVENT_FLAG_INIT & aFlags) &&
01452       aEvent->eventStructType == NS_MUTATION_EVENT) {
01453     return NS_OK;
01454   }
01455 
01456   if (!(NS_EVENT_FLAG_INIT & aFlags) &&
01457       aEvent->message == NS_FORM_INPUT &&
01458       formControlFrame) {
01459     nsAutoString fName;
01460     formControlFrame->GetProperty(nsHTMLAtoms::filename, fName);
01461     mFileName = fName.IsEmpty() ? nsnull : new nsString(fName);
01462   }
01463 
01464   //
01465   // Web pages expect the value of a radio button or checkbox to be set
01466   // *before* onclick and DOMActivate fire, and they expect that if they set
01467   // the value explicitly during onclick or DOMActivate it will not be toggled
01468   // or any such nonsense.
01469   // In order to support that (bug 57137 and 58460 are examples) we toggle
01470   // the checked attribute *first*, and then fire onclick.  If the user
01471   // returns false, we reset the control to the old checked value.  Otherwise,
01472   // we dispatch DOMActivate.  If DOMActivate is cancelled, we also reset
01473   // the control to the old checked value.  We need to keep track of whether
01474   // we've already toggled the state from onclick since the user could
01475   // explicitly dispatch DOMActivate on the element.
01476   //
01477   // This is a compatibility hack.
01478   //
01479 
01480   // Track whether we're in the outermost HandleDOMEvent invocation that will
01481   // cause activation of the input.  That is, if we're a click event, or a
01482   // DOMActivate that was dispatched directly, this will be set, but if we're
01483   // a DOMActivate dispatched from click handling, it will not be set.
01484   PRBool outerActivateEvent =
01485     !(aFlags & NS_EVENT_FLAG_CAPTURE) &&
01486     !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) &&
01487     (aEvent->message == NS_MOUSE_LEFT_CLICK ||
01488      (aEvent->message == NS_UI_ACTIVATE &&
01489       !GET_BOOLBIT(mBitField, BF_IN_INTERNAL_ACTIVATE)));
01490 
01491   PRBool originalCheckedValue = PR_FALSE;
01492 
01493   nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton;
01494 
01495   if (outerActivateEvent) {
01496 
01497     SET_BOOLBIT(mBitField, BF_CHECKED_IS_TOGGLED, PR_FALSE);
01498 
01499     switch(mType) {
01500       case NS_FORM_INPUT_CHECKBOX:
01501         {
01502           GetChecked(&originalCheckedValue);
01503           DoSetChecked(!originalCheckedValue);
01504           SET_BOOLBIT(mBitField, BF_CHECKED_IS_TOGGLED, PR_TRUE);
01505         }
01506         break;
01507 
01508       case NS_FORM_INPUT_RADIO:
01509         {
01510           nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
01511           if (container) {
01512             nsAutoString name;
01513             if (GetNameIfExists(name)) {
01514               container->GetCurrentRadioButton(name,
01515                                                getter_AddRefs(selectedRadioButton));
01516             }
01517           }
01518 
01519           GetChecked(&originalCheckedValue);
01520           if (!originalCheckedValue) {
01521             DoSetChecked(PR_TRUE);
01522             SET_BOOLBIT(mBitField, BF_CHECKED_IS_TOGGLED, PR_TRUE);
01523           }
01524         }
01525         break;
01526 
01527       case NS_FORM_INPUT_SUBMIT:
01528       case NS_FORM_INPUT_IMAGE:
01529         if(mForm) {
01530           // tell the form that we are about to enter a click handler.
01531           // that means that if there are scripted submissions, the
01532           // latest one will be deferred until after the exit point of the handler. 
01533           mForm->OnSubmitClickBegin();
01534         }
01535         break;
01536 
01537       default:
01538         break;
01539     } //switch
01540   }
01541 
01542   // If NS_EVENT_FLAG_NO_CONTENT_DISPATCH is set we will not allow content to handle
01543   // this event.  But to allow middle mouse button paste to work we must allow 
01544   // middle clicks to go to text fields anyway.
01545   PRBool noContentDispatch = aEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH;
01546   if ((mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) &&
01547       aEvent->message == NS_MOUSE_MIDDLE_CLICK) {
01548     aEvent->flags &= ~NS_EVENT_FLAG_NO_CONTENT_DISPATCH;
01549   }
01550 
01551   // We must cache type because mType may change during JS event (bug 2369)
01552   //
01553   PRInt32 oldType = mType;
01554 
01555   // Try script event handlers first if its not a focus/blur event
01556   //we dont want the doc to get these
01557   rv = nsGenericHTMLFormElement::HandleDOMEvent(aPresContext, aEvent,
01558                                                 aDOMEvent, aFlags,
01559                                                 aEventStatus);
01560 
01561   // Ideally we would make the default action for click and space just dispatch
01562   // DOMActivate, and the default action for DOMActivate flip the checkbox/
01563   // radio state and fire onchange.  However, for backwards compatibility, we
01564   // need to flip the state before firing click, and we need to fire click
01565   // when space is pressed.  So, we just nest the firing of DOMActivate inside
01566   // the click event handling, and allow cancellation of DOMActivate to cancel
01567   // the click.
01568   if (*aEventStatus != nsEventStatus_eConsumeNoDefault &&
01569       !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT) &&
01570       aEvent->message == NS_MOUSE_LEFT_CLICK && mType != NS_FORM_INPUT_TEXT) {
01571     nsUIEvent actEvent(NS_IS_TRUSTED_EVENT(aEvent), NS_UI_ACTIVATE, 1);
01572 
01573     nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
01574     if (shell) {
01575       nsEventStatus status = nsEventStatus_eIgnore;
01576       SET_BOOLBIT(mBitField, BF_IN_INTERNAL_ACTIVATE, PR_TRUE);
01577       rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
01578       SET_BOOLBIT(mBitField, BF_IN_INTERNAL_ACTIVATE, PR_FALSE);
01579 
01580       // If activate is cancelled, we must do the same as when click is
01581       // cancelled (revert the checkbox to its original value).
01582       if (status == nsEventStatus_eConsumeNoDefault)
01583         *aEventStatus = status;
01584     }
01585   }
01586 
01587   if (outerActivateEvent) {
01588     switch(oldType) {
01589       case NS_FORM_INPUT_SUBMIT:
01590       case NS_FORM_INPUT_IMAGE:
01591         if(mForm) {
01592           // tell the form that we are about to exit a click handler
01593           // so the form knows not to defer subsequent submissions
01594           // the pending ones that were created during the handler
01595           // will be flushed or forgoten.
01596           mForm->OnSubmitClickEnd();
01597         }
01598         break;
01599     } //switch
01600   }
01601 
01602   // Reset the flag for other content besides this text field
01603   aEvent->flags |= noContentDispatch ? NS_EVENT_FLAG_NO_CONTENT_DISPATCH : NS_EVENT_FLAG_NONE;
01604 
01605   // now check to see if the event was "cancelled"
01606   if (GET_BOOLBIT(mBitField, BF_CHECKED_IS_TOGGLED) && outerActivateEvent) {
01607     if (*aEventStatus == nsEventStatus_eConsumeNoDefault) {
01608       // if it was cancelled and a radio button, then set the old
01609       // selected btn to TRUE. if it is a checkbox then set it to its
01610       // original value
01611       if (selectedRadioButton) {
01612         selectedRadioButton->SetChecked(PR_TRUE);
01613         // If this one is no longer a radio button we must reset it back to
01614         // false to cancel the action.  See how the web of hack grows?
01615         if (mType != NS_FORM_INPUT_RADIO) {
01616           DoSetChecked(PR_FALSE);
01617         }
01618       } else if (oldType == NS_FORM_INPUT_CHECKBOX) {
01619         DoSetChecked(originalCheckedValue);
01620       }
01621     } else {
01622       FireOnChange();
01623 #ifdef ACCESSIBILITY
01624       // Fire an event to notify accessibility
01625       if (mType == NS_FORM_INPUT_CHECKBOX) {
01626         FireEventForAccessibility(this, aPresContext,
01627                                   NS_LITERAL_STRING("CheckboxStateChange"));
01628       } else {
01629         FireEventForAccessibility(this, aPresContext,
01630                                   NS_LITERAL_STRING("RadioStateChange"));
01631         // Fire event for the previous selected radio.
01632         FireEventForAccessibility(selectedRadioButton, aPresContext,
01633                                   NS_LITERAL_STRING("RadioStateChange"));
01634       }
01635 #endif
01636     }
01637   }
01638 
01639   if (NS_SUCCEEDED(rv) && 
01640       !(aFlags & NS_EVENT_FLAG_CAPTURE) &&
01641       !(aFlags & NS_EVENT_FLAG_SYSTEM_EVENT)) {
01642     if (nsEventStatus_eIgnore == *aEventStatus) {
01643       if (mHasBeenDisabled) {
01644         MaybeClearFilename(aEvent, aDOMEvent, oldType);
01645       }
01646       switch (aEvent->message) {
01647 
01648         case NS_FOCUS_CONTENT:
01649         {
01650           // Check to see if focus has bubbled up from a form control's
01651           // child textfield or button.  If that's the case, don't focus
01652           // this parent file control -- leave focus on the child.
01653           nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
01654           if (formControlFrame && !(aFlags & NS_EVENT_FLAG_BUBBLE) &&
01655               ShouldFocus(this)) {
01656             // This is ugly, but if untrusted focus event is dispatched, set
01657             // focus to the 'Browse...' button, not to the text field.
01658             if (mType == NS_FORM_INPUT_FILE && !NS_IS_TRUSTED_EVENT(aEvent)) {
01659               FocusFileInputButton(formControlFrame, aPresContext);
01660             } else {
01661               formControlFrame->SetFocus(PR_TRUE, PR_TRUE);
01662             }
01663           }
01664         }                                                                         
01665         break; // NS_FOCUS_CONTENT
01666 
01667         case NS_KEY_PRESS:
01668         case NS_KEY_UP:
01669         {
01670           // For backwards compat, trigger checks/radios/buttons with
01671           // space or enter (bug 25300)
01672           nsKeyEvent * keyEvent = (nsKeyEvent *)aEvent;
01673 
01674           if ((aEvent->message == NS_KEY_PRESS &&
01675                keyEvent->keyCode == NS_VK_RETURN) ||
01676               (aEvent->message == NS_KEY_UP &&
01677                keyEvent->keyCode == NS_VK_SPACE)) {
01678             switch(mType) {
01679               case NS_FORM_INPUT_CHECKBOX:
01680               case NS_FORM_INPUT_RADIO:
01681               {
01682                 // Checkbox and Radio try to submit on Enter press
01683                 if (keyEvent->keyCode != NS_VK_SPACE) {
01684                   MaybeSubmitForm(aPresContext);
01685 
01686                   break;  // If we are submitting, do not send click event
01687                 }
01688                 // else fall through and treat Space like click...
01689               }
01690               case NS_FORM_INPUT_BUTTON:
01691               case NS_FORM_INPUT_RESET:
01692               case NS_FORM_INPUT_SUBMIT:
01693               case NS_FORM_INPUT_IMAGE: // Bug 34418
01694               {
01695                 nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent),
01696                                    NS_MOUSE_LEFT_CLICK, nsnull,
01697                                    nsMouseEvent::eReal);
01698                 nsEventStatus status = nsEventStatus_eIgnore;
01699 
01700                 rv = HandleDOMEvent(aPresContext, &event, nsnull,
01701                                     NS_EVENT_FLAG_INIT, &status);
01702               } // case
01703             } // switch
01704           }
01705           if (aEvent->message == NS_KEY_PRESS && mType == NS_FORM_INPUT_RADIO &&
01706               !keyEvent->isAlt && !keyEvent->isControl && !keyEvent->isMeta) {
01707             PRBool isMovingBack = PR_FALSE;
01708             switch (keyEvent->keyCode) {
01709               case NS_VK_UP: 
01710               case NS_VK_LEFT:
01711                 isMovingBack = PR_TRUE;
01712               case NS_VK_DOWN:
01713               case NS_VK_RIGHT:
01714               // Arrow key pressed, focus+select prev/next radio button
01715               nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
01716               if (container) {
01717                 nsAutoString name;
01718                 if (GetNameIfExists(name)) {
01719                   container->GetNextRadioButton(name, isMovingBack, this,
01720                                                 getter_AddRefs(selectedRadioButton));
01721                   nsCOMPtr<nsIContent> radioContent =
01722                     do_QueryInterface(selectedRadioButton);
01723                   if (radioContent) {
01724                     rv = selectedRadioButton->Focus();
01725                     if (NS_SUCCEEDED(rv)) {
01726                       nsEventStatus status = nsEventStatus_eIgnore;
01727                       nsMouseEvent event(NS_IS_TRUSTED_EVENT(aEvent),
01728                                          NS_MOUSE_LEFT_CLICK, nsnull,
01729                                          nsMouseEvent::eReal);
01730                       rv = radioContent->HandleDOMEvent(aPresContext, &event,
01731                                                         nsnull, NS_EVENT_FLAG_INIT, 
01732                                                         &status);
01733                       if (NS_SUCCEEDED(rv)) {
01734                         *aEventStatus = nsEventStatus_eConsumeNoDefault;
01735                       }
01736                     }
01737                   }
01738                 }
01739               }
01740             }
01741           }
01742 
01743           /*
01744            * If this is input type=text, and the user hit enter, fire onChange
01745            * and submit the form (if we are in one)
01746            *
01747            * Bug 99920, bug 109463 and bug 147850:
01748            * (a) if there is a submit control in the form, click the first
01749            *     submit control in the form.
01750            * (b) if there is just one text control in the form, submit by
01751            *     sending a submit event directly to the form
01752            * (c) if there is more than one text input and no submit buttons, do
01753            *     not submit, period.
01754            */
01755 
01756           if (aEvent->message == NS_KEY_PRESS &&
01757               (keyEvent->keyCode == NS_VK_RETURN ||
01758                keyEvent->keyCode == NS_VK_ENTER) &&
01759               (mType == NS_FORM_INPUT_TEXT ||
01760                mType == NS_FORM_INPUT_PASSWORD ||
01761                mType == NS_FORM_INPUT_FILE)) {
01762 
01763             PRBool isButton = PR_FALSE;
01764             // If this is an enter on the button of a file input, don't submit
01765             // -- that's supposed to put up the filepicker
01766             if (mType == NS_FORM_INPUT_FILE && aDOMEvent) {
01767               nsCOMPtr<nsIDOMNSEvent> nsEvent(do_QueryInterface(*aDOMEvent));
01768               if (nsEvent) {
01769                 nsCOMPtr<nsIDOMEventTarget> originalTarget;
01770                 nsEvent->GetOriginalTarget(getter_AddRefs(originalTarget));
01771                 nsCOMPtr<nsIContent> maybeButton(do_QueryInterface(originalTarget));
01772                 if (maybeButton) {
01773                   nsAutoString type;
01774                   maybeButton->GetAttr(kNameSpaceID_None, nsHTMLAtoms::type,
01775                                        type);
01776                   isButton = type.EqualsLiteral("button");
01777                 }
01778               }
01779             }
01780             
01781             if (!isButton) {
01782               nsIFrame* primaryFrame = GetPrimaryFrame(PR_FALSE);
01783               if (primaryFrame) {
01784                 nsITextControlFrame* textFrame = nsnull;
01785                 CallQueryInterface(primaryFrame, &textFrame);
01786               
01787                 // Fire onChange (if necessary)
01788                 if (textFrame) {
01789                   textFrame->CheckFireOnChange();
01790                 }
01791               }
01792 
01793               rv = MaybeSubmitForm(aPresContext);
01794               NS_ENSURE_SUCCESS(rv, rv);
01795             }
01796           }
01797 
01798         } break; // NS_KEY_PRESS || NS_KEY_UP
01799 
01800         // cancel all of these events for buttons
01801         case NS_MOUSE_MIDDLE_BUTTON_DOWN:
01802         case NS_MOUSE_MIDDLE_BUTTON_UP:
01803         case NS_MOUSE_MIDDLE_DOUBLECLICK:
01804         case NS_MOUSE_RIGHT_DOUBLECLICK:
01805         case NS_MOUSE_RIGHT_BUTTON_DOWN:
01806         case NS_MOUSE_RIGHT_BUTTON_UP:
01807         {
01808           if (mType == NS_FORM_INPUT_BUTTON || 
01809               mType == NS_FORM_INPUT_RESET || 
01810               mType == NS_FORM_INPUT_SUBMIT ) {
01811             if (aDOMEvent) {
01812               (*aDOMEvent)->StopPropagation();
01813             } else {
01814               rv = NS_ERROR_FAILURE;
01815             }
01816           }
01817 
01818           break;
01819         }
01820       default:
01821         break;
01822       }
01823 
01824       if (outerActivateEvent) {
01825         if (mForm && (oldType == NS_FORM_INPUT_SUBMIT ||
01826                       oldType == NS_FORM_INPUT_IMAGE)) {
01827           if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE) {
01828             // If the type has changed to a non-submit type, then we want to
01829             // flush the stored submission if there is one (as if the submit()
01830             // was allowed to succeed)
01831             mForm->FlushPendingSubmission();
01832           }
01833         }
01834         switch(mType) {
01835         case NS_FORM_INPUT_RESET:
01836         case NS_FORM_INPUT_SUBMIT:
01837         case NS_FORM_INPUT_IMAGE:
01838           if (mForm) {
01839             nsFormEvent event(PR_TRUE, (mType == NS_FORM_INPUT_RESET) ?
01840                               NS_FORM_RESET : NS_FORM_SUBMIT);
01841             event.originator      = this;
01842             nsEventStatus status  = nsEventStatus_eIgnore;
01843 
01844             nsCOMPtr<nsIPresShell> presShell = aPresContext->GetPresShell();
01845 
01846             // If |nsIPresShell::Destroy| has been called due to
01847             // handling the event (base class HandleDOMEvent, above),
01848             // the pres context will return a null pres shell.  See
01849             // bug 125624.
01850             if (presShell) {
01851               nsCOMPtr<nsIContent> form(do_QueryInterface(mForm));
01852               presShell->HandleDOMEventWithTarget(form, &event, &status);
01853             }
01854           }
01855           break;
01856 
01857         default:
01858           break;
01859         } //switch 
01860       } //click or outer activate event
01861     } else {
01862       if (outerActivateEvent &&
01863           (oldType == NS_FORM_INPUT_SUBMIT || oldType == NS_FORM_INPUT_IMAGE) &&
01864           mForm) {
01865         // tell the form to flush a possible pending submission.
01866         // the reason is that the script returned false (the event was
01867         // not ignored) so if there is a stored submission, it needs to
01868         // be submitted immediately.
01869         mForm->FlushPendingSubmission();
01870       } else {
01871         // Because of security issues related to type="file", canceling default
01872         // action may clear file name.
01873         MaybeClearFilename(aEvent, aDOMEvent, oldType);
01874       }
01875     } //if
01876   } // if
01877 
01878   return rv;
01879 }
01880 
01881 
01882 nsresult
01883 nsHTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
01884                                nsIContent* aBindingParent,
01885                                PRBool aCompileEventHandlers)
01886 {
01887   nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
01888                                                      aBindingParent,
01889                                                      aCompileEventHandlers);
01890   NS_ENSURE_SUCCESS(rv, rv);
01891 
01892   if (mType == NS_FORM_INPUT_IMAGE) {
01893     // Our base URI may have changed; claim that our URI changed, and the
01894     // nsImageLoadingContent will decide whether a new image load is warranted.
01895     nsAutoString uri;
01896     nsresult result = GetAttr(kNameSpaceID_None, nsHTMLAtoms::src, uri);
01897     if (result == NS_CONTENT_ATTR_HAS_VALUE) {
01898       ImageURIChanged(uri, PR_FALSE);
01899     }
01900   }
01901 
01902   // Add radio to document if we don't have a form already (if we do it's
01903   // already been added into that group)
01904   if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) {
01905     AddedToRadioGroup();
01906   }
01907 
01908   return rv;
01909 }
01910 
01911 void
01912 nsHTMLInputElement::UnbindFromTree(PRBool aDeep, PRBool aNullParent)
01913 {
01914   // If we have a form and are unbound from it,
01915   // nsGenericHTMLFormElement::UnbindFromTree() will unset the form and
01916   // that takes care of form's WillRemove so we just have to take care
01917   // of the case where we're removing from the document and we don't
01918   // have a form
01919   if (!mForm && mType == NS_FORM_INPUT_RADIO) {
01920     WillRemoveFromRadioGroup();
01921   }
01922 
01923   nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
01924 }
01925 
01926 static const nsAttrValue::EnumTable kInputTypeTable[] = {
01927   { "button", NS_FORM_INPUT_BUTTON },
01928   { "checkbox", NS_FORM_INPUT_CHECKBOX },
01929   { "file", NS_FORM_INPUT_FILE },
01930   { "hidden", NS_FORM_INPUT_HIDDEN },
01931   { "reset", NS_FORM_INPUT_RESET },
01932   { "image", NS_FORM_INPUT_IMAGE },
01933   { "password", NS_FORM_INPUT_PASSWORD },
01934   { "radio", NS_FORM_INPUT_RADIO },
01935   { "submit", NS_FORM_INPUT_SUBMIT },
01936   { "text", NS_FORM_INPUT_TEXT },
01937   { 0 }
01938 };
01939 
01940 PRBool
01941 nsHTMLInputElement::ParseAttribute(nsIAtom* aAttribute,
01942                                    const nsAString& aValue,
01943                                    nsAttrValue& aResult)
01944 {
01945   if (aAttribute == nsHTMLAtoms::type) {
01946     // XXX ARG!! This is major evilness. ParseAttribute
01947     // shouldn't set members. Override SetAttr instead
01948     if (!aResult.ParseEnumValue(aValue, kInputTypeTable)) {
01949       mType = NS_FORM_INPUT_TEXT;
01950       return PR_FALSE;
01951     }
01952 
01953     // Make sure to do the check for newType being NS_FORM_INPUT_FILE and the
01954     // corresponding SetValueInternal() call _before_ we set mType.  That way
01955     // the logic in SetValueInternal() will work right (that logic makes
01956     // assumptions about our frame based on mType, but we won't have had time
01957     // to recreate frames yet -- that happens later in the SetAttr()
01958     // process).
01959     PRInt8 newType = aResult.GetEnumValue();
01960     if (newType == NS_FORM_INPUT_FILE) {      
01961       // These calls aren't strictly needed any more since we'll never
01962       // confuse values and filenames. However they're there for backwards
01963       // compat.
01964       SetFileName(EmptyString(), PR_TRUE);
01965       SetValueInternal(EmptyString(), nsnull);
01966     }
01967 
01968     mType = newType;
01969     
01970     return PR_TRUE;
01971   }
01972   if (aAttribute == nsHTMLAtoms::width) {
01973     return aResult.ParseSpecialIntValue(aValue, PR_TRUE, PR_FALSE);
01974   }
01975   if (aAttribute == nsHTMLAtoms::height) {
01976     return aResult.ParseSpecialIntValue(aValue, PR_TRUE, PR_FALSE);
01977   }
01978   if (aAttribute == nsHTMLAtoms::maxlength) {
01979     return aResult.ParseIntWithBounds(aValue, 0);
01980   }
01981   if (aAttribute == nsHTMLAtoms::size) {
01982     return aResult.ParseIntWithBounds(aValue, 0);
01983   }
01984   if (aAttribute == nsHTMLAtoms::border) {
01985     return aResult.ParseIntWithBounds(aValue, 0);
01986   }
01987   if (aAttribute == nsHTMLAtoms::align) {
01988     return ParseAlignValue(aValue, aResult);
01989   }
01990   if (ParseImageAttribute(aAttribute, aValue, aResult)) {
01991     // We have to call |ParseImageAttribute| unconditionally since we
01992     // don't know if we're going to have a type="image" attribute yet,
01993     // (or could have it set dynamically in the future).  See bug
01994     // 214077.
01995     return PR_TRUE;
01996   }
01997 
01998   return nsGenericHTMLElement::ParseAttribute(aAttribute, aValue, aResult);
01999 }
02000 
02001 NS_IMETHODIMP
02002 nsHTMLInputElement::GetType(nsAString& aValue)
02003 {
02004   const nsAttrValue::EnumTable *table = kInputTypeTable;
02005 
02006   while (table->tag) {
02007     if (mType == table->value) {
02008       CopyUTF8toUTF16(table->tag, aValue);
02009 
02010       return NS_OK;
02011     }
02012 
02013     ++table;
02014   }
02015 
02016   NS_ERROR("Shouldn't get here!");
02017 
02018   aValue.Truncate();
02019 
02020   return NS_OK;
02021 }
02022 
02023 NS_IMETHODIMP
02024 nsHTMLInputElement::SetType(const nsAString& aValue)
02025 {
02026   return SetAttrHelper(nsHTMLAtoms::type, aValue);
02027 }
02028 
02029 static void
02030 MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
02031                       nsRuleData* aData)
02032 {
02033   const nsAttrValue* value = aAttributes->GetAttr(nsHTMLAtoms::type);
02034   if (value && value->Type() == nsAttrValue::eEnum &&
02035       value->GetEnumValue() == NS_FORM_INPUT_IMAGE) {
02036     nsGenericHTMLFormElement::MapImageBorderAttributeInto(aAttributes, aData);
02037     nsGenericHTMLFormElement::MapImageMarginAttributeInto(aAttributes, aData);
02038     nsGenericHTMLFormElement::MapImageSizeAttributesInto(aAttributes, aData);
02039     // Images treat align as "float"
02040     nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aData);
02041   } 
02042 
02043   nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aData);
02044 }
02045 
02046 nsChangeHint
02047 nsHTMLInputElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
02048                                            PRInt32 aModType) const
02049 {
02050   nsChangeHint retval =
02051     nsGenericHTMLFormElement::GetAttributeChangeHint(aAttribute, aModType);
02052   if (aAttribute == nsHTMLAtoms::type) {
02053     NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
02054   } else if (aAttribute == nsHTMLAtoms::value) {
02055     NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
02056   } else if (aAttribute == nsHTMLAtoms::size &&
02057              (mType == NS_FORM_INPUT_TEXT ||
02058               mType == NS_FORM_INPUT_PASSWORD)) {
02059     NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
02060   }
02061   return retval;
02062 }
02063 
02064 NS_IMETHODIMP_(PRBool)
02065 nsHTMLInputElement::IsAttributeMapped(const nsIAtom* aAttribute) const
02066 {
02067   static const MappedAttributeEntry attributes[] = {
02068     { &nsHTMLAtoms::align },
02069     { &nsHTMLAtoms::type },
02070     { nsnull },
02071   };
02072 
02073   static const MappedAttributeEntry* const map[] = {
02074     attributes,
02075     sCommonAttributeMap,
02076     sImageMarginSizeAttributeMap,
02077     sImageBorderAttributeMap,
02078   };
02079 
02080   return FindAttributeDependence(aAttribute, map, NS_ARRAY_LENGTH(map));
02081 }
02082 
02083 nsMapRuleToAttributesFunc
02084 nsHTMLInputElement::GetAttributeMappingFunction() const
02085 {
02086   return &MapAttributesIntoRule;
02087 }
02088 
02089 
02090 // Controllers Methods
02091 
02092 NS_IMETHODIMP
02093 nsHTMLInputElement::GetControllers(nsIControllers** aResult)
02094 {
02095   NS_ENSURE_ARG_POINTER(aResult);
02096 
02097   //XXX: what about type "file"?
02098   if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD)
02099   {
02100     if (!mControllers)
02101     {
02102       nsresult rv;
02103       mControllers = do_CreateInstance(kXULControllersCID, &rv);
02104       NS_ENSURE_SUCCESS(rv, rv);
02105 
02106       nsCOMPtr<nsIController>
02107         controller(do_CreateInstance("@mozilla.org/editor/editorcontroller;1",
02108                                      &rv));
02109       NS_ENSURE_SUCCESS(rv, rv);
02110 
02111       mControllers->AppendController(controller);
02112     }
02113   }
02114 
02115   *aResult = mControllers;
02116   NS_IF_ADDREF(*aResult);
02117 
02118   return NS_OK;
02119 }
02120 
02121 NS_IMETHODIMP
02122 nsHTMLInputElement::GetTextLength(PRInt32* aTextLength)
02123 {
02124   nsAutoString val;
02125 
02126   nsresult rv = GetValue(val);
02127 
02128   *aTextLength = val.Length();
02129 
02130   return rv;
02131 }
02132 
02133 NS_IMETHODIMP
02134 nsHTMLInputElement::SetSelectionRange(PRInt32 aSelectionStart,
02135                                       PRInt32 aSelectionEnd)
02136 {
02137   nsresult rv = NS_ERROR_FAILURE;
02138   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
02139 
02140   if (formControlFrame) {
02141     nsITextControlFrame* textControlFrame = nsnull;
02142     CallQueryInterface(formControlFrame, &textControlFrame);
02143 
02144     if (textControlFrame)
02145       rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd);
02146   }
02147 
02148   return rv;
02149 }
02150 
02151 NS_IMETHODIMP
02152 nsHTMLInputElement::GetSelectionStart(PRInt32* aSelectionStart)
02153 {
02154   NS_ENSURE_ARG_POINTER(aSelectionStart);
02155   
02156   PRInt32 selEnd;
02157   return GetSelectionRange(aSelectionStart, &selEnd);
02158 }
02159 
02160 NS_IMETHODIMP
02161 nsHTMLInputElement::SetSelectionStart(PRInt32 aSelectionStart)
02162 {
02163   nsresult rv = NS_ERROR_FAILURE;
02164   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
02165 
02166   if (formControlFrame) {
02167     nsITextControlFrame* textControlFrame = nsnull;
02168     CallQueryInterface(formControlFrame, &textControlFrame);
02169 
02170     if (textControlFrame)
02171       rv = textControlFrame->SetSelectionStart(aSelectionStart);
02172   }
02173 
02174   return rv;
02175 }
02176 
02177 NS_IMETHODIMP
02178 nsHTMLInputElement::GetSelectionEnd(PRInt32* aSelectionEnd)
02179 {
02180   NS_ENSURE_ARG_POINTER(aSelectionEnd);
02181   
02182   PRInt32 selStart;
02183   return GetSelectionRange(&selStart, aSelectionEnd);
02184 }
02185 
02186 
02187 NS_IMETHODIMP
02188 nsHTMLInputElement::SetSelectionEnd(PRInt32 aSelectionEnd)
02189 {
02190   nsresult rv = NS_ERROR_FAILURE;
02191   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
02192 
02193   if (formControlFrame) {
02194     nsITextControlFrame* textControlFrame = nsnull;
02195     CallQueryInterface(formControlFrame, &textControlFrame);
02196 
02197     if (textControlFrame)
02198       rv = textControlFrame->SetSelectionEnd(aSelectionEnd);
02199   }
02200 
02201   return rv;
02202 }
02203 
02204 nsresult
02205 nsHTMLInputElement::GetSelectionRange(PRInt32* aSelectionStart,
02206                                       PRInt32* aSelectionEnd)
02207 {
02208   nsresult rv = NS_ERROR_FAILURE;
02209   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
02210 
02211   if (formControlFrame) {
02212     nsITextControlFrame* textControlFrame = nsnull;
02213     CallQueryInterface(formControlFrame, &textControlFrame);
02214 
02215     if (textControlFrame)
02216       rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
02217   }
02218 
02219   return rv;
02220 }
02221 
02222 NS_IMETHODIMP
02223 nsHTMLInputElement::GetPhonetic(nsAString& aPhonetic)
02224 {
02225   aPhonetic.Truncate(0);
02226   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
02227 
02228   if (formControlFrame) {
02229     nsCOMPtr<nsIPhonetic>
02230       phonetic(do_QueryInterface(formControlFrame));
02231 
02232     if (phonetic)
02233       phonetic->GetPhonetic(aPhonetic);
02234   }
02235 
02236   return NS_OK;
02237 }
02238 
02239 #ifdef ACCESSIBILITY
02240 /*static*/ nsresult
02241 FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
02242                           nsPresContext* aPresContext,
02243                           const nsAString& aEventType)
02244 {
02245   nsCOMPtr<nsIContent> content(do_QueryInterface(aTarget));
02246   NS_ENSURE_TRUE(content, NS_ERROR_FAILURE);
02247 
02248   nsCOMPtr<nsIDOMEvent> event;
02249   nsCOMPtr<nsIEventListenerManager> manager;
02250   content->GetListenerManager(getter_AddRefs(manager));
02251   if (manager &&
02252       NS_SUCCEEDED(manager->CreateEvent(aPresContext, nsnull,
02253                                         NS_LITERAL_STRING("Events"),
02254                                         getter_AddRefs(event)))) {
02255     event->InitEvent(aEventType, PR_TRUE, PR_TRUE);
02256 
02257     nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
02258     if (privateEvent) {
02259       privateEvent->SetTrusted(PR_TRUE);
02260     }
02261 
02262     PRBool defaultActionEnabled;
02263     aPresContext->EventStateManager()->DispatchNewEvent(aTarget, event,
02264                                                         &defaultActionEnabled);
02265   }
02266 
02267   return NS_OK;
02268 }
02269 #endif
02270 
02271 nsresult
02272 nsHTMLInputElement::Reset()
02273 {
02274   nsresult rv = NS_OK;
02275 
02276   nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_FALSE);
02277 
02278   switch (mType) {
02279     case NS_FORM_INPUT_CHECKBOX:
02280     case NS_FORM_INPUT_RADIO:
02281     {
02282       PRBool resetVal;
02283       GetDefaultChecked(&resetVal);
02284       rv = DoSetChecked(resetVal);
02285       SetCheckedChanged(PR_FALSE);
02286       break;
02287     }
02288     case NS_FORM_INPUT_PASSWORD:
02289     case NS_FORM_INPUT_TEXT:
02290     {
02291       // If the frame is there, we have to set the value so that it will show
02292       // up.
02293       if (formControlFrame) {
02294         nsAutoString resetVal;
02295         GetDefaultValue(resetVal);
02296         rv = SetValue(resetVal);
02297       }
02298       SetValueChanged(PR_FALSE);
02299       break;
02300     }
02301     case NS_FORM_INPUT_FILE:
02302     {
02303       // Resetting it to blank should not perform security check
02304       SetFileName(EmptyString(), PR_TRUE);
02305       break;
02306     }
02307     // Value is the same as defaultValue for hidden inputs
02308     case NS_FORM_INPUT_HIDDEN:
02309     default:
02310       break;
02311   }
02312 
02313   // Notify frame that it has been reset
02314   if (formControlFrame) {
02315     formControlFrame->OnContentReset();
02316   }
02317   return rv;
02318 }
02319 
02320 NS_IMETHODIMP
02321 nsHTMLInputElement::SubmitNamesValues(nsIFormSubmission* aFormSubmission,
02322                                       nsIContent* aSubmitElement)
02323 {
02324   nsresult rv = NS_OK;
02325 
02326   //
02327   // Disabled elements don't submit
02328   //
02329   PRBool disabled;
02330   rv = GetDisabled(&disabled);
02331   if (NS_FAILED(rv) || disabled) {
02332     return rv;
02333   }
02334 
02335   //
02336   // For type=reset, and type=button, we just never submit, period.
02337   //
02338   if (mType == NS_FORM_INPUT_RESET || mType == NS_FORM_INPUT_BUTTON) {
02339     return rv;
02340   }
02341 
02342   //
02343   // For type=image and type=button, we only submit if we were the button
02344   // pressed
02345   //
02346   if ((mType == NS_FORM_INPUT_SUBMIT || mType == NS_FORM_INPUT_IMAGE)
02347       && aSubmitElement != this) {
02348     return rv;
02349   }
02350 
02351   //
02352   // For type=radio and type=checkbox, we only submit if checked=true
02353   //
02354   if (mType == NS_FORM_INPUT_RADIO || mType == NS_FORM_INPUT_CHECKBOX) {
02355     PRBool checked;
02356     rv = GetChecked(&checked);
02357     if (NS_FAILED(rv) || !checked) {
02358       return rv;
02359     }
02360   }
02361 
02362   //
02363   // Get the name
02364   //
02365   nsAutoString name;
02366   rv = GetAttr(kNameSpaceID_None, nsHTMLAtoms::name, name);
02367   if (NS_FAILED(rv)) {
02368     return rv;
02369   }
02370   PRBool nameThere = (rv != NS_CONTENT_ATTR_NOT_THERE);
02371 
02372   //
02373   // Submit .x, .y for input type=image
02374   //
02375   if (mType == NS_FORM_INPUT_IMAGE) {
02376     // Go to the frame to find out where it was clicked.  This is the only
02377     // case where I can actually see using the frame, because you're talking
02378     // about a value--mouse click--that is rightfully the domain of the frame.
02379     //
02380     // If the frame isn't there or isn't an ImageControlFrame, then we're not
02381     // submitting these values no matter *how* nicely you ask.
02382     PRInt32 clickedX;
02383     PRInt32 clickedY;
02384     nsIFormControlFrame* formControlFrame = GetFormControlFrame(PR_TRUE);
02385 
02386     nsIImageControlFrame* imageControlFrame = nsnull;
02387     if (formControlFrame) {
02388       CallQueryInterface(formControlFrame, &imageControlFrame);
02389     }
02390     
02391     nsAutoString xVal;
02392     nsAutoString yVal;
02393     
02394     if (imageControlFrame) {
02395       imageControlFrame->GetClickedX(&clickedX);
02396       imageControlFrame->GetClickedY(&clickedY);
02397 
02398       // Convert the values to strings for submission
02399       xVal.AppendInt(clickedX);
02400       yVal.AppendInt(clickedY);
02401     }
02402     
02403     if (!name.IsEmpty()) {
02404       aFormSubmission->AddNameValuePair(this,
02405                                         name + NS_LITERAL_STRING(".x"), xVal);
02406       aFormSubmission->AddNameValuePair(this,
02407                                         name + NS_LITERAL_STRING(".y"), yVal);
02408     } else {
02409       // If the Image Element has no name, simply return x and y
02410       // to Nav and IE compatability.
02411       aFormSubmission->AddNameValuePair(this, NS_LITERAL_STRING("x"), xVal);
02412       aFormSubmission->AddNameValuePair(this, NS_LITERAL_STRING("y"), yVal);
02413     }
02414   }
02415 
02416   //
02417   // Submit name=value
02418   //
02419 
02420   // If name not there, don't submit
02421   if (!nameThere) {
02422     return rv;
02423   }
02424 
02425   //
02426   // Submit file if it's input type=file and this encoding method accepts files
02427   //
02428   if (mType == NS_FORM_INPUT_FILE) {
02429     //
02430     // Open the file
02431     //
02432     nsCOMPtr<nsIFile> file;
02433  
02434     if (mFileName) {
02435       if (StringBeginsWith(*mFileName, NS_LITERAL_STRING("file:"),
02436                            nsCaseInsensitiveStringComparator())) {
02437         // Converts the URL string into the corresponding nsIFile if possible.
02438         // A local file will be created if the URL string begins with file://.
02439         rv = NS_GetFileFromURLSpec(NS_ConvertUCS2toUTF8(*mFileName),
02440                                    getter_AddRefs(file));
02441       }
02442 
02443       if (!file) {
02444         // this is no "file://", try as local file
02445         nsCOMPtr<nsILocalFile> localFile;
02446         rv = NS_NewLocalFile(*mFileName, PR_FALSE, getter_AddRefs(localFile));
02447         file = localFile;
02448       }
02449     }
02450 
02451     if (file) {
02452 
02453       //
02454       // Get the leaf path name (to be submitted as the value)
02455       //
02456       nsAutoString filename;
02457       rv = file->GetLeafName(filename);
02458 
02459       if (NS_SUCCEEDED(rv) && !filename.IsEmpty()) {
02460         PRBool acceptsFiles = aFormSubmission->AcceptsFiles();
02461 
02462         if (acceptsFiles) {
02463           //
02464           // Get content type
02465           //
02466           nsCOMPtr<nsIMIMEService> MIMEService =
02467             do_GetService(NS_MIMESERVICE_CONTRACTID, &rv);
02468           NS_ENSURE_SUCCESS(rv, rv);
02469 
02470           nsCAutoString contentType;
02471           rv = MIMEService->GetTypeFromFile(file, contentType);
02472           if (NS_FAILED(rv)) {
02473             contentType.AssignLiteral("application/octet-stream");
02474           }
02475 
02476           //
02477           // Get input stream
02478           //
02479           nsCOMPtr<nsIInputStream> fileStream;
02480           rv = NS_NewLocalFileInputStream(getter_AddRefs(fileStream),
02481                                           file, -1, -1,
02482                                           nsIFileInputStream::CLOSE_ON_EOF |
02483                                           nsIFileInputStream::REOPEN_ON_REWIND);
02484           if (fileStream) {
02485             //
02486             // Create buffered stream (for efficiency)
02487             //
02488             nsCOMPtr<nsIInputStream> bufferedStream;
02489             rv = NS_NewBufferedInputStream(getter_AddRefs(bufferedStream),
02490                                            fileStream, 8192);
02491             NS_ENSURE_SUCCESS(rv, rv);
02492             if (bufferedStream) {
02493               //
02494               // Submit
02495               //
02496               aFormSubmission->AddNameFilePair(this, name, filename,
02497                                                bufferedStream, contentType,
02498                                                PR_FALSE);
02499               return rv;
02500             }
02501           }
02502         }
02503 
02504         //
02505         // If we don't submit as a file, at least submit the truncated filename.
02506         //
02507         aFormSubmission->AddNameFilePair(this, name, filename,
02508             nsnull, NS_LITERAL_CSTRING("application/octet-stream"),
02509             PR_FALSE);
02510         return rv;
02511       } else {
02512         // Ignore error returns from GetLeafName.  See bug 199053
02513         rv = NS_OK;
02514       }
02515     }
02516     
02517     //
02518     // If we can't even make a truncated filename, submit empty string
02519     // rather than sending everything
02520     //
02521     aFormSubmission->AddNameFilePair(this, name, EmptyString(),
02522         nsnull, NS_LITERAL_CSTRING("application/octet-stream"),
02523         PR_FALSE);
02524     return rv;
02525   }
02526 
02527   // Get the value
02528   nsAutoString value;
02529   rv = GetValue(value);
02530   NS_ENSURE_SUCCESS(rv, rv);
02531 
02532   if (mType == NS_FORM_INPUT_SUBMIT && value.IsEmpty() &&
02533       !HasAttr(kNameSpaceID_None, nsHTMLAtoms::value)) {
02534     // Get our default value, which is the same as our default label
02535     nsXPIDLString defaultValue;
02536     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
02537                                        "Submit", defaultValue);
02538     value = defaultValue;
02539   }
02540       
02541   // Submit
02542   // (for type=image, only submit if value is non-null)
02543   if (mType != NS_FORM_INPUT_IMAGE || !value.IsEmpty()) {
02544     rv = aFormSubmission->AddNameValuePair(this, name, value);
02545   }
02546 
02547   return rv;
02548 }
02549 
02550 
02551 NS_IMETHODIMP
02552 nsHTMLInputElement::SaveState()
02553 {
02554   nsresult rv = NS_OK;
02555 
02556   nsPresState *state = nsnull;
02557   switch (mType) {
02558     case NS_FORM_INPUT_CHECKBOX:
02559     case NS_FORM_INPUT_RADIO:
02560       {
02561         PRBool checked = PR_FALSE;
02562         GetChecked(&checked);
02563         PRBool defaultChecked = PR_FALSE;
02564         GetDefaultChecked(&defaultChecked);
02565         // Only save if checked != defaultChecked (bug 62713)
02566         // (always save if it's a radio button so that the checked
02567         // state of all radio buttons is restored)
02568         if (mType == NS_FORM_INPUT_RADIO || checked != defaultChecked) {
02569           rv = GetPrimaryPresState(this, &state);
02570           if (state) {
02571             if (checked) {
02572               rv = state->SetStateProperty(NS_LITERAL_STRING("checked"),
02573                                            NS_LITERAL_STRING("t"));
02574             } else {
02575               rv = state->SetStateProperty(NS_LITERAL_STRING("checked"),
02576                                            NS_LITERAL_STRING("f"));
02577             }
02578             NS_ASSERTION(NS_SUCCEEDED(rv), "checked save failed!");
02579           }
02580         }
02581         break;
02582       }
02583 
02584     // Never save passwords in session history
02585     case NS_FORM_INPUT_PASSWORD:
02586       break;
02587     case NS_FORM_INPUT_TEXT:
02588     case NS_FORM_INPUT_HIDDEN:
02589       {
02590         if (GET_BOOLBIT(mBitField, BF_VALUE_CHANGED)) {
02591           rv = GetPrimaryPresState(this, &state);
02592           if (state) {
02593             nsAutoString value;
02594             GetValue(value);
02595             rv = nsLinebreakConverter::ConvertStringLineBreaks(
02596                      value,
02597                      nsLinebreakConverter::eLinebreakPlatform,
02598                      nsLinebreakConverter::eLinebreakContent);
02599             NS_ASSERTION(NS_SUCCEEDED(rv), "Converting linebreaks failed!");
02600             rv = state->SetStateProperty(NS_LITERAL_STRING("v"), value);
02601             NS_ASSERTION(NS_SUCCEEDED(rv), "value save failed!");
02602           }
02603         }
02604         break;
02605       }
02606     case NS_FORM_INPUT_FILE:
02607       {
02608         if (mFileName) {
02609           rv = GetPrimaryPresState(this, &state);
02610           if (state) {
02611             rv = state->SetStateProperty(NS_LITERAL_STRING("f"), *mFileName);
02612             NS_ASSERTION(NS_SUCCEEDED(rv), "value save failed!");
02613           }
02614         }
02615         break;
02616       }
02617   }
02618   
02619   if (GET_BOOLBIT(mBitField, BF_DISABLED_CHANGED)) {
02620     rv |= GetPrimaryPresState(this, &state);
02621     if (state) {
02622       PRBool disabled;
02623       GetDisabled(&disabled);
02624       if (disabled) {
02625         rv |= state->SetStateProperty(NS_LITERAL_STRING("disabled"),
02626                                      NS_LITERAL_STRING("t"));
02627       } else {
02628         rv |= state->SetStateProperty(NS_LITERAL_STRING("disabled"),
02629                                      NS_LITERAL_STRING("f"));
02630       }
02631       NS_ASSERTION(NS_SUCCEEDED(rv), "disabled save failed!");
02632     }
02633   }
02634 
02635   return rv;
02636 }
02637 
02638 void
02639 nsHTMLInputElement::DoneCreatingElement()
02640 {
02641   SET_BOOLBIT(mBitField, BF_PARSER_CREATING, PR_FALSE);
02642 
02643   //
02644   // Restore state for checkbox, radio, text and file
02645   //
02646   PRBool restoredCheckedState = PR_FALSE;
02647   switch (mType) {
02648     case NS_FORM_INPUT_CHECKBOX:
02649     case NS_FORM_INPUT_RADIO:
02650     case NS_FORM_INPUT_TEXT:
02651     case NS_FORM_INPUT_FILE:
02652     case NS_FORM_INPUT_HIDDEN:
02653       restoredCheckedState = RestoreFormControlState(this, this);
02654       break;
02655   }
02656 
02657   //
02658   // If restore does not occur, we initialize .checked using the CHECKED
02659   // property.
02660   //
02661   if (!restoredCheckedState &&
02662       GET_BOOLBIT(mBitField, BF_SHOULD_INIT_CHECKED)) {
02663     PRBool resetVal;
02664     GetDefaultChecked(&resetVal);
02665     DoSetChecked(resetVal, PR_FALSE);
02666     SetCheckedChanged(PR_FALSE);
02667   }
02668 
02669   SET_BOOLBIT(mBitField, BF_SHOULD_INIT_CHECKED, PR_FALSE);
02670 }
02671 
02672 PRInt32
02673 nsHTMLInputElement::IntrinsicState() const
02674 {
02675   PRInt32 state = nsGenericHTMLFormElement::IntrinsicState();
02676   if (GET_BOOLBIT(mBitField, BF_CHECKED) &&
02677       (mType == NS_FORM_INPUT_CHECKBOX ||
02678        mType == NS_FORM_INPUT_RADIO)) {
02679     state |= NS_EVENT_STATE_CHECKED;
02680   }
02681   return state;
02682 }
02683 
02684 PRBool
02685 nsHTMLInputElement::RestoreState(nsPresState* aState)
02686 {
02687   PRBool restoredCheckedState = PR_FALSE;
02688 
02689   nsresult rv;
02690   
02691   switch (mType) {
02692     case NS_FORM_INPUT_CHECKBOX:
02693     case NS_FORM_INPUT_RADIO:
02694       {
02695         nsAutoString checked;
02696         rv = aState->GetStateProperty(NS_LITERAL_STRING("checked"), checked);
02697         NS_ASSERTION(NS_SUCCEEDED(rv), "checked restore failed!");
02698         if (rv == NS_STATE_PROPERTY_EXISTS) {
02699           restoredCheckedState = PR_TRUE;
02700           DoSetChecked(checked.EqualsLiteral("t"), PR_FALSE);
02701         }
02702         break;
02703       }
02704 
02705     case NS_FORM_INPUT_TEXT:
02706     case NS_FORM_INPUT_HIDDEN:
02707       {
02708         nsAutoString value;
02709         rv = aState->GetStateProperty(NS_LITERAL_STRING("v"), value);
02710         NS_ASSERTION(NS_SUCCEEDED(rv), "value restore failed!");
02711         if (rv == NS_STATE_PROPERTY_EXISTS) {
02712           SetValueInternal(value, nsnull);
02713         }
02714         break;
02715       }
02716     case NS_FORM_INPUT_FILE:
02717       {
02718         nsAutoString value;
02719         rv = aState->GetStateProperty(NS_LITERAL_STRING("f"), value);
02720         NS_ASSERTION(NS_SUCCEEDED(rv), "value restore failed!");
02721         if (rv == NS_STATE_PROPERTY_EXISTS) {
02722           // Can there really be a frame at this point?
02723           SetFileName(value, PR_TRUE);
02724         }
02725         break;
02726       }
02727   }
02728   
02729   nsAutoString disabled;
02730   rv = aState->GetStateProperty(NS_LITERAL_STRING("disabled"), disabled);
02731   NS_ASSERTION(NS_SUCCEEDED(rv), "disabled restore failed!");
02732   if (rv == NS_STATE_PROPERTY_EXISTS) {
02733     SetDisabled(disabled.EqualsLiteral("t"));
02734   }
02735 
02736   return restoredCheckedState;
02737 }
02738 
02739 PRBool
02740 nsHTMLInputElement::AllowDrop()
02741 {
02742   // Allow drop on anything other than file inputs.
02743 
02744   return mType != NS_FORM_INPUT_FILE;
02745 }
02746 
02747 /*
02748  * Radio group stuff
02749  */
02750 
02751 NS_IMETHODIMP
02752 nsHTMLInputElement::AddedToRadioGroup(PRBool aNotify)
02753 {
02754   // Make sure not to notify if we're still being created by the parser
02755   if (aNotify)
02756     aNotify = GET_BOOLBIT(mBitField, BF_PARSER_CREATING) != 0;
02757 
02758   //
02759   //  If the input element is not in a form and
02760   //  not in a document, we just need to return.
02761   //
02762   if (!mForm && !(IsInDoc() && GetParent())) {
02763     return NS_OK;
02764   }
02765 
02766   //
02767   // If the input element is checked, and we add it to the group, it will
02768   // deselect whatever is currently selected in that group
02769   //
02770   PRBool checked;
02771   GetChecked(&checked);
02772   if (checked) {
02773     //
02774     // If it is checked, call "RadioSetChecked" to perform the selection/
02775     // deselection ritual.  This has the side effect of repainting the
02776     // radio button, but as adding a checked radio button into the group
02777     // should not be that common an occurrence, I think we can live with
02778     // that.
02779     //
02780     RadioSetChecked(aNotify);
02781   }
02782 
02783   //
02784   // For integrity purposes, we have to ensure that "checkedChanged" is
02785   // the same for this new element as for all the others in the group
02786   //
02787   PRBool checkedChanged = PR_FALSE;
02788   nsCOMPtr<nsIRadioVisitor> visitor;
02789   nsresult rv = NS_GetRadioGetCheckedChangedVisitor(&checkedChanged, this,
02790                                            getter_AddRefs(visitor));
02791   NS_ENSURE_SUCCESS(rv, rv);
02792   
02793   VisitGroup(visitor);
02794   SetCheckedChangedInternal(checkedChanged);
02795   
02796   //
02797   // Add the radio to the radio group container.
02798   //
02799   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
02800   if (container) {
02801     nsAutoString name;
02802     if (GetNameIfExists(name)) {
02803       container->AddToRadioGroup(name, NS_STATIC_CAST(nsIFormControl*, this));
02804     }
02805   }
02806 
02807   return NS_OK;
02808 }
02809 
02810 NS_IMETHODIMP
02811 nsHTMLInputElement::WillRemoveFromRadioGroup()
02812 {
02813   //
02814   // If the input element is not in a form and
02815   // not in a document, we just need to return.
02816   //
02817   if (!mForm && !(IsInDoc() && GetParent())) {
02818     return NS_OK;
02819   }
02820 
02821   //
02822   // If this button was checked, we need to notify the group that there is no
02823   // longer a selected radio button
02824   //
02825   PRBool checked = PR_FALSE;
02826   GetChecked(&checked);
02827 
02828   nsAutoString name;
02829   PRBool gotName = PR_FALSE;
02830   if (checked) {
02831     if (!gotName) {
02832       if (!GetNameIfExists(name)) {
02833         // If the name doesn't exist, nothing is going to happen anyway
02834         return NS_OK;
02835       }
02836       gotName = PR_TRUE;
02837     }
02838 
02839     nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
02840     if (container) {
02841       container->SetCurrentRadioButton(name, nsnull);
02842     }
02843   }
02844   
02845   //
02846   // Remove this radio from its group in the container
02847   //
02848   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
02849   if (container) {
02850     if (!gotName) {
02851       if (!GetNameIfExists(name)) {
02852         // If the name doesn't exist, nothing is going to happen anyway
02853         return NS_OK;
02854       }
02855       gotName = PR_TRUE;
02856     }
02857     container->RemoveFromRadioGroup(name,
02858                                     NS_STATIC_CAST(nsIFormControl*, this));
02859   }
02860 
02861   return NS_OK;
02862 }
02863 
02864 PRBool
02865 nsHTMLInputElement::IsFocusable(PRInt32 *aTabIndex)
02866 {
02867   if (!nsGenericHTMLElement::IsFocusable(aTabIndex)) {
02868     return PR_FALSE;
02869   }
02870 
02871   if (mType == NS_FORM_INPUT_TEXT || mType == NS_FORM_INPUT_PASSWORD) {
02872     return PR_TRUE;
02873   }
02874 
02875   if (mType == NS_FORM_INPUT_HIDDEN || mType == NS_FORM_INPUT_FILE) {
02876     // Sub controls of file input are tabbable, not the file input itself.
02877     if (aTabIndex) {
02878       *aTabIndex = -1;
02879     }
02880     return PR_FALSE;
02881   }
02882 
02883   if (!aTabIndex) {
02884     // The other controls are all focusable
02885     return PR_TRUE;
02886   }
02887 
02888   // We need to set tabindex to -1 if we're not tabbable
02889   if (mType != NS_FORM_INPUT_TEXT && mType != NS_FORM_INPUT_PASSWORD &&
02890       !(sTabFocusModel & eTabFocus_formElementsMask)) {
02891     *aTabIndex = -1;
02892   }
02893 
02894   if (mType != NS_FORM_INPUT_RADIO) {
02895     return PR_TRUE;
02896   }
02897 
02898   PRBool checked;
02899   GetChecked(&checked);
02900   if (checked) {
02901     // Selected radio buttons are tabbable
02902     return PR_TRUE;
02903   }
02904 
02905   // Current radio button is not selected.
02906   // But make it tabbable if nothing in group is selected.
02907   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
02908   nsAutoString name;
02909   if (!container || !GetNameIfExists(name)) {
02910     return PR_TRUE;
02911   }
02912 
02913   nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
02914   container->GetCurrentRadioButton(name, getter_AddRefs(currentRadio));
02915   if (currentRadio) {
02916     *aTabIndex = -1;
02917   }
02918   return PR_TRUE;
02919 }
02920 
02921 nsresult
02922 nsHTMLInputElement::VisitGroup(nsIRadioVisitor* aVisitor)
02923 {
02924   nsresult rv = NS_OK;
02925   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
02926   if (container) {
02927     nsAutoString name;
02928     if (GetNameIfExists(name)) {
02929       rv = container->WalkRadioGroup(name, aVisitor);
02930     } else {
02931       PRBool stop;
02932       aVisitor->Visit(this, &stop);
02933     }
02934   } else {
02935     PRBool stop;
02936     aVisitor->Visit(this, &stop);
02937   }
02938   return rv;
02939 }
02940 
02941 void
02942 nsHTMLInputElement::MaybeClearFilename(nsEvent* aEvent, nsIDOMEvent** aDOMEvent,
02943                                        PRInt32 aOldType)
02944 {
02945   if (NS_IS_TRUSTED_EVENT(aEvent) &&
02946       (aOldType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_FILE) &&
02947        (aEvent->message == NS_KEY_UP ||
02948         aEvent->message == NS_KEY_DOWN ||
02949         aEvent->message == NS_KEY_PRESS)) {
02950         PRBool isButton = PR_FALSE;
02951     if (aDOMEvent) {
02952       nsCOMPtr<nsIDOMNSEvent> nsEvent(do_QueryInterface(*aDOMEvent));
02953       if (nsEvent) {
02954         nsCOMPtr<nsIDOMEventTarget> originalTarget;
02955         nsEvent->GetOriginalTarget(getter_AddRefs(originalTarget));
02956         nsCOMPtr<nsIContent> maybeButton(do_QueryInterface(originalTarget));
02957         if (maybeButton && maybeButton->IsNativeAnonymous() &&
02958             maybeButton->GetParent() == this) {
02959           nsAutoString type;
02960           maybeButton->GetAttr(kNameSpaceID_None, nsHTMLAtoms::type, type);
02961           isButton = type.EqualsLiteral("button");
02962         }
02963       }
02964     }
02965     nsKeyEvent* keyEvent = NS_STATIC_CAST(nsKeyEvent*, aEvent);
02966     if (!isButton &&
02967         keyEvent->keyCode != NS_VK_RETURN &&
02968         keyEvent->keyCode != NS_VK_ENTER &&
02969         keyEvent->keyCode != NS_VK_TAB) {
02970       SetFileName(EmptyString(), PR_TRUE);
02971       mHasBeenDisabled = PR_FALSE;
02972     }
02973   }
02974 }
02975 
02976 //
02977 // Visitor classes
02978 //
02979 //
02980 // CLASS nsRadioVisitor
02981 //
02982 // (this is the superclass of the others)
02983 //
02984 class nsRadioVisitor : public nsIRadioVisitor {
02985 public:
02986   nsRadioVisitor() { }
02987   virtual ~nsRadioVisitor() { };
02988 
02989   NS_DECL_ISUPPORTS
02990 
02991   NS_IMETHOD Visit(nsIFormControl* aRadio, PRBool* aStop) = 0;
02992 };
02993 
02994 NS_IMPL_ADDREF(nsRadioVisitor)
02995 NS_IMPL_RELEASE(nsRadioVisitor)
02996 
02997 NS_INTERFACE_MAP_BEGIN(nsRadioVisitor)
02998   NS_INTERFACE_MAP_ENTRY(nsIRadioVisitor)
02999   NS_INTERFACE_MAP_ENTRY(nsISupports)
03000 NS_INTERFACE_MAP_END
03001 
03002 
03003 //
03004 // CLASS nsRadioSetCheckedChangedVisitor
03005 //
03006 class nsRadioSetCheckedChangedVisitor : public nsRadioVisitor {
03007 public:
03008   nsRadioSetCheckedChangedVisitor(PRBool aCheckedChanged) :
03009     nsRadioVisitor(), mCheckedChanged(aCheckedChanged)
03010     { }
03011 
03012   virtual ~nsRadioSetCheckedChangedVisitor() { }
03013 
03014   NS_IMETHOD Visit(nsIFormControl* aRadio, PRBool* aStop)
03015   {
03016     nsCOMPtr<nsIRadioControlElement> radio(do_QueryInterface(aRadio));
03017     NS_ASSERTION(radio, "Visit() passed a null button (or non-radio)!");
03018     radio->SetCheckedChangedInternal(mCheckedChanged);
03019     return NS_OK;
03020   }
03021 
03022 protected:
03023   PRPackedBool mCheckedChanged;
03024 };
03025 
03026 //
03027 // CLASS nsRadioGetCheckedChangedVisitor
03028 //
03029 class nsRadioGetCheckedChangedVisitor : public nsRadioVisitor {
03030 public:
03031   nsRadioGetCheckedChangedVisitor(PRBool* aCheckedChanged,
03032                                   nsIFormControl* aExcludeElement) :
03033     nsRadioVisitor(),
03034     mCheckedChanged(aCheckedChanged),
03035     mExcludeElement(aExcludeElement)
03036     { }
03037 
03038   virtual ~nsRadioGetCheckedChangedVisitor() { }
03039 
03040   NS_IMETHOD Visit(nsIFormControl* aRadio, PRBool* aStop)
03041   {
03042     if (aRadio == mExcludeElement) {
03043       return NS_OK;
03044     }
03045     nsCOMPtr<nsIRadioControlElement> radio(do_QueryInterface(aRadio));
03046     NS_ASSERTION(radio, "Visit() passed a null button (or non-radio)!");
03047     radio->GetCheckedChanged(mCheckedChanged);
03048     *aStop = PR_TRUE;
03049     return NS_OK;
03050   }
03051 
03052 protected:
03053   PRBool* mCheckedChanged;
03054   nsIFormControl* mExcludeElement;
03055 };
03056 
03057 nsresult
03058 NS_GetRadioSetCheckedChangedVisitor(PRBool aCheckedChanged,
03059                                     nsIRadioVisitor** aVisitor)
03060 {
03061   //
03062   // These are static so that we don't have to keep creating new visitors for
03063   // such an ordinary process all the time.  There are only two possibilities
03064   // for this visitor: set to true, and set to false.
03065   //
03066   static nsIRadioVisitor* sVisitorTrue = nsnull;
03067   static nsIRadioVisitor* sVisitorFalse = nsnull;
03068 
03069   //
03070   // Get the visitor that sets them to true
03071   //
03072   if (aCheckedChanged) {
03073     if (!sVisitorTrue) {
03074       sVisitorTrue = new nsRadioSetCheckedChangedVisitor(PR_TRUE);
03075       if (!sVisitorTrue) {
03076         return NS_ERROR_OUT_OF_MEMORY;
03077       }
03078       NS_ADDREF(sVisitorTrue);
03079       nsresult rv =
03080         nsContentUtils::ReleasePtrOnShutdown((nsISupports**)&sVisitorTrue);
03081       if (NS_FAILED(rv)) {
03082         NS_RELEASE(sVisitorTrue);
03083         return rv;
03084       }
03085     }
03086     *aVisitor = sVisitorTrue;
03087   }
03088   //
03089   // Get the visitor that sets them to false
03090   //
03091   else {
03092     if (!sVisitorFalse) {
03093       sVisitorFalse = new nsRadioSetCheckedChangedVisitor(PR_FALSE);
03094       if (!sVisitorFalse) {
03095         return NS_ERROR_OUT_OF_MEMORY;
03096       }
03097       NS_ADDREF(sVisitorFalse);
03098       nsresult rv =
03099         nsContentUtils::ReleasePtrOnShutdown((nsISupports**)&sVisitorFalse);
03100       if (NS_FAILED(rv)) {
03101         NS_RELEASE(sVisitorFalse);
03102         return rv;
03103       }
03104     }
03105     *aVisitor = sVisitorFalse;
03106   }
03107 
03108   NS_ADDREF(*aVisitor);
03109   return NS_OK;
03110 }
03111 
03112 nsresult
03113 NS_GetRadioGetCheckedChangedVisitor(PRBool* aCheckedChanged,
03114                                     nsIFormControl* aExcludeElement,
03115                                     nsIRadioVisitor** aVisitor)
03116 {
03117   *aVisitor = new nsRadioGetCheckedChangedVisitor(aCheckedChanged,
03118                                                   aExcludeElement);
03119   if (!*aVisitor) {
03120     return NS_ERROR_OUT_OF_MEMORY;
03121   }
03122   NS_ADDREF(*aVisitor);
03123 
03124   return NS_OK;
03125 }