LCOV - app.info - content/html/content/src/nsHTMLInputElement.cpp

LCOV - code coverage report
| Current view: | directory - content/html/content/src - nsHTMLInputElement.cpp (source / functions) |  | Found | Hit | Coverage |
| Test: | app.info | Lines: | 1762 | 188 | 10.7 %
| Date: | 2012-04-21 | Functions: | 222 | 45 | 20.3 %

           1                 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
           2                 : /* ***** BEGIN LICENSE BLOCK *****
           3                 :  * Version: MPL 1.1/GPL 2.0/LGPL 2.1
           4                 :  *
           5                 :  * The contents of this file are subject to the Mozilla Public License Version
           6                 :  * 1.1 (the "License"); you may not use this file except in compliance with
           7                 :  * the License. You may obtain a copy of the License at
           8                 :  * http://www.mozilla.org/MPL/
           9                 :  *
          10                 :  * Software distributed under the License is distributed on an "AS IS" basis,
          11                 :  * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
          12                 :  * for the specific language governing rights and limitations under the
          13                 :  * License.
          14                 :  *
          15                 :  * The Original Code is Mozilla Communicator client code.
          16                 :  *
          17                 :  * The Initial Developer of the Original Code is
          18                 :  * Netscape Communications Corporation.
          19                 :  * Portions created by the Initial Developer are Copyright (C) 1998
          20                 :  * the Initial Developer. All Rights Reserved.
          21                 :  *
          22                 :  * Contributor(s):
          23                 :  *   Pierre Phaneuf <pp@ludusdesign.com>
          24                 :  *   Geoff Lankow <geoff@darktrojan.net>
          25                 :  *
          26                 :  * Alternatively, the contents of this file may be used under the terms of
          27                 :  * either of the GNU General Public License Version 2 or later (the "GPL"),
          28                 :  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
          29                 :  * in which case the provisions of the GPL or the LGPL are applicable instead
          30                 :  * of those above. If you wish to allow use of your version of this file only
          31                 :  * under the terms of either the GPL or the LGPL, and not to allow others to
          32                 :  * use your version of this file under the terms of the MPL, indicate your
          33                 :  * decision by deleting the provisions above and replace them with the notice
          34                 :  * and other provisions required by the GPL or the LGPL. If you do not delete
          35                 :  * the provisions above, a recipient may use your version of this file under
          36                 :  * the terms of any one of the MPL, the GPL or the LGPL.
          37                 :  *
          38                 :  * ***** END LICENSE BLOCK ***** */
          39                 :
          40                 : #include "mozilla/Util.h"
          41                 :
          42                 : #include "nsHTMLInputElement.h"
          43                 :
          44                 : #include "nsIDOMHTMLInputElement.h"
          45                 : #include "nsITextControlElement.h"
          46                 : #include "nsIDOMNSEditableElement.h"
          47                 : #include "nsIRadioVisitor.h"
          48                 : #include "nsIPhonetic.h"
          49                 :
          50                 : #include "nsIControllers.h"
          51                 : #include "nsFocusManager.h"
          52                 : #include "nsPIDOMWindow.h"
          53                 : #include "nsContentCID.h"
          54                 : #include "nsIComponentManager.h"
          55                 : #include "nsIDOMHTMLFormElement.h"
          56                 : #include "nsGkAtoms.h"
          57                 : #include "nsStyleConsts.h"
          58                 : #include "nsPresContext.h"
          59                 : #include "nsMappedAttributes.h"
          60                 : #include "nsIFormControl.h"
          61                 : #include "nsIForm.h"
          62                 : #include "nsFormSubmission.h"
          63                 : #include "nsFormSubmissionConstants.h"
          64                 : #include "nsIDocument.h"
          65                 : #include "nsIPresShell.h"
          66                 : #include "nsIFormControlFrame.h"
          67                 : #include "nsITextControlFrame.h"
          68                 : #include "nsIFrame.h"
          69                 : #include "nsEventStates.h"
          70                 : #include "nsIServiceManager.h"
          71                 : #include "nsIScriptSecurityManager.h"
          72                 : #include "nsDOMError.h"
          73                 : #include "nsIPrivateDOMEvent.h"
          74                 : #include "nsIEditor.h"
          75                 : #include "nsGUIEvent.h"
          76                 : #include "nsIIOService.h"
          77                 : #include "nsDocument.h"
          78                 : #include "nsAttrValueOrString.h"
          79                 :
          80                 : #include "nsPresState.h"
          81                 : #include "nsLayoutErrors.h"
          82                 : #include "nsIDOMEvent.h"
          83                 : #include "nsIDOMNSEvent.h"
          84                 : #include "nsIDOMNodeList.h"
          85                 : #include "nsIDOMHTMLCollection.h"
          86                 : #include "nsLinebreakConverter.h" //to strip out carriage returns
          87                 : #include "nsReadableUtils.h"
          88                 : #include "nsUnicharUtils.h"
          89                 : #include "nsEventDispatcher.h"
          90                 : #include "nsLayoutUtils.h"
          91                 :
          92                 : #include "nsIDOMMutationEvent.h"
          93                 : #include "nsIDOMEventTarget.h"
          94                 : #include "nsMutationEvent.h"
          95                 : #include "nsEventListenerManager.h"
          96                 :
          97                 : #include "nsRuleData.h"
          98                 :
          99                 : // input type=radio
         100                 : #include "nsIRadioGroupContainer.h"
         101                 :
         102                 : // input type=file
         103                 : #include "nsILocalFile.h"
         104                 : #include "nsNetUtil.h"
         105                 : #include "nsDOMFile.h"
         106                 : #include "nsIFilePicker.h"
         107                 : #include "nsDirectoryServiceDefs.h"
         108                 : #include "nsIContentPrefService.h"
         109                 : #include "nsIObserverService.h"
         110                 : #include "nsIPopupWindowManager.h"
         111                 : #include "nsGlobalWindow.h"
         112                 :
         113                 : // input type=image
         114                 : #include "nsImageLoadingContent.h"
         115                 :
         116                 : #include "mozAutoDocUpdate.h"
         117                 : #include "nsContentCreatorFunctions.h"
         118                 : #include "nsContentUtils.h"
         119                 : #include "nsRadioVisitor.h"
         120                 :
         121                 : #include "mozilla/LookAndFeel.h"
         122                 : #include "mozilla/Util.h" // DebugOnly
         123                 :
         124                 : #include "nsIIDNService.h"
         125                 :
         126                 : using namespace mozilla;
         127                 : using namespace mozilla::dom;
         128                 :
         129                 : // XXX align=left, hspace, vspace, border? other nav4 attrs
         130                 :
         131                 : static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
         132                 :
         133                 : // First bits are needed for the control type.
         134                 : #define NS_OUTER_ACTIVATE_EVENT   (1 << 9)
         135                 : #define NS_ORIGINAL_CHECKED_VALUE (1 << 10)
         136                 : #define NS_NO_CONTENT_DISPATCH    (1 << 11)
         137                 : #define NS_ORIGINAL_INDETERMINATE_VALUE (1 << 12)
         138                 : #define NS_CONTROL_TYPE(bits)  ((bits) & ~( \
         139                 :   NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | NS_NO_CONTENT_DISPATCH | \
         140                 :   NS_ORIGINAL_INDETERMINATE_VALUE))
         141                 :
         142                 : // whether textfields should be selected once focused:
         143                 : //  -1: no, 1: yes, 0: uninitialized
         144                 : static PRInt32 gSelectTextFieldOnFocus;
         145                 : UploadLastDir* nsHTMLInputElement::gUploadLastDir;
         146                 :
         147                 : static const nsAttrValue::EnumTable kInputTypeTable[] = {
         148                 :   { "button", NS_FORM_INPUT_BUTTON },
         149                 :   { "checkbox", NS_FORM_INPUT_CHECKBOX },
         150                 :   { "email", NS_FORM_INPUT_EMAIL },
         151                 :   { "file", NS_FORM_INPUT_FILE },
         152                 :   { "hidden", NS_FORM_INPUT_HIDDEN },
         153                 :   { "reset", NS_FORM_INPUT_RESET },
         154                 :   { "image", NS_FORM_INPUT_IMAGE },
         155                 :   { "password", NS_FORM_INPUT_PASSWORD },
         156                 :   { "radio", NS_FORM_INPUT_RADIO },
         157                 :   { "search", NS_FORM_INPUT_SEARCH },
         158                 :   { "submit", NS_FORM_INPUT_SUBMIT },
         159                 :   { "tel", NS_FORM_INPUT_TEL },
         160                 :   { "text", NS_FORM_INPUT_TEXT },
         161                 :   { "url", NS_FORM_INPUT_URL },
         162                 :   { 0 }
         163                 : };
         164                 :
         165                 : // Default type is 'text'.
         166                 : static const nsAttrValue::EnumTable* kInputDefaultType = &kInputTypeTable[12];
         167                 :
         168                 : static const PRUint8 NS_INPUT_AUTOCOMPLETE_OFF     = 0;
         169                 : static const PRUint8 NS_INPUT_AUTOCOMPLETE_ON      = 1;
         170                 : static const PRUint8 NS_INPUT_AUTOCOMPLETE_DEFAULT = 2;
         171                 :
         172                 : static const nsAttrValue::EnumTable kInputAutocompleteTable[] = {
         173                 :   { "", NS_INPUT_AUTOCOMPLETE_DEFAULT },
         174                 :   { "on", NS_INPUT_AUTOCOMPLETE_ON },
         175                 :   { "off", NS_INPUT_AUTOCOMPLETE_OFF },
         176                 :   { 0 }
         177                 : };
         178                 :
         179                 : // Default autocomplete value is "".
         180                 : static const nsAttrValue::EnumTable* kInputDefaultAutocomplete = &kInputAutocompleteTable[0];
         181                 :
         182                 : #define NS_INPUT_ELEMENT_STATE_IID                 \
         183                 : { /* dc3b3d14-23e2-4479-b513-7b369343e3a0 */       \
         184                 :   0xdc3b3d14,                                      \
         185                 :   0x23e2,                                          \
         186                 :   0x4479,                                          \
         187                 :   {0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \
         188                 : }
         189                 :
         190                 : class nsHTMLInputElementState MOZ_FINAL : public nsISupports
         191               0 : {
         192                 :   public:
         193                 :     NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPUT_ELEMENT_STATE_IID)
         194                 :     NS_DECL_ISUPPORTS
         195                 :
         196               0 :     bool IsCheckedSet() {
         197               0 :       return mCheckedSet;
         198                 :     }
         199                 :
         200               0 :     bool GetChecked() {
         201               0 :       return mChecked;
         202                 :     }
         203                 :
         204               0 :     void SetChecked(bool aChecked) {
         205               0 :       mChecked = aChecked;
         206               0 :       mCheckedSet = true;
         207               0 :     }
         208                 :
         209               0 :     const nsString& GetValue() {
         210               0 :       return mValue;
         211                 :     }
         212                 :
         213               0 :     void SetValue(const nsAString &aValue) {
         214               0 :       mValue = aValue;
         215               0 :     }
         216                 :
         217               0 :     const nsCOMArray<nsIDOMFile>& GetFiles() {
         218               0 :       return mFiles;
         219                 :     }
         220                 :
         221               0 :     void SetFiles(const nsCOMArray<nsIDOMFile> &aFiles) {
         222               0 :       mFiles.Clear();
         223               0 :       mFiles.AppendObjects(aFiles);
         224               0 :     }
         225                 :
         226               0 :     nsHTMLInputElementState()
         227                 :       : mValue()
         228                 :       , mChecked(false)
         229               0 :       , mCheckedSet(false)
         230               0 :     {};
         231                 :
         232                 :   protected:
         233                 :     nsString mValue;
         234                 :     nsCOMArray<nsIDOMFile> mFiles;
         235                 :     bool mChecked;
         236                 :     bool mCheckedSet;
         237                 : };
         238                 :
         239               0 : NS_IMPL_ISUPPORTS1(nsHTMLInputElementState, nsHTMLInputElementState)
         240                 : NS_DEFINE_STATIC_IID_ACCESSOR(nsHTMLInputElementState, NS_INPUT_ELEMENT_STATE_IID)
         241                 :
         242               0 : class AsyncClickHandler : public nsRunnable {
         243                 : public:
         244               0 :   AsyncClickHandler(nsHTMLInputElement* aInput)
         245               0 :    : mInput(aInput) {
         246                 :
         247               0 :     nsPIDOMWindow* win = aInput->OwnerDoc()->GetWindow();
         248               0 :     if (win) {
         249               0 :       mPopupControlState = win->GetPopupControlState();
         250                 :     }
         251               0 :   };
         252                 :
         253                 :   NS_IMETHOD Run();
         254                 :
         255                 : protected:
         256                 :   nsRefPtr<nsHTMLInputElement> mInput;
         257                 :   PopupControlState mPopupControlState;
         258                 : };
         259                 :
         260                 : NS_IMETHODIMP
         261               0 : AsyncClickHandler::Run()
         262                 : {
         263                 :   // Get parent nsPIDOMWindow object.
         264               0 :   nsCOMPtr<nsIDocument> doc = mInput->OwnerDoc();
         265                 :
         266               0 :   nsPIDOMWindow* win = doc->GetWindow();
         267               0 :   if (!win) {
         268               0 :     return NS_ERROR_FAILURE;
         269                 :   }
         270                 :
         271                 :   // Check if page is allowed to open the popup
         272               0 :   if (mPopupControlState > openControlled) {
         273                 :     nsCOMPtr<nsIPopupWindowManager> pm =
         274               0 :       do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
         275                 :
         276               0 :     if (!pm) {
         277               0 :       return NS_OK;
         278                 :     }
         279                 :
         280                 :     PRUint32 permission;
         281               0 :     pm->TestPermission(doc->GetDocumentURI(), &permission);
         282               0 :     if (permission == nsIPopupWindowManager::DENY_POPUP) {
         283               0 :       nsCOMPtr<nsIDOMDocument> domDoc = do_QueryInterface(doc);
         284               0 :       nsGlobalWindow::FirePopupBlockedEvent(domDoc, win, nsnull, EmptyString(), EmptyString());
         285               0 :       return NS_OK;
         286                 :     }
         287                 :   }
         288                 :
         289                 :   // Get Loc title
         290               0 :   nsXPIDLString title;
         291                 :   nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
         292               0 :                                      "FileUpload", title);
         293                 :
         294               0 :   nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1");
         295               0 :   if (!filePicker)
         296               0 :     return NS_ERROR_FAILURE;
         297                 :
         298               0 :   bool multi = mInput->HasAttr(kNameSpaceID_None, nsGkAtoms::multiple);
         299                 :
         300               0 :   nsresult rv = filePicker->Init(win, title,
         301                 :                                  multi
         302                 :                                   ? static_cast<PRInt16>(nsIFilePicker::modeOpenMultiple)
         303               0 :                                   : static_cast<PRInt16>(nsIFilePicker::modeOpen));
         304               0 :   NS_ENSURE_SUCCESS(rv, rv);
         305                 :
         306               0 :   if (mInput->HasAttr(kNameSpaceID_None, nsGkAtoms::accept)) {
         307               0 :     PRInt32 filters = mInput->GetFilterFromAccept();
         308                 :
         309               0 :     if (filters) {
         310                 :       // We add |filterAll| to be sure the user always has a sane fallback.
         311               0 :       filePicker->AppendFilters(filters | nsIFilePicker::filterAll);
         312                 :
         313                 :       // If the accept attribute asked for a filter, we need to make it default.
         314                 :       // |filterAll| will always use index=0 so we need to set index=1 as the
         315                 :       // current filter.
         316               0 :       filePicker->SetFilterIndex(1);
         317                 :     } else {
         318               0 :       filePicker->AppendFilters(nsIFilePicker::filterAll);
         319                 :     }
         320                 :   } else {
         321               0 :     filePicker->AppendFilters(nsIFilePicker::filterAll);
         322                 :   }
         323                 :
         324                 :   // Set default directry and filename
         325               0 :   nsAutoString defaultName;
         326                 :
         327               0 :   const nsCOMArray<nsIDOMFile>& oldFiles = mInput->GetFiles();
         328                 :
         329               0 :   if (oldFiles.Count()) {
         330               0 :     nsString path;
         331                 :
         332               0 :     oldFiles[0]->GetMozFullPathInternal(path);
         333                 :
         334               0 :     nsCOMPtr<nsILocalFile> localFile;
         335               0 :     rv = NS_NewLocalFile(path, false, getter_AddRefs(localFile));
         336                 :
         337               0 :     if (NS_SUCCEEDED(rv)) {
         338               0 :       nsCOMPtr<nsIFile> parentFile;
         339               0 :       rv = localFile->GetParent(getter_AddRefs(parentFile));
         340               0 :       if (NS_SUCCEEDED(rv)) {
         341               0 :         nsCOMPtr<nsILocalFile> parentLocalFile = do_QueryInterface(parentFile, &rv);
         342               0 :         if (parentLocalFile) {
         343               0 :           filePicker->SetDisplayDirectory(parentLocalFile);
         344                 :         }
         345                 :       }
         346                 :     }
         347                 :
         348                 :     // Unfortunately nsIFilePicker doesn't allow multiple files to be
         349                 :     // default-selected, so only select something by default if exactly
         350                 :     // one file was selected before.
         351               0 :     if (oldFiles.Count() == 1) {
         352               0 :       nsAutoString leafName;
         353               0 :       oldFiles[0]->GetName(leafName);
         354               0 :       if (!leafName.IsEmpty()) {
         355               0 :         filePicker->SetDefaultString(leafName);
         356                 :       }
         357                 :     }
         358                 :   } else {
         359                 :     // Attempt to retrieve the last used directory from the content pref service
         360               0 :     nsCOMPtr<nsILocalFile> localFile;
         361                 :     nsHTMLInputElement::gUploadLastDir->FetchLastUsedDirectory(doc->GetDocumentURI(),
         362               0 :                                                                getter_AddRefs(localFile));
         363               0 :     if (!localFile) {
         364                 :       // Default to "desktop" directory for each platform
         365               0 :       nsCOMPtr<nsIFile> homeDir;
         366               0 :       NS_GetSpecialDirectory(NS_OS_DESKTOP_DIR, getter_AddRefs(homeDir));
         367               0 :       localFile = do_QueryInterface(homeDir);
         368                 :     }
         369               0 :     filePicker->SetDisplayDirectory(localFile);
         370                 :   }
         371                 :
         372                 :   // Open dialog
         373                 :   PRInt16 mode;
         374               0 :   rv = filePicker->Show(&mode);
         375               0 :   NS_ENSURE_SUCCESS(rv, rv);
         376               0 :   if (mode == nsIFilePicker::returnCancel) {
         377               0 :     return NS_OK;
         378                 :   }
         379                 :
         380                 :   // Collect new selected filenames
         381               0 :   nsCOMArray<nsIDOMFile> newFiles;
         382               0 :   if (multi) {
         383               0 :     nsCOMPtr<nsISimpleEnumerator> iter;
         384               0 :     rv = filePicker->GetFiles(getter_AddRefs(iter));
         385               0 :     NS_ENSURE_SUCCESS(rv, rv);
         386                 :
         387               0 :     nsCOMPtr<nsISupports> tmp;
         388               0 :     bool prefSaved = false;
         389               0 :     bool loop = true;
         390               0 :     while (NS_SUCCEEDED(iter->HasMoreElements(&loop)) && loop) {
         391               0 :       iter->GetNext(getter_AddRefs(tmp));
         392               0 :       nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(tmp);
         393               0 :       if (localFile) {
         394               0 :         nsString unicodePath;
         395               0 :         rv = localFile->GetPath(unicodePath);
         396               0 :         if (!unicodePath.IsEmpty()) {
         397                 :           nsCOMPtr<nsIDOMFile> domFile =
         398               0 :             do_QueryObject(new nsDOMFileFile(localFile));
         399               0 :           newFiles.AppendObject(domFile);
         400                 :         }
         401               0 :         if (!prefSaved) {
         402                 :           // Store the last used directory using the content pref service
         403                 :           nsHTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(doc->GetDocumentURI(),
         404               0 :                                                                      localFile);
         405               0 :           prefSaved = true;
         406                 :         }
         407                 :       }
         408                 :     }
         409                 :   }
         410                 :   else {
         411               0 :     nsCOMPtr<nsILocalFile> localFile;
         412               0 :     rv = filePicker->GetFile(getter_AddRefs(localFile));
         413               0 :     if (localFile) {
         414               0 :       nsString unicodePath;
         415               0 :       rv = localFile->GetPath(unicodePath);
         416               0 :       if (!unicodePath.IsEmpty()) {
         417                 :         nsCOMPtr<nsIDOMFile> domFile=
         418               0 :           do_QueryObject(new nsDOMFileFile(localFile));
         419               0 :         newFiles.AppendObject(domFile);
         420                 :       }
         421                 :       // Store the last used directory using the content pref service
         422                 :       nsHTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(doc->GetDocumentURI(),
         423               0 :                                                                  localFile);
         424                 :     }
         425                 :   }
         426                 :
         427                 :   // Set new selected files
         428               0 :   if (newFiles.Count()) {
         429                 :     // The text control frame (if there is one) isn't going to send a change
         430                 :     // event because it will think this is done by a script.
         431                 :     // So, we can safely send one by ourself.
         432               0 :     mInput->SetFiles(newFiles, true);
         433               0 :     nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
         434               0 :                                          static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
         435               0 :                                          NS_LITERAL_STRING("change"), true,
         436               0 :                                          false);
         437                 :   }
         438                 :
         439               0 :   return NS_OK;
         440                 : }
         441                 :
         442                 : #define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")
         443                 :
         444               6 : NS_IMPL_ISUPPORTS2(UploadLastDir, nsIObserver, nsISupportsWeakReference)
         445                 :
         446                 : void
         447               1 : nsHTMLInputElement::InitUploadLastDir() {
         448               1 :   gUploadLastDir = new UploadLastDir();
         449               1 :   NS_ADDREF(gUploadLastDir);
         450                 :
         451                 :   nsCOMPtr<nsIObserverService> observerService =
         452               2 :     mozilla::services::GetObserverService();
         453               1 :   if (observerService && gUploadLastDir) {
         454               1 :     observerService->AddObserver(gUploadLastDir, "browser:purge-session-history", true);
         455                 :   }
         456               1 : }
         457                 :
         458                 : void
         459            1364 : nsHTMLInputElement::DestroyUploadLastDir() {
         460            1364 :   NS_IF_RELEASE(gUploadLastDir);
         461            1364 : }
         462                 :
         463                 : nsresult
         464               0 : UploadLastDir::FetchLastUsedDirectory(nsIURI* aURI, nsILocalFile** aFile)
         465                 : {
         466               0 :   NS_PRECONDITION(aURI, "aURI is null");
         467               0 :   NS_PRECONDITION(aFile, "aFile is null");
         468                 :   // Attempt to get the CPS, if it's not present we'll just return
         469                 :   nsCOMPtr<nsIContentPrefService> contentPrefService =
         470               0 :     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
         471               0 :   if (!contentPrefService)
         472               0 :     return NS_ERROR_NOT_AVAILABLE;
         473               0 :   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
         474               0 :   if (!uri)
         475               0 :     return NS_ERROR_OUT_OF_MEMORY;
         476               0 :   uri->SetAsISupports(aURI);
         477                 :
         478                 :   // Get the last used directory, if it is stored
         479                 :   bool hasPref;
         480               0 :   if (NS_SUCCEEDED(contentPrefService->HasPref(uri, CPS_PREF_NAME, &hasPref)) && hasPref) {
         481               0 :     nsCOMPtr<nsIVariant> pref;
         482               0 :     contentPrefService->GetPref(uri, CPS_PREF_NAME, nsnull, getter_AddRefs(pref));
         483               0 :     nsString prefStr;
         484               0 :     pref->GetAsAString(prefStr);
         485                 :
         486               0 :     nsCOMPtr<nsILocalFile> localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
         487               0 :     if (!localFile)
         488               0 :       return NS_ERROR_OUT_OF_MEMORY;
         489               0 :     localFile->InitWithPath(prefStr);
         490               0 :     localFile.forget(aFile);
         491                 :   }
         492               0 :   return NS_OK;
         493                 : }
         494                 :
         495                 : nsresult
         496               0 : UploadLastDir::StoreLastUsedDirectory(nsIURI* aURI, nsILocalFile* aFile)
         497                 : {
         498               0 :   NS_PRECONDITION(aURI, "aURI is null");
         499               0 :   NS_PRECONDITION(aFile, "aFile is null");
         500               0 :   nsCOMPtr<nsIFile> parentFile;
         501               0 :   aFile->GetParent(getter_AddRefs(parentFile));
         502               0 :   if (!parentFile) {
         503               0 :     return NS_OK;
         504                 :   }
         505               0 :   nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(parentFile);
         506                 :
         507                 :   // Attempt to get the CPS, if it's not present we'll just return
         508                 :   nsCOMPtr<nsIContentPrefService> contentPrefService =
         509               0 :     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
         510               0 :   if (!contentPrefService)
         511               0 :     return NS_ERROR_NOT_AVAILABLE;
         512               0 :   nsCOMPtr<nsIWritableVariant> uri = do_CreateInstance(NS_VARIANT_CONTRACTID);
         513               0 :   if (!uri)
         514               0 :     return NS_ERROR_OUT_OF_MEMORY;
         515               0 :   uri->SetAsISupports(aURI);
         516                 :
         517                 :   // Find the parent of aFile, and store it
         518               0 :   nsString unicodePath;
         519               0 :   parentFile->GetPath(unicodePath);
         520               0 :   if (unicodePath.IsEmpty()) // nothing to do
         521               0 :     return NS_OK;
         522               0 :   nsCOMPtr<nsIWritableVariant> prefValue = do_CreateInstance(NS_VARIANT_CONTRACTID);
         523               0 :   if (!prefValue)
         524               0 :     return NS_ERROR_OUT_OF_MEMORY;
         525               0 :   prefValue->SetAsAString(unicodePath);
         526               0 :   return contentPrefService->SetPref(uri, CPS_PREF_NAME, prefValue);
         527                 : }
         528                 :
         529                 : NS_IMETHODIMP
         530               0 : UploadLastDir::Observe(nsISupports *aSubject, char const *aTopic, PRUnichar const *aData)
         531                 : {
         532               0 :   if (strcmp(aTopic, "browser:purge-session-history") == 0) {
         533                 :     nsCOMPtr<nsIContentPrefService> contentPrefService =
         534               0 :       do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
         535               0 :     if (contentPrefService)
         536               0 :       contentPrefService->RemovePrefsByName(CPS_PREF_NAME);
         537                 :   }
         538               0 :   return NS_OK;
         539                 : }
         540                 :
         541                 : #ifdef ACCESSIBILITY
         542                 : //Helper method
         543                 : static nsresult FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
         544                 :                                           nsPresContext* aPresContext,
         545                 :                                           const nsAString& aEventType);
         546                 : #endif
         547                 :
         548                 : //
         549                 : // construction, destruction
         550                 : //
         551                 :
         552               2 : NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Input)
         553                 :
         554               1 : nsHTMLInputElement::nsHTMLInputElement(already_AddRefed<nsINodeInfo> aNodeInfo,
         555                 :                                        FromParser aFromParser)
         556                 :   : nsGenericHTMLFormElement(aNodeInfo)
         557                 :   , mType(kInputDefaultType->value)
         558                 :   , mDisabledChanged(false)
         559                 :   , mValueChanged(false)
         560                 :   , mCheckedChanged(false)
         561                 :   , mChecked(false)
         562                 :   , mHandlingSelectEvent(false)
         563                 :   , mShouldInitChecked(false)
         564                 :   , mParserCreating(aFromParser != NOT_FROM_PARSER)
         565                 :   , mInInternalActivate(false)
         566                 :   , mCheckedIsToggled(false)
         567                 :   , mIndeterminate(false)
         568                 :   , mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT)
         569                 :   , mCanShowValidUI(true)
         570               1 :   , mCanShowInvalidUI(true)
         571                 : {
         572               1 :   mInputData.mState = new nsTextEditorState(this);
         573               1 :   NS_ADDREF(mInputData.mState);
         574                 :
         575               1 :   if (!gUploadLastDir)
         576               1 :     nsHTMLInputElement::InitUploadLastDir();
         577                 :
         578                 :   // Set up our default state.  By default we're enabled (since we're
         579                 :   // a control type that can be disabled but not actually disabled
         580                 :   // right now), optional, and valid.  We are NOT readwrite by default
         581                 :   // until someone calls UpdateEditableState on us, apparently!  Also
         582                 :   // by default we don't have to show validity UI and so forth.
         583                 :   AddStatesSilently(NS_EVENT_STATE_ENABLED |
         584                 :                     NS_EVENT_STATE_OPTIONAL |
         585               1 :                     NS_EVENT_STATE_VALID);
         586               1 : }
         587                 :
         588               3 : nsHTMLInputElement::~nsHTMLInputElement()
         589                 : {
         590               1 :   if (mFileList) {
         591               0 :     mFileList->Disconnect();
         592                 :   }
         593               1 :   DestroyImageLoadingContent();
         594               1 :   FreeData();
         595               4 : }
         596                 :
         597                 : void
         598               1 : nsHTMLInputElement::FreeData()
         599                 : {
         600               1 :   if (!IsSingleLineTextControl(false)) {
         601               0 :     nsMemory::Free(mInputData.mValue);
         602               0 :     mInputData.mValue = nsnull;
         603                 :   } else {
         604               1 :     UnbindFromFrame(nsnull);
         605               1 :     NS_IF_RELEASE(mInputData.mState);
         606                 :   }
         607               1 : }
         608                 :
         609                 : nsTextEditorState*
         610               2 : nsHTMLInputElement::GetEditorState() const
         611                 : {
         612               2 :   if (!IsSingleLineTextControl(false)) {
         613               0 :     return nsnull;
         614                 :   }
         615                 :
         616               2 :   NS_ASSERTION(mInputData.mState,
         617                 :     "Single line text controls need to have a state associated with them");
         618                 :
         619               2 :   return mInputData.mState;
         620                 : }
         621                 :
         622                 :
         623                 : // nsISupports
         624                 :
         625            1396 : NS_IMPL_CYCLE_COLLECTION_CLASS(nsHTMLInputElement)
         626               1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLInputElement,
         627                 :                                                   nsGenericHTMLFormElement)
         628               1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mControllers)
         629               1 :   if (tmp->IsSingleLineTextControl(false)) {
         630               1 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NATIVE_MEMBER(mInputData.mState, nsTextEditorState)
         631                 :   }
         632               1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMARRAY(mFiles)
         633               1 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE_NSCOMPTR(mFileList)
         634               1 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
         635                 :
         636               1 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLInputElement,
         637                 :                                                   nsGenericHTMLFormElement)
         638               1 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMPTR(mControllers)
         639               1 :   NS_IMPL_CYCLE_COLLECTION_UNLINK_NSCOMARRAY(mFiles)
         640               1 :   if (tmp->mFileList) {
         641               0 :     tmp->mFileList->Disconnect();
         642               0 :     tmp->mFileList = nsnull;
         643                 :   }
         644                 :   //XXX should unlink more?
         645               1 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
         646                 :
         647              19 : NS_IMPL_ADDREF_INHERITED(nsHTMLInputElement, nsGenericElement)
         648              19 : NS_IMPL_RELEASE_INHERITED(nsHTMLInputElement, nsGenericElement)
         649                 :
         650                 :
         651               1 : DOMCI_NODE_DATA(HTMLInputElement, nsHTMLInputElement)
         652                 :
         653                 : // QueryInterface implementation for nsHTMLInputElement
         654              39 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(nsHTMLInputElement)
         655              24 :   NS_HTML_CONTENT_INTERFACE_TABLE8(nsHTMLInputElement,
         656                 :                                    nsIDOMHTMLInputElement,
         657                 :                                    nsITextControlElement,
         658                 :                                    nsIPhonetic,
         659                 :                                    imgIDecoderObserver,
         660                 :                                    nsIImageLoadingContent,
         661                 :                                    imgIContainerObserver,
         662                 :                                    nsIDOMNSEditableElement,
         663                 :                                    nsIConstraintValidation)
         664              23 :   NS_HTML_CONTENT_INTERFACE_TABLE_TO_MAP_SEGUE(nsHTMLInputElement,
         665                 :                                                nsGenericHTMLFormElement)
         666               0 : NS_HTML_CONTENT_INTERFACE_TABLE_TAIL_CLASSINFO(HTMLInputElement)
         667                 :
         668                 : // nsIConstraintValidation
         669               0 : NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(nsHTMLInputElement)
         670                 :
         671                 : // nsIDOMNode
         672                 :
         673                 : nsresult
         674               0 : nsHTMLInputElement::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
         675                 : {
         676               0 :   *aResult = nsnull;
         677                 :
         678               0 :   nsCOMPtr<nsINodeInfo> ni = aNodeInfo;
         679                 :   nsRefPtr<nsHTMLInputElement> it =
         680               0 :     new nsHTMLInputElement(ni.forget(), NOT_FROM_PARSER);
         681                 :
         682               0 :   nsresult rv = CopyInnerTo(it);
         683               0 :   NS_ENSURE_SUCCESS(rv, rv);
         684                 :
         685               0 :   switch (mType) {
         686                 :     case NS_FORM_INPUT_EMAIL:
         687                 :     case NS_FORM_INPUT_SEARCH:
         688                 :     case NS_FORM_INPUT_TEXT:
         689                 :     case NS_FORM_INPUT_PASSWORD:
         690                 :     case NS_FORM_INPUT_TEL:
         691                 :     case NS_FORM_INPUT_URL:
         692               0 :       if (mValueChanged) {
         693                 :         // We don't have our default value anymore.  Set our value on
         694                 :         // the clone.
         695               0 :         nsAutoString value;
         696               0 :         GetValueInternal(value);
         697                 :         // SetValueInternal handles setting the VALUE_CHANGED bit for us
         698               0 :         it->SetValueInternal(value, false, true);
         699                 :       }
         700               0 :       break;
         701                 :     case NS_FORM_INPUT_FILE:
         702               0 :       if (it->OwnerDoc()->IsStaticDocument()) {
         703                 :         // We're going to be used in print preview.  Since the doc is static
         704                 :         // we can just grab the pretty string and use it as wallpaper
         705               0 :         GetDisplayFileName(it->mStaticDocFileList);
         706                 :       } else {
         707               0 :         it->mFiles.Clear();
         708               0 :         it->mFiles.AppendObjects(mFiles);
         709                 :       }
         710               0 :       break;
         711                 :     case NS_FORM_INPUT_RADIO:
         712                 :     case NS_FORM_INPUT_CHECKBOX:
         713               0 :       if (mCheckedChanged) {
         714                 :         // We no longer have our original checked state.  Set our
         715                 :         // checked state on the clone.
         716               0 :         it->DoSetChecked(mChecked, false, true);
         717                 :       }
         718               0 :       break;
         719                 :     case NS_FORM_INPUT_IMAGE:
         720               0 :       if (it->OwnerDoc()->IsStaticDocument()) {
         721               0 :         CreateStaticImageClone(it);
         722                 :       }
         723               0 :       break;
         724                 :     default:
         725               0 :       break;
         726                 :   }
         727                 :
         728               0 :   it.forget(aResult);
         729               0 :   return NS_OK;
         730                 : }
         731                 :
         732                 : nsresult
         733               0 : nsHTMLInputElement::BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
         734                 :                                   const nsAttrValueOrString* aValue,
         735                 :                                   bool aNotify)
         736                 : {
         737               0 :   if (aNameSpaceID == kNameSpaceID_None) {
         738                 :     //
         739                 :     // When name or type changes, radio should be removed from radio group.
         740                 :     // (type changes are handled in the form itself currently)
         741                 :     // If the parser is not done creating the radio, we also should not do it.
         742                 :     //
         743               0 :     if ((aName == nsGkAtoms::name ||
         744               0 :          (aName == nsGkAtoms::type && !mForm)) &&
         745                 :         mType == NS_FORM_INPUT_RADIO &&
         746               0 :         (mForm || !mParserCreating)) {
         747               0 :       WillRemoveFromRadioGroup();
         748               0 :     } else if (aNotify && aName == nsGkAtoms::src &&
         749                 :                mType == NS_FORM_INPUT_IMAGE) {
         750               0 :       if (aValue) {
         751               0 :         LoadImage(aValue->String(), true, aNotify);
         752                 :       } else {
         753                 :         // Null value means the attr got unset; drop the image
         754               0 :         CancelImageRequests(aNotify);
         755                 :       }
         756               0 :     } else if (aNotify && aName == nsGkAtoms::disabled) {
         757               0 :       mDisabledChanged = true;
         758                 :     }
         759                 :   }
         760                 :
         761                 :   return nsGenericHTMLFormElement::BeforeSetAttr(aNameSpaceID, aName,
         762               0 :                                                  aValue, aNotify);
         763                 : }
         764                 :
         765                 : nsresult
         766               0 : nsHTMLInputElement::AfterSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName,
         767                 :                                  const nsAttrValue* aValue, bool aNotify)
         768                 : {
         769               0 :   if (aNameSpaceID == kNameSpaceID_None) {
         770                 :     //
         771                 :     // When name or type changes, radio should be added to radio group.
         772                 :     // (type changes are handled in the form itself currently)
         773                 :     // If the parser is not done creating the radio, we also should not do it.
         774                 :     //
         775               0 :     if ((aName == nsGkAtoms::name ||
         776               0 :          (aName == nsGkAtoms::type && !mForm)) &&
         777                 :         mType == NS_FORM_INPUT_RADIO &&
         778               0 :         (mForm || !mParserCreating)) {
         779               0 :       AddedToRadioGroup();
         780               0 :       UpdateValueMissingValidityStateForRadio(false);
         781                 :     }
         782                 :
         783                 :     // If @value is changed and BF_VALUE_CHANGED is false, @value is the value
         784                 :     // of the element so, if the value of the element is different than @value,
         785                 :     // we have to re-set it. This is only the case when GetValueMode() returns
         786                 :     // VALUE_MODE_VALUE.
         787               0 :     if (aName == nsGkAtoms::value &&
         788               0 :         !mValueChanged && GetValueMode() == VALUE_MODE_VALUE) {
         789               0 :       SetDefaultValueAsValue();
         790                 :     }
         791                 :
         792                 :     //
         793                 :     // Checked must be set no matter what type of control it is, since
         794                 :     // mChecked must reflect the new value
         795               0 :     if (aName == nsGkAtoms::checked && !mCheckedChanged) {
         796                 :       // Delay setting checked if the parser is creating this element (wait
         797                 :       // until everything is set)
         798               0 :       if (mParserCreating) {
         799               0 :         mShouldInitChecked = true;
         800                 :       } else {
         801               0 :         DoSetChecked(DefaultChecked(), true, true);
         802               0 :         SetCheckedChanged(false);
         803                 :       }
         804                 :     }
         805                 :
         806               0 :     if (aName == nsGkAtoms::type) {
         807               0 :       if (!aValue) {
         808                 :         // We're now a text input.  Note that we have to handle this manually,
         809                 :         // since removing an attribute (which is what happened, since aValue is
         810                 :         // null) doesn't call ParseAttribute.
         811               0 :         HandleTypeChange(kInputDefaultType->value);
         812                 :       }
         813                 :
         814               0 :       UpdateBarredFromConstraintValidation();
         815                 :
         816               0 :       if (mType != NS_FORM_INPUT_IMAGE) {
         817                 :         // We're no longer an image input.  Cancel our image requests, if we have
         818                 :         // any.  Note that doing this when we already weren't an image is ok --
         819                 :         // just does nothing.
         820               0 :         CancelImageRequests(aNotify);
         821               0 :       } else if (aNotify) {
         822                 :         // We just got switched to be an image input; we should see
         823                 :         // whether we have an image to load;
         824               0 :         nsAutoString src;
         825               0 :         if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
         826               0 :           LoadImage(src, false, aNotify);
         827                 :         }
         828                 :       }
         829                 :     }
         830                 :
         831               0 :     if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
         832               0 :       nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
         833                 :
         834               0 :       if (container) {
         835               0 :         nsAutoString name;
         836               0 :         GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
         837               0 :         container->RadioRequiredChanged(name, this);
         838                 :       }
         839                 :     }
         840                 :
         841               0 :     if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
         842                 :         aName == nsGkAtoms::readonly) {
         843               0 :       UpdateValueMissingValidityState();
         844                 :
         845                 :       // This *has* to be called *after* validity has changed.
         846               0 :       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
         847               0 :         UpdateBarredFromConstraintValidation();
         848                 :       }
         849               0 :     } else if (MaxLengthApplies() && aName == nsGkAtoms::maxlength) {
         850               0 :       UpdateTooLongValidityState();
         851               0 :     } else if (aName == nsGkAtoms::pattern) {
         852               0 :       UpdatePatternMismatchValidityState();
         853               0 :     } else if (aName == nsGkAtoms::multiple) {
         854               0 :       UpdateTypeMismatchValidityState();
         855                 :     }
         856                 :
         857               0 :     UpdateEditableState(aNotify);
         858               0 :     UpdateState(aNotify);
         859                 :   }
         860                 :
         861                 :   return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName,
         862               0 :                                                 aValue, aNotify);
         863                 : }
         864                 :
         865                 : // nsIDOMHTMLInputElement
         866                 :
         867                 : NS_IMETHODIMP
         868               0 : nsHTMLInputElement::GetForm(nsIDOMHTMLFormElement** aForm)
         869                 : {
         870               0 :   return nsGenericHTMLFormElement::GetForm(aForm);
         871                 : }
         872                 :
         873               1 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, DefaultValue, value)
         874               0 : NS_IMPL_BOOL_ATTR(nsHTMLInputElement, DefaultChecked, checked)
         875               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, Accept, accept)
         876               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, Align, align)
         877               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, Alt, alt)
         878               0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Autocomplete, autocomplete,
         879                 :                                 kInputDefaultAutocomplete->tag)
         880               0 : NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Autofocus, autofocus)
         881                 : //NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Checked, checked)
         882               0 : NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Disabled, disabled)
         883               0 : NS_IMPL_ACTION_ATTR(nsHTMLInputElement, FormAction, formaction)
         884               0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLInputElement, FormEnctype, formenctype,
         885                 :                                 kFormDefaultEnctype->tag)
         886               0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLInputElement, FormMethod, formmethod,
         887                 :                                 kFormDefaultMethod->tag)
         888               0 : NS_IMPL_BOOL_ATTR(nsHTMLInputElement, FormNoValidate, formnovalidate)
         889               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, FormTarget, formtarget)
         890               0 : NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Multiple, multiple)
         891               0 : NS_IMPL_NON_NEGATIVE_INT_ATTR(nsHTMLInputElement, MaxLength, maxlength)
         892               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, Name, name)
         893               0 : NS_IMPL_BOOL_ATTR(nsHTMLInputElement, ReadOnly, readonly)
         894               0 : NS_IMPL_BOOL_ATTR(nsHTMLInputElement, Required, required)
         895               0 : NS_IMPL_URI_ATTR(nsHTMLInputElement, Src, src)
         896               0 : NS_IMPL_INT_ATTR(nsHTMLInputElement, TabIndex, tabindex)
         897               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, UseMap, usemap)
         898                 : //NS_IMPL_STRING_ATTR(nsHTMLInputElement, Value, value)
         899               0 : NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(nsHTMLInputElement, Size, size, DEFAULT_COLS)
         900               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, Pattern, pattern)
         901               0 : NS_IMPL_STRING_ATTR(nsHTMLInputElement, Placeholder, placeholder)
         902               0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(nsHTMLInputElement, Type, type,
         903                 :                                 kInputDefaultType->tag)
         904                 :
         905                 : NS_IMETHODIMP
         906               0 : nsHTMLInputElement::GetIndeterminate(bool* aValue)
         907                 : {
         908               0 :   *aValue = mIndeterminate;
         909               0 :   return NS_OK;
         910                 : }
         911                 :
         912                 : nsresult
         913               0 : nsHTMLInputElement::SetIndeterminateInternal(bool aValue,
         914                 :                                              bool aShouldInvalidate)
         915                 : {
         916               0 :   mIndeterminate = aValue;
         917                 :
         918               0 :   if (aShouldInvalidate) {
         919                 :     // Repaint the frame
         920               0 :     nsIFrame* frame = GetPrimaryFrame();
         921               0 :     if (frame)
         922               0 :       frame->InvalidateFrameSubtree();
         923                 :   }
         924                 :
         925               0 :   UpdateState(true);
         926                 :
         927               0 :   return NS_OK;
         928                 : }
         929                 :
         930                 : NS_IMETHODIMP
         931               0 : nsHTMLInputElement::SetIndeterminate(bool aValue)
         932                 : {
         933               0 :   return SetIndeterminateInternal(aValue, true);
         934                 : }
         935                 :
         936                 : NS_IMETHODIMP
         937               1 : nsHTMLInputElement::GetValue(nsAString& aValue)
         938                 : {
         939               1 :   return GetValueInternal(aValue);
         940                 : }
         941                 :
         942                 : nsresult
         943               1 : nsHTMLInputElement::GetValueInternal(nsAString& aValue) const
         944                 : {
         945               1 :   switch (GetValueMode()) {
         946                 :     case VALUE_MODE_VALUE:
         947               1 :       mInputData.mState->GetValue(aValue, true);
         948               1 :       return NS_OK;
         949                 :
         950                 :     case VALUE_MODE_FILENAME:
         951               0 :       if (nsContentUtils::CallerHasUniversalXPConnect()) {
         952               0 :         if (mFiles.Count()) {
         953               0 :           return mFiles[0]->GetMozFullPath(aValue);
         954                 :         }
         955                 :         else {
         956               0 :           aValue.Truncate();
         957                 :         }
         958                 :       } else {
         959                 :         // Just return the leaf name
         960               0 :         if (mFiles.Count() == 0 || NS_FAILED(mFiles[0]->GetName(aValue))) {
         961               0 :           aValue.Truncate();
         962                 :         }
         963                 :       }
         964                 :
         965               0 :       return NS_OK;
         966                 :
         967                 :     case VALUE_MODE_DEFAULT:
         968                 :       // Treat defaultValue as value.
         969               0 :       GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue);
         970               0 :       return NS_OK;
         971                 :
         972                 :     case VALUE_MODE_DEFAULT_ON:
         973                 :       // Treat default value as value and returns "on" if no value.
         974               0 :       if (!GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue)) {
         975               0 :         aValue.AssignLiteral("on");
         976                 :       }
         977               0 :       return NS_OK;
         978                 :   }
         979                 :
         980                 :   // This return statement is required for some compilers.
         981                 :   return NS_OK;
         982                 : }
         983                 :
         984                 : bool
         985               0 : nsHTMLInputElement::IsValueEmpty() const
         986                 : {
         987               0 :   nsAutoString value;
         988               0 :   GetValueInternal(value);
         989                 :
         990               0 :   return value.IsEmpty();
         991                 : }
         992                 :
         993                 : NS_IMETHODIMP
         994               0 : nsHTMLInputElement::SetValue(const nsAString& aValue)
         995                 : {
         996                 :   // check security.  Note that setting the value to the empty string is always
         997                 :   // OK and gives pages a way to clear a file input if necessary.
         998               0 :   if (mType == NS_FORM_INPUT_FILE) {
         999               0 :     if (!aValue.IsEmpty()) {
        1000               0 :       if (!nsContentUtils::CallerHasUniversalXPConnect()) {
        1001                 :         // setting the value of a "FILE" input widget requires the
        1002                 :         // UniversalXPConnect privilege
        1003               0 :         return NS_ERROR_DOM_SECURITY_ERR;
        1004                 :       }
        1005               0 :       const PRUnichar *name = PromiseFlatString(aValue).get();
        1006               0 :       return MozSetFileNameArray(&name, 1);
        1007                 :     }
        1008                 :     else {
        1009               0 :       ClearFiles(true);
        1010                 :     }
        1011                 :   }
        1012                 :   else {
        1013               0 :     SetValueInternal(aValue, false, true);
        1014                 :   }
        1015                 :
        1016               0 :   return NS_OK;
        1017                 : }
        1018                 :
        1019                 : NS_IMETHODIMP
        1020               0 : nsHTMLInputElement::GetList(nsIDOMHTMLElement** aValue)
        1021                 : {
        1022               0 :   *aValue = nsnull;
        1023                 :
        1024               0 :   nsAutoString dataListId;
        1025               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::list, dataListId);
        1026               0 :   if (dataListId.IsEmpty()) {
        1027               0 :     return NS_OK;
        1028                 :   }
        1029                 :
        1030               0 :   nsIDocument* doc = GetCurrentDoc();
        1031               0 :   if (!doc) {
        1032               0 :     return NS_OK;
        1033                 :   }
        1034                 :
        1035               0 :   Element* element = doc->GetElementById(dataListId);
        1036               0 :   if (!element || !element->IsHTML(nsGkAtoms::datalist)) {
        1037               0 :     return NS_OK;
        1038                 :   }
        1039                 :
        1040               0 :   CallQueryInterface(element, aValue);
        1041               0 :   return NS_OK;
        1042                 : }
        1043                 :
        1044                 : NS_IMETHODIMP
        1045               0 : nsHTMLInputElement::MozGetFileNameArray(PRUint32 *aLength, PRUnichar ***aFileNames)
        1046                 : {
        1047               0 :   if (!nsContentUtils::CallerHasUniversalXPConnect()) {
        1048                 :     // Since this function returns full paths it's important that normal pages
        1049                 :     // can't call it.
        1050               0 :     return NS_ERROR_DOM_SECURITY_ERR;
        1051                 :   }
        1052                 :
        1053               0 :   *aLength = mFiles.Count();
        1054                 :   PRUnichar **ret =
        1055               0 :     static_cast<PRUnichar **>(NS_Alloc(mFiles.Count() * sizeof(PRUnichar*)));
        1056               0 :   if (!ret) {
        1057               0 :     return NS_ERROR_OUT_OF_MEMORY;
        1058                 :   }
        1059                 :
        1060               0 :   for (PRInt32 i = 0; i < mFiles.Count(); i++) {
        1061               0 :     nsString str;
        1062               0 :     mFiles[i]->GetMozFullPathInternal(str);
        1063               0 :     ret[i] = NS_strdup(str.get());
        1064                 :   }
        1065                 :
        1066               0 :   *aFileNames = ret;
        1067                 :
        1068               0 :   return NS_OK;
        1069                 : }
        1070                 :
        1071                 : NS_IMETHODIMP
        1072               0 : nsHTMLInputElement::MozSetFileNameArray(const PRUnichar **aFileNames, PRUint32 aLength)
        1073                 : {
        1074               0 :   if (!nsContentUtils::CallerHasUniversalXPConnect()) {
        1075                 :     // setting the value of a "FILE" input widget requires the
        1076                 :     // UniversalXPConnect privilege
        1077               0 :     return NS_ERROR_DOM_SECURITY_ERR;
        1078                 :   }
        1079                 :
        1080               0 :   nsCOMArray<nsIDOMFile> files;
        1081               0 :   for (PRUint32 i = 0; i < aLength; ++i) {
        1082               0 :     nsCOMPtr<nsIFile> file;
        1083               0 :     if (StringBeginsWith(nsDependentString(aFileNames[i]),
        1084               0 :                          NS_LITERAL_STRING("file:"),
        1085               0 :                          nsASCIICaseInsensitiveStringComparator())) {
        1086                 :       // Converts the URL string into the corresponding nsIFile if possible
        1087                 :       // A local file will be created if the URL string begins with file://
        1088               0 :       NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileNames[i]),
        1089               0 :                             getter_AddRefs(file));
        1090                 :     }
        1091                 :
        1092               0 :     if (!file) {
        1093                 :       // this is no "file://", try as local file
        1094               0 :       nsCOMPtr<nsILocalFile> localFile;
        1095               0 :       NS_NewLocalFile(nsDependentString(aFileNames[i]),
        1096               0 :                       false, getter_AddRefs(localFile));
        1097               0 :       file = do_QueryInterface(localFile);
        1098                 :     }
        1099                 :
        1100               0 :     if (file) {
        1101               0 :       nsCOMPtr<nsIDOMFile> domFile = new nsDOMFileFile(file);
        1102               0 :       files.AppendObject(domFile);
        1103                 :     } else {
        1104               0 :       continue; // Not much we can do if the file doesn't exist
        1105                 :     }
        1106                 :
        1107                 :   }
        1108                 :
        1109               0 :   SetFiles(files, true);
        1110                 :
        1111               0 :   return NS_OK;
        1112                 : }
        1113                 :
        1114                 : NS_IMETHODIMP
        1115               0 : nsHTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult)
        1116                 : {
        1117               0 :   *aResult = IsSingleLineTextControl(aExcludePassword);
        1118                 :
        1119               0 :   return NS_OK;
        1120                 : }
        1121                 :
        1122                 : NS_IMETHODIMP
        1123               0 : nsHTMLInputElement::SetUserInput(const nsAString& aValue)
        1124                 : {
        1125               0 :   if (!nsContentUtils::IsCallerTrustedForWrite()) {
        1126               0 :     return NS_ERROR_DOM_SECURITY_ERR;
        1127                 :   }
        1128                 :
        1129               0 :   if (mType == NS_FORM_INPUT_FILE)
        1130                 :   {
        1131               0 :     const PRUnichar* name = PromiseFlatString(aValue).get();
        1132               0 :     return MozSetFileNameArray(&name, 1);
        1133                 :   } else {
        1134               0 :     SetValueInternal(aValue, true, true);
        1135                 :   }
        1136                 :
        1137                 :   return nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
        1138                 :                                               static_cast<nsIDOMHTMLInputElement*>(this),
        1139               0 :                                               NS_LITERAL_STRING("input"), true,
        1140               0 :                                               true);
        1141                 : }
        1142                 :
        1143                 : NS_IMETHODIMP_(nsIEditor*)
        1144               0 : nsHTMLInputElement::GetTextEditor()
        1145                 : {
        1146               0 :   nsTextEditorState *state = GetEditorState();
        1147               0 :   if (state) {
        1148               0 :     return state->GetEditor();
        1149                 :   }
        1150               0 :   return nsnull;
        1151                 : }
        1152                 :
        1153                 : NS_IMETHODIMP_(nsISelectionController*)
        1154               0 : nsHTMLInputElement::GetSelectionController()
        1155                 : {
        1156               0 :   nsTextEditorState *state = GetEditorState();
        1157               0 :   if (state) {
        1158               0 :     return state->GetSelectionController();
        1159                 :   }
        1160               0 :   return nsnull;
        1161                 : }
        1162                 :
        1163                 : nsFrameSelection*
        1164               0 : nsHTMLInputElement::GetConstFrameSelection()
        1165                 : {
        1166               0 :   nsTextEditorState *state = GetEditorState();
        1167               0 :   if (state) {
        1168               0 :     return state->GetConstFrameSelection();
        1169                 :   }
        1170               0 :   return nsnull;
        1171                 : }
        1172                 :
        1173                 : NS_IMETHODIMP
        1174               0 : nsHTMLInputElement::BindToFrame(nsTextControlFrame* aFrame)
        1175                 : {
        1176               0 :   nsTextEditorState *state = GetEditorState();
        1177               0 :   if (state) {
        1178               0 :     return state->BindToFrame(aFrame);
        1179                 :   }
        1180               0 :   return NS_ERROR_FAILURE;
        1181                 : }
        1182                 :
        1183                 : NS_IMETHODIMP_(void)
        1184               1 : nsHTMLInputElement::UnbindFromFrame(nsTextControlFrame* aFrame)
        1185                 : {
        1186               1 :   nsTextEditorState *state = GetEditorState();
        1187               1 :   if (state && aFrame) {
        1188               0 :     state->UnbindFromFrame(aFrame);
        1189                 :   }
        1190               1 : }
        1191                 :
        1192                 : NS_IMETHODIMP
        1193               0 : nsHTMLInputElement::CreateEditor()
        1194                 : {
        1195               0 :   nsTextEditorState *state = GetEditorState();
        1196               0 :   if (state) {
        1197               0 :     return state->PrepareEditor();
        1198                 :   }
        1199               0 :   return NS_ERROR_FAILURE;
        1200                 : }
        1201                 :
        1202                 : NS_IMETHODIMP_(nsIContent*)
        1203               0 : nsHTMLInputElement::GetRootEditorNode()
        1204                 : {
        1205               0 :   nsTextEditorState *state = GetEditorState();
        1206               0 :   if (state) {
        1207               0 :     return state->GetRootNode();
        1208                 :   }
        1209               0 :   return nsnull;
        1210                 : }
        1211                 :
        1212                 : NS_IMETHODIMP_(nsIContent*)
        1213               0 : nsHTMLInputElement::CreatePlaceholderNode()
        1214                 : {
        1215               0 :   nsTextEditorState *state = GetEditorState();
        1216               0 :   if (state) {
        1217               0 :     NS_ENSURE_SUCCESS(state->CreatePlaceholderNode(), nsnull);
        1218               0 :     return state->GetPlaceholderNode();
        1219                 :   }
        1220               0 :   return nsnull;
        1221                 : }
        1222                 :
        1223                 : NS_IMETHODIMP_(nsIContent*)
        1224               0 : nsHTMLInputElement::GetPlaceholderNode()
        1225                 : {
        1226               0 :   nsTextEditorState *state = GetEditorState();
        1227               0 :   if (state) {
        1228               0 :     return state->GetPlaceholderNode();
        1229                 :   }
        1230               0 :   return nsnull;
        1231                 : }
        1232                 :
        1233                 : NS_IMETHODIMP_(void)
        1234               0 : nsHTMLInputElement::UpdatePlaceholderText(bool aNotify)
        1235                 : {
        1236               0 :   nsTextEditorState *state = GetEditorState();
        1237               0 :   if (state) {
        1238               0 :     state->UpdatePlaceholderText(aNotify);
        1239                 :   }
        1240               0 : }
        1241                 :
        1242                 : NS_IMETHODIMP_(void)
        1243               0 : nsHTMLInputElement::SetPlaceholderClass(bool aVisible, bool aNotify)
        1244                 : {
        1245               0 :   nsTextEditorState *state = GetEditorState();
        1246               0 :   if (state) {
        1247               0 :     state->SetPlaceholderClass(aVisible, aNotify);
        1248                 :   }
        1249               0 : }
        1250                 :
        1251                 : void
        1252               0 : nsHTMLInputElement::GetDisplayFileName(nsAString& aValue) const
        1253                 : {
        1254               0 :   if (OwnerDoc()->IsStaticDocument()) {
        1255               0 :     aValue = mStaticDocFileList;
        1256               0 :     return;
        1257                 :   }
        1258                 :
        1259               0 :   aValue.Truncate();
        1260               0 :   for (PRInt32 i = 0; i < mFiles.Count(); ++i) {
        1261               0 :     nsString str;
        1262               0 :     mFiles[i]->GetMozFullPathInternal(str);
        1263               0 :     if (i == 0) {
        1264               0 :       aValue.Append(str);
        1265                 :     }
        1266                 :     else {
        1267               0 :       aValue.Append(NS_LITERAL_STRING(", ") + str);
        1268                 :     }
        1269                 :   }
        1270                 : }
        1271                 :
        1272                 : void
        1273               0 : nsHTMLInputElement::SetFiles(const nsCOMArray<nsIDOMFile>& aFiles,
        1274                 :                              bool aSetValueChanged)
        1275                 : {
        1276               0 :   mFiles.Clear();
        1277               0 :   mFiles.AppendObjects(aFiles);
        1278                 :
        1279               0 :   AfterSetFiles(aSetValueChanged);
        1280               0 : }
        1281                 :
        1282                 : void
        1283               0 : nsHTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
        1284                 :                              bool aSetValueChanged)
        1285                 : {
        1286               0 :   mFiles.Clear();
        1287                 :
        1288               0 :   if (aFiles) {
        1289                 :     PRUint32 listLength;
        1290               0 :     aFiles->GetLength(&listLength);
        1291               0 :     for (PRUint32 i = 0; i < listLength; i++) {
        1292               0 :       nsCOMPtr<nsIDOMFile> file;
        1293               0 :       aFiles->Item(i, getter_AddRefs(file));
        1294               0 :       mFiles.AppendObject(file);
        1295                 :     }
        1296                 :   }
        1297                 :
        1298               0 :   AfterSetFiles(aSetValueChanged);
        1299               0 : }
        1300                 :
        1301                 : void
        1302               0 : nsHTMLInputElement::AfterSetFiles(bool aSetValueChanged)
        1303                 : {
        1304                 :   // No need to flush here, if there's no frame at this point we
        1305                 :   // don't need to force creation of one just to tell it about this
        1306                 :   // new value.  We just want the display to update as needed.
        1307               0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
        1308               0 :   if (formControlFrame) {
        1309               0 :     nsAutoString readableValue;
        1310               0 :     GetDisplayFileName(readableValue);
        1311               0 :     formControlFrame->SetFormProperty(nsGkAtoms::value, readableValue);
        1312                 :   }
        1313                 :
        1314               0 :   UpdateFileList();
        1315                 :
        1316               0 :   if (aSetValueChanged) {
        1317               0 :     SetValueChanged(true);
        1318                 :   }
        1319                 :
        1320               0 :   UpdateAllValidityStates(true);
        1321               0 : }
        1322                 :
        1323                 : const nsCOMArray<nsIDOMFile>&
        1324               0 : nsHTMLInputElement::GetFiles() const
        1325                 : {
        1326               0 :   return mFiles;
        1327                 : }
        1328                 :
        1329                 : nsresult
        1330               0 : nsHTMLInputElement::UpdateFileList()
        1331                 : {
        1332               0 :   if (mFileList) {
        1333               0 :     mFileList->Clear();
        1334                 :
        1335               0 :     const nsCOMArray<nsIDOMFile>& files = GetFiles();
        1336               0 :     for (PRInt32 i = 0; i < files.Count(); ++i) {
        1337               0 :       if (!mFileList->Append(files[i])) {
        1338               0 :         return NS_ERROR_FAILURE;
        1339                 :       }
        1340                 :     }
        1341                 :   }
        1342                 :
        1343               0 :   return NS_OK;
        1344                 : }
        1345                 :
        1346                 : nsresult
        1347               1 : nsHTMLInputElement::SetValueInternal(const nsAString& aValue,
        1348                 :                                      bool aUserInput,
        1349                 :                                      bool aSetValueChanged)
        1350                 : {
        1351               1 :   NS_PRECONDITION(GetValueMode() != VALUE_MODE_FILENAME,
        1352                 :                   "Don't call SetValueInternal for file inputs");
        1353                 :
        1354               1 :   switch (GetValueMode()) {
        1355                 :     case VALUE_MODE_VALUE:
        1356                 :     {
        1357                 :       // At the moment, only single line text control have to sanitize their value
        1358                 :       // Because we have to create a new string for that, we should prevent doing
        1359                 :       // it if it's useless.
        1360               2 :       nsAutoString value(aValue);
        1361                 :
        1362               1 :       if (!mParserCreating) {
        1363               1 :         SanitizeValue(value);
        1364                 :       }
        1365                 :
        1366               1 :       if (aSetValueChanged) {
        1367               0 :         SetValueChanged(true);
        1368                 :       }
        1369                 :
        1370               1 :       mInputData.mState->SetValue(value, aUserInput);
        1371                 :
        1372                 :       // This call might be useless in some situations because if the element is
        1373                 :       // a single line text control, nsTextEditorState::SetValue will call
        1374                 :       // nsHTMLInputElement::OnValueChanged which is going to call UpdateState()
        1375                 :       // if the element is focused. This bug 665547.
        1376               2 :       if (PlaceholderApplies() &&
        1377               1 :           HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
        1378               0 :         UpdateState(true);
        1379                 :       }
        1380                 :
        1381               1 :       return NS_OK;
        1382                 :     }
        1383                 :
        1384                 :     case VALUE_MODE_DEFAULT:
        1385                 :     case VALUE_MODE_DEFAULT_ON:
        1386                 :       // If the value of a hidden input was changed, we mark it changed so that we
        1387                 :       // will know we need to save / restore the value.  Yes, we are overloading
        1388                 :       // the meaning of ValueChanged just a teensy bit to save a measly byte of
        1389                 :       // storage space in nsHTMLInputElement.  Yes, you are free to make a new flag,
        1390                 :       // NEED_TO_SAVE_VALUE, at such time as mBitField becomes a 16-bit value.
        1391               0 :       if (mType == NS_FORM_INPUT_HIDDEN) {
        1392               0 :         SetValueChanged(true);
        1393                 :       }
        1394                 :
        1395                 :       // Treat value == defaultValue for other input elements.
        1396                 :       return nsGenericHTMLFormElement::SetAttr(kNameSpaceID_None,
        1397                 :                                                nsGkAtoms::value, aValue,
        1398               0 :                                                true);
        1399                 :
        1400                 :     case VALUE_MODE_FILENAME:
        1401               0 :       return NS_ERROR_UNEXPECTED;
        1402                 :   }
        1403                 :
        1404                 :   // This return statement is required for some compilers.
        1405                 :   return NS_OK;
        1406                 : }
        1407                 :
        1408                 : NS_IMETHODIMP
        1409               0 : nsHTMLInputElement::SetValueChanged(bool aValueChanged)
        1410                 : {
        1411               0 :   bool valueChangedBefore = mValueChanged;
        1412                 :
        1413               0 :   mValueChanged = aValueChanged;
        1414                 :
        1415               0 :   if (valueChangedBefore != aValueChanged) {
        1416               0 :     UpdateState(true);
        1417                 :   }
        1418                 :
        1419               0 :   return NS_OK;
        1420                 : }
        1421                 :
        1422                 : NS_IMETHODIMP
        1423               0 : nsHTMLInputElement::GetChecked(bool* aChecked)
        1424                 : {
        1425               0 :   *aChecked = mChecked;
        1426               0 :   return NS_OK;
        1427                 : }
        1428                 :
        1429                 : void
        1430               0 : nsHTMLInputElement::SetCheckedChanged(bool aCheckedChanged)
        1431                 : {
        1432               0 :   DoSetCheckedChanged(aCheckedChanged, true);
        1433               0 : }
        1434                 :
        1435                 : void
        1436               0 : nsHTMLInputElement::DoSetCheckedChanged(bool aCheckedChanged,
        1437                 :                                         bool aNotify)
        1438                 : {
        1439               0 :   if (mType == NS_FORM_INPUT_RADIO) {
        1440               0 :     if (mCheckedChanged != aCheckedChanged) {
        1441                 :       nsCOMPtr<nsIRadioVisitor> visitor =
        1442               0 :         new nsRadioSetCheckedChangedVisitor(aCheckedChanged);
        1443               0 :       VisitGroup(visitor, aNotify);
        1444                 :     }
        1445                 :   } else {
        1446               0 :     SetCheckedChangedInternal(aCheckedChanged);
        1447                 :   }
        1448               0 : }
        1449                 :
        1450                 : void
        1451               0 : nsHTMLInputElement::SetCheckedChangedInternal(bool aCheckedChanged)
        1452                 : {
        1453               0 :   bool checkedChangedBefore = mCheckedChanged;
        1454                 :
        1455               0 :   mCheckedChanged = aCheckedChanged;
        1456                 :
        1457                 :   // This method can't be called when we are not authorized to notify
        1458                 :   // so we do not need a aNotify parameter.
        1459               0 :   if (checkedChangedBefore != aCheckedChanged) {
        1460               0 :     UpdateState(true);
        1461                 :   }
        1462               0 : }
        1463                 :
        1464                 : NS_IMETHODIMP
        1465               0 : nsHTMLInputElement::SetChecked(bool aChecked)
        1466                 : {
        1467               0 :   return DoSetChecked(aChecked, true, true);
        1468                 : }
        1469                 :
        1470                 : nsresult
        1471               0 : nsHTMLInputElement::DoSetChecked(bool aChecked, bool aNotify,
        1472                 :                                  bool aSetValueChanged)
        1473                 : {
        1474                 :   // If the user or JS attempts to set checked, whether it actually changes the
        1475                 :   // value or not, we say the value was changed so that defaultValue don't
        1476                 :   // affect it no more.
        1477               0 :   if (aSetValueChanged) {
        1478               0 :     DoSetCheckedChanged(true, aNotify);
        1479                 :   }
        1480                 :
        1481                 :   // Don't do anything if we're not changing whether it's checked (it would
        1482                 :   // screw up state actually, especially when you are setting radio button to
        1483                 :   // false)
        1484               0 :   if (mChecked == aChecked) {
        1485               0 :     return NS_OK;
        1486                 :   }
        1487                 :
        1488                 :   // Set checked
        1489               0 :   if (mType != NS_FORM_INPUT_RADIO) {
        1490               0 :     SetCheckedInternal(aChecked, aNotify);
        1491               0 :     return NS_OK;
        1492                 :   }
        1493                 :
        1494                 :   // For radio button, we need to do some extra fun stuff
        1495               0 :   if (aChecked) {
        1496               0 :     return RadioSetChecked(aNotify);
        1497                 :   }
        1498                 :
        1499               0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
        1500               0 :   if (container) {
        1501               0 :     nsAutoString name;
        1502               0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        1503               0 :     container->SetCurrentRadioButton(name, nsnull);
        1504                 :   }
        1505                 :   // SetCheckedInternal is going to ask all radios to update their
        1506                 :   // validity state. We have to be sure the radio group container knows
        1507                 :   // the currently selected radio.
        1508               0 :   SetCheckedInternal(false, aNotify);
        1509               0 :   return NS_OK;
        1510                 : }
        1511                 :
        1512                 : nsresult
        1513               0 : nsHTMLInputElement::RadioSetChecked(bool aNotify)
        1514                 : {
        1515                 :   // Find the selected radio button so we can deselect it
        1516               0 :   nsCOMPtr<nsIDOMHTMLInputElement> currentlySelected = GetSelectedRadioButton();
        1517                 :
        1518                 :   // Deselect the currently selected radio button
        1519               0 :   if (currentlySelected) {
        1520                 :     // Pass true for the aNotify parameter since the currently selected
        1521                 :     // button is already in the document.
        1522               0 :     static_cast<nsHTMLInputElement*>(currentlySelected.get())
        1523               0 :       ->SetCheckedInternal(false, true);
        1524                 :   }
        1525                 :
        1526                 :   // Let the group know that we are now the One True Radio Button
        1527               0 :   nsresult rv = NS_OK;
        1528               0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
        1529               0 :   if (container) {
        1530               0 :     nsAutoString name;
        1531               0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        1532               0 :     rv = container->SetCurrentRadioButton(name, this);
        1533                 :   }
        1534                 :
        1535                 :   // SetCheckedInternal is going to ask all radios to update their
        1536                 :   // validity state. We have to be sure the radio group container knows
        1537                 :   // the currently selected radio.
        1538               0 :   if (NS_SUCCEEDED(rv)) {
        1539               0 :     SetCheckedInternal(true, aNotify);
        1540                 :   }
        1541                 :
        1542               0 :   return rv;
        1543                 : }
        1544                 :
        1545                 : nsIRadioGroupContainer*
        1546               0 : nsHTMLInputElement::GetRadioGroupContainer() const
        1547                 : {
        1548               0 :   NS_ASSERTION(mType == NS_FORM_INPUT_RADIO,
        1549                 :                "GetRadioGroupContainer should only be called when type='radio'");
        1550                 :
        1551               0 :   nsAutoString name;
        1552               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        1553                 :
        1554               0 :   if (name.IsEmpty()) {
        1555               0 :     return nsnull;
        1556                 :   }
        1557                 :
        1558               0 :   if (mForm) {
        1559               0 :     return mForm;
        1560                 :   }
        1561                 :
        1562               0 :   return static_cast<nsDocument*>(GetCurrentDoc());
        1563                 : }
        1564                 :
        1565                 : already_AddRefed<nsIDOMHTMLInputElement>
        1566               0 : nsHTMLInputElement::GetSelectedRadioButton()
        1567                 : {
        1568               0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
        1569               0 :   if (!container) {
        1570               0 :     return nsnull;
        1571                 :   }
        1572                 :
        1573               0 :   nsAutoString name;
        1574               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        1575                 :
        1576               0 :   nsCOMPtr<nsIDOMHTMLInputElement> selected;
        1577               0 :   container->GetCurrentRadioButton(name, getter_AddRefs(selected));
        1578               0 :   return selected.forget();
        1579                 : }
        1580                 :
        1581                 : nsresult
        1582               0 : nsHTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext)
        1583                 : {
        1584               0 :   if (!mForm) {
        1585                 :     // Nothing to do here.
        1586               0 :     return NS_OK;
        1587                 :   }
        1588                 :
        1589               0 :   nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
        1590               0 :   if (!shell) {
        1591               0 :     return NS_OK;
        1592                 :   }
        1593                 :
        1594                 :   // Get the default submit element
        1595               0 :   nsIFormControl* submitControl = mForm->GetDefaultSubmitElement();
        1596               0 :   if (submitControl) {
        1597               0 :     nsCOMPtr<nsIContent> submitContent = do_QueryInterface(submitControl);
        1598               0 :     NS_ASSERTION(submitContent, "Form control not implementing nsIContent?!");
        1599                 :     // Fire the button's onclick handler and let the button handle
        1600                 :     // submitting the form.
        1601               0 :     nsMouseEvent event(true, NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal);
        1602               0 :     nsEventStatus status = nsEventStatus_eIgnore;
        1603               0 :     shell->HandleDOMEventWithTarget(submitContent, &event, &status);
        1604               0 :   } else if (mForm->HasSingleTextControl() &&
        1605               0 :              (mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
        1606               0 :               mForm->CheckValidFormSubmission())) {
        1607                 :     // TODO: removing this code and have the submit event sent by the form,
        1608                 :     // bug 592124.
        1609                 :     // If there's only one text control, just submit the form
        1610                 :     // Hold strong ref across the event
        1611               0 :     nsRefPtr<nsHTMLFormElement> form = mForm;
        1612               0 :     nsFormEvent event(true, NS_FORM_SUBMIT);
        1613               0 :     nsEventStatus status = nsEventStatus_eIgnore;
        1614               0 :     shell->HandleDOMEventWithTarget(mForm, &event, &status);
        1615                 :   }
        1616                 :
        1617               0 :   return NS_OK;
        1618                 : }
        1619                 :
        1620                 : void
        1621               0 : nsHTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify)
        1622                 : {
        1623                 :   // Set the value
        1624               0 :   mChecked = aChecked;
        1625                 :
        1626                 :   // Notify the frame
        1627               0 :   if (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO) {
        1628               0 :     nsIFrame* frame = GetPrimaryFrame();
        1629               0 :     if (frame) {
        1630               0 :       frame->InvalidateFrameSubtree();
        1631                 :     }
        1632                 :   }
        1633                 :
        1634               0 :   UpdateAllValidityStates(aNotify);
        1635                 :
        1636                 :   // Notify the document that the CSS :checked pseudoclass for this element
        1637                 :   // has changed state.
        1638               0 :   UpdateState(aNotify);
        1639               0 : }
        1640                 :
        1641                 : NS_IMETHODIMP
        1642               0 : nsHTMLInputElement::Focus()
        1643                 : {
        1644               0 :   if (mType != NS_FORM_INPUT_FILE) {
        1645               0 :     return nsGenericHTMLElement::Focus();
        1646                 :   }
        1647                 :
        1648                 :   // For file inputs, focus the button instead.
        1649               0 :   nsIFrame* frame = GetPrimaryFrame();
        1650               0 :   if (frame) {
        1651               0 :     for (nsIFrame* childFrame = frame->GetFirstPrincipalChild();
        1652                 :          childFrame;
        1653                 :          childFrame = childFrame->GetNextSibling()) {
        1654                 :       // See if the child is a button control.
        1655                 :       nsCOMPtr<nsIFormControl> formCtrl =
        1656               0 :         do_QueryInterface(childFrame->GetContent());
        1657               0 :       if (formCtrl && formCtrl->GetType() == NS_FORM_INPUT_BUTTON) {
        1658               0 :         nsCOMPtr<nsIDOMElement> element = do_QueryInterface(formCtrl);
        1659               0 :         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
        1660               0 :         if (fm && element) {
        1661               0 :           fm->SetFocus(element, 0);
        1662                 :         }
        1663                 :         break;
        1664                 :       }
        1665                 :     }
        1666                 :   }
        1667                 :
        1668               0 :   return NS_OK;
        1669                 : }
        1670                 :
        1671                 : NS_IMETHODIMP
        1672               0 : nsHTMLInputElement::Select()
        1673                 : {
        1674               0 :   if (!IsSingleLineTextControl(false)) {
        1675               0 :     return NS_OK;
        1676                 :   }
        1677                 :
        1678                 :   // XXX Bug?  We have to give the input focus before contents can be
        1679                 :   // selected
        1680                 :
        1681               0 :   FocusTristate state = FocusState();
        1682               0 :   if (state == eUnfocusable) {
        1683               0 :     return NS_OK;
        1684                 :   }
        1685                 :
        1686               0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
        1687                 :
        1688               0 :   nsRefPtr<nsPresContext> presContext = GetPresContext();
        1689               0 :   if (state == eInactiveWindow) {
        1690               0 :     if (fm)
        1691               0 :       fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
        1692               0 :     SelectAll(presContext);
        1693               0 :     return NS_OK;
        1694                 :   }
        1695                 :
        1696               0 :   if (DispatchSelectEvent(presContext) && fm) {
        1697               0 :     fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
        1698                 :
        1699                 :     // ensure that the element is actually focused
        1700               0 :     nsCOMPtr<nsIDOMElement> focusedElement;
        1701               0 :     fm->GetFocusedElement(getter_AddRefs(focusedElement));
        1702               0 :     if (SameCOMIdentity(static_cast<nsIDOMNode *>(this), focusedElement)) {
        1703                 :       // Now Select all the text!
        1704               0 :       SelectAll(presContext);
        1705                 :     }
        1706                 :   }
        1707                 :
        1708               0 :   return NS_OK;
        1709                 : }
        1710                 :
        1711                 : bool
        1712               0 : nsHTMLInputElement::DispatchSelectEvent(nsPresContext* aPresContext)
        1713                 : {
        1714               0 :   nsEventStatus status = nsEventStatus_eIgnore;
        1715                 :
        1716                 :   // If already handling select event, don't dispatch a second.
        1717               0 :   if (!mHandlingSelectEvent) {
        1718               0 :     nsEvent event(nsContentUtils::IsCallerChrome(), NS_FORM_SELECTED);
        1719                 :
        1720               0 :     mHandlingSelectEvent = true;
        1721                 :     nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
        1722               0 :                                 aPresContext, &event, nsnull, &status);
        1723               0 :     mHandlingSelectEvent = false;
        1724                 :   }
        1725                 :
        1726                 :   // If the DOM event was not canceled (e.g. by a JS event handler
        1727                 :   // returning false)
        1728               0 :   return (status == nsEventStatus_eIgnore);
        1729                 : }
        1730                 :
        1731                 : void
        1732               0 : nsHTMLInputElement::SelectAll(nsPresContext* aPresContext)
        1733                 : {
        1734               0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
        1735                 :
        1736               0 :   if (formControlFrame) {
        1737               0 :     formControlFrame->SetFormProperty(nsGkAtoms::select, EmptyString());
        1738                 :   }
        1739               0 : }
        1740                 :
        1741                 : NS_IMETHODIMP
        1742               0 : nsHTMLInputElement::Click()
        1743                 : {
        1744               0 :   if (mType == NS_FORM_INPUT_FILE)
        1745               0 :     FireAsyncClickHandler();
        1746                 :
        1747               0 :   return nsGenericHTMLElement::Click();
        1748                 : }
        1749                 :
        1750                 : NS_IMETHODIMP
        1751               0 : nsHTMLInputElement::FireAsyncClickHandler()
        1752                 : {
        1753               0 :   nsCOMPtr<nsIRunnable> event = new AsyncClickHandler(this);
        1754               0 :   return NS_DispatchToMainThread(event);
        1755                 : }
        1756                 :
        1757                 : bool
        1758               0 : nsHTMLInputElement::NeedToInitializeEditorForEvent(nsEventChainPreVisitor& aVisitor) const
        1759                 : {
        1760                 :   // We only need to initialize the editor for single line input controls because they
        1761                 :   // are lazily initialized.  We don't need to initialize the control for
        1762                 :   // certain types of events, because we know that those events are safe to be
        1763                 :   // handled without the editor being initialized.  These events include:
        1764                 :   // mousein/move/out, and DOM mutation events.
        1765               0 :   if (!IsSingleLineTextControl(false) ||
        1766                 :       aVisitor.mEvent->eventStructType == NS_MUTATION_EVENT) {
        1767               0 :     return false;
        1768                 :   }
        1769                 :
        1770               0 :   switch (aVisitor.mEvent->message) {
        1771                 :   case NS_MOUSE_MOVE:
        1772                 :   case NS_MOUSE_ENTER:
        1773                 :   case NS_MOUSE_EXIT:
        1774                 :   case NS_MOUSE_ENTER_SYNTH:
        1775                 :   case NS_MOUSE_EXIT_SYNTH:
        1776               0 :     return false;
        1777                 :   default:
        1778               0 :     return true;
        1779                 :   }
        1780                 : }
        1781                 :
        1782                 : nsresult
        1783               0 : nsHTMLInputElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
        1784                 : {
        1785                 :   // Do not process any DOM events if the element is disabled
        1786               0 :   aVisitor.mCanHandle = false;
        1787               0 :   if (IsElementDisabledForEvents(aVisitor.mEvent->message, GetPrimaryFrame())) {
        1788               0 :     return NS_OK;
        1789                 :   }
        1790                 :
        1791                 :   // Initialize the editor if needed.
        1792               0 :   if (NeedToInitializeEditorForEvent(aVisitor)) {
        1793               0 :     nsITextControlFrame* textControlFrame = do_QueryFrame(GetPrimaryFrame());
        1794               0 :     if (textControlFrame)
        1795               0 :       textControlFrame->EnsureEditorInitialized();
        1796                 :   }
        1797                 :
        1798                 :   //FIXME Allow submission etc. also when there is no prescontext, Bug 329509.
        1799               0 :   if (!aVisitor.mPresContext) {
        1800               0 :     return nsGenericHTMLElement::PreHandleEvent(aVisitor);
        1801                 :   }
        1802                 :   //
        1803                 :   // Web pages expect the value of a radio button or checkbox to be set
        1804                 :   // *before* onclick and DOMActivate fire, and they expect that if they set
        1805                 :   // the value explicitly during onclick or DOMActivate it will not be toggled
        1806                 :   // or any such nonsense.
        1807                 :   // In order to support that (bug 57137 and 58460 are examples) we toggle
        1808                 :   // the checked attribute *first*, and then fire onclick.  If the user
        1809                 :   // returns false, we reset the control to the old checked value.  Otherwise,
        1810                 :   // we dispatch DOMActivate.  If DOMActivate is cancelled, we also reset
        1811                 :   // the control to the old checked value.  We need to keep track of whether
        1812                 :   // we've already toggled the state from onclick since the user could
        1813                 :   // explicitly dispatch DOMActivate on the element.
        1814                 :   //
        1815                 :   // This is a compatibility hack.
        1816                 :   //
        1817                 :
        1818                 :   // Track whether we're in the outermost Dispatch invocation that will
        1819                 :   // cause activation of the input.  That is, if we're a click event, or a
        1820                 :   // DOMActivate that was dispatched directly, this will be set, but if we're
        1821                 :   // a DOMActivate dispatched from click handling, it will not be set.
        1822                 :   bool outerActivateEvent =
        1823                 :     (NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent) ||
        1824               0 :      (aVisitor.mEvent->message == NS_UI_ACTIVATE && !mInInternalActivate));
        1825                 :
        1826               0 :   if (outerActivateEvent) {
        1827               0 :     aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
        1828                 :   }
        1829                 :
        1830               0 :   bool originalCheckedValue = false;
        1831                 :
        1832               0 :   if (outerActivateEvent) {
        1833               0 :     mCheckedIsToggled = false;
        1834                 :
        1835               0 :     switch(mType) {
        1836                 :       case NS_FORM_INPUT_CHECKBOX:
        1837                 :         {
        1838               0 :           if (mIndeterminate) {
        1839                 :             // indeterminate is always set to FALSE when the checkbox is toggled
        1840               0 :             SetIndeterminateInternal(false, false);
        1841               0 :             aVisitor.mItemFlags |= NS_ORIGINAL_INDETERMINATE_VALUE;
        1842                 :           }
        1843                 :
        1844               0 :           GetChecked(&originalCheckedValue);
        1845               0 :           DoSetChecked(!originalCheckedValue, true, true);
        1846               0 :           mCheckedIsToggled = true;
        1847                 :         }
        1848               0 :         break;
        1849                 :
        1850                 :       case NS_FORM_INPUT_RADIO:
        1851                 :         {
        1852               0 :           nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton = GetSelectedRadioButton();
        1853               0 :           aVisitor.mItemData = selectedRadioButton;
        1854                 :
        1855               0 :           originalCheckedValue = mChecked;
        1856               0 :           if (!originalCheckedValue) {
        1857               0 :             DoSetChecked(true, true, true);
        1858               0 :             mCheckedIsToggled = true;
        1859                 :           }
        1860                 :         }
        1861               0 :         break;
        1862                 :
        1863                 :       case NS_FORM_INPUT_SUBMIT:
        1864                 :       case NS_FORM_INPUT_IMAGE:
        1865               0 :         if(mForm) {
        1866                 :           // tell the form that we are about to enter a click handler.
        1867                 :           // that means that if there are scripted submissions, the
        1868                 :           // latest one will be deferred until after the exit point of the handler.
        1869               0 :           mForm->OnSubmitClickBegin(this);
        1870                 :         }
        1871               0 :         break;
        1872                 :
        1873                 :       default:
        1874               0 :         break;
        1875                 :     }
        1876                 :   }
        1877                 :
        1878               0 :   if (originalCheckedValue) {
        1879               0 :     aVisitor.mItemFlags |= NS_ORIGINAL_CHECKED_VALUE;
        1880                 :   }
        1881                 :
        1882                 :   // If NS_EVENT_FLAG_NO_CONTENT_DISPATCH is set we will not allow content to handle
        1883                 :   // this event.  But to allow middle mouse button paste to work we must allow
        1884                 :   // middle clicks to go to text fields anyway.
        1885               0 :   if (aVisitor.mEvent->flags & NS_EVENT_FLAG_NO_CONTENT_DISPATCH) {
        1886               0 :     aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH;
        1887                 :   }
        1888               0 :   if (IsSingleLineTextControl(false) &&
        1889                 :       aVisitor.mEvent->message == NS_MOUSE_CLICK &&
        1890                 :       aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT &&
        1891                 :       static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
        1892                 :         nsMouseEvent::eMiddleButton) {
        1893               0 :     aVisitor.mEvent->flags &= ~NS_EVENT_FLAG_NO_CONTENT_DISPATCH;
        1894                 :   }
        1895                 :
        1896                 :   // We must cache type because mType may change during JS event (bug 2369)
        1897               0 :   aVisitor.mItemFlags |= mType;
        1898                 :
        1899                 :   // Fire onchange (if necessary), before we do the blur, bug 357684.
        1900               0 :   if (aVisitor.mEvent->message == NS_BLUR_CONTENT) {
        1901               0 :     nsIFrame* primaryFrame = GetPrimaryFrame();
        1902               0 :     if (primaryFrame) {
        1903               0 :       nsITextControlFrame* textFrame = do_QueryFrame(primaryFrame);
        1904               0 :       if (textFrame) {
        1905               0 :         textFrame->CheckFireOnChange();
        1906                 :       }
        1907                 :     }
        1908                 :   }
        1909                 :
        1910               0 :   return nsGenericHTMLFormElement::PreHandleEvent(aVisitor);
        1911                 : }
        1912                 :
        1913                 : static bool
        1914               0 : SelectTextFieldOnFocus()
        1915                 : {
        1916               0 :   if (!gSelectTextFieldOnFocus) {
        1917               0 :     PRInt32 selectTextfieldsOnKeyFocus = -1;
        1918                 :     nsresult rv =
        1919                 :       LookAndFeel::GetInt(LookAndFeel::eIntID_SelectTextfieldsOnKeyFocus,
        1920               0 :                           &selectTextfieldsOnKeyFocus);
        1921               0 :     if (NS_FAILED(rv)) {
        1922               0 :       gSelectTextFieldOnFocus = -1;
        1923                 :     } else {
        1924               0 :       gSelectTextFieldOnFocus = selectTextfieldsOnKeyFocus != 0 ? 1 : -1;
        1925                 :     }
        1926                 :   }
        1927                 :
        1928               0 :   return gSelectTextFieldOnFocus == 1;
        1929                 : }
        1930                 :
        1931                 : nsresult
        1932               0 : nsHTMLInputElement::PostHandleEvent(nsEventChainPostVisitor& aVisitor)
        1933                 : {
        1934               0 :   if (!aVisitor.mPresContext) {
        1935               0 :     return NS_OK;
        1936                 :   }
        1937                 :
        1938               0 :   if (aVisitor.mEvent->message == NS_FOCUS_CONTENT ||
        1939                 :       aVisitor.mEvent->message == NS_BLUR_CONTENT) {
        1940                 :
        1941               0 :     UpdateValidityUIBits(aVisitor.mEvent->message == NS_FOCUS_CONTENT);
        1942                 :
        1943               0 :     UpdateState(true);
        1944                 :   }
        1945                 :
        1946                 :   // ignore the activate event fired by the "Browse..." button
        1947                 :   // (file input controls fire their own) (bug 500885)
        1948               0 :   if (mType == NS_FORM_INPUT_FILE) {
        1949                 :     nsCOMPtr<nsIContent> maybeButton =
        1950               0 :       do_QueryInterface(aVisitor.mEvent->originalTarget);
        1951               0 :     if (maybeButton &&
        1952               0 :       maybeButton->IsRootOfNativeAnonymousSubtree() &&
        1953               0 :       maybeButton->AttrValueIs(kNameSpaceID_None,
        1954                 :                                nsGkAtoms::type,
        1955                 :                                nsGkAtoms::button,
        1956               0 :                                eCaseMatters)) {
        1957               0 :         return NS_OK;
        1958                 :     }
        1959                 :   }
        1960                 :
        1961               0 :   nsresult rv = NS_OK;
        1962               0 :   bool outerActivateEvent = !!(aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT);
        1963                 :   bool originalCheckedValue =
        1964               0 :     !!(aVisitor.mItemFlags & NS_ORIGINAL_CHECKED_VALUE);
        1965               0 :   bool noContentDispatch = !!(aVisitor.mItemFlags & NS_NO_CONTENT_DISPATCH);
        1966               0 :   PRUint8 oldType = NS_CONTROL_TYPE(aVisitor.mItemFlags);
        1967                 :   // Ideally we would make the default action for click and space just dispatch
        1968                 :   // DOMActivate, and the default action for DOMActivate flip the checkbox/
        1969                 :   // radio state and fire onchange.  However, for backwards compatibility, we
        1970                 :   // need to flip the state before firing click, and we need to fire click
        1971                 :   // when space is pressed.  So, we just nest the firing of DOMActivate inside
        1972                 :   // the click event handling, and allow cancellation of DOMActivate to cancel
        1973                 :   // the click.
        1974               0 :   if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault &&
        1975               0 :       !IsSingleLineTextControl(true) &&
        1976                 :       NS_IS_MOUSE_LEFT_CLICK(aVisitor.mEvent)) {
        1977               0 :     nsUIEvent actEvent(NS_IS_TRUSTED_EVENT(aVisitor.mEvent), NS_UI_ACTIVATE, 1);
        1978                 :
        1979               0 :     nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
        1980               0 :     if (shell) {
        1981               0 :       nsEventStatus status = nsEventStatus_eIgnore;
        1982               0 :       mInInternalActivate = true;
        1983               0 :       rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
        1984               0 :       mInInternalActivate = false;
        1985                 :
        1986                 :       // If activate is cancelled, we must do the same as when click is
        1987                 :       // cancelled (revert the checkbox to its original value).
        1988               0 :       if (status == nsEventStatus_eConsumeNoDefault)
        1989               0 :         aVisitor.mEventStatus = status;
        1990                 :     }
        1991                 :   }
        1992                 :
        1993               0 :   if (outerActivateEvent) {
        1994               0 :     switch(oldType) {
        1995                 :       case NS_FORM_INPUT_SUBMIT:
        1996                 :       case NS_FORM_INPUT_IMAGE:
        1997               0 :         if(mForm) {
        1998                 :           // tell the form that we are about to exit a click handler
        1999                 :           // so the form knows not to defer subsequent submissions
        2000                 :           // the pending ones that were created during the handler
        2001                 :           // will be flushed or forgoten.
        2002               0 :           mForm->OnSubmitClickEnd();
        2003                 :         }
        2004               0 :         break;
        2005                 :     }
        2006                 :   }
        2007                 :
        2008                 :   // Reset the flag for other content besides this text field
        2009                 :   aVisitor.mEvent->flags |=
        2010               0 :     noContentDispatch ? NS_EVENT_FLAG_NO_CONTENT_DISPATCH : NS_EVENT_FLAG_NONE;
        2011                 :
        2012                 :   // now check to see if the event was "cancelled"
        2013               0 :   if (mCheckedIsToggled && outerActivateEvent) {
        2014               0 :     if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
        2015                 :       // if it was cancelled and a radio button, then set the old
        2016                 :       // selected btn to TRUE. if it is a checkbox then set it to its
        2017                 :       // original value
        2018               0 :       if (oldType == NS_FORM_INPUT_RADIO) {
        2019                 :         nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton =
        2020               0 :           do_QueryInterface(aVisitor.mItemData);
        2021               0 :         if (selectedRadioButton) {
        2022               0 :           selectedRadioButton->SetChecked(true);
        2023                 :         }
        2024                 :         // If there was no checked radio button or this one is no longer a
        2025                 :         // radio button we must reset it back to false to cancel the action.
        2026                 :         // See how the web of hack grows?
        2027               0 :         if (!selectedRadioButton || mType != NS_FORM_INPUT_RADIO) {
        2028               0 :           DoSetChecked(false, true, true);
        2029                 :         }
        2030               0 :       } else if (oldType == NS_FORM_INPUT_CHECKBOX) {
        2031                 :         bool originalIndeterminateValue =
        2032               0 :           !!(aVisitor.mItemFlags & NS_ORIGINAL_INDETERMINATE_VALUE);
        2033               0 :         SetIndeterminateInternal(originalIndeterminateValue, false);
        2034               0 :         DoSetChecked(originalCheckedValue, true, true);
        2035                 :       }
        2036                 :     } else {
        2037                 :       nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
        2038                 :                                            static_cast<nsIDOMHTMLInputElement*>(this),
        2039               0 :                                            NS_LITERAL_STRING("change"), true,
        2040               0 :                                            false);
        2041                 : #ifdef ACCESSIBILITY
        2042                 :       // Fire an event to notify accessibility
        2043               0 :       if (mType == NS_FORM_INPUT_CHECKBOX) {
        2044                 :         FireEventForAccessibility(this, aVisitor.mPresContext,
        2045               0 :                                   NS_LITERAL_STRING("CheckboxStateChange"));
        2046                 :       } else {
        2047                 :         FireEventForAccessibility(this, aVisitor.mPresContext,
        2048               0 :                                   NS_LITERAL_STRING("RadioStateChange"));
        2049                 :         // Fire event for the previous selected radio.
        2050                 :         nsCOMPtr<nsIDOMHTMLInputElement> previous =
        2051               0 :           do_QueryInterface(aVisitor.mItemData);
        2052               0 :         if(previous) {
        2053                 :           FireEventForAccessibility(previous, aVisitor.mPresContext,
        2054               0 :                                     NS_LITERAL_STRING("RadioStateChange"));
        2055                 :         }
        2056                 :       }
        2057                 : #endif
        2058                 :     }
        2059                 :   }
        2060                 :
        2061               0 :   if (NS_SUCCEEDED(rv)) {
        2062               0 :     if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
        2063               0 :       switch (aVisitor.mEvent->message) {
        2064                 :
        2065                 :         case NS_FOCUS_CONTENT:
        2066                 :         {
        2067                 :           // see if we should select the contents of the textbox. This happens
        2068                 :           // for text and password fields when the field was focused by the
        2069                 :           // keyboard or a navigation, the platform allows it, and it wasn't
        2070                 :           // just because we raised a window.
        2071               0 :           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
        2072               0 :           if (fm && IsSingleLineTextControl(false) &&
        2073               0 :               !(static_cast<nsFocusEvent *>(aVisitor.mEvent))->fromRaise &&
        2074               0 :               SelectTextFieldOnFocus()) {
        2075               0 :             nsIDocument* document = GetCurrentDoc();
        2076               0 :             if (document) {
        2077                 :               PRUint32 lastFocusMethod;
        2078               0 :               fm->GetLastFocusMethod(document->GetWindow(), &lastFocusMethod);
        2079               0 :               if (lastFocusMethod &
        2080                 :                   (nsIFocusManager::FLAG_BYKEY | nsIFocusManager::FLAG_BYMOVEFOCUS)) {
        2081               0 :                 nsRefPtr<nsPresContext> presContext = GetPresContext();
        2082               0 :                 if (DispatchSelectEvent(presContext)) {
        2083               0 :                   SelectAll(presContext);
        2084                 :                 }
        2085                 :               }
        2086                 :             }
        2087                 :           }
        2088               0 :           break;
        2089                 :         }
        2090                 :
        2091                 :         case NS_KEY_PRESS:
        2092                 :         case NS_KEY_UP:
        2093                 :         {
        2094                 :           // For backwards compat, trigger checks/radios/buttons with
        2095                 :           // space or enter (bug 25300)
        2096               0 :           nsKeyEvent * keyEvent = (nsKeyEvent *)aVisitor.mEvent;
        2097                 :
        2098               0 :           if ((aVisitor.mEvent->message == NS_KEY_PRESS &&
        2099                 :                keyEvent->keyCode == NS_VK_RETURN) ||
        2100                 :               (aVisitor.mEvent->message == NS_KEY_UP &&
        2101                 :                keyEvent->keyCode == NS_VK_SPACE)) {
        2102               0 :             switch(mType) {
        2103                 :               case NS_FORM_INPUT_CHECKBOX:
        2104                 :               case NS_FORM_INPUT_RADIO:
        2105                 :               {
        2106                 :                 // Checkbox and Radio try to submit on Enter press
        2107               0 :                 if (keyEvent->keyCode != NS_VK_SPACE) {
        2108               0 :                   MaybeSubmitForm(aVisitor.mPresContext);
        2109                 :
        2110               0 :                   break;  // If we are submitting, do not send click event
        2111                 :                 }
        2112                 :                 // else fall through and treat Space like click...
        2113                 :               }
        2114                 :               case NS_FORM_INPUT_BUTTON:
        2115                 :               case NS_FORM_INPUT_RESET:
        2116                 :               case NS_FORM_INPUT_SUBMIT:
        2117                 :               case NS_FORM_INPUT_IMAGE: // Bug 34418
        2118                 :               {
        2119                 :                 nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent),
        2120               0 :                                    NS_MOUSE_CLICK, nsnull, nsMouseEvent::eReal);
        2121               0 :                 event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
        2122               0 :                 nsEventStatus status = nsEventStatus_eIgnore;
        2123                 :
        2124                 :                 nsEventDispatcher::Dispatch(static_cast<nsIContent*>(this),
        2125                 :                                             aVisitor.mPresContext, &event,
        2126               0 :                                             nsnull, &status);
        2127               0 :                 aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
        2128                 :               } // case
        2129                 :             } // switch
        2130                 :           }
        2131               0 :           if (aVisitor.mEvent->message == NS_KEY_PRESS &&
        2132               0 :               mType == NS_FORM_INPUT_RADIO && !keyEvent->isAlt &&
        2133               0 :               !keyEvent->isControl && !keyEvent->isMeta) {
        2134               0 :             bool isMovingBack = false;
        2135               0 :             switch (keyEvent->keyCode) {
        2136                 :               case NS_VK_UP:
        2137                 :               case NS_VK_LEFT:
        2138               0 :                 isMovingBack = true;
        2139                 :                 // FALLTHROUGH
        2140                 :               case NS_VK_DOWN:
        2141                 :               case NS_VK_RIGHT:
        2142                 :               // Arrow key pressed, focus+select prev/next radio button
        2143               0 :               nsIRadioGroupContainer* container = GetRadioGroupContainer();
        2144               0 :               if (container) {
        2145               0 :                 nsAutoString name;
        2146               0 :                 GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        2147               0 :                 nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton;
        2148                 :                 container->GetNextRadioButton(name, isMovingBack, this,
        2149               0 :                                               getter_AddRefs(selectedRadioButton));
        2150                 :                 nsCOMPtr<nsIContent> radioContent =
        2151               0 :                   do_QueryInterface(selectedRadioButton);
        2152               0 :                 if (radioContent) {
        2153               0 :                   rv = selectedRadioButton->Focus();
        2154               0 :                   if (NS_SUCCEEDED(rv)) {
        2155               0 :                     nsEventStatus status = nsEventStatus_eIgnore;
        2156                 :                     nsMouseEvent event(NS_IS_TRUSTED_EVENT(aVisitor.mEvent),
        2157                 :                                        NS_MOUSE_CLICK, nsnull,
        2158               0 :                                        nsMouseEvent::eReal);
        2159               0 :                     event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_KEYBOARD;
        2160                 :                     rv = nsEventDispatcher::Dispatch(radioContent,
        2161                 :                                                      aVisitor.mPresContext,
        2162               0 :                                                      &event, nsnull, &status);
        2163               0 :                     if (NS_SUCCEEDED(rv)) {
        2164               0 :                       aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
        2165                 :                     }
        2166                 :                   }
        2167                 :                 }
        2168                 :               }
        2169                 :             }
        2170                 :           }
        2171                 :
        2172                 :           /*
        2173                 :            * For some input types, if the user hits enter, the form is submitted.
        2174                 :            *
        2175                 :            * Bug 99920, bug 109463 and bug 147850:
        2176                 :            * (a) if there is a submit control in the form, click the first
        2177                 :            *     submit control in the form.
        2178                 :            * (b) if there is just one text control in the form, submit by
        2179                 :            *     sending a submit event directly to the form
        2180                 :            * (c) if there is more than one text input and no submit buttons, do
        2181                 :            *     not submit, period.
        2182                 :            */
        2183                 :
        2184               0 :           if (aVisitor.mEvent->message == NS_KEY_PRESS &&
        2185                 :               (keyEvent->keyCode == NS_VK_RETURN ||
        2186                 :                keyEvent->keyCode == NS_VK_ENTER) &&
        2187               0 :                IsSingleLineTextControl(false, mType)) {
        2188               0 :             nsIFrame* primaryFrame = GetPrimaryFrame();
        2189               0 :             if (primaryFrame) {
        2190               0 :               nsITextControlFrame* textFrame = do_QueryFrame(primaryFrame);
        2191                 :
        2192                 :               // Fire onChange (if necessary)
        2193               0 :               if (textFrame) {
        2194               0 :                 textFrame->CheckFireOnChange();
        2195                 :               }
        2196                 :             }
        2197                 :
        2198               0 :             rv = MaybeSubmitForm(aVisitor.mPresContext);
        2199               0 :             NS_ENSURE_SUCCESS(rv, rv);
        2200                 :           }
        2201                 :
        2202               0 :         } break; // NS_KEY_PRESS || NS_KEY_UP
        2203                 :
        2204                 :         case NS_MOUSE_BUTTON_DOWN:
        2205                 :         case NS_MOUSE_BUTTON_UP:
        2206                 :         case NS_MOUSE_DOUBLECLICK:
        2207                 :         {
        2208                 :           // cancel all of these events for buttons
        2209                 :           //XXXsmaug Why?
        2210               0 :           if (aVisitor.mEvent->eventStructType == NS_MOUSE_EVENT &&
        2211                 :               (static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
        2212                 :                  nsMouseEvent::eMiddleButton ||
        2213                 :                static_cast<nsMouseEvent*>(aVisitor.mEvent)->button ==
        2214                 :                  nsMouseEvent::eRightButton)) {
        2215               0 :             if (mType == NS_FORM_INPUT_BUTTON ||
        2216                 :                 mType == NS_FORM_INPUT_RESET ||
        2217                 :                 mType == NS_FORM_INPUT_SUBMIT) {
        2218               0 :               if (aVisitor.mDOMEvent) {
        2219               0 :                 aVisitor.mDOMEvent->StopPropagation();
        2220                 :               } else {
        2221               0 :                 rv = NS_ERROR_FAILURE;
        2222                 :               }
        2223                 :             }
        2224                 :
        2225                 :           }
        2226               0 :           break;
        2227                 :         }
        2228                 :         default:
        2229               0 :           break;
        2230                 :       }
        2231                 :
        2232               0 :       if (outerActivateEvent) {
        2233               0 :         if (mForm && (oldType == NS_FORM_INPUT_SUBMIT ||
        2234                 :                       oldType == NS_FORM_INPUT_IMAGE)) {
        2235               0 :           if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE) {
        2236                 :             // If the type has changed to a non-submit type, then we want to
        2237                 :             // flush the stored submission if there is one (as if the submit()
        2238                 :             // was allowed to succeed)
        2239               0 :             mForm->FlushPendingSubmission();
        2240                 :           }
        2241                 :         }
        2242               0 :         switch(mType) {
        2243                 :         case NS_FORM_INPUT_RESET:
        2244                 :         case NS_FORM_INPUT_SUBMIT:
        2245                 :         case NS_FORM_INPUT_IMAGE:
        2246               0 :           if (mForm) {
        2247                 :             nsFormEvent event(true, (mType == NS_FORM_INPUT_RESET) ?
        2248               0 :                               NS_FORM_RESET : NS_FORM_SUBMIT);
        2249               0 :             event.originator      = this;
        2250               0 :             nsEventStatus status  = nsEventStatus_eIgnore;
        2251                 :
        2252                 :             nsCOMPtr<nsIPresShell> presShell =
        2253               0 :               aVisitor.mPresContext->GetPresShell();
        2254                 :
        2255                 :             // If |nsIPresShell::Destroy| has been called due to
        2256                 :             // handling the event the pres context will return a null
        2257                 :             // pres shell.  See bug 125624.
        2258                 :             // TODO: removing this code and have the submit event sent by the
        2259                 :             // form, see bug 592124.
        2260               0 :             if (presShell && (event.message != NS_FORM_SUBMIT ||
        2261               0 :                               mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate) ||
        2262                 :                               // We know the element is a submit control, if this check is moved,
        2263                 :                               // make sure formnovalidate is used only if it's a submit control.
        2264               0 :                               HasAttr(kNameSpaceID_None, nsGkAtoms::formnovalidate) ||
        2265               0 :                               mForm->CheckValidFormSubmission())) {
        2266                 :               // Hold a strong ref while dispatching
        2267               0 :               nsRefPtr<nsHTMLFormElement> form(mForm);
        2268               0 :               presShell->HandleDOMEventWithTarget(mForm, &event, &status);
        2269               0 :               aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
        2270                 :             }
        2271                 :           }
        2272               0 :           break;
        2273                 :
        2274                 :         default:
        2275               0 :           break;
        2276                 :         } //switch
        2277                 :       } //click or outer activate event
        2278               0 :     } else if (outerActivateEvent &&
        2279                 :                (oldType == NS_FORM_INPUT_SUBMIT ||
        2280                 :                 oldType == NS_FORM_INPUT_IMAGE) &&
        2281                 :                mForm) {
        2282                 :       // tell the form to flush a possible pending submission.
        2283                 :       // the reason is that the script returned false (the event was
        2284                 :       // not ignored) so if there is a stored submission, it needs to
        2285                 :       // be submitted immediately.
        2286               0 :       mForm->FlushPendingSubmission();
        2287                 :     }
        2288                 :   } // if
        2289                 :
        2290               0 :   return rv;
        2291                 : }
        2292                 :
        2293                 : void
        2294               0 : nsHTMLInputElement::MaybeLoadImage()
        2295                 : {
        2296                 :   // Our base URI may have changed; claim that our URI changed, and the
        2297                 :   // nsImageLoadingContent will decide whether a new image load is warranted.
        2298               0 :   nsAutoString uri;
        2299               0 :   if (mType == NS_FORM_INPUT_IMAGE &&
        2300               0 :       GetAttr(kNameSpaceID_None, nsGkAtoms::src, uri) &&
        2301               0 :       (NS_FAILED(LoadImage(uri, false, true)) ||
        2302               0 :        !LoadingEnabled())) {
        2303               0 :     CancelImageRequests(true);
        2304                 :   }
        2305               0 : }
        2306                 :
        2307                 : nsresult
        2308               1 : nsHTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
        2309                 :                                nsIContent* aBindingParent,
        2310                 :                                bool aCompileEventHandlers)
        2311                 : {
        2312                 :   nsresult rv = nsGenericHTMLFormElement::BindToTree(aDocument, aParent,
        2313                 :                                                      aBindingParent,
        2314               1 :                                                      aCompileEventHandlers);
        2315               1 :   NS_ENSURE_SUCCESS(rv, rv);
        2316                 :
        2317               1 :   if (mType == NS_FORM_INPUT_IMAGE) {
        2318                 :     // Our base URI may have changed; claim that our URI changed, and the
        2319                 :     // nsImageLoadingContent will decide whether a new image load is warranted.
        2320               0 :     if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
        2321                 :       // FIXME: Bug 660963 it would be nice if we could just have
        2322                 :       // ClearBrokenState update our state and do it fast...
        2323               0 :       ClearBrokenState();
        2324               0 :       RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
        2325                 :       nsContentUtils::AddScriptRunner(
        2326               0 :         NS_NewRunnableMethod(this, &nsHTMLInputElement::MaybeLoadImage));
        2327                 :     }
        2328                 :   }
        2329                 :
        2330                 :   // Add radio to document if we don't have a form already (if we do it's
        2331                 :   // already been added into that group)
        2332               1 :   if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) {
        2333               0 :     AddedToRadioGroup();
        2334                 :   }
        2335                 :
        2336                 :   // An element can't suffer from value missing if it is not in a document.
        2337                 :   // We have to check if we suffer from that as we are now in a document.
        2338               1 :   UpdateValueMissingValidityState();
        2339                 :
        2340                 :   // If there is a disabled fieldset in the parent chain, the element is now
        2341                 :   // barred from constraint validation and can't suffer from value missing
        2342                 :   // (call done before).
        2343               1 :   UpdateBarredFromConstraintValidation();
        2344                 :
        2345                 :   // And now make sure our state is up to date
        2346               1 :   UpdateState(false);
        2347                 :
        2348               1 :   return rv;
        2349                 : }
        2350                 :
        2351                 : void
        2352               3 : nsHTMLInputElement::UnbindFromTree(bool aDeep, bool aNullParent)
        2353                 : {
        2354                 :   // If we have a form and are unbound from it,
        2355                 :   // nsGenericHTMLFormElement::UnbindFromTree() will unset the form and
        2356                 :   // that takes care of form's WillRemove so we just have to take care
        2357                 :   // of the case where we're removing from the document and we don't
        2358                 :   // have a form
        2359               3 :   if (!mForm && mType == NS_FORM_INPUT_RADIO) {
        2360               0 :     WillRemoveFromRadioGroup();
        2361                 :   }
        2362                 :
        2363               3 :   nsGenericHTMLFormElement::UnbindFromTree(aDeep, aNullParent);
        2364                 :
        2365                 :   // GetCurrentDoc is returning nsnull so we can update the value
        2366                 :   // missing validity state to reflect we are no longer into a doc.
        2367               3 :   UpdateValueMissingValidityState();
        2368                 :   // We might be no longer disabled because of parent chain changed.
        2369               3 :   UpdateBarredFromConstraintValidation();
        2370                 :
        2371                 :   // And now make sure our state is up to date
        2372               3 :   UpdateState(false);
        2373               3 : }
        2374                 :
        2375                 : void
        2376               0 : nsHTMLInputElement::HandleTypeChange(PRUint8 aNewType)
        2377                 : {
        2378               0 :   ValueModeType aOldValueMode = GetValueMode();
        2379               0 :   nsAutoString aOldValue;
        2380                 :
        2381               0 :   if (aOldValueMode == VALUE_MODE_VALUE && !mParserCreating) {
        2382               0 :     GetValue(aOldValue);
        2383                 :   }
        2384                 :
        2385                 :   // Only single line text inputs have a text editor state.
        2386               0 :   bool isNewTypeSingleLine = IsSingleLineTextControl(false, aNewType);
        2387               0 :   bool isCurrentTypeSingleLine = IsSingleLineTextControl(false, mType);
        2388                 :
        2389               0 :   if (isNewTypeSingleLine && !isCurrentTypeSingleLine) {
        2390               0 :     FreeData();
        2391               0 :     mInputData.mState = new nsTextEditorState(this);
        2392               0 :     NS_ADDREF(mInputData.mState);
        2393               0 :   } else if (isCurrentTypeSingleLine && !isNewTypeSingleLine) {
        2394               0 :     FreeData();
        2395                 :   }
        2396                 :
        2397               0 :   mType = aNewType;
        2398                 :
        2399               0 :   if (!mParserCreating) {
        2400                 :     /**
        2401                 :      * The following code is trying to reproduce the algorithm described here:
        2402                 :      * http://www.whatwg.org/specs/web-apps/current-work/complete.html#input-type-change
        2403                 :      */
        2404               0 :     switch (GetValueMode()) {
        2405                 :       case VALUE_MODE_DEFAULT:
        2406                 :       case VALUE_MODE_DEFAULT_ON:
        2407                 :         // If the previous value mode was value, we need to set the value content
        2408                 :         // attribute to the previous value.
        2409                 :         // There is no value sanitizing algorithm for elements in this mode.
        2410               0 :         if (aOldValueMode == VALUE_MODE_VALUE && !aOldValue.IsEmpty()) {
        2411               0 :           SetAttr(kNameSpaceID_None, nsGkAtoms::value, aOldValue, true);
        2412                 :         }
        2413               0 :         break;
        2414                 :       case VALUE_MODE_VALUE:
        2415                 :         // If the previous value mode wasn't value, we have to set the value to
        2416                 :         // the value content attribute.
        2417                 :         // SetValueInternal is going to sanitize the value.
        2418                 :         {
        2419               0 :           nsAutoString value;
        2420               0 :           if (aOldValueMode != VALUE_MODE_VALUE) {
        2421               0 :             GetAttr(kNameSpaceID_None, nsGkAtoms::value, value);
        2422                 :           } else {
        2423                 :             // We get the current value so we can sanitize it.
        2424               0 :             GetValue(value);
        2425                 :           }
        2426               0 :           SetValueInternal(value, false, false);
        2427                 :         }
        2428               0 :         break;
        2429                 :       case VALUE_MODE_FILENAME:
        2430                 :       default:
        2431                 :         // We don't care about the value.
        2432                 :         // There is no value sanitizing algorithm for elements in this mode.
        2433               0 :         break;
        2434                 :     }
        2435                 :   }
        2436                 :
        2437                 :   // Do not notify, it will be done after if needed.
        2438               0 :   UpdateAllValidityStates(false);
        2439               0 : }
        2440                 :
        2441                 : void
        2442               2 : nsHTMLInputElement::SanitizeValue(nsAString& aValue)
        2443                 : {
        2444               2 :   NS_ASSERTION(!mParserCreating, "The element parsing should be finished!");
        2445                 :
        2446               2 :   switch (mType) {
        2447                 :     case NS_FORM_INPUT_TEXT:
        2448                 :     case NS_FORM_INPUT_SEARCH:
        2449                 :     case NS_FORM_INPUT_TEL:
        2450                 :     case NS_FORM_INPUT_PASSWORD:
        2451                 :       {
        2452               2 :         PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
        2453               2 :         aValue.StripChars(crlf);
        2454                 :       }
        2455               2 :       break;
        2456                 :     case NS_FORM_INPUT_EMAIL:
        2457                 :     case NS_FORM_INPUT_URL:
        2458                 :       {
        2459               0 :         PRUnichar crlf[] = { PRUnichar('\r'), PRUnichar('\n'), 0 };
        2460               0 :         aValue.StripChars(crlf);
        2461                 :
        2462               0 :         aValue = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aValue);
        2463                 :       }
        2464               0 :       break;
        2465                 :   }
        2466               2 : }
        2467                 :
        2468                 : bool
        2469               0 : nsHTMLInputElement::ParseAttribute(PRInt32 aNamespaceID,
        2470                 :                                    nsIAtom* aAttribute,
        2471                 :                                    const nsAString& aValue,
        2472                 :                                    nsAttrValue& aResult)
        2473                 : {
        2474               0 :   if (aNamespaceID == kNameSpaceID_None) {
        2475               0 :     if (aAttribute == nsGkAtoms::type) {
        2476                 :       // XXX ARG!! This is major evilness. ParseAttribute
        2477                 :       // shouldn't set members. Override SetAttr instead
        2478                 :       PRInt32 newType;
        2479               0 :       bool success = aResult.ParseEnumValue(aValue, kInputTypeTable, false);
        2480               0 :       if (success) {
        2481               0 :         newType = aResult.GetEnumValue();
        2482                 :       } else {
        2483               0 :         newType = kInputDefaultType->value;
        2484                 :       }
        2485                 :
        2486               0 :       if (newType != mType) {
        2487                 :         // Make sure to do the check for newType being NS_FORM_INPUT_FILE and
        2488                 :         // the corresponding SetValueInternal() call _before_ we set mType.
        2489                 :         // That way the logic in SetValueInternal() will work right (that logic
        2490                 :         // makes assumptions about our frame based on mType, but we won't have
        2491                 :         // had time to recreate frames yet -- that happens later in the
        2492                 :         // SetAttr() process).
        2493               0 :         if (newType == NS_FORM_INPUT_FILE || mType == NS_FORM_INPUT_FILE) {
        2494                 :           // This call isn't strictly needed any more since we'll never
        2495                 :           // confuse values and filenames. However it's there for backwards
        2496                 :           // compat.
        2497               0 :           ClearFiles(false);
        2498                 :         }
        2499                 :
        2500               0 :         HandleTypeChange(newType);
        2501                 :       }
        2502                 :
        2503               0 :       return success;
        2504                 :     }
        2505               0 :     if (aAttribute == nsGkAtoms::width) {
        2506               0 :       return aResult.ParseSpecialIntValue(aValue);
        2507                 :     }
        2508               0 :     if (aAttribute == nsGkAtoms::height) {
        2509               0 :       return aResult.ParseSpecialIntValue(aValue);
        2510                 :     }
        2511               0 :     if (aAttribute == nsGkAtoms::maxlength) {
        2512               0 :       return aResult.ParseNonNegativeIntValue(aValue);
        2513                 :     }
        2514               0 :     if (aAttribute == nsGkAtoms::size) {
        2515               0 :       return aResult.ParsePositiveIntValue(aValue);
        2516                 :     }
        2517               0 :     if (aAttribute == nsGkAtoms::border) {
        2518               0 :       return aResult.ParseIntWithBounds(aValue, 0);
        2519                 :     }
        2520               0 :     if (aAttribute == nsGkAtoms::align) {
        2521               0 :       return ParseAlignValue(aValue, aResult);
        2522                 :     }
        2523               0 :     if (aAttribute == nsGkAtoms::formmethod) {
        2524               0 :       return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
        2525                 :     }
        2526               0 :     if (aAttribute == nsGkAtoms::formenctype) {
        2527               0 :       return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
        2528                 :     }
        2529               0 :     if (aAttribute == nsGkAtoms::autocomplete) {
        2530               0 :       return aResult.ParseEnumValue(aValue, kInputAutocompleteTable, false);
        2531                 :     }
        2532               0 :     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
        2533                 :       // We have to call |ParseImageAttribute| unconditionally since we
        2534                 :       // don't know if we're going to have a type="image" attribute yet,
        2535                 :       // (or could have it set dynamically in the future).  See bug
        2536                 :       // 214077.
        2537               0 :       return true;
        2538                 :     }
        2539                 :   }
        2540                 :
        2541                 :   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
        2542               0 :                                               aResult);
        2543                 : }
        2544                 :
        2545                 : static void
        2546               0 : MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
        2547                 :                       nsRuleData* aData)
        2548                 : {
        2549               0 :   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
        2550               0 :   if (value && value->Type() == nsAttrValue::eEnum &&
        2551               0 :       value->GetEnumValue() == NS_FORM_INPUT_IMAGE) {
        2552               0 :     nsGenericHTMLFormElement::MapImageBorderAttributeInto(aAttributes, aData);
        2553               0 :     nsGenericHTMLFormElement::MapImageMarginAttributeInto(aAttributes, aData);
        2554               0 :     nsGenericHTMLFormElement::MapImageSizeAttributesInto(aAttributes, aData);
        2555                 :     // Images treat align as "float"
        2556               0 :     nsGenericHTMLFormElement::MapImageAlignAttributeInto(aAttributes, aData);
        2557                 :   }
        2558                 :
        2559               0 :   nsGenericHTMLFormElement::MapCommonAttributesInto(aAttributes, aData);
        2560               0 : }
        2561                 :
        2562                 : nsChangeHint
        2563               0 : nsHTMLInputElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
        2564                 :                                            PRInt32 aModType) const
        2565                 : {
        2566                 :   nsChangeHint retval =
        2567               0 :     nsGenericHTMLFormElement::GetAttributeChangeHint(aAttribute, aModType);
        2568               0 :   if (aAttribute == nsGkAtoms::type) {
        2569               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
        2570               0 :   } else if (mType == NS_FORM_INPUT_IMAGE &&
        2571                 :              (aAttribute == nsGkAtoms::alt ||
        2572                 :               aAttribute == nsGkAtoms::value)) {
        2573                 :     // We might need to rebuild our alt text.  Just go ahead and
        2574                 :     // reconstruct our frame.  This should be quite rare..
        2575               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
        2576               0 :   } else if (aAttribute == nsGkAtoms::value) {
        2577               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
        2578               0 :   } else if (aAttribute == nsGkAtoms::size &&
        2579               0 :              IsSingleLineTextControl(false)) {
        2580               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_REFLOW);
        2581               0 :   } else if (PlaceholderApplies() && aAttribute == nsGkAtoms::placeholder) {
        2582               0 :     NS_UpdateHint(retval, NS_STYLE_HINT_FRAMECHANGE);
        2583                 :   }
        2584               0 :   return retval;
        2585                 : }
        2586                 :
        2587                 : NS_IMETHODIMP_(bool)
        2588               0 : nsHTMLInputElement::IsAttributeMapped(const nsIAtom* aAttribute) const
        2589                 : {
        2590                 :   static const MappedAttributeEntry attributes[] = {
        2591                 :     { &nsGkAtoms::align },
        2592                 :     { &nsGkAtoms::type },
        2593                 :     { nsnull },
        2594                 :   };
        2595                 :
        2596                 :   static const MappedAttributeEntry* const map[] = {
        2597                 :     attributes,
        2598                 :     sCommonAttributeMap,
        2599                 :     sImageMarginSizeAttributeMap,
        2600                 :     sImageBorderAttributeMap,
        2601                 :   };
        2602                 :
        2603               0 :   return FindAttributeDependence(aAttribute, map);
        2604                 : }
        2605                 :
        2606                 : nsMapRuleToAttributesFunc
        2607               0 : nsHTMLInputElement::GetAttributeMappingFunction() const
        2608                 : {
        2609               0 :   return &MapAttributesIntoRule;
        2610                 : }
        2611                 :
        2612                 :
        2613                 : // Controllers Methods
        2614                 :
        2615                 : NS_IMETHODIMP
        2616               0 : nsHTMLInputElement::GetControllers(nsIControllers** aResult)
        2617                 : {
        2618               0 :   NS_ENSURE_ARG_POINTER(aResult);
        2619                 :
        2620                 :   //XXX: what about type "file"?
        2621               0 :   if (IsSingleLineTextControl(false))
        2622                 :   {
        2623               0 :     if (!mControllers)
        2624                 :     {
        2625                 :       nsresult rv;
        2626               0 :       mControllers = do_CreateInstance(kXULControllersCID, &rv);
        2627               0 :       NS_ENSURE_SUCCESS(rv, rv);
        2628                 :
        2629                 :       nsCOMPtr<nsIController>
        2630                 :         controller(do_CreateInstance("@mozilla.org/editor/editorcontroller;1",
        2631               0 :                                      &rv));
        2632               0 :       NS_ENSURE_SUCCESS(rv, rv);
        2633                 :
        2634               0 :       mControllers->AppendController(controller);
        2635                 :
        2636                 :       controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1",
        2637               0 :                                      &rv);
        2638               0 :       NS_ENSURE_SUCCESS(rv, rv);
        2639                 :
        2640               0 :       mControllers->AppendController(controller);
        2641                 :     }
        2642                 :   }
        2643                 :
        2644               0 :   *aResult = mControllers;
        2645               0 :   NS_IF_ADDREF(*aResult);
        2646                 :
        2647               0 :   return NS_OK;
        2648                 : }
        2649                 :
        2650                 : NS_IMETHODIMP
        2651               0 : nsHTMLInputElement::GetTextLength(PRInt32* aTextLength)
        2652                 : {
        2653               0 :   nsAutoString val;
        2654                 :
        2655               0 :   nsresult rv = GetValue(val);
        2656                 :
        2657               0 :   *aTextLength = val.Length();
        2658                 :
        2659               0 :   return rv;
        2660                 : }
        2661                 :
        2662                 : NS_IMETHODIMP
        2663               0 : nsHTMLInputElement::SetSelectionRange(PRInt32 aSelectionStart,
        2664                 :                                       PRInt32 aSelectionEnd,
        2665                 :                                       const nsAString& aDirection)
        2666                 : {
        2667               0 :   nsresult rv = NS_ERROR_FAILURE;
        2668               0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
        2669                 :
        2670               0 :   if (formControlFrame) {
        2671               0 :     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
        2672               0 :     if (textControlFrame) {
        2673                 :       // Default to forward, even if not specified.
        2674                 :       // Note that we don't currently support directionless selections, so
        2675                 :       // "none" is treated like "forward".
        2676               0 :       nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eForward;
        2677               0 :       if (aDirection.EqualsLiteral("backward")) {
        2678               0 :         dir = nsITextControlFrame::eBackward;
        2679                 :       }
        2680                 :
        2681               0 :       rv = textControlFrame->SetSelectionRange(aSelectionStart, aSelectionEnd, dir);
        2682               0 :       if (NS_SUCCEEDED(rv)) {
        2683               0 :         rv = textControlFrame->ScrollSelectionIntoView();
        2684                 :       }
        2685                 :     }
        2686                 :   }
        2687                 :
        2688               0 :   return rv;
        2689                 : }
        2690                 :
        2691                 : NS_IMETHODIMP
        2692               0 : nsHTMLInputElement::GetSelectionStart(PRInt32* aSelectionStart)
        2693                 : {
        2694               0 :   NS_ENSURE_ARG_POINTER(aSelectionStart);
        2695                 :
        2696                 :   PRInt32 selEnd;
        2697               0 :   nsresult rv = GetSelectionRange(aSelectionStart, &selEnd);
        2698                 :
        2699               0 :   if (NS_FAILED(rv)) {
        2700               0 :     nsTextEditorState *state = GetEditorState();
        2701               0 :     if (state && state->IsSelectionCached()) {
        2702               0 :       *aSelectionStart = state->GetSelectionProperties().mStart;
        2703               0 :       return NS_OK;
        2704                 :     }
        2705                 :   }
        2706               0 :   return rv;
        2707                 : }
        2708                 :
        2709                 : NS_IMETHODIMP
        2710               0 : nsHTMLInputElement::SetSelectionStart(PRInt32 aSelectionStart)
        2711                 : {
        2712               0 :   nsTextEditorState *state = GetEditorState();
        2713               0 :   if (state && state->IsSelectionCached()) {
        2714               0 :     state->GetSelectionProperties().mStart = aSelectionStart;
        2715               0 :     return NS_OK;
        2716                 :   }
        2717                 :
        2718               0 :   nsAutoString direction;
        2719               0 :   nsresult rv = GetSelectionDirection(direction);
        2720               0 :   NS_ENSURE_SUCCESS(rv, rv);
        2721                 :   PRInt32 start, end;
        2722               0 :   rv = GetSelectionRange(&start, &end);
        2723               0 :   NS_ENSURE_SUCCESS(rv, rv);
        2724               0 :   start = aSelectionStart;
        2725               0 :   if (end < start) {
        2726               0 :     end = start;
        2727                 :   }
        2728               0 :   return SetSelectionRange(start, end, direction);
        2729                 : }
        2730                 :
        2731                 : NS_IMETHODIMP
        2732               0 : nsHTMLInputElement::GetSelectionEnd(PRInt32* aSelectionEnd)
        2733                 : {
        2734               0 :   NS_ENSURE_ARG_POINTER(aSelectionEnd);
        2735                 :
        2736                 :   PRInt32 selStart;
        2737               0 :   nsresult rv = GetSelectionRange(&selStart, aSelectionEnd);
        2738                 :
        2739               0 :   if (NS_FAILED(rv)) {
        2740               0 :     nsTextEditorState *state = GetEditorState();
        2741               0 :     if (state && state->IsSelectionCached()) {
        2742               0 :       *aSelectionEnd = state->GetSelectionProperties().mEnd;
        2743               0 :       return NS_OK;
        2744                 :     }
        2745                 :   }
        2746               0 :   return rv;
        2747                 : }
        2748                 :
        2749                 :
        2750                 : NS_IMETHODIMP
        2751               0 : nsHTMLInputElement::SetSelectionEnd(PRInt32 aSelectionEnd)
        2752                 : {
        2753               0 :   nsTextEditorState *state = GetEditorState();
        2754               0 :   if (state && state->IsSelectionCached()) {
        2755               0 :     state->GetSelectionProperties().mEnd = aSelectionEnd;
        2756               0 :     return NS_OK;
        2757                 :   }
        2758                 :
        2759               0 :   nsAutoString direction;
        2760               0 :   nsresult rv = GetSelectionDirection(direction);
        2761               0 :   NS_ENSURE_SUCCESS(rv, rv);
        2762                 :   PRInt32 start, end;
        2763               0 :   rv = GetSelectionRange(&start, &end);
        2764               0 :   NS_ENSURE_SUCCESS(rv, rv);
        2765               0 :   end = aSelectionEnd;
        2766               0 :   if (start > end) {
        2767               0 :     start = end;
        2768                 :   }
        2769               0 :   return SetSelectionRange(start, end, direction);
        2770                 : }
        2771                 :
        2772                 : NS_IMETHODIMP
        2773               0 : nsHTMLInputElement::GetFiles(nsIDOMFileList** aFileList)
        2774                 : {
        2775               0 :   *aFileList = nsnull;
        2776                 :
        2777               0 :   if (mType != NS_FORM_INPUT_FILE) {
        2778               0 :     return NS_OK;
        2779                 :   }
        2780                 :
        2781               0 :   if (!mFileList) {
        2782               0 :     mFileList = new nsDOMFileList(static_cast<nsIContent*>(this));
        2783               0 :     if (!mFileList) return NS_ERROR_OUT_OF_MEMORY;
        2784                 :
        2785               0 :     UpdateFileList();
        2786                 :   }
        2787                 :
        2788               0 :   NS_ADDREF(*aFileList = mFileList);
        2789                 :
        2790               0 :   return NS_OK;
        2791                 : }
        2792                 :
        2793                 : nsresult
        2794               0 : nsHTMLInputElement::GetSelectionRange(PRInt32* aSelectionStart,
        2795                 :                                       PRInt32* aSelectionEnd)
        2796                 : {
        2797               0 :   nsresult rv = NS_ERROR_FAILURE;
        2798               0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
        2799                 :
        2800               0 :   if (formControlFrame) {
        2801               0 :     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
        2802               0 :     if (textControlFrame)
        2803               0 :       rv = textControlFrame->GetSelectionRange(aSelectionStart, aSelectionEnd);
        2804                 :   }
        2805                 :
        2806               0 :   return rv;
        2807                 : }
        2808                 :
        2809                 : static void
        2810               0 : DirectionToName(nsITextControlFrame::SelectionDirection dir, nsAString& aDirection)
        2811                 : {
        2812               0 :   if (dir == nsITextControlFrame::eNone) {
        2813               0 :     aDirection.AssignLiteral("none");
        2814               0 :   } else if (dir == nsITextControlFrame::eForward) {
        2815               0 :     aDirection.AssignLiteral("forward");
        2816               0 :   } else if (dir == nsITextControlFrame::eBackward) {
        2817               0 :     aDirection.AssignLiteral("backward");
        2818                 :   } else {
        2819               0 :     NS_NOTREACHED("Invalid SelectionDirection value");
        2820                 :   }
        2821               0 : }
        2822                 :
        2823                 : NS_IMETHODIMP
        2824               0 : nsHTMLInputElement::GetSelectionDirection(nsAString& aDirection)
        2825                 : {
        2826               0 :   nsresult rv = NS_ERROR_FAILURE;
        2827               0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
        2828                 :
        2829               0 :   if (formControlFrame) {
        2830               0 :     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
        2831               0 :     if (textControlFrame) {
        2832                 :       nsITextControlFrame::SelectionDirection dir;
        2833               0 :       rv = textControlFrame->GetSelectionRange(nsnull, nsnull, &dir);
        2834               0 :       if (NS_SUCCEEDED(rv)) {
        2835               0 :         DirectionToName(dir, aDirection);
        2836                 :       }
        2837                 :     }
        2838                 :   }
        2839                 :
        2840               0 :   if (NS_FAILED(rv)) {
        2841               0 :     nsTextEditorState *state = GetEditorState();
        2842               0 :     if (state && state->IsSelectionCached()) {
        2843               0 :       DirectionToName(state->GetSelectionProperties().mDirection, aDirection);
        2844               0 :       return NS_OK;
        2845                 :     }
        2846                 :   }
        2847                 :
        2848               0 :   return rv;
        2849                 : }
        2850                 :
        2851                 : NS_IMETHODIMP
        2852               0 : nsHTMLInputElement::SetSelectionDirection(const nsAString& aDirection) {
        2853               0 :   nsTextEditorState *state = GetEditorState();
        2854               0 :   if (state && state->IsSelectionCached()) {
        2855               0 :     nsITextControlFrame::SelectionDirection dir = nsITextControlFrame::eNone;
        2856               0 :     if (aDirection.EqualsLiteral("forward")) {
        2857               0 :       dir = nsITextControlFrame::eForward;
        2858               0 :     } else if (aDirection.EqualsLiteral("backward")) {
        2859               0 :       dir = nsITextControlFrame::eBackward;
        2860                 :     }
        2861               0 :     state->GetSelectionProperties().mDirection = dir;
        2862               0 :     return NS_OK;
        2863                 :   }
        2864                 :
        2865                 :   PRInt32 start, end;
        2866               0 :   nsresult rv = GetSelectionRange(&start, &end);
        2867               0 :   if (NS_SUCCEEDED(rv)) {
        2868               0 :     rv = SetSelectionRange(start, end, aDirection);
        2869                 :   }
        2870                 :
        2871               0 :   return rv;
        2872                 : }
        2873                 :
        2874                 : NS_IMETHODIMP
        2875               0 : nsHTMLInputElement::GetPhonetic(nsAString& aPhonetic)
        2876                 : {
        2877               0 :   aPhonetic.Truncate();
        2878               0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
        2879                 :
        2880               0 :   if (formControlFrame) {
        2881               0 :     nsITextControlFrame* textControlFrame = do_QueryFrame(formControlFrame);
        2882               0 :     if (textControlFrame)
        2883               0 :       textControlFrame->GetPhonetic(aPhonetic);
        2884                 :   }
        2885                 :
        2886               0 :   return NS_OK;
        2887                 : }
        2888                 :
        2889                 : #ifdef ACCESSIBILITY
        2890                 : /*static*/ nsresult
        2891               0 : FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
        2892                 :                           nsPresContext* aPresContext,
        2893                 :                           const nsAString& aEventType)
        2894                 : {
        2895               0 :   nsCOMPtr<nsIDOMEvent> event;
        2896               0 :   if (NS_SUCCEEDED(nsEventDispatcher::CreateEvent(aPresContext, nsnull,
        2897                 :                                                   NS_LITERAL_STRING("Events"),
        2898                 :                                                   getter_AddRefs(event)))) {
        2899               0 :     event->InitEvent(aEventType, true, true);
        2900                 :
        2901               0 :     nsCOMPtr<nsIPrivateDOMEvent> privateEvent(do_QueryInterface(event));
        2902               0 :     if (privateEvent) {
        2903               0 :       privateEvent->SetTrusted(true);
        2904                 :     }
        2905                 :
        2906               0 :     nsEventDispatcher::DispatchDOMEvent(aTarget, nsnull, event, aPresContext, nsnull);
        2907                 :   }
        2908                 :
        2909               0 :   return NS_OK;
        2910                 : }
        2911                 : #endif
        2912                 :
        2913                 : nsresult
        2914               0 : nsHTMLInputElement::SetDefaultValueAsValue()
        2915                 : {
        2916               0 :   NS_ASSERTION(GetValueMode() == VALUE_MODE_VALUE,
        2917                 :                "GetValueMode() should return VALUE_MODE_VALUE!");
        2918                 :
        2919                 :   // The element has a content attribute value different from it's value when
        2920                 :   // it's in the value mode value.
        2921               0 :   nsAutoString resetVal;
        2922               0 :   GetDefaultValue(resetVal);
        2923                 :
        2924                 :   // SetValueInternal is going to sanitize the value.
        2925               0 :   return SetValueInternal(resetVal, false, false);
        2926                 : }
        2927                 :
        2928                 : NS_IMETHODIMP
        2929               0 : nsHTMLInputElement::Reset()
        2930                 : {
        2931                 :   // We should be able to reset all dirty flags regardless of the type.
        2932               0 :   SetCheckedChanged(false);
        2933               0 :   SetValueChanged(false);
        2934                 :
        2935               0 :   switch (GetValueMode()) {
        2936                 :     case VALUE_MODE_VALUE:
        2937               0 :       return SetDefaultValueAsValue();
        2938                 :     case VALUE_MODE_DEFAULT_ON:
        2939               0 :       return DoSetChecked(DefaultChecked(), true, false);
        2940                 :     case VALUE_MODE_FILENAME:
        2941               0 :       ClearFiles(false);
        2942               0 :       return NS_OK;
        2943                 :     case VALUE_MODE_DEFAULT:
        2944                 :     default:
        2945               0 :       return NS_OK;
        2946                 :   }
        2947                 : }
        2948                 :
        2949                 : NS_IMETHODIMP
        2950               0 : nsHTMLInputElement::SubmitNamesValues(nsFormSubmission* aFormSubmission)
        2951                 : {
        2952                 :   // Disabled elements don't submit
        2953                 :   // For type=reset, and type=button, we just never submit, period.
        2954                 :   // For type=image and type=button, we only submit if we were the button
        2955                 :   // pressed
        2956                 :   // For type=radio and type=checkbox, we only submit if checked=true
        2957               0 :   if (IsDisabled() || mType == NS_FORM_INPUT_RESET ||
        2958                 :       mType == NS_FORM_INPUT_BUTTON ||
        2959                 :       ((mType == NS_FORM_INPUT_SUBMIT || mType == NS_FORM_INPUT_IMAGE) &&
        2960               0 :        aFormSubmission->GetOriginatingElement() != this) ||
        2961                 :       ((mType == NS_FORM_INPUT_RADIO || mType == NS_FORM_INPUT_CHECKBOX) &&
        2962               0 :        !mChecked)) {
        2963               0 :     return NS_OK;
        2964                 :   }
        2965                 :
        2966                 :   // Get the name
        2967               0 :   nsAutoString name;
        2968               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        2969                 :
        2970                 :   // Submit .x, .y for input type=image
        2971               0 :   if (mType == NS_FORM_INPUT_IMAGE) {
        2972                 :     // Get a property set by the frame to find out where it was clicked.
        2973                 :     nsIntPoint* lastClickedPoint =
        2974               0 :       static_cast<nsIntPoint*>(GetProperty(nsGkAtoms::imageClickedPoint));
        2975                 :     PRInt32 x, y;
        2976               0 :     if (lastClickedPoint) {
        2977                 :       // Convert the values to strings for submission
        2978               0 :       x = lastClickedPoint->x;
        2979               0 :       y = lastClickedPoint->y;
        2980                 :     } else {
        2981               0 :       x = y = 0;
        2982                 :     }
        2983                 :
        2984               0 :     nsAutoString xVal, yVal;
        2985               0 :     xVal.AppendInt(x);
        2986               0 :     yVal.AppendInt(y);
        2987                 :
        2988               0 :     if (!name.IsEmpty()) {
        2989               0 :       aFormSubmission->AddNameValuePair(name + NS_LITERAL_STRING(".x"), xVal);
        2990               0 :       aFormSubmission->AddNameValuePair(name + NS_LITERAL_STRING(".y"), yVal);
        2991                 :     } else {
        2992                 :       // If the Image Element has no name, simply return x and y
        2993                 :       // to Nav and IE compatibility.
        2994               0 :       aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("x"), xVal);
        2995               0 :       aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("y"), yVal);
        2996                 :     }
        2997                 :
        2998               0 :     return NS_OK;
        2999                 :   }
        3000                 :
        3001                 :   //
        3002                 :   // Submit name=value
        3003                 :   //
        3004                 :
        3005                 :   // If name not there, don't submit
        3006               0 :   if (name.IsEmpty()) {
        3007               0 :     return NS_OK;
        3008                 :   }
        3009                 :
        3010                 :   // Get the value
        3011               0 :   nsAutoString value;
        3012               0 :   nsresult rv = GetValue(value);
        3013               0 :   if (NS_FAILED(rv)) {
        3014               0 :     return rv;
        3015                 :   }
        3016                 :
        3017               0 :   if (mType == NS_FORM_INPUT_SUBMIT && value.IsEmpty() &&
        3018               0 :       !HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
        3019                 :     // Get our default value, which is the same as our default label
        3020               0 :     nsXPIDLString defaultValue;
        3021                 :     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
        3022               0 :                                        "Submit", defaultValue);
        3023               0 :     value = defaultValue;
        3024                 :   }
        3025                 :
        3026                 :   //
        3027                 :   // Submit file if its input type=file and this encoding method accepts files
        3028                 :   //
        3029               0 :   if (mType == NS_FORM_INPUT_FILE) {
        3030                 :     // Submit files
        3031                 :
        3032               0 :     const nsCOMArray<nsIDOMFile>& files = GetFiles();
        3033                 :
        3034               0 :     for (PRInt32 i = 0; i < files.Count(); ++i) {
        3035               0 :       aFormSubmission->AddNameFilePair(name, files[i]);
        3036                 :     }
        3037                 :
        3038               0 :     if (files.Count() == 0) {
        3039                 :       // If no file was selected, pretend we had an empty file with an
        3040                 :       // empty filename.
        3041               0 :       aFormSubmission->AddNameFilePair(name, nsnull);
        3042                 :
        3043                 :     }
        3044                 :
        3045               0 :     return NS_OK;
        3046                 :   }
        3047                 :
        3048               0 :   if (mType == NS_FORM_INPUT_HIDDEN && name.EqualsLiteral("_charset_")) {
        3049               0 :     nsCString charset;
        3050               0 :     aFormSubmission->GetCharset(charset);
        3051                 :     return aFormSubmission->AddNameValuePair(name,
        3052               0 :                                              NS_ConvertASCIItoUTF16(charset));
        3053                 :   }
        3054               0 :   if (IsSingleLineTextControl(true) &&
        3055               0 :       name.EqualsLiteral("isindex") &&
        3056               0 :       aFormSubmission->SupportsIsindexSubmission()) {
        3057               0 :     return aFormSubmission->AddIsindex(value);
        3058                 :   }
        3059               0 :   return aFormSubmission->AddNameValuePair(name, value);
        3060                 : }
        3061                 :
        3062                 :
        3063                 : NS_IMETHODIMP
        3064               3 : nsHTMLInputElement::SaveState()
        3065                 : {
        3066               6 :   nsRefPtr<nsHTMLInputElementState> inputState;
        3067               3 :   switch (mType) {
        3068                 :     case NS_FORM_INPUT_CHECKBOX:
        3069                 :     case NS_FORM_INPUT_RADIO:
        3070                 :       {
        3071               0 :         if (mCheckedChanged) {
        3072               0 :           inputState = new nsHTMLInputElementState();
        3073               0 :           inputState->SetChecked(mChecked);
        3074                 :         }
        3075               0 :         break;
        3076                 :       }
        3077                 :
        3078                 :     // Never save passwords in session history
        3079                 :     case NS_FORM_INPUT_PASSWORD:
        3080               0 :       break;
        3081                 :     case NS_FORM_INPUT_EMAIL:
        3082                 :     case NS_FORM_INPUT_SEARCH:
        3083                 :     case NS_FORM_INPUT_TEXT:
        3084                 :     case NS_FORM_INPUT_TEL:
        3085                 :     case NS_FORM_INPUT_URL:
        3086                 :     case NS_FORM_INPUT_HIDDEN:
        3087                 :       {
        3088               3 :         if (mValueChanged) {
        3089               0 :           inputState = new nsHTMLInputElementState();
        3090               0 :           nsAutoString value;
        3091               0 :           GetValue(value);
        3092                 :           DebugOnly<nsresult> rv =
        3093                 :             nsLinebreakConverter::ConvertStringLineBreaks(
        3094                 :                  value,
        3095                 :                  nsLinebreakConverter::eLinebreakPlatform,
        3096               0 :                  nsLinebreakConverter::eLinebreakContent);
        3097               0 :           NS_ASSERTION(NS_SUCCEEDED(rv), "Converting linebreaks failed!");
        3098               0 :           inputState->SetValue(value);
        3099                 :        }
        3100               3 :       break;
        3101                 :     }
        3102                 :     case NS_FORM_INPUT_FILE:
        3103                 :       {
        3104               0 :         if (mFiles.Count()) {
        3105               0 :           inputState = new nsHTMLInputElementState();
        3106               0 :           inputState->SetFiles(mFiles);
        3107                 :         }
        3108               0 :         break;
        3109                 :       }
        3110                 :   }
        3111                 :
        3112               3 :   nsresult rv = NS_OK;
        3113               3 :   nsPresState* state = nsnull;
        3114               3 :   if (inputState) {
        3115               0 :     rv = GetPrimaryPresState(this, &state);
        3116               0 :     if (state) {
        3117               0 :       state->SetStateProperty(inputState);
        3118                 :     }
        3119                 :   }
        3120                 :
        3121               3 :   if (mDisabledChanged) {
        3122               0 :     rv |= GetPrimaryPresState(this, &state);
        3123               0 :     if (state) {
        3124                 :       // We do not want to save the real disabled state but the disabled
        3125                 :       // attribute.
        3126               0 :       state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
        3127                 :     }
        3128                 :   }
        3129                 :
        3130               3 :   return rv;
        3131                 : }
        3132                 :
        3133                 : void
        3134               1 : nsHTMLInputElement::DoneCreatingElement()
        3135                 : {
        3136               1 :   mParserCreating = false;
        3137                 :
        3138                 :   //
        3139                 :   // Restore state as needed.  Note that disabled state applies to all control
        3140                 :   // types.
        3141                 :   //
        3142                 :   bool restoredCheckedState =
        3143               1 :     !mInhibitRestoration && RestoreFormControlState(this, this);
        3144                 :
        3145                 :   //
        3146                 :   // If restore does not occur, we initialize .checked using the CHECKED
        3147                 :   // property.
        3148                 :   //
        3149               1 :   if (!restoredCheckedState && mShouldInitChecked) {
        3150               0 :     DoSetChecked(DefaultChecked(), false, true);
        3151               0 :     DoSetCheckedChanged(false, false);
        3152                 :   }
        3153                 :
        3154                 :   // Sanitize the value.
        3155               1 :   if (GetValueMode() == VALUE_MODE_VALUE) {
        3156               2 :     nsAutoString aValue;
        3157               1 :     GetValue(aValue);
        3158               1 :     SetValueInternal(aValue, false, false);
        3159                 :   }
        3160                 :
        3161               1 :   mShouldInitChecked = false;
        3162               1 : }
        3163                 :
        3164                 : nsEventStates
        3165               5 : nsHTMLInputElement::IntrinsicState() const
        3166                 : {
        3167                 :   // If you add states here, and they're type-dependent, you need to add them
        3168                 :   // to the type case in AfterSetAttr.
        3169                 :
        3170               5 :   nsEventStates state = nsGenericHTMLFormElement::IntrinsicState();
        3171               5 :   if (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO) {
        3172                 :     // Check current checked state (:checked)
        3173               0 :     if (mChecked) {
        3174               0 :       state |= NS_EVENT_STATE_CHECKED;
        3175                 :     }
        3176                 :
        3177                 :     // Check current indeterminate state (:indeterminate)
        3178               0 :     if (mType == NS_FORM_INPUT_CHECKBOX && mIndeterminate) {
        3179               0 :       state |= NS_EVENT_STATE_INDETERMINATE;
        3180                 :     }
        3181                 :
        3182                 :     // Check whether we are the default checked element (:default)
        3183               0 :     if (DefaultChecked()) {
        3184               0 :       state |= NS_EVENT_STATE_DEFAULT;
        3185                 :     }
        3186               5 :   } else if (mType == NS_FORM_INPUT_IMAGE) {
        3187               0 :     state |= nsImageLoadingContent::ImageState();
        3188                 :   }
        3189                 :
        3190               5 :   if (DoesRequiredApply() && HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
        3191               0 :     state |= NS_EVENT_STATE_REQUIRED;
        3192                 :   } else {
        3193               5 :     state |= NS_EVENT_STATE_OPTIONAL;
        3194                 :   }
        3195                 :
        3196               5 :   if (IsCandidateForConstraintValidation()) {
        3197               5 :     if (IsValid()) {
        3198               5 :       state |= NS_EVENT_STATE_VALID;
        3199                 :     } else {
        3200               0 :       state |= NS_EVENT_STATE_INVALID;
        3201                 :
        3202               0 :       if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
        3203               0 :           (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
        3204               0 :            (mCanShowInvalidUI && ShouldShowValidityUI()))) {
        3205               0 :         state |= NS_EVENT_STATE_MOZ_UI_INVALID;
        3206                 :       }
        3207                 :     }
        3208                 :
        3209                 :     // :-moz-ui-valid applies if all of the following conditions are true:
        3210                 :     // 1. The element is not focused, or had either :-moz-ui-valid or
        3211                 :     //    :-moz-ui-invalid applying before it was focused ;
        3212                 :     // 2. The element is either valid or isn't allowed to have
        3213                 :     //    :-moz-ui-invalid applying ;
        3214                 :     // 3. The element has no form owner or its form owner doesn't have the
        3215                 :     //    novalidate attribute set ;
        3216                 :     // 4. The element has already been modified or the user tried to submit the
        3217                 :     //    form owner while invalid.
        3218              10 :     if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
        3219               5 :         (mCanShowValidUI && ShouldShowValidityUI() &&
        3220               0 :          (IsValid() || (!state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
        3221               0 :                         !mCanShowInvalidUI)))) {
        3222               0 :       state |= NS_EVENT_STATE_MOZ_UI_VALID;
        3223                 :     }
        3224                 :   }
        3225                 :
        3226               5 :   if (PlaceholderApplies() && HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder) &&
        3227               0 :       !nsContentUtils::IsFocusedContent((nsIContent*)(this)) &&
        3228               0 :       IsValueEmpty()) {
        3229               0 :     state |= NS_EVENT_STATE_MOZ_PLACEHOLDER;
        3230                 :   }
        3231                 :
        3232               5 :   if (mForm && !mForm->GetValidity() && IsSubmitControl()) {
        3233               0 :     state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
        3234                 :   }
        3235                 :
        3236                 :   return state;
        3237                 : }
        3238                 :
        3239                 : bool
        3240               0 : nsHTMLInputElement::RestoreState(nsPresState* aState)
        3241                 : {
        3242               0 :   bool restoredCheckedState = false;
        3243                 :
        3244                 :   nsCOMPtr<nsHTMLInputElementState> inputState
        3245               0 :     (do_QueryInterface(aState->GetStateProperty()));
        3246                 :
        3247               0 :   if (inputState) {
        3248               0 :     switch (mType) {
        3249                 :       case NS_FORM_INPUT_CHECKBOX:
        3250                 :       case NS_FORM_INPUT_RADIO:
        3251                 :         {
        3252               0 :           if (inputState->IsCheckedSet()) {
        3253               0 :             restoredCheckedState = true;
        3254               0 :             DoSetChecked(inputState->GetChecked(), true, true);
        3255                 :           }
        3256               0 :           break;
        3257                 :         }
        3258                 :
        3259                 :       case NS_FORM_INPUT_EMAIL:
        3260                 :       case NS_FORM_INPUT_SEARCH:
        3261                 :       case NS_FORM_INPUT_TEXT:
        3262                 :       case NS_FORM_INPUT_TEL:
        3263                 :       case NS_FORM_INPUT_URL:
        3264                 :       case NS_FORM_INPUT_HIDDEN:
        3265                 :         {
        3266               0 :           SetValueInternal(inputState->GetValue(), false, true);
        3267               0 :           break;
        3268                 :         }
        3269                 :       case NS_FORM_INPUT_FILE:
        3270                 :         {
        3271               0 :           const nsCOMArray<nsIDOMFile>& files = inputState->GetFiles();
        3272               0 :           SetFiles(files, true);
        3273               0 :           break;
        3274                 :         }
        3275                 :     }
        3276                 :   }
        3277                 :
        3278               0 :   if (aState->IsDisabledSet()) {
        3279               0 :     SetDisabled(aState->GetDisabled());
        3280                 :   }
        3281                 :
        3282               0 :   return restoredCheckedState;
        3283                 : }
        3284                 :
        3285                 : bool
        3286               0 : nsHTMLInputElement::AllowDrop()
        3287                 : {
        3288                 :   // Allow drop on anything other than file inputs.
        3289                 :
        3290               0 :   return mType != NS_FORM_INPUT_FILE;
        3291                 : }
        3292                 :
        3293                 : /*
        3294                 :  * Radio group stuff
        3295                 :  */
        3296                 :
        3297                 : void
        3298               0 : nsHTMLInputElement::AddedToRadioGroup()
        3299                 : {
        3300                 :   // Make sure not to notify if we're still being created by the parser
        3301               0 :   bool notify = !mParserCreating;
        3302                 :
        3303                 :   //
        3304                 :   //  If the input element is not in a form and
        3305                 :   //  not in a document, we just need to return.
        3306                 :   //
        3307               0 :   if (!mForm && !(IsInDoc() && GetParent())) {
        3308               0 :     return;
        3309                 :   }
        3310                 :
        3311                 :   //
        3312                 :   // If the input element is checked, and we add it to the group, it will
        3313                 :   // deselect whatever is currently selected in that group
        3314                 :   //
        3315               0 :   if (mChecked) {
        3316                 :     //
        3317                 :     // If it is checked, call "RadioSetChecked" to perform the selection/
        3318                 :     // deselection ritual.  This has the side effect of repainting the
        3319                 :     // radio button, but as adding a checked radio button into the group
        3320                 :     // should not be that common an occurrence, I think we can live with
        3321                 :     // that.
        3322                 :     //
        3323               0 :     RadioSetChecked(notify);
        3324                 :   }
        3325                 :
        3326                 :   //
        3327                 :   // For integrity purposes, we have to ensure that "checkedChanged" is
        3328                 :   // the same for this new element as for all the others in the group
        3329                 :   //
        3330               0 :   bool checkedChanged = mCheckedChanged;
        3331                 :
        3332                 :   nsCOMPtr<nsIRadioVisitor> visitor =
        3333               0 :     new nsRadioGetCheckedChangedVisitor(&checkedChanged, this);
        3334               0 :   VisitGroup(visitor, notify);
        3335                 :
        3336               0 :   SetCheckedChangedInternal(checkedChanged);
        3337                 :
        3338                 :   //
        3339                 :   // Add the radio to the radio group container.
        3340                 :   //
        3341               0 :   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
        3342               0 :   if (container) {
        3343               0 :     nsAutoString name;
        3344               0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        3345               0 :     container->AddToRadioGroup(name, static_cast<nsIFormControl*>(this));
        3346                 :
        3347                 :     // We initialize the validity of the element to the validity of the group
        3348                 :     // because we assume UpdateValueMissingState() will be called after.
        3349                 :     SetValidityState(VALIDITY_STATE_VALUE_MISSING,
        3350               0 :                      container->GetValueMissingState(name));
        3351                 :   }
        3352                 : }
        3353                 :
        3354                 : void
        3355               0 : nsHTMLInputElement::WillRemoveFromRadioGroup()
        3356                 : {
        3357               0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
        3358               0 :   if (!container) {
        3359               0 :     return;
        3360                 :   }
        3361                 :
        3362               0 :   nsAutoString name;
        3363               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        3364                 :
        3365                 :   // If this button was checked, we need to notify the group that there is no
        3366                 :   // longer a selected radio button
        3367               0 :   if (mChecked) {
        3368               0 :     container->SetCurrentRadioButton(name, nsnull);
        3369                 :   }
        3370                 :
        3371                 :   // Remove this radio from its group in the container.
        3372                 :   // We need to call UpdateValueMissingValidityStateForRadio before to make sure
        3373                 :   // the group validity is updated (with this element being ignored).
        3374               0 :   UpdateValueMissingValidityStateForRadio(true);
        3375               0 :   container->RemoveFromRadioGroup(name, static_cast<nsIFormControl*>(this));
        3376                 : }
        3377                 :
        3378                 : bool
        3379               0 : nsHTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool *aIsFocusable, PRInt32 *aTabIndex)
        3380                 : {
        3381               0 :   if (nsGenericHTMLFormElement::IsHTMLFocusable(aWithMouse, aIsFocusable, aTabIndex)) {
        3382               0 :     return true;
        3383                 :   }
        3384                 :
        3385               0 :   if (IsDisabled()) {
        3386               0 :     *aIsFocusable = false;
        3387               0 :     return true;
        3388                 :   }
        3389                 :
        3390               0 :   if (IsSingleLineTextControl(false)) {
        3391               0 :     *aIsFocusable = true;
        3392               0 :     return false;
        3393                 :   }
        3394                 :
        3395                 : #ifdef XP_MACOSX
        3396                 :   const bool defaultFocusable = !aWithMouse || nsFocusManager::sMouseFocusesFormControl;
        3397                 : #else
        3398               0 :   const bool defaultFocusable = true;
        3399                 : #endif
        3400                 :
        3401               0 :   if (mType == NS_FORM_INPUT_FILE) {
        3402               0 :     if (aTabIndex) {
        3403               0 :       *aTabIndex = -1;
        3404                 :     }
        3405               0 :     *aIsFocusable = defaultFocusable;
        3406               0 :     return true;
        3407                 :   }
        3408                 :
        3409               0 :   if (mType == NS_FORM_INPUT_HIDDEN) {
        3410               0 :     if (aTabIndex) {
        3411               0 :       *aTabIndex = -1;
        3412                 :     }
        3413               0 :     *aIsFocusable = false;
        3414               0 :     return false;
        3415                 :   }
        3416                 :
        3417               0 :   if (!aTabIndex) {
        3418                 :     // The other controls are all focusable
        3419               0 :     *aIsFocusable = defaultFocusable;
        3420               0 :     return false;
        3421                 :   }
        3422                 :
        3423               0 :   if (mType != NS_FORM_INPUT_RADIO) {
        3424               0 :     *aIsFocusable = defaultFocusable;
        3425               0 :     return false;
        3426                 :   }
        3427                 :
        3428               0 :   if (mChecked) {
        3429                 :     // Selected radio buttons are tabbable
        3430               0 :     *aIsFocusable = defaultFocusable;
        3431               0 :     return false;
        3432                 :   }
        3433                 :
        3434                 :   // Current radio button is not selected.
        3435                 :   // But make it tabbable if nothing in group is selected.
        3436               0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
        3437               0 :   if (!container) {
        3438               0 :     *aIsFocusable = defaultFocusable;
        3439               0 :     return false;
        3440                 :   }
        3441                 :
        3442               0 :   nsAutoString name;
        3443               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        3444                 :
        3445               0 :   nsCOMPtr<nsIDOMHTMLInputElement> currentRadio;
        3446               0 :   container->GetCurrentRadioButton(name, getter_AddRefs(currentRadio));
        3447               0 :   if (currentRadio) {
        3448               0 :     *aTabIndex = -1;
        3449                 :   }
        3450               0 :   *aIsFocusable = defaultFocusable;
        3451               0 :   return false;
        3452                 : }
        3453                 :
        3454                 : nsresult
        3455               0 : nsHTMLInputElement::VisitGroup(nsIRadioVisitor* aVisitor, bool aFlushContent)
        3456                 : {
        3457               0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
        3458               0 :   if (container) {
        3459               0 :     nsAutoString name;
        3460               0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        3461               0 :     return container->WalkRadioGroup(name, aVisitor, aFlushContent);
        3462                 :   }
        3463                 :
        3464               0 :   aVisitor->Visit(this);
        3465               0 :   return NS_OK;
        3466                 : }
        3467                 :
        3468                 : nsHTMLInputElement::ValueModeType
        3469               9 : nsHTMLInputElement::GetValueMode() const
        3470                 : {
        3471               9 :   switch (mType)
        3472                 :   {
        3473                 :     case NS_FORM_INPUT_HIDDEN:
        3474                 :     case NS_FORM_INPUT_SUBMIT:
        3475                 :     case NS_FORM_INPUT_BUTTON:
        3476                 :     case NS_FORM_INPUT_RESET:
        3477                 :     case NS_FORM_INPUT_IMAGE:
        3478               0 :       return VALUE_MODE_DEFAULT;
        3479                 :     case NS_FORM_INPUT_CHECKBOX:
        3480                 :     case NS_FORM_INPUT_RADIO:
        3481               0 :       return VALUE_MODE_DEFAULT_ON;
        3482                 :     case NS_FORM_INPUT_FILE:
        3483               0 :       return VALUE_MODE_FILENAME;
        3484                 : #ifdef DEBUG
        3485                 :     case NS_FORM_INPUT_TEXT:
        3486                 :     case NS_FORM_INPUT_PASSWORD:
        3487                 :     case NS_FORM_INPUT_SEARCH:
        3488                 :     case NS_FORM_INPUT_TEL:
        3489                 :     case NS_FORM_INPUT_EMAIL:
        3490                 :     case NS_FORM_INPUT_URL:
        3491               9 :       return VALUE_MODE_VALUE;
        3492                 :     default:
        3493               0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
        3494               0 :       return VALUE_MODE_VALUE;
        3495                 : #else // DEBUG
        3496                 :     default:
        3497                 :       return VALUE_MODE_VALUE;
        3498                 : #endif // DEBUG
        3499                 :   }
        3500                 : }
        3501                 :
        3502                 : bool
        3503               0 : nsHTMLInputElement::IsMutable() const
        3504                 : {
        3505               0 :   return !IsDisabled() && GetCurrentDoc() &&
        3506               0 :          !(DoesReadOnlyApply() &&
        3507               0 :            HasAttr(kNameSpaceID_None, nsGkAtoms::readonly));
        3508                 : }
        3509                 :
        3510                 : bool
        3511               0 : nsHTMLInputElement::DoesReadOnlyApply() const
        3512                 : {
        3513               0 :   switch (mType)
        3514                 :   {
        3515                 :     case NS_FORM_INPUT_HIDDEN:
        3516                 :     case NS_FORM_INPUT_BUTTON:
        3517                 :     case NS_FORM_INPUT_IMAGE:
        3518                 :     case NS_FORM_INPUT_RESET:
        3519                 :     case NS_FORM_INPUT_SUBMIT:
        3520                 :     case NS_FORM_INPUT_RADIO:
        3521                 :     case NS_FORM_INPUT_FILE:
        3522                 :     case NS_FORM_INPUT_CHECKBOX:
        3523                 :     // TODO:
        3524                 :     // case NS_FORM_INPUT_COLOR:
        3525                 :     // case NS_FORM_INPUT_RANGE:
        3526               0 :       return false;
        3527                 : #ifdef DEBUG
        3528                 :     case NS_FORM_INPUT_TEXT:
        3529                 :     case NS_FORM_INPUT_PASSWORD:
        3530                 :     case NS_FORM_INPUT_SEARCH:
        3531                 :     case NS_FORM_INPUT_TEL:
        3532                 :     case NS_FORM_INPUT_EMAIL:
        3533                 :     case NS_FORM_INPUT_URL:
        3534               0 :       return true;
        3535                 :     default:
        3536               0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesReadOnlyApply()");
        3537               0 :       return true;
        3538                 : #else // DEBUG
        3539                 :     default:
        3540                 :       return true;
        3541                 : #endif // DEBUG
        3542                 :   }
        3543                 : }
        3544                 :
        3545                 : bool
        3546               5 : nsHTMLInputElement::DoesRequiredApply() const
        3547                 : {
        3548               5 :   switch (mType)
        3549                 :   {
        3550                 :     case NS_FORM_INPUT_HIDDEN:
        3551                 :     case NS_FORM_INPUT_BUTTON:
        3552                 :     case NS_FORM_INPUT_IMAGE:
        3553                 :     case NS_FORM_INPUT_RESET:
        3554                 :     case NS_FORM_INPUT_SUBMIT:
        3555                 :     // TODO:
        3556                 :     // case NS_FORM_INPUT_COLOR:
        3557                 :     // case NS_FORM_INPUT_RANGE:
        3558               0 :       return false;
        3559                 : #ifdef DEBUG
        3560                 :     case NS_FORM_INPUT_RADIO:
        3561                 :     case NS_FORM_INPUT_CHECKBOX:
        3562                 :     case NS_FORM_INPUT_FILE:
        3563                 :     case NS_FORM_INPUT_TEXT:
        3564                 :     case NS_FORM_INPUT_PASSWORD:
        3565                 :     case NS_FORM_INPUT_SEARCH:
        3566                 :     case NS_FORM_INPUT_TEL:
        3567                 :     case NS_FORM_INPUT_EMAIL:
        3568                 :     case NS_FORM_INPUT_URL:
        3569               5 :       return true;
        3570                 :     default:
        3571               0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
        3572               0 :       return true;
        3573                 : #else // DEBUG
        3574                 :     default:
        3575                 :       return true;
        3576                 : #endif // DEBUG
        3577                 :   }
        3578                 : }
        3579                 :
        3580                 : bool
        3581               1 : nsHTMLInputElement::DoesPatternApply() const
        3582                 : {
        3583               1 :   return IsSingleLineTextControl(false);
        3584                 : }
        3585                 :
        3586                 : // nsIConstraintValidation
        3587                 :
        3588                 : NS_IMETHODIMP
        3589               0 : nsHTMLInputElement::SetCustomValidity(const nsAString& aError)
        3590                 : {
        3591               0 :   nsIConstraintValidation::SetCustomValidity(aError);
        3592                 :
        3593               0 :   UpdateState(true);
        3594                 :
        3595               0 :   return NS_OK;
        3596                 : }
        3597                 :
        3598                 : bool
        3599               0 : nsHTMLInputElement::IsTooLong()
        3600                 : {
        3601               0 :   if (!MaxLengthApplies() ||
        3602               0 :       !HasAttr(kNameSpaceID_None, nsGkAtoms::maxlength) ||
        3603               0 :       !mValueChanged) {
        3604               0 :     return false;
        3605                 :   }
        3606                 :
        3607               0 :   PRInt32 maxLength = -1;
        3608               0 :   GetMaxLength(&maxLength);
        3609                 :
        3610                 :   // Maxlength of -1 means parsing error.
        3611               0 :   if (maxLength == -1) {
        3612               0 :     return false;
        3613                 :   }
        3614                 :
        3615               0 :   PRInt32 textLength = -1;
        3616               0 :   GetTextLength(&textLength);
        3617                 :
        3618               0 :   return textLength > maxLength;
        3619                 : }
        3620                 :
        3621                 : bool
        3622               5 : nsHTMLInputElement::IsValueMissing() const
        3623                 : {
        3624               5 :   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::required) ||
        3625               0 :       !DoesRequiredApply()) {
        3626               5 :     return false;
        3627                 :   }
        3628                 :
        3629               0 :   if (GetValueMode() == VALUE_MODE_VALUE) {
        3630               0 :     if (!IsMutable()) {
        3631               0 :       return false;
        3632                 :     }
        3633                 :
        3634               0 :     return IsValueEmpty();
        3635                 :   }
        3636                 :
        3637               0 :   switch (mType)
        3638                 :   {
        3639                 :     case NS_FORM_INPUT_CHECKBOX:
        3640               0 :       return !mChecked;
        3641                 :     case NS_FORM_INPUT_FILE:
        3642                 :       {
        3643               0 :         const nsCOMArray<nsIDOMFile>& files = GetFiles();
        3644               0 :         return !files.Count();
        3645                 :       }
        3646                 :     default:
        3647               0 :       return false;
        3648                 :   }
        3649                 : }
        3650                 :
        3651                 : bool
        3652               1 : nsHTMLInputElement::HasTypeMismatch() const
        3653                 : {
        3654               1 :   if (mType != NS_FORM_INPUT_EMAIL && mType != NS_FORM_INPUT_URL) {
        3655               1 :     return false;
        3656                 :   }
        3657                 :
        3658               0 :   nsAutoString value;
        3659               0 :   NS_ENSURE_SUCCESS(GetValueInternal(value), false);
        3660                 :
        3661               0 :   if (value.IsEmpty()) {
        3662               0 :     return false;
        3663                 :   }
        3664                 :
        3665               0 :   if (mType == NS_FORM_INPUT_EMAIL) {
        3666               0 :     return HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)
        3667               0 :              ? !IsValidEmailAddressList(value) : !IsValidEmailAddress(value);
        3668               0 :   } else if (mType == NS_FORM_INPUT_URL) {
        3669                 :     /**
        3670                 :      * TODO:
        3671                 :      * The URL is not checked as the HTML5 specifications want it to be because
        3672                 :      * there is no code to check for a valid URI/IRI according to 3986 and 3987
        3673                 :      * RFC's at the moment, see bug 561586.
        3674                 :      *
        3675                 :      * RFC 3987 (IRI) implementation: bug 42899
        3676                 :      *
        3677                 :      * HTML5 specifications:
        3678                 :      * http://dev.w3.org/html5/spec/infrastructure.html#valid-url
        3679                 :      */
        3680               0 :     nsCOMPtr<nsIIOService> ioService = do_GetIOService();
        3681               0 :     nsCOMPtr<nsIURI> uri;
        3682                 :
        3683               0 :     return !NS_SUCCEEDED(ioService->NewURI(NS_ConvertUTF16toUTF8(value), nsnull,
        3684                 :                                            nsnull, getter_AddRefs(uri)));
        3685                 :   }
        3686                 :
        3687               0 :   return false;
        3688                 : }
        3689                 :
        3690                 : bool
        3691               1 : nsHTMLInputElement::HasPatternMismatch() const
        3692                 : {
        3693               2 :   nsAutoString pattern;
        3694               2 :   if (!DoesPatternApply() ||
        3695               1 :       !GetAttr(kNameSpaceID_None, nsGkAtoms::pattern, pattern)) {
        3696               1 :     return false;
        3697                 :   }
        3698                 :
        3699               0 :   nsAutoString value;
        3700               0 :   NS_ENSURE_SUCCESS(GetValueInternal(value), false);
        3701                 :
        3702               0 :   if (value.IsEmpty()) {
        3703               0 :     return false;
        3704                 :   }
        3705                 :
        3706               0 :   nsIDocument* doc = OwnerDoc();
        3707                 :
        3708               0 :   return !nsContentUtils::IsPatternMatching(value, pattern, doc);
        3709                 : }
        3710                 :
        3711                 : void
        3712               1 : nsHTMLInputElement::UpdateTooLongValidityState()
        3713                 : {
        3714                 :   // TODO: this code will be re-enabled with bug 613016 and bug 613019.
        3715                 : #if 0
        3716                 :   SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
        3717                 : #endif
        3718               1 : }
        3719                 :
        3720                 : void
        3721               0 : nsHTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
        3722                 : {
        3723               0 :   bool notify = !mParserCreating;
        3724               0 :   nsCOMPtr<nsIDOMHTMLInputElement> selection = GetSelectedRadioButton();
        3725                 :
        3726                 :   // If there is no selection, that might mean the radio is not in a group.
        3727                 :   // In that case, we can look for the checked state of the radio.
        3728               0 :   bool selected = selection || (!aIgnoreSelf && mChecked);
        3729               0 :   bool required = !aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required);
        3730               0 :   bool valueMissing = false;
        3731                 :
        3732               0 :   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
        3733                 :
        3734               0 :   if (!container) {
        3735               0 :     SetValidityState(VALIDITY_STATE_VALUE_MISSING, required && !selected);
        3736                 :     return;
        3737                 :   }
        3738                 :
        3739               0 :   nsAutoString name;
        3740               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
        3741                 :
        3742                 :   // If the current radio is required and not ignored, we can assume the entire
        3743                 :   // group is required.
        3744               0 :   if (!required) {
        3745               0 :     required = (aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required))
        3746               0 :                  ? container->GetRequiredRadioCount(name) - 1
        3747               0 :                  : container->GetRequiredRadioCount(name);
        3748                 :   }
        3749                 :
        3750               0 :   valueMissing = required && !selected;
        3751                 :
        3752               0 :   if (container->GetValueMissingState(name) != valueMissing) {
        3753               0 :     container->SetValueMissingState(name, valueMissing);
        3754                 :
        3755               0 :     SetValidityState(VALIDITY_STATE_VALUE_MISSING, valueMissing);
        3756                 :
        3757                 :     // nsRadioSetValueMissingState will call ContentStateChanged while visiting.
        3758               0 :     nsAutoScriptBlocker scriptBlocker;
        3759                 :     nsCOMPtr<nsIRadioVisitor> visitor =
        3760               0 :       new nsRadioSetValueMissingState(this, valueMissing, notify);
        3761               0 :     VisitGroup(visitor, notify);
        3762                 :   }
        3763                 : }
        3764                 :
        3765                 : void
        3766               5 : nsHTMLInputElement::UpdateValueMissingValidityState()
        3767                 : {
        3768               5 :   if (mType == NS_FORM_INPUT_RADIO) {
        3769               0 :     UpdateValueMissingValidityStateForRadio(false);
        3770               0 :     return;
        3771                 :   }
        3772                 :
        3773               5 :   SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
        3774                 : }
        3775                 :
        3776                 : void
        3777               1 : nsHTMLInputElement::UpdateTypeMismatchValidityState()
        3778                 : {
        3779               1 :     SetValidityState(VALIDITY_STATE_TYPE_MISMATCH, HasTypeMismatch());
        3780               1 : }
        3781                 :
        3782                 : void
        3783               1 : nsHTMLInputElement::UpdatePatternMismatchValidityState()
        3784                 : {
        3785               1 :   SetValidityState(VALIDITY_STATE_PATTERN_MISMATCH, HasPatternMismatch());
        3786               1 : }
        3787                 :
        3788                 : void
        3789               1 : nsHTMLInputElement::UpdateAllValidityStates(bool aNotify)
        3790                 : {
        3791               1 :   bool validBefore = IsValid();
        3792               1 :   UpdateTooLongValidityState();
        3793               1 :   UpdateValueMissingValidityState();
        3794               1 :   UpdateTypeMismatchValidityState();
        3795               1 :   UpdatePatternMismatchValidityState();
        3796                 :
        3797               1 :   if (validBefore != IsValid()) {
        3798               0 :     UpdateState(aNotify);
        3799                 :   }
        3800               1 : }
        3801                 :
        3802                 : void
        3803               4 : nsHTMLInputElement::UpdateBarredFromConstraintValidation()
        3804                 : {
        3805                 :   SetBarredFromConstraintValidation(mType == NS_FORM_INPUT_HIDDEN ||
        3806                 :                                     mType == NS_FORM_INPUT_BUTTON ||
        3807                 :                                     mType == NS_FORM_INPUT_RESET ||
        3808                 :                                     mType == NS_FORM_INPUT_SUBMIT ||
        3809                 :                                     mType == NS_FORM_INPUT_IMAGE ||
        3810               4 :                                     HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) ||
        3811               8 :                                     IsDisabled());
        3812               4 : }
        3813                 :
        3814                 : nsresult
        3815               0 : nsHTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
        3816                 :                                          ValidityStateType aType)
        3817                 : {
        3818               0 :   nsresult rv = NS_OK;
        3819                 :
        3820               0 :   switch (aType)
        3821                 :   {
        3822                 :     case VALIDITY_STATE_TOO_LONG:
        3823                 :     {
        3824               0 :       nsXPIDLString message;
        3825               0 :       PRInt32 maxLength = -1;
        3826               0 :       PRInt32 textLength = -1;
        3827               0 :       nsAutoString strMaxLength;
        3828               0 :       nsAutoString strTextLength;
        3829                 :
        3830               0 :       GetMaxLength(&maxLength);
        3831               0 :       GetTextLength(&textLength);
        3832                 :
        3833               0 :       strMaxLength.AppendInt(maxLength);
        3834               0 :       strTextLength.AppendInt(textLength);
        3835                 :
        3836               0 :       const PRUnichar* params[] = { strMaxLength.get(), strTextLength.get() };
        3837                 :       rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
        3838                 :                                                  "FormValidationTextTooLong",
        3839               0 :                                                  params, message);
        3840               0 :       aValidationMessage = message;
        3841                 :       break;
        3842                 :     }
        3843                 :     case VALIDITY_STATE_VALUE_MISSING:
        3844                 :     {
        3845               0 :       nsXPIDLString message;
        3846               0 :       nsCAutoString key;
        3847               0 :       switch (mType)
        3848                 :       {
        3849                 :         case NS_FORM_INPUT_FILE:
        3850               0 :           key.Assign("FormValidationFileMissing");
        3851               0 :           break;
        3852                 :         case NS_FORM_INPUT_CHECKBOX:
        3853               0 :           key.Assign("FormValidationCheckboxMissing");
        3854               0 :           break;
        3855                 :         case NS_FORM_INPUT_RADIO:
        3856               0 :           key.Assign("FormValidationRadioMissing");
        3857               0 :           break;
        3858                 :         default:
        3859               0 :           key.Assign("FormValidationValueMissing");
        3860                 :       }
        3861                 :       rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
        3862               0 :                                               key.get(), message);
        3863               0 :       aValidationMessage = message;
        3864                 :       break;
        3865                 :     }
        3866                 :     case VALIDITY_STATE_TYPE_MISMATCH:
        3867                 :     {
        3868               0 :       nsXPIDLString message;
        3869               0 :       nsCAutoString key;
        3870               0 :       if (mType == NS_FORM_INPUT_EMAIL) {
        3871               0 :         key.AssignLiteral("FormValidationInvalidEmail");
        3872               0 :       } else if (mType == NS_FORM_INPUT_URL) {
        3873               0 :         key.AssignLiteral("FormValidationInvalidURL");
        3874                 :       } else {
        3875               0 :         return NS_ERROR_UNEXPECTED;
        3876                 :       }
        3877                 :       rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
        3878               0 :                                               key.get(), message);
        3879               0 :       aValidationMessage = message;
        3880               0 :       break;
        3881                 :     }
        3882                 :     case VALIDITY_STATE_PATTERN_MISMATCH:
        3883                 :     {
        3884               0 :       nsXPIDLString message;
        3885               0 :       nsAutoString title;
        3886               0 :       GetAttr(kNameSpaceID_None, nsGkAtoms::title, title);
        3887               0 :       if (title.IsEmpty()) {
        3888                 :         rv = nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
        3889                 :                                                 "FormValidationPatternMismatch",
        3890               0 :                                                 message);
        3891                 :       } else {
        3892               0 :         if (title.Length() > nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
        3893               0 :           title.Truncate(nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
        3894                 :         }
        3895               0 :         const PRUnichar* params[] = { title.get() };
        3896                 :         rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
        3897                 :                                                    "FormValidationPatternMismatchWithTitle",
        3898               0 :                                                    params, message);
        3899                 :       }
        3900               0 :       aValidationMessage = message;
        3901                 :       break;
        3902                 :     }
        3903                 :     default:
        3904               0 :       rv = nsIConstraintValidation::GetValidationMessage(aValidationMessage, aType);
        3905                 :   }
        3906                 :
        3907               0 :   return rv;
        3908                 : }
        3909                 :
        3910                 : //static
        3911                 : bool
        3912               0 : nsHTMLInputElement::IsValidEmailAddressList(const nsAString& aValue)
        3913                 : {
        3914               0 :   HTMLSplitOnSpacesTokenizer tokenizer(aValue, ',');
        3915                 :
        3916               0 :   while (tokenizer.hasMoreTokens()) {
        3917               0 :     if (!IsValidEmailAddress(tokenizer.nextToken())) {
        3918               0 :       return false;
        3919                 :     }
        3920                 :   }
        3921                 :
        3922               0 :   return !tokenizer.lastTokenEndedWithSeparator();
        3923                 : }
        3924                 :
        3925                 : //static
        3926                 : bool
        3927               0 : nsHTMLInputElement::IsValidEmailAddress(const nsAString& aValue)
        3928                 : {
        3929               0 :   nsCAutoString value = NS_ConvertUTF16toUTF8(aValue);
        3930               0 :   PRUint32 i = 0;
        3931               0 :   PRUint32 length = value.Length();
        3932                 :
        3933                 :   // Puny-encode the string if needed before running the validation algorithm.
        3934               0 :   nsCOMPtr<nsIIDNService> idnSrv = do_GetService(NS_IDNSERVICE_CONTRACTID);
        3935               0 :   if (idnSrv) {
        3936                 :     bool ace;
        3937               0 :     if (NS_SUCCEEDED(idnSrv->IsACE(value, &ace)) && !ace) {
        3938               0 :       nsCAutoString punyCodedValue;
        3939               0 :       if (NS_SUCCEEDED(idnSrv->ConvertUTF8toACE(value, punyCodedValue))) {
        3940               0 :         value = punyCodedValue;
        3941               0 :         length = value.Length();
        3942                 :       }
        3943                 :     }
        3944                 :   } else {
        3945               0 :     NS_ERROR("nsIIDNService isn't present!");
        3946                 :   }
        3947                 :
        3948                 :   // If the email address is empty, begins with a '@' or ends with a '.',
        3949                 :   // we know it's invalid.
        3950               0 :   if (length == 0 || value[0] == '@' || value[length-1] == '.') {
        3951               0 :     return false;
        3952                 :   }
        3953                 :
        3954                 :   // Parsing the username.
        3955               0 :   for (; i < length && value[i] != '@'; ++i) {
        3956               0 :     PRUnichar c = value[i];
        3957                 :
        3958                 :     // The username characters have to be in this list to be valid.
        3959               0 :     if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
        3960                 :           c == '.' || c == '!' || c == '#' || c == '$' || c == '%' ||
        3961                 :           c == '&' || c == '\''|| c == '*' || c == '+' || c == '-' ||
        3962                 :           c == '/' || c == '=' || c == '?' || c == '^' || c == '_' ||
        3963               0 :           c == '`' || c == '{' || c == '|' || c == '}' || c == '~' )) {
        3964               0 :       return false;
        3965                 :     }
        3966                 :   }
        3967                 :
        3968                 :   // There is no domain name (or it's one-character long),
        3969                 :   // that's not a valid email address.
        3970               0 :   if (++i >= length) {
        3971               0 :     return false;
        3972                 :   }
        3973                 :
        3974                 :   // The domain name can't begin with a dot.
        3975               0 :   if (value[i] == '.') {
        3976               0 :     return false;
        3977                 :   }
        3978                 :
        3979                 :   // Parsing the domain name.
        3980               0 :   for (; i < length; ++i) {
        3981               0 :     PRUnichar c = value[i];
        3982                 :
        3983               0 :     if (c == '.') {
        3984                 :       // A dot can't follow a dot.
        3985               0 :       if (value[i-1] == '.') {
        3986               0 :         return false;
        3987                 :       }
        3988               0 :     } else if (!(nsCRT::IsAsciiAlpha(c) || nsCRT::IsAsciiDigit(c) ||
        3989               0 :                  c == '-')) {
        3990                 :       // The domain characters have to be in this list to be valid.
        3991               0 :       return false;
        3992                 :     }
        3993                 :   }
        3994                 :
        3995               0 :   return true;
        3996                 : }
        3997                 :
        3998                 : NS_IMETHODIMP_(bool)
        3999               0 : nsHTMLInputElement::IsSingleLineTextControl() const
        4000                 : {
        4001               0 :   return IsSingleLineTextControl(false);
        4002                 : }
        4003                 :
        4004                 : NS_IMETHODIMP_(bool)
        4005               0 : nsHTMLInputElement::IsTextArea() const
        4006                 : {
        4007               0 :   return false;
        4008                 : }
        4009                 :
        4010                 : NS_IMETHODIMP_(bool)
        4011               0 : nsHTMLInputElement::IsPlainTextControl() const
        4012                 : {
        4013                 :   // need to check our HTML attribute and/or CSS.
        4014               0 :   return true;
        4015                 : }
        4016                 :
        4017                 : NS_IMETHODIMP_(bool)
        4018               0 : nsHTMLInputElement::IsPasswordTextControl() const
        4019                 : {
        4020               0 :   return mType == NS_FORM_INPUT_PASSWORD;
        4021                 : }
        4022                 :
        4023                 : NS_IMETHODIMP_(PRInt32)
        4024               0 : nsHTMLInputElement::GetCols()
        4025                 : {
        4026                 :   // Else we know (assume) it is an input with size attr
        4027               0 :   const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::size);
        4028               0 :   if (attr && attr->Type() == nsAttrValue::eInteger) {
        4029               0 :     PRInt32 cols = attr->GetIntegerValue();
        4030               0 :     if (cols > 0) {
        4031               0 :       return cols;
        4032                 :     }
        4033                 :   }
        4034                 :
        4035               0 :   return DEFAULT_COLS;
        4036                 : }
        4037                 :
        4038                 : NS_IMETHODIMP_(PRInt32)
        4039               0 : nsHTMLInputElement::GetWrapCols()
        4040                 : {
        4041               0 :   return -1; // only textarea's can have wrap cols
        4042                 : }
        4043                 :
        4044                 : NS_IMETHODIMP_(PRInt32)
        4045               0 : nsHTMLInputElement::GetRows()
        4046                 : {
        4047               0 :   return DEFAULT_ROWS;
        4048                 : }
        4049                 :
        4050                 : NS_IMETHODIMP_(void)
        4051               1 : nsHTMLInputElement::GetDefaultValueFromContent(nsAString& aValue)
        4052                 : {
        4053               1 :   nsTextEditorState *state = GetEditorState();
        4054               1 :   if (state) {
        4055               1 :     GetDefaultValue(aValue);
        4056                 :     // This is called by the frame to show the value.
        4057                 :     // We have to sanitize it when needed.
        4058               1 :     if (!mParserCreating) {
        4059               1 :       SanitizeValue(aValue);
        4060                 :     }
        4061                 :   }
        4062               1 : }
        4063                 :
        4064                 : NS_IMETHODIMP_(bool)
        4065               1 : nsHTMLInputElement::ValueChanged() const
        4066                 : {
        4067               1 :   return mValueChanged;
        4068                 : }
        4069                 :
        4070                 : NS_IMETHODIMP_(void)
        4071               0 : nsHTMLInputElement::GetTextEditorValue(nsAString& aValue,
        4072                 :                                        bool aIgnoreWrap) const
        4073                 : {
        4074               0 :   nsTextEditorState *state = GetEditorState();
        4075               0 :   if (state) {
        4076               0 :     state->GetValue(aValue, aIgnoreWrap);
        4077                 :   }
        4078               0 : }
        4079                 :
        4080                 : NS_IMETHODIMP_(void)
        4081               0 : nsHTMLInputElement::SetTextEditorValue(const nsAString& aValue,
        4082                 :                                        bool aUserInput)
        4083                 : {
        4084               0 :   nsTextEditorState *state = GetEditorState();
        4085               0 :   if (state) {
        4086               0 :     state->SetValue(aValue, aUserInput);
        4087                 :   }
        4088               0 : }
        4089                 :
        4090                 : NS_IMETHODIMP_(void)
        4091               0 : nsHTMLInputElement::InitializeKeyboardEventListeners()
        4092                 : {
        4093               0 :   nsTextEditorState *state = GetEditorState();
        4094               0 :   if (state) {
        4095               0 :     state->InitializeKeyboardEventListeners();
        4096                 :   }
        4097               0 : }
        4098                 :
        4099                 : NS_IMETHODIMP_(void)
        4100               1 : nsHTMLInputElement::OnValueChanged(bool aNotify)
        4101                 : {
        4102               1 :   UpdateAllValidityStates(aNotify);
        4103                 :
        4104                 :   // :-moz-placeholder pseudo-class may change when the value changes.
        4105                 :   // However, we don't want to waste cycles if the state doesn't apply.
        4106               2 :   if (PlaceholderApplies() &&
        4107               1 :       HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder) &&
        4108               0 :       !nsContentUtils::IsFocusedContent(this)) {
        4109               0 :     UpdateState(aNotify);
        4110                 :   }
        4111               1 : }
        4112                 :
        4113                 : NS_IMETHODIMP_(bool)
        4114               0 : nsHTMLInputElement::HasCachedSelection()
        4115                 : {
        4116               0 :   bool isCached = false;
        4117               0 :   nsTextEditorState *state = GetEditorState();
        4118               0 :   if (state) {
        4119               0 :     isCached = state->IsSelectionCached() &&
        4120               0 :                state->HasNeverInitializedBefore() &&
        4121               0 :                !state->GetSelectionProperties().IsDefault();
        4122               0 :     if (isCached) {
        4123               0 :       state->WillInitEagerly();
        4124                 :     }
        4125                 :   }
        4126               0 :   return isCached;
        4127                 : }
        4128                 :
        4129                 : void
        4130               0 : nsHTMLInputElement::FieldSetDisabledChanged(bool aNotify)
        4131                 : {
        4132               0 :   UpdateValueMissingValidityState();
        4133               0 :   UpdateBarredFromConstraintValidation();
        4134                 :
        4135               0 :   nsGenericHTMLFormElement::FieldSetDisabledChanged(aNotify);
        4136               0 : }
        4137                 :
        4138                 : PRInt32
        4139               0 : nsHTMLInputElement::GetFilterFromAccept()
        4140                 : {
        4141               0 :   NS_ASSERTION(HasAttr(kNameSpaceID_None, nsGkAtoms::accept),
        4142                 :                "You should not call GetFileFiltersFromAccept if the element"
        4143                 :                " has no accept attribute!");
        4144                 :
        4145               0 :   PRInt32 filter = 0;
        4146               0 :   nsAutoString accept;
        4147               0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::accept, accept);
        4148                 :
        4149               0 :   HTMLSplitOnSpacesTokenizer tokenizer(accept, ',');
        4150                 :
        4151               0 :   while (tokenizer.hasMoreTokens()) {
        4152               0 :     const nsDependentSubstring token = tokenizer.nextToken();
        4153                 :
        4154               0 :     PRInt32 tokenFilter = 0;
        4155               0 :     if (token.EqualsLiteral("image/*")) {
        4156               0 :       tokenFilter = nsIFilePicker::filterImages;
        4157               0 :     } else if (token.EqualsLiteral("audio/*")) {
        4158               0 :       tokenFilter = nsIFilePicker::filterAudio;
        4159               0 :     } else if (token.EqualsLiteral("video/*")) {
        4160               0 :       tokenFilter = nsIFilePicker::filterVideo;
        4161                 :     }
        4162                 :
        4163               0 :     if (tokenFilter) {
        4164                 :       // We do not want to set more than one filter so if we found two different
        4165                 :       // kwown tokens, we will return 0 (no filter).
        4166               0 :       if (filter && filter != tokenFilter) {
        4167               0 :         return 0;
        4168                 :       }
        4169               0 :       filter = tokenFilter;
        4170                 :     }
        4171                 :   }
        4172                 :
        4173               0 :   return filter;
        4174                 : }
        4175                 :
        4176                 : void
        4177               0 : nsHTMLInputElement::UpdateValidityUIBits(bool aIsFocused)
        4178                 : {
        4179               0 :   if (aIsFocused) {
        4180                 :     // If the invalid UI is shown, we should show it while focusing (and
        4181                 :     // update). Otherwise, we should not.
        4182               0 :     mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
        4183                 :
        4184                 :     // If neither invalid UI nor valid UI is shown, we shouldn't show the valid
        4185                 :     // UI while typing.
        4186               0 :     mCanShowValidUI = ShouldShowValidityUI();
        4187                 :   } else {
        4188               0 :     mCanShowInvalidUI = true;
        4189               0 :     mCanShowValidUI = true;
        4190                 :   }
        4191            4188 : }
        4192                 :

Generated by: LCOV version 1.7