LCOV - code coverage report
Current view: top level - dom/html - HTMLInputElement.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 640 3557 18.0 %
Date: 2017-07-14 16:53:18 Functions: 105 394 26.6 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "mozilla/dom/HTMLInputElement.h"
       8             : 
       9             : #include "mozilla/ArrayUtils.h"
      10             : #include "mozilla/AsyncEventDispatcher.h"
      11             : #include "mozilla/DebugOnly.h"
      12             : #include "mozilla/dom/Date.h"
      13             : #include "mozilla/dom/Directory.h"
      14             : #include "mozilla/dom/HTMLFormSubmission.h"
      15             : #include "mozilla/dom/FileSystemUtils.h"
      16             : #include "mozilla/dom/GetFilesHelper.h"
      17             : #include "nsAttrValueInlines.h"
      18             : #include "nsCRTGlue.h"
      19             : 
      20             : #include "nsIDOMHTMLInputElement.h"
      21             : #include "nsITextControlElement.h"
      22             : #include "nsIDOMNSEditableElement.h"
      23             : #include "nsIRadioVisitor.h"
      24             : #include "InputType.h"
      25             : 
      26             : #include "HTMLFormSubmissionConstants.h"
      27             : #include "mozilla/Telemetry.h"
      28             : #include "nsIControllers.h"
      29             : #include "nsIStringBundle.h"
      30             : #include "nsFocusManager.h"
      31             : #include "nsColorControlFrame.h"
      32             : #include "nsNumberControlFrame.h"
      33             : #include "nsPIDOMWindow.h"
      34             : #include "nsRepeatService.h"
      35             : #include "nsContentCID.h"
      36             : #include "nsIComponentManager.h"
      37             : #include "nsIDOMHTMLFormElement.h"
      38             : #include "mozilla/dom/ProgressEvent.h"
      39             : #include "nsGkAtoms.h"
      40             : #include "nsStyleConsts.h"
      41             : #include "nsPresContext.h"
      42             : #include "nsMappedAttributes.h"
      43             : #include "nsIFormControl.h"
      44             : #include "nsIDocument.h"
      45             : #include "nsIPresShell.h"
      46             : #include "nsIFormControlFrame.h"
      47             : #include "nsITextControlFrame.h"
      48             : #include "nsIFrame.h"
      49             : #include "nsRangeFrame.h"
      50             : #include "nsIServiceManager.h"
      51             : #include "nsError.h"
      52             : #include "nsIEditor.h"
      53             : #include "nsDocument.h"
      54             : #include "nsAttrValueOrString.h"
      55             : #include "nsDateTimeControlFrame.h"
      56             : 
      57             : #include "nsPresState.h"
      58             : #include "nsIDOMEvent.h"
      59             : #include "nsIDOMNodeList.h"
      60             : #include "nsIDOMHTMLCollection.h"
      61             : #include "nsLinebreakConverter.h" //to strip out carriage returns
      62             : #include "nsReadableUtils.h"
      63             : #include "nsUnicharUtils.h"
      64             : #include "nsLayoutUtils.h"
      65             : #include "nsVariant.h"
      66             : 
      67             : #include "nsIDOMMutationEvent.h"
      68             : #include "mozilla/ContentEvents.h"
      69             : #include "mozilla/EventDispatcher.h"
      70             : #include "mozilla/EventStates.h"
      71             : #include "mozilla/GenericSpecifiedValuesInlines.h"
      72             : #include "mozilla/InternalMutationEvent.h"
      73             : #include "mozilla/TextEditor.h"
      74             : #include "mozilla/TextEvents.h"
      75             : #include "mozilla/TouchEvents.h"
      76             : 
      77             : #include <algorithm>
      78             : 
      79             : // input type=radio
      80             : #include "nsIRadioGroupContainer.h"
      81             : 
      82             : // input type=file
      83             : #include "mozilla/dom/FileSystemEntry.h"
      84             : #include "mozilla/dom/FileSystem.h"
      85             : #include "mozilla/dom/File.h"
      86             : #include "mozilla/dom/FileList.h"
      87             : #include "nsIFile.h"
      88             : #include "nsDirectoryServiceDefs.h"
      89             : #include "nsIContentPrefService.h"
      90             : #include "nsIMIMEService.h"
      91             : #include "nsIObserverService.h"
      92             : #include "nsIPopupWindowManager.h"
      93             : #include "nsGlobalWindow.h"
      94             : 
      95             : // input type=image
      96             : #include "nsImageLoadingContent.h"
      97             : #include "imgRequestProxy.h"
      98             : 
      99             : #include "mozAutoDocUpdate.h"
     100             : #include "nsContentCreatorFunctions.h"
     101             : #include "nsContentUtils.h"
     102             : #include "mozilla/dom/DirectionalityUtils.h"
     103             : #include "nsRadioVisitor.h"
     104             : #include "nsTextEditorState.h"
     105             : 
     106             : #include "mozilla/LookAndFeel.h"
     107             : #include "mozilla/Preferences.h"
     108             : #include "mozilla/MathAlgorithms.h"
     109             : 
     110             : #include "nsIIDNService.h"
     111             : 
     112             : #include <limits>
     113             : 
     114             : #include "nsIColorPicker.h"
     115             : #include "nsIStringEnumerator.h"
     116             : #include "HTMLSplitOnSpacesTokenizer.h"
     117             : #include "nsIController.h"
     118             : #include "nsIMIMEInfo.h"
     119             : #include "nsFrameSelection.h"
     120             : 
     121             : // input type=date
     122             : #include "js/Date.h"
     123             : 
     124          10 : NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Input)
     125             : 
     126             : // XXX align=left, hspace, vspace, border? other nav4 attrs
     127             : 
     128             : static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
     129             : 
     130             : namespace mozilla {
     131             : namespace dom {
     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             : #define NS_PRE_HANDLE_BLUR_EVENT  (1 << 13)
     142             : #define NS_PRE_HANDLE_INPUT_EVENT (1 << 14)
     143             : 
     144             : // whether textfields should be selected once focused:
     145             : //  -1: no, 1: yes, 0: uninitialized
     146             : static int32_t gSelectTextFieldOnFocus;
     147             : UploadLastDir* HTMLInputElement::gUploadLastDir;
     148             : 
     149             : static const nsAttrValue::EnumTable kInputTypeTable[] = {
     150             :   { "button", NS_FORM_INPUT_BUTTON },
     151             :   { "checkbox", NS_FORM_INPUT_CHECKBOX },
     152             :   { "color", NS_FORM_INPUT_COLOR },
     153             :   { "date", NS_FORM_INPUT_DATE },
     154             :   { "datetime-local", NS_FORM_INPUT_DATETIME_LOCAL },
     155             :   { "email", NS_FORM_INPUT_EMAIL },
     156             :   { "file", NS_FORM_INPUT_FILE },
     157             :   { "hidden", NS_FORM_INPUT_HIDDEN },
     158             :   { "reset", NS_FORM_INPUT_RESET },
     159             :   { "image", NS_FORM_INPUT_IMAGE },
     160             :   { "month", NS_FORM_INPUT_MONTH },
     161             :   { "number", NS_FORM_INPUT_NUMBER },
     162             :   { "password", NS_FORM_INPUT_PASSWORD },
     163             :   { "radio", NS_FORM_INPUT_RADIO },
     164             :   { "range", NS_FORM_INPUT_RANGE },
     165             :   { "search", NS_FORM_INPUT_SEARCH },
     166             :   { "submit", NS_FORM_INPUT_SUBMIT },
     167             :   { "tel", NS_FORM_INPUT_TEL },
     168             :   { "time", NS_FORM_INPUT_TIME },
     169             :   { "url", NS_FORM_INPUT_URL },
     170             :   { "week", NS_FORM_INPUT_WEEK },
     171             :   // "text" must be last for ParseAttribute to work right.  If you add things
     172             :   // before it, please update kInputDefaultType.
     173             :   { "text", NS_FORM_INPUT_TEXT },
     174             :   { nullptr, 0 }
     175             : };
     176             : 
     177             : // Default type is 'text'.
     178             : static const nsAttrValue::EnumTable* kInputDefaultType =
     179             :   &kInputTypeTable[ArrayLength(kInputTypeTable) - 2];
     180             : 
     181             : static const uint8_t NS_INPUT_INPUTMODE_AUTO              = 0;
     182             : static const uint8_t NS_INPUT_INPUTMODE_NUMERIC           = 1;
     183             : static const uint8_t NS_INPUT_INPUTMODE_DIGIT             = 2;
     184             : static const uint8_t NS_INPUT_INPUTMODE_UPPERCASE         = 3;
     185             : static const uint8_t NS_INPUT_INPUTMODE_LOWERCASE         = 4;
     186             : static const uint8_t NS_INPUT_INPUTMODE_TITLECASE         = 5;
     187             : static const uint8_t NS_INPUT_INPUTMODE_AUTOCAPITALIZED   = 6;
     188             : 
     189             : static const nsAttrValue::EnumTable kInputInputmodeTable[] = {
     190             :   { "auto", NS_INPUT_INPUTMODE_AUTO },
     191             :   { "numeric", NS_INPUT_INPUTMODE_NUMERIC },
     192             :   { "digit", NS_INPUT_INPUTMODE_DIGIT },
     193             :   { "uppercase", NS_INPUT_INPUTMODE_UPPERCASE },
     194             :   { "lowercase", NS_INPUT_INPUTMODE_LOWERCASE },
     195             :   { "titlecase", NS_INPUT_INPUTMODE_TITLECASE },
     196             :   { "autocapitalized", NS_INPUT_INPUTMODE_AUTOCAPITALIZED },
     197             :   { nullptr, 0 }
     198             : };
     199             : 
     200             : // Default inputmode value is "auto".
     201             : static const nsAttrValue::EnumTable* kInputDefaultInputmode = &kInputInputmodeTable[0];
     202             : 
     203           3 : const Decimal HTMLInputElement::kStepScaleFactorDate = Decimal(86400000);
     204           3 : const Decimal HTMLInputElement::kStepScaleFactorNumberRange = Decimal(1);
     205           3 : const Decimal HTMLInputElement::kStepScaleFactorTime = Decimal(1000);
     206           3 : const Decimal HTMLInputElement::kStepScaleFactorMonth = Decimal(1);
     207           3 : const Decimal HTMLInputElement::kStepScaleFactorWeek = Decimal(7 * 86400000);
     208           3 : const Decimal HTMLInputElement::kDefaultStepBase = Decimal(0);
     209           3 : const Decimal HTMLInputElement::kDefaultStepBaseWeek = Decimal(-259200000);
     210           3 : const Decimal HTMLInputElement::kDefaultStep = Decimal(1);
     211           3 : const Decimal HTMLInputElement::kDefaultStepTime = Decimal(60);
     212           3 : const Decimal HTMLInputElement::kStepAny = Decimal(0);
     213             : 
     214             : const double HTMLInputElement::kMinimumYear = 1;
     215             : const double HTMLInputElement::kMaximumYear = 275760;
     216             : const double HTMLInputElement::kMaximumWeekInMaximumYear = 37;
     217             : const double HTMLInputElement::kMaximumDayInMaximumYear = 13;
     218             : const double HTMLInputElement::kMaximumMonthInMaximumYear = 9;
     219             : const double HTMLInputElement::kMaximumWeekInYear = 53;
     220             : const double HTMLInputElement::kMsPerDay = 24 * 60 * 60 * 1000;
     221             : 
     222             : #define NS_INPUT_ELEMENT_STATE_IID                 \
     223             : { /* dc3b3d14-23e2-4479-b513-7b369343e3a0 */       \
     224             :   0xdc3b3d14,                                      \
     225             :   0x23e2,                                          \
     226             :   0x4479,                                          \
     227             :   {0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \
     228             : }
     229             : 
     230             : #define PROGRESS_STR "progress"
     231             : static const uint32_t kProgressEventInterval = 50; // ms
     232             : 
     233             : // An helper class for the dispatching of the 'change' event.
     234             : // This class is used when the FilePicker finished its task (or when files and
     235             : // directories are set by some chrome/test only method).
     236             : // The task of this class is to postpone the dispatching of 'change' and 'input'
     237             : // events at the end of the exploration of the directories.
     238           0 : class DispatchChangeEventCallback final : public GetFilesCallback
     239             : {
     240             : public:
     241           0 :   explicit DispatchChangeEventCallback(HTMLInputElement* aInputElement)
     242           0 :     : mInputElement(aInputElement)
     243             :   {
     244           0 :     MOZ_ASSERT(aInputElement);
     245           0 :   }
     246             : 
     247             :   virtual void
     248           0 :   Callback(nsresult aStatus, const Sequence<RefPtr<File>>& aFiles) override
     249             :   {
     250           0 :     nsTArray<OwningFileOrDirectory> array;
     251           0 :     for (uint32_t i = 0; i < aFiles.Length(); ++i) {
     252           0 :       OwningFileOrDirectory* element = array.AppendElement();
     253           0 :       element->SetAsFile() = aFiles[i];
     254             :     }
     255             : 
     256           0 :     mInputElement->SetFilesOrDirectories(array, true);
     257           0 :     Unused << NS_WARN_IF(NS_FAILED(DispatchEvents()));
     258           0 :   }
     259             : 
     260             :   nsresult
     261           0 :   DispatchEvents()
     262             :   {
     263           0 :     nsresult rv = NS_OK;
     264           0 :     rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
     265           0 :                                               static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),
     266           0 :                                               NS_LITERAL_STRING("input"), true,
     267           0 :                                               false);
     268           0 :     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "DispatchTrustedEvent failed");
     269             : 
     270           0 :     rv = nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),
     271           0 :                                               static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),
     272           0 :                                               NS_LITERAL_STRING("change"), true,
     273           0 :                                               false);
     274             : 
     275           0 :     return rv;
     276             :   }
     277             : 
     278             : private:
     279             :   RefPtr<HTMLInputElement> mInputElement;
     280             : };
     281             : 
     282             : class HTMLInputElementState final : public nsISupports
     283             : {
     284             :   public:
     285             :     NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPUT_ELEMENT_STATE_IID)
     286             :     NS_DECL_ISUPPORTS
     287             : 
     288           0 :     bool IsCheckedSet()
     289             :     {
     290           0 :       return mCheckedSet;
     291             :     }
     292             : 
     293           0 :     bool GetChecked()
     294             :     {
     295           0 :       return mChecked;
     296             :     }
     297             : 
     298           0 :     void SetChecked(bool aChecked)
     299             :     {
     300           0 :       mChecked = aChecked;
     301           0 :       mCheckedSet = true;
     302           0 :     }
     303             : 
     304           0 :     const nsString& GetValue()
     305             :     {
     306           0 :       return mValue;
     307             :     }
     308             : 
     309           0 :     void SetValue(const nsAString& aValue)
     310             :     {
     311           0 :       mValue = aValue;
     312           0 :     }
     313             : 
     314             :     void
     315           0 :     GetFilesOrDirectories(nsPIDOMWindowInner* aWindow,
     316             :                           nsTArray<OwningFileOrDirectory>& aResult) const
     317             :     {
     318           0 :       for (uint32_t i = 0; i < mBlobImplsOrDirectoryPaths.Length(); ++i) {
     319           0 :         if (mBlobImplsOrDirectoryPaths[i].mType == BlobImplOrDirectoryPath::eBlobImpl) {
     320             :           RefPtr<File> file =
     321             :             File::Create(aWindow,
     322           0 :                          mBlobImplsOrDirectoryPaths[i].mBlobImpl);
     323           0 :           MOZ_ASSERT(file);
     324             : 
     325           0 :           OwningFileOrDirectory* element = aResult.AppendElement();
     326           0 :           element->SetAsFile() = file;
     327             :         } else {
     328           0 :           MOZ_ASSERT(mBlobImplsOrDirectoryPaths[i].mType == BlobImplOrDirectoryPath::eDirectoryPath);
     329             : 
     330           0 :           nsCOMPtr<nsIFile> file;
     331             :           nsresult rv =
     332           0 :             NS_NewLocalFile(mBlobImplsOrDirectoryPaths[i].mDirectoryPath,
     333           0 :                             true, getter_AddRefs(file));
     334           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
     335           0 :             continue;
     336             :           }
     337             : 
     338           0 :           RefPtr<Directory> directory = Directory::Create(aWindow, file);
     339           0 :           MOZ_ASSERT(directory);
     340             : 
     341           0 :           OwningFileOrDirectory* element = aResult.AppendElement();
     342           0 :           element->SetAsDirectory() = directory;
     343             :         }
     344             :       }
     345           0 :     }
     346             : 
     347           0 :     void SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aArray)
     348             :     {
     349           0 :       mBlobImplsOrDirectoryPaths.Clear();
     350           0 :       for (uint32_t i = 0; i < aArray.Length(); ++i) {
     351           0 :         if (aArray[i].IsFile()) {
     352           0 :           BlobImplOrDirectoryPath* data = mBlobImplsOrDirectoryPaths.AppendElement();
     353             : 
     354           0 :           data->mBlobImpl = aArray[i].GetAsFile()->Impl();
     355           0 :           data->mType = BlobImplOrDirectoryPath::eBlobImpl;
     356             :         } else {
     357           0 :           MOZ_ASSERT(aArray[i].IsDirectory());
     358           0 :           nsAutoString fullPath;
     359           0 :           nsresult rv = aArray[i].GetAsDirectory()->GetFullRealPath(fullPath);
     360           0 :           if (NS_WARN_IF(NS_FAILED(rv))) {
     361           0 :             continue;
     362             :           }
     363             : 
     364             :           BlobImplOrDirectoryPath* data =
     365           0 :             mBlobImplsOrDirectoryPaths.AppendElement();
     366             : 
     367           0 :           data->mDirectoryPath = fullPath;
     368           0 :           data->mType = BlobImplOrDirectoryPath::eDirectoryPath;
     369             :         }
     370             :       }
     371           0 :     }
     372             : 
     373           0 :     HTMLInputElementState()
     374           0 :       : mValue()
     375             :       , mChecked(false)
     376           0 :       , mCheckedSet(false)
     377           0 :     {}
     378             : 
     379             :   protected:
     380           0 :     ~HTMLInputElementState() {}
     381             : 
     382             :     nsString mValue;
     383             : 
     384           0 :     struct BlobImplOrDirectoryPath
     385             :     {
     386             :       RefPtr<BlobImpl> mBlobImpl;
     387             :       nsString mDirectoryPath;
     388             : 
     389             :       enum {
     390             :         eBlobImpl,
     391             :         eDirectoryPath
     392             :       } mType;
     393             :     };
     394             : 
     395             :     nsTArray<BlobImplOrDirectoryPath> mBlobImplsOrDirectoryPaths;
     396             : 
     397             :     bool mChecked;
     398             :     bool mCheckedSet;
     399             : };
     400             : 
     401             : NS_DEFINE_STATIC_IID_ACCESSOR(HTMLInputElementState, NS_INPUT_ELEMENT_STATE_IID)
     402             : 
     403           0 : NS_IMPL_ISUPPORTS(HTMLInputElementState, HTMLInputElementState)
     404             : 
     405           0 : struct HTMLInputElement::FileData
     406             : {
     407             :   /**
     408             :    * The value of the input if it is a file input. This is the list of files or
     409             :    * directories DOM objects used when uploading a file. It is vital that this
     410             :    * is kept separate from mValue so that it won't be possible to 'leak' the
     411             :    * value from a text-input to a file-input. Additionally, the logic for this
     412             :    * value is kept as simple as possible to avoid accidental errors where the
     413             :    * wrong filename is used.  Therefor the list of filenames is always owned by
     414             :    * this member, never by the frame. Whenever the frame wants to change the
     415             :    * filename it has to call SetFilesOrDirectories to update this member.
     416             :    */
     417             :   nsTArray<OwningFileOrDirectory> mFilesOrDirectories;
     418             : 
     419             :   RefPtr<GetFilesHelper> mGetFilesRecursiveHelper;
     420             :   RefPtr<GetFilesHelper> mGetFilesNonRecursiveHelper;
     421             : 
     422             :   /**
     423             :    * Hack for bug 1086684: Stash the .value when we're a file picker.
     424             :    */
     425             :   nsString mFirstFilePath;
     426             : 
     427             :   RefPtr<FileList> mFileList;
     428             :   Sequence<RefPtr<FileSystemEntry>> mEntries;
     429             : 
     430             :   nsString mStaticDocFileList;
     431             : 
     432           0 :   void ClearGetFilesHelpers()
     433             :   {
     434           0 :     if (mGetFilesRecursiveHelper) {
     435           0 :       mGetFilesRecursiveHelper->Unlink();
     436           0 :       mGetFilesRecursiveHelper = nullptr;
     437             :     }
     438             : 
     439           0 :     if (mGetFilesNonRecursiveHelper) {
     440           0 :       mGetFilesNonRecursiveHelper->Unlink();
     441           0 :       mGetFilesNonRecursiveHelper = nullptr;
     442             :     }
     443           0 :   }
     444             : 
     445             :   // Cycle Collection support.
     446           0 :   void Traverse(nsCycleCollectionTraversalCallback &cb)
     447             :   {
     448           0 :     FileData* tmp = this;
     449           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesOrDirectories)
     450           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)
     451           0 :     NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEntries)
     452           0 :     if (mGetFilesRecursiveHelper) {
     453           0 :       mGetFilesRecursiveHelper->Traverse(cb);
     454             :     }
     455             : 
     456           0 :     if (mGetFilesNonRecursiveHelper) {
     457           0 :       mGetFilesNonRecursiveHelper->Traverse(cb);
     458             :     }
     459           0 :   }
     460             : 
     461           0 :   void Unlink()
     462             :   {
     463           0 :     FileData* tmp = this;
     464           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesOrDirectories)
     465           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)
     466           0 :     NS_IMPL_CYCLE_COLLECTION_UNLINK(mEntries)
     467           0 :     ClearGetFilesHelpers();
     468           0 :   }
     469             : };
     470             : 
     471           0 : HTMLInputElement::nsFilePickerShownCallback::nsFilePickerShownCallback(
     472           0 :   HTMLInputElement* aInput, nsIFilePicker* aFilePicker)
     473             :   : mFilePicker(aFilePicker)
     474           0 :   , mInput(aInput)
     475             : {
     476           0 : }
     477             : 
     478           0 : NS_IMPL_ISUPPORTS(UploadLastDir::ContentPrefCallback, nsIContentPrefCallback2)
     479             : 
     480             : NS_IMETHODIMP
     481           0 : UploadLastDir::ContentPrefCallback::HandleCompletion(uint16_t aReason)
     482             : {
     483           0 :   nsCOMPtr<nsIFile> localFile;
     484           0 :   nsAutoString prefStr;
     485             : 
     486           0 :   if (aReason == nsIContentPrefCallback2::COMPLETE_ERROR || !mResult) {
     487           0 :     prefStr = Preferences::GetString("dom.input.fallbackUploadDir");
     488             :   }
     489             : 
     490           0 :   if (prefStr.IsEmpty() && mResult) {
     491           0 :     nsCOMPtr<nsIVariant> pref;
     492           0 :     mResult->GetValue(getter_AddRefs(pref));
     493           0 :     pref->GetAsAString(prefStr);
     494             :   }
     495             : 
     496           0 :   if (!prefStr.IsEmpty()) {
     497           0 :     localFile = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
     498           0 :     if (localFile && NS_WARN_IF(NS_FAILED(localFile->InitWithPath(prefStr)))) {
     499           0 :       localFile = nullptr;
     500             :     }
     501             :   }
     502             : 
     503           0 :   if (localFile) {
     504           0 :     mFilePicker->SetDisplayDirectory(localFile);
     505             :   } else {
     506             :     // If no custom directory was set through the pref, default to
     507             :     // "desktop" directory for each platform.
     508           0 :     mFilePicker->SetDisplaySpecialDirectory(NS_LITERAL_STRING(NS_OS_DESKTOP_DIR));
     509             :   }
     510             : 
     511           0 :   mFilePicker->Open(mFpCallback);
     512           0 :   return NS_OK;
     513             : }
     514             : 
     515             : NS_IMETHODIMP
     516           0 : UploadLastDir::ContentPrefCallback::HandleResult(nsIContentPref* pref)
     517             : {
     518           0 :   mResult = pref;
     519           0 :   return NS_OK;
     520             : }
     521             : 
     522             : NS_IMETHODIMP
     523           0 : UploadLastDir::ContentPrefCallback::HandleError(nsresult error)
     524             : {
     525             :   // HandleCompletion is always called (even with HandleError was called),
     526             :   // so we don't need to do anything special here.
     527           0 :   return NS_OK;
     528             : }
     529             : 
     530             : namespace {
     531             : 
     532             : /**
     533             :  * This may return nullptr if the DOM File's implementation of
     534             :  * File::mozFullPathInternal does not successfully return a non-empty
     535             :  * string that is a valid path. This can happen on Firefox OS, for example,
     536             :  * where the file picker can create Blobs.
     537             :  */
     538             : static already_AddRefed<nsIFile>
     539           0 : LastUsedDirectory(const OwningFileOrDirectory& aData)
     540             : {
     541           0 :   if (aData.IsFile()) {
     542           0 :     nsAutoString path;
     543           0 :     ErrorResult error;
     544           0 :     aData.GetAsFile()->GetMozFullPathInternal(path, error);
     545           0 :     if (error.Failed() || path.IsEmpty()) {
     546           0 :       error.SuppressException();
     547           0 :       return nullptr;
     548             :     }
     549             : 
     550           0 :     nsCOMPtr<nsIFile> localFile;
     551           0 :     nsresult rv = NS_NewLocalFile(path, true, getter_AddRefs(localFile));
     552           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     553           0 :       return nullptr;
     554             :     }
     555             : 
     556           0 :     nsCOMPtr<nsIFile> parentFile;
     557           0 :     rv = localFile->GetParent(getter_AddRefs(parentFile));
     558           0 :     if (NS_WARN_IF(NS_FAILED(rv))) {
     559           0 :       return nullptr;
     560             :     }
     561             : 
     562           0 :     return parentFile.forget();
     563             :   }
     564             : 
     565           0 :   MOZ_ASSERT(aData.IsDirectory());
     566             : 
     567           0 :   nsCOMPtr<nsIFile> localFile = aData.GetAsDirectory()->GetInternalNsIFile();
     568           0 :   MOZ_ASSERT(localFile);
     569             : 
     570           0 :   return localFile.forget();
     571             : }
     572             : 
     573             : void
     574           0 : GetDOMFileOrDirectoryName(const OwningFileOrDirectory& aData,
     575             :                           nsAString& aName)
     576             : {
     577           0 :   if (aData.IsFile()) {
     578           0 :     aData.GetAsFile()->GetName(aName);
     579             :   } else {
     580           0 :     MOZ_ASSERT(aData.IsDirectory());
     581           0 :     ErrorResult rv;
     582           0 :     aData.GetAsDirectory()->GetName(aName, rv);
     583           0 :     if (NS_WARN_IF(rv.Failed())) {
     584           0 :       rv.SuppressException();
     585             :     }
     586             :   }
     587           0 : }
     588             : 
     589             : void
     590           0 : GetDOMFileOrDirectoryPath(const OwningFileOrDirectory& aData,
     591             :                           nsAString& aPath,
     592             :                           ErrorResult& aRv)
     593             : {
     594           0 :   if (aData.IsFile()) {
     595           0 :     aData.GetAsFile()->GetMozFullPathInternal(aPath, aRv);
     596             :   } else {
     597           0 :     MOZ_ASSERT(aData.IsDirectory());
     598           0 :     aData.GetAsDirectory()->GetFullRealPath(aPath);
     599             :   }
     600           0 : }
     601             : 
     602             : } // namespace
     603             : 
     604             : /* static */
     605             : bool
     606           1 : HTMLInputElement::ValueAsDateEnabled(JSContext* cx, JSObject* obj)
     607             : {
     608           1 :   return IsExperimentalFormsEnabled() || IsInputDateTimeEnabled() ||
     609           1 :     IsInputDateTimeOthersEnabled();
     610             : }
     611             : 
     612             : NS_IMETHODIMP
     613           0 : HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
     614             : {
     615           0 :   mInput->PickerClosed();
     616             : 
     617           0 :   if (aResult == nsIFilePicker::returnCancel) {
     618           0 :     return NS_OK;
     619             :   }
     620             : 
     621             :   int16_t mode;
     622           0 :   mFilePicker->GetMode(&mode);
     623             : 
     624             :   // Collect new selected filenames
     625           0 :   nsTArray<OwningFileOrDirectory> newFilesOrDirectories;
     626           0 :   if (mode == static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)) {
     627           0 :     nsCOMPtr<nsISimpleEnumerator> iter;
     628             :     nsresult rv =
     629           0 :       mFilePicker->GetDomFileOrDirectoryEnumerator(getter_AddRefs(iter));
     630           0 :     NS_ENSURE_SUCCESS(rv, rv);
     631             : 
     632           0 :     if (!iter) {
     633           0 :       return NS_OK;
     634             :     }
     635             : 
     636           0 :     nsCOMPtr<nsISupports> tmp;
     637           0 :     bool hasMore = true;
     638             : 
     639           0 :     while (NS_SUCCEEDED(iter->HasMoreElements(&hasMore)) && hasMore) {
     640           0 :       iter->GetNext(getter_AddRefs(tmp));
     641           0 :       nsCOMPtr<nsIDOMBlob> domBlob = do_QueryInterface(tmp);
     642           0 :       MOZ_ASSERT(domBlob,
     643             :                  "Null file object from FilePicker's file enumerator?");
     644           0 :       if (!domBlob) {
     645           0 :         continue;
     646             :       }
     647             : 
     648           0 :       OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
     649           0 :       element->SetAsFile() = static_cast<File*>(domBlob.get());
     650             :     }
     651             :   } else {
     652           0 :     MOZ_ASSERT(mode == static_cast<int16_t>(nsIFilePicker::modeOpen) ||
     653             :                mode == static_cast<int16_t>(nsIFilePicker::modeGetFolder));
     654           0 :     nsCOMPtr<nsISupports> tmp;
     655           0 :     nsresult rv = mFilePicker->GetDomFileOrDirectory(getter_AddRefs(tmp));
     656           0 :     NS_ENSURE_SUCCESS(rv, rv);
     657             : 
     658           0 :     nsCOMPtr<nsIDOMBlob> blob = do_QueryInterface(tmp);
     659           0 :     if (blob) {
     660           0 :       RefPtr<File> file = static_cast<Blob*>(blob.get())->ToFile();
     661           0 :       MOZ_ASSERT(file);
     662             : 
     663           0 :       OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
     664           0 :       element->SetAsFile() = file;
     665           0 :     } else if (tmp) {
     666           0 :       RefPtr<Directory> directory = static_cast<Directory*>(tmp.get());
     667           0 :       OwningFileOrDirectory* element = newFilesOrDirectories.AppendElement();
     668           0 :       element->SetAsDirectory() = directory;
     669             :     }
     670             :   }
     671             : 
     672           0 :   if (newFilesOrDirectories.IsEmpty()) {
     673           0 :     return NS_OK;
     674             :   }
     675             : 
     676             :   // Store the last used directory using the content pref service:
     677           0 :   nsCOMPtr<nsIFile> lastUsedDir = LastUsedDirectory(newFilesOrDirectories[0]);
     678             : 
     679           0 :   if (lastUsedDir) {
     680           0 :     HTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(
     681           0 :       mInput->OwnerDoc(), lastUsedDir);
     682             :   }
     683             : 
     684             :   // The text control frame (if there is one) isn't going to send a change
     685             :   // event because it will think this is done by a script.
     686             :   // So, we can safely send one by ourself.
     687           0 :   mInput->SetFilesOrDirectories(newFilesOrDirectories, true);
     688             : 
     689             :   RefPtr<DispatchChangeEventCallback> dispatchChangeEventCallback =
     690           0 :     new DispatchChangeEventCallback(mInput);
     691             : 
     692           0 :   if (IsWebkitDirPickerEnabled() &&
     693           0 :       mInput->HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)) {
     694           0 :     ErrorResult error;
     695           0 :     GetFilesHelper* helper = mInput->GetOrCreateGetFilesHelper(true, error);
     696           0 :     if (NS_WARN_IF(error.Failed())) {
     697           0 :       return error.StealNSResult();
     698             :     }
     699             : 
     700           0 :     helper->AddCallback(dispatchChangeEventCallback);
     701           0 :     return NS_OK;
     702             :   }
     703             : 
     704           0 :   return dispatchChangeEventCallback->DispatchEvents();
     705             : }
     706             : 
     707           0 : NS_IMPL_ISUPPORTS(HTMLInputElement::nsFilePickerShownCallback,
     708             :                   nsIFilePickerShownCallback)
     709             : 
     710             : class nsColorPickerShownCallback final
     711             :   : public nsIColorPickerShownCallback
     712             : {
     713           0 :   ~nsColorPickerShownCallback() {}
     714             : 
     715             : public:
     716           0 :   nsColorPickerShownCallback(HTMLInputElement* aInput,
     717             :                              nsIColorPicker* aColorPicker)
     718           0 :     : mInput(aInput)
     719             :     , mColorPicker(aColorPicker)
     720           0 :     , mValueChanged(false)
     721           0 :   {}
     722             : 
     723             :   NS_DECL_ISUPPORTS
     724             : 
     725             :   NS_IMETHOD Update(const nsAString& aColor) override;
     726             :   NS_IMETHOD Done(const nsAString& aColor) override;
     727             : 
     728             : private:
     729             :   /**
     730             :    * Updates the internals of the object using aColor as the new value.
     731             :    * If aTrustedUpdate is true, it will consider that aColor is a new value.
     732             :    * Otherwise, it will check that aColor is different from the current value.
     733             :    */
     734             :   nsresult UpdateInternal(const nsAString& aColor, bool aTrustedUpdate);
     735             : 
     736             :   RefPtr<HTMLInputElement> mInput;
     737             :   nsCOMPtr<nsIColorPicker>   mColorPicker;
     738             :   bool                       mValueChanged;
     739             : };
     740             : 
     741             : nsresult
     742           0 : nsColorPickerShownCallback::UpdateInternal(const nsAString& aColor,
     743             :                                            bool aTrustedUpdate)
     744             : {
     745           0 :   bool valueChanged = false;
     746             : 
     747           0 :   nsAutoString oldValue;
     748           0 :   if (aTrustedUpdate) {
     749           0 :     valueChanged = true;
     750             :   } else {
     751           0 :     mInput->GetValue(oldValue, CallerType::System);
     752             :   }
     753             : 
     754           0 :   IgnoredErrorResult rv;
     755           0 :   mInput->SetValue(aColor, CallerType::System, rv);
     756             : 
     757           0 :   if (!aTrustedUpdate) {
     758           0 :     nsAutoString newValue;
     759           0 :     mInput->GetValue(newValue, CallerType::System);
     760           0 :     if (!oldValue.Equals(newValue)) {
     761           0 :       valueChanged = true;
     762             :     }
     763             :   }
     764             : 
     765           0 :   if (valueChanged) {
     766           0 :     mValueChanged = true;
     767           0 :     return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
     768           0 :                                                 static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
     769           0 :                                                 NS_LITERAL_STRING("input"), true,
     770           0 :                                                 false);
     771             :   }
     772             : 
     773           0 :   return NS_OK;
     774             : }
     775             : 
     776             : NS_IMETHODIMP
     777           0 : nsColorPickerShownCallback::Update(const nsAString& aColor)
     778             : {
     779           0 :   return UpdateInternal(aColor, true);
     780             : }
     781             : 
     782             : NS_IMETHODIMP
     783           0 : nsColorPickerShownCallback::Done(const nsAString& aColor)
     784             : {
     785             :   /**
     786             :    * When Done() is called, we might be at the end of a serie of Update() calls
     787             :    * in which case mValueChanged is set to true and a change event will have to
     788             :    * be fired but we might also be in a one shot Done() call situation in which
     789             :    * case we should fire a change event iif the value actually changed.
     790             :    * UpdateInternal(bool) is taking care of that logic for us.
     791             :    */
     792           0 :   nsresult rv = NS_OK;
     793             : 
     794           0 :   mInput->PickerClosed();
     795             : 
     796           0 :   if (!aColor.IsEmpty()) {
     797           0 :     UpdateInternal(aColor, false);
     798             :   }
     799             : 
     800           0 :   if (mValueChanged) {
     801           0 :     rv = nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
     802           0 :                                               static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
     803           0 :                                               NS_LITERAL_STRING("change"), true,
     804           0 :                                               false);
     805             :   }
     806             : 
     807           0 :   return rv;
     808             : }
     809             : 
     810           0 : NS_IMPL_ISUPPORTS(nsColorPickerShownCallback, nsIColorPickerShownCallback)
     811             : 
     812             : bool
     813           0 : HTMLInputElement::IsPopupBlocked() const
     814             : {
     815           0 :   nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
     816           0 :   MOZ_ASSERT(win, "window should not be null");
     817           0 :   if (!win) {
     818           0 :     return true;
     819             :   }
     820             : 
     821             :   // Check if page is allowed to open the popup
     822           0 :   if (win->GetPopupControlState() <= openControlled) {
     823           0 :     return false;
     824             :   }
     825             : 
     826           0 :   nsCOMPtr<nsIPopupWindowManager> pm = do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);
     827           0 :   if (!pm) {
     828           0 :     return true;
     829             :   }
     830             : 
     831             :   uint32_t permission;
     832           0 :   pm->TestPermission(OwnerDoc()->NodePrincipal(), &permission);
     833           0 :   return permission == nsIPopupWindowManager::DENY_POPUP;
     834             : }
     835             : 
     836             : nsresult
     837           0 : HTMLInputElement::InitColorPicker()
     838             : {
     839           0 :   if (mPickerRunning) {
     840           0 :     NS_WARNING("Just one nsIColorPicker is allowed");
     841           0 :     return NS_ERROR_FAILURE;
     842             :   }
     843             : 
     844           0 :   nsCOMPtr<nsIDocument> doc = OwnerDoc();
     845             : 
     846           0 :   nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
     847           0 :   if (!win) {
     848           0 :     return NS_ERROR_FAILURE;
     849             :   }
     850             : 
     851           0 :   if (IsPopupBlocked()) {
     852           0 :     win->FirePopupBlockedEvent(doc, nullptr, EmptyString(), EmptyString());
     853           0 :     return NS_OK;
     854             :   }
     855             : 
     856             :   // Get Loc title
     857           0 :   nsXPIDLString title;
     858             :   nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
     859           0 :                                      "ColorPicker", title);
     860             : 
     861           0 :   nsCOMPtr<nsIColorPicker> colorPicker = do_CreateInstance("@mozilla.org/colorpicker;1");
     862           0 :   if (!colorPicker) {
     863           0 :     return NS_ERROR_FAILURE;
     864             :   }
     865             : 
     866           0 :   nsAutoString initialValue;
     867           0 :   GetNonFileValueInternal(initialValue);
     868           0 :   nsresult rv = colorPicker->Init(win, title, initialValue);
     869           0 :   NS_ENSURE_SUCCESS(rv, rv);
     870             : 
     871             :   nsCOMPtr<nsIColorPickerShownCallback> callback =
     872           0 :     new nsColorPickerShownCallback(this, colorPicker);
     873             : 
     874           0 :   rv = colorPicker->Open(callback);
     875           0 :   if (NS_SUCCEEDED(rv)) {
     876           0 :     mPickerRunning = true;
     877             :   }
     878             : 
     879           0 :   return rv;
     880             : }
     881             : 
     882             : nsresult
     883           0 : HTMLInputElement::InitFilePicker(FilePickerType aType)
     884             : {
     885           0 :   if (mPickerRunning) {
     886           0 :     NS_WARNING("Just one nsIFilePicker is allowed");
     887           0 :     return NS_ERROR_FAILURE;
     888             :   }
     889             : 
     890             :   // Get parent nsPIDOMWindow object.
     891           0 :   nsCOMPtr<nsIDocument> doc = OwnerDoc();
     892             : 
     893           0 :   nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
     894           0 :   if (!win) {
     895           0 :     return NS_ERROR_FAILURE;
     896             :   }
     897             : 
     898           0 :   if (IsPopupBlocked()) {
     899           0 :     win->FirePopupBlockedEvent(doc, nullptr, EmptyString(), EmptyString());
     900           0 :     return NS_OK;
     901             :   }
     902             : 
     903             :   // Get Loc title
     904           0 :   nsXPIDLString title;
     905           0 :   nsXPIDLString okButtonLabel;
     906           0 :   if (aType == FILE_PICKER_DIRECTORY) {
     907             :     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
     908           0 :                                        "DirectoryUpload", title);
     909             : 
     910             :     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
     911             :                                        "DirectoryPickerOkButtonLabel",
     912           0 :                                        okButtonLabel);
     913             :   } else {
     914             :     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
     915           0 :                                        "FileUpload", title);
     916             :   }
     917             : 
     918           0 :   nsCOMPtr<nsIFilePicker> filePicker = do_CreateInstance("@mozilla.org/filepicker;1");
     919           0 :   if (!filePicker)
     920           0 :     return NS_ERROR_FAILURE;
     921             : 
     922             :   int16_t mode;
     923             : 
     924           0 :   if (aType == FILE_PICKER_DIRECTORY) {
     925           0 :     mode = static_cast<int16_t>(nsIFilePicker::modeGetFolder);
     926           0 :   } else if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
     927           0 :     mode = static_cast<int16_t>(nsIFilePicker::modeOpenMultiple);
     928             :   } else {
     929           0 :     mode = static_cast<int16_t>(nsIFilePicker::modeOpen);
     930             :   }
     931             : 
     932           0 :   nsresult rv = filePicker->Init(win, title, mode);
     933           0 :   NS_ENSURE_SUCCESS(rv, rv);
     934             : 
     935           0 :   if (!okButtonLabel.IsEmpty()) {
     936           0 :     filePicker->SetOkButtonLabel(okButtonLabel);
     937             :   }
     938             : 
     939             :   // Native directory pickers ignore file type filters, so we don't spend
     940             :   // cycles adding them for FILE_PICKER_DIRECTORY.
     941           0 :   if (HasAttr(kNameSpaceID_None, nsGkAtoms::accept) &&
     942             :       aType != FILE_PICKER_DIRECTORY) {
     943           0 :     SetFilePickerFiltersFromAccept(filePicker);
     944             :   } else {
     945           0 :     filePicker->AppendFilters(nsIFilePicker::filterAll);
     946             :   }
     947             : 
     948             :   // Set default directory and filename
     949           0 :   nsAutoString defaultName;
     950             : 
     951             :   const nsTArray<OwningFileOrDirectory>& oldFiles =
     952           0 :     GetFilesOrDirectoriesInternal();
     953             : 
     954             :   nsCOMPtr<nsIFilePickerShownCallback> callback =
     955           0 :     new HTMLInputElement::nsFilePickerShownCallback(this, filePicker);
     956             : 
     957           0 :   if (!oldFiles.IsEmpty() &&
     958             :       aType != FILE_PICKER_DIRECTORY) {
     959           0 :     nsAutoString path;
     960             : 
     961           0 :     nsCOMPtr<nsIFile> parentFile = LastUsedDirectory(oldFiles[0]);
     962           0 :     if (parentFile) {
     963           0 :       filePicker->SetDisplayDirectory(parentFile);
     964             :     }
     965             : 
     966             :     // Unfortunately nsIFilePicker doesn't allow multiple files to be
     967             :     // default-selected, so only select something by default if exactly
     968             :     // one file was selected before.
     969           0 :     if (oldFiles.Length() == 1) {
     970           0 :       nsAutoString leafName;
     971           0 :       GetDOMFileOrDirectoryName(oldFiles[0], leafName);
     972             : 
     973           0 :       if (!leafName.IsEmpty()) {
     974           0 :         filePicker->SetDefaultString(leafName);
     975             :       }
     976             :     }
     977             : 
     978           0 :     rv = filePicker->Open(callback);
     979           0 :     if (NS_SUCCEEDED(rv)) {
     980           0 :       mPickerRunning = true;
     981             :     }
     982             : 
     983           0 :     return rv;
     984             :   }
     985             : 
     986           0 :   HTMLInputElement::gUploadLastDir->FetchDirectoryAndDisplayPicker(doc, filePicker, callback);
     987           0 :   mPickerRunning = true;
     988           0 :   return NS_OK;
     989             : }
     990             : 
     991             : #define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")
     992             : 
     993           4 : NS_IMPL_ISUPPORTS(UploadLastDir, nsIObserver, nsISupportsWeakReference)
     994             : 
     995             : void
     996           1 : HTMLInputElement::InitUploadLastDir() {
     997           1 :   gUploadLastDir = new UploadLastDir();
     998           1 :   NS_ADDREF(gUploadLastDir);
     999             : 
    1000             :   nsCOMPtr<nsIObserverService> observerService =
    1001           2 :     mozilla::services::GetObserverService();
    1002           1 :   if (observerService && gUploadLastDir) {
    1003           1 :     observerService->AddObserver(gUploadLastDir, "browser:purge-session-history", true);
    1004             :   }
    1005           1 : }
    1006             : 
    1007             : void
    1008           0 : HTMLInputElement::DestroyUploadLastDir() {
    1009           0 :   NS_IF_RELEASE(gUploadLastDir);
    1010           0 : }
    1011             : 
    1012             : nsresult
    1013           0 : UploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument* aDoc,
    1014             :                                               nsIFilePicker* aFilePicker,
    1015             :                                               nsIFilePickerShownCallback* aFpCallback)
    1016             : {
    1017           0 :   NS_PRECONDITION(aDoc, "aDoc is null");
    1018           0 :   NS_PRECONDITION(aFilePicker, "aFilePicker is null");
    1019           0 :   NS_PRECONDITION(aFpCallback, "aFpCallback is null");
    1020             : 
    1021           0 :   nsIURI* docURI = aDoc->GetDocumentURI();
    1022           0 :   NS_PRECONDITION(docURI, "docURI is null");
    1023             : 
    1024           0 :   nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
    1025             :   nsCOMPtr<nsIContentPrefCallback2> prefCallback =
    1026           0 :     new UploadLastDir::ContentPrefCallback(aFilePicker, aFpCallback);
    1027             : 
    1028             : #ifdef MOZ_B2G
    1029             :   if (XRE_IsContentProcess()) {
    1030             :     prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
    1031             :     return NS_OK;
    1032             :   }
    1033             : #endif
    1034             : 
    1035             :   // Attempt to get the CPS, if it's not present we'll fallback to use the Desktop folder
    1036             :   nsCOMPtr<nsIContentPrefService2> contentPrefService =
    1037           0 :     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
    1038           0 :   if (!contentPrefService) {
    1039           0 :     prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);
    1040           0 :     return NS_OK;
    1041             :   }
    1042             : 
    1043           0 :   nsAutoCString cstrSpec;
    1044           0 :   docURI->GetSpec(cstrSpec);
    1045           0 :   NS_ConvertUTF8toUTF16 spec(cstrSpec);
    1046             : 
    1047           0 :   contentPrefService->GetByDomainAndName(spec, CPS_PREF_NAME, loadContext, prefCallback);
    1048           0 :   return NS_OK;
    1049             : }
    1050             : 
    1051             : nsresult
    1052           0 : UploadLastDir::StoreLastUsedDirectory(nsIDocument* aDoc, nsIFile* aDir)
    1053             : {
    1054           0 :   NS_PRECONDITION(aDoc, "aDoc is null");
    1055           0 :   if (!aDir) {
    1056           0 :     return NS_OK;
    1057             :   }
    1058             : 
    1059             : #ifdef MOZ_B2G
    1060             :   if (XRE_IsContentProcess()) {
    1061             :     return NS_OK;
    1062             :   }
    1063             : #endif
    1064             : 
    1065           0 :   nsCOMPtr<nsIURI> docURI = aDoc->GetDocumentURI();
    1066           0 :   NS_PRECONDITION(docURI, "docURI is null");
    1067             : 
    1068             :   // Attempt to get the CPS, if it's not present we'll just return
    1069             :   nsCOMPtr<nsIContentPrefService2> contentPrefService =
    1070           0 :     do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
    1071           0 :   if (!contentPrefService)
    1072           0 :     return NS_ERROR_NOT_AVAILABLE;
    1073             : 
    1074           0 :   nsAutoCString cstrSpec;
    1075           0 :   docURI->GetSpec(cstrSpec);
    1076           0 :   NS_ConvertUTF8toUTF16 spec(cstrSpec);
    1077             : 
    1078             :   // Find the parent of aFile, and store it
    1079           0 :   nsString unicodePath;
    1080           0 :   aDir->GetPath(unicodePath);
    1081           0 :   if (unicodePath.IsEmpty()) // nothing to do
    1082           0 :     return NS_OK;
    1083           0 :   RefPtr<nsVariantCC> prefValue = new nsVariantCC();
    1084           0 :   prefValue->SetAsAString(unicodePath);
    1085             : 
    1086             :   // Use the document's current load context to ensure that the content pref
    1087             :   // service doesn't persistently store this directory for this domain if the
    1088             :   // user is using private browsing:
    1089           0 :   nsCOMPtr<nsILoadContext> loadContext = aDoc->GetLoadContext();
    1090           0 :   return contentPrefService->Set(spec, CPS_PREF_NAME, prefValue, loadContext, nullptr);
    1091             : }
    1092             : 
    1093             : NS_IMETHODIMP
    1094           0 : UploadLastDir::Observe(nsISupports* aSubject, char const* aTopic, char16_t const* aData)
    1095             : {
    1096           0 :   if (strcmp(aTopic, "browser:purge-session-history") == 0) {
    1097             :     nsCOMPtr<nsIContentPrefService2> contentPrefService =
    1098           0 :       do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);
    1099           0 :     if (contentPrefService)
    1100           0 :       contentPrefService->RemoveByName(CPS_PREF_NAME, nullptr, nullptr);
    1101             :   }
    1102           0 :   return NS_OK;
    1103             : }
    1104             : 
    1105             : #ifdef ACCESSIBILITY
    1106             : //Helper method
    1107             : static nsresult FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
    1108             :                                           nsPresContext* aPresContext,
    1109             :                                           EventMessage aEventMessage);
    1110             : #endif
    1111             : 
    1112             : nsTextEditorState* HTMLInputElement::sCachedTextEditorState = nullptr;
    1113             : bool HTMLInputElement::sShutdown = false;
    1114             : 
    1115             : /* static */ void
    1116           1 : HTMLInputElement::ReleaseTextEditorState(nsTextEditorState* aState)
    1117             : {
    1118           1 :   if (!sShutdown && !sCachedTextEditorState) {
    1119           1 :     aState->PrepareForReuse();
    1120           1 :     sCachedTextEditorState = aState;
    1121             :   } else {
    1122           0 :     delete aState;
    1123             :   }
    1124           1 : }
    1125             : 
    1126             : /* static */ void
    1127           0 : HTMLInputElement::Shutdown()
    1128             : {
    1129           0 :   sShutdown = true;
    1130           0 :   delete sCachedTextEditorState;
    1131           0 :   sCachedTextEditorState = nullptr;
    1132           0 : }
    1133             : 
    1134             : //
    1135             : // construction, destruction
    1136             : //
    1137             : 
    1138           7 : HTMLInputElement::HTMLInputElement(already_AddRefed<mozilla::dom::NodeInfo>& aNodeInfo,
    1139           7 :                                    FromParser aFromParser, FromClone aFromClone)
    1140           7 :   : nsGenericHTMLFormElementWithState(aNodeInfo, kInputDefaultType->value)
    1141             :   , mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown)
    1142             :   , mAutocompleteInfoState(nsContentUtils::eAutocompleteAttrState_Unknown)
    1143             :   , mDisabledChanged(false)
    1144             :   , mValueChanged(false)
    1145             :   , mLastValueChangeWasInteractive(false)
    1146             :   , mCheckedChanged(false)
    1147             :   , mChecked(false)
    1148             :   , mHandlingSelectEvent(false)
    1149             :   , mShouldInitChecked(false)
    1150           7 :   , mDoneCreating(aFromParser == NOT_FROM_PARSER &&
    1151             :                   aFromClone == FromClone::no)
    1152             :   , mInInternalActivate(false)
    1153             :   , mCheckedIsToggled(false)
    1154             :   , mIndeterminate(false)
    1155           7 :   , mInhibitRestoration(aFromParser & FROM_PARSER_FRAGMENT)
    1156             :   , mCanShowValidUI(true)
    1157             :   , mCanShowInvalidUI(true)
    1158             :   , mHasRange(false)
    1159             :   , mIsDraggingRange(false)
    1160             :   , mNumberControlSpinnerIsSpinning(false)
    1161             :   , mNumberControlSpinnerSpinsUp(false)
    1162             :   , mPickerRunning(false)
    1163             :   , mSelectionCached(true)
    1164          21 :   , mIsPreviewEnabled(false)
    1165             : {
    1166             :   // If size is above 512, mozjemalloc allocates 1kB, see
    1167             :   // memory/mozjemalloc/jemalloc.c
    1168             :   static_assert(sizeof(HTMLInputElement) <= 512,
    1169             :                 "Keep the size of HTMLInputElement under 512 to avoid "
    1170             :                 "performance regression!");
    1171             : 
    1172             :   // We are in a type=text so we now we currenty need a nsTextEditorState.
    1173           7 :   mInputData.mState =
    1174           7 :     nsTextEditorState::Construct(this, &sCachedTextEditorState);
    1175             : 
    1176           7 :   void* memory = mInputTypeMem;
    1177           7 :   mInputType = InputType::Create(this, mType, memory);
    1178             : 
    1179           7 :   if (!gUploadLastDir)
    1180           1 :     HTMLInputElement::InitUploadLastDir();
    1181             : 
    1182             :   // Set up our default state.  By default we're enabled (since we're
    1183             :   // a control type that can be disabled but not actually disabled
    1184             :   // right now), optional, and valid.  We are NOT readwrite by default
    1185             :   // until someone calls UpdateEditableState on us, apparently!  Also
    1186             :   // by default we don't have to show validity UI and so forth.
    1187          14 :   AddStatesSilently(NS_EVENT_STATE_ENABLED |
    1188          14 :                     NS_EVENT_STATE_OPTIONAL |
    1189          21 :                     NS_EVENT_STATE_VALID);
    1190           7 :   UpdateApzAwareFlag();
    1191           7 : }
    1192             : 
    1193           0 : HTMLInputElement::~HTMLInputElement()
    1194             : {
    1195           0 :   if (mNumberControlSpinnerIsSpinning) {
    1196           0 :     StopNumberControlSpinnerSpin(eDisallowDispatchingEvents);
    1197             :   }
    1198           0 :   DestroyImageLoadingContent();
    1199           0 :   FreeData();
    1200           0 : }
    1201             : 
    1202             : void
    1203           1 : HTMLInputElement::FreeData()
    1204             : {
    1205           1 :   if (!IsSingleLineTextControl(false)) {
    1206           0 :     free(mInputData.mValue);
    1207           0 :     mInputData.mValue = nullptr;
    1208             :   } else {
    1209           1 :     UnbindFromFrame(nullptr);
    1210           1 :     ReleaseTextEditorState(mInputData.mState);
    1211           1 :     mInputData.mState = nullptr;
    1212             :   }
    1213             : 
    1214           1 :   if (mInputType) {
    1215           1 :     mInputType->DropReference();
    1216           1 :     mInputType = nullptr;
    1217             :   }
    1218           1 : }
    1219             : 
    1220             : nsTextEditorState*
    1221         343 : HTMLInputElement::GetEditorState() const
    1222             : {
    1223         343 :   if (!IsSingleLineTextControl(false)) {
    1224           0 :     return nullptr;
    1225             :   }
    1226             : 
    1227         343 :   MOZ_ASSERT(mInputData.mState, "Single line text controls need to have a state"
    1228             :                                 " associated with them");
    1229             : 
    1230         343 :   return mInputData.mState;
    1231             : }
    1232             : 
    1233             : 
    1234             : // nsISupports
    1235             : 
    1236             : NS_IMPL_CYCLE_COLLECTION_CLASS(HTMLInputElement)
    1237             : 
    1238           2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,
    1239             :                                                   nsGenericHTMLFormElementWithState)
    1240           2 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)
    1241           2 :   NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)
    1242           2 :   if (tmp->IsSingleLineTextControl(false)) {
    1243           2 :     tmp->mInputData.mState->Traverse(cb);
    1244             :   }
    1245             : 
    1246           2 :   if (tmp->mFileData) {
    1247           0 :     tmp->mFileData->Traverse(cb);
    1248             :   }
    1249           2 : NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    1250             : 
    1251           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,
    1252             :                                                 nsGenericHTMLFormElementWithState)
    1253           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)
    1254           0 :   NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)
    1255           0 :   if (tmp->IsSingleLineTextControl(false)) {
    1256           0 :     tmp->mInputData.mState->Unlink();
    1257             :   }
    1258             : 
    1259           0 :   if (tmp->mFileData) {
    1260           0 :     tmp->mFileData->Unlink();
    1261             :   }
    1262             :   //XXX should unlink more?
    1263           0 : NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    1264             : 
    1265         434 : NS_IMPL_ADDREF_INHERITED(HTMLInputElement, Element)
    1266         410 : NS_IMPL_RELEASE_INHERITED(HTMLInputElement, Element)
    1267             : 
    1268             : // QueryInterface implementation for HTMLInputElement
    1269         370 : NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLInputElement)
    1270         353 :   NS_INTERFACE_TABLE_INHERITED(HTMLInputElement,
    1271             :                                nsIDOMHTMLInputElement,
    1272             :                                nsITextControlElement,
    1273             :                                imgINotificationObserver,
    1274             :                                nsIImageLoadingContent,
    1275             :                                imgIOnloadBlocker,
    1276             :                                nsIDOMNSEditableElement,
    1277             :                                nsIConstraintValidation)
    1278         353 : NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)
    1279             : 
    1280             : // nsIConstraintValidation
    1281           0 : NS_IMPL_NSICONSTRAINTVALIDATION_EXCEPT_SETCUSTOMVALIDITY(HTMLInputElement)
    1282             : 
    1283             : // nsIDOMNode
    1284             : 
    1285             : nsresult
    1286           2 : HTMLInputElement::Clone(mozilla::dom::NodeInfo* aNodeInfo, nsINode** aResult,
    1287             :                         bool aPreallocateArrays) const
    1288             : {
    1289           2 :   *aResult = nullptr;
    1290             : 
    1291           4 :   already_AddRefed<mozilla::dom::NodeInfo> ni = RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();
    1292             :   RefPtr<HTMLInputElement> it = new HTMLInputElement(ni, NOT_FROM_PARSER,
    1293           4 :                                                      FromClone::yes);
    1294             : 
    1295           2 :   nsresult rv = const_cast<HTMLInputElement*>(this)->CopyInnerTo(it, aPreallocateArrays);
    1296           2 :   NS_ENSURE_SUCCESS(rv, rv);
    1297             : 
    1298           2 :   switch (GetValueMode()) {
    1299             :     case VALUE_MODE_VALUE:
    1300           2 :       if (mValueChanged) {
    1301             :         // We don't have our default value anymore.  Set our value on
    1302             :         // the clone.
    1303           0 :         nsAutoString value;
    1304           0 :         GetNonFileValueInternal(value);
    1305             :         // SetValueInternal handles setting the VALUE_CHANGED bit for us
    1306           0 :         rv = it->SetValueInternal(value, nsTextEditorState::eSetValue_Notify);
    1307           0 :         NS_ENSURE_SUCCESS(rv, rv);
    1308             :       }
    1309           2 :       break;
    1310             :     case VALUE_MODE_FILENAME:
    1311           0 :       if (it->OwnerDoc()->IsStaticDocument()) {
    1312             :         // We're going to be used in print preview.  Since the doc is static
    1313             :         // we can just grab the pretty string and use it as wallpaper
    1314           0 :         GetDisplayFileName(it->mFileData->mStaticDocFileList);
    1315             :       } else {
    1316           0 :         it->mFileData->ClearGetFilesHelpers();
    1317           0 :         it->mFileData->mFilesOrDirectories.Clear();
    1318           0 :         it->mFileData->mFilesOrDirectories.AppendElements(
    1319           0 :           mFileData->mFilesOrDirectories);
    1320             :       }
    1321           0 :       break;
    1322             :     case VALUE_MODE_DEFAULT_ON:
    1323           0 :       if (mCheckedChanged) {
    1324             :         // We no longer have our original checked state.  Set our
    1325             :         // checked state on the clone.
    1326           0 :         it->DoSetChecked(mChecked, false, true);
    1327             :         // Then tell DoneCreatingElement() not to overwrite:
    1328           0 :         it->mShouldInitChecked = false;
    1329             :       }
    1330           0 :       break;
    1331             :     case VALUE_MODE_DEFAULT:
    1332           0 :       if (mType == NS_FORM_INPUT_IMAGE && it->OwnerDoc()->IsStaticDocument()) {
    1333           0 :         CreateStaticImageClone(it);
    1334             :       }
    1335           0 :       break;
    1336             :   }
    1337             : 
    1338           2 :   it->DoneCreatingElement();
    1339             : 
    1340           2 :   it->mLastValueChangeWasInteractive = mLastValueChangeWasInteractive;
    1341           2 :   it.forget(aResult);
    1342           2 :   return NS_OK;
    1343             : }
    1344             : 
    1345             : nsresult
    1346          32 : HTMLInputElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
    1347             :                                 const nsAttrValueOrString* aValue,
    1348             :                                 bool aNotify)
    1349             : {
    1350          32 :   if (aNameSpaceID == kNameSpaceID_None) {
    1351             :     //
    1352             :     // When name or type changes, radio should be removed from radio group.
    1353             :     // (type changes are handled in the form itself currently)
    1354             :     // If we are not done creating the radio, we also should not do it.
    1355             :     //
    1356          50 :     if ((aName == nsGkAtoms::name ||
    1357          27 :          (aName == nsGkAtoms::type && !mForm)) &&
    1358           1 :         mType == NS_FORM_INPUT_RADIO &&
    1359           0 :         (mForm || mDoneCreating)) {
    1360           0 :       WillRemoveFromRadioGroup();
    1361          25 :     } else if (aNotify && aName == nsGkAtoms::src &&
    1362           0 :                mType == NS_FORM_INPUT_IMAGE) {
    1363           0 :       if (aValue) {
    1364             :         // Mark channel as urgent-start before load image if the image load is
    1365             :         // initaiated by a user interaction.
    1366           0 :         mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
    1367             : 
    1368           0 :         LoadImage(aValue->String(), true, aNotify, eImageLoadType_Normal);
    1369             :       } else {
    1370             :         // Null value means the attr got unset; drop the image
    1371           0 :         CancelImageRequests(aNotify);
    1372             :       }
    1373          25 :     } else if (aNotify && aName == nsGkAtoms::disabled) {
    1374           0 :       mDisabledChanged = true;
    1375          25 :     } else if (mType == NS_FORM_INPUT_RADIO && aName == nsGkAtoms::required) {
    1376           0 :       nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
    1377             : 
    1378           0 :       if (container &&
    1379           0 :           ((aValue && !HasAttr(aNameSpaceID, aName)) ||
    1380           0 :            (!aValue && HasAttr(aNameSpaceID, aName)))) {
    1381           0 :         nsAutoString name;
    1382           0 :         GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    1383           0 :         container->RadioRequiredWillChange(name, !!aValue);
    1384             :       }
    1385             :     }
    1386             : 
    1387          25 :     if (aName == nsGkAtoms::webkitdirectory) {
    1388           0 :       Telemetry::Accumulate(Telemetry::WEBKIT_DIRECTORY_USED, true);
    1389             :     }
    1390             :   }
    1391             : 
    1392          32 :   return nsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID, aName,
    1393          32 :                                                           aValue, aNotify);
    1394             : }
    1395             : 
    1396             : nsresult
    1397          32 : HTMLInputElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
    1398             :                                const nsAttrValue* aValue,
    1399             :                                const nsAttrValue* aOldValue, bool aNotify)
    1400             : {
    1401          32 :   if (aNameSpaceID == kNameSpaceID_None) {
    1402             :     //
    1403             :     // When name or type changes, radio should be added to radio group.
    1404             :     // (type changes are handled in the form itself currently)
    1405             :     // If we are not done creating the radio, we also should not do it.
    1406             :     //
    1407          50 :     if ((aName == nsGkAtoms::name ||
    1408          27 :          (aName == nsGkAtoms::type && !mForm)) &&
    1409           1 :         mType == NS_FORM_INPUT_RADIO &&
    1410           0 :         (mForm || mDoneCreating)) {
    1411           0 :       AddedToRadioGroup();
    1412           0 :       UpdateValueMissingValidityStateForRadio(false);
    1413             :     }
    1414             : 
    1415             :     // If @value is changed and BF_VALUE_CHANGED is false, @value is the value
    1416             :     // of the element so, if the value of the element is different than @value,
    1417             :     // we have to re-set it. This is only the case when GetValueMode() returns
    1418             :     // VALUE_MODE_VALUE.
    1419          50 :     if (aName == nsGkAtoms::value &&
    1420          25 :         !mValueChanged && GetValueMode() == VALUE_MODE_VALUE) {
    1421           0 :       SetDefaultValueAsValue();
    1422             :     }
    1423             : 
    1424             :     //
    1425             :     // Checked must be set no matter what type of control it is, since
    1426             :     // mChecked must reflect the new value
    1427          25 :     if (aName == nsGkAtoms::checked && !mCheckedChanged) {
    1428             :       // Delay setting checked if we are creating this element (wait
    1429             :       // until everything is set)
    1430           0 :       if (!mDoneCreating) {
    1431           0 :         mShouldInitChecked = true;
    1432             :       } else {
    1433           0 :         DoSetChecked(DefaultChecked(), true, false);
    1434             :       }
    1435             :     }
    1436             : 
    1437          25 :     if (aName == nsGkAtoms::type) {
    1438             :       uint8_t newType;
    1439           1 :       if (!aValue) {
    1440             :         // We're now a text input.
    1441           0 :         newType = kInputDefaultType->value;
    1442             :       } else {
    1443           1 :         newType = aValue->GetEnumValue();
    1444             :       }
    1445           1 :       if (newType != mType) {
    1446           1 :         HandleTypeChange(newType, aNotify);
    1447             :       }
    1448             :     }
    1449             : 
    1450          50 :     if (aName == nsGkAtoms::required || aName == nsGkAtoms::disabled ||
    1451          25 :         aName == nsGkAtoms::readonly) {
    1452           0 :       UpdateValueMissingValidityState();
    1453             : 
    1454             :       // This *has* to be called *after* validity has changed.
    1455           0 :       if (aName == nsGkAtoms::readonly || aName == nsGkAtoms::disabled) {
    1456           0 :         UpdateBarredFromConstraintValidation();
    1457             :       }
    1458          25 :     } else if (aName == nsGkAtoms::maxlength) {
    1459           0 :       UpdateTooLongValidityState();
    1460          25 :     } else if (aName == nsGkAtoms::minlength) {
    1461           0 :       UpdateTooShortValidityState();
    1462          25 :     } else if (aName == nsGkAtoms::pattern && mDoneCreating) {
    1463           0 :       UpdatePatternMismatchValidityState();
    1464          25 :     } else if (aName == nsGkAtoms::multiple) {
    1465           0 :       UpdateTypeMismatchValidityState();
    1466          25 :     } else if (aName == nsGkAtoms::max) {
    1467           0 :       UpdateHasRange();
    1468           0 :       nsresult rv = mInputType->MinMaxStepAttrChanged();
    1469           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1470             :       // Validity state must be updated *after* the UpdateValueDueToAttrChange
    1471             :       // call above or else the following assert will not be valid.
    1472             :       // We don't assert the state of underflow during creation since
    1473             :       // DoneCreatingElement sanitizes.
    1474           0 :       UpdateRangeOverflowValidityState();
    1475           0 :       MOZ_ASSERT(!mDoneCreating ||
    1476             :                  mType != NS_FORM_INPUT_RANGE ||
    1477             :                  !GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
    1478             :                  "HTML5 spec does not allow underflow for type=range");
    1479          25 :     } else if (aName == nsGkAtoms::min) {
    1480           0 :       UpdateHasRange();
    1481           0 :       nsresult rv = mInputType->MinMaxStepAttrChanged();
    1482           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1483             :       // See corresponding @max comment
    1484           0 :       UpdateRangeUnderflowValidityState();
    1485           0 :       UpdateStepMismatchValidityState();
    1486           0 :       MOZ_ASSERT(!mDoneCreating ||
    1487             :                  mType != NS_FORM_INPUT_RANGE ||
    1488             :                  !GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
    1489             :                  "HTML5 spec does not allow underflow for type=range");
    1490          25 :     } else if (aName == nsGkAtoms::step) {
    1491           0 :       nsresult rv = mInputType->MinMaxStepAttrChanged();
    1492           0 :       NS_ENSURE_SUCCESS(rv, rv);
    1493             :       // See corresponding @max comment
    1494           0 :       UpdateStepMismatchValidityState();
    1495           0 :       MOZ_ASSERT(!mDoneCreating ||
    1496             :                  mType != NS_FORM_INPUT_RANGE ||
    1497             :                  !GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),
    1498             :                  "HTML5 spec does not allow underflow for type=range");
    1499          50 :     } else if (aName == nsGkAtoms::dir &&
    1500          25 :                aValue && aValue->Equals(nsGkAtoms::_auto, eIgnoreCase)) {
    1501           0 :       SetDirectionFromValue(aNotify);
    1502          25 :     } else if (aName == nsGkAtoms::lang) {
    1503           0 :       if (mType == NS_FORM_INPUT_NUMBER) {
    1504             :         // Update the value that is displayed to the user to the new locale:
    1505           0 :         nsAutoString value;
    1506           0 :         GetNonFileValueInternal(value);
    1507             :         nsNumberControlFrame* numberControlFrame =
    1508           0 :           do_QueryFrame(GetPrimaryFrame());
    1509           0 :         if (numberControlFrame) {
    1510           0 :           numberControlFrame->SetValueOfAnonTextControl(value);
    1511             :         }
    1512             :       }
    1513          25 :     } else if (aName == nsGkAtoms::autocomplete) {
    1514             :       // Clear the cached @autocomplete attribute and autocompleteInfo state.
    1515           0 :       mAutocompleteAttrState = nsContentUtils::eAutocompleteAttrState_Unknown;
    1516           0 :       mAutocompleteInfoState = nsContentUtils::eAutocompleteAttrState_Unknown;
    1517             :     }
    1518             :   }
    1519             : 
    1520          32 :   return nsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID, aName,
    1521             :                                                          aValue, aOldValue,
    1522          32 :                                                          aNotify);
    1523             : }
    1524             : 
    1525             : void
    1526           0 : HTMLInputElement::BeforeSetForm(bool aBindToTree)
    1527             : {
    1528             :   // No need to remove from radio group if we are just binding to tree.
    1529           0 :   if (mType == NS_FORM_INPUT_RADIO && !aBindToTree) {
    1530           0 :     WillRemoveFromRadioGroup();
    1531             :   }
    1532           0 : }
    1533             : 
    1534             : void
    1535           0 : HTMLInputElement::AfterClearForm(bool aUnbindOrDelete)
    1536             : {
    1537           0 :   MOZ_ASSERT(!mForm);
    1538             : 
    1539             :   // Do not add back to radio group if we are releasing or unbinding from tree.
    1540           0 :   if (mType == NS_FORM_INPUT_RADIO && !aUnbindOrDelete) {
    1541           0 :     AddedToRadioGroup();
    1542           0 :     UpdateValueMissingValidityStateForRadio(false);
    1543             :   }
    1544           0 : }
    1545             : 
    1546             : // nsIDOMHTMLInputElement
    1547             : 
    1548             : NS_IMETHODIMP
    1549           0 : HTMLInputElement::GetForm(nsIDOMHTMLFormElement** aForm)
    1550             : {
    1551           0 :   return nsGenericHTMLFormElementWithState::GetForm(aForm);
    1552             : }
    1553             : 
    1554          30 : NS_IMPL_STRING_ATTR(HTMLInputElement, DefaultValue, value)
    1555           0 : NS_IMPL_BOOL_ATTR(HTMLInputElement, DefaultChecked, checked)
    1556           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Accept, accept)
    1557           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Align, align)
    1558           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Alt, alt)
    1559           0 : NS_IMPL_BOOL_ATTR(HTMLInputElement, Autofocus, autofocus)
    1560             : //NS_IMPL_BOOL_ATTR(HTMLInputElement, Checked, checked)
    1561           0 : NS_IMPL_BOOL_ATTR(HTMLInputElement, Disabled, disabled)
    1562           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Max, max)
    1563           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Min, min)
    1564           0 : NS_IMPL_ACTION_ATTR(HTMLInputElement, FormAction, formaction)
    1565           0 : NS_IMPL_ENUM_ATTR_DEFAULT_MISSING_INVALID_VALUES(HTMLInputElement, FormEnctype, formenctype,
    1566             :                                                  "", kFormDefaultEnctype->tag)
    1567           0 : NS_IMPL_ENUM_ATTR_DEFAULT_MISSING_INVALID_VALUES(HTMLInputElement, FormMethod, formmethod,
    1568             :                                                  "", kFormDefaultMethod->tag)
    1569           0 : NS_IMPL_BOOL_ATTR(HTMLInputElement, FormNoValidate, formnovalidate)
    1570           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, FormTarget, formtarget)
    1571           0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLInputElement, InputMode, inputmode,
    1572             :                                 kInputDefaultInputmode->tag)
    1573           0 : NS_IMPL_BOOL_ATTR(HTMLInputElement, Multiple, multiple)
    1574           0 : NS_IMPL_NON_NEGATIVE_INT_ATTR(HTMLInputElement, MaxLength, maxlength)
    1575           0 : NS_IMPL_NON_NEGATIVE_INT_ATTR(HTMLInputElement, MinLength, minlength)
    1576           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Name, name)
    1577           0 : NS_IMPL_BOOL_ATTR(HTMLInputElement, ReadOnly, readonly)
    1578           0 : NS_IMPL_BOOL_ATTR(HTMLInputElement, Required, required)
    1579           0 : NS_IMPL_URI_ATTR(HTMLInputElement, Src, src)
    1580           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Step, step)
    1581           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, UseMap, usemap)
    1582             : //NS_IMPL_STRING_ATTR(HTMLInputElement, Value, value)
    1583           0 : NS_IMPL_UINT_ATTR_NON_ZERO_DEFAULT_VALUE(HTMLInputElement, Size, size, DEFAULT_COLS)
    1584           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Pattern, pattern)
    1585           0 : NS_IMPL_STRING_ATTR(HTMLInputElement, Placeholder, placeholder)
    1586           0 : NS_IMPL_ENUM_ATTR_DEFAULT_VALUE(HTMLInputElement, Type, type,
    1587             :                                 kInputDefaultType->tag)
    1588             : 
    1589             : NS_IMETHODIMP
    1590           0 : HTMLInputElement::GetAutocomplete(nsAString& aValue)
    1591             : {
    1592           0 :   if (!DoesAutocompleteApply()) {
    1593           0 :     return NS_OK;
    1594             :   }
    1595             : 
    1596           0 :   aValue.Truncate();
    1597           0 :   const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
    1598             : 
    1599           0 :   mAutocompleteAttrState =
    1600           0 :     nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aValue,
    1601           0 :                                                    mAutocompleteAttrState);
    1602           0 :   return NS_OK;
    1603             : }
    1604             : 
    1605             : NS_IMETHODIMP
    1606           0 : HTMLInputElement::SetAutocomplete(const nsAString& aValue)
    1607             : {
    1608           0 :   return SetAttr(kNameSpaceID_None, nsGkAtoms::autocomplete, nullptr, aValue, true);
    1609             : }
    1610             : 
    1611             : void
    1612           0 : HTMLInputElement::GetAutocompleteInfo(Nullable<AutocompleteInfo>& aInfo)
    1613             : {
    1614           0 :   if (!DoesAutocompleteApply()) {
    1615           0 :     aInfo.SetNull();
    1616           0 :     return;
    1617             :   }
    1618             : 
    1619           0 :   const nsAttrValue* attributeVal = GetParsedAttr(nsGkAtoms::autocomplete);
    1620           0 :   mAutocompleteInfoState =
    1621           0 :     nsContentUtils::SerializeAutocompleteAttribute(attributeVal, aInfo.SetValue(),
    1622           0 :                                                    mAutocompleteInfoState,
    1623             :                                                    true);
    1624             : }
    1625             : 
    1626             : int32_t
    1627           0 : HTMLInputElement::TabIndexDefault()
    1628             : {
    1629           0 :   return 0;
    1630             : }
    1631             : 
    1632             : uint32_t
    1633           0 : HTMLInputElement::Height()
    1634             : {
    1635           0 :   if (mType != NS_FORM_INPUT_IMAGE) {
    1636           0 :     return 0;
    1637             :   }
    1638           0 :   return GetWidthHeightForImage(mCurrentRequest).height;
    1639             : }
    1640             : 
    1641             : NS_IMETHODIMP
    1642           0 : HTMLInputElement::GetHeight(uint32_t* aHeight)
    1643             : {
    1644           0 :   *aHeight = Height();
    1645           0 :   return NS_OK;
    1646             : }
    1647             : 
    1648             : NS_IMETHODIMP
    1649           0 : HTMLInputElement::SetHeight(uint32_t aHeight)
    1650             : {
    1651           0 :   ErrorResult rv;
    1652           0 :   SetHeight(aHeight, rv);
    1653           0 :   return rv.StealNSResult();
    1654             : }
    1655             : 
    1656             : NS_IMETHODIMP
    1657           0 : HTMLInputElement::GetIndeterminate(bool* aValue)
    1658             : {
    1659           0 :   *aValue = Indeterminate();
    1660           0 :   return NS_OK;
    1661             : }
    1662             : 
    1663             : void
    1664           0 : HTMLInputElement::SetIndeterminateInternal(bool aValue,
    1665             :                                            bool aShouldInvalidate)
    1666             : {
    1667           0 :   mIndeterminate = aValue;
    1668             : 
    1669           0 :   if (aShouldInvalidate) {
    1670             :     // Repaint the frame
    1671           0 :     nsIFrame* frame = GetPrimaryFrame();
    1672           0 :     if (frame)
    1673           0 :       frame->InvalidateFrameSubtree();
    1674             :   }
    1675             : 
    1676           0 :   UpdateState(true);
    1677           0 : }
    1678             : 
    1679             : NS_IMETHODIMP
    1680           0 : HTMLInputElement::SetIndeterminate(bool aValue)
    1681             : {
    1682           0 :   SetIndeterminateInternal(aValue, true);
    1683           0 :   return NS_OK;
    1684             : }
    1685             : 
    1686             : uint32_t
    1687           0 : HTMLInputElement::Width()
    1688             : {
    1689           0 :   if (mType != NS_FORM_INPUT_IMAGE) {
    1690           0 :     return 0;
    1691             :   }
    1692           0 :   return GetWidthHeightForImage(mCurrentRequest).width;
    1693             : }
    1694             : 
    1695             : NS_IMETHODIMP
    1696           0 : HTMLInputElement::GetWidth(uint32_t* aWidth)
    1697             : {
    1698           0 :   *aWidth = Width();
    1699           0 :   return NS_OK;
    1700             : }
    1701             : 
    1702             : NS_IMETHODIMP
    1703           0 : HTMLInputElement::SetWidth(uint32_t aWidth)
    1704             : {
    1705           0 :   ErrorResult rv;
    1706           0 :   SetWidth(aWidth, rv);
    1707           0 :   return rv.StealNSResult();
    1708             : }
    1709             : 
    1710             : void
    1711           5 : HTMLInputElement::GetValue(nsAString& aValue, CallerType aCallerType)
    1712             : {
    1713           5 :   GetValueInternal(aValue, aCallerType);
    1714             : 
    1715             :   // Don't return non-sanitized value for types that are experimental on mobile
    1716             :   // or datetime types
    1717           5 :   if (IsExperimentalMobileType(mType) || IsDateTimeInputType(mType)) {
    1718           0 :     SanitizeValue(aValue);
    1719             :   }
    1720           5 : }
    1721             : 
    1722             : void
    1723           5 : HTMLInputElement::GetValueInternal(nsAString& aValue,
    1724             :                                    CallerType aCallerType) const
    1725             : {
    1726           5 :   if (mType != NS_FORM_INPUT_FILE) {
    1727           5 :     GetNonFileValueInternal(aValue);
    1728           5 :     return;
    1729             :   }
    1730             : 
    1731           0 :   if (aCallerType == CallerType::System) {
    1732           0 :     aValue.Assign(mFileData->mFirstFilePath);
    1733           0 :     return;
    1734             :   }
    1735             : 
    1736           0 :   if (mFileData->mFilesOrDirectories.IsEmpty()) {
    1737           0 :     aValue.Truncate();
    1738           0 :     return;
    1739             :   }
    1740             : 
    1741           0 :   nsAutoString file;
    1742           0 :   GetDOMFileOrDirectoryName(mFileData->mFilesOrDirectories[0], file);
    1743           0 :   if (file.IsEmpty()) {
    1744           0 :     aValue.Truncate();
    1745           0 :     return;
    1746             :   }
    1747             : 
    1748           0 :   aValue.AssignLiteral("C:\\fakepath\\");
    1749           0 :   aValue.Append(file);
    1750             : }
    1751             : 
    1752             : void
    1753           5 : HTMLInputElement::GetNonFileValueInternal(nsAString& aValue) const
    1754             : {
    1755           5 :   switch (GetValueMode()) {
    1756             :     case VALUE_MODE_VALUE:
    1757           5 :       if (IsSingleLineTextControl(false)) {
    1758           5 :         mInputData.mState->GetValue(aValue, true);
    1759           0 :       } else if (!aValue.Assign(mInputData.mValue, fallible)) {
    1760           0 :         aValue.Truncate();
    1761             :       }
    1762           5 :       return;
    1763             : 
    1764             :     case VALUE_MODE_FILENAME:
    1765           0 :       NS_NOTREACHED("Someone screwed up here");
    1766             :       // We'll just return empty string if someone does screw up.
    1767           0 :       aValue.Truncate();
    1768           0 :       return;
    1769             : 
    1770             :     case VALUE_MODE_DEFAULT:
    1771             :       // Treat defaultValue as value.
    1772           0 :       GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue);
    1773           0 :       return;
    1774             : 
    1775             :     case VALUE_MODE_DEFAULT_ON:
    1776             :       // Treat default value as value and returns "on" if no value.
    1777           0 :       if (!GetAttr(kNameSpaceID_None, nsGkAtoms::value, aValue)) {
    1778           0 :         aValue.AssignLiteral("on");
    1779             :       }
    1780           0 :       return;
    1781             :   }
    1782             : }
    1783             : 
    1784             : bool
    1785           7 : HTMLInputElement::IsValueEmpty() const
    1786             : {
    1787           7 :   if (GetValueMode() == VALUE_MODE_VALUE && IsSingleLineTextControl(false)) {
    1788           7 :     return !mInputData.mState->HasNonEmptyValue();
    1789             :   }
    1790             : 
    1791           0 :   nsAutoString value;
    1792           0 :   GetNonFileValueInternal(value);
    1793             : 
    1794           0 :   return value.IsEmpty();
    1795             : }
    1796             : 
    1797             : void
    1798           0 : HTMLInputElement::ClearFiles(bool aSetValueChanged)
    1799             : {
    1800           0 :   nsTArray<OwningFileOrDirectory> data;
    1801           0 :   SetFilesOrDirectories(data, aSetValueChanged);
    1802           0 : }
    1803             : 
    1804             : int32_t
    1805           0 : HTMLInputElement::MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const
    1806             : {
    1807           0 :   return (aYear - 1970) * 12 + aMonth - 1;
    1808             : }
    1809             : 
    1810             : /* static */ Decimal
    1811           0 : HTMLInputElement::StringToDecimal(const nsAString& aValue)
    1812             : {
    1813           0 :   if (!IsASCII(aValue)) {
    1814           0 :     return Decimal::nan();
    1815             :   }
    1816           0 :   NS_LossyConvertUTF16toASCII asciiString(aValue);
    1817           0 :   std::string stdString = asciiString.get();
    1818           0 :   return Decimal::fromString(stdString);
    1819             : }
    1820             : 
    1821             : Decimal
    1822           0 : HTMLInputElement::GetValueAsDecimal() const
    1823             : {
    1824           0 :   Decimal decimalValue;
    1825           0 :   nsAutoString stringValue;
    1826             : 
    1827           0 :   GetNonFileValueInternal(stringValue);
    1828             : 
    1829           0 :   return !mInputType->ConvertStringToNumber(stringValue, decimalValue) ?
    1830           0 :     Decimal::nan() : decimalValue;
    1831             : }
    1832             : 
    1833             : void
    1834           1 : HTMLInputElement::SetValue(const nsAString& aValue, CallerType aCallerType,
    1835             :                            ErrorResult& aRv)
    1836             : {
    1837             :   // check security.  Note that setting the value to the empty string is always
    1838             :   // OK and gives pages a way to clear a file input if necessary.
    1839           1 :   if (mType == NS_FORM_INPUT_FILE) {
    1840           0 :     if (!aValue.IsEmpty()) {
    1841           0 :       if (aCallerType != CallerType::System) {
    1842             :         // setting the value of a "FILE" input widget requires
    1843             :         // chrome privilege
    1844           0 :         aRv.Throw(NS_ERROR_DOM_SECURITY_ERR);
    1845           0 :         return;
    1846             :       }
    1847           0 :       Sequence<nsString> list;
    1848           0 :       if (!list.AppendElement(aValue, fallible)) {
    1849           0 :         aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
    1850           0 :         return;
    1851             :       }
    1852             : 
    1853           0 :       MozSetFileNameArray(list, aRv);
    1854           0 :       return;
    1855             :     }
    1856             :     else {
    1857           0 :       ClearFiles(true);
    1858             :     }
    1859             :   }
    1860             :   else {
    1861           1 :     if (MayFireChangeOnBlur()) {
    1862             :       // If the value has been set by a script, we basically want to keep the
    1863             :       // current change event state. If the element is ready to fire a change
    1864             :       // event, we should keep it that way. Otherwise, we should make sure the
    1865             :       // element will not fire any event because of the script interaction.
    1866             :       //
    1867             :       // NOTE: this is currently quite expensive work (too much string
    1868             :       // manipulation). We should probably optimize that.
    1869           2 :       nsAutoString currentValue;
    1870           1 :       GetValue(currentValue, aCallerType);
    1871             : 
    1872             :       // Some types sanitize value, so GetValue doesn't return pure
    1873             :       // previous value correctly.
    1874             :       nsresult rv =
    1875           2 :         SetValueInternal(aValue,
    1876           2 :           (IsExperimentalMobileType(mType) || IsDateTimeInputType(mType)) ?
    1877             :             nullptr : &currentValue,
    1878             :           nsTextEditorState::eSetValue_ByContent |
    1879             :           nsTextEditorState::eSetValue_Notify |
    1880           1 :           nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
    1881           1 :       if (NS_FAILED(rv)) {
    1882           0 :         aRv.Throw(rv);
    1883           0 :         return;
    1884             :       }
    1885             : 
    1886           1 :       if (mFocusedValue.Equals(currentValue)) {
    1887           1 :         GetValue(mFocusedValue, aCallerType);
    1888             :       }
    1889             :     } else {
    1890             :       nsresult rv =
    1891             :         SetValueInternal(aValue,
    1892             :           nsTextEditorState::eSetValue_ByContent |
    1893             :           nsTextEditorState::eSetValue_Notify |
    1894           0 :           nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
    1895           0 :       if (NS_FAILED(rv)) {
    1896           0 :         aRv.Throw(rv);
    1897           0 :         return;
    1898             :       }
    1899             :     }
    1900             :   }
    1901             : }
    1902             : 
    1903             : nsGenericHTMLElement*
    1904           0 : HTMLInputElement::GetList() const
    1905             : {
    1906           0 :   nsAutoString dataListId;
    1907           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::list, dataListId);
    1908           0 :   if (dataListId.IsEmpty()) {
    1909           0 :     return nullptr;
    1910             :   }
    1911             : 
    1912             :   //XXXsmaug How should this all work in case input element is in Shadow DOM.
    1913           0 :   nsIDocument* doc = GetUncomposedDoc();
    1914           0 :   if (!doc) {
    1915           0 :     return nullptr;
    1916             :   }
    1917             : 
    1918           0 :   Element* element = doc->GetElementById(dataListId);
    1919           0 :   if (!element || !element->IsHTMLElement(nsGkAtoms::datalist)) {
    1920           0 :     return nullptr;
    1921             :   }
    1922             : 
    1923           0 :   return static_cast<nsGenericHTMLElement*>(element);
    1924             : }
    1925             : 
    1926             : NS_IMETHODIMP
    1927           0 : HTMLInputElement::GetList(nsIDOMHTMLElement** aValue)
    1928             : {
    1929           0 :   *aValue = nullptr;
    1930             : 
    1931           0 :   RefPtr<nsGenericHTMLElement> element = GetList();
    1932           0 :   if (!element) {
    1933           0 :     return NS_OK;
    1934             :   }
    1935             : 
    1936           0 :   element.forget(aValue);
    1937           0 :   return NS_OK;
    1938             : }
    1939             : 
    1940             : void
    1941           0 : HTMLInputElement::SetValue(Decimal aValue, CallerType aCallerType)
    1942             : {
    1943           0 :   MOZ_ASSERT(!aValue.isInfinity(), "aValue must not be Infinity!");
    1944             : 
    1945           0 :   if (aValue.isNaN()) {
    1946           0 :     IgnoredErrorResult rv;
    1947           0 :     SetValue(EmptyString(), aCallerType, rv);
    1948           0 :     return;
    1949             :   }
    1950             : 
    1951           0 :   nsAutoString value;
    1952           0 :   mInputType->ConvertNumberToString(aValue, value);
    1953           0 :   IgnoredErrorResult rv;
    1954           0 :   SetValue(value, aCallerType, rv);
    1955             : }
    1956             : 
    1957             : Nullable<Date>
    1958           0 : HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
    1959             : {
    1960           0 :   if (!IsDateTimeInputType(mType)) {
    1961           0 :     return Nullable<Date>();
    1962             :   }
    1963             : 
    1964           0 :   switch (mType) {
    1965             :     case NS_FORM_INPUT_DATE:
    1966             :     {
    1967             :       uint32_t year, month, day;
    1968           0 :       nsAutoString value;
    1969           0 :       GetNonFileValueInternal(value);
    1970           0 :       if (!ParseDate(value, &year, &month, &day)) {
    1971           0 :         return Nullable<Date>();
    1972             :       }
    1973             : 
    1974           0 :       JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, day));
    1975           0 :       return Nullable<Date>(Date(time));
    1976             :     }
    1977             :     case NS_FORM_INPUT_TIME:
    1978             :     {
    1979             :       uint32_t millisecond;
    1980           0 :       nsAutoString value;
    1981           0 :       GetNonFileValueInternal(value);
    1982           0 :       if (!ParseTime(value, &millisecond)) {
    1983           0 :         return Nullable<Date>();
    1984             :       }
    1985             : 
    1986           0 :       JS::ClippedTime time = JS::TimeClip(millisecond);
    1987           0 :       MOZ_ASSERT(time.toDouble() == millisecond,
    1988             :                  "HTML times are restricted to the day after the epoch and "
    1989             :                  "never clip");
    1990           0 :       return Nullable<Date>(Date(time));
    1991             :     }
    1992             :     case NS_FORM_INPUT_MONTH:
    1993             :     {
    1994             :       uint32_t year, month;
    1995           0 :       nsAutoString value;
    1996           0 :       GetNonFileValueInternal(value);
    1997           0 :       if (!ParseMonth(value, &year, &month)) {
    1998           0 :         return Nullable<Date>();
    1999             :       }
    2000             : 
    2001           0 :       JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, 1));
    2002           0 :       return Nullable<Date>(Date(time));
    2003             :     }
    2004             :     case NS_FORM_INPUT_WEEK:
    2005             :     {
    2006             :       uint32_t year, week;
    2007           0 :       nsAutoString value;
    2008           0 :       GetNonFileValueInternal(value);
    2009           0 :       if (!ParseWeek(value, &year, &week)) {
    2010           0 :         return Nullable<Date>();
    2011             :       }
    2012             : 
    2013           0 :       double days = DaysSinceEpochFromWeek(year, week);
    2014           0 :       JS::ClippedTime time = JS::TimeClip(days * kMsPerDay);
    2015             : 
    2016           0 :       return Nullable<Date>(Date(time));
    2017             :     }
    2018             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    2019             :     {
    2020             :       uint32_t year, month, day, timeInMs;
    2021           0 :       nsAutoString value;
    2022           0 :       GetNonFileValueInternal(value);
    2023           0 :       if (!ParseDateTimeLocal(value, &year, &month, &day, &timeInMs)) {
    2024           0 :         return Nullable<Date>();
    2025             :       }
    2026             : 
    2027             :       JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, day,
    2028           0 :                                                        timeInMs));
    2029           0 :       return Nullable<Date>(Date(time));
    2030             :     }
    2031             :   }
    2032             : 
    2033           0 :   MOZ_ASSERT(false, "Unrecognized input type");
    2034             :   aRv.Throw(NS_ERROR_UNEXPECTED);
    2035             :   return Nullable<Date>();
    2036             : }
    2037             : 
    2038             : void
    2039           0 : HTMLInputElement::SetValueAsDate(const Nullable<Date>& aDate, ErrorResult& aRv)
    2040             : {
    2041           0 :   if (!IsDateTimeInputType(mType)) {
    2042           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2043           0 :     return;
    2044             :   }
    2045             : 
    2046             :   // At this point we know we're not a file input, so we can just pass "not
    2047             :   // system" as the caller type, since the caller type only matters in the file
    2048             :   // input case.
    2049           0 :   if (aDate.IsNull() || aDate.Value().IsUndefined()) {
    2050           0 :     SetValue(EmptyString(), CallerType::NonSystem, aRv);
    2051           0 :     return;
    2052             :   }
    2053             : 
    2054           0 :   double milliseconds = aDate.Value().TimeStamp().toDouble();
    2055             : 
    2056           0 :   if (mType != NS_FORM_INPUT_MONTH) {
    2057           0 :     SetValue(Decimal::fromDouble(milliseconds), CallerType::NonSystem);
    2058           0 :     return;
    2059             :   }
    2060             : 
    2061             :   // type=month expects the value to be number of months.
    2062           0 :   double year = JS::YearFromTime(milliseconds);
    2063           0 :   double month = JS::MonthFromTime(milliseconds);
    2064             : 
    2065           0 :   if (IsNaN(year) || IsNaN(month)) {
    2066           0 :     SetValue(EmptyString(), CallerType::NonSystem, aRv);
    2067           0 :     return;
    2068             :   }
    2069             : 
    2070           0 :   int32_t months = MonthsSinceJan1970(year, month + 1);
    2071           0 :   SetValue(Decimal(int32_t(months)), CallerType::NonSystem);
    2072             : }
    2073             : 
    2074             : void
    2075           0 : HTMLInputElement::SetValueAsNumber(double aValueAsNumber, ErrorResult& aRv)
    2076             : {
    2077             :   // TODO: return TypeError when HTMLInputElement is converted to WebIDL, see
    2078             :   // bug 825197.
    2079           0 :   if (IsInfinite(aValueAsNumber)) {
    2080           0 :     aRv.Throw(NS_ERROR_INVALID_ARG);
    2081           0 :     return;
    2082             :   }
    2083             : 
    2084           0 :   if (!DoesValueAsNumberApply()) {
    2085           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    2086           0 :     return;
    2087             :   }
    2088             : 
    2089             :   // At this point we know we're not a file input, so we can just pass "not
    2090             :   // system" as the caller type, since the caller type only matters in the file
    2091             :   // input case.
    2092           0 :   SetValue(Decimal::fromDouble(aValueAsNumber), CallerType::NonSystem);
    2093             : }
    2094             : 
    2095             : Decimal
    2096           0 : HTMLInputElement::GetMinimum() const
    2097             : {
    2098           0 :   MOZ_ASSERT(DoesValueAsNumberApply(),
    2099             :              "GetMinimum() should only be used for types that allow .valueAsNumber");
    2100             : 
    2101             :   // Only type=range has a default minimum
    2102             :   Decimal defaultMinimum =
    2103           0 :     mType == NS_FORM_INPUT_RANGE ? Decimal(0) : Decimal::nan();
    2104             : 
    2105           0 :   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::min)) {
    2106           0 :     return defaultMinimum;
    2107             :   }
    2108             : 
    2109           0 :   nsAutoString minStr;
    2110           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
    2111             : 
    2112           0 :   Decimal min;
    2113           0 :   return mInputType->ConvertStringToNumber(minStr, min) ? min : defaultMinimum;
    2114             : }
    2115             : 
    2116             : Decimal
    2117           0 : HTMLInputElement::GetMaximum() const
    2118             : {
    2119           0 :   MOZ_ASSERT(DoesValueAsNumberApply(),
    2120             :              "GetMaximum() should only be used for types that allow .valueAsNumber");
    2121             : 
    2122             :   // Only type=range has a default maximum
    2123             :   Decimal defaultMaximum =
    2124           0 :     mType == NS_FORM_INPUT_RANGE ? Decimal(100) : Decimal::nan();
    2125             : 
    2126           0 :   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::max)) {
    2127           0 :     return defaultMaximum;
    2128             :   }
    2129             : 
    2130           0 :   nsAutoString maxStr;
    2131           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
    2132             : 
    2133           0 :   Decimal max;
    2134           0 :   return mInputType->ConvertStringToNumber(maxStr, max) ? max : defaultMaximum;
    2135             : }
    2136             : 
    2137             : Decimal
    2138           0 : HTMLInputElement::GetStepBase() const
    2139             : {
    2140           0 :   MOZ_ASSERT(IsDateTimeInputType(mType) ||
    2141             :              mType == NS_FORM_INPUT_NUMBER ||
    2142             :              mType == NS_FORM_INPUT_RANGE,
    2143             :              "Check that kDefaultStepBase is correct for this new type");
    2144             : 
    2145           0 :   Decimal stepBase;
    2146             : 
    2147             :   // Do NOT use GetMinimum here - the spec says to use "the min content
    2148             :   // attribute", not "the minimum".
    2149           0 :   nsAutoString minStr;
    2150           0 :   if (GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr) &&
    2151           0 :       mInputType->ConvertStringToNumber(minStr, stepBase)) {
    2152           0 :     return stepBase;
    2153             :   }
    2154             : 
    2155             :   // If @min is not a double, we should use @value.
    2156           0 :   nsAutoString valueStr;
    2157           0 :   if (GetAttr(kNameSpaceID_None, nsGkAtoms::value, valueStr) &&
    2158           0 :       mInputType->ConvertStringToNumber(valueStr, stepBase)) {
    2159           0 :     return stepBase;
    2160             :   }
    2161             : 
    2162           0 :   if (mType == NS_FORM_INPUT_WEEK) {
    2163           0 :     return kDefaultStepBaseWeek;
    2164             :   }
    2165             : 
    2166           0 :   return kDefaultStepBase;
    2167             : }
    2168             : 
    2169             : nsresult
    2170           0 : HTMLInputElement::GetValueIfStepped(int32_t aStep,
    2171             :                                     StepCallerType aCallerType,
    2172             :                                     Decimal* aNextStep)
    2173             : {
    2174           0 :   if (!DoStepDownStepUpApply()) {
    2175           0 :     return NS_ERROR_DOM_INVALID_STATE_ERR;
    2176             :   }
    2177             : 
    2178           0 :   Decimal stepBase = GetStepBase();
    2179           0 :   Decimal step = GetStep();
    2180           0 :   if (step == kStepAny) {
    2181           0 :     if (aCallerType != CALLED_FOR_USER_EVENT) {
    2182           0 :       return NS_ERROR_DOM_INVALID_STATE_ERR;
    2183             :     }
    2184             :     // Allow the spin buttons and up/down arrow keys to do something sensible:
    2185           0 :     step = GetDefaultStep();
    2186             :   }
    2187             : 
    2188           0 :   Decimal minimum = GetMinimum();
    2189           0 :   Decimal maximum = GetMaximum();
    2190             : 
    2191           0 :   if (!maximum.isNaN()) {
    2192             :     // "max - (max - stepBase) % step" is the nearest valid value to max.
    2193           0 :     maximum = maximum - NS_floorModulo(maximum - stepBase, step);
    2194           0 :     if (!minimum.isNaN()) {
    2195           0 :       if (minimum > maximum) {
    2196             :         // Either the minimum was greater than the maximum prior to our
    2197             :         // adjustment to align maximum on a step, or else (if we adjusted
    2198             :         // maximum) there is no valid step between minimum and the unadjusted
    2199             :         // maximum.
    2200           0 :         return NS_OK;
    2201             :       }
    2202             :     }
    2203             :   }
    2204             : 
    2205           0 :   Decimal value = GetValueAsDecimal();
    2206           0 :   bool valueWasNaN = false;
    2207           0 :   if (value.isNaN()) {
    2208           0 :     value = Decimal(0);
    2209           0 :     valueWasNaN = true;
    2210             :   }
    2211           0 :   Decimal valueBeforeStepping = value;
    2212             : 
    2213           0 :   Decimal deltaFromStep = NS_floorModulo(value - stepBase, step);
    2214             : 
    2215           0 :   if (deltaFromStep != Decimal(0)) {
    2216           0 :     if (aStep > 0) {
    2217           0 :       value += step - deltaFromStep;      // partial step
    2218           0 :       value += step * Decimal(aStep - 1); // then remaining steps
    2219           0 :     } else if (aStep < 0) {
    2220           0 :       value -= deltaFromStep;             // partial step
    2221           0 :       value += step * Decimal(aStep + 1); // then remaining steps
    2222             :     }
    2223             :   } else {
    2224           0 :     value += step * Decimal(aStep);
    2225             :   }
    2226             : 
    2227           0 :   if (value < minimum) {
    2228           0 :     value = minimum;
    2229           0 :     deltaFromStep = NS_floorModulo(value - stepBase, step);
    2230           0 :     if (deltaFromStep != Decimal(0)) {
    2231           0 :       value += step - deltaFromStep;
    2232             :     }
    2233             :   }
    2234           0 :   if (value > maximum) {
    2235           0 :     value = maximum;
    2236           0 :     deltaFromStep = NS_floorModulo(value - stepBase, step);
    2237           0 :     if (deltaFromStep != Decimal(0)) {
    2238           0 :       value -= deltaFromStep;
    2239             :     }
    2240             :   }
    2241             : 
    2242           0 :   if (!valueWasNaN && // value="", resulting in us using "0"
    2243           0 :       ((aStep > 0 && value < valueBeforeStepping) ||
    2244           0 :        (aStep < 0 && value > valueBeforeStepping))) {
    2245             :     // We don't want step-up to effectively step down, or step-down to
    2246             :     // effectively step up, so return;
    2247           0 :     return NS_OK;
    2248             :   }
    2249             : 
    2250           0 :   *aNextStep = value;
    2251           0 :   return NS_OK;
    2252             : }
    2253             : 
    2254             : nsresult
    2255           0 : HTMLInputElement::ApplyStep(int32_t aStep)
    2256             : {
    2257           0 :   Decimal nextStep = Decimal::nan(); // unchanged if value will not change
    2258             : 
    2259           0 :   nsresult rv = GetValueIfStepped(aStep, CALLED_FOR_SCRIPT, &nextStep);
    2260             : 
    2261           0 :   if (NS_SUCCEEDED(rv) && nextStep.isFinite()) {
    2262             :     // We know we're not a file input, so the caller type does not matter; just
    2263             :     // pass "not system" to be safe.
    2264           0 :     SetValue(nextStep, CallerType::NonSystem);
    2265             :   }
    2266             : 
    2267           0 :   return rv;
    2268             : }
    2269             : 
    2270             : /* static */
    2271             : bool
    2272           6 : HTMLInputElement::IsExperimentalMobileType(uint8_t aType)
    2273             : {
    2274           6 :   return (aType == NS_FORM_INPUT_DATE || aType == NS_FORM_INPUT_TIME) &&
    2275           6 :     !IsInputDateTimeEnabled();
    2276             : }
    2277             : 
    2278             : bool
    2279          77 : HTMLInputElement::IsDateTimeInputType(uint8_t aType)
    2280             : {
    2281          77 :   return aType == NS_FORM_INPUT_DATE ||
    2282          77 :          aType == NS_FORM_INPUT_TIME ||
    2283          77 :          aType == NS_FORM_INPUT_MONTH ||
    2284         154 :          aType == NS_FORM_INPUT_WEEK ||
    2285          77 :          aType == NS_FORM_INPUT_DATETIME_LOCAL;
    2286             : }
    2287             : 
    2288             : NS_IMETHODIMP
    2289           0 : HTMLInputElement::StepDown(int32_t n, uint8_t optional_argc)
    2290             : {
    2291           0 :   return ApplyStep(optional_argc ? -n : -1);
    2292             : }
    2293             : 
    2294             : NS_IMETHODIMP
    2295           0 : HTMLInputElement::StepUp(int32_t n, uint8_t optional_argc)
    2296             : {
    2297           0 :   return ApplyStep(optional_argc ? n : 1);
    2298             : }
    2299             : 
    2300             : void
    2301           0 : HTMLInputElement::FlushFrames()
    2302             : {
    2303           0 :   if (GetComposedDoc()) {
    2304           0 :     GetComposedDoc()->FlushPendingNotifications(FlushType::Frames);
    2305             :   }
    2306           0 : }
    2307             : 
    2308             : void
    2309           0 : HTMLInputElement::MozGetFileNameArray(nsTArray<nsString>& aArray,
    2310             :                                       ErrorResult& aRv)
    2311             : {
    2312           0 :   if (NS_WARN_IF(mType != NS_FORM_INPUT_FILE)) {
    2313           0 :     return;
    2314             :   }
    2315             : 
    2316             :   const nsTArray<OwningFileOrDirectory>& filesOrDirs =
    2317           0 :     GetFilesOrDirectoriesInternal();
    2318           0 :   for (uint32_t i = 0; i < filesOrDirs.Length(); i++) {
    2319           0 :     nsAutoString str;
    2320           0 :     GetDOMFileOrDirectoryPath(filesOrDirs[i], str, aRv);
    2321           0 :     if (NS_WARN_IF(aRv.Failed())) {
    2322           0 :       return;
    2323             :     }
    2324             : 
    2325           0 :     aArray.AppendElement(str);
    2326             :   }
    2327             : }
    2328             : 
    2329             : void
    2330           0 : HTMLInputElement::MozSetFileArray(const Sequence<OwningNonNull<File>>& aFiles)
    2331             : {
    2332           0 :   if (NS_WARN_IF(mType != NS_FORM_INPUT_FILE)) {
    2333           0 :     return;
    2334             :   }
    2335             : 
    2336           0 :   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
    2337           0 :   MOZ_ASSERT(global);
    2338           0 :   if (!global) {
    2339           0 :     return;
    2340             :   }
    2341             : 
    2342           0 :   nsTArray<OwningFileOrDirectory> files;
    2343           0 :   for (uint32_t i = 0; i < aFiles.Length(); ++i) {
    2344           0 :     RefPtr<File> file = File::Create(global, aFiles[i].get()->Impl());
    2345           0 :     MOZ_ASSERT(file);
    2346             : 
    2347           0 :     OwningFileOrDirectory* element = files.AppendElement();
    2348           0 :     element->SetAsFile() = file;
    2349             :   }
    2350             : 
    2351           0 :   SetFilesOrDirectories(files, true);
    2352             : }
    2353             : 
    2354             : void
    2355           0 : HTMLInputElement::MozSetFileNameArray(const Sequence<nsString>& aFileNames,
    2356             :                                       ErrorResult& aRv)
    2357             : {
    2358           0 :   if (NS_WARN_IF(mType != NS_FORM_INPUT_FILE)) {
    2359           0 :     return;
    2360             :   }
    2361             : 
    2362           0 :   if (XRE_IsContentProcess()) {
    2363           0 :     aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);
    2364           0 :     return;
    2365             :   }
    2366             : 
    2367           0 :   nsTArray<OwningFileOrDirectory> files;
    2368           0 :   for (uint32_t i = 0; i < aFileNames.Length(); ++i) {
    2369           0 :     nsCOMPtr<nsIFile> file;
    2370             : 
    2371           0 :     if (StringBeginsWith(aFileNames[i], NS_LITERAL_STRING("file:"),
    2372           0 :                          nsASCIICaseInsensitiveStringComparator())) {
    2373             :       // Converts the URL string into the corresponding nsIFile if possible
    2374             :       // A local file will be created if the URL string begins with file://
    2375           0 :       NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileNames[i]),
    2376           0 :                             getter_AddRefs(file));
    2377             :     }
    2378             : 
    2379           0 :     if (!file) {
    2380             :       // this is no "file://", try as local file
    2381           0 :       NS_NewLocalFile(aFileNames[i], false, getter_AddRefs(file));
    2382             :     }
    2383             : 
    2384           0 :     if (!file) {
    2385           0 :       continue; // Not much we can do if the file doesn't exist
    2386             :     }
    2387             : 
    2388           0 :     nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
    2389           0 :     if (!global) {
    2390           0 :       aRv.Throw(NS_ERROR_FAILURE);
    2391           0 :       return;
    2392             :     }
    2393             : 
    2394           0 :     RefPtr<File> domFile = File::CreateFromFile(global, file);
    2395             : 
    2396           0 :     OwningFileOrDirectory* element = files.AppendElement();
    2397           0 :     element->SetAsFile() = domFile;
    2398             :   }
    2399             : 
    2400           0 :   SetFilesOrDirectories(files, true);
    2401             : }
    2402             : 
    2403             : void
    2404           0 : HTMLInputElement::MozSetDirectory(const nsAString& aDirectoryPath,
    2405             :                                   ErrorResult& aRv)
    2406             : {
    2407           0 :   if (NS_WARN_IF(mType != NS_FORM_INPUT_FILE)) {
    2408           0 :     return;
    2409             :   }
    2410             : 
    2411           0 :   nsCOMPtr<nsIFile> file;
    2412           0 :   aRv = NS_NewLocalFile(aDirectoryPath, true, getter_AddRefs(file));
    2413           0 :   if (NS_WARN_IF(aRv.Failed())) {
    2414           0 :     return;
    2415             :   }
    2416             : 
    2417           0 :   nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
    2418           0 :   if (NS_WARN_IF(!window)) {
    2419           0 :     aRv.Throw(NS_ERROR_FAILURE);
    2420           0 :     return;
    2421             :   }
    2422             : 
    2423           0 :   RefPtr<Directory> directory = Directory::Create(window, file);
    2424           0 :   MOZ_ASSERT(directory);
    2425             : 
    2426           0 :   nsTArray<OwningFileOrDirectory> array;
    2427           0 :   OwningFileOrDirectory* element = array.AppendElement();
    2428           0 :   element->SetAsDirectory() = directory;
    2429             : 
    2430           0 :   SetFilesOrDirectories(array, true);
    2431             : }
    2432             : 
    2433           0 : void HTMLInputElement::GetDateTimeInputBoxValue(DateTimeValue& aValue)
    2434             : {
    2435           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType)) || !mDateTimeInputBoxValue) {
    2436           0 :     return;
    2437             :   }
    2438             : 
    2439           0 :   aValue = *mDateTimeInputBoxValue;
    2440             : }
    2441             : 
    2442             : void
    2443           0 : HTMLInputElement::UpdateDateTimeInputBox(const DateTimeValue& aValue)
    2444             : {
    2445           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
    2446           0 :     return;
    2447             :   }
    2448             : 
    2449           0 :   nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
    2450           0 :   if (frame) {
    2451           0 :     frame->SetValueFromPicker(aValue);
    2452             :   }
    2453             : }
    2454             : 
    2455             : void
    2456           0 : HTMLInputElement::SetDateTimePickerState(bool aOpen)
    2457             : {
    2458           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
    2459           0 :     return;
    2460             :   }
    2461             : 
    2462           0 :   nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
    2463           0 :   if (frame) {
    2464           0 :     frame->SetPickerState(aOpen);
    2465             :   }
    2466             : }
    2467             : 
    2468             : void
    2469           0 : HTMLInputElement::OpenDateTimePicker(const DateTimeValue& aInitialValue)
    2470             : {
    2471           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
    2472           0 :     return;
    2473             :   }
    2474             : 
    2475           0 :   mDateTimeInputBoxValue = new DateTimeValue(aInitialValue);
    2476           0 :   nsContentUtils::DispatchChromeEvent(OwnerDoc(),
    2477             :                                       static_cast<nsIDOMHTMLInputElement*>(this),
    2478           0 :                                       NS_LITERAL_STRING("MozOpenDateTimePicker"),
    2479           0 :                                       true, true);
    2480             : }
    2481             : 
    2482             : void
    2483           0 : HTMLInputElement::UpdateDateTimePicker(const DateTimeValue& aValue)
    2484             : {
    2485           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
    2486           0 :     return;
    2487             :   }
    2488             : 
    2489           0 :   mDateTimeInputBoxValue = new DateTimeValue(aValue);
    2490           0 :   nsContentUtils::DispatchChromeEvent(OwnerDoc(),
    2491             :                                       static_cast<nsIDOMHTMLInputElement*>(this),
    2492           0 :                                       NS_LITERAL_STRING("MozUpdateDateTimePicker"),
    2493           0 :                                       true, true);
    2494             : }
    2495             : 
    2496             : void
    2497           0 : HTMLInputElement::CloseDateTimePicker()
    2498             : {
    2499           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
    2500           0 :     return;
    2501             :   }
    2502             : 
    2503           0 :   nsContentUtils::DispatchChromeEvent(OwnerDoc(),
    2504             :                                       static_cast<nsIDOMHTMLInputElement*>(this),
    2505           0 :                                       NS_LITERAL_STRING("MozCloseDateTimePicker"),
    2506           0 :                                       true, true);
    2507             : }
    2508             : 
    2509             : void
    2510           0 : HTMLInputElement::SetFocusState(bool aIsFocused)
    2511             : {
    2512           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
    2513           0 :     return;
    2514             :   }
    2515             : 
    2516           0 :   EventStates focusStates = NS_EVENT_STATE_FOCUS | NS_EVENT_STATE_FOCUSRING;
    2517           0 :   if (aIsFocused) {
    2518           0 :     AddStates(focusStates);
    2519             :   } else {
    2520           0 :     RemoveStates(focusStates);
    2521             :   }
    2522             : }
    2523             : 
    2524             : void
    2525           0 : HTMLInputElement::UpdateValidityState()
    2526             : {
    2527           0 :   if (NS_WARN_IF(!IsDateTimeInputType(mType))) {
    2528           0 :     return;
    2529             :   }
    2530             : 
    2531             :   // For now, datetime input box call this function only when the value may
    2532             :   // become valid/invalid. For other validity states, they will be updated when
    2533             :   // .value is actually changed.
    2534           0 :   UpdateBadInputValidityState();
    2535           0 :   UpdateState(true);
    2536             : }
    2537             : 
    2538             : bool
    2539           0 : HTMLInputElement::MozIsTextField(bool aExcludePassword)
    2540             : {
    2541             :   // TODO: temporary until bug 888320 is fixed.
    2542           0 :   if (IsExperimentalMobileType(mType) || IsDateTimeInputType(mType)) {
    2543           0 :     return false;
    2544             :   }
    2545             : 
    2546           0 :   return IsSingleLineTextControl(aExcludePassword);
    2547             : }
    2548             : 
    2549             : HTMLInputElement*
    2550           0 : HTMLInputElement::GetOwnerNumberControl()
    2551             : {
    2552           0 :   if (IsInNativeAnonymousSubtree() &&
    2553           0 :       mType == NS_FORM_INPUT_TEXT &&
    2554           0 :       GetParent() && GetParent()->GetParent()) {
    2555             :     HTMLInputElement* grandparent =
    2556           0 :       HTMLInputElement::FromContentOrNull(GetParent()->GetParent());
    2557           0 :     if (grandparent && grandparent->mType == NS_FORM_INPUT_NUMBER) {
    2558           0 :       return grandparent;
    2559             :     }
    2560             :   }
    2561           0 :   return nullptr;
    2562             : }
    2563             : 
    2564             : NS_IMETHODIMP
    2565           0 : HTMLInputElement::MozIsTextField(bool aExcludePassword, bool* aResult)
    2566             : {
    2567           0 :   *aResult = MozIsTextField(aExcludePassword);
    2568           0 :   return NS_OK;
    2569             : }
    2570             : 
    2571             : void
    2572           0 : HTMLInputElement::SetUserInput(const nsAString& aInput,
    2573             :                                nsIPrincipal& aSubjectPrincipal) {
    2574           0 :   if (mType == NS_FORM_INPUT_FILE &&
    2575           0 :       !nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)) {
    2576           0 :     return;
    2577             :   }
    2578             : 
    2579           0 :   SetUserInput(aInput);
    2580             : }
    2581             : 
    2582             : NS_IMETHODIMP
    2583           0 : HTMLInputElement::SetUserInput(const nsAString& aValue)
    2584             : {
    2585           0 :   if (mType == NS_FORM_INPUT_FILE)
    2586             :   {
    2587           0 :     Sequence<nsString> list;
    2588           0 :     if (!list.AppendElement(aValue, fallible)) {
    2589           0 :       return NS_ERROR_OUT_OF_MEMORY;
    2590             :     }
    2591             : 
    2592           0 :     ErrorResult rv;
    2593           0 :     MozSetFileNameArray(list, rv);
    2594           0 :     return rv.StealNSResult();
    2595             :   } else {
    2596             :     nsresult rv =
    2597             :       SetValueInternal(aValue,
    2598             :         nsTextEditorState::eSetValue_BySetUserInput |
    2599             :         nsTextEditorState::eSetValue_Notify|
    2600           0 :         nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);
    2601           0 :     NS_ENSURE_SUCCESS(rv, rv);
    2602             :   }
    2603             : 
    2604           0 :   nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
    2605             :                                        static_cast<nsIDOMHTMLInputElement*>(this),
    2606           0 :                                        NS_LITERAL_STRING("input"), true,
    2607           0 :                                        true);
    2608             : 
    2609             :   // If this element is not currently focused, it won't receive a change event for this
    2610             :   // update through the normal channels. So fire a change event immediately, instead.
    2611           0 :   if (!ShouldBlur(this)) {
    2612           0 :     FireChangeEventIfNeeded();
    2613             :   }
    2614             : 
    2615           0 :   return NS_OK;
    2616             : }
    2617             : 
    2618             : nsIEditor*
    2619           1 : HTMLInputElement::GetEditor()
    2620             : {
    2621           1 :   return GetTextEditorFromState();
    2622             : }
    2623             : 
    2624             : TextEditor*
    2625           8 : HTMLInputElement::GetTextEditorFromState()
    2626             : {
    2627           8 :   nsTextEditorState* state = GetEditorState();
    2628           8 :   if (state) {
    2629           8 :     return state->GetTextEditor();
    2630             :   }
    2631           0 :   return nullptr;
    2632             : }
    2633             : 
    2634             : NS_IMETHODIMP_(TextEditor*)
    2635           7 : HTMLInputElement::GetTextEditor()
    2636             : {
    2637           7 :   return GetTextEditorFromState();
    2638             : }
    2639             : 
    2640             : NS_IMETHODIMP_(nsISelectionController*)
    2641           8 : HTMLInputElement::GetSelectionController()
    2642             : {
    2643           8 :   nsTextEditorState* state = GetEditorState();
    2644           8 :   if (state) {
    2645           8 :     return state->GetSelectionController();
    2646             :   }
    2647           0 :   return nullptr;
    2648             : }
    2649             : 
    2650             : nsFrameSelection*
    2651           6 : HTMLInputElement::GetConstFrameSelection()
    2652             : {
    2653           6 :   nsTextEditorState* state = GetEditorState();
    2654           6 :   if (state) {
    2655           6 :     return state->GetConstFrameSelection();
    2656             :   }
    2657           0 :   return nullptr;
    2658             : }
    2659             : 
    2660             : NS_IMETHODIMP
    2661           4 : HTMLInputElement::BindToFrame(nsTextControlFrame* aFrame)
    2662             : {
    2663           4 :   nsTextEditorState* state = GetEditorState();
    2664           4 :   if (state) {
    2665           4 :     return state->BindToFrame(aFrame);
    2666             :   }
    2667           0 :   return NS_ERROR_FAILURE;
    2668             : }
    2669             : 
    2670             : NS_IMETHODIMP_(void)
    2671           3 : HTMLInputElement::UnbindFromFrame(nsTextControlFrame* aFrame)
    2672             : {
    2673           3 :   nsTextEditorState* state = GetEditorState();
    2674           3 :   if (state && aFrame) {
    2675           2 :     state->UnbindFromFrame(aFrame);
    2676             :   }
    2677           3 : }
    2678             : 
    2679             : NS_IMETHODIMP
    2680           2 : HTMLInputElement::CreateEditor()
    2681             : {
    2682           2 :   nsTextEditorState* state = GetEditorState();
    2683           2 :   if (state) {
    2684           2 :     return state->PrepareEditor();
    2685             :   }
    2686           0 :   return NS_ERROR_FAILURE;
    2687             : }
    2688             : 
    2689             : NS_IMETHODIMP_(Element*)
    2690          16 : HTMLInputElement::GetRootEditorNode()
    2691             : {
    2692          16 :   nsTextEditorState* state = GetEditorState();
    2693          16 :   if (state) {
    2694          16 :     return state->GetRootNode();
    2695             :   }
    2696           0 :   return nullptr;
    2697             : }
    2698             : 
    2699             : NS_IMETHODIMP_(Element*)
    2700           4 : HTMLInputElement::CreatePlaceholderNode()
    2701             : {
    2702           4 :   nsTextEditorState* state = GetEditorState();
    2703           4 :   if (state) {
    2704           4 :     NS_ENSURE_SUCCESS(state->CreatePlaceholderNode(), nullptr);
    2705           4 :     return state->GetPlaceholderNode();
    2706             :   }
    2707           0 :   return nullptr;
    2708             : }
    2709             : 
    2710             : NS_IMETHODIMP_(Element*)
    2711         102 : HTMLInputElement::GetPlaceholderNode()
    2712             : {
    2713         102 :   nsTextEditorState* state = GetEditorState();
    2714         102 :   if (state) {
    2715         102 :     return state->GetPlaceholderNode();
    2716             :   }
    2717           0 :   return nullptr;
    2718             : }
    2719             : 
    2720             : NS_IMETHODIMP_(void)
    2721           5 : HTMLInputElement::UpdateOverlayTextVisibility(bool aNotify)
    2722             : {
    2723           5 :   nsTextEditorState* state = GetEditorState();
    2724           5 :   if (state) {
    2725           5 :     state->UpdateOverlayTextVisibility(aNotify);
    2726             :   }
    2727           5 : }
    2728             : 
    2729             : NS_IMETHODIMP_(bool)
    2730          48 : HTMLInputElement::GetPlaceholderVisibility()
    2731             : {
    2732          48 :   nsTextEditorState* state = GetEditorState();
    2733          48 :   if (!state) {
    2734           0 :     return false;
    2735             :   }
    2736             : 
    2737          48 :   return state->GetPlaceholderVisibility();
    2738             : }
    2739             : 
    2740             : NS_IMETHODIMP_(Element*)
    2741           0 : HTMLInputElement::CreatePreviewNode()
    2742             : {
    2743           0 :   nsTextEditorState* state = GetEditorState();
    2744           0 :   if (state) {
    2745           0 :     NS_ENSURE_SUCCESS(state->CreatePreviewNode(), nullptr);
    2746           0 :     return state->GetPreviewNode();
    2747             :   }
    2748           0 :   return nullptr;
    2749             : }
    2750             : 
    2751             : NS_IMETHODIMP_(Element*)
    2752          85 : HTMLInputElement::GetPreviewNode()
    2753             : {
    2754          85 :   nsTextEditorState* state = GetEditorState();
    2755          85 :   if (state) {
    2756          85 :     return state->GetPreviewNode();
    2757             :   }
    2758           0 :   return nullptr;
    2759             : }
    2760             : 
    2761             : NS_IMETHODIMP_(void)
    2762           0 : HTMLInputElement::SetPreviewValue(const nsAString& aValue)
    2763             : {
    2764           0 :   nsTextEditorState* state = GetEditorState();
    2765           0 :   if (state) {
    2766           0 :     state->SetPreviewText(aValue, true);
    2767             :   }
    2768           0 : }
    2769             : 
    2770             : NS_IMETHODIMP_(void)
    2771           0 : HTMLInputElement::GetPreviewValue(nsAString& aValue)
    2772             : {
    2773           0 :   nsTextEditorState* state = GetEditorState();
    2774           0 :   if (state) {
    2775           0 :     state->GetPreviewText(aValue);
    2776             :   }
    2777           0 : }
    2778             : 
    2779             : NS_IMETHODIMP_(void)
    2780           0 : HTMLInputElement::EnablePreview()
    2781             : {
    2782           0 :   if (mIsPreviewEnabled) {
    2783           0 :     return;
    2784             :   }
    2785             : 
    2786           0 :   mIsPreviewEnabled = true;
    2787             :   // Reconstruct the frame to append an anonymous preview node
    2788           0 :   nsLayoutUtils::PostRestyleEvent(this, nsRestyleHint(0), nsChangeHint_ReconstructFrame);
    2789             : }
    2790             : 
    2791             : NS_IMETHODIMP_(bool)
    2792           4 : HTMLInputElement::IsPreviewEnabled()
    2793             : {
    2794           4 :   return mIsPreviewEnabled;
    2795             : }
    2796             : 
    2797             : NS_IMETHODIMP_(bool)
    2798           0 : HTMLInputElement::GetPreviewVisibility()
    2799             : {
    2800           0 :   nsTextEditorState* state = GetEditorState();
    2801           0 :   if (!state) {
    2802           0 :     return false;
    2803             :   }
    2804             : 
    2805           0 :   return state->GetPreviewVisibility();
    2806             : }
    2807             : 
    2808             : void
    2809           0 : HTMLInputElement::GetDisplayFileName(nsAString& aValue) const
    2810             : {
    2811           0 :   MOZ_ASSERT(mFileData);
    2812             : 
    2813           0 :   if (OwnerDoc()->IsStaticDocument()) {
    2814           0 :     aValue = mFileData->mStaticDocFileList;
    2815           0 :     return;
    2816             :   }
    2817             : 
    2818           0 :   if (mFileData->mFilesOrDirectories.Length() == 1) {
    2819           0 :     GetDOMFileOrDirectoryName(mFileData->mFilesOrDirectories[0], aValue);
    2820           0 :     return;
    2821             :   }
    2822             : 
    2823           0 :   nsXPIDLString value;
    2824             : 
    2825           0 :   if (mFileData->mFilesOrDirectories.IsEmpty()) {
    2826           0 :     if ((IsDirPickerEnabled() && Allowdirs()) ||
    2827           0 :         (IsWebkitDirPickerEnabled() &&
    2828           0 :          HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
    2829             :       nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
    2830           0 :                                          "NoDirSelected", value);
    2831           0 :     } else if (HasAttr(kNameSpaceID_None, nsGkAtoms::multiple)) {
    2832             :       nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
    2833           0 :                                          "NoFilesSelected", value);
    2834             :     } else {
    2835             :       nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
    2836           0 :                                          "NoFileSelected", value);
    2837             :     }
    2838             :   } else {
    2839           0 :     nsString count;
    2840           0 :     count.AppendInt(int(mFileData->mFilesOrDirectories.Length()));
    2841             : 
    2842           0 :     const char16_t* params[] = { count.get() };
    2843             :     nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
    2844           0 :                                           "XFilesSelected", params, value);
    2845             :   }
    2846             : 
    2847           0 :   aValue = value;
    2848             : }
    2849             : 
    2850             : const nsTArray<OwningFileOrDirectory>&
    2851           0 : HTMLInputElement::GetFilesOrDirectoriesInternal() const
    2852             : {
    2853           0 :   return mFileData->mFilesOrDirectories;
    2854             : }
    2855             : 
    2856             : void
    2857           0 : HTMLInputElement::SetFilesOrDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories,
    2858             :                                         bool aSetValueChanged)
    2859             : {
    2860           0 :   MOZ_ASSERT(mFileData);
    2861             : 
    2862           0 :   mFileData->ClearGetFilesHelpers();
    2863             : 
    2864           0 :   if (IsWebkitFileSystemEnabled()) {
    2865           0 :     HTMLInputElementBinding::ClearCachedWebkitEntriesValue(this);
    2866           0 :     mFileData->mEntries.Clear();
    2867             :   }
    2868             : 
    2869           0 :   mFileData->mFilesOrDirectories.Clear();
    2870           0 :   mFileData->mFilesOrDirectories.AppendElements(aFilesOrDirectories);
    2871             : 
    2872           0 :   AfterSetFilesOrDirectories(aSetValueChanged);
    2873           0 : }
    2874             : 
    2875             : void
    2876           0 : HTMLInputElement::SetFiles(nsIDOMFileList* aFiles,
    2877             :                            bool aSetValueChanged)
    2878             : {
    2879           0 :   MOZ_ASSERT(mFileData);
    2880             : 
    2881           0 :   RefPtr<FileList> files = static_cast<FileList*>(aFiles);
    2882           0 :   mFileData->mFilesOrDirectories.Clear();
    2883           0 :   mFileData->ClearGetFilesHelpers();
    2884             : 
    2885           0 :   if (IsWebkitFileSystemEnabled()) {
    2886           0 :     HTMLInputElementBinding::ClearCachedWebkitEntriesValue(this);
    2887           0 :     mFileData->mEntries.Clear();
    2888             :   }
    2889             : 
    2890           0 :   if (aFiles) {
    2891             :     uint32_t listLength;
    2892           0 :     aFiles->GetLength(&listLength);
    2893           0 :     for (uint32_t i = 0; i < listLength; i++) {
    2894             :       OwningFileOrDirectory* element =
    2895           0 :         mFileData->mFilesOrDirectories.AppendElement();
    2896           0 :       element->SetAsFile() = files->Item(i);
    2897             :     }
    2898             :   }
    2899             : 
    2900           0 :   AfterSetFilesOrDirectories(aSetValueChanged);
    2901           0 : }
    2902             : 
    2903             : // This method is used for testing only.
    2904             : void
    2905           0 : HTMLInputElement::MozSetDndFilesAndDirectories(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories)
    2906             : {
    2907           0 :   if (NS_WARN_IF(mType != NS_FORM_INPUT_FILE)) {
    2908           0 :     return;
    2909             :   }
    2910             : 
    2911           0 :   SetFilesOrDirectories(aFilesOrDirectories, true);
    2912             : 
    2913           0 :   if (IsWebkitFileSystemEnabled()) {
    2914           0 :     UpdateEntries(aFilesOrDirectories);
    2915             :   }
    2916             : 
    2917             :   RefPtr<DispatchChangeEventCallback> dispatchChangeEventCallback =
    2918           0 :     new DispatchChangeEventCallback(this);
    2919             : 
    2920           0 :   if (IsWebkitDirPickerEnabled() &&
    2921           0 :       HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)) {
    2922           0 :     ErrorResult rv;
    2923             :     GetFilesHelper* helper = GetOrCreateGetFilesHelper(true /* recursionFlag */,
    2924           0 :                                                        rv);
    2925           0 :     if (NS_WARN_IF(rv.Failed())) {
    2926           0 :       rv.SuppressException();
    2927           0 :       return;
    2928             :     }
    2929             : 
    2930           0 :     helper->AddCallback(dispatchChangeEventCallback);
    2931             :   } else {
    2932           0 :     dispatchChangeEventCallback->DispatchEvents();
    2933             :   }
    2934             : }
    2935             : 
    2936             : void
    2937           0 : HTMLInputElement::AfterSetFilesOrDirectories(bool aSetValueChanged)
    2938             : {
    2939             :   // No need to flush here, if there's no frame at this point we
    2940             :   // don't need to force creation of one just to tell it about this
    2941             :   // new value.  We just want the display to update as needed.
    2942           0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(false);
    2943           0 :   if (formControlFrame) {
    2944           0 :     nsAutoString readableValue;
    2945           0 :     GetDisplayFileName(readableValue);
    2946           0 :     formControlFrame->SetFormProperty(nsGkAtoms::value, readableValue);
    2947             :   }
    2948             : 
    2949             :   // Grab the full path here for any chrome callers who access our .value via a
    2950             :   // CPOW. This path won't be called from a CPOW meaning the potential sync IPC
    2951             :   // call under GetMozFullPath won't be rejected for not being urgent.
    2952             :   // XXX Protected by the ifndef because the blob code doesn't allow us to send
    2953             :   // this message in b2g.
    2954           0 :   if (mFileData->mFilesOrDirectories.IsEmpty()) {
    2955           0 :     mFileData->mFirstFilePath.Truncate();
    2956             :   } else {
    2957           0 :     ErrorResult rv;
    2958           0 :     GetDOMFileOrDirectoryPath(mFileData->mFilesOrDirectories[0],
    2959           0 :                               mFileData->mFirstFilePath, rv);
    2960           0 :     if (NS_WARN_IF(rv.Failed())) {
    2961           0 :       rv.SuppressException();
    2962             :     }
    2963             :   }
    2964             : 
    2965           0 :   UpdateFileList();
    2966             : 
    2967           0 :   if (aSetValueChanged) {
    2968           0 :     SetValueChanged(true);
    2969             :   }
    2970             : 
    2971           0 :   UpdateAllValidityStates(true);
    2972           0 : }
    2973             : 
    2974             : void
    2975           0 : HTMLInputElement::FireChangeEventIfNeeded()
    2976             : {
    2977             :   // We're not exposing the GetValue return value anywhere here, so it's safe to
    2978             :   // claim to be a system caller.
    2979           0 :   nsAutoString value;
    2980           0 :   GetValue(value, CallerType::System);
    2981             : 
    2982           0 :   if (!MayFireChangeOnBlur() || mFocusedValue.Equals(value)) {
    2983           0 :     return;
    2984             :   }
    2985             : 
    2986             :   // Dispatch the change event.
    2987           0 :   mFocusedValue = value;
    2988           0 :   nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
    2989             :                                        static_cast<nsIContent*>(this),
    2990           0 :                                        NS_LITERAL_STRING("change"), true,
    2991           0 :                                        false);
    2992             : }
    2993             : 
    2994             : FileList*
    2995           0 : HTMLInputElement::GetFiles()
    2996             : {
    2997           0 :   if (mType != NS_FORM_INPUT_FILE) {
    2998           0 :     return nullptr;
    2999             :   }
    3000             : 
    3001           0 :   if (IsDirPickerEnabled() && Allowdirs() &&
    3002           0 :       (!IsWebkitDirPickerEnabled() ||
    3003           0 :        !HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory))) {
    3004           0 :     return nullptr;
    3005             :   }
    3006             : 
    3007           0 :   if (!mFileData->mFileList) {
    3008           0 :     mFileData->mFileList = new FileList(static_cast<nsIContent*>(this));
    3009           0 :     UpdateFileList();
    3010             :   }
    3011             : 
    3012           0 :   return mFileData->mFileList;
    3013             : }
    3014             : 
    3015             : /* static */ void
    3016           0 : HTMLInputElement::HandleNumberControlSpin(void* aData)
    3017             : {
    3018           0 :   HTMLInputElement* input = static_cast<HTMLInputElement*>(aData);
    3019             : 
    3020           0 :   NS_ASSERTION(input->mNumberControlSpinnerIsSpinning,
    3021             :                "Should have called nsRepeatService::Stop()");
    3022             : 
    3023             :   nsNumberControlFrame* numberControlFrame =
    3024           0 :     do_QueryFrame(input->GetPrimaryFrame());
    3025           0 :   if (input->mType != NS_FORM_INPUT_NUMBER || !numberControlFrame) {
    3026             :     // Type has changed (and possibly our frame type hasn't been updated yet)
    3027             :     // or else we've lost our frame. Either way, stop the timer and don't do
    3028             :     // anything else.
    3029           0 :     input->StopNumberControlSpinnerSpin();
    3030             :   } else {
    3031           0 :     input->StepNumberControlForUserEvent(input->mNumberControlSpinnerSpinsUp ? 1 : -1);
    3032             :   }
    3033           0 : }
    3034             : 
    3035             : void
    3036           0 : HTMLInputElement::UpdateFileList()
    3037             : {
    3038           0 :   MOZ_ASSERT(mFileData);
    3039             : 
    3040           0 :   if (mFileData->mFileList) {
    3041           0 :     mFileData->mFileList->Clear();
    3042             : 
    3043             :     const nsTArray<OwningFileOrDirectory>& array =
    3044           0 :       GetFilesOrDirectoriesInternal();
    3045             : 
    3046           0 :     for (uint32_t i = 0; i < array.Length(); ++i) {
    3047           0 :       if (array[i].IsFile()) {
    3048           0 :         mFileData->mFileList->Append(array[i].GetAsFile());
    3049             :       }
    3050             :     }
    3051             :   }
    3052           0 : }
    3053             : 
    3054             : nsresult
    3055           4 : HTMLInputElement::SetValueInternal(const nsAString& aValue,
    3056             :                                    const nsAString* aOldValue,
    3057             :                                    uint32_t aFlags)
    3058             : {
    3059           4 :   NS_PRECONDITION(GetValueMode() != VALUE_MODE_FILENAME,
    3060             :                   "Don't call SetValueInternal for file inputs");
    3061             : 
    3062           4 :   switch (GetValueMode()) {
    3063             :     case VALUE_MODE_VALUE:
    3064             :     {
    3065             :       // At the moment, only single line text control have to sanitize their value
    3066             :       // Because we have to create a new string for that, we should prevent doing
    3067             :       // it if it's useless.
    3068           8 :       nsAutoString value(aValue);
    3069             : 
    3070           4 :       if (mDoneCreating) {
    3071           4 :         SanitizeValue(value);
    3072             :       }
    3073             :       // else DoneCreatingElement calls us again once mDoneCreating is true
    3074             : 
    3075           4 :       bool setValueChanged = !!(aFlags & nsTextEditorState::eSetValue_Notify);
    3076           4 :       if (setValueChanged) {
    3077           1 :         SetValueChanged(true);
    3078             :       }
    3079             : 
    3080           4 :       if (IsSingleLineTextControl(false)) {
    3081           4 :         if (!mInputData.mState->SetValue(value, aOldValue, aFlags)) {
    3082           0 :           return NS_ERROR_OUT_OF_MEMORY;
    3083             :         }
    3084           4 :         if (mType == NS_FORM_INPUT_EMAIL) {
    3085           0 :           UpdateAllValidityStates(!mDoneCreating);
    3086             :         }
    3087             :       } else {
    3088           0 :         free(mInputData.mValue);
    3089           0 :         mInputData.mValue = ToNewUnicode(value);
    3090           0 :         if (setValueChanged) {
    3091           0 :           SetValueChanged(true);
    3092             :         }
    3093           0 :         if (mType == NS_FORM_INPUT_NUMBER) {
    3094             :           // This has to happen before OnValueChanged is called because that
    3095             :           // method needs the new value of our frame's anon text control.
    3096             :           nsNumberControlFrame* numberControlFrame =
    3097           0 :             do_QueryFrame(GetPrimaryFrame());
    3098           0 :           if (numberControlFrame) {
    3099           0 :             numberControlFrame->SetValueOfAnonTextControl(value);
    3100             :           }
    3101           0 :         } else if (mType == NS_FORM_INPUT_RANGE) {
    3102           0 :           nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
    3103           0 :           if (frame) {
    3104           0 :             frame->UpdateForValueChange();
    3105             :           }
    3106           0 :         } else if ((mType == NS_FORM_INPUT_TIME ||
    3107           0 :                     mType == NS_FORM_INPUT_DATE) &&
    3108           0 :                    !IsExperimentalMobileType(mType) &&
    3109           0 :                    !(aFlags & nsTextEditorState::eSetValue_BySetUserInput)) {
    3110           0 :           nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
    3111           0 :           if (frame) {
    3112           0 :             frame->OnValueChanged();
    3113             :           }
    3114             :         }
    3115           0 :         if (mDoneCreating) {
    3116             :           OnValueChanged(/* aNotify = */ true,
    3117           0 :                          /* aWasInteractiveUserChange = */ false);
    3118             :         }
    3119             :         // else DoneCreatingElement calls us again once mDoneCreating is true
    3120             :       }
    3121             : 
    3122           4 :       if (mType == NS_FORM_INPUT_COLOR) {
    3123             :         // Update color frame, to reflect color changes
    3124           0 :         nsColorControlFrame* colorControlFrame = do_QueryFrame(GetPrimaryFrame());
    3125           0 :         if (colorControlFrame) {
    3126           0 :           colorControlFrame->UpdateColor();
    3127             :         }
    3128             :       }
    3129             : 
    3130             :       // This call might be useless in some situations because if the element is
    3131             :       // a single line text control, nsTextEditorState::SetValue will call
    3132             :       // nsHTMLInputElement::OnValueChanged which is going to call UpdateState()
    3133             :       // if the element is focused. This bug 665547.
    3134           8 :       if (PlaceholderApplies() &&
    3135           4 :           HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
    3136           1 :         UpdateState(true);
    3137             :       }
    3138             : 
    3139           4 :       return NS_OK;
    3140             :     }
    3141             : 
    3142             :     case VALUE_MODE_DEFAULT:
    3143             :     case VALUE_MODE_DEFAULT_ON:
    3144             :       // If the value of a hidden input was changed, we mark it changed so that we
    3145             :       // will know we need to save / restore the value.  Yes, we are overloading
    3146             :       // the meaning of ValueChanged just a teensy bit to save a measly byte of
    3147             :       // storage space in HTMLInputElement.  Yes, you are free to make a new flag,
    3148             :       // NEED_TO_SAVE_VALUE, at such time as mBitField becomes a 16-bit value.
    3149           0 :       if (mType == NS_FORM_INPUT_HIDDEN) {
    3150           0 :         SetValueChanged(true);
    3151             :       }
    3152             : 
    3153             :       // Treat value == defaultValue for other input elements.
    3154           0 :       return nsGenericHTMLFormElementWithState::SetAttr(kNameSpaceID_None,
    3155             :                                                         nsGkAtoms::value, aValue,
    3156           0 :                                                         true);
    3157             : 
    3158             :     case VALUE_MODE_FILENAME:
    3159           0 :       return NS_ERROR_UNEXPECTED;
    3160             :   }
    3161             : 
    3162             :   // This return statement is required for some compilers.
    3163           0 :   return NS_OK;
    3164             : }
    3165             : 
    3166             : NS_IMETHODIMP
    3167           2 : HTMLInputElement::SetValueChanged(bool aValueChanged)
    3168             : {
    3169           2 :   bool valueChangedBefore = mValueChanged;
    3170             : 
    3171           2 :   mValueChanged = aValueChanged;
    3172             : 
    3173           2 :   if (valueChangedBefore != aValueChanged) {
    3174           1 :     UpdateState(true);
    3175             :   }
    3176             : 
    3177           2 :   return NS_OK;
    3178             : }
    3179             : 
    3180             : NS_IMETHODIMP
    3181           0 : HTMLInputElement::GetChecked(bool* aChecked)
    3182             : {
    3183           0 :   *aChecked = Checked();
    3184           0 :   return NS_OK;
    3185             : }
    3186             : 
    3187             : void
    3188           0 : HTMLInputElement::SetCheckedChanged(bool aCheckedChanged)
    3189             : {
    3190           0 :   DoSetCheckedChanged(aCheckedChanged, true);
    3191           0 : }
    3192             : 
    3193             : void
    3194           0 : HTMLInputElement::DoSetCheckedChanged(bool aCheckedChanged,
    3195             :                                       bool aNotify)
    3196             : {
    3197           0 :   if (mType == NS_FORM_INPUT_RADIO) {
    3198           0 :     if (mCheckedChanged != aCheckedChanged) {
    3199             :       nsCOMPtr<nsIRadioVisitor> visitor =
    3200           0 :         new nsRadioSetCheckedChangedVisitor(aCheckedChanged);
    3201           0 :       VisitGroup(visitor, aNotify);
    3202             :     }
    3203             :   } else {
    3204           0 :     SetCheckedChangedInternal(aCheckedChanged);
    3205             :   }
    3206           0 : }
    3207             : 
    3208             : void
    3209           0 : HTMLInputElement::SetCheckedChangedInternal(bool aCheckedChanged)
    3210             : {
    3211           0 :   bool checkedChangedBefore = mCheckedChanged;
    3212             : 
    3213           0 :   mCheckedChanged = aCheckedChanged;
    3214             : 
    3215             :   // This method can't be called when we are not authorized to notify
    3216             :   // so we do not need a aNotify parameter.
    3217           0 :   if (checkedChangedBefore != aCheckedChanged) {
    3218           0 :     UpdateState(true);
    3219             :   }
    3220           0 : }
    3221             : 
    3222             : NS_IMETHODIMP
    3223           0 : HTMLInputElement::SetChecked(bool aChecked)
    3224             : {
    3225           0 :   DoSetChecked(aChecked, true, true);
    3226           0 :   return NS_OK;
    3227             : }
    3228             : 
    3229             : void
    3230           0 : HTMLInputElement::DoSetChecked(bool aChecked, bool aNotify,
    3231             :                                bool aSetValueChanged)
    3232             : {
    3233             :   // If the user or JS attempts to set checked, whether it actually changes the
    3234             :   // value or not, we say the value was changed so that defaultValue don't
    3235             :   // affect it no more.
    3236           0 :   if (aSetValueChanged) {
    3237           0 :     DoSetCheckedChanged(true, aNotify);
    3238             :   }
    3239             : 
    3240             :   // Don't do anything if we're not changing whether it's checked (it would
    3241             :   // screw up state actually, especially when you are setting radio button to
    3242             :   // false)
    3243           0 :   if (mChecked == aChecked) {
    3244           0 :     return;
    3245             :   }
    3246             : 
    3247             :   // Set checked
    3248           0 :   if (mType != NS_FORM_INPUT_RADIO) {
    3249           0 :     SetCheckedInternal(aChecked, aNotify);
    3250           0 :     return;
    3251             :   }
    3252             : 
    3253             :   // For radio button, we need to do some extra fun stuff
    3254           0 :   if (aChecked) {
    3255           0 :     RadioSetChecked(aNotify);
    3256           0 :     return;
    3257             :   }
    3258             : 
    3259           0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
    3260           0 :   if (container) {
    3261           0 :     nsAutoString name;
    3262           0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    3263           0 :     container->SetCurrentRadioButton(name, nullptr);
    3264             :   }
    3265             :   // SetCheckedInternal is going to ask all radios to update their
    3266             :   // validity state. We have to be sure the radio group container knows
    3267             :   // the currently selected radio.
    3268           0 :   SetCheckedInternal(false, aNotify);
    3269             : }
    3270             : 
    3271             : void
    3272           0 : HTMLInputElement::RadioSetChecked(bool aNotify)
    3273             : {
    3274             :   // Find the selected radio button so we can deselect it
    3275           0 :   nsCOMPtr<nsIDOMHTMLInputElement> currentlySelected = GetSelectedRadioButton();
    3276             : 
    3277             :   // Deselect the currently selected radio button
    3278           0 :   if (currentlySelected) {
    3279             :     // Pass true for the aNotify parameter since the currently selected
    3280             :     // button is already in the document.
    3281           0 :     static_cast<HTMLInputElement*>(currentlySelected.get())
    3282           0 :       ->SetCheckedInternal(false, true);
    3283             :   }
    3284             : 
    3285             :   // Let the group know that we are now the One True Radio Button
    3286           0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
    3287           0 :   if (container) {
    3288           0 :     nsAutoString name;
    3289           0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    3290           0 :     container->SetCurrentRadioButton(name, this);
    3291             :   }
    3292             : 
    3293             :   // SetCheckedInternal is going to ask all radios to update their
    3294             :   // validity state.
    3295           0 :   SetCheckedInternal(true, aNotify);
    3296           0 : }
    3297             : 
    3298             : nsIRadioGroupContainer*
    3299           0 : HTMLInputElement::GetRadioGroupContainer() const
    3300             : {
    3301           0 :   NS_ASSERTION(mType == NS_FORM_INPUT_RADIO,
    3302             :                "GetRadioGroupContainer should only be called when type='radio'");
    3303             : 
    3304           0 :   nsAutoString name;
    3305           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    3306             : 
    3307           0 :   if (name.IsEmpty()) {
    3308           0 :     return nullptr;
    3309             :   }
    3310             : 
    3311           0 :   if (mForm) {
    3312           0 :     return mForm;
    3313             :   }
    3314             : 
    3315             :   //XXXsmaug It isn't clear how this should work in Shadow DOM.
    3316           0 :   return static_cast<nsDocument*>(GetUncomposedDoc());
    3317             : }
    3318             : 
    3319             : already_AddRefed<nsIDOMHTMLInputElement>
    3320           0 : HTMLInputElement::GetSelectedRadioButton() const
    3321             : {
    3322           0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
    3323           0 :   if (!container) {
    3324           0 :     return nullptr;
    3325             :   }
    3326             : 
    3327           0 :   nsAutoString name;
    3328           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    3329             : 
    3330           0 :   nsCOMPtr<nsIDOMHTMLInputElement> selected = container->GetCurrentRadioButton(name);
    3331           0 :   return selected.forget();
    3332             : }
    3333             : 
    3334             : nsresult
    3335           0 : HTMLInputElement::MaybeSubmitForm(nsPresContext* aPresContext)
    3336             : {
    3337           0 :   if (!mForm) {
    3338             :     // Nothing to do here.
    3339           0 :     return NS_OK;
    3340             :   }
    3341             : 
    3342           0 :   nsCOMPtr<nsIPresShell> shell = aPresContext->GetPresShell();
    3343           0 :   if (!shell) {
    3344           0 :     return NS_OK;
    3345             :   }
    3346             : 
    3347             :   // Get the default submit element
    3348           0 :   nsIFormControl* submitControl = mForm->GetDefaultSubmitElement();
    3349           0 :   if (submitControl) {
    3350           0 :     nsCOMPtr<nsIContent> submitContent = do_QueryInterface(submitControl);
    3351           0 :     NS_ASSERTION(submitContent, "Form control not implementing nsIContent?!");
    3352             :     // Fire the button's onclick handler and let the button handle
    3353             :     // submitting the form.
    3354           0 :     WidgetMouseEvent event(true, eMouseClick, nullptr, WidgetMouseEvent::eReal);
    3355           0 :     nsEventStatus status = nsEventStatus_eIgnore;
    3356           0 :     shell->HandleDOMEventWithTarget(submitContent, &event, &status);
    3357           0 :   } else if (!mForm->ImplicitSubmissionIsDisabled() &&
    3358           0 :              mForm->SubmissionCanProceed(nullptr)) {
    3359             :     // TODO: removing this code and have the submit event sent by the form,
    3360             :     // bug 592124.
    3361             :     // If there's only one text control, just submit the form
    3362             :     // Hold strong ref across the event
    3363           0 :     RefPtr<mozilla::dom::HTMLFormElement> form = mForm;
    3364           0 :     InternalFormEvent event(true, eFormSubmit);
    3365           0 :     nsEventStatus status = nsEventStatus_eIgnore;
    3366           0 :     shell->HandleDOMEventWithTarget(form, &event, &status);
    3367             :   }
    3368             : 
    3369           0 :   return NS_OK;
    3370             : }
    3371             : 
    3372             : void
    3373           0 : HTMLInputElement::SetCheckedInternal(bool aChecked, bool aNotify)
    3374             : {
    3375             :   // Set the value
    3376           0 :   mChecked = aChecked;
    3377             : 
    3378             :   // Notify the frame
    3379           0 :   if (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO) {
    3380           0 :     nsIFrame* frame = GetPrimaryFrame();
    3381           0 :     if (frame) {
    3382           0 :       frame->InvalidateFrameSubtree();
    3383             :     }
    3384             :   }
    3385             : 
    3386           0 :   UpdateAllValidityStates(aNotify);
    3387             : 
    3388             :   // Notify the document that the CSS :checked pseudoclass for this element
    3389             :   // has changed state.
    3390           0 :   UpdateState(aNotify);
    3391             : 
    3392             :   // Notify all radios in the group that value has changed, this is to let
    3393             :   // radios to have the chance to update its states, e.g., :indeterminate.
    3394           0 :   if (mType == NS_FORM_INPUT_RADIO) {
    3395           0 :     nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this);
    3396           0 :     VisitGroup(visitor, aNotify);
    3397             :   }
    3398           0 : }
    3399             : 
    3400             : void
    3401           0 : HTMLInputElement::Blur(ErrorResult& aError)
    3402             : {
    3403           0 :   if (mType == NS_FORM_INPUT_NUMBER) {
    3404             :     // Blur our anonymous text control, if we have one. (DOM 'change' event
    3405             :     // firing and other things depend on this.)
    3406             :     nsNumberControlFrame* numberControlFrame =
    3407           0 :       do_QueryFrame(GetPrimaryFrame());
    3408           0 :     if (numberControlFrame) {
    3409           0 :       HTMLInputElement* textControl = numberControlFrame->GetAnonTextControl();
    3410           0 :       if (textControl) {
    3411           0 :         textControl->Blur(aError);
    3412           0 :         return;
    3413             :       }
    3414             :     }
    3415             :   }
    3416             : 
    3417           0 :   if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
    3418           0 :       !IsExperimentalMobileType(mType)) {
    3419           0 :     nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
    3420           0 :     if (frame) {
    3421           0 :       frame->HandleBlurEvent();
    3422           0 :       return;
    3423             :     }
    3424             :   }
    3425             : 
    3426           0 :   nsGenericHTMLElement::Blur(aError);
    3427             : }
    3428             : 
    3429             : void
    3430           0 : HTMLInputElement::Focus(ErrorResult& aError)
    3431             : {
    3432           0 :   if (mType == NS_FORM_INPUT_NUMBER) {
    3433             :     // Focus our anonymous text control, if we have one.
    3434             :     nsNumberControlFrame* numberControlFrame =
    3435           0 :       do_QueryFrame(GetPrimaryFrame());
    3436           0 :     if (numberControlFrame) {
    3437           0 :       HTMLInputElement* textControl = numberControlFrame->GetAnonTextControl();
    3438           0 :       if (textControl) {
    3439           0 :         textControl->Focus(aError);
    3440           0 :         return;
    3441             :       }
    3442             :     }
    3443             :   }
    3444             : 
    3445           0 :   if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
    3446           0 :       !IsExperimentalMobileType(mType)) {
    3447           0 :     nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
    3448           0 :     if (frame) {
    3449           0 :       frame->HandleFocusEvent();
    3450           0 :       return;
    3451             :     }
    3452             :   }
    3453             : 
    3454           0 :   if (mType != NS_FORM_INPUT_FILE) {
    3455           0 :     nsGenericHTMLElement::Focus(aError);
    3456           0 :     return;
    3457             :   }
    3458             : 
    3459             :   // For file inputs, focus the first button instead. In the case of there
    3460             :   // being two buttons (when the picker is a directory picker) the user can
    3461             :   // tab to the next one.
    3462           0 :   nsIFrame* frame = GetPrimaryFrame();
    3463           0 :   if (frame) {
    3464           0 :     for (nsIFrame* childFrame : frame->PrincipalChildList()) {
    3465             :       // See if the child is a button control.
    3466             :       nsCOMPtr<nsIFormControl> formCtrl =
    3467           0 :         do_QueryInterface(childFrame->GetContent());
    3468           0 :       if (formCtrl && formCtrl->ControlType() == NS_FORM_BUTTON_BUTTON) {
    3469           0 :         nsCOMPtr<nsIDOMElement> element = do_QueryInterface(formCtrl);
    3470           0 :         nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3471           0 :         if (fm && element) {
    3472           0 :           fm->SetFocus(element, 0);
    3473             :         }
    3474           0 :         break;
    3475             :       }
    3476             :     }
    3477             :   }
    3478             : 
    3479           0 :   return;
    3480             : }
    3481             : 
    3482             : #if !defined(ANDROID) && !defined(XP_MACOSX)
    3483             : bool
    3484           0 : HTMLInputElement::IsNodeApzAwareInternal() const
    3485             : {
    3486             :   // Tell APZC we may handle mouse wheel event and do preventDefault when input
    3487             :   // type is number.
    3488           0 :   return (mType == NS_FORM_INPUT_NUMBER) || (mType == NS_FORM_INPUT_RANGE) ||
    3489           0 :          nsINode::IsNodeApzAwareInternal();
    3490             : }
    3491             : #endif
    3492             : 
    3493             : bool
    3494           0 : HTMLInputElement::IsInteractiveHTMLContent(bool aIgnoreTabindex) const
    3495             : {
    3496           0 :   return mType != NS_FORM_INPUT_HIDDEN ||
    3497           0 :          nsGenericHTMLFormElementWithState::IsInteractiveHTMLContent(aIgnoreTabindex);
    3498             : }
    3499             : 
    3500             : void
    3501           2 : HTMLInputElement::AsyncEventRunning(AsyncEventDispatcher* aEvent)
    3502             : {
    3503           2 :   nsImageLoadingContent::AsyncEventRunning(aEvent);
    3504           2 : }
    3505             : 
    3506             : NS_IMETHODIMP
    3507           0 : HTMLInputElement::Select()
    3508             : {
    3509           0 :   if (mType == NS_FORM_INPUT_NUMBER) {
    3510             :     nsNumberControlFrame* numberControlFrame =
    3511           0 :       do_QueryFrame(GetPrimaryFrame());
    3512           0 :     if (numberControlFrame) {
    3513           0 :       return numberControlFrame->HandleSelectCall();
    3514             :     }
    3515           0 :     return NS_OK;
    3516             :   }
    3517             : 
    3518           0 :   if (!IsSingleLineTextControl(false)) {
    3519           0 :     return NS_OK;
    3520             :   }
    3521             : 
    3522             :   // XXX Bug?  We have to give the input focus before contents can be
    3523             :   // selected
    3524             : 
    3525           0 :   FocusTristate state = FocusState();
    3526           0 :   if (state == eUnfocusable) {
    3527           0 :     return NS_OK;
    3528             :   }
    3529             : 
    3530           0 :   nsTextEditorState* tes = GetEditorState();
    3531           0 :   if (tes) {
    3532           0 :     RefPtr<nsFrameSelection> fs = tes->GetConstFrameSelection();
    3533           0 :     if (fs && fs->MouseDownRecorded()) {
    3534             :       // This means that we're being called while the frame selection has a mouse
    3535             :       // down event recorded to adjust the caret during the mouse up event.
    3536             :       // We are probably called from the focus event handler.  We should override
    3537             :       // the delayed caret data in this case to ensure that this select() call
    3538             :       // takes effect.
    3539           0 :       fs->SetDelayedCaretData(nullptr);
    3540             :     }
    3541             :   }
    3542             : 
    3543           0 :   nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    3544             : 
    3545           0 :   RefPtr<nsPresContext> presContext = GetPresContext(eForComposedDoc);
    3546           0 :   if (state == eInactiveWindow) {
    3547           0 :     if (fm)
    3548           0 :       fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
    3549           0 :     SelectAll(presContext);
    3550           0 :     return NS_OK;
    3551             :   }
    3552             : 
    3553           0 :   if (DispatchSelectEvent(presContext) && fm) {
    3554           0 :     fm->SetFocus(this, nsIFocusManager::FLAG_NOSCROLL);
    3555             : 
    3556             :     // ensure that the element is actually focused
    3557           0 :     nsCOMPtr<nsIDOMElement> focusedElement;
    3558           0 :     fm->GetFocusedElement(getter_AddRefs(focusedElement));
    3559           0 :     if (SameCOMIdentity(static_cast<nsIDOMNode*>(this), focusedElement)) {
    3560             :       // Now Select all the text!
    3561           0 :       SelectAll(presContext);
    3562             :     }
    3563             :   }
    3564             : 
    3565           0 :   return NS_OK;
    3566             : }
    3567             : 
    3568             : bool
    3569           0 : HTMLInputElement::DispatchSelectEvent(nsPresContext* aPresContext)
    3570             : {
    3571           0 :   nsEventStatus status = nsEventStatus_eIgnore;
    3572             : 
    3573             :   // If already handling select event, don't dispatch a second.
    3574           0 :   if (!mHandlingSelectEvent) {
    3575           0 :     WidgetEvent event(true, eFormSelect);
    3576             : 
    3577           0 :     mHandlingSelectEvent = true;
    3578           0 :     EventDispatcher::Dispatch(static_cast<nsIContent*>(this),
    3579           0 :                               aPresContext, &event, nullptr, &status);
    3580           0 :     mHandlingSelectEvent = false;
    3581             :   }
    3582             : 
    3583             :   // If the DOM event was not canceled (e.g. by a JS event handler
    3584             :   // returning false)
    3585           0 :   return (status == nsEventStatus_eIgnore);
    3586             : }
    3587             : 
    3588             : void
    3589           0 : HTMLInputElement::SelectAll(nsPresContext* aPresContext)
    3590             : {
    3591           0 :   nsIFormControlFrame* formControlFrame = GetFormControlFrame(true);
    3592             : 
    3593           0 :   if (formControlFrame) {
    3594           0 :     formControlFrame->SetFormProperty(nsGkAtoms::select, EmptyString());
    3595             :   }
    3596           0 : }
    3597             : 
    3598             : bool
    3599           4 : HTMLInputElement::NeedToInitializeEditorForEvent(
    3600             :                     EventChainPreVisitor& aVisitor) const
    3601             : {
    3602             :   // We only need to initialize the editor for single line input controls because they
    3603             :   // are lazily initialized.  We don't need to initialize the control for
    3604             :   // certain types of events, because we know that those events are safe to be
    3605             :   // handled without the editor being initialized.  These events include:
    3606             :   // mousein/move/out, overflow/underflow, and DOM mutation events.
    3607           8 :   if (!IsSingleLineTextControl(false) ||
    3608           4 :       aVisitor.mEvent->mClass == eMutationEventClass) {
    3609           0 :     return false;
    3610             :   }
    3611             : 
    3612           4 :   switch (aVisitor.mEvent->mMessage) {
    3613             :   case eMouseMove:
    3614             :   case eMouseEnterIntoWidget:
    3615             :   case eMouseExitFromWidget:
    3616             :   case eMouseOver:
    3617             :   case eMouseOut:
    3618             :   case eScrollPortUnderflow:
    3619             :   case eScrollPortOverflow:
    3620           1 :     return false;
    3621             :   default:
    3622           3 :     return true;
    3623             :   }
    3624             : }
    3625             : 
    3626             : bool
    3627           4 : HTMLInputElement::IsDisabledForEvents(EventMessage aMessage)
    3628             : {
    3629           4 :   return IsElementDisabledForEvents(aMessage, GetPrimaryFrame());
    3630             : }
    3631             : 
    3632             : nsresult
    3633           4 : HTMLInputElement::GetEventTargetParent(EventChainPreVisitor& aVisitor)
    3634             : {
    3635             :   // Do not process any DOM events if the element is disabled
    3636           4 :   aVisitor.mCanHandle = false;
    3637           4 :   if (IsDisabledForEvents(aVisitor.mEvent->mMessage)) {
    3638           0 :     return NS_OK;
    3639             :   }
    3640             : 
    3641             :   // Initialize the editor if needed.
    3642           4 :   if (NeedToInitializeEditorForEvent(aVisitor)) {
    3643           3 :     nsITextControlFrame* textControlFrame = do_QueryFrame(GetPrimaryFrame());
    3644           3 :     if (textControlFrame)
    3645           3 :       textControlFrame->EnsureEditorInitialized();
    3646             :   }
    3647             : 
    3648             :   //FIXME Allow submission etc. also when there is no prescontext, Bug 329509.
    3649           4 :   if (!aVisitor.mPresContext) {
    3650           0 :     return nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
    3651             :   }
    3652             :   //
    3653             :   // Web pages expect the value of a radio button or checkbox to be set
    3654             :   // *before* onclick and DOMActivate fire, and they expect that if they set
    3655             :   // the value explicitly during onclick or DOMActivate it will not be toggled
    3656             :   // or any such nonsense.
    3657             :   // In order to support that (bug 57137 and 58460 are examples) we toggle
    3658             :   // the checked attribute *first*, and then fire onclick.  If the user
    3659             :   // returns false, we reset the control to the old checked value.  Otherwise,
    3660             :   // we dispatch DOMActivate.  If DOMActivate is cancelled, we also reset
    3661             :   // the control to the old checked value.  We need to keep track of whether
    3662             :   // we've already toggled the state from onclick since the user could
    3663             :   // explicitly dispatch DOMActivate on the element.
    3664             :   //
    3665             :   // This is a compatibility hack.
    3666             :   //
    3667             : 
    3668             :   // Track whether we're in the outermost Dispatch invocation that will
    3669             :   // cause activation of the input.  That is, if we're a click event, or a
    3670             :   // DOMActivate that was dispatched directly, this will be set, but if we're
    3671             :   // a DOMActivate dispatched from click handling, it will not be set.
    3672           4 :   WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
    3673             :   bool outerActivateEvent =
    3674           8 :     ((mouseEvent && mouseEvent->IsLeftClickEvent()) ||
    3675           8 :      (aVisitor.mEvent->mMessage == eLegacyDOMActivate && !mInInternalActivate));
    3676             : 
    3677           4 :   if (outerActivateEvent) {
    3678           0 :     aVisitor.mItemFlags |= NS_OUTER_ACTIVATE_EVENT;
    3679             :   }
    3680             : 
    3681           4 :   bool originalCheckedValue = false;
    3682             : 
    3683           4 :   if (outerActivateEvent) {
    3684           0 :     mCheckedIsToggled = false;
    3685             : 
    3686           0 :     switch(mType) {
    3687             :       case NS_FORM_INPUT_CHECKBOX:
    3688             :         {
    3689           0 :           if (mIndeterminate) {
    3690             :             // indeterminate is always set to FALSE when the checkbox is toggled
    3691           0 :             SetIndeterminateInternal(false, false);
    3692           0 :             aVisitor.mItemFlags |= NS_ORIGINAL_INDETERMINATE_VALUE;
    3693             :           }
    3694             : 
    3695           0 :           GetChecked(&originalCheckedValue);
    3696           0 :           DoSetChecked(!originalCheckedValue, true, true);
    3697           0 :           mCheckedIsToggled = true;
    3698             :         }
    3699           0 :         break;
    3700             : 
    3701             :       case NS_FORM_INPUT_RADIO:
    3702             :         {
    3703           0 :           nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton = GetSelectedRadioButton();
    3704           0 :           aVisitor.mItemData = selectedRadioButton;
    3705             : 
    3706           0 :           originalCheckedValue = mChecked;
    3707           0 :           if (!originalCheckedValue) {
    3708           0 :             DoSetChecked(true, true, true);
    3709           0 :             mCheckedIsToggled = true;
    3710             :           }
    3711             :         }
    3712           0 :         break;
    3713             : 
    3714             :       case NS_FORM_INPUT_SUBMIT:
    3715             :       case NS_FORM_INPUT_IMAGE:
    3716           0 :         if (mForm) {
    3717             :           // tell the form that we are about to enter a click handler.
    3718             :           // that means that if there are scripted submissions, the
    3719             :           // latest one will be deferred until after the exit point of the handler.
    3720           0 :           mForm->OnSubmitClickBegin(this);
    3721             :         }
    3722           0 :         break;
    3723             : 
    3724             :       default:
    3725           0 :         break;
    3726             :     }
    3727             :   }
    3728             : 
    3729           4 :   if (originalCheckedValue) {
    3730           0 :     aVisitor.mItemFlags |= NS_ORIGINAL_CHECKED_VALUE;
    3731             :   }
    3732             : 
    3733             :   // If mNoContentDispatch is true we will not allow content to handle
    3734             :   // this event.  But to allow middle mouse button paste to work we must allow
    3735             :   // middle clicks to go to text fields anyway.
    3736           4 :   if (aVisitor.mEvent->mFlags.mNoContentDispatch) {
    3737           0 :     aVisitor.mItemFlags |= NS_NO_CONTENT_DISPATCH;
    3738             :   }
    3739          12 :   if (IsSingleLineTextControl(false) &&
    3740           4 :       aVisitor.mEvent->mMessage == eMouseClick &&
    3741           0 :       aVisitor.mEvent->AsMouseEvent()->button ==
    3742             :         WidgetMouseEvent::eMiddleButton) {
    3743           0 :     aVisitor.mEvent->mFlags.mNoContentDispatch = false;
    3744             :   }
    3745             : 
    3746             :   // We must cache type because mType may change during JS event (bug 2369)
    3747           4 :   aVisitor.mItemFlags |= mType;
    3748             : 
    3749           8 :   if (aVisitor.mEvent->mMessage == eFocus &&
    3750           0 :       aVisitor.mEvent->IsTrusted() &&
    3751           4 :       MayFireChangeOnBlur() &&
    3752             :       // StartRangeThumbDrag already set mFocusedValue on 'mousedown' before
    3753             :       // we get the 'focus' event.
    3754           0 :       !mIsDraggingRange) {
    3755           0 :     GetValue(mFocusedValue, CallerType::System);
    3756             :   }
    3757             : 
    3758             :   // Fire onchange (if necessary), before we do the blur, bug 357684.
    3759           4 :   if (aVisitor.mEvent->mMessage == eBlur) {
    3760             :     // We set NS_PRE_HANDLE_BLUR_EVENT here and handle it in PreHandleEvent to
    3761             :     // prevent breaking event target chain creation.
    3762           0 :     aVisitor.mWantsPreHandleEvent = true;
    3763           0 :     aVisitor.mItemFlags |= NS_PRE_HANDLE_BLUR_EVENT;
    3764             :   }
    3765             : 
    3766           4 :   if (mType == NS_FORM_INPUT_RANGE &&
    3767           0 :       (aVisitor.mEvent->mMessage == eFocus ||
    3768           0 :        aVisitor.mEvent->mMessage == eBlur)) {
    3769             :     // Just as nsGenericHTMLFormElementWithState::GetEventTargetParent calls
    3770             :     // nsIFormControlFrame::SetFocus, we handle focus here.
    3771           0 :     nsIFrame* frame = GetPrimaryFrame();
    3772           0 :     if (frame) {
    3773           0 :       frame->InvalidateFrameSubtree();
    3774             :     }
    3775             :   }
    3776             : 
    3777          12 :   if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
    3778           0 :       !IsExperimentalMobileType(mType) &&
    3779           4 :       aVisitor.mEvent->mMessage == eFocus &&
    3780           0 :       aVisitor.mEvent->mOriginalTarget == this) {
    3781             :     // If original target is this and not the anonymous text control, we should
    3782             :     // pass the focus to the anonymous text control.
    3783           0 :     nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
    3784           0 :     if (frame) {
    3785           0 :       frame->HandleFocusEvent();
    3786             :     }
    3787             :   }
    3788             : 
    3789           4 :   if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
    3790           0 :     if (mNumberControlSpinnerIsSpinning) {
    3791             :       // If the timer is running the user has depressed the mouse on one of the
    3792             :       // spin buttons. If the mouse exits the button we either want to reverse
    3793             :       // the direction of spin if it has moved over the other button, or else
    3794             :       // we want to end the spin. We do this here (rather than in
    3795             :       // PostHandleEvent) because we don't want to let content preventDefault()
    3796             :       // the end of the spin.
    3797           0 :       if (aVisitor.mEvent->mMessage == eMouseMove) {
    3798             :         // Be aggressive about stopping the spin:
    3799           0 :         bool stopSpin = true;
    3800             :         nsNumberControlFrame* numberControlFrame =
    3801           0 :           do_QueryFrame(GetPrimaryFrame());
    3802           0 :         if (numberControlFrame) {
    3803             :           bool oldNumberControlSpinTimerSpinsUpValue =
    3804           0 :                  mNumberControlSpinnerSpinsUp;
    3805           0 :           switch (numberControlFrame->GetSpinButtonForPointerEvent(
    3806           0 :                     aVisitor.mEvent->AsMouseEvent())) {
    3807             :           case nsNumberControlFrame::eSpinButtonUp:
    3808           0 :             mNumberControlSpinnerSpinsUp = true;
    3809           0 :             stopSpin = false;
    3810           0 :             break;
    3811             :           case nsNumberControlFrame::eSpinButtonDown:
    3812           0 :             mNumberControlSpinnerSpinsUp = false;
    3813           0 :             stopSpin = false;
    3814           0 :             break;
    3815             :           }
    3816           0 :           if (mNumberControlSpinnerSpinsUp !=
    3817             :                 oldNumberControlSpinTimerSpinsUpValue) {
    3818             :             nsNumberControlFrame* numberControlFrame =
    3819           0 :               do_QueryFrame(GetPrimaryFrame());
    3820           0 :             if (numberControlFrame) {
    3821           0 :               numberControlFrame->SpinnerStateChanged();
    3822             :             }
    3823             :           }
    3824             :         }
    3825           0 :         if (stopSpin) {
    3826           0 :           StopNumberControlSpinnerSpin();
    3827             :         }
    3828           0 :       } else if (aVisitor.mEvent->mMessage == eMouseUp) {
    3829           0 :         StopNumberControlSpinnerSpin();
    3830             :       }
    3831             :     }
    3832           0 :     if (aVisitor.mEvent->mMessage == eFocus ||
    3833           0 :         aVisitor.mEvent->mMessage == eBlur) {
    3834           0 :       if (aVisitor.mEvent->mMessage == eFocus) {
    3835             :         // Tell our frame it's getting focus so that it can make sure focus
    3836             :         // is moved to our anonymous text control.
    3837             :         nsNumberControlFrame* numberControlFrame =
    3838           0 :           do_QueryFrame(GetPrimaryFrame());
    3839           0 :         if (numberControlFrame) {
    3840             :           // This could kill the frame!
    3841           0 :           numberControlFrame->HandleFocusEvent(aVisitor.mEvent);
    3842             :         }
    3843             :       }
    3844           0 :       nsIFrame* frame = GetPrimaryFrame();
    3845           0 :       if (frame && frame->IsThemed()) {
    3846             :         // Our frame's nested <input type=text> will be invalidated when it
    3847             :         // loses focus, but since we are also native themed we need to make
    3848             :         // sure that our entire area is repainted since any focus highlight
    3849             :         // from the theme should be removed from us (the repainting of the
    3850             :         // sub-area occupied by the anon text control is not enough to do
    3851             :         // that).
    3852           0 :         frame->InvalidateFrame();
    3853             :       }
    3854             :     }
    3855             :   }
    3856             : 
    3857           4 :   nsresult rv = nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);
    3858             : 
    3859             :   // We do this after calling the base class' GetEventTargetParent so that
    3860             :   // nsIContent::GetEventTargetParent doesn't reset any change we make to
    3861             :   // mCanHandle.
    3862           8 :   if (mType == NS_FORM_INPUT_NUMBER &&
    3863           4 :       aVisitor.mEvent->IsTrusted()  &&
    3864           0 :       aVisitor.mEvent->mOriginalTarget != this) {
    3865             :     // <input type=number> has an anonymous <input type=text> descendant. If
    3866             :     // 'input' or 'change' events are fired at that text control then we need
    3867             :     // to do some special handling here.
    3868           0 :     HTMLInputElement* textControl = nullptr;
    3869             :     nsNumberControlFrame* numberControlFrame =
    3870           0 :       do_QueryFrame(GetPrimaryFrame());
    3871           0 :     if (numberControlFrame) {
    3872           0 :       textControl = numberControlFrame->GetAnonTextControl();
    3873             :     }
    3874           0 :     if (textControl && aVisitor.mEvent->mOriginalTarget == textControl) {
    3875           0 :       if (aVisitor.mEvent->mMessage == eEditorInput) {
    3876           0 :         aVisitor.mWantsPreHandleEvent = true;
    3877             :         // We set NS_PRE_HANDLE_INPUT_EVENT here and handle it in PreHandleEvent
    3878             :         // to prevent breaking event target chain creation.
    3879           0 :         aVisitor.mItemFlags |= NS_PRE_HANDLE_INPUT_EVENT;
    3880             :       }
    3881           0 :       else if (aVisitor.mEvent->mMessage == eFormChange) {
    3882             :         // We cancel the DOM 'change' event that is fired for any change to our
    3883             :         // anonymous text control since we fire our own 'change' events and
    3884             :         // content shouldn't be seeing two 'change' events. Besides that we
    3885             :         // (as a number) control have tighter restrictions on when our internal
    3886             :         // value changes than our anon text control does, so in some cases
    3887             :         // (if our text control's value doesn't parse as a number) we don't
    3888             :         // want to fire a 'change' event at all.
    3889           0 :         aVisitor.mCanHandle = false;
    3890             :       }
    3891             :     }
    3892             :   }
    3893             : 
    3894             :   // Stop the event if the related target's first non-native ancestor is the
    3895             :   // same as the original target's first non-native ancestor (we are moving
    3896             :   // inside of the same element).
    3897          12 :   if ((mType == NS_FORM_INPUT_TIME || mType == NS_FORM_INPUT_DATE) &&
    3898           0 :       !IsExperimentalMobileType(mType) &&
    3899           4 :       aVisitor.mEvent->IsTrusted() &&
    3900           0 :       (aVisitor.mEvent->mMessage == eFocus ||
    3901           0 :        aVisitor.mEvent->mMessage == eFocusIn ||
    3902           0 :        aVisitor.mEvent->mMessage == eFocusOut ||
    3903           0 :        aVisitor.mEvent->mMessage == eBlur)) {
    3904             :     nsCOMPtr<nsIContent> originalTarget =
    3905           0 :       do_QueryInterface(aVisitor.mEvent->AsFocusEvent()->mOriginalTarget);
    3906             :     nsCOMPtr<nsIContent> relatedTarget =
    3907           0 :       do_QueryInterface(aVisitor.mEvent->AsFocusEvent()->mRelatedTarget);
    3908             : 
    3909           0 :     if (originalTarget && relatedTarget &&
    3910           0 :         originalTarget->FindFirstNonChromeOnlyAccessContent() ==
    3911           0 :         relatedTarget->FindFirstNonChromeOnlyAccessContent()) {
    3912           0 :       aVisitor.mCanHandle = false;
    3913             :     }
    3914             :   }
    3915             : 
    3916           4 :   return rv;
    3917             : }
    3918             : 
    3919             : nsresult
    3920           0 : HTMLInputElement::PreHandleEvent(EventChainVisitor& aVisitor)
    3921             : {
    3922           0 :   if (!aVisitor.mPresContext) {
    3923           0 :     return nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
    3924             :   }
    3925             :   nsresult rv;
    3926           0 :   if (aVisitor.mItemFlags & NS_PRE_HANDLE_BLUR_EVENT) {
    3927           0 :     MOZ_ASSERT(aVisitor.mEvent->mMessage == eBlur);
    3928             :     // Experimental mobile types rely on the system UI to prevent users to not
    3929             :     // set invalid values but we have to be extra-careful. Especially if the
    3930             :     // option has been enabled on desktop.
    3931           0 :     if (IsExperimentalMobileType(mType)) {
    3932           0 :       nsAutoString aValue;
    3933           0 :       GetNonFileValueInternal(aValue);
    3934           0 :       rv = SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
    3935           0 :       NS_ENSURE_SUCCESS(rv, rv);
    3936             :     }
    3937           0 :     FireChangeEventIfNeeded();
    3938             :   }
    3939           0 :   rv = nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);
    3940           0 :   if (aVisitor.mItemFlags & NS_PRE_HANDLE_INPUT_EVENT) {
    3941           0 :     nsNumberControlFrame* numberControlFrame = do_QueryFrame(GetPrimaryFrame());
    3942           0 :     MOZ_ASSERT(aVisitor.mEvent->mMessage == eEditorInput);
    3943           0 :     MOZ_ASSERT(numberControlFrame);
    3944           0 :     MOZ_ASSERT(numberControlFrame->GetAnonTextControl() ==
    3945             :                aVisitor.mEvent->mOriginalTarget);
    3946             :     // Propogate the anon text control's new value to our HTMLInputElement:
    3947           0 :     nsAutoString value;
    3948           0 :     numberControlFrame->GetValueOfAnonTextControl(value);
    3949           0 :     numberControlFrame->HandlingInputEvent(true);
    3950           0 :     AutoWeakFrame weakNumberControlFrame(numberControlFrame);
    3951             :     rv = SetValueInternal(value,
    3952             :                           nsTextEditorState::eSetValue_BySetUserInput |
    3953           0 :                           nsTextEditorState::eSetValue_Notify);
    3954           0 :     NS_ENSURE_SUCCESS(rv, rv);
    3955           0 :     if (weakNumberControlFrame.IsAlive()) {
    3956           0 :       numberControlFrame->HandlingInputEvent(false);
    3957             :     }
    3958             :   }
    3959           0 :   return rv;
    3960             : }
    3961             : 
    3962             : void
    3963           0 : HTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent* aEvent)
    3964             : {
    3965           0 :   mIsDraggingRange = true;
    3966           0 :   mRangeThumbDragStartValue = GetValueAsDecimal();
    3967             :   // Don't use CAPTURE_RETARGETTOELEMENT, as that breaks pseudo-class styling
    3968             :   // of the thumb.
    3969           0 :   nsIPresShell::SetCapturingContent(this, CAPTURE_IGNOREALLOWED);
    3970           0 :   nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
    3971             : 
    3972             :   // Before we change the value, record the current value so that we'll
    3973             :   // correctly send a 'change' event if appropriate. We need to do this here
    3974             :   // because the 'focus' event is handled after the 'mousedown' event that
    3975             :   // we're being called for (i.e. too late to update mFocusedValue, since we'll
    3976             :   // have changed it by then).
    3977           0 :   GetValue(mFocusedValue, CallerType::System);
    3978             : 
    3979           0 :   SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));
    3980           0 : }
    3981             : 
    3982             : void
    3983           0 : HTMLInputElement::FinishRangeThumbDrag(WidgetGUIEvent* aEvent)
    3984             : {
    3985           0 :   MOZ_ASSERT(mIsDraggingRange);
    3986             : 
    3987           0 :   if (nsIPresShell::GetCapturingContent() == this) {
    3988           0 :     nsIPresShell::SetCapturingContent(nullptr, 0); // cancel capture
    3989             :   }
    3990           0 :   if (aEvent) {
    3991           0 :     nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
    3992           0 :     SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));
    3993             :   }
    3994           0 :   mIsDraggingRange = false;
    3995           0 :   FireChangeEventIfNeeded();
    3996           0 : }
    3997             : 
    3998             : void
    3999           0 : HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent)
    4000             : {
    4001           0 :   MOZ_ASSERT(mIsDraggingRange);
    4002             : 
    4003           0 :   mIsDraggingRange = false;
    4004           0 :   if (nsIPresShell::GetCapturingContent() == this) {
    4005           0 :     nsIPresShell::SetCapturingContent(nullptr, 0); // cancel capture
    4006             :   }
    4007           0 :   if (aIsForUserEvent) {
    4008           0 :     SetValueOfRangeForUserEvent(mRangeThumbDragStartValue);
    4009             :   } else {
    4010             :     // Don't dispatch an 'input' event - at least not using
    4011             :     // DispatchTrustedEvent.
    4012             :     // TODO: decide what we should do here - bug 851782.
    4013           0 :     nsAutoString val;
    4014           0 :     mInputType->ConvertNumberToString(mRangeThumbDragStartValue, val);
    4015             :     // TODO: What should we do if SetValueInternal fails?  (The allocation
    4016             :     // is small, so we should be fine here.)
    4017             :     SetValueInternal(val, nsTextEditorState::eSetValue_BySetUserInput |
    4018           0 :                           nsTextEditorState::eSetValue_Notify);
    4019           0 :     nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
    4020           0 :     if (frame) {
    4021           0 :       frame->UpdateForValueChange();
    4022             :     }
    4023             :     RefPtr<AsyncEventDispatcher> asyncDispatcher =
    4024           0 :       new AsyncEventDispatcher(this, NS_LITERAL_STRING("input"), true, false);
    4025           0 :     asyncDispatcher->RunDOMEventWhenSafe();
    4026             :   }
    4027           0 : }
    4028             : 
    4029             : void
    4030           0 : HTMLInputElement::SetValueOfRangeForUserEvent(Decimal aValue)
    4031             : {
    4032           0 :   MOZ_ASSERT(aValue.isFinite());
    4033             : 
    4034           0 :   Decimal oldValue = GetValueAsDecimal();
    4035             : 
    4036           0 :   nsAutoString val;
    4037           0 :   mInputType->ConvertNumberToString(aValue, val);
    4038             :   // TODO: What should we do if SetValueInternal fails?  (The allocation
    4039             :   // is small, so we should be fine here.)
    4040             :   SetValueInternal(val, nsTextEditorState::eSetValue_BySetUserInput |
    4041           0 :                         nsTextEditorState::eSetValue_Notify);
    4042           0 :   nsRangeFrame* frame = do_QueryFrame(GetPrimaryFrame());
    4043           0 :   if (frame) {
    4044           0 :     frame->UpdateForValueChange();
    4045             :   }
    4046             : 
    4047           0 :   if (GetValueAsDecimal() != oldValue) {
    4048           0 :     nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
    4049             :                                          static_cast<nsIDOMHTMLInputElement*>(this),
    4050           0 :                                          NS_LITERAL_STRING("input"), true,
    4051           0 :                                          false);
    4052             :   }
    4053           0 : }
    4054             : 
    4055             : void
    4056           0 : HTMLInputElement::StartNumberControlSpinnerSpin()
    4057             : {
    4058           0 :   MOZ_ASSERT(!mNumberControlSpinnerIsSpinning);
    4059             : 
    4060           0 :   mNumberControlSpinnerIsSpinning = true;
    4061             : 
    4062           0 :   nsRepeatService::GetInstance()->Start(HandleNumberControlSpin, this, OwnerDoc(),
    4063           0 :                                         NS_LITERAL_CSTRING("HandleNumberControlSpin"));
    4064             : 
    4065             :   // Capture the mouse so that we can tell if the pointer moves from one
    4066             :   // spin button to the other, or to some other element:
    4067           0 :   nsIPresShell::SetCapturingContent(this, CAPTURE_IGNOREALLOWED);
    4068             : 
    4069             :   nsNumberControlFrame* numberControlFrame =
    4070           0 :     do_QueryFrame(GetPrimaryFrame());
    4071           0 :   if (numberControlFrame) {
    4072           0 :     numberControlFrame->SpinnerStateChanged();
    4073             :   }
    4074           0 : }
    4075             : 
    4076             : void
    4077           0 : HTMLInputElement::StopNumberControlSpinnerSpin(SpinnerStopState aState)
    4078             : {
    4079           0 :   if (mNumberControlSpinnerIsSpinning) {
    4080           0 :     if (nsIPresShell::GetCapturingContent() == this) {
    4081           0 :       nsIPresShell::SetCapturingContent(nullptr, 0); // cancel capture
    4082             :     }
    4083             : 
    4084           0 :     nsRepeatService::GetInstance()->Stop(HandleNumberControlSpin, this);
    4085             : 
    4086           0 :     mNumberControlSpinnerIsSpinning = false;
    4087             : 
    4088           0 :     if (aState == eAllowDispatchingEvents) {
    4089           0 :       FireChangeEventIfNeeded();
    4090             :     }
    4091             : 
    4092             :     nsNumberControlFrame* numberControlFrame =
    4093           0 :       do_QueryFrame(GetPrimaryFrame());
    4094           0 :     if (numberControlFrame) {
    4095           0 :       MOZ_ASSERT(aState == eAllowDispatchingEvents,
    4096             :                  "Shouldn't have primary frame for the element when we're not "
    4097             :                  "allowed to dispatch events to it anymore.");
    4098           0 :       numberControlFrame->SpinnerStateChanged();
    4099             :     }
    4100             :   }
    4101           0 : }
    4102             : 
    4103             : void
    4104           0 : HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection)
    4105             : {
    4106             :   // We can't use GetValidityState here because the validity state is not set
    4107             :   // if the user hasn't previously taken an action to set or change the value,
    4108             :   // according to the specs.
    4109           0 :   if (HasBadInput()) {
    4110             :     // If the user has typed a value into the control and inadvertently made a
    4111             :     // mistake (e.g. put a thousand separator at the wrong point) we do not
    4112             :     // want to wipe out what they typed if they try to increment/decrement the
    4113             :     // value. Better is to highlight the value as being invalid so that they
    4114             :     // can correct what they typed.
    4115             :     // We only do this if there actually is a value typed in by/displayed to
    4116             :     // the user. (IsValid() can return false if the 'required' attribute is
    4117             :     // set and the value is the empty string.)
    4118             :     nsNumberControlFrame* numberControlFrame =
    4119           0 :       do_QueryFrame(GetPrimaryFrame());
    4120           0 :     if (numberControlFrame &&
    4121           0 :         !numberControlFrame->AnonTextControlIsEmpty()) {
    4122             :       // We pass 'true' for UpdateValidityUIBits' aIsFocused argument
    4123             :       // regardless because we need the UI to update _now_ or the user will
    4124             :       // wonder why the step behavior isn't functioning.
    4125           0 :       UpdateValidityUIBits(true);
    4126           0 :       UpdateState(true);
    4127           0 :       return;
    4128             :     }
    4129             :   }
    4130             : 
    4131           0 :   Decimal newValue = Decimal::nan(); // unchanged if value will not change
    4132             : 
    4133           0 :   nsresult rv = GetValueIfStepped(aDirection, CALLED_FOR_USER_EVENT, &newValue);
    4134             : 
    4135           0 :   if (NS_FAILED(rv) || !newValue.isFinite()) {
    4136           0 :     return; // value should not or will not change
    4137             :   }
    4138             : 
    4139           0 :   nsAutoString newVal;
    4140           0 :   mInputType->ConvertNumberToString(newValue, newVal);
    4141             :   // TODO: What should we do if SetValueInternal fails?  (The allocation
    4142             :   // is small, so we should be fine here.)
    4143             :   SetValueInternal(newVal, nsTextEditorState::eSetValue_BySetUserInput |
    4144           0 :                            nsTextEditorState::eSetValue_Notify);
    4145             : 
    4146           0 :   nsContentUtils::DispatchTrustedEvent(OwnerDoc(),
    4147             :                                        static_cast<nsIDOMHTMLInputElement*>(this),
    4148           0 :                                        NS_LITERAL_STRING("input"), true,
    4149           0 :                                        false);
    4150             : }
    4151             : 
    4152             : static bool
    4153           0 : SelectTextFieldOnFocus()
    4154             : {
    4155           0 :   if (!gSelectTextFieldOnFocus) {
    4156           0 :     int32_t selectTextfieldsOnKeyFocus = -1;
    4157             :     nsresult rv =
    4158             :       LookAndFeel::GetInt(LookAndFeel::eIntID_SelectTextfieldsOnKeyFocus,
    4159           0 :                           &selectTextfieldsOnKeyFocus);
    4160           0 :     if (NS_FAILED(rv)) {
    4161           0 :       gSelectTextFieldOnFocus = -1;
    4162             :     } else {
    4163           0 :       gSelectTextFieldOnFocus = selectTextfieldsOnKeyFocus != 0 ? 1 : -1;
    4164             :     }
    4165             :   }
    4166             : 
    4167           0 :   return gSelectTextFieldOnFocus == 1;
    4168             : }
    4169             : 
    4170             : bool
    4171           0 : HTMLInputElement::ShouldPreventDOMActivateDispatch(EventTarget* aOriginalTarget)
    4172             : {
    4173             :   /*
    4174             :    * For the moment, there is only one situation where we actually want to
    4175             :    * prevent firing a DOMActivate event:
    4176             :    *  - we are a <input type='file'> that just got a click event,
    4177             :    *  - the event was targeted to our button which should have sent a
    4178             :    *    DOMActivate event.
    4179             :    */
    4180             : 
    4181           0 :   if (mType != NS_FORM_INPUT_FILE) {
    4182           0 :     return false;
    4183             :   }
    4184             : 
    4185           0 :   nsCOMPtr<nsIContent> target = do_QueryInterface(aOriginalTarget);
    4186           0 :   if (!target) {
    4187           0 :     return false;
    4188             :   }
    4189             : 
    4190           0 :   return target->GetParent() == this &&
    4191           0 :          target->IsRootOfNativeAnonymousSubtree() &&
    4192           0 :          target->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
    4193           0 :                              nsGkAtoms::button, eCaseMatters);
    4194             : }
    4195             : 
    4196             : nsresult
    4197           4 : HTMLInputElement::MaybeInitPickers(EventChainPostVisitor& aVisitor)
    4198             : {
    4199             :   // Open a file picker when we receive a click on a <input type='file'>, or
    4200             :   // open a color picker when we receive a click on a <input type='color'>.
    4201             :   // A click is handled in the following cases:
    4202             :   // - preventDefault() has not been called (or something similar);
    4203             :   // - it's the left mouse button.
    4204             :   // We do not prevent non-trusted click because authors can already use
    4205             :   // .click(). However, the pickers will follow the rules of popup-blocking.
    4206           4 :   if (aVisitor.mEvent->DefaultPrevented()) {
    4207           0 :     return NS_OK;
    4208             :   }
    4209           4 :   WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
    4210           4 :   if (!(mouseEvent && mouseEvent->IsLeftClickEvent())) {
    4211           4 :     return NS_OK;
    4212             :   }
    4213           0 :   if (mType == NS_FORM_INPUT_FILE) {
    4214             :     // If the user clicked on the "Choose folder..." button we open the
    4215             :     // directory picker, else we open the file picker.
    4216           0 :     FilePickerType type = FILE_PICKER_FILE;
    4217             :     nsCOMPtr<nsIContent> target =
    4218           0 :       do_QueryInterface(aVisitor.mEvent->mOriginalTarget);
    4219           0 :     if (target &&
    4220           0 :         target->FindFirstNonChromeOnlyAccessContent() == this &&
    4221           0 :         ((IsDirPickerEnabled() && Allowdirs()) ||
    4222           0 :          (IsWebkitDirPickerEnabled() &&
    4223           0 :           HasAttr(kNameSpaceID_None, nsGkAtoms::webkitdirectory)))) {
    4224           0 :       type = FILE_PICKER_DIRECTORY;
    4225             :     }
    4226           0 :     return InitFilePicker(type);
    4227             :   }
    4228           0 :   if (mType == NS_FORM_INPUT_COLOR) {
    4229           0 :     return InitColorPicker();
    4230             :   }
    4231             : 
    4232           0 :   return NS_OK;
    4233             : }
    4234             : 
    4235             : /**
    4236             :  * Return true if the input event should be ignore because of it's modifiers
    4237             :  */
    4238             : static bool
    4239           0 : IgnoreInputEventWithModifier(WidgetInputEvent* aEvent)
    4240             : {
    4241           0 :   return aEvent->IsShift() || aEvent->IsControl() || aEvent->IsAlt() ||
    4242           0 :          aEvent->IsMeta() || aEvent->IsAltGraph() || aEvent->IsFn() ||
    4243           0 :          aEvent->IsOS();
    4244             : }
    4245             : 
    4246             : nsresult
    4247           4 : HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
    4248             : {
    4249           4 :   if (!aVisitor.mPresContext) {
    4250             :     // Hack alert! In order to open file picker even in case the element isn't
    4251             :     // in document, try to init picker even without PresContext.
    4252           0 :     return MaybeInitPickers(aVisitor);
    4253             :   }
    4254             : 
    4255           8 :   if (aVisitor.mEvent->mMessage == eFocus ||
    4256           4 :       aVisitor.mEvent->mMessage == eBlur) {
    4257           0 :     if (aVisitor.mEvent->mMessage == eBlur) {
    4258           0 :       if (mIsDraggingRange) {
    4259           0 :         FinishRangeThumbDrag();
    4260           0 :       } else if (mNumberControlSpinnerIsSpinning) {
    4261           0 :         StopNumberControlSpinnerSpin();
    4262             :       }
    4263             :     }
    4264             : 
    4265           0 :     UpdateValidityUIBits(aVisitor.mEvent->mMessage == eFocus);
    4266             : 
    4267           0 :     UpdateState(true);
    4268             :   }
    4269             : 
    4270           4 :   nsresult rv = NS_OK;
    4271           4 :   bool outerActivateEvent = !!(aVisitor.mItemFlags & NS_OUTER_ACTIVATE_EVENT);
    4272             :   bool originalCheckedValue =
    4273           4 :     !!(aVisitor.mItemFlags & NS_ORIGINAL_CHECKED_VALUE);
    4274           4 :   bool noContentDispatch = !!(aVisitor.mItemFlags & NS_NO_CONTENT_DISPATCH);
    4275           4 :   uint8_t oldType = NS_CONTROL_TYPE(aVisitor.mItemFlags);
    4276             : 
    4277             :   // Ideally we would make the default action for click and space just dispatch
    4278             :   // DOMActivate, and the default action for DOMActivate flip the checkbox/
    4279             :   // radio state and fire onchange.  However, for backwards compatibility, we
    4280             :   // need to flip the state before firing click, and we need to fire click
    4281             :   // when space is pressed.  So, we just nest the firing of DOMActivate inside
    4282             :   // the click event handling, and allow cancellation of DOMActivate to cancel
    4283             :   // the click.
    4284          12 :   if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault &&
    4285           4 :       !IsSingleLineTextControl(true) &&
    4286           0 :       mType != NS_FORM_INPUT_NUMBER) {
    4287           0 :     WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
    4288           0 :     if (mouseEvent && mouseEvent->IsLeftClickEvent() &&
    4289           0 :         !ShouldPreventDOMActivateDispatch(aVisitor.mEvent->mOriginalTarget)) {
    4290             :       // DOMActive event should be trusted since the activation is actually
    4291             :       // occurred even if the cause is an untrusted click event.
    4292           0 :       InternalUIEvent actEvent(true, eLegacyDOMActivate, mouseEvent);
    4293           0 :       actEvent.mDetail = 1;
    4294             : 
    4295           0 :       nsCOMPtr<nsIPresShell> shell = aVisitor.mPresContext->GetPresShell();
    4296           0 :       if (shell) {
    4297           0 :         nsEventStatus status = nsEventStatus_eIgnore;
    4298           0 :         mInInternalActivate = true;
    4299           0 :         rv = shell->HandleDOMEventWithTarget(this, &actEvent, &status);
    4300           0 :         mInInternalActivate = false;
    4301             : 
    4302             :         // If activate is cancelled, we must do the same as when click is
    4303             :         // cancelled (revert the checkbox to its original value).
    4304           0 :         if (status == nsEventStatus_eConsumeNoDefault) {
    4305           0 :           aVisitor.mEventStatus = status;
    4306             :         }
    4307             :       }
    4308             :     }
    4309             :   }
    4310             : 
    4311           4 :   if (outerActivateEvent) {
    4312           0 :     switch(oldType) {
    4313             :       case NS_FORM_INPUT_SUBMIT:
    4314             :       case NS_FORM_INPUT_IMAGE:
    4315           0 :         if (mForm) {
    4316             :           // tell the form that we are about to exit a click handler
    4317             :           // so the form knows not to defer subsequent submissions
    4318             :           // the pending ones that were created during the handler
    4319             :           // will be flushed or forgoten.
    4320           0 :           mForm->OnSubmitClickEnd();
    4321             :         }
    4322           0 :         break;
    4323             :       default:
    4324           0 :         break;
    4325             :     }
    4326             :   }
    4327             : 
    4328             :   // Reset the flag for other content besides this text field
    4329           4 :   aVisitor.mEvent->mFlags.mNoContentDispatch = noContentDispatch;
    4330             : 
    4331             :   // now check to see if the event was "cancelled"
    4332           4 :   if (mCheckedIsToggled && outerActivateEvent) {
    4333           0 :     if (aVisitor.mEventStatus == nsEventStatus_eConsumeNoDefault) {
    4334             :       // if it was cancelled and a radio button, then set the old
    4335             :       // selected btn to TRUE. if it is a checkbox then set it to its
    4336             :       // original value
    4337           0 :       if (oldType == NS_FORM_INPUT_RADIO) {
    4338             :         nsCOMPtr<nsIDOMHTMLInputElement> selectedRadioButton =
    4339           0 :           do_QueryInterface(aVisitor.mItemData);
    4340           0 :         if (selectedRadioButton) {
    4341           0 :           selectedRadioButton->SetChecked(true);
    4342             :         }
    4343             :         // If there was no checked radio button or this one is no longer a
    4344             :         // radio button we must reset it back to false to cancel the action.
    4345             :         // See how the web of hack grows?
    4346           0 :         if (!selectedRadioButton || mType != NS_FORM_INPUT_RADIO) {
    4347           0 :           DoSetChecked(false, true, true);
    4348             :         }
    4349           0 :       } else if (oldType == NS_FORM_INPUT_CHECKBOX) {
    4350             :         bool originalIndeterminateValue =
    4351           0 :           !!(aVisitor.mItemFlags & NS_ORIGINAL_INDETERMINATE_VALUE);
    4352           0 :         SetIndeterminateInternal(originalIndeterminateValue, false);
    4353           0 :         DoSetChecked(originalCheckedValue, true, true);
    4354             :       }
    4355             :     } else {
    4356             :       // Fire input event and then change event.
    4357             :       nsContentUtils::DispatchTrustedEvent<InternalEditorInputEvent>
    4358           0 :         (OwnerDoc(), static_cast<nsIDOMHTMLInputElement*>(this),
    4359           0 :          eEditorInput, true, false);
    4360             : 
    4361             :       nsContentUtils::DispatchTrustedEvent<WidgetEvent>
    4362           0 :         (OwnerDoc(), static_cast<nsIDOMHTMLInputElement*>(this),
    4363           0 :          eFormChange, true, false);
    4364             : #ifdef ACCESSIBILITY
    4365             :       // Fire an event to notify accessibility
    4366           0 :       if (mType == NS_FORM_INPUT_CHECKBOX) {
    4367           0 :         FireEventForAccessibility(this, aVisitor.mPresContext,
    4368           0 :                                   eFormCheckboxStateChange);
    4369             :       } else {
    4370           0 :         FireEventForAccessibility(this, aVisitor.mPresContext,
    4371           0 :                                   eFormRadioStateChange);
    4372             :         // Fire event for the previous selected radio.
    4373             :         nsCOMPtr<nsIDOMHTMLInputElement> previous =
    4374           0 :           do_QueryInterface(aVisitor.mItemData);
    4375           0 :         if (previous) {
    4376           0 :           FireEventForAccessibility(previous, aVisitor.mPresContext,
    4377           0 :                                     eFormRadioStateChange);
    4378             :         }
    4379             :       }
    4380             : #endif
    4381             :     }
    4382             :   }
    4383             : 
    4384           4 :   if (NS_SUCCEEDED(rv)) {
    4385           4 :     WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
    4386           8 :     if (mType ==  NS_FORM_INPUT_NUMBER &&
    4387           0 :         keyEvent && keyEvent->mMessage == eKeyPress &&
    4388           0 :         aVisitor.mEvent->IsTrusted() &&
    4389           4 :         (keyEvent->mKeyCode == NS_VK_UP || keyEvent->mKeyCode == NS_VK_DOWN) &&
    4390           0 :         !IgnoreInputEventWithModifier(keyEvent)) {
    4391             :       // We handle the up/down arrow keys specially for <input type=number>.
    4392             :       // On some platforms the editor for the nested text control will
    4393             :       // process these keys to send the cursor to the start/end of the text
    4394             :       // control and as a result aVisitor.mEventStatus will already have been
    4395             :       // set to nsEventStatus_eConsumeNoDefault. However, we know that
    4396             :       // whenever the up/down arrow keys cause the value of the number
    4397             :       // control to change the string in the text control will change, and
    4398             :       // the cursor will be moved to the end of the text control, overwriting
    4399             :       // the editor's handling of up/down keypress events. For that reason we
    4400             :       // just ignore aVisitor.mEventStatus here and go ahead and handle the
    4401             :       // event to increase/decrease the value of the number control.
    4402           0 :       if (!aVisitor.mEvent->DefaultPreventedByContent() && IsMutable()) {
    4403           0 :         StepNumberControlForUserEvent(keyEvent->mKeyCode == NS_VK_UP ? 1 : -1);
    4404           0 :         FireChangeEventIfNeeded();
    4405           0 :         aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
    4406             :       }
    4407           4 :     } else if (nsEventStatus_eIgnore == aVisitor.mEventStatus) {
    4408           4 :       switch (aVisitor.mEvent->mMessage) {
    4409             :         case eFocus: {
    4410             :           // see if we should select the contents of the textbox. This happens
    4411             :           // for text and password fields when the field was focused by the
    4412             :           // keyboard or a navigation, the platform allows it, and it wasn't
    4413             :           // just because we raised a window.
    4414           0 :           nsIFocusManager* fm = nsFocusManager::GetFocusManager();
    4415           0 :           if (fm && IsSingleLineTextControl(false) &&
    4416           0 :               !aVisitor.mEvent->AsFocusEvent()->mFromRaise &&
    4417           0 :               SelectTextFieldOnFocus()) {
    4418           0 :             nsIDocument* document = GetComposedDoc();
    4419           0 :             if (document) {
    4420             :               uint32_t lastFocusMethod;
    4421           0 :               fm->GetLastFocusMethod(document->GetWindow(), &lastFocusMethod);
    4422           0 :               if (lastFocusMethod &
    4423             :                   (nsIFocusManager::FLAG_BYKEY | nsIFocusManager::FLAG_BYMOVEFOCUS)) {
    4424             :                 RefPtr<nsPresContext> presContext =
    4425           0 :                   GetPresContext(eForComposedDoc);
    4426           0 :                 if (DispatchSelectEvent(presContext)) {
    4427           0 :                   SelectAll(presContext);
    4428             :                 }
    4429             :               }
    4430             :             }
    4431             :           }
    4432           0 :           break;
    4433             :         }
    4434             : 
    4435             :         case eKeyPress:
    4436             :         case eKeyUp:
    4437             :         {
    4438             :           // For backwards compat, trigger checks/radios/buttons with
    4439             :           // space or enter (bug 25300)
    4440           0 :           WidgetKeyboardEvent* keyEvent = aVisitor.mEvent->AsKeyboardEvent();
    4441           0 :           if ((aVisitor.mEvent->mMessage == eKeyPress &&
    4442           0 :                keyEvent->mKeyCode == NS_VK_RETURN) ||
    4443           0 :               (aVisitor.mEvent->mMessage == eKeyUp &&
    4444           0 :                keyEvent->mKeyCode == NS_VK_SPACE)) {
    4445           0 :             switch(mType) {
    4446             :               case NS_FORM_INPUT_CHECKBOX:
    4447             :               case NS_FORM_INPUT_RADIO:
    4448             :               {
    4449             :                 // Checkbox and Radio try to submit on Enter press
    4450           0 :                 if (keyEvent->mKeyCode != NS_VK_SPACE) {
    4451           0 :                   MaybeSubmitForm(aVisitor.mPresContext);
    4452             : 
    4453           0 :                   break;  // If we are submitting, do not send click event
    4454             :                 }
    4455             :                 // else fall through and treat Space like click...
    4456             :                 MOZ_FALLTHROUGH;
    4457             :               }
    4458             :               case NS_FORM_INPUT_BUTTON:
    4459             :               case NS_FORM_INPUT_RESET:
    4460             :               case NS_FORM_INPUT_SUBMIT:
    4461             :               case NS_FORM_INPUT_IMAGE: // Bug 34418
    4462             :               case NS_FORM_INPUT_COLOR:
    4463             :               {
    4464           0 :                 DispatchSimulatedClick(this, aVisitor.mEvent->IsTrusted(),
    4465           0 :                                        aVisitor.mPresContext);
    4466           0 :                 aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
    4467             :               } // case
    4468             :             } // switch
    4469             :           }
    4470           0 :           if (aVisitor.mEvent->mMessage == eKeyPress &&
    4471           0 :               mType == NS_FORM_INPUT_RADIO && !keyEvent->IsAlt() &&
    4472           0 :               !keyEvent->IsControl() && !keyEvent->IsMeta()) {
    4473           0 :             bool isMovingBack = false;
    4474           0 :             switch (keyEvent->mKeyCode) {
    4475             :               case NS_VK_UP:
    4476             :               case NS_VK_LEFT:
    4477           0 :                 isMovingBack = true;
    4478             :                 MOZ_FALLTHROUGH;
    4479             :               case NS_VK_DOWN:
    4480             :               case NS_VK_RIGHT:
    4481             :               // Arrow key pressed, focus+select prev/next radio button
    4482           0 :               nsIRadioGroupContainer* container = GetRadioGroupContainer();
    4483           0 :               if (container) {
    4484           0 :                 nsAutoString name;
    4485           0 :                 GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    4486           0 :                 RefPtr<HTMLInputElement> selectedRadioButton;
    4487           0 :                 container->GetNextRadioButton(name, isMovingBack, this,
    4488           0 :                                               getter_AddRefs(selectedRadioButton));
    4489           0 :                 if (selectedRadioButton) {
    4490           0 :                   rv = selectedRadioButton->Focus();
    4491           0 :                   if (NS_SUCCEEDED(rv)) {
    4492           0 :                     rv = DispatchSimulatedClick(selectedRadioButton,
    4493           0 :                                                 aVisitor.mEvent->IsTrusted(),
    4494           0 :                                                 aVisitor.mPresContext);
    4495           0 :                     if (NS_SUCCEEDED(rv)) {
    4496           0 :                       aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
    4497             :                     }
    4498             :                   }
    4499             :                 }
    4500             :               }
    4501             :             }
    4502             :           }
    4503             : 
    4504             :           /*
    4505             :            * For some input types, if the user hits enter, the form is submitted.
    4506             :            *
    4507             :            * Bug 99920, bug 109463 and bug 147850:
    4508             :            * (a) if there is a submit control in the form, click the first
    4509             :            *     submit control in the form.
    4510             :            * (b) if there is just one text control in the form, submit by
    4511             :            *     sending a submit event directly to the form
    4512             :            * (c) if there is more than one text input and no submit buttons, do
    4513             :            *     not submit, period.
    4514             :            */
    4515             : 
    4516           0 :           if (aVisitor.mEvent->mMessage == eKeyPress &&
    4517           0 :               keyEvent->mKeyCode == NS_VK_RETURN &&
    4518           0 :                (IsSingleLineTextControl(false, mType) ||
    4519           0 :                 mType == NS_FORM_INPUT_NUMBER ||
    4520           0 :                 IsExperimentalMobileType(mType) ||
    4521           0 :                 IsDateTimeInputType(mType))) {
    4522           0 :             FireChangeEventIfNeeded();
    4523           0 :             rv = MaybeSubmitForm(aVisitor.mPresContext);
    4524           0 :             NS_ENSURE_SUCCESS(rv, rv);
    4525             :           }
    4526             : 
    4527           0 :           if (aVisitor.mEvent->mMessage == eKeyPress &&
    4528           0 :               mType == NS_FORM_INPUT_RANGE && !keyEvent->IsAlt() &&
    4529           0 :               !keyEvent->IsControl() && !keyEvent->IsMeta() &&
    4530           0 :               (keyEvent->mKeyCode == NS_VK_LEFT ||
    4531           0 :                keyEvent->mKeyCode == NS_VK_RIGHT ||
    4532           0 :                keyEvent->mKeyCode == NS_VK_UP ||
    4533           0 :                keyEvent->mKeyCode == NS_VK_DOWN ||
    4534           0 :                keyEvent->mKeyCode == NS_VK_PAGE_UP ||
    4535           0 :                keyEvent->mKeyCode == NS_VK_PAGE_DOWN ||
    4536           0 :                keyEvent->mKeyCode == NS_VK_HOME ||
    4537           0 :                keyEvent->mKeyCode == NS_VK_END)) {
    4538           0 :             Decimal minimum = GetMinimum();
    4539           0 :             Decimal maximum = GetMaximum();
    4540           0 :             MOZ_ASSERT(minimum.isFinite() && maximum.isFinite());
    4541           0 :             if (minimum < maximum) { // else the value is locked to the minimum
    4542           0 :               Decimal value = GetValueAsDecimal();
    4543           0 :               Decimal step = GetStep();
    4544           0 :               if (step == kStepAny) {
    4545           0 :                 step = GetDefaultStep();
    4546             :               }
    4547           0 :               MOZ_ASSERT(value.isFinite() && step.isFinite());
    4548           0 :               Decimal newValue;
    4549           0 :               switch (keyEvent->mKeyCode) {
    4550             :                 case  NS_VK_LEFT:
    4551           0 :                   newValue = value + (GetComputedDirectionality() == eDir_RTL
    4552           0 :                                         ? step : -step);
    4553           0 :                   break;
    4554             :                 case  NS_VK_RIGHT:
    4555           0 :                   newValue = value + (GetComputedDirectionality() == eDir_RTL
    4556           0 :                                         ? -step : step);
    4557           0 :                   break;
    4558             :                 case  NS_VK_UP:
    4559             :                   // Even for horizontal range, "up" means "increase"
    4560           0 :                   newValue = value + step;
    4561           0 :                   break;
    4562             :                 case  NS_VK_DOWN:
    4563             :                   // Even for horizontal range, "down" means "decrease"
    4564           0 :                   newValue = value - step;
    4565           0 :                   break;
    4566             :                 case  NS_VK_HOME:
    4567           0 :                   newValue = minimum;
    4568           0 :                   break;
    4569             :                 case  NS_VK_END:
    4570           0 :                   newValue = maximum;
    4571           0 :                   break;
    4572             :                 case  NS_VK_PAGE_UP:
    4573             :                   // For PgUp/PgDn we jump 10% of the total range, unless step
    4574             :                   // requires us to jump more.
    4575           0 :                   newValue = value + std::max(step, (maximum - minimum) / Decimal(10));
    4576           0 :                   break;
    4577             :                 case  NS_VK_PAGE_DOWN:
    4578           0 :                   newValue = value - std::max(step, (maximum - minimum) / Decimal(10));
    4579           0 :                   break;
    4580             :               }
    4581           0 :               SetValueOfRangeForUserEvent(newValue);
    4582           0 :               FireChangeEventIfNeeded();
    4583           0 :               aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
    4584             :             }
    4585             :           }
    4586             : 
    4587           0 :         } break; // eKeyPress || eKeyUp
    4588             : 
    4589             :         case eMouseDown:
    4590             :         case eMouseUp:
    4591             :         case eMouseDoubleClick: {
    4592             :           // cancel all of these events for buttons
    4593             :           //XXXsmaug Why?
    4594           0 :           WidgetMouseEvent* mouseEvent = aVisitor.mEvent->AsMouseEvent();
    4595           0 :           if (mouseEvent->button == WidgetMouseEvent::eMiddleButton ||
    4596           0 :               mouseEvent->button == WidgetMouseEvent::eRightButton) {
    4597           0 :             if (mType == NS_FORM_INPUT_BUTTON ||
    4598           0 :                 mType == NS_FORM_INPUT_RESET ||
    4599           0 :                 mType == NS_FORM_INPUT_SUBMIT) {
    4600           0 :               if (aVisitor.mDOMEvent) {
    4601           0 :                 aVisitor.mDOMEvent->StopPropagation();
    4602             :               } else {
    4603           0 :                 rv = NS_ERROR_FAILURE;
    4604             :               }
    4605             :             }
    4606             :           }
    4607           0 :           if (mType == NS_FORM_INPUT_NUMBER && aVisitor.mEvent->IsTrusted()) {
    4608           0 :             if (mouseEvent->button == WidgetMouseEvent::eLeftButton &&
    4609           0 :                 !IgnoreInputEventWithModifier(mouseEvent)) {
    4610             :               nsNumberControlFrame* numberControlFrame =
    4611           0 :                 do_QueryFrame(GetPrimaryFrame());
    4612           0 :               if (numberControlFrame) {
    4613           0 :                 if (aVisitor.mEvent->mMessage == eMouseDown &&
    4614           0 :                     IsMutable()) {
    4615           0 :                   switch (numberControlFrame->GetSpinButtonForPointerEvent(
    4616           0 :                             aVisitor.mEvent->AsMouseEvent())) {
    4617             :                   case nsNumberControlFrame::eSpinButtonUp:
    4618           0 :                     StepNumberControlForUserEvent(1);
    4619           0 :                     mNumberControlSpinnerSpinsUp = true;
    4620           0 :                     StartNumberControlSpinnerSpin();
    4621           0 :                     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
    4622           0 :                     break;
    4623             :                   case nsNumberControlFrame::eSpinButtonDown:
    4624           0 :                     StepNumberControlForUserEvent(-1);
    4625           0 :                     mNumberControlSpinnerSpinsUp = false;
    4626           0 :                     StartNumberControlSpinnerSpin();
    4627           0 :                     aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
    4628           0 :                     break;
    4629             :                   }
    4630             :                 }
    4631             :               }
    4632             :             }
    4633           0 :             if (aVisitor.mEventStatus != nsEventStatus_eConsumeNoDefault) {
    4634             :               // We didn't handle this to step up/down. Whatever this was, be
    4635             :               // aggressive about stopping the spin. (And don't set
    4636             :               // nsEventStatus_eConsumeNoDefault after doing so, since that
    4637             :               // might prevent, say, the context menu from opening.)
    4638           0 :               StopNumberControlSpinnerSpin();
    4639             :             }
    4640             :           }
    4641           0 :           break;
    4642             :         }
    4643             : #if !defined(ANDROID) && !defined(XP_MACOSX)
    4644             :         case eWheel: {
    4645             :           // Handle wheel events as increasing / decreasing the input element's
    4646             :           // value when it's focused and it's type is number or range.
    4647           0 :           WidgetWheelEvent* wheelEvent = aVisitor.mEvent->AsWheelEvent();
    4648           0 :           if (!aVisitor.mEvent->DefaultPrevented() &&
    4649           0 :               aVisitor.mEvent->IsTrusted() && IsMutable() && wheelEvent &&
    4650           0 :               wheelEvent->mDeltaY != 0 &&
    4651           0 :               wheelEvent->mDeltaMode != nsIDOMWheelEvent::DOM_DELTA_PIXEL) {
    4652           0 :             if (mType == NS_FORM_INPUT_NUMBER) {
    4653             :               nsNumberControlFrame* numberControlFrame =
    4654           0 :                 do_QueryFrame(GetPrimaryFrame());
    4655           0 :               if (numberControlFrame && numberControlFrame->IsFocused()) {
    4656           0 :                 StepNumberControlForUserEvent(wheelEvent->mDeltaY > 0 ? -1 : 1);
    4657           0 :                 FireChangeEventIfNeeded();
    4658           0 :                 aVisitor.mEvent->PreventDefault();
    4659             :               }
    4660           0 :             } else if (mType == NS_FORM_INPUT_RANGE &&
    4661           0 :                        nsContentUtils::IsFocusedContent(this) &&
    4662           0 :                        GetMinimum() < GetMaximum()) {
    4663           0 :               Decimal value = GetValueAsDecimal();
    4664           0 :               Decimal step = GetStep();
    4665           0 :               if (step == kStepAny) {
    4666           0 :                 step = GetDefaultStep();
    4667             :               }
    4668           0 :               MOZ_ASSERT(value.isFinite() && step.isFinite());
    4669           0 :               SetValueOfRangeForUserEvent(wheelEvent->mDeltaY < 0 ?
    4670           0 :                                           value + step : value - step);
    4671           0 :               FireChangeEventIfNeeded();
    4672           0 :               aVisitor.mEvent->PreventDefault();
    4673             :             }
    4674             :           }
    4675           0 :           break;
    4676             :         }
    4677             : #endif
    4678             :         default:
    4679           4 :           break;
    4680             :       }
    4681             : 
    4682           4 :       if (outerActivateEvent) {
    4683           0 :         if (mForm && (oldType == NS_FORM_INPUT_SUBMIT ||
    4684             :                       oldType == NS_FORM_INPUT_IMAGE)) {
    4685           0 :           if (mType != NS_FORM_INPUT_SUBMIT && mType != NS_FORM_INPUT_IMAGE) {
    4686             :             // If the type has changed to a non-submit type, then we want to
    4687             :             // flush the stored submission if there is one (as if the submit()
    4688             :             // was allowed to succeed)
    4689           0 :             mForm->FlushPendingSubmission();
    4690             :           }
    4691             :         }
    4692           0 :         switch(mType) {
    4693             :         case NS_FORM_INPUT_RESET:
    4694             :         case NS_FORM_INPUT_SUBMIT:
    4695             :         case NS_FORM_INPUT_IMAGE:
    4696           0 :           if (mForm) {
    4697             :             InternalFormEvent event(true,
    4698           0 :               (mType == NS_FORM_INPUT_RESET) ? eFormReset : eFormSubmit);
    4699           0 :             event.mOriginator = this;
    4700           0 :             nsEventStatus status  = nsEventStatus_eIgnore;
    4701             : 
    4702             :             nsCOMPtr<nsIPresShell> presShell =
    4703           0 :               aVisitor.mPresContext->GetPresShell();
    4704             : 
    4705             :             // If |nsIPresShell::Destroy| has been called due to
    4706             :             // handling the event the pres context will return a null
    4707             :             // pres shell.  See bug 125624.
    4708             :             // TODO: removing this code and have the submit event sent by the
    4709             :             // form, see bug 592124.
    4710           0 :             if (presShell && (event.mMessage != eFormSubmit ||
    4711           0 :                               mForm->SubmissionCanProceed(this))) {
    4712             :               // Hold a strong ref while dispatching
    4713           0 :               RefPtr<mozilla::dom::HTMLFormElement> form(mForm);
    4714           0 :               presShell->HandleDOMEventWithTarget(form, &event, &status);
    4715           0 :               aVisitor.mEventStatus = nsEventStatus_eConsumeNoDefault;
    4716             :             }
    4717             :           }
    4718           0 :           break;
    4719             : 
    4720             :         default:
    4721           0 :           break;
    4722             :         } //switch
    4723             :       } //click or outer activate event
    4724           0 :     } else if (outerActivateEvent &&
    4725           0 :                (oldType == NS_FORM_INPUT_SUBMIT ||
    4726           0 :                 oldType == NS_FORM_INPUT_IMAGE) &&
    4727           0 :                mForm) {
    4728             :       // tell the form to flush a possible pending submission.
    4729             :       // the reason is that the script returned false (the event was
    4730             :       // not ignored) so if there is a stored submission, it needs to
    4731             :       // be submitted immediately.
    4732           0 :       mForm->FlushPendingSubmission();
    4733             :     }
    4734             :   } // if
    4735             : 
    4736           4 :   if (NS_SUCCEEDED(rv) && mType == NS_FORM_INPUT_RANGE) {
    4737           0 :     PostHandleEventForRangeThumb(aVisitor);
    4738             :   }
    4739             : 
    4740           4 :   return MaybeInitPickers(aVisitor);
    4741             : }
    4742             : 
    4743             : void
    4744           0 : HTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor& aVisitor)
    4745             : {
    4746           0 :   MOZ_ASSERT(mType == NS_FORM_INPUT_RANGE);
    4747             : 
    4748           0 :   if ((nsEventStatus_eConsumeNoDefault == aVisitor.mEventStatus &&
    4749           0 :        !MozInputRangeIgnorePreventDefault()) ||
    4750           0 :       !(aVisitor.mEvent->mClass == eMouseEventClass ||
    4751           0 :         aVisitor.mEvent->mClass == eTouchEventClass ||
    4752           0 :         aVisitor.mEvent->mClass == eKeyboardEventClass)) {
    4753           0 :     return;
    4754             :   }
    4755             : 
    4756           0 :   nsRangeFrame* rangeFrame = do_QueryFrame(GetPrimaryFrame());
    4757           0 :   if (!rangeFrame && mIsDraggingRange) {
    4758           0 :     CancelRangeThumbDrag();
    4759           0 :     return;
    4760             :   }
    4761             : 
    4762           0 :   switch (aVisitor.mEvent->mMessage)
    4763             :   {
    4764             :     case eMouseDown:
    4765             :     case eTouchStart: {
    4766           0 :       if (mIsDraggingRange) {
    4767           0 :         break;
    4768             :       }
    4769           0 :       if (nsIPresShell::GetCapturingContent()) {
    4770           0 :         break; // don't start drag if someone else is already capturing
    4771             :       }
    4772           0 :       WidgetInputEvent* inputEvent = aVisitor.mEvent->AsInputEvent();
    4773           0 :       if (IgnoreInputEventWithModifier(inputEvent)) {
    4774           0 :         break; // ignore
    4775             :       }
    4776           0 :       if (aVisitor.mEvent->mMessage == eMouseDown) {
    4777           0 :         if (aVisitor.mEvent->AsMouseEvent()->buttons ==
    4778             :               WidgetMouseEvent::eLeftButtonFlag) {
    4779           0 :           StartRangeThumbDrag(inputEvent);
    4780           0 :         } else if (mIsDraggingRange) {
    4781           0 :           CancelRangeThumbDrag();
    4782             :         }
    4783             :       } else {
    4784           0 :         if (aVisitor.mEvent->AsTouchEvent()->mTouches.Length() == 1) {
    4785           0 :           StartRangeThumbDrag(inputEvent);
    4786           0 :         } else if (mIsDraggingRange) {
    4787           0 :           CancelRangeThumbDrag();
    4788             :         }
    4789             :       }
    4790           0 :       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
    4791           0 :     } break;
    4792             : 
    4793             :     case eMouseMove:
    4794             :     case eTouchMove:
    4795           0 :       if (!mIsDraggingRange) {
    4796           0 :         break;
    4797             :       }
    4798           0 :       if (nsIPresShell::GetCapturingContent() != this) {
    4799             :         // Someone else grabbed capture.
    4800           0 :         CancelRangeThumbDrag();
    4801           0 :         break;
    4802             :       }
    4803             :       SetValueOfRangeForUserEvent(
    4804           0 :         rangeFrame->GetValueAtEventPoint(aVisitor.mEvent->AsInputEvent()));
    4805           0 :       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
    4806           0 :       break;
    4807             : 
    4808             :     case eMouseUp:
    4809             :     case eTouchEnd:
    4810           0 :       if (!mIsDraggingRange) {
    4811           0 :         break;
    4812             :       }
    4813             :       // We don't check to see whether we are the capturing content here and
    4814             :       // call CancelRangeThumbDrag() if that is the case. We just finish off
    4815             :       // the drag and set our final value (unless someone has called
    4816             :       // preventDefault() and prevents us getting here).
    4817           0 :       FinishRangeThumbDrag(aVisitor.mEvent->AsInputEvent());
    4818           0 :       aVisitor.mEvent->mFlags.mMultipleActionsPrevented = true;
    4819           0 :       break;
    4820             : 
    4821             :     case eKeyPress:
    4822           0 :       if (mIsDraggingRange &&
    4823           0 :           aVisitor.mEvent->AsKeyboardEvent()->mKeyCode == NS_VK_ESCAPE) {
    4824           0 :         CancelRangeThumbDrag();
    4825             :       }
    4826           0 :       break;
    4827             : 
    4828             :     case eTouchCancel:
    4829           0 :       if (mIsDraggingRange) {
    4830           0 :         CancelRangeThumbDrag();
    4831             :       }
    4832           0 :       break;
    4833             : 
    4834             :     default:
    4835           0 :       break;
    4836             :   }
    4837             : }
    4838             : 
    4839             : void
    4840           0 : HTMLInputElement::MaybeLoadImage()
    4841             : {
    4842             :   // Our base URI may have changed; claim that our URI changed, and the
    4843             :   // nsImageLoadingContent will decide whether a new image load is warranted.
    4844           0 :   nsAutoString uri;
    4845           0 :   if (mType == NS_FORM_INPUT_IMAGE &&
    4846           0 :       GetAttr(kNameSpaceID_None, nsGkAtoms::src, uri) &&
    4847           0 :       (NS_FAILED(LoadImage(uri, false, true, eImageLoadType_Normal)) ||
    4848           0 :        !LoadingEnabled())) {
    4849           0 :     CancelImageRequests(true);
    4850             :   }
    4851           0 : }
    4852             : 
    4853             : nsresult
    4854          21 : HTMLInputElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
    4855             :                              nsIContent* aBindingParent,
    4856             :                              bool aCompileEventHandlers)
    4857             : {
    4858          21 :   nsresult rv = nsGenericHTMLFormElementWithState::BindToTree(aDocument, aParent,
    4859             :                                                               aBindingParent,
    4860          21 :                                                               aCompileEventHandlers);
    4861          21 :   NS_ENSURE_SUCCESS(rv, rv);
    4862             : 
    4863          21 :   nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
    4864          21 :                                     aCompileEventHandlers);
    4865             : 
    4866          21 :   if (mType == NS_FORM_INPUT_IMAGE) {
    4867             :     // Our base URI may have changed; claim that our URI changed, and the
    4868             :     // nsImageLoadingContent will decide whether a new image load is warranted.
    4869           0 :     if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
    4870             :       // Mark channel as urgent-start before load image if the image load is
    4871             :       // initaiated by a user interaction.
    4872           0 :       mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
    4873             : 
    4874             :       // FIXME: Bug 660963 it would be nice if we could just have
    4875             :       // ClearBrokenState update our state and do it fast...
    4876           0 :       ClearBrokenState();
    4877           0 :       RemoveStatesSilently(NS_EVENT_STATE_BROKEN);
    4878           0 :       nsContentUtils::AddScriptRunner(
    4879           0 :         NewRunnableMethod("dom::HTMLInputElement::MaybeLoadImage",
    4880             :                           this,
    4881           0 :                           &HTMLInputElement::MaybeLoadImage));
    4882             :     }
    4883             :   }
    4884             : 
    4885             :   // Add radio to document if we don't have a form already (if we do it's
    4886             :   // already been added into that group)
    4887          21 :   if (aDocument && !mForm && mType == NS_FORM_INPUT_RADIO) {
    4888           0 :     AddedToRadioGroup();
    4889             :   }
    4890             : 
    4891             :   // Set direction based on value if dir=auto
    4892          21 :   if (HasDirAuto()) {
    4893           0 :     SetDirectionFromValue(false);
    4894             :   }
    4895             : 
    4896             :   // An element can't suffer from value missing if it is not in a document.
    4897             :   // We have to check if we suffer from that as we are now in a document.
    4898          21 :   UpdateValueMissingValidityState();
    4899             : 
    4900             :   // If there is a disabled fieldset in the parent chain, the element is now
    4901             :   // barred from constraint validation and can't suffer from value missing
    4902             :   // (call done before).
    4903          21 :   UpdateBarredFromConstraintValidation();
    4904             : 
    4905             :   // And now make sure our state is up to date
    4906          21 :   UpdateState(false);
    4907             : 
    4908          21 :   if (mType == NS_FORM_INPUT_PASSWORD) {
    4909           0 :     if (IsInComposedDoc()) {
    4910             :       AsyncEventDispatcher* dispatcher =
    4911             :         new AsyncEventDispatcher(this,
    4912           0 :                                  NS_LITERAL_STRING("DOMInputPasswordAdded"),
    4913             :                                  true,
    4914           0 :                                  true);
    4915           0 :       dispatcher->PostDOMEvent();
    4916             :     }
    4917             : 
    4918             : #ifdef EARLY_BETA_OR_EARLIER
    4919           0 :     Telemetry::Accumulate(Telemetry::PWMGR_PASSWORD_INPUT_IN_FORM, !!mForm);
    4920             : #endif
    4921             :   }
    4922             : 
    4923          21 :   return rv;
    4924             : }
    4925             : 
    4926             : void
    4927           2 : HTMLInputElement::UnbindFromTree(bool aDeep, bool aNullParent)
    4928             : {
    4929             :   // If we have a form and are unbound from it,
    4930             :   // nsGenericHTMLFormElementWithState::UnbindFromTree() will unset the form and
    4931             :   // that takes care of form's WillRemove so we just have to take care
    4932             :   // of the case where we're removing from the document and we don't
    4933             :   // have a form
    4934           2 :   if (!mForm && mType == NS_FORM_INPUT_RADIO) {
    4935           0 :     WillRemoveFromRadioGroup();
    4936             :   }
    4937             : 
    4938           2 :   nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
    4939           2 :   nsGenericHTMLFormElementWithState::UnbindFromTree(aDeep, aNullParent);
    4940             : 
    4941             :   // GetCurrentDoc is returning nullptr so we can update the value
    4942             :   // missing validity state to reflect we are no longer into a doc.
    4943           2 :   UpdateValueMissingValidityState();
    4944             :   // We might be no longer disabled because of parent chain changed.
    4945           2 :   UpdateBarredFromConstraintValidation();
    4946             : 
    4947             :   // And now make sure our state is up to date
    4948           2 :   UpdateState(false);
    4949           2 : }
    4950             : 
    4951             : void
    4952           1 : HTMLInputElement::HandleTypeChange(uint8_t aNewType, bool aNotify)
    4953             : {
    4954           1 :   uint8_t oldType = mType;
    4955           1 :   MOZ_ASSERT(oldType != aNewType);
    4956             : 
    4957           1 :   nsFocusManager* fm = nsFocusManager::GetFocusManager();
    4958           1 :   if (fm) {
    4959             :     // Input element can represent very different kinds of UIs, and we may
    4960             :     // need to flush styling even when focusing the already focused input
    4961             :     // element.
    4962           1 :     fm->NeedsFlushBeforeEventHandling(this);
    4963             :   }
    4964             : 
    4965           1 :   if (aNewType == NS_FORM_INPUT_FILE || oldType == NS_FORM_INPUT_FILE) {
    4966           0 :     if (aNewType == NS_FORM_INPUT_FILE) {
    4967           0 :       mFileData.reset(new FileData());
    4968             :     } else {
    4969           0 :       mFileData->Unlink();
    4970           0 :       mFileData = nullptr;
    4971             :     }
    4972             :   }
    4973             : 
    4974           1 :   if (oldType == NS_FORM_INPUT_RANGE && mIsDraggingRange) {
    4975           0 :     CancelRangeThumbDrag(false);
    4976             :   }
    4977             : 
    4978           1 :   ValueModeType aOldValueMode = GetValueMode();
    4979           2 :   nsAutoString aOldValue;
    4980             : 
    4981           1 :   if (aOldValueMode == VALUE_MODE_VALUE) {
    4982             :     // Doesn't matter what caller type we pass here, since we know we're not a
    4983             :     // file input anyway.
    4984           1 :     GetValue(aOldValue, CallerType::NonSystem);
    4985             :   }
    4986             : 
    4987           1 :   nsTextEditorState::SelectionProperties sp;
    4988             : 
    4989           1 :   if (GetEditorState()) {
    4990           1 :     mInputData.mState->SyncUpSelectionPropertiesBeforeDestruction();
    4991           1 :     sp = mInputData.mState->GetSelectionProperties();
    4992             :   }
    4993             : 
    4994             :   // We already have a copy of the value, lets free it and changes the type.
    4995           1 :   FreeData();
    4996           1 :   mType = aNewType;
    4997           1 :   void* memory = mInputTypeMem;
    4998           1 :   mInputType = InputType::Create(this, mType, memory);
    4999             : 
    5000           1 :   if (IsSingleLineTextControl()) {
    5001             : 
    5002           1 :     mInputData.mState =
    5003           1 :       nsTextEditorState::Construct(this, &sCachedTextEditorState);
    5004           1 :     if (!sp.IsDefault()) {
    5005           0 :       mInputData.mState->SetSelectionProperties(sp);
    5006             :     }
    5007             :   }
    5008             : 
    5009             :   /**
    5010             :    * The following code is trying to reproduce the algorithm described here:
    5011             :    * http://www.whatwg.org/specs/web-apps/current-work/complete.html#input-type-change
    5012             :    */
    5013           1 :   switch (GetValueMode()) {
    5014             :     case VALUE_MODE_DEFAULT:
    5015             :     case VALUE_MODE_DEFAULT_ON:
    5016             :       // If the previous value mode was value, we need to set the value content
    5017             :       // attribute to the previous value.
    5018             :       // There is no value sanitizing algorithm for elements in this mode.
    5019           0 :       if (aOldValueMode == VALUE_MODE_VALUE && !aOldValue.IsEmpty()) {
    5020           0 :         SetAttr(kNameSpaceID_None, nsGkAtoms::value, aOldValue, true);
    5021             :       }
    5022           0 :       break;
    5023             :     case VALUE_MODE_VALUE:
    5024             :       // If the previous value mode wasn't value, we have to set the value to
    5025             :       // the value content attribute.
    5026             :       // SetValueInternal is going to sanitize the value.
    5027             :       {
    5028           2 :         nsAutoString value;
    5029           1 :         if (aOldValueMode != VALUE_MODE_VALUE) {
    5030           0 :           GetAttr(kNameSpaceID_None, nsGkAtoms::value, value);
    5031             :         } else {
    5032           1 :           value = aOldValue;
    5033             :         }
    5034             :         // TODO: What should we do if SetValueInternal fails?  (The allocation
    5035             :         // may potentially be big, but most likely we've failed to allocate
    5036             :         // before the type change.)
    5037           1 :         SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
    5038             :       }
    5039           1 :       break;
    5040             :     case VALUE_MODE_FILENAME:
    5041             :     default:
    5042             :       // We don't care about the value.
    5043             :       // There is no value sanitizing algorithm for elements in this mode.
    5044           0 :       break;
    5045             :   }
    5046             : 
    5047             :   // Updating mFocusedValue in consequence:
    5048             :   // If the new type fires a change event on blur, but the previous type
    5049             :   // doesn't, we should set mFocusedValue to the current value.
    5050             :   // Otherwise, if the new type doesn't fire a change event on blur, but the
    5051             :   // previous type does, we should clear out mFocusedValue.
    5052           1 :   if (MayFireChangeOnBlur(mType) && !MayFireChangeOnBlur(oldType)) {
    5053           0 :     GetValue(mFocusedValue, CallerType::System);
    5054           1 :   } else if (!IsSingleLineTextControl(false, mType) &&
    5055           0 :              IsSingleLineTextControl(false, oldType)) {
    5056           0 :     mFocusedValue.Truncate();
    5057             :   }
    5058             : 
    5059           1 :   UpdateHasRange();
    5060             : 
    5061             :   // Do not notify, it will be done after if needed.
    5062           1 :   UpdateAllValidityStates(false);
    5063             : 
    5064           1 :   UpdateApzAwareFlag();
    5065             : 
    5066           1 :   UpdateBarredFromConstraintValidation();
    5067             : 
    5068           1 :   if (oldType == NS_FORM_INPUT_IMAGE) {
    5069             :     // We're no longer an image input.  Cancel our image requests, if we have
    5070             :     // any.
    5071           0 :     CancelImageRequests(aNotify);
    5072           1 :   } else if (aNotify && mType == NS_FORM_INPUT_IMAGE) {
    5073             :     // We just got switched to be an image input; we should see
    5074             :     // whether we have an image to load;
    5075           0 :     nsAutoString src;
    5076           0 :     if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
    5077             :       // Mark channel as urgent-start before load image if the image load is
    5078             :       // initaiated by a user interaction.
    5079           0 :       mUseUrgentStartForChannel = EventStateManager::IsHandlingUserInput();
    5080             : 
    5081           0 :       LoadImage(src, false, aNotify, eImageLoadType_Normal);
    5082             :     }
    5083             :   }
    5084             : 
    5085           1 :   if (mType == NS_FORM_INPUT_PASSWORD && IsInComposedDoc()) {
    5086             :     AsyncEventDispatcher* dispatcher =
    5087             :       new AsyncEventDispatcher(this,
    5088           0 :                                NS_LITERAL_STRING("DOMInputPasswordAdded"),
    5089             :                                true,
    5090           0 :                                true);
    5091           0 :     dispatcher->PostDOMEvent();
    5092             :   }
    5093           1 : }
    5094             : 
    5095             : void
    5096          34 : HTMLInputElement::SanitizeValue(nsAString& aValue)
    5097             : {
    5098          34 :   NS_ASSERTION(mDoneCreating, "The element creation should be finished!");
    5099             : 
    5100          34 :   switch (mType) {
    5101             :     case NS_FORM_INPUT_TEXT:
    5102             :     case NS_FORM_INPUT_SEARCH:
    5103             :     case NS_FORM_INPUT_TEL:
    5104             :     case NS_FORM_INPUT_PASSWORD:
    5105             :       {
    5106          34 :         aValue.StripCRLF();
    5107             :       }
    5108          34 :       break;
    5109             :     case NS_FORM_INPUT_EMAIL:
    5110             :     case NS_FORM_INPUT_URL:
    5111             :       {
    5112           0 :         aValue.StripCRLF();
    5113             : 
    5114           0 :         aValue = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aValue);
    5115             :       }
    5116           0 :       break;
    5117             :     case NS_FORM_INPUT_NUMBER:
    5118             :       {
    5119           0 :         Decimal value;
    5120           0 :         bool ok = mInputType->ConvertStringToNumber(aValue, value);
    5121           0 :         if (!ok) {
    5122           0 :           aValue.Truncate();
    5123             :         }
    5124             :       }
    5125           0 :       break;
    5126             :     case NS_FORM_INPUT_RANGE:
    5127             :       {
    5128           0 :         Decimal minimum = GetMinimum();
    5129           0 :         Decimal maximum = GetMaximum();
    5130           0 :         MOZ_ASSERT(minimum.isFinite() && maximum.isFinite(),
    5131             :                    "type=range should have a default maximum/minimum");
    5132             : 
    5133             :         // We use this to avoid modifying the string unnecessarily, since that
    5134             :         // may introduce rounding. This is set to true only if the value we
    5135             :         // parse out from aValue needs to be sanitized.
    5136           0 :         bool needSanitization = false;
    5137             : 
    5138           0 :         Decimal value;
    5139           0 :         bool ok = mInputType->ConvertStringToNumber(aValue, value);
    5140           0 :         if (!ok) {
    5141           0 :           needSanitization = true;
    5142             :           // Set value to midway between minimum and maximum.
    5143           0 :           value = maximum <= minimum ? minimum : minimum + (maximum - minimum)/Decimal(2);
    5144           0 :         } else if (value < minimum || maximum < minimum) {
    5145           0 :           needSanitization = true;
    5146           0 :           value = minimum;
    5147           0 :         } else if (value > maximum) {
    5148           0 :           needSanitization = true;
    5149           0 :           value = maximum;
    5150             :         }
    5151             : 
    5152           0 :         Decimal step = GetStep();
    5153           0 :         if (step != kStepAny) {
    5154           0 :           Decimal stepBase = GetStepBase();
    5155             :           // There could be rounding issues below when dealing with fractional
    5156             :           // numbers, but let's ignore that until ECMAScript supplies us with a
    5157             :           // decimal number type.
    5158           0 :           Decimal deltaToStep = NS_floorModulo(value - stepBase, step);
    5159           0 :           if (deltaToStep != Decimal(0)) {
    5160             :             // "suffering from a step mismatch"
    5161             :             // Round the element's value to the nearest number for which the
    5162             :             // element would not suffer from a step mismatch, and which is
    5163             :             // greater than or equal to the minimum, and, if the maximum is not
    5164             :             // less than the minimum, which is less than or equal to the
    5165             :             // maximum, if there is a number that matches these constraints:
    5166           0 :             MOZ_ASSERT(deltaToStep > Decimal(0), "stepBelow/stepAbove will be wrong");
    5167           0 :             Decimal stepBelow = value - deltaToStep;
    5168           0 :             Decimal stepAbove = value - deltaToStep + step;
    5169           0 :             Decimal halfStep = step / Decimal(2);
    5170           0 :             bool stepAboveIsClosest = (stepAbove - value) <= halfStep;
    5171           0 :             bool stepAboveInRange = stepAbove >= minimum &&
    5172           0 :                                     stepAbove <= maximum;
    5173           0 :             bool stepBelowInRange = stepBelow >= minimum &&
    5174           0 :                                     stepBelow <= maximum;
    5175             : 
    5176           0 :             if ((stepAboveIsClosest || !stepBelowInRange) && stepAboveInRange) {
    5177           0 :               needSanitization = true;
    5178           0 :               value = stepAbove;
    5179           0 :             } else if ((!stepAboveIsClosest || !stepAboveInRange) && stepBelowInRange) {
    5180           0 :               needSanitization = true;
    5181           0 :               value = stepBelow;
    5182             :             }
    5183             :           }
    5184             :         }
    5185             : 
    5186           0 :         if (needSanitization) {
    5187             :           char buf[32];
    5188           0 :           DebugOnly<bool> ok = value.toString(buf, ArrayLength(buf));
    5189           0 :           aValue.AssignASCII(buf);
    5190           0 :           MOZ_ASSERT(ok, "buf not big enough");
    5191             :         }
    5192             :       }
    5193           0 :       break;
    5194             :     case NS_FORM_INPUT_DATE:
    5195             :       {
    5196           0 :         if (!aValue.IsEmpty() && !IsValidDate(aValue)) {
    5197           0 :           aValue.Truncate();
    5198             :         }
    5199             :       }
    5200           0 :       break;
    5201             :     case NS_FORM_INPUT_TIME:
    5202             :       {
    5203           0 :         if (!aValue.IsEmpty() && !IsValidTime(aValue)) {
    5204           0 :           aValue.Truncate();
    5205             :         }
    5206             :       }
    5207           0 :       break;
    5208             :     case NS_FORM_INPUT_MONTH:
    5209             :       {
    5210           0 :         if (!aValue.IsEmpty() && !IsValidMonth(aValue)) {
    5211           0 :           aValue.Truncate();
    5212             :         }
    5213             :       }
    5214           0 :       break;
    5215             :     case NS_FORM_INPUT_WEEK:
    5216             :       {
    5217           0 :         if (!aValue.IsEmpty() && !IsValidWeek(aValue)) {
    5218           0 :           aValue.Truncate();
    5219             :         }
    5220             :       }
    5221           0 :       break;
    5222             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    5223             :       {
    5224           0 :         if (!aValue.IsEmpty() && !IsValidDateTimeLocal(aValue)) {
    5225           0 :           aValue.Truncate();
    5226             :         } else {
    5227           0 :           NormalizeDateTimeLocal(aValue);
    5228             :         }
    5229             :       }
    5230           0 :       break;
    5231             :     case NS_FORM_INPUT_COLOR:
    5232             :       {
    5233           0 :         if (IsValidSimpleColor(aValue)) {
    5234           0 :           ToLowerCase(aValue);
    5235             :         } else {
    5236             :           // Set default (black) color, if aValue wasn't parsed correctly.
    5237           0 :           aValue.AssignLiteral("#000000");
    5238             :         }
    5239             :       }
    5240           0 :       break;
    5241             :   }
    5242          34 : }
    5243             : 
    5244           0 : bool HTMLInputElement::IsValidSimpleColor(const nsAString& aValue) const
    5245             : {
    5246           0 :   if (aValue.Length() != 7 || aValue.First() != '#') {
    5247           0 :     return false;
    5248             :   }
    5249             : 
    5250           0 :   for (int i = 1; i < 7; ++i) {
    5251           0 :     if (!nsCRT::IsAsciiDigit(aValue[i]) &&
    5252           0 :         !(aValue[i] >= 'a' && aValue[i] <= 'f') &&
    5253           0 :         !(aValue[i] >= 'A' && aValue[i] <= 'F')) {
    5254           0 :       return false;
    5255             :     }
    5256             :   }
    5257           0 :   return true;
    5258             : }
    5259             : 
    5260             : bool
    5261           0 : HTMLInputElement::IsLeapYear(uint32_t aYear) const
    5262             : {
    5263           0 :   if ((aYear % 4 == 0 && aYear % 100 != 0) || ( aYear % 400 == 0)) {
    5264           0 :     return true;
    5265             :   }
    5266           0 :   return false;
    5267             : }
    5268             : 
    5269             : uint32_t
    5270           0 : HTMLInputElement::DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
    5271             :                             bool isoWeek) const
    5272             : {
    5273             :   // Tomohiko Sakamoto algorithm.
    5274           0 :   int monthTable[] = {0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4};
    5275           0 :   aYear -= aMonth < 3;
    5276             : 
    5277           0 :   uint32_t day = (aYear + aYear / 4 - aYear / 100 + aYear / 400 +
    5278           0 :                   monthTable[aMonth - 1] + aDay) % 7;
    5279             : 
    5280           0 :   if (isoWeek) {
    5281           0 :     return ((day + 6) % 7) + 1;
    5282             :   }
    5283             : 
    5284           0 :   return day;
    5285             : }
    5286             : 
    5287             : uint32_t
    5288           0 : HTMLInputElement::MaximumWeekInYear(uint32_t aYear) const
    5289             : {
    5290           0 :   int day = DayOfWeek(aYear, 1, 1, true); // January 1.
    5291             :   // A year starting on Thursday or a leap year starting on Wednesday has 53
    5292             :   // weeks. All other years have 52 weeks.
    5293           0 :   return day == 4 || (day == 3 && IsLeapYear(aYear)) ?
    5294           0 :     kMaximumWeekInYear : kMaximumWeekInYear - 1;
    5295             : }
    5296             : 
    5297             : bool
    5298           0 : HTMLInputElement::IsValidWeek(const nsAString& aValue) const
    5299             : {
    5300             :   uint32_t year, week;
    5301           0 :   return ParseWeek(aValue, &year, &week);
    5302             : }
    5303             : 
    5304             : bool
    5305           0 : HTMLInputElement::IsValidMonth(const nsAString& aValue) const
    5306             : {
    5307             :   uint32_t year, month;
    5308           0 :   return ParseMonth(aValue, &year, &month);
    5309             : }
    5310             : 
    5311             : bool
    5312           0 : HTMLInputElement::IsValidDate(const nsAString& aValue) const
    5313             : {
    5314             :   uint32_t year, month, day;
    5315           0 :   return ParseDate(aValue, &year, &month, &day);
    5316             : }
    5317             : 
    5318             : bool
    5319           0 : HTMLInputElement::IsValidDateTimeLocal(const nsAString& aValue) const
    5320             : {
    5321             :   uint32_t year, month, day, time;
    5322           0 :   return ParseDateTimeLocal(aValue, &year, &month, &day, &time);
    5323             : }
    5324             : 
    5325             : bool
    5326           0 : HTMLInputElement::ParseYear(const nsAString& aValue, uint32_t* aYear) const
    5327             : {
    5328           0 :   if (aValue.Length() < 4) {
    5329           0 :     return false;
    5330             :   }
    5331             : 
    5332           0 :   return DigitSubStringToNumber(aValue, 0, aValue.Length(), aYear) &&
    5333           0 :       *aYear > 0;
    5334             : }
    5335             : 
    5336             : bool
    5337           0 : HTMLInputElement::ParseMonth(const nsAString& aValue, uint32_t* aYear,
    5338             :                              uint32_t* aMonth) const
    5339             : {
    5340             :   // Parse the year, month values out a string formatted as 'yyyy-mm'.
    5341           0 :   if (aValue.Length() < 7) {
    5342           0 :     return false;
    5343             :   }
    5344             : 
    5345           0 :   uint32_t endOfYearOffset = aValue.Length() - 3;
    5346           0 :   if (aValue[endOfYearOffset] != '-') {
    5347           0 :     return false;
    5348             :   }
    5349             : 
    5350           0 :   const nsAString& yearStr = Substring(aValue, 0, endOfYearOffset);
    5351           0 :   if (!ParseYear(yearStr, aYear)) {
    5352           0 :     return false;
    5353             :   }
    5354             : 
    5355           0 :   return DigitSubStringToNumber(aValue, endOfYearOffset + 1, 2, aMonth) &&
    5356           0 :          *aMonth > 0 && *aMonth <= 12;
    5357             : }
    5358             : 
    5359             : bool
    5360           0 : HTMLInputElement::ParseWeek(const nsAString& aValue, uint32_t* aYear,
    5361             :                             uint32_t* aWeek) const
    5362             : {
    5363             :   // Parse the year, month values out a string formatted as 'yyyy-Www'.
    5364           0 :   if (aValue.Length() < 8) {
    5365           0 :     return false;
    5366             :   }
    5367             : 
    5368           0 :   uint32_t endOfYearOffset = aValue.Length() - 4;
    5369           0 :   if (aValue[endOfYearOffset] != '-') {
    5370           0 :     return false;
    5371             :   }
    5372             : 
    5373           0 :   if (aValue[endOfYearOffset + 1] != 'W') {
    5374           0 :     return false;
    5375             :   }
    5376             : 
    5377           0 :   const nsAString& yearStr = Substring(aValue, 0, endOfYearOffset);
    5378           0 :   if (!ParseYear(yearStr, aYear)) {
    5379           0 :     return false;
    5380             :   }
    5381             : 
    5382           0 :   return DigitSubStringToNumber(aValue, endOfYearOffset + 2, 2, aWeek) &&
    5383           0 :          *aWeek > 0 && *aWeek <= MaximumWeekInYear(*aYear);
    5384             : 
    5385             : }
    5386             : 
    5387             : bool
    5388           0 : HTMLInputElement::ParseDate(const nsAString& aValue, uint32_t* aYear,
    5389             :                             uint32_t* aMonth, uint32_t* aDay) const
    5390             : {
    5391             : /*
    5392             :  * Parse the year, month, day values out a date string formatted as 'yyyy-mm-dd'.
    5393             :  * -The year must be 4 or more digits long, and year > 0
    5394             :  * -The month must be exactly 2 digits long, and 01 <= month <= 12
    5395             :  * -The day must be exactly 2 digit long, and 01 <= day <= maxday
    5396             :  *  Where maxday is the number of days in the month 'month' and year 'year'
    5397             :  */
    5398           0 :   if (aValue.Length() < 10) {
    5399           0 :     return false;
    5400             :   }
    5401             : 
    5402           0 :   uint32_t endOfMonthOffset = aValue.Length() - 3;
    5403           0 :   if (aValue[endOfMonthOffset] != '-') {
    5404           0 :     return false;
    5405             :   }
    5406             : 
    5407           0 :   const nsAString& yearMonthStr = Substring(aValue, 0, endOfMonthOffset);
    5408           0 :   if (!ParseMonth(yearMonthStr, aYear, aMonth)) {
    5409           0 :     return false;
    5410             :   }
    5411             : 
    5412           0 :   return DigitSubStringToNumber(aValue, endOfMonthOffset + 1, 2, aDay) &&
    5413           0 :          *aDay > 0 && *aDay <= NumberOfDaysInMonth(*aMonth, *aYear);
    5414             : }
    5415             : 
    5416             : bool
    5417           0 : HTMLInputElement::ParseDateTimeLocal(const nsAString& aValue, uint32_t* aYear,
    5418             :                                      uint32_t* aMonth, uint32_t* aDay,
    5419             :                                      uint32_t* aTime) const
    5420             : {
    5421             :   // Parse the year, month, day and time values out a string formatted as
    5422             :   // 'yyyy-mm-ddThh:mm[:ss.s] or 'yyyy-mm-dd hh:mm[:ss.s]', where fractions of
    5423             :   // seconds can be 1 to 3 digits.
    5424             :   // The minimum length allowed is 16, which is of the form 'yyyy-mm-ddThh:mm'
    5425             :   // or 'yyyy-mm-dd hh:mm'.
    5426           0 :   if (aValue.Length() < 16) {
    5427           0 :     return false;
    5428             :   }
    5429             : 
    5430           0 :   int32_t sepIndex = aValue.FindChar('T');
    5431           0 :   if (sepIndex == -1) {
    5432           0 :     sepIndex = aValue.FindChar(' ');
    5433             : 
    5434           0 :     if (sepIndex == -1) {
    5435           0 :       return false;
    5436             :     }
    5437             :   }
    5438             : 
    5439           0 :   const nsAString& dateStr = Substring(aValue, 0, sepIndex);
    5440           0 :   if (!ParseDate(dateStr, aYear, aMonth, aDay)) {
    5441           0 :     return false;
    5442             :   }
    5443             : 
    5444           0 :   const nsAString& timeStr = Substring(aValue, sepIndex + 1,
    5445           0 :                                        aValue.Length() - sepIndex + 1);
    5446           0 :   if (!ParseTime(timeStr, aTime)) {
    5447           0 :     return false;
    5448             :   }
    5449             : 
    5450           0 :   return true;
    5451             : }
    5452             : 
    5453             : void
    5454           0 : HTMLInputElement::NormalizeDateTimeLocal(nsAString& aValue) const
    5455             : {
    5456           0 :   if (aValue.IsEmpty()) {
    5457           0 :     return;
    5458             :   }
    5459             : 
    5460             :   // Use 'T' as the separator between date string and time string.
    5461           0 :   int32_t sepIndex = aValue.FindChar(' ');
    5462           0 :   if (sepIndex != -1) {
    5463           0 :     aValue.Replace(sepIndex, 1, NS_LITERAL_STRING("T"));
    5464             :   } else {
    5465           0 :     sepIndex = aValue.FindChar('T');
    5466             :   }
    5467             : 
    5468             :   // Time expressed as the shortest possible string, which is hh:mm.
    5469           0 :   if ((aValue.Length() - sepIndex) == 6) {
    5470           0 :     return;
    5471             :   }
    5472             : 
    5473             :   // Fractions of seconds part is optional, ommit it if it's 0.
    5474           0 :   if ((aValue.Length() - sepIndex) > 9) {
    5475           0 :     const uint32_t millisecSepIndex = sepIndex + 9;
    5476             :     uint32_t milliseconds;
    5477           0 :     if (!DigitSubStringToNumber(aValue, millisecSepIndex + 1,
    5478           0 :                                 aValue.Length() - (millisecSepIndex + 1),
    5479             :                                 &milliseconds)) {
    5480           0 :       return;
    5481             :     }
    5482             : 
    5483           0 :     if (milliseconds != 0) {
    5484           0 :       return;
    5485             :     }
    5486             : 
    5487           0 :     aValue.Cut(millisecSepIndex, aValue.Length() - millisecSepIndex);
    5488             :   }
    5489             : 
    5490             :   // Seconds part is optional, ommit it if it's 0.
    5491           0 :   const uint32_t secondSepIndex = sepIndex + 6;
    5492             :   uint32_t seconds;
    5493           0 :   if (!DigitSubStringToNumber(aValue, secondSepIndex + 1,
    5494           0 :                               aValue.Length() - (secondSepIndex + 1),
    5495             :                               &seconds)) {
    5496           0 :     return;
    5497             :   }
    5498             : 
    5499           0 :   if (seconds != 0) {
    5500           0 :     return;
    5501             :   }
    5502             : 
    5503           0 :   aValue.Cut(secondSepIndex, aValue.Length() - secondSepIndex);
    5504             : }
    5505             : 
    5506             : double
    5507           0 : HTMLInputElement::DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const
    5508             : {
    5509           0 :   double days = JS::DayFromYear(aYear) + (aWeek - 1) * 7;
    5510           0 :   uint32_t dayOneIsoWeekday = DayOfWeek(aYear, 1, 1, true);
    5511             : 
    5512             :   // If day one of that year is on/before Thursday, we should subtract the
    5513             :   // days that belong to last year in our first week, otherwise, our first
    5514             :   // days belong to last year's last week, and we should add those days
    5515             :   // back.
    5516           0 :   if (dayOneIsoWeekday <= 4) {
    5517           0 :     days -= (dayOneIsoWeekday - 1);
    5518             :   } else {
    5519           0 :     days += (7 - dayOneIsoWeekday + 1);
    5520             :   }
    5521             : 
    5522           0 :   return days;
    5523             : }
    5524             : 
    5525             : uint32_t
    5526           0 : HTMLInputElement::NumberOfDaysInMonth(uint32_t aMonth, uint32_t aYear) const
    5527             : {
    5528             : /*
    5529             :  * Returns the number of days in a month.
    5530             :  * Months that are |longMonths| always have 31 days.
    5531             :  * Months that are not |longMonths| have 30 days except February (month 2).
    5532             :  * February has 29 days during leap years which are years that are divisible by 400.
    5533             :  * or divisible by 100 and 4. February has 28 days otherwise.
    5534             :  */
    5535             : 
    5536             :   static const bool longMonths[] = { true, false, true, false, true, false,
    5537             :                                      true, true, false, true, false, true };
    5538           0 :   MOZ_ASSERT(aMonth <= 12 && aMonth > 0);
    5539             : 
    5540           0 :   if (longMonths[aMonth-1]) {
    5541           0 :     return 31;
    5542             :   }
    5543             : 
    5544           0 :   if (aMonth != 2) {
    5545           0 :     return 30;
    5546             :   }
    5547             : 
    5548           0 :   return IsLeapYear(aYear) ? 29 : 28;
    5549             : }
    5550             : 
    5551             : /* static */ bool
    5552           0 : HTMLInputElement::DigitSubStringToNumber(const nsAString& aStr,
    5553             :                                          uint32_t aStart, uint32_t aLen,
    5554             :                                          uint32_t* aRetVal)
    5555             : {
    5556           0 :   MOZ_ASSERT(aStr.Length() > (aStart + aLen - 1));
    5557             : 
    5558           0 :   for (uint32_t offset = 0; offset < aLen; ++offset) {
    5559           0 :     if (!NS_IsAsciiDigit(aStr[aStart + offset])) {
    5560           0 :       return false;
    5561             :     }
    5562             :   }
    5563             : 
    5564             :   nsresult ec;
    5565           0 :   *aRetVal = static_cast<uint32_t>(PromiseFlatString(Substring(aStr, aStart, aLen)).ToInteger(&ec));
    5566             : 
    5567           0 :   return NS_SUCCEEDED(ec);
    5568             : }
    5569             : 
    5570             : bool
    5571           0 : HTMLInputElement::IsValidTime(const nsAString& aValue) const
    5572             : {
    5573           0 :   return ParseTime(aValue, nullptr);
    5574             : }
    5575             : 
    5576             : /* static */ bool
    5577           0 : HTMLInputElement::ParseTime(const nsAString& aValue, uint32_t* aResult)
    5578             : {
    5579             :   /* The string must have the following parts:
    5580             :    * - HOURS: two digits, value being in [0, 23];
    5581             :    * - Colon (:);
    5582             :    * - MINUTES: two digits, value being in [0, 59];
    5583             :    * - Optional:
    5584             :    *   - Colon (:);
    5585             :    *   - SECONDS: two digits, value being in [0, 59];
    5586             :    *   - Optional:
    5587             :    *     - DOT (.);
    5588             :    *     - FRACTIONAL SECONDS: one to three digits, no value range.
    5589             :    */
    5590             : 
    5591             :   // The following format is the shorter one allowed: "HH:MM".
    5592           0 :   if (aValue.Length() < 5) {
    5593           0 :     return false;
    5594             :   }
    5595             : 
    5596             :   uint32_t hours;
    5597           0 :   if (!DigitSubStringToNumber(aValue, 0, 2, &hours) || hours > 23) {
    5598           0 :     return false;
    5599             :   }
    5600             : 
    5601             :   // Hours/minutes separator.
    5602           0 :   if (aValue[2] != ':') {
    5603           0 :     return false;
    5604             :   }
    5605             : 
    5606             :   uint32_t minutes;
    5607           0 :   if (!DigitSubStringToNumber(aValue, 3, 2, &minutes) || minutes > 59) {
    5608           0 :     return false;
    5609             :   }
    5610             : 
    5611           0 :   if (aValue.Length() == 5) {
    5612           0 :     if (aResult) {
    5613           0 :       *aResult = ((hours * 60) + minutes) * 60000;
    5614             :     }
    5615           0 :     return true;
    5616             :   }
    5617             : 
    5618             :   // The following format is the next shorter one: "HH:MM:SS".
    5619           0 :   if (aValue.Length() < 8 || aValue[5] != ':') {
    5620           0 :     return false;
    5621             :   }
    5622             : 
    5623             :   uint32_t seconds;
    5624           0 :   if (!DigitSubStringToNumber(aValue, 6, 2, &seconds) || seconds > 59) {
    5625           0 :     return false;
    5626             :   }
    5627             : 
    5628           0 :   if (aValue.Length() == 8) {
    5629           0 :     if (aResult) {
    5630           0 :       *aResult = (((hours * 60) + minutes) * 60 + seconds) * 1000;
    5631             :     }
    5632           0 :     return true;
    5633             :   }
    5634             : 
    5635             :   // The string must follow this format now: "HH:MM:SS.{s,ss,sss}".
    5636             :   // There can be 1 to 3 digits for the fractions of seconds.
    5637           0 :   if (aValue.Length() == 9 || aValue.Length() > 12 || aValue[8] != '.') {
    5638           0 :     return false;
    5639             :   }
    5640             : 
    5641             :   uint32_t fractionsSeconds;
    5642           0 :   if (!DigitSubStringToNumber(aValue, 9, aValue.Length() - 9, &fractionsSeconds)) {
    5643           0 :     return false;
    5644             :   }
    5645             : 
    5646           0 :   if (aResult) {
    5647           0 :     *aResult = (((hours * 60) + minutes) * 60 + seconds) * 1000 +
    5648             :                // NOTE: there is 10.0 instead of 10 and static_cast<int> because
    5649             :                // some old [and stupid] compilers can't just do the right thing.
    5650           0 :                fractionsSeconds * pow(10.0, static_cast<int>(3 - (aValue.Length() - 9)));
    5651             :   }
    5652             : 
    5653           0 :   return true;
    5654             : }
    5655             : 
    5656             : /* static */ bool
    5657           0 : HTMLInputElement::IsDateTimeTypeSupported(uint8_t aDateTimeInputType)
    5658             : {
    5659           0 :   return ((aDateTimeInputType == NS_FORM_INPUT_DATE ||
    5660           0 :            aDateTimeInputType == NS_FORM_INPUT_TIME) &&
    5661           0 :           (IsInputDateTimeEnabled() || IsExperimentalFormsEnabled())) ||
    5662           0 :          ((aDateTimeInputType == NS_FORM_INPUT_MONTH ||
    5663           0 :            aDateTimeInputType == NS_FORM_INPUT_WEEK ||
    5664           0 :            aDateTimeInputType == NS_FORM_INPUT_DATETIME_LOCAL) &&
    5665           0 :           IsInputDateTimeOthersEnabled());
    5666             : }
    5667             : 
    5668             : /* static */ bool
    5669           0 : HTMLInputElement::IsWebkitDirPickerEnabled()
    5670             : {
    5671             :   static bool sWebkitDirPickerEnabled = false;
    5672             :   static bool sWebkitDirPickerPrefCached = false;
    5673           0 :   if (!sWebkitDirPickerPrefCached) {
    5674           0 :     sWebkitDirPickerPrefCached = true;
    5675             :     Preferences::AddBoolVarCache(&sWebkitDirPickerEnabled,
    5676             :                                  "dom.webkitBlink.dirPicker.enabled",
    5677           0 :                                  false);
    5678             :   }
    5679             : 
    5680           0 :   return sWebkitDirPickerEnabled;
    5681             : }
    5682             : 
    5683             : /* static */ bool
    5684           0 : HTMLInputElement::IsWebkitFileSystemEnabled()
    5685             : {
    5686             :   static bool sWebkitFileSystemEnabled = false;
    5687             :   static bool sWebkitFileSystemPrefCached = false;
    5688           0 :   if (!sWebkitFileSystemPrefCached) {
    5689           0 :     sWebkitFileSystemPrefCached = true;
    5690             :     Preferences::AddBoolVarCache(&sWebkitFileSystemEnabled,
    5691             :                                  "dom.webkitBlink.filesystem.enabled",
    5692           0 :                                  false);
    5693             :   }
    5694             : 
    5695           0 :   return sWebkitFileSystemEnabled;
    5696             : }
    5697             : 
    5698             : /* static */ bool
    5699           0 : HTMLInputElement::IsDirPickerEnabled()
    5700             : {
    5701             :   static bool sDirPickerEnabled = false;
    5702             :   static bool sDirPickerPrefCached = false;
    5703           0 :   if (!sDirPickerPrefCached) {
    5704           0 :     sDirPickerPrefCached = true;
    5705             :     Preferences::AddBoolVarCache(&sDirPickerEnabled, "dom.input.dirpicker",
    5706           0 :                                  false);
    5707             :   }
    5708             : 
    5709           0 :   return sDirPickerEnabled;
    5710             : }
    5711             : 
    5712             : /* static */ bool
    5713           1 : HTMLInputElement::IsExperimentalFormsEnabled()
    5714             : {
    5715             :   static bool sExperimentalFormsEnabled = false;
    5716             :   static bool sExperimentalFormsPrefCached = false;
    5717           1 :   if (!sExperimentalFormsPrefCached) {
    5718           1 :     sExperimentalFormsPrefCached = true;
    5719             :     Preferences::AddBoolVarCache(&sExperimentalFormsEnabled,
    5720             :                                  "dom.experimental_forms",
    5721           1 :                                  false);
    5722             :   }
    5723             : 
    5724           1 :   return sExperimentalFormsEnabled;
    5725             : }
    5726             : 
    5727             : /* static */ bool
    5728           1 : HTMLInputElement::IsInputDateTimeEnabled()
    5729             : {
    5730             :   static bool sDateTimeEnabled = false;
    5731             :   static bool sDateTimePrefCached = false;
    5732           1 :   if (!sDateTimePrefCached) {
    5733           1 :     sDateTimePrefCached = true;
    5734             :     Preferences::AddBoolVarCache(&sDateTimeEnabled, "dom.forms.datetime",
    5735           1 :                                  false);
    5736             :   }
    5737             : 
    5738           1 :   return sDateTimeEnabled;
    5739             : }
    5740             : 
    5741             : /* static */ bool
    5742           0 : HTMLInputElement::IsInputDateTimeOthersEnabled()
    5743             : {
    5744             :   static bool sDateTimeOthersEnabled = false;
    5745             :   static bool sDateTimeOthersPrefCached = false;
    5746           0 :   if (!sDateTimeOthersPrefCached) {
    5747           0 :     sDateTimeOthersPrefCached = true;
    5748             :     Preferences::AddBoolVarCache(&sDateTimeOthersEnabled,
    5749           0 :                                  "dom.forms.datetime.others", false);
    5750             :   }
    5751             : 
    5752           0 :   return sDateTimeOthersEnabled;
    5753             : }
    5754             : 
    5755             : /* static */ bool
    5756           0 : HTMLInputElement::IsInputNumberEnabled()
    5757             : {
    5758             :   static bool sInputNumberEnabled = false;
    5759             :   static bool sInputNumberPrefCached = false;
    5760           0 :   if (!sInputNumberPrefCached) {
    5761           0 :     sInputNumberPrefCached = true;
    5762             :     Preferences::AddBoolVarCache(&sInputNumberEnabled, "dom.forms.number",
    5763           0 :                                  false);
    5764             :   }
    5765             : 
    5766           0 :   return sInputNumberEnabled;
    5767             : }
    5768             : 
    5769             : /* static */ bool
    5770           0 : HTMLInputElement::IsInputColorEnabled()
    5771             : {
    5772             :   static bool sInputColorEnabled = false;
    5773             :   static bool sInputColorPrefCached = false;
    5774           0 :   if (!sInputColorPrefCached) {
    5775           0 :     sInputColorPrefCached = true;
    5776             :     Preferences::AddBoolVarCache(&sInputColorEnabled, "dom.forms.color",
    5777           0 :                                  false);
    5778             :   }
    5779             : 
    5780           0 :   return sInputColorEnabled;
    5781             : }
    5782             : 
    5783             : bool
    5784          25 : HTMLInputElement::ParseAttribute(int32_t aNamespaceID,
    5785             :                                  nsIAtom* aAttribute,
    5786             :                                  const nsAString& aValue,
    5787             :                                  nsAttrValue& aResult)
    5788             : {
    5789             :   // We can't make these static_asserts because kInputDefaultType and
    5790             :   // kInputTypeTable aren't constexpr.
    5791          25 :   MOZ_ASSERT(kInputDefaultType->value == NS_FORM_INPUT_TEXT,
    5792             :              "Someone forgot to update kInputDefaultType when adding a new "
    5793             :              "input type.");
    5794          25 :   MOZ_ASSERT(kInputTypeTable[ArrayLength(kInputTypeTable) - 1].tag == nullptr,
    5795             :              "Last entry in the table must be the nullptr guard");
    5796          25 :   MOZ_ASSERT(kInputTypeTable[ArrayLength(kInputTypeTable) - 2].value ==
    5797             :                NS_FORM_INPUT_TEXT,
    5798             :              "Next to last entry in the table must be the \"text\" entry");
    5799             : 
    5800          25 :   if (aNamespaceID == kNameSpaceID_None) {
    5801          18 :     if (aAttribute == nsGkAtoms::type) {
    5802           1 :       aResult.ParseEnumValue(aValue, kInputTypeTable, false, kInputDefaultType);
    5803           1 :       int32_t newType = aResult.GetEnumValue();
    5804           1 :       if ((newType == NS_FORM_INPUT_NUMBER && !IsInputNumberEnabled()) ||
    5805           2 :           (newType == NS_FORM_INPUT_COLOR && !IsInputColorEnabled()) ||
    5806           1 :           (IsDateTimeInputType(newType) && !IsDateTimeTypeSupported(newType))) {
    5807             :         // There's no public way to set an nsAttrValue to an enum value, but we
    5808             :         // can just re-parse with a table that doesn't have any types other than
    5809             :         // "text" in it.
    5810           0 :         aResult.ParseEnumValue(aValue, kInputDefaultType, false, kInputDefaultType);
    5811             :       }
    5812             : 
    5813           1 :       return true;
    5814             :     }
    5815          17 :     if (aAttribute == nsGkAtoms::width) {
    5816           0 :       return aResult.ParseSpecialIntValue(aValue);
    5817             :     }
    5818          17 :     if (aAttribute == nsGkAtoms::height) {
    5819           0 :       return aResult.ParseSpecialIntValue(aValue);
    5820             :     }
    5821          17 :     if (aAttribute == nsGkAtoms::maxlength) {
    5822           0 :       return aResult.ParseNonNegativeIntValue(aValue);
    5823             :     }
    5824          17 :     if (aAttribute == nsGkAtoms::minlength) {
    5825           0 :       return aResult.ParseNonNegativeIntValue(aValue);
    5826             :     }
    5827          17 :     if (aAttribute == nsGkAtoms::size) {
    5828           0 :       return aResult.ParsePositiveIntValue(aValue);
    5829             :     }
    5830          17 :     if (aAttribute == nsGkAtoms::border) {
    5831           0 :       return aResult.ParseIntWithBounds(aValue, 0);
    5832             :     }
    5833          17 :     if (aAttribute == nsGkAtoms::align) {
    5834           0 :       return ParseAlignValue(aValue, aResult);
    5835             :     }
    5836          17 :     if (aAttribute == nsGkAtoms::formmethod) {
    5837           0 :       return aResult.ParseEnumValue(aValue, kFormMethodTable, false);
    5838             :     }
    5839          17 :     if (aAttribute == nsGkAtoms::formenctype) {
    5840           0 :       return aResult.ParseEnumValue(aValue, kFormEnctypeTable, false);
    5841             :     }
    5842          17 :     if (aAttribute == nsGkAtoms::autocomplete) {
    5843           0 :       aResult.ParseAtomArray(aValue);
    5844           0 :       return true;
    5845             :     }
    5846          17 :     if (aAttribute == nsGkAtoms::inputmode) {
    5847           2 :       return aResult.ParseEnumValue(aValue, kInputInputmodeTable, false);
    5848             :     }
    5849          15 :     if (ParseImageAttribute(aAttribute, aValue, aResult)) {
    5850             :       // We have to call |ParseImageAttribute| unconditionally since we
    5851             :       // don't know if we're going to have a type="image" attribute yet,
    5852             :       // (or could have it set dynamically in the future).  See bug
    5853             :       // 214077.
    5854           0 :       return true;
    5855             :     }
    5856             :   }
    5857             : 
    5858          22 :   return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
    5859          22 :                                               aResult);
    5860             : }
    5861             : 
    5862             : void
    5863          33 : HTMLInputElement::MapAttributesIntoRule(const nsMappedAttributes* aAttributes,
    5864             :                                         GenericSpecifiedValues* aData)
    5865             : {
    5866          33 :   const nsAttrValue* value = aAttributes->GetAttr(nsGkAtoms::type);
    5867          66 :   if (value && value->Type() == nsAttrValue::eEnum &&
    5868          33 :       value->GetEnumValue() == NS_FORM_INPUT_IMAGE) {
    5869           0 :     nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes, aData);
    5870           0 :     nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes, aData);
    5871           0 :     nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes, aData);
    5872             :     // Images treat align as "float"
    5873           0 :     nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes, aData);
    5874             :   }
    5875             : 
    5876          33 :   nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes, aData);
    5877          33 : }
    5878             : 
    5879             : nsChangeHint
    5880           0 : HTMLInputElement::GetAttributeChangeHint(const nsIAtom* aAttribute,
    5881             :                                          int32_t aModType) const
    5882             : {
    5883             :   nsChangeHint retval =
    5884           0 :     nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute, aModType);
    5885           0 :   if (aAttribute == nsGkAtoms::type ||
    5886             :       // The presence or absence of the 'directory' attribute determines what
    5887             :       // buttons we show for type=file.
    5888           0 :       aAttribute == nsGkAtoms::allowdirs ||
    5889           0 :       aAttribute == nsGkAtoms::webkitdirectory) {
    5890           0 :     retval |= nsChangeHint_ReconstructFrame;
    5891           0 :   } else if (mType == NS_FORM_INPUT_IMAGE &&
    5892           0 :              (aAttribute == nsGkAtoms::alt ||
    5893           0 :               aAttribute == nsGkAtoms::value)) {
    5894             :     // We might need to rebuild our alt text.  Just go ahead and
    5895             :     // reconstruct our frame.  This should be quite rare..
    5896           0 :     retval |= nsChangeHint_ReconstructFrame;
    5897           0 :   } else if (aAttribute == nsGkAtoms::value) {
    5898           0 :     retval |= NS_STYLE_HINT_REFLOW;
    5899           0 :   } else if (aAttribute == nsGkAtoms::size &&
    5900           0 :              IsSingleLineTextControl(false)) {
    5901           0 :     retval |= NS_STYLE_HINT_REFLOW;
    5902           0 :   } else if (PlaceholderApplies() && aAttribute == nsGkAtoms::placeholder) {
    5903           0 :     retval |= nsChangeHint_ReconstructFrame;
    5904             :   }
    5905           0 :   return retval;
    5906             : }
    5907             : 
    5908             : NS_IMETHODIMP_(bool)
    5909          25 : HTMLInputElement::IsAttributeMapped(const nsIAtom* aAttribute) const
    5910             : {
    5911             :   static const MappedAttributeEntry attributes[] = {
    5912             :     { &nsGkAtoms::align },
    5913             :     { &nsGkAtoms::type },
    5914             :     { nullptr },
    5915             :   };
    5916             : 
    5917             :   static const MappedAttributeEntry* const map[] = {
    5918             :     attributes,
    5919             :     sCommonAttributeMap,
    5920             :     sImageMarginSizeAttributeMap,
    5921             :     sImageBorderAttributeMap,
    5922             :   };
    5923             : 
    5924          25 :   return FindAttributeDependence(aAttribute, map);
    5925             : }
    5926             : 
    5927             : nsMapRuleToAttributesFunc
    5928           1 : HTMLInputElement::GetAttributeMappingFunction() const
    5929             : {
    5930           1 :   return &MapAttributesIntoRule;
    5931             : }
    5932             : 
    5933             : 
    5934             : // Directory picking methods:
    5935             : 
    5936             : bool
    5937           0 : HTMLInputElement::IsFilesAndDirectoriesSupported() const
    5938             : {
    5939             :   // This method is supposed to return true if a file and directory picker
    5940             :   // supports the selection of both files and directories *at the same time*.
    5941             :   // Only Mac currently supports that. We could implement it for Mac, but
    5942             :   // currently we do not.
    5943           0 :   return false;
    5944             : }
    5945             : 
    5946             : void
    5947           0 : HTMLInputElement::ChooseDirectory(ErrorResult& aRv)
    5948             : {
    5949           0 :   if (mType != NS_FORM_INPUT_FILE) {
    5950           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    5951           0 :     return;
    5952             :   }
    5953             :   // Script can call this method directly, so even though we don't show the
    5954             :   // "Pick Folder..." button on platforms that don't have a directory picker
    5955             :   // we have to redirect to the file picker here.
    5956             :   InitFilePicker(
    5957             : #if defined(ANDROID) || defined(MOZ_B2G)
    5958             :                  // No native directory picker - redirect to plain file picker
    5959             :                  FILE_PICKER_FILE
    5960             : #else
    5961             :                  FILE_PICKER_DIRECTORY
    5962             : #endif
    5963           0 :                  );
    5964             : }
    5965             : 
    5966             : already_AddRefed<Promise>
    5967           0 : HTMLInputElement::GetFilesAndDirectories(ErrorResult& aRv)
    5968             : {
    5969           0 :   if (mType != NS_FORM_INPUT_FILE) {
    5970           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    5971           0 :     return nullptr;
    5972             :   }
    5973             : 
    5974           0 :   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
    5975           0 :   MOZ_ASSERT(global);
    5976           0 :   if (!global) {
    5977           0 :     return nullptr;
    5978             :   }
    5979             : 
    5980           0 :   RefPtr<Promise> p = Promise::Create(global, aRv);
    5981           0 :   if (aRv.Failed()) {
    5982           0 :     return nullptr;
    5983             :   }
    5984             : 
    5985             :   const nsTArray<OwningFileOrDirectory>& filesAndDirs =
    5986           0 :     GetFilesOrDirectoriesInternal();
    5987             : 
    5988           0 :   Sequence<OwningFileOrDirectory> filesAndDirsSeq;
    5989             : 
    5990           0 :   if (!filesAndDirsSeq.SetLength(filesAndDirs.Length(),
    5991           0 :                                  mozilla::fallible_t())) {
    5992           0 :     p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);
    5993           0 :     return p.forget();
    5994             :   }
    5995             : 
    5996           0 :   for (uint32_t i = 0; i < filesAndDirs.Length(); ++i) {
    5997           0 :     if (filesAndDirs[i].IsDirectory()) {
    5998           0 :       RefPtr<Directory> directory = filesAndDirs[i].GetAsDirectory();
    5999             : 
    6000             :       // In future we could refactor SetFilePickerFiltersFromAccept to return a
    6001             :       // semicolon separated list of file extensions and include that in the
    6002             :       // filter string passed here.
    6003           0 :       directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));
    6004           0 :       filesAndDirsSeq[i].SetAsDirectory() = directory;
    6005             :     } else {
    6006           0 :       MOZ_ASSERT(filesAndDirs[i].IsFile());
    6007             : 
    6008             :       // This file was directly selected by the user, so don't filter it.
    6009           0 :       filesAndDirsSeq[i].SetAsFile() = filesAndDirs[i].GetAsFile();
    6010             :     }
    6011             :   }
    6012             : 
    6013           0 :   p->MaybeResolve(filesAndDirsSeq);
    6014           0 :   return p.forget();
    6015             : }
    6016             : 
    6017             : already_AddRefed<Promise>
    6018           0 : HTMLInputElement::GetFiles(bool aRecursiveFlag, ErrorResult& aRv)
    6019             : {
    6020           0 :   if (mType != NS_FORM_INPUT_FILE) {
    6021           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    6022           0 :     return nullptr;
    6023             :   }
    6024             : 
    6025           0 :   GetFilesHelper* helper = GetOrCreateGetFilesHelper(aRecursiveFlag, aRv);
    6026           0 :   if (NS_WARN_IF(aRv.Failed())) {
    6027           0 :     return nullptr;
    6028             :   }
    6029           0 :   MOZ_ASSERT(helper);
    6030             : 
    6031           0 :   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
    6032           0 :   MOZ_ASSERT(global);
    6033           0 :   if (!global) {
    6034           0 :     return nullptr;
    6035             :   }
    6036             : 
    6037           0 :   RefPtr<Promise> p = Promise::Create(global, aRv);
    6038           0 :   if (aRv.Failed()) {
    6039           0 :     return nullptr;
    6040             :   }
    6041             : 
    6042           0 :   helper->AddPromise(p);
    6043           0 :   return p.forget();
    6044             : }
    6045             : 
    6046             : 
    6047             : // Controllers Methods
    6048             : 
    6049             : nsIControllers*
    6050           7 : HTMLInputElement::GetControllers(ErrorResult& aRv)
    6051             : {
    6052             :   //XXX: what about type "file"?
    6053           7 :   if (IsSingleLineTextControl(false))
    6054             :   {
    6055           7 :     if (!mControllers)
    6056             :     {
    6057             :       nsresult rv;
    6058           2 :       mControllers = do_CreateInstance(kXULControllersCID, &rv);
    6059           2 :       if (NS_FAILED(rv)) {
    6060           0 :         aRv.Throw(rv);
    6061           0 :         return nullptr;
    6062             :       }
    6063             : 
    6064             :       nsCOMPtr<nsIController>
    6065           4 :         controller(do_CreateInstance("@mozilla.org/editor/editorcontroller;1",
    6066           4 :                                      &rv));
    6067           2 :       if (NS_FAILED(rv)) {
    6068           0 :         aRv.Throw(rv);
    6069           0 :         return nullptr;
    6070             :       }
    6071             : 
    6072           2 :       mControllers->AppendController(controller);
    6073             : 
    6074           4 :       controller = do_CreateInstance("@mozilla.org/editor/editingcontroller;1",
    6075           2 :                                      &rv);
    6076           2 :       if (NS_FAILED(rv)) {
    6077           0 :         aRv.Throw(rv);
    6078           0 :         return nullptr;
    6079             :       }
    6080             : 
    6081           2 :       mControllers->AppendController(controller);
    6082             :     }
    6083             :   }
    6084             : 
    6085           7 :   return mControllers;
    6086             : }
    6087             : 
    6088             : NS_IMETHODIMP
    6089           4 : HTMLInputElement::GetControllers(nsIControllers** aResult)
    6090             : {
    6091           4 :   NS_ENSURE_ARG_POINTER(aResult);
    6092             : 
    6093           8 :   ErrorResult rv;
    6094           8 :   RefPtr<nsIControllers> controller = GetControllers(rv);
    6095           4 :   controller.forget(aResult);
    6096           4 :   return rv.StealNSResult();
    6097             : }
    6098             : 
    6099             : int32_t
    6100           0 : HTMLInputElement::InputTextLength(CallerType aCallerType)
    6101             : {
    6102           0 :   nsAutoString val;
    6103           0 :   GetValue(val, aCallerType);
    6104           0 :   return val.Length();
    6105             : }
    6106             : 
    6107             : void
    6108           0 : HTMLInputElement::SetSelectionRange(uint32_t aSelectionStart,
    6109             :                                     uint32_t aSelectionEnd,
    6110             :                                     const Optional<nsAString>& aDirection,
    6111             :                                     ErrorResult& aRv)
    6112             : {
    6113           0 :   if (!SupportsTextSelection()) {
    6114           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    6115           0 :     return;
    6116             :   }
    6117             : 
    6118           0 :   nsTextEditorState* state = GetEditorState();
    6119           0 :   MOZ_ASSERT(state, "SupportsTextSelection() returned true!");
    6120           0 :   state->SetSelectionRange(aSelectionStart, aSelectionEnd, aDirection, aRv);
    6121             : }
    6122             : 
    6123             : void
    6124           0 : HTMLInputElement::SetRangeText(const nsAString& aReplacement, ErrorResult& aRv)
    6125             : {
    6126           0 :   if (!SupportsTextSelection()) {
    6127           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    6128           0 :     return;
    6129             :   }
    6130             : 
    6131           0 :   nsTextEditorState* state = GetEditorState();
    6132           0 :   MOZ_ASSERT(state, "SupportsTextSelection() returned true!");
    6133           0 :   state->SetRangeText(aReplacement, aRv);
    6134             : }
    6135             : 
    6136             : void
    6137           0 : HTMLInputElement::SetRangeText(const nsAString& aReplacement, uint32_t aStart,
    6138             :                                uint32_t aEnd, SelectionMode aSelectMode,
    6139             :                                ErrorResult& aRv)
    6140             : {
    6141           0 :   if (!SupportsTextSelection()) {
    6142           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    6143           0 :     return;
    6144             :   }
    6145             : 
    6146           0 :   nsTextEditorState* state = GetEditorState();
    6147           0 :   MOZ_ASSERT(state, "SupportsTextSelection() returned true!");
    6148           0 :   state->SetRangeText(aReplacement, aStart, aEnd, aSelectMode, aRv);
    6149             : }
    6150             : 
    6151             : void
    6152           0 : HTMLInputElement::GetValueFromSetRangeText(nsAString& aValue)
    6153             : {
    6154           0 :   GetNonFileValueInternal(aValue);
    6155           0 : }
    6156             : 
    6157             : nsresult
    6158           0 : HTMLInputElement::SetValueFromSetRangeText(const nsAString& aValue)
    6159             : {
    6160             :   return SetValueInternal(aValue,
    6161             :                           nsTextEditorState::eSetValue_ByContent |
    6162           0 :                           nsTextEditorState::eSetValue_Notify);
    6163             : }
    6164             : 
    6165             : Nullable<uint32_t>
    6166           0 : HTMLInputElement::GetSelectionStart(ErrorResult& aRv)
    6167             : {
    6168           0 :   if (!SupportsTextSelection()) {
    6169           0 :     return Nullable<uint32_t>();
    6170             :   }
    6171             : 
    6172           0 :   uint32_t selStart = GetSelectionStartIgnoringType(aRv);
    6173           0 :   if (aRv.Failed()) {
    6174           0 :     return Nullable<uint32_t>();
    6175             :   }
    6176             : 
    6177           0 :   return Nullable<uint32_t>(selStart);
    6178             : }
    6179             : 
    6180             : uint32_t
    6181           0 : HTMLInputElement::GetSelectionStartIgnoringType(ErrorResult& aRv)
    6182             : {
    6183             :   uint32_t selEnd, selStart;
    6184           0 :   GetSelectionRange(&selStart, &selEnd, aRv);
    6185           0 :   return selStart;
    6186             : }
    6187             : 
    6188             : void
    6189           1 : HTMLInputElement::SetSelectionStart(const Nullable<uint32_t>& aSelectionStart,
    6190             :                                     ErrorResult& aRv)
    6191             : {
    6192           1 :   if (!SupportsTextSelection()) {
    6193           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    6194           0 :     return;
    6195             :   }
    6196             : 
    6197           1 :   nsTextEditorState* state = GetEditorState();
    6198           1 :   MOZ_ASSERT(state, "SupportsTextSelection() returned true!");
    6199           1 :   state->SetSelectionStart(aSelectionStart, aRv);
    6200             : }
    6201             : 
    6202             : Nullable<uint32_t>
    6203           0 : HTMLInputElement::GetSelectionEnd(ErrorResult& aRv)
    6204             : {
    6205           0 :   if (!SupportsTextSelection()) {
    6206           0 :     return Nullable<uint32_t>();
    6207             :   }
    6208             : 
    6209           0 :   uint32_t selEnd = GetSelectionEndIgnoringType(aRv);
    6210           0 :   if (aRv.Failed()) {
    6211           0 :     return Nullable<uint32_t>();
    6212             :   }
    6213             : 
    6214           0 :   return Nullable<uint32_t>(selEnd);
    6215             : }
    6216             : 
    6217             : uint32_t
    6218           0 : HTMLInputElement::GetSelectionEndIgnoringType(ErrorResult& aRv)
    6219             : {
    6220             :   uint32_t selEnd, selStart;
    6221           0 :   GetSelectionRange(&selStart, &selEnd, aRv);
    6222           0 :   return selEnd;
    6223             : }
    6224             : 
    6225             : void
    6226           1 : HTMLInputElement::SetSelectionEnd(const Nullable<uint32_t>& aSelectionEnd,
    6227             :                                   ErrorResult& aRv)
    6228             : {
    6229           1 :   if (!SupportsTextSelection()) {
    6230           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    6231           0 :     return;
    6232             :   }
    6233             : 
    6234           1 :   nsTextEditorState* state = GetEditorState();
    6235           1 :   MOZ_ASSERT(state, "SupportsTextSelection() returned true!");
    6236           1 :   state->SetSelectionEnd(aSelectionEnd, aRv);
    6237             : }
    6238             : 
    6239             : NS_IMETHODIMP
    6240           0 : HTMLInputElement::GetFiles(nsIDOMFileList** aFileList)
    6241             : {
    6242           0 :   RefPtr<FileList> list = GetFiles();
    6243           0 :   list.forget(aFileList);
    6244           0 :   return NS_OK;
    6245             : }
    6246             : 
    6247             : void
    6248           0 : HTMLInputElement::GetSelectionRange(uint32_t* aSelectionStart,
    6249             :                                     uint32_t* aSelectionEnd,
    6250             :                                     ErrorResult& aRv)
    6251             : {
    6252           0 :   nsTextEditorState* state = GetEditorState();
    6253           0 :   if (!state) {
    6254             :     // Not a text control.
    6255           0 :     aRv.Throw(NS_ERROR_UNEXPECTED);
    6256           0 :     return;
    6257             :   }
    6258             : 
    6259           0 :   state->GetSelectionRange(aSelectionStart, aSelectionEnd, aRv);
    6260             : }
    6261             : 
    6262             : void
    6263           0 : HTMLInputElement::GetSelectionDirection(nsAString& aDirection, ErrorResult& aRv)
    6264             : {
    6265           0 :   if (!SupportsTextSelection()) {
    6266           0 :     aDirection.SetIsVoid(true);
    6267           0 :     return;
    6268             :   }
    6269             : 
    6270           0 :   nsTextEditorState* state = GetEditorState();
    6271           0 :   MOZ_ASSERT(state, "SupportsTextSelection came back true!");
    6272           0 :   state->GetSelectionDirectionString(aDirection, aRv);
    6273             : }
    6274             : 
    6275             : void
    6276           0 : HTMLInputElement::SetSelectionDirection(const nsAString& aDirection, ErrorResult& aRv)
    6277             : {
    6278           0 :   if (!SupportsTextSelection()) {
    6279           0 :     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
    6280           0 :     return;
    6281             :   }
    6282             : 
    6283           0 :   nsTextEditorState* state = GetEditorState();
    6284           0 :   MOZ_ASSERT(state, "SupportsTextSelection came back true!");
    6285           0 :   state->SetSelectionDirection(aDirection, aRv);
    6286             : }
    6287             : 
    6288             : #ifdef ACCESSIBILITY
    6289             : /*static*/ nsresult
    6290           0 : FireEventForAccessibility(nsIDOMHTMLInputElement* aTarget,
    6291             :                           nsPresContext* aPresContext,
    6292             :                           EventMessage aEventMessage)
    6293             : {
    6294           0 :   nsCOMPtr<mozilla::dom::Element> element = do_QueryInterface(aTarget);
    6295             :   return nsContentUtils::DispatchTrustedEvent<WidgetEvent>
    6296           0 :     (element->OwnerDoc(), aTarget, aEventMessage, true, true);
    6297             : }
    6298             : #endif
    6299             : 
    6300             : void
    6301           8 : HTMLInputElement::UpdateApzAwareFlag()
    6302             : {
    6303             : #if !defined(ANDROID) && !defined(XP_MACOSX)
    6304           8 :   if ((mType == NS_FORM_INPUT_NUMBER) || (mType == NS_FORM_INPUT_RANGE)) {
    6305           0 :     SetMayBeApzAware();
    6306             :   }
    6307             : #endif
    6308           8 : }
    6309             : 
    6310             : nsresult
    6311           0 : HTMLInputElement::SetDefaultValueAsValue()
    6312             : {
    6313           0 :   NS_ASSERTION(GetValueMode() == VALUE_MODE_VALUE,
    6314             :                "GetValueMode() should return VALUE_MODE_VALUE!");
    6315             : 
    6316             :   // The element has a content attribute value different from it's value when
    6317             :   // it's in the value mode value.
    6318           0 :   nsAutoString resetVal;
    6319           0 :   GetDefaultValue(resetVal);
    6320             : 
    6321             :   // SetValueInternal is going to sanitize the value.
    6322           0 :   return SetValueInternal(resetVal, nsTextEditorState::eSetValue_Internal);
    6323             : }
    6324             : 
    6325             : void
    6326           0 : HTMLInputElement::SetDirectionFromValue(bool aNotify)
    6327             : {
    6328           0 :   if (IsSingleLineTextControl(true)) {
    6329           0 :     nsAutoString value;
    6330           0 :     GetValue(value, CallerType::System);
    6331           0 :     SetDirectionalityFromValue(this, value, aNotify);
    6332             :   }
    6333           0 : }
    6334             : 
    6335             : NS_IMETHODIMP
    6336           0 : HTMLInputElement::Reset()
    6337             : {
    6338             :   // We should be able to reset all dirty flags regardless of the type.
    6339           0 :   SetCheckedChanged(false);
    6340           0 :   SetValueChanged(false);
    6341           0 :   mLastValueChangeWasInteractive = false;
    6342             : 
    6343           0 :   switch (GetValueMode()) {
    6344             :     case VALUE_MODE_VALUE:
    6345           0 :       return SetDefaultValueAsValue();
    6346             :     case VALUE_MODE_DEFAULT_ON:
    6347           0 :       DoSetChecked(DefaultChecked(), true, false);
    6348           0 :       return NS_OK;
    6349             :     case VALUE_MODE_FILENAME:
    6350           0 :       ClearFiles(false);
    6351           0 :       return NS_OK;
    6352             :     case VALUE_MODE_DEFAULT:
    6353             :     default:
    6354           0 :       return NS_OK;
    6355             :   }
    6356             : }
    6357             : 
    6358             : NS_IMETHODIMP
    6359           0 : HTMLInputElement::SubmitNamesValues(HTMLFormSubmission* aFormSubmission)
    6360             : {
    6361             :   // Disabled elements don't submit
    6362             :   // For type=reset, and type=button, we just never submit, period.
    6363             :   // For type=image and type=button, we only submit if we were the button
    6364             :   // pressed
    6365             :   // For type=radio and type=checkbox, we only submit if checked=true
    6366           0 :   if (IsDisabled() || mType == NS_FORM_INPUT_RESET ||
    6367           0 :       mType == NS_FORM_INPUT_BUTTON ||
    6368           0 :       ((mType == NS_FORM_INPUT_SUBMIT || mType == NS_FORM_INPUT_IMAGE) &&
    6369           0 :        aFormSubmission->GetOriginatingElement() != this) ||
    6370           0 :       ((mType == NS_FORM_INPUT_RADIO || mType == NS_FORM_INPUT_CHECKBOX) &&
    6371           0 :        !mChecked)) {
    6372           0 :     return NS_OK;
    6373             :   }
    6374             : 
    6375             :   // Get the name
    6376           0 :   nsAutoString name;
    6377           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    6378             : 
    6379             :   // Submit .x, .y for input type=image
    6380           0 :   if (mType == NS_FORM_INPUT_IMAGE) {
    6381             :     // Get a property set by the frame to find out where it was clicked.
    6382             :     nsIntPoint* lastClickedPoint =
    6383           0 :       static_cast<nsIntPoint*>(GetProperty(nsGkAtoms::imageClickedPoint));
    6384             :     int32_t x, y;
    6385           0 :     if (lastClickedPoint) {
    6386             :       // Convert the values to strings for submission
    6387           0 :       x = lastClickedPoint->x;
    6388           0 :       y = lastClickedPoint->y;
    6389             :     } else {
    6390           0 :       x = y = 0;
    6391             :     }
    6392             : 
    6393           0 :     nsAutoString xVal, yVal;
    6394           0 :     xVal.AppendInt(x);
    6395           0 :     yVal.AppendInt(y);
    6396             : 
    6397           0 :     if (!name.IsEmpty()) {
    6398           0 :       aFormSubmission->AddNameValuePair(name + NS_LITERAL_STRING(".x"), xVal);
    6399           0 :       aFormSubmission->AddNameValuePair(name + NS_LITERAL_STRING(".y"), yVal);
    6400             :     } else {
    6401             :       // If the Image Element has no name, simply return x and y
    6402             :       // to Nav and IE compatibility.
    6403           0 :       aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("x"), xVal);
    6404           0 :       aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("y"), yVal);
    6405             :     }
    6406             : 
    6407           0 :     return NS_OK;
    6408             :   }
    6409             : 
    6410             :   // If name not there, don't submit
    6411           0 :   if (name.IsEmpty()) {
    6412           0 :     return NS_OK;
    6413             :   }
    6414             : 
    6415             :   //
    6416             :   // Submit file if its input type=file and this encoding method accepts files
    6417             :   //
    6418           0 :   if (mType == NS_FORM_INPUT_FILE) {
    6419             :     // Submit files
    6420             : 
    6421             :     const nsTArray<OwningFileOrDirectory>& files =
    6422           0 :       GetFilesOrDirectoriesInternal();
    6423             : 
    6424           0 :     if (files.IsEmpty()) {
    6425           0 :       aFormSubmission->AddNameBlobOrNullPair(name, nullptr);
    6426           0 :       return NS_OK;
    6427             :     }
    6428             : 
    6429           0 :     for (uint32_t i = 0; i < files.Length(); ++i) {
    6430           0 :       if (files[i].IsFile()) {
    6431           0 :         aFormSubmission->AddNameBlobOrNullPair(name, files[i].GetAsFile());
    6432             :       } else {
    6433           0 :         MOZ_ASSERT(files[i].IsDirectory());
    6434           0 :         aFormSubmission->AddNameDirectoryPair(name, files[i].GetAsDirectory());
    6435             :       }
    6436             :     }
    6437             : 
    6438           0 :     return NS_OK;
    6439             :   }
    6440             : 
    6441           0 :   if (mType == NS_FORM_INPUT_HIDDEN && name.EqualsLiteral("_charset_")) {
    6442           0 :     nsCString charset;
    6443           0 :     aFormSubmission->GetCharset(charset);
    6444             :     return aFormSubmission->AddNameValuePair(name,
    6445           0 :                                              NS_ConvertASCIItoUTF16(charset));
    6446             :   }
    6447             : 
    6448             :   //
    6449             :   // Submit name=value
    6450             :   //
    6451             : 
    6452             :   // Get the value
    6453           0 :   nsAutoString value;
    6454           0 :   GetValue(value, CallerType::System);
    6455             : 
    6456           0 :   if (mType == NS_FORM_INPUT_SUBMIT && value.IsEmpty() &&
    6457           0 :       !HasAttr(kNameSpaceID_None, nsGkAtoms::value)) {
    6458             :     // Get our default value, which is the same as our default label
    6459           0 :     nsXPIDLString defaultValue;
    6460             :     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
    6461           0 :                                        "Submit", defaultValue);
    6462           0 :     value = defaultValue;
    6463             :   }
    6464             : 
    6465           0 :   if (IsSingleLineTextControl(true) &&
    6466           0 :       name.EqualsLiteral("isindex") &&
    6467           0 :       aFormSubmission->SupportsIsindexSubmission()) {
    6468           0 :     return aFormSubmission->AddIsindex(value);
    6469             :   }
    6470           0 :   return aFormSubmission->AddNameValuePair(name, value);
    6471             : }
    6472             : 
    6473             : 
    6474             : NS_IMETHODIMP
    6475           2 : HTMLInputElement::SaveState()
    6476             : {
    6477           4 :   RefPtr<HTMLInputElementState> inputState;
    6478           2 :   switch (GetValueMode()) {
    6479             :     case VALUE_MODE_DEFAULT_ON:
    6480           0 :       if (mCheckedChanged) {
    6481           0 :         inputState = new HTMLInputElementState();
    6482           0 :         inputState->SetChecked(mChecked);
    6483             :       }
    6484           2 :       break;
    6485             :     case VALUE_MODE_FILENAME:
    6486           0 :       if (!mFileData->mFilesOrDirectories.IsEmpty()) {
    6487           0 :         inputState = new HTMLInputElementState();
    6488           0 :         inputState->SetFilesOrDirectories(mFileData->mFilesOrDirectories);
    6489             :       }
    6490           0 :       break;
    6491             :     case VALUE_MODE_VALUE:
    6492             :     case VALUE_MODE_DEFAULT:
    6493             :       // VALUE_MODE_DEFAULT shouldn't have their value saved except 'hidden',
    6494             :       // mType shouldn't be NS_FORM_INPUT_PASSWORD and value should have changed.
    6495           4 :       if ((GetValueMode() == VALUE_MODE_DEFAULT &&
    6496           2 :            mType != NS_FORM_INPUT_HIDDEN) ||
    6497           6 :           mType == NS_FORM_INPUT_PASSWORD || !mValueChanged) {
    6498           2 :         break;
    6499             :       }
    6500             : 
    6501           0 :       inputState = new HTMLInputElementState();
    6502           0 :       nsAutoString value;
    6503           0 :       GetValue(value, CallerType::System);
    6504             : 
    6505           0 :       if (!IsSingleLineTextControl(false)) {
    6506             :         nsresult rv = nsLinebreakConverter::ConvertStringLineBreaks(
    6507             :                value,
    6508             :                nsLinebreakConverter::eLinebreakPlatform,
    6509           0 :                nsLinebreakConverter::eLinebreakContent);
    6510             : 
    6511           0 :         if (NS_FAILED(rv)) {
    6512           0 :           NS_ERROR("Converting linebreaks failed!");
    6513           0 :           return rv;
    6514             :         }
    6515             :       }
    6516             : 
    6517           0 :       inputState->SetValue(value);
    6518           0 :       break;
    6519             :   }
    6520             : 
    6521           2 :   if (inputState) {
    6522           0 :     nsPresState* state = GetPrimaryPresState();
    6523           0 :     if (state) {
    6524           0 :       state->SetStateProperty(inputState);
    6525             :     }
    6526             :   }
    6527             : 
    6528           2 :   if (mDisabledChanged) {
    6529           0 :     nsPresState* state = GetPrimaryPresState();
    6530           0 :     if (state) {
    6531             :       // We do not want to save the real disabled state but the disabled
    6532             :       // attribute.
    6533           0 :       state->SetDisabled(HasAttr(kNameSpaceID_None, nsGkAtoms::disabled));
    6534             :     }
    6535             :   }
    6536             : 
    6537           2 :   return NS_OK;
    6538             : }
    6539             : 
    6540             : void
    6541           2 : HTMLInputElement::DoneCreatingElement()
    6542             : {
    6543           2 :   mDoneCreating = true;
    6544             : 
    6545             :   //
    6546             :   // Restore state as needed.  Note that disabled state applies to all control
    6547             :   // types.
    6548             :   //
    6549             :   bool restoredCheckedState =
    6550           2 :     !mInhibitRestoration && NS_SUCCEEDED(GenerateStateKey()) && RestoreFormControlState();
    6551             : 
    6552             :   //
    6553             :   // If restore does not occur, we initialize .checked using the CHECKED
    6554             :   // property.
    6555             :   //
    6556           2 :   if (!restoredCheckedState && mShouldInitChecked) {
    6557           0 :     DoSetChecked(DefaultChecked(), false, false);
    6558             :   }
    6559             : 
    6560             :   // Sanitize the value.
    6561           2 :   if (GetValueMode() == VALUE_MODE_VALUE) {
    6562           4 :     nsAutoString aValue;
    6563           2 :     GetValue(aValue, CallerType::System);
    6564             :     // TODO: What should we do if SetValueInternal fails?  (The allocation
    6565             :     // may potentially be big, but most likely we've failed to allocate
    6566             :     // before the type change.)
    6567           2 :     SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
    6568             :   }
    6569             : 
    6570           2 :   mShouldInitChecked = false;
    6571           2 : }
    6572             : 
    6573             : EventStates
    6574          60 : HTMLInputElement::IntrinsicState() const
    6575             : {
    6576             :   // If you add states here, and they're type-dependent, you need to add them
    6577             :   // to the type case in AfterSetAttr.
    6578             : 
    6579          60 :   EventStates state = nsGenericHTMLFormElementWithState::IntrinsicState();
    6580          60 :   if (mType == NS_FORM_INPUT_CHECKBOX || mType == NS_FORM_INPUT_RADIO) {
    6581             :     // Check current checked state (:checked)
    6582           0 :     if (mChecked) {
    6583           0 :       state |= NS_EVENT_STATE_CHECKED;
    6584             :     }
    6585             : 
    6586             :     // Check current indeterminate state (:indeterminate)
    6587           0 :     if (mType == NS_FORM_INPUT_CHECKBOX && mIndeterminate) {
    6588           0 :       state |= NS_EVENT_STATE_INDETERMINATE;
    6589             :     }
    6590             : 
    6591           0 :     if (mType == NS_FORM_INPUT_RADIO) {
    6592           0 :       nsCOMPtr<nsIDOMHTMLInputElement> selected = GetSelectedRadioButton();
    6593           0 :       bool indeterminate = !selected && !mChecked;
    6594             : 
    6595           0 :       if (indeterminate) {
    6596           0 :         state |= NS_EVENT_STATE_INDETERMINATE;
    6597             :       }
    6598             :     }
    6599             : 
    6600             :     // Check whether we are the default checked element (:default)
    6601           0 :     if (DefaultChecked()) {
    6602           0 :       state |= NS_EVENT_STATE_DEFAULT;
    6603           0 :     }
    6604          60 :   } else if (mType == NS_FORM_INPUT_IMAGE) {
    6605           0 :     state |= nsImageLoadingContent::ImageState();
    6606             :   }
    6607             : 
    6608          60 :   if (DoesRequiredApply() && HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
    6609           0 :     state |= NS_EVENT_STATE_REQUIRED;
    6610             :   } else {
    6611          60 :     state |= NS_EVENT_STATE_OPTIONAL;
    6612             :   }
    6613             : 
    6614          60 :   if (IsCandidateForConstraintValidation()) {
    6615          60 :     if (IsValid()) {
    6616          60 :       state |= NS_EVENT_STATE_VALID;
    6617             :     } else {
    6618           0 :       state |= NS_EVENT_STATE_INVALID;
    6619             : 
    6620           0 :       if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
    6621           0 :           (GetValidityState(VALIDITY_STATE_CUSTOM_ERROR) ||
    6622           0 :            (mCanShowInvalidUI && ShouldShowValidityUI()))) {
    6623           0 :         state |= NS_EVENT_STATE_MOZ_UI_INVALID;
    6624             :       }
    6625             :     }
    6626             : 
    6627             :     // :-moz-ui-valid applies if all of the following conditions are true:
    6628             :     // 1. The element is not focused, or had either :-moz-ui-valid or
    6629             :     //    :-moz-ui-invalid applying before it was focused ;
    6630             :     // 2. The element is either valid or isn't allowed to have
    6631             :     //    :-moz-ui-invalid applying ;
    6632             :     // 3. The element has no form owner or its form owner doesn't have the
    6633             :     //    novalidate attribute set ;
    6634             :     // 4. The element has already been modified or the user tried to submit the
    6635             :     //    form owner while invalid.
    6636         243 :     if ((!mForm || !mForm->HasAttr(kNameSpaceID_None, nsGkAtoms::novalidate)) &&
    6637         123 :         (mCanShowValidUI && ShouldShowValidityUI() &&
    6638          63 :          (IsValid() || (!state.HasState(NS_EVENT_STATE_MOZ_UI_INVALID) &&
    6639           0 :                         !mCanShowInvalidUI)))) {
    6640           3 :       state |= NS_EVENT_STATE_MOZ_UI_VALID;
    6641             :     }
    6642             : 
    6643             :     // :in-range and :out-of-range only apply if the element currently has a range
    6644          60 :     if (mHasRange) {
    6645           0 :       state |= (GetValidityState(VALIDITY_STATE_RANGE_OVERFLOW) ||
    6646           0 :                 GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW))
    6647           0 :                  ? NS_EVENT_STATE_OUTOFRANGE
    6648           0 :                  : NS_EVENT_STATE_INRANGE;
    6649             :     }
    6650             :   }
    6651             : 
    6652         180 :   if (PlaceholderApplies() &&
    6653          67 :       HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder) &&
    6654           7 :       IsValueEmpty()) {
    6655           5 :     state |= NS_EVENT_STATE_PLACEHOLDERSHOWN;
    6656             :   }
    6657             : 
    6658          60 :   if (mForm && !mForm->GetValidity() && IsSubmitControl()) {
    6659           0 :     state |= NS_EVENT_STATE_MOZ_SUBMITINVALID;
    6660             :   }
    6661             : 
    6662          60 :   return state;
    6663             : }
    6664             : 
    6665             : void
    6666           0 : HTMLInputElement::AddStates(EventStates aStates)
    6667             : {
    6668           0 :   if (mType == NS_FORM_INPUT_TEXT) {
    6669           0 :     EventStates focusStates(aStates & (NS_EVENT_STATE_FOCUS |
    6670           0 :                                        NS_EVENT_STATE_FOCUSRING));
    6671           0 :     if (!focusStates.IsEmpty()) {
    6672           0 :       HTMLInputElement* ownerNumberControl = GetOwnerNumberControl();
    6673           0 :       if (ownerNumberControl) {
    6674           0 :         ownerNumberControl->AddStates(focusStates);
    6675             :       }
    6676             :     }
    6677             :   }
    6678           0 :   nsGenericHTMLFormElementWithState::AddStates(aStates);
    6679           0 : }
    6680             : 
    6681             : void
    6682           0 : HTMLInputElement::RemoveStates(EventStates aStates)
    6683             : {
    6684           0 :   if (mType == NS_FORM_INPUT_TEXT) {
    6685           0 :     EventStates focusStates(aStates & (NS_EVENT_STATE_FOCUS |
    6686           0 :                                        NS_EVENT_STATE_FOCUSRING));
    6687           0 :     if (!focusStates.IsEmpty()) {
    6688           0 :       HTMLInputElement* ownerNumberControl = GetOwnerNumberControl();
    6689           0 :       if (ownerNumberControl) {
    6690           0 :         ownerNumberControl->RemoveStates(focusStates);
    6691             :       }
    6692             :     }
    6693             :   }
    6694           0 :   nsGenericHTMLFormElementWithState::RemoveStates(aStates);
    6695           0 : }
    6696             : 
    6697             : bool
    6698           0 : HTMLInputElement::RestoreState(nsPresState* aState)
    6699             : {
    6700           0 :   bool restoredCheckedState = false;
    6701             : 
    6702             :   nsCOMPtr<HTMLInputElementState> inputState
    6703           0 :     (do_QueryInterface(aState->GetStateProperty()));
    6704             : 
    6705           0 :   if (inputState) {
    6706           0 :     switch (GetValueMode()) {
    6707             :       case VALUE_MODE_DEFAULT_ON:
    6708           0 :         if (inputState->IsCheckedSet()) {
    6709           0 :           restoredCheckedState = true;
    6710           0 :           DoSetChecked(inputState->GetChecked(), true, true);
    6711             :         }
    6712           0 :         break;
    6713             :       case VALUE_MODE_FILENAME:
    6714             :         {
    6715           0 :           nsPIDOMWindowInner* window = OwnerDoc()->GetInnerWindow();
    6716           0 :           if (window) {
    6717           0 :             nsTArray<OwningFileOrDirectory> array;
    6718           0 :             inputState->GetFilesOrDirectories(window, array);
    6719             : 
    6720           0 :             SetFilesOrDirectories(array, true);
    6721             :           }
    6722             :         }
    6723           0 :         break;
    6724             :       case VALUE_MODE_VALUE:
    6725             :       case VALUE_MODE_DEFAULT:
    6726           0 :         if (GetValueMode() == VALUE_MODE_DEFAULT &&
    6727           0 :             mType != NS_FORM_INPUT_HIDDEN) {
    6728           0 :           break;
    6729             :         }
    6730             : 
    6731             :         // TODO: What should we do if SetValueInternal fails?  (The allocation
    6732             :         // may potentially be big, but most likely we've failed to allocate
    6733             :         // before the type change.)
    6734           0 :         SetValueInternal(inputState->GetValue(),
    6735           0 :                          nsTextEditorState::eSetValue_Notify);
    6736           0 :         break;
    6737             :     }
    6738             :   }
    6739             : 
    6740           0 :   if (aState->IsDisabledSet() && !aState->GetDisabled()) {
    6741           0 :     SetDisabled(false);
    6742             :   }
    6743             : 
    6744           0 :   return restoredCheckedState;
    6745             : }
    6746             : 
    6747             : bool
    6748           0 : HTMLInputElement::AllowDrop()
    6749             : {
    6750             :   // Allow drop on anything other than file inputs.
    6751             : 
    6752           0 :   return mType != NS_FORM_INPUT_FILE;
    6753             : }
    6754             : 
    6755             : /*
    6756             :  * Radio group stuff
    6757             :  */
    6758             : 
    6759             : void
    6760           0 : HTMLInputElement::AddedToRadioGroup()
    6761             : {
    6762             :   // If the element is neither in a form nor a document, there is no group so we
    6763             :   // should just stop here.
    6764           0 :   if (!mForm && !IsInUncomposedDoc()) {
    6765           0 :     return;
    6766             :   }
    6767             : 
    6768             :   // Make sure not to notify if we're still being created
    6769           0 :   bool notify = mDoneCreating;
    6770             : 
    6771             :   //
    6772             :   // If the input element is checked, and we add it to the group, it will
    6773             :   // deselect whatever is currently selected in that group
    6774             :   //
    6775           0 :   if (mChecked) {
    6776             :     //
    6777             :     // If it is checked, call "RadioSetChecked" to perform the selection/
    6778             :     // deselection ritual.  This has the side effect of repainting the
    6779             :     // radio button, but as adding a checked radio button into the group
    6780             :     // should not be that common an occurrence, I think we can live with
    6781             :     // that.
    6782             :     //
    6783           0 :     RadioSetChecked(notify);
    6784             :   }
    6785             : 
    6786             :   //
    6787             :   // For integrity purposes, we have to ensure that "checkedChanged" is
    6788             :   // the same for this new element as for all the others in the group
    6789             :   //
    6790           0 :   bool checkedChanged = mCheckedChanged;
    6791             : 
    6792             :   nsCOMPtr<nsIRadioVisitor> visitor =
    6793           0 :     new nsRadioGetCheckedChangedVisitor(&checkedChanged, this);
    6794           0 :   VisitGroup(visitor, notify);
    6795             : 
    6796           0 :   SetCheckedChangedInternal(checkedChanged);
    6797             : 
    6798             :   //
    6799             :   // Add the radio to the radio group container.
    6800             :   //
    6801           0 :   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
    6802           0 :   if (container) {
    6803           0 :     nsAutoString name;
    6804           0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    6805           0 :     container->AddToRadioGroup(name, static_cast<nsIFormControl*>(this));
    6806             : 
    6807             :     // We initialize the validity of the element to the validity of the group
    6808             :     // because we assume UpdateValueMissingState() will be called after.
    6809           0 :     SetValidityState(VALIDITY_STATE_VALUE_MISSING,
    6810           0 :                      container->GetValueMissingState(name));
    6811             :   }
    6812             : }
    6813             : 
    6814             : void
    6815           0 : HTMLInputElement::WillRemoveFromRadioGroup()
    6816             : {
    6817           0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
    6818           0 :   if (!container) {
    6819           0 :     return;
    6820             :   }
    6821             : 
    6822           0 :   nsAutoString name;
    6823           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    6824             : 
    6825             :   // If this button was checked, we need to notify the group that there is no
    6826             :   // longer a selected radio button
    6827           0 :   if (mChecked) {
    6828           0 :     container->SetCurrentRadioButton(name, nullptr);
    6829             : 
    6830           0 :     nsCOMPtr<nsIRadioVisitor> visitor = new nsRadioUpdateStateVisitor(this);
    6831           0 :     VisitGroup(visitor, true);
    6832             :   }
    6833             : 
    6834             :   // Remove this radio from its group in the container.
    6835             :   // We need to call UpdateValueMissingValidityStateForRadio before to make sure
    6836             :   // the group validity is updated (with this element being ignored).
    6837           0 :   UpdateValueMissingValidityStateForRadio(true);
    6838           0 :   container->RemoveFromRadioGroup(name, static_cast<nsIFormControl*>(this));
    6839             : }
    6840             : 
    6841             : bool
    6842           0 : HTMLInputElement::IsHTMLFocusable(bool aWithMouse, bool* aIsFocusable, int32_t* aTabIndex)
    6843             : {
    6844           0 :   if (nsGenericHTMLFormElementWithState::IsHTMLFocusable(aWithMouse, aIsFocusable,
    6845             :       aTabIndex))
    6846             :   {
    6847           0 :     return true;
    6848             :   }
    6849             : 
    6850           0 :   if (IsDisabled()) {
    6851           0 :     *aIsFocusable = false;
    6852           0 :     return true;
    6853             :   }
    6854             : 
    6855           0 :   if (IsSingleLineTextControl(false) ||
    6856           0 :       mType == NS_FORM_INPUT_RANGE) {
    6857           0 :     *aIsFocusable = true;
    6858           0 :     return false;
    6859             :   }
    6860             : 
    6861             : #ifdef XP_MACOSX
    6862             :   const bool defaultFocusable = !aWithMouse || nsFocusManager::sMouseFocusesFormControl;
    6863             : #else
    6864           0 :   const bool defaultFocusable = true;
    6865             : #endif
    6866             : 
    6867           0 :   if (mType == NS_FORM_INPUT_FILE ||
    6868           0 :       mType == NS_FORM_INPUT_NUMBER ||
    6869           0 :       mType == NS_FORM_INPUT_TIME ||
    6870           0 :       mType == NS_FORM_INPUT_DATE) {
    6871           0 :     if (aTabIndex) {
    6872             :       // We only want our native anonymous child to be tabable to, not ourself.
    6873           0 :       *aTabIndex = -1;
    6874             :     }
    6875           0 :     if (mType == NS_FORM_INPUT_NUMBER ||
    6876           0 :         mType == NS_FORM_INPUT_TIME ||
    6877           0 :         mType == NS_FORM_INPUT_DATE) {
    6878           0 :       *aIsFocusable = true;
    6879             :     } else {
    6880           0 :       *aIsFocusable = defaultFocusable;
    6881             :     }
    6882           0 :     return true;
    6883             :   }
    6884             : 
    6885           0 :   if (mType == NS_FORM_INPUT_HIDDEN) {
    6886           0 :     if (aTabIndex) {
    6887           0 :       *aTabIndex = -1;
    6888             :     }
    6889           0 :     *aIsFocusable = false;
    6890           0 :     return false;
    6891             :   }
    6892             : 
    6893           0 :   if (!aTabIndex) {
    6894             :     // The other controls are all focusable
    6895           0 :     *aIsFocusable = defaultFocusable;
    6896           0 :     return false;
    6897             :   }
    6898             : 
    6899           0 :   if (mType != NS_FORM_INPUT_RADIO) {
    6900           0 :     *aIsFocusable = defaultFocusable;
    6901           0 :     return false;
    6902             :   }
    6903             : 
    6904           0 :   if (mChecked) {
    6905             :     // Selected radio buttons are tabbable
    6906           0 :     *aIsFocusable = defaultFocusable;
    6907           0 :     return false;
    6908             :   }
    6909             : 
    6910             :   // Current radio button is not selected.
    6911             :   // But make it tabbable if nothing in group is selected.
    6912           0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
    6913           0 :   if (!container) {
    6914           0 :     *aIsFocusable = defaultFocusable;
    6915           0 :     return false;
    6916             :   }
    6917             : 
    6918           0 :   nsAutoString name;
    6919           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    6920             : 
    6921           0 :   if (container->GetCurrentRadioButton(name)) {
    6922           0 :     *aTabIndex = -1;
    6923             :   }
    6924           0 :   *aIsFocusable = defaultFocusable;
    6925           0 :   return false;
    6926             : }
    6927             : 
    6928             : nsresult
    6929           0 : HTMLInputElement::VisitGroup(nsIRadioVisitor* aVisitor, bool aFlushContent)
    6930             : {
    6931           0 :   nsIRadioGroupContainer* container = GetRadioGroupContainer();
    6932           0 :   if (container) {
    6933           0 :     nsAutoString name;
    6934           0 :     GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    6935           0 :     return container->WalkRadioGroup(name, aVisitor, aFlushContent);
    6936             :   }
    6937             : 
    6938           0 :   aVisitor->Visit(this);
    6939           0 :   return NS_OK;
    6940             : }
    6941             : 
    6942             : HTMLInputElement::ValueModeType
    6943          90 : HTMLInputElement::GetValueMode() const
    6944             : {
    6945          90 :   switch (mType)
    6946             :   {
    6947             :     case NS_FORM_INPUT_HIDDEN:
    6948             :     case NS_FORM_INPUT_SUBMIT:
    6949             :     case NS_FORM_INPUT_BUTTON:
    6950             :     case NS_FORM_INPUT_RESET:
    6951             :     case NS_FORM_INPUT_IMAGE:
    6952           0 :       return VALUE_MODE_DEFAULT;
    6953             :     case NS_FORM_INPUT_CHECKBOX:
    6954             :     case NS_FORM_INPUT_RADIO:
    6955           0 :       return VALUE_MODE_DEFAULT_ON;
    6956             :     case NS_FORM_INPUT_FILE:
    6957           0 :       return VALUE_MODE_FILENAME;
    6958             : #ifdef DEBUG
    6959             :     case NS_FORM_INPUT_TEXT:
    6960             :     case NS_FORM_INPUT_PASSWORD:
    6961             :     case NS_FORM_INPUT_SEARCH:
    6962             :     case NS_FORM_INPUT_TEL:
    6963             :     case NS_FORM_INPUT_EMAIL:
    6964             :     case NS_FORM_INPUT_URL:
    6965             :     case NS_FORM_INPUT_NUMBER:
    6966             :     case NS_FORM_INPUT_RANGE:
    6967             :     case NS_FORM_INPUT_DATE:
    6968             :     case NS_FORM_INPUT_TIME:
    6969             :     case NS_FORM_INPUT_COLOR:
    6970             :     case NS_FORM_INPUT_MONTH:
    6971             :     case NS_FORM_INPUT_WEEK:
    6972             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    6973          90 :       return VALUE_MODE_VALUE;
    6974             :     default:
    6975           0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in GetValueMode()");
    6976           0 :       return VALUE_MODE_VALUE;
    6977             : #else // DEBUG
    6978             :     default:
    6979             :       return VALUE_MODE_VALUE;
    6980             : #endif // DEBUG
    6981             :   }
    6982             : }
    6983             : 
    6984             : bool
    6985           0 : HTMLInputElement::IsMutable() const
    6986             : {
    6987           0 :   return !IsDisabled() &&
    6988           0 :          !(DoesReadOnlyApply() &&
    6989           0 :            HasAttr(kNameSpaceID_None, nsGkAtoms::readonly));
    6990             : }
    6991             : 
    6992             : bool
    6993           0 : HTMLInputElement::DoesReadOnlyApply() const
    6994             : {
    6995           0 :   switch (mType)
    6996             :   {
    6997             :     case NS_FORM_INPUT_HIDDEN:
    6998             :     case NS_FORM_INPUT_BUTTON:
    6999             :     case NS_FORM_INPUT_IMAGE:
    7000             :     case NS_FORM_INPUT_RESET:
    7001             :     case NS_FORM_INPUT_SUBMIT:
    7002             :     case NS_FORM_INPUT_RADIO:
    7003             :     case NS_FORM_INPUT_FILE:
    7004             :     case NS_FORM_INPUT_CHECKBOX:
    7005             :     case NS_FORM_INPUT_RANGE:
    7006             :     case NS_FORM_INPUT_COLOR:
    7007           0 :       return false;
    7008             : #ifdef DEBUG
    7009             :     case NS_FORM_INPUT_TEXT:
    7010             :     case NS_FORM_INPUT_PASSWORD:
    7011             :     case NS_FORM_INPUT_SEARCH:
    7012             :     case NS_FORM_INPUT_TEL:
    7013             :     case NS_FORM_INPUT_EMAIL:
    7014             :     case NS_FORM_INPUT_URL:
    7015             :     case NS_FORM_INPUT_NUMBER:
    7016             :     case NS_FORM_INPUT_DATE:
    7017             :     case NS_FORM_INPUT_TIME:
    7018             :     case NS_FORM_INPUT_MONTH:
    7019             :     case NS_FORM_INPUT_WEEK:
    7020             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    7021           0 :       return true;
    7022             :     default:
    7023           0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesReadOnlyApply()");
    7024           0 :       return true;
    7025             : #else // DEBUG
    7026             :     default:
    7027             :       return true;
    7028             : #endif // DEBUG
    7029             :   }
    7030             : }
    7031             : 
    7032             : bool
    7033          60 : HTMLInputElement::DoesRequiredApply() const
    7034             : {
    7035          60 :   switch (mType)
    7036             :   {
    7037             :     case NS_FORM_INPUT_HIDDEN:
    7038             :     case NS_FORM_INPUT_BUTTON:
    7039             :     case NS_FORM_INPUT_IMAGE:
    7040             :     case NS_FORM_INPUT_RESET:
    7041             :     case NS_FORM_INPUT_SUBMIT:
    7042             :     case NS_FORM_INPUT_RANGE:
    7043             :     case NS_FORM_INPUT_COLOR:
    7044           0 :       return false;
    7045             : #ifdef DEBUG
    7046             :     case NS_FORM_INPUT_RADIO:
    7047             :     case NS_FORM_INPUT_CHECKBOX:
    7048             :     case NS_FORM_INPUT_FILE:
    7049             :     case NS_FORM_INPUT_TEXT:
    7050             :     case NS_FORM_INPUT_PASSWORD:
    7051             :     case NS_FORM_INPUT_SEARCH:
    7052             :     case NS_FORM_INPUT_TEL:
    7053             :     case NS_FORM_INPUT_EMAIL:
    7054             :     case NS_FORM_INPUT_URL:
    7055             :     case NS_FORM_INPUT_NUMBER:
    7056             :     case NS_FORM_INPUT_DATE:
    7057             :     case NS_FORM_INPUT_TIME:
    7058             :     case NS_FORM_INPUT_MONTH:
    7059             :     case NS_FORM_INPUT_WEEK:
    7060             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    7061          60 :       return true;
    7062             :     default:
    7063           0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
    7064           0 :       return true;
    7065             : #else // DEBUG
    7066             :     default:
    7067             :       return true;
    7068             : #endif // DEBUG
    7069             :   }
    7070             : }
    7071             : 
    7072             : bool
    7073          70 : HTMLInputElement::PlaceholderApplies() const
    7074             : {
    7075          70 :   if (IsDateTimeInputType(mType)) {
    7076           0 :     return false;
    7077             :   }
    7078             : 
    7079          70 :   return IsSingleLineTextControl(false);
    7080             : }
    7081             : 
    7082             : bool
    7083           1 : HTMLInputElement::DoesMinMaxApply() const
    7084             : {
    7085           1 :   switch (mType)
    7086             :   {
    7087             :     case NS_FORM_INPUT_NUMBER:
    7088             :     case NS_FORM_INPUT_DATE:
    7089             :     case NS_FORM_INPUT_TIME:
    7090             :     case NS_FORM_INPUT_RANGE:
    7091             :     case NS_FORM_INPUT_MONTH:
    7092             :     case NS_FORM_INPUT_WEEK:
    7093             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    7094           0 :       return true;
    7095             : #ifdef DEBUG
    7096             :     case NS_FORM_INPUT_RESET:
    7097             :     case NS_FORM_INPUT_SUBMIT:
    7098             :     case NS_FORM_INPUT_IMAGE:
    7099             :     case NS_FORM_INPUT_BUTTON:
    7100             :     case NS_FORM_INPUT_HIDDEN:
    7101             :     case NS_FORM_INPUT_RADIO:
    7102             :     case NS_FORM_INPUT_CHECKBOX:
    7103             :     case NS_FORM_INPUT_FILE:
    7104             :     case NS_FORM_INPUT_TEXT:
    7105             :     case NS_FORM_INPUT_PASSWORD:
    7106             :     case NS_FORM_INPUT_SEARCH:
    7107             :     case NS_FORM_INPUT_TEL:
    7108             :     case NS_FORM_INPUT_EMAIL:
    7109             :     case NS_FORM_INPUT_URL:
    7110             :     case NS_FORM_INPUT_COLOR:
    7111           1 :       return false;
    7112             :     default:
    7113           0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesRequiredApply()");
    7114           0 :       return false;
    7115             : #else // DEBUG
    7116             :     default:
    7117             :       return false;
    7118             : #endif // DEBUG
    7119             :   }
    7120             : }
    7121             : 
    7122             : bool
    7123           0 : HTMLInputElement::DoesAutocompleteApply() const
    7124             : {
    7125           0 :   switch (mType)
    7126             :   {
    7127             :     case NS_FORM_INPUT_HIDDEN:
    7128             :     case NS_FORM_INPUT_TEXT:
    7129             :     case NS_FORM_INPUT_SEARCH:
    7130             :     case NS_FORM_INPUT_URL:
    7131             :     case NS_FORM_INPUT_TEL:
    7132             :     case NS_FORM_INPUT_EMAIL:
    7133             :     case NS_FORM_INPUT_PASSWORD:
    7134             :     case NS_FORM_INPUT_DATE:
    7135             :     case NS_FORM_INPUT_TIME:
    7136             :     case NS_FORM_INPUT_NUMBER:
    7137             :     case NS_FORM_INPUT_RANGE:
    7138             :     case NS_FORM_INPUT_COLOR:
    7139             :     case NS_FORM_INPUT_MONTH:
    7140             :     case NS_FORM_INPUT_WEEK:
    7141             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    7142           0 :       return true;
    7143             : #ifdef DEBUG
    7144             :     case NS_FORM_INPUT_RESET:
    7145             :     case NS_FORM_INPUT_SUBMIT:
    7146             :     case NS_FORM_INPUT_IMAGE:
    7147             :     case NS_FORM_INPUT_BUTTON:
    7148             :     case NS_FORM_INPUT_RADIO:
    7149             :     case NS_FORM_INPUT_CHECKBOX:
    7150             :     case NS_FORM_INPUT_FILE:
    7151           0 :       return false;
    7152             :     default:
    7153           0 :       NS_NOTYETIMPLEMENTED("Unexpected input type in DoesAutocompleteApply()");
    7154           0 :       return false;
    7155             : #else // DEBUG
    7156             :     default:
    7157             :       return false;
    7158             : #endif // DEBUG
    7159             :   }
    7160             : }
    7161             : 
    7162             : Decimal
    7163           0 : HTMLInputElement::GetStep() const
    7164             : {
    7165           0 :   MOZ_ASSERT(DoesStepApply(), "GetStep() can only be called if @step applies");
    7166             : 
    7167           0 :   if (!HasAttr(kNameSpaceID_None, nsGkAtoms::step)) {
    7168           0 :     return GetDefaultStep() * GetStepScaleFactor();
    7169             :   }
    7170             : 
    7171           0 :   nsAutoString stepStr;
    7172           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::step, stepStr);
    7173             : 
    7174           0 :   if (stepStr.LowerCaseEqualsLiteral("any")) {
    7175             :     // The element can't suffer from step mismatch if there is no step.
    7176           0 :     return kStepAny;
    7177             :   }
    7178             : 
    7179           0 :   Decimal step = StringToDecimal(stepStr);
    7180           0 :   if (!step.isFinite() || step <= Decimal(0)) {
    7181           0 :     step = GetDefaultStep();
    7182             :   }
    7183             : 
    7184             :   // For input type=date, we round the step value to have a rounded day.
    7185           0 :   if (mType == NS_FORM_INPUT_DATE || mType == NS_FORM_INPUT_MONTH ||
    7186           0 :       mType == NS_FORM_INPUT_WEEK) {
    7187           0 :     step = std::max(step.round(), Decimal(1));
    7188             :   }
    7189             : 
    7190           0 :   return step * GetStepScaleFactor();
    7191             : }
    7192             : 
    7193             : // nsIConstraintValidation
    7194             : 
    7195             : NS_IMETHODIMP
    7196           0 : HTMLInputElement::SetCustomValidity(const nsAString& aError)
    7197             : {
    7198           0 :   nsIConstraintValidation::SetCustomValidity(aError);
    7199             : 
    7200           0 :   UpdateState(true);
    7201             : 
    7202           0 :   return NS_OK;
    7203             : }
    7204             : 
    7205             : bool
    7206           7 : HTMLInputElement::IsTooLong()
    7207             : {
    7208           8 :   if (!mValueChanged ||
    7209           1 :       !mLastValueChangeWasInteractive) {
    7210           7 :     return false;
    7211             :   }
    7212             : 
    7213           0 :   return mInputType->IsTooLong();
    7214             : }
    7215             : 
    7216             : bool
    7217           7 : HTMLInputElement::IsTooShort()
    7218             : {
    7219           8 :   if (!mValueChanged ||
    7220           1 :       !mLastValueChangeWasInteractive) {
    7221           7 :     return false;
    7222             :   }
    7223             : 
    7224           0 :   return mInputType->IsTooShort();
    7225             : }
    7226             : 
    7227             : bool
    7228          30 : HTMLInputElement::IsValueMissing() const
    7229             : {
    7230             :   // Should use UpdateValueMissingValidityStateForRadio() for type radio.
    7231          30 :   MOZ_ASSERT(mType != NS_FORM_INPUT_RADIO);
    7232             : 
    7233          30 :   return mInputType->IsValueMissing();
    7234             : }
    7235             : 
    7236             : bool
    7237           7 : HTMLInputElement::HasTypeMismatch() const
    7238             : {
    7239           7 :   return mInputType->HasTypeMismatch();
    7240             : }
    7241             : 
    7242             : bool
    7243           7 : HTMLInputElement::HasPatternMismatch() const
    7244             : {
    7245           7 :   return mInputType->HasPatternMismatch();
    7246             : }
    7247             : 
    7248             : bool
    7249           7 : HTMLInputElement::IsRangeOverflow() const
    7250             : {
    7251           7 :   return mInputType->IsRangeOverflow();
    7252             : }
    7253             : 
    7254             : bool
    7255           7 : HTMLInputElement::IsRangeUnderflow() const
    7256             : {
    7257           7 :   return mInputType->IsRangeUnderflow();
    7258             : }
    7259             : 
    7260             : bool
    7261           7 : HTMLInputElement::HasStepMismatch(bool aUseZeroIfValueNaN) const
    7262             : {
    7263           7 :   return mInputType->HasStepMismatch(aUseZeroIfValueNaN);
    7264             : }
    7265             : 
    7266             : bool
    7267           7 : HTMLInputElement::HasBadInput() const
    7268             : {
    7269           7 :   return mInputType->HasBadInput();
    7270             : }
    7271             : 
    7272             : void
    7273           7 : HTMLInputElement::UpdateTooLongValidityState()
    7274             : {
    7275           7 :   SetValidityState(VALIDITY_STATE_TOO_LONG, IsTooLong());
    7276           7 : }
    7277             : 
    7278             : void
    7279           7 : HTMLInputElement::UpdateTooShortValidityState()
    7280             : {
    7281           7 :   SetValidityState(VALIDITY_STATE_TOO_SHORT, IsTooShort());
    7282           7 : }
    7283             : 
    7284             : void
    7285           0 : HTMLInputElement::UpdateValueMissingValidityStateForRadio(bool aIgnoreSelf)
    7286             : {
    7287           0 :   bool notify = mDoneCreating;
    7288           0 :   nsCOMPtr<nsIDOMHTMLInputElement> selection = GetSelectedRadioButton();
    7289             : 
    7290           0 :   aIgnoreSelf = aIgnoreSelf || !IsMutable();
    7291             : 
    7292             :   // If there is no selection, that might mean the radio is not in a group.
    7293             :   // In that case, we can look for the checked state of the radio.
    7294           0 :   bool selected = selection || (!aIgnoreSelf && mChecked);
    7295           0 :   bool required = !aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required);
    7296           0 :   bool valueMissing = false;
    7297             : 
    7298           0 :   nsCOMPtr<nsIRadioGroupContainer> container = GetRadioGroupContainer();
    7299             : 
    7300           0 :   if (!container) {
    7301           0 :     SetValidityState(VALIDITY_STATE_VALUE_MISSING,
    7302           0 :                      IsMutable() && required && !selected);
    7303           0 :     return;
    7304             :   }
    7305             : 
    7306           0 :   nsAutoString name;
    7307           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::name, name);
    7308             : 
    7309             :   // If the current radio is required and not ignored, we can assume the entire
    7310             :   // group is required.
    7311           0 :   if (!required) {
    7312           0 :     required = (aIgnoreSelf && HasAttr(kNameSpaceID_None, nsGkAtoms::required))
    7313           0 :                  ? container->GetRequiredRadioCount(name) - 1
    7314           0 :                  : container->GetRequiredRadioCount(name);
    7315             :   }
    7316             : 
    7317           0 :   valueMissing = required && !selected;
    7318             : 
    7319           0 :   if (container->GetValueMissingState(name) != valueMissing) {
    7320           0 :     container->SetValueMissingState(name, valueMissing);
    7321             : 
    7322           0 :     SetValidityState(VALIDITY_STATE_VALUE_MISSING, valueMissing);
    7323             : 
    7324             :     // nsRadioSetValueMissingState will call ContentStateChanged while visiting.
    7325           0 :     nsAutoScriptBlocker scriptBlocker;
    7326             :     nsCOMPtr<nsIRadioVisitor> visitor =
    7327           0 :       new nsRadioSetValueMissingState(this, valueMissing, notify);
    7328           0 :     VisitGroup(visitor, notify);
    7329             :   }
    7330             : }
    7331             : 
    7332             : void
    7333          30 : HTMLInputElement::UpdateValueMissingValidityState()
    7334             : {
    7335          30 :   if (mType == NS_FORM_INPUT_RADIO) {
    7336           0 :     UpdateValueMissingValidityStateForRadio(false);
    7337           0 :     return;
    7338             :   }
    7339             : 
    7340          30 :   SetValidityState(VALIDITY_STATE_VALUE_MISSING, IsValueMissing());
    7341             : }
    7342             : 
    7343             : void
    7344           7 : HTMLInputElement::UpdateTypeMismatchValidityState()
    7345             : {
    7346           7 :     SetValidityState(VALIDITY_STATE_TYPE_MISMATCH, HasTypeMismatch());
    7347           7 : }
    7348             : 
    7349             : void
    7350           7 : HTMLInputElement::UpdatePatternMismatchValidityState()
    7351             : {
    7352           7 :   SetValidityState(VALIDITY_STATE_PATTERN_MISMATCH, HasPatternMismatch());
    7353           7 : }
    7354             : 
    7355             : void
    7356           7 : HTMLInputElement::UpdateRangeOverflowValidityState()
    7357             : {
    7358           7 :   SetValidityState(VALIDITY_STATE_RANGE_OVERFLOW, IsRangeOverflow());
    7359           7 : }
    7360             : 
    7361             : void
    7362           7 : HTMLInputElement::UpdateRangeUnderflowValidityState()
    7363             : {
    7364           7 :   SetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW, IsRangeUnderflow());
    7365           7 : }
    7366             : 
    7367             : void
    7368           7 : HTMLInputElement::UpdateStepMismatchValidityState()
    7369             : {
    7370           7 :   SetValidityState(VALIDITY_STATE_STEP_MISMATCH, HasStepMismatch());
    7371           7 : }
    7372             : 
    7373             : void
    7374           7 : HTMLInputElement::UpdateBadInputValidityState()
    7375             : {
    7376           7 :   SetValidityState(VALIDITY_STATE_BAD_INPUT, HasBadInput());
    7377           7 : }
    7378             : 
    7379             : void
    7380           7 : HTMLInputElement::UpdateAllValidityStates(bool aNotify)
    7381             : {
    7382           7 :   bool validBefore = IsValid();
    7383           7 :   UpdateTooLongValidityState();
    7384           7 :   UpdateTooShortValidityState();
    7385           7 :   UpdateValueMissingValidityState();
    7386           7 :   UpdateTypeMismatchValidityState();
    7387           7 :   UpdatePatternMismatchValidityState();
    7388           7 :   UpdateRangeOverflowValidityState();
    7389           7 :   UpdateRangeUnderflowValidityState();
    7390           7 :   UpdateStepMismatchValidityState();
    7391           7 :   UpdateBadInputValidityState();
    7392             : 
    7393           7 :   if (validBefore != IsValid()) {
    7394           0 :     UpdateState(aNotify);
    7395             :   }
    7396           7 : }
    7397             : 
    7398             : void
    7399          24 : HTMLInputElement::UpdateBarredFromConstraintValidation()
    7400             : {
    7401          72 :   SetBarredFromConstraintValidation(mType == NS_FORM_INPUT_HIDDEN ||
    7402          48 :                                     mType == NS_FORM_INPUT_BUTTON ||
    7403          48 :                                     mType == NS_FORM_INPUT_RESET ||
    7404          72 :                                     HasAttr(kNameSpaceID_None, nsGkAtoms::readonly) ||
    7405          48 :                                     IsDisabled());
    7406          24 : }
    7407             : 
    7408             : void
    7409           0 : HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
    7410             :                                        ErrorResult& aRv)
    7411             : {
    7412           0 :   aRv = GetValidationMessage(aValidationMessage);
    7413           0 : }
    7414             : 
    7415             : nsresult
    7416           0 : HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
    7417             :                                        ValidityStateType aType)
    7418             : {
    7419           0 :   return mInputType->GetValidationMessage(aValidationMessage, aType);
    7420             : }
    7421             : 
    7422             : NS_IMETHODIMP_(bool)
    7423          79 : HTMLInputElement::IsSingleLineTextControl() const
    7424             : {
    7425          79 :   return IsSingleLineTextControl(false);
    7426             : }
    7427             : 
    7428             : NS_IMETHODIMP_(bool)
    7429          20 : HTMLInputElement::IsTextArea() const
    7430             : {
    7431          20 :   return false;
    7432             : }
    7433             : 
    7434             : NS_IMETHODIMP_(bool)
    7435           6 : HTMLInputElement::IsPlainTextControl() const
    7436             : {
    7437             :   // need to check our HTML attribute and/or CSS.
    7438           6 :   return true;
    7439             : }
    7440             : 
    7441             : NS_IMETHODIMP_(bool)
    7442           4 : HTMLInputElement::IsPasswordTextControl() const
    7443             : {
    7444           4 :   return mType == NS_FORM_INPUT_PASSWORD;
    7445             : }
    7446             : 
    7447             : NS_IMETHODIMP_(int32_t)
    7448          20 : HTMLInputElement::GetCols()
    7449             : {
    7450             :   // Else we know (assume) it is an input with size attr
    7451          20 :   const nsAttrValue* attr = GetParsedAttr(nsGkAtoms::size);
    7452          20 :   if (attr && attr->Type() == nsAttrValue::eInteger) {
    7453           0 :     int32_t cols = attr->GetIntegerValue();
    7454           0 :     if (cols > 0) {
    7455           0 :       return cols;
    7456             :     }
    7457             :   }
    7458             : 
    7459          20 :   return DEFAULT_COLS;
    7460             : }
    7461             : 
    7462             : NS_IMETHODIMP_(int32_t)
    7463           5 : HTMLInputElement::GetWrapCols()
    7464             : {
    7465           5 :   return 0; // only textarea's can have wrap cols
    7466             : }
    7467             : 
    7468             : NS_IMETHODIMP_(int32_t)
    7469          20 : HTMLInputElement::GetRows()
    7470             : {
    7471          20 :   return DEFAULT_ROWS;
    7472             : }
    7473             : 
    7474             : NS_IMETHODIMP_(void)
    7475          30 : HTMLInputElement::GetDefaultValueFromContent(nsAString& aValue)
    7476             : {
    7477          30 :   nsTextEditorState *state = GetEditorState();
    7478          30 :   if (state) {
    7479          30 :     GetDefaultValue(aValue);
    7480             :     // This is called by the frame to show the value.
    7481             :     // We have to sanitize it when needed.
    7482          30 :     if (mDoneCreating) {
    7483          30 :       SanitizeValue(aValue);
    7484             :     }
    7485             :   }
    7486          30 : }
    7487             : 
    7488             : NS_IMETHODIMP_(bool)
    7489          32 : HTMLInputElement::ValueChanged() const
    7490             : {
    7491          32 :   return mValueChanged;
    7492             : }
    7493             : 
    7494             : NS_IMETHODIMP_(void)
    7495          11 : HTMLInputElement::GetTextEditorValue(nsAString& aValue,
    7496             :                                      bool aIgnoreWrap) const
    7497             : {
    7498          11 :   nsTextEditorState* state = GetEditorState();
    7499          11 :   if (state) {
    7500          11 :     state->GetValue(aValue, aIgnoreWrap);
    7501             :   }
    7502          11 : }
    7503             : 
    7504             : NS_IMETHODIMP_(void)
    7505           4 : HTMLInputElement::InitializeKeyboardEventListeners()
    7506             : {
    7507           4 :   nsTextEditorState* state = GetEditorState();
    7508           4 :   if (state) {
    7509           4 :     state->InitializeKeyboardEventListeners();
    7510             :   }
    7511           4 : }
    7512             : 
    7513             : NS_IMETHODIMP_(void)
    7514           6 : HTMLInputElement::OnValueChanged(bool aNotify, bool aWasInteractiveUserChange)
    7515             : {
    7516           6 :   mLastValueChangeWasInteractive = aWasInteractiveUserChange;
    7517             : 
    7518           6 :   UpdateAllValidityStates(aNotify);
    7519             : 
    7520           6 :   if (HasDirAuto()) {
    7521           0 :     SetDirectionFromValue(aNotify);
    7522             :   }
    7523             : 
    7524             :   // :placeholder-shown pseudo-class may change when the value changes.
    7525             :   // However, we don't want to waste cycles if the state doesn't apply.
    7526          12 :   if (PlaceholderApplies() &&
    7527           6 :       HasAttr(kNameSpaceID_None, nsGkAtoms::placeholder)) {
    7528           3 :     UpdateState(aNotify);
    7529             :   }
    7530           6 : }
    7531             : 
    7532             : NS_IMETHODIMP_(bool)
    7533           4 : HTMLInputElement::HasCachedSelection()
    7534             : {
    7535           4 :   bool isCached = false;
    7536           4 :   nsTextEditorState* state = GetEditorState();
    7537           4 :   if (state) {
    7538          12 :     isCached = state->IsSelectionCached() &&
    7539           7 :                state->HasNeverInitializedBefore() &&
    7540           3 :                state->GetSelectionProperties().GetStart() !=
    7541           3 :                  state->GetSelectionProperties().GetEnd();
    7542           4 :     if (isCached) {
    7543           0 :       state->WillInitEagerly();
    7544             :     }
    7545             :   }
    7546           4 :   return isCached;
    7547             : }
    7548             : 
    7549             : void
    7550           0 : HTMLInputElement::FieldSetDisabledChanged(bool aNotify)
    7551             : {
    7552           0 :   UpdateValueMissingValidityState();
    7553           0 :   UpdateBarredFromConstraintValidation();
    7554             : 
    7555           0 :   nsGenericHTMLFormElementWithState::FieldSetDisabledChanged(aNotify);
    7556           0 : }
    7557             : 
    7558             : void
    7559           0 : HTMLInputElement::SetFilePickerFiltersFromAccept(nsIFilePicker* filePicker)
    7560             : {
    7561             :   // We always add |filterAll|
    7562           0 :   filePicker->AppendFilters(nsIFilePicker::filterAll);
    7563             : 
    7564           0 :   NS_ASSERTION(HasAttr(kNameSpaceID_None, nsGkAtoms::accept),
    7565             :                "You should not call SetFilePickerFiltersFromAccept if the"
    7566             :                " element has no accept attribute!");
    7567             : 
    7568             :   // Services to retrieve image/*, audio/*, video/* filters
    7569             :   nsCOMPtr<nsIStringBundleService> stringService =
    7570           0 :     mozilla::services::GetStringBundleService();
    7571           0 :   if (!stringService) {
    7572           0 :     return;
    7573             :   }
    7574           0 :   nsCOMPtr<nsIStringBundle> filterBundle;
    7575           0 :   if (NS_FAILED(stringService->CreateBundle("chrome://global/content/filepicker.properties",
    7576             :                                             getter_AddRefs(filterBundle)))) {
    7577           0 :     return;
    7578             :   }
    7579             : 
    7580             :   // Service to retrieve mime type information for mime types filters
    7581           0 :   nsCOMPtr<nsIMIMEService> mimeService = do_GetService("@mozilla.org/mime;1");
    7582           0 :   if (!mimeService) {
    7583           0 :     return;
    7584             :   }
    7585             : 
    7586           0 :   nsAutoString accept;
    7587           0 :   GetAttr(kNameSpaceID_None, nsGkAtoms::accept, accept);
    7588             : 
    7589           0 :   HTMLSplitOnSpacesTokenizer tokenizer(accept, ',');
    7590             : 
    7591           0 :   nsTArray<nsFilePickerFilter> filters;
    7592           0 :   nsString allExtensionsList;
    7593             : 
    7594           0 :   bool allMimeTypeFiltersAreValid = true;
    7595           0 :   bool atLeastOneFileExtensionFilter = false;
    7596             : 
    7597             :   // Retrieve all filters
    7598           0 :   while (tokenizer.hasMoreTokens()) {
    7599           0 :     const nsDependentSubstring& token = tokenizer.nextToken();
    7600             : 
    7601           0 :     if (token.IsEmpty()) {
    7602           0 :       continue;
    7603             :     }
    7604             : 
    7605           0 :     int32_t filterMask = 0;
    7606           0 :     nsString filterName;
    7607           0 :     nsString extensionListStr;
    7608             : 
    7609             :     // First, check for image/audio/video filters...
    7610           0 :     if (token.EqualsLiteral("image/*")) {
    7611           0 :       filterMask = nsIFilePicker::filterImages;
    7612           0 :       filterBundle->GetStringFromName(u"imageFilter",
    7613           0 :                                       getter_Copies(extensionListStr));
    7614           0 :     } else if (token.EqualsLiteral("audio/*")) {
    7615           0 :       filterMask = nsIFilePicker::filterAudio;
    7616           0 :       filterBundle->GetStringFromName(u"audioFilter",
    7617           0 :                                       getter_Copies(extensionListStr));
    7618           0 :     } else if (token.EqualsLiteral("video/*")) {
    7619           0 :       filterMask = nsIFilePicker::filterVideo;
    7620           0 :       filterBundle->GetStringFromName(u"videoFilter",
    7621           0 :                                       getter_Copies(extensionListStr));
    7622           0 :     } else if (token.First() == '.') {
    7623           0 :       if (token.Contains(';') || token.Contains('*')) {
    7624             :         // Ignore this filter as it contains reserved characters
    7625           0 :         continue;
    7626             :       }
    7627           0 :       extensionListStr = NS_LITERAL_STRING("*") + token;
    7628           0 :       filterName = extensionListStr;
    7629           0 :       atLeastOneFileExtensionFilter = true;
    7630             :     } else {
    7631             :       //... if no image/audio/video filter is found, check mime types filters
    7632           0 :       nsCOMPtr<nsIMIMEInfo> mimeInfo;
    7633           0 :       if (NS_FAILED(mimeService->GetFromTypeAndExtension(
    7634             :                       NS_ConvertUTF16toUTF8(token),
    7635             :                       EmptyCString(), // No extension
    7636           0 :                       getter_AddRefs(mimeInfo))) ||
    7637           0 :           !mimeInfo) {
    7638           0 :         allMimeTypeFiltersAreValid =  false;
    7639           0 :         continue;
    7640             :       }
    7641             : 
    7642             :       // Get a name for the filter: first try the description, then the mime type
    7643             :       // name if there is no description
    7644           0 :       mimeInfo->GetDescription(filterName);
    7645           0 :       if (filterName.IsEmpty()) {
    7646           0 :         nsCString mimeTypeName;
    7647           0 :         mimeInfo->GetType(mimeTypeName);
    7648           0 :         CopyUTF8toUTF16(mimeTypeName, filterName);
    7649             :       }
    7650             : 
    7651             :       // Get extension list
    7652           0 :       nsCOMPtr<nsIUTF8StringEnumerator> extensions;
    7653           0 :       mimeInfo->GetFileExtensions(getter_AddRefs(extensions));
    7654             : 
    7655             :       bool hasMore;
    7656           0 :       while (NS_SUCCEEDED(extensions->HasMore(&hasMore)) && hasMore) {
    7657           0 :         nsCString extension;
    7658           0 :         if (NS_FAILED(extensions->GetNext(extension))) {
    7659           0 :           continue;
    7660             :         }
    7661           0 :         if (!extensionListStr.IsEmpty()) {
    7662           0 :           extensionListStr.AppendLiteral("; ");
    7663             :         }
    7664           0 :         extensionListStr += NS_LITERAL_STRING("*.") +
    7665           0 :                             NS_ConvertUTF8toUTF16(extension);
    7666             :       }
    7667             :     }
    7668             : 
    7669           0 :     if (!filterMask && (extensionListStr.IsEmpty() || filterName.IsEmpty())) {
    7670             :       // No valid filter found
    7671           0 :       allMimeTypeFiltersAreValid = false;
    7672           0 :       continue;
    7673             :     }
    7674             : 
    7675             :     // If we arrived here, that means we have a valid filter: let's create it
    7676             :     // and add it to our list, if no similar filter is already present
    7677           0 :     nsFilePickerFilter filter;
    7678           0 :     if (filterMask) {
    7679           0 :       filter = nsFilePickerFilter(filterMask);
    7680             :     } else {
    7681           0 :       filter = nsFilePickerFilter(filterName, extensionListStr);
    7682             :     }
    7683             : 
    7684           0 :     if (!filters.Contains(filter)) {
    7685           0 :       if (!allExtensionsList.IsEmpty()) {
    7686           0 :         allExtensionsList.AppendLiteral("; ");
    7687             :       }
    7688           0 :       allExtensionsList += extensionListStr;
    7689           0 :       filters.AppendElement(filter);
    7690             :     }
    7691             :   }
    7692             : 
    7693             :   // Remove similar filters
    7694             :   // Iterate over a copy, as we might modify the original filters list
    7695           0 :   nsTArray<nsFilePickerFilter> filtersCopy;
    7696           0 :   filtersCopy = filters;
    7697           0 :   for (uint32_t i = 0; i < filtersCopy.Length(); ++i) {
    7698           0 :     const nsFilePickerFilter& filterToCheck = filtersCopy[i];
    7699           0 :     if (filterToCheck.mFilterMask) {
    7700           0 :       continue;
    7701             :     }
    7702           0 :     for (uint32_t j = 0; j < filtersCopy.Length(); ++j) {
    7703           0 :       if (i == j) {
    7704           0 :         continue;
    7705             :       }
    7706             :       // Check if this filter's extension list is a substring of the other one.
    7707             :       // e.g. if filters are "*.jpeg" and "*.jpeg; *.jpg" the first one should
    7708             :       // be removed.
    7709             :       // Add an extra "; " to be sure the check will work and avoid cases like
    7710             :       // "*.xls" being a subtring of "*.xslx" while those are two differents
    7711             :       // filters and none should be removed.
    7712           0 :       if (FindInReadable(filterToCheck.mFilter + NS_LITERAL_STRING(";"),
    7713           0 :                          filtersCopy[j].mFilter + NS_LITERAL_STRING(";"))) {
    7714             :         // We already have a similar, less restrictive filter (i.e.
    7715             :         // filterToCheck extensionList is just a subset of another filter
    7716             :         // extension list): remove this one
    7717           0 :         filters.RemoveElement(filterToCheck);
    7718             :       }
    7719             :     }
    7720             :   }
    7721             : 
    7722             :   // Add "All Supported Types" filter
    7723           0 :   if (filters.Length() > 1) {
    7724           0 :     nsXPIDLString title;
    7725             :     nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
    7726           0 :                                        "AllSupportedTypes", title);
    7727           0 :     filePicker->AppendFilter(title, allExtensionsList);
    7728             :   }
    7729             : 
    7730             :   // Add each filter
    7731           0 :   for (uint32_t i = 0; i < filters.Length(); ++i) {
    7732           0 :     const nsFilePickerFilter& filter = filters[i];
    7733           0 :     if (filter.mFilterMask) {
    7734           0 :       filePicker->AppendFilters(filter.mFilterMask);
    7735             :     } else {
    7736           0 :       filePicker->AppendFilter(filter.mTitle, filter.mFilter);
    7737             :     }
    7738             :   }
    7739             : 
    7740           0 :   if (filters.Length() >= 1 &&
    7741           0 :       (allMimeTypeFiltersAreValid || atLeastOneFileExtensionFilter)) {
    7742             :     // |filterAll| will always use index=0 so we need to set index=1 as the
    7743             :     // current filter.
    7744           0 :     filePicker->SetFilterIndex(1);
    7745             :   }
    7746             : }
    7747             : 
    7748             : Decimal
    7749           0 : HTMLInputElement::GetStepScaleFactor() const
    7750             : {
    7751           0 :   MOZ_ASSERT(DoesStepApply());
    7752             : 
    7753           0 :   switch (mType) {
    7754             :     case NS_FORM_INPUT_DATE:
    7755           0 :       return kStepScaleFactorDate;
    7756             :     case NS_FORM_INPUT_NUMBER:
    7757             :     case NS_FORM_INPUT_RANGE:
    7758           0 :       return kStepScaleFactorNumberRange;
    7759             :     case NS_FORM_INPUT_TIME:
    7760             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    7761           0 :       return kStepScaleFactorTime;
    7762             :     case NS_FORM_INPUT_MONTH:
    7763           0 :       return kStepScaleFactorMonth;
    7764             :     case NS_FORM_INPUT_WEEK:
    7765           0 :       return kStepScaleFactorWeek;
    7766             :     default:
    7767           0 :       MOZ_ASSERT(false, "Unrecognized input type");
    7768             :       return Decimal::nan();
    7769             :   }
    7770             : }
    7771             : 
    7772             : Decimal
    7773           0 : HTMLInputElement::GetDefaultStep() const
    7774             : {
    7775           0 :   MOZ_ASSERT(DoesStepApply());
    7776             : 
    7777           0 :   switch (mType) {
    7778             :     case NS_FORM_INPUT_DATE:
    7779             :     case NS_FORM_INPUT_MONTH:
    7780             :     case NS_FORM_INPUT_WEEK:
    7781             :     case NS_FORM_INPUT_NUMBER:
    7782             :     case NS_FORM_INPUT_RANGE:
    7783           0 :       return kDefaultStep;
    7784             :     case NS_FORM_INPUT_TIME:
    7785             :     case NS_FORM_INPUT_DATETIME_LOCAL:
    7786           0 :       return kDefaultStepTime;
    7787             :     default:
    7788           0 :       MOZ_ASSERT(false, "Unrecognized input type");
    7789             :       return Decimal::nan();
    7790             :   }
    7791             : }
    7792             : 
    7793             : void
    7794           0 : HTMLInputElement::UpdateValidityUIBits(bool aIsFocused)
    7795             : {
    7796           0 :   if (aIsFocused) {
    7797             :     // If the invalid UI is shown, we should show it while focusing (and
    7798             :     // update). Otherwise, we should not.
    7799           0 :     mCanShowInvalidUI = !IsValid() && ShouldShowValidityUI();
    7800             : 
    7801             :     // If neither invalid UI nor valid UI is shown, we shouldn't show the valid
    7802             :     // UI while typing.
    7803           0 :     mCanShowValidUI = ShouldShowValidityUI();
    7804             :   } else {
    7805           0 :     mCanShowInvalidUI = true;
    7806           0 :     mCanShowValidUI = true;
    7807             :   }
    7808           0 : }
    7809             : 
    7810             : void
    7811           1 : HTMLInputElement::UpdateHasRange()
    7812             : {
    7813             :   /*
    7814             :    * There is a range if min/max applies for the type and if the element
    7815             :    * currently have a valid min or max.
    7816             :    */
    7817             : 
    7818           1 :   mHasRange = false;
    7819             : 
    7820           1 :   if (!DoesMinMaxApply()) {
    7821           2 :     return;
    7822             :   }
    7823             : 
    7824           0 :   Decimal minimum = GetMinimum();
    7825           0 :   if (!minimum.isNaN()) {
    7826           0 :     mHasRange = true;
    7827           0 :     return;
    7828             :   }
    7829             : 
    7830           0 :   Decimal maximum = GetMaximum();
    7831           0 :   if (!maximum.isNaN()) {
    7832           0 :     mHasRange = true;
    7833           0 :     return;
    7834             :   }
    7835             : }
    7836             : 
    7837             : void
    7838           0 : HTMLInputElement::PickerClosed()
    7839             : {
    7840           0 :   mPickerRunning = false;
    7841           0 : }
    7842             : 
    7843             : JSObject*
    7844           2 : HTMLInputElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
    7845             : {
    7846           2 :   return HTMLInputElementBinding::Wrap(aCx, this, aGivenProto);
    7847             : }
    7848             : 
    7849             : GetFilesHelper*
    7850           0 : HTMLInputElement::GetOrCreateGetFilesHelper(bool aRecursiveFlag,
    7851             :                                             ErrorResult& aRv)
    7852             : {
    7853           0 :   MOZ_ASSERT(mFileData);
    7854             : 
    7855           0 :   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
    7856           0 :   MOZ_ASSERT(global);
    7857           0 :   if (!global) {
    7858           0 :     aRv.Throw(NS_ERROR_FAILURE);
    7859           0 :     return nullptr;
    7860             :   }
    7861             : 
    7862           0 :   if (aRecursiveFlag) {
    7863           0 :     if (!mFileData->mGetFilesRecursiveHelper) {
    7864           0 :       mFileData->mGetFilesRecursiveHelper =
    7865           0 :         GetFilesHelper::Create(global,
    7866             :                                GetFilesOrDirectoriesInternal(),
    7867           0 :                                aRecursiveFlag, aRv);
    7868           0 :       if (NS_WARN_IF(aRv.Failed())) {
    7869           0 :         return nullptr;
    7870             :       }
    7871             :     }
    7872             : 
    7873           0 :     return mFileData->mGetFilesRecursiveHelper;
    7874             :   }
    7875             : 
    7876           0 :   if (!mFileData->mGetFilesNonRecursiveHelper) {
    7877           0 :     mFileData->mGetFilesNonRecursiveHelper =
    7878           0 :       GetFilesHelper::Create(global,
    7879             :                              GetFilesOrDirectoriesInternal(),
    7880           0 :                              aRecursiveFlag, aRv);
    7881           0 :     if (NS_WARN_IF(aRv.Failed())) {
    7882           0 :       return nullptr;
    7883             :     }
    7884             :   }
    7885             : 
    7886           0 :   return mFileData->mGetFilesNonRecursiveHelper;
    7887             : }
    7888             : 
    7889             : void
    7890           0 : HTMLInputElement::UpdateEntries(const nsTArray<OwningFileOrDirectory>& aFilesOrDirectories)
    7891             : {
    7892           0 :   MOZ_ASSERT(mFileData && mFileData->mEntries.IsEmpty());
    7893             : 
    7894           0 :   nsCOMPtr<nsIGlobalObject> global = OwnerDoc()->GetScopeObject();
    7895           0 :   MOZ_ASSERT(global);
    7896             : 
    7897           0 :   RefPtr<FileSystem> fs = FileSystem::Create(global);
    7898           0 :   if (NS_WARN_IF(!fs)) {
    7899           0 :     return;
    7900             :   }
    7901             : 
    7902           0 :   Sequence<RefPtr<FileSystemEntry>> entries;
    7903           0 :   for (uint32_t i = 0; i < aFilesOrDirectories.Length(); ++i) {
    7904             :     RefPtr<FileSystemEntry> entry =
    7905           0 :       FileSystemEntry::Create(global, aFilesOrDirectories[i], fs);
    7906           0 :     MOZ_ASSERT(entry);
    7907             : 
    7908           0 :     if (!entries.AppendElement(entry, fallible)) {
    7909           0 :       return;
    7910             :     }
    7911             :   }
    7912             : 
    7913             :   // The root fileSystem is a DirectoryEntry object that contains only the
    7914             :   // dropped fileEntry and directoryEntry objects.
    7915           0 :   fs->CreateRoot(entries);
    7916             : 
    7917           0 :   mFileData->mEntries.SwapElements(entries);
    7918             : }
    7919             : 
    7920             : void
    7921           0 : HTMLInputElement::GetWebkitEntries(nsTArray<RefPtr<FileSystemEntry>>& aSequence)
    7922             : {
    7923           0 :   if (NS_WARN_IF(mType != NS_FORM_INPUT_FILE)) {
    7924           0 :     return;
    7925             :   }
    7926             : 
    7927           0 :   Telemetry::Accumulate(Telemetry::BLINK_FILESYSTEM_USED, true);
    7928           0 :   aSequence.AppendElements(mFileData->mEntries);
    7929             : }
    7930             : 
    7931             : already_AddRefed<nsINodeList>
    7932           0 : HTMLInputElement::GetLabels()
    7933             : {
    7934           0 :   if (!IsLabelable()) {
    7935           0 :     return nullptr;
    7936             :   }
    7937             : 
    7938           0 :   return nsGenericHTMLElement::Labels();
    7939             : }
    7940             : 
    7941             : } // namespace dom
    7942             : } // namespace mozilla
    7943             : 
    7944             : #undef NS_ORIGINAL_CHECKED_VALUE

Generated by: LCOV version 1.13