Bug 1396323 - Don't initialize HTMLInputElement editor for eVoidEvent. r=ehsan
Keyboard APZ dispatches an eVoidEvent to gather all event targets that a key event
would normally go to. This can sometimes trigger an HTMLInputElement to initialize its
editor, which can cause unnecessary DOM modifications.
MozReview-Commit-ID: 6EEttouVB81

/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- *//* vim: set ts=8 sts=2 et sw=2 tw=80: *//* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */#include"mozilla/dom/HTMLInputElement.h"#include"mozilla/ArrayUtils.h"#include"mozilla/AsyncEventDispatcher.h"#include"mozilla/DebugOnly.h"#include"mozilla/dom/Date.h"#include"mozilla/dom/Directory.h"#include"mozilla/dom/HTMLFormSubmission.h"#include"mozilla/dom/FileSystemUtils.h"#include"mozilla/dom/GetFilesHelper.h"#include"nsAttrValueInlines.h"#include"nsCRTGlue.h"#include"nsIDOMHTMLInputElement.h"#include"nsITextControlElement.h"#include"nsIDOMNSEditableElement.h"#include"nsIRadioVisitor.h"#include"InputType.h"#include"HTMLFormSubmissionConstants.h"#include"mozilla/Telemetry.h"#include"nsIControllers.h"#include"nsIStringBundle.h"#include"nsFocusManager.h"#include"nsColorControlFrame.h"#include"nsNumberControlFrame.h"#include"nsPIDOMWindow.h"#include"nsRepeatService.h"#include"nsContentCID.h"#include"nsIComponentManager.h"#include"nsIDOMHTMLFormElement.h"#include"mozilla/dom/ProgressEvent.h"#include"nsGkAtoms.h"#include"nsStyleConsts.h"#include"nsPresContext.h"#include"nsMappedAttributes.h"#include"nsIFormControl.h"#include"nsIDocument.h"#include"nsIPresShell.h"#include"nsIFormControlFrame.h"#include"nsITextControlFrame.h"#include"nsIFrame.h"#include"nsRangeFrame.h"#include"nsIServiceManager.h"#include"nsError.h"#include"nsIEditor.h"#include"nsDocument.h"#include"nsAttrValueOrString.h"#include"nsDateTimeControlFrame.h"#include"nsPresState.h"#include"nsIDOMEvent.h"#include"nsIDOMNodeList.h"#include"nsIDOMHTMLCollection.h"#include"nsLinebreakConverter.h" //to strip out carriage returns#include"nsReadableUtils.h"#include"nsUnicharUtils.h"#include"nsLayoutUtils.h"#include"nsVariant.h"#include"nsIDOMMutationEvent.h"#include"mozilla/ContentEvents.h"#include"mozilla/EventDispatcher.h"#include"mozilla/EventStates.h"#include"mozilla/GenericSpecifiedValuesInlines.h"#include"mozilla/InternalMutationEvent.h"#include"mozilla/TextEditor.h"#include"mozilla/TextEvents.h"#include"mozilla/TouchEvents.h"#include<algorithm>// input type=radio#include"nsIRadioGroupContainer.h"// input type=file#include"mozilla/dom/FileSystemEntry.h"#include"mozilla/dom/FileSystem.h"#include"mozilla/dom/File.h"#include"mozilla/dom/FileList.h"#include"nsIFile.h"#include"nsDirectoryServiceDefs.h"#include"nsIContentPrefService2.h"#include"nsIMIMEService.h"#include"nsIObserverService.h"#include"nsIPopupWindowManager.h"#include"nsGlobalWindow.h"// input type=image#include"nsImageLoadingContent.h"#include"imgRequestProxy.h"#include"mozAutoDocUpdate.h"#include"nsContentCreatorFunctions.h"#include"nsContentUtils.h"#include"mozilla/dom/DirectionalityUtils.h"#include"nsRadioVisitor.h"#include"nsTextEditorState.h"#include"mozilla/LookAndFeel.h"#include"mozilla/Preferences.h"#include"mozilla/MathAlgorithms.h"#include"nsIIDNService.h"#include<limits>#include"nsIColorPicker.h"#include"nsIStringEnumerator.h"#include"HTMLSplitOnSpacesTokenizer.h"#include"nsIController.h"#include"nsIMIMEInfo.h"#include"nsFrameSelection.h"// input type=date#include"js/Date.h"NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Input)// XXX align=left, hspace, vspace, border? other nav4 attrsstaticNS_DEFINE_CID(kXULControllersCID,NS_XULCONTROLLERS_CID);namespacemozilla{namespacedom{// First bits are needed for the control type.#define NS_OUTER_ACTIVATE_EVENT (1 << 9)#define NS_ORIGINAL_CHECKED_VALUE (1 << 10)#define NS_NO_CONTENT_DISPATCH (1 << 11)#define NS_ORIGINAL_INDETERMINATE_VALUE (1 << 12)#define NS_CONTROL_TYPE(bits) ((bits) & ~( \ NS_OUTER_ACTIVATE_EVENT | NS_ORIGINAL_CHECKED_VALUE | NS_NO_CONTENT_DISPATCH | \ NS_ORIGINAL_INDETERMINATE_VALUE))#define NS_PRE_HANDLE_BLUR_EVENT (1 << 13)#define NS_PRE_HANDLE_INPUT_EVENT (1 << 14)// whether textfields should be selected once focused:// -1: no, 1: yes, 0: uninitializedstaticint32_tgSelectTextFieldOnFocus;UploadLastDir*HTMLInputElement::gUploadLastDir;staticconstnsAttrValue::EnumTablekInputTypeTable[]={{"button",NS_FORM_INPUT_BUTTON},{"checkbox",NS_FORM_INPUT_CHECKBOX},{"color",NS_FORM_INPUT_COLOR},{"date",NS_FORM_INPUT_DATE},{"datetime-local",NS_FORM_INPUT_DATETIME_LOCAL},{"email",NS_FORM_INPUT_EMAIL},{"file",NS_FORM_INPUT_FILE},{"hidden",NS_FORM_INPUT_HIDDEN},{"reset",NS_FORM_INPUT_RESET},{"image",NS_FORM_INPUT_IMAGE},{"month",NS_FORM_INPUT_MONTH},{"number",NS_FORM_INPUT_NUMBER},{"password",NS_FORM_INPUT_PASSWORD},{"radio",NS_FORM_INPUT_RADIO},{"range",NS_FORM_INPUT_RANGE},{"search",NS_FORM_INPUT_SEARCH},{"submit",NS_FORM_INPUT_SUBMIT},{"tel",NS_FORM_INPUT_TEL},{"time",NS_FORM_INPUT_TIME},{"url",NS_FORM_INPUT_URL},{"week",NS_FORM_INPUT_WEEK},// "text" must be last for ParseAttribute to work right. If you add things// before it, please update kInputDefaultType.{"text",NS_FORM_INPUT_TEXT},{nullptr,0}};// Default type is 'text'.staticconstnsAttrValue::EnumTable*kInputDefaultType=&kInputTypeTable[ArrayLength(kInputTypeTable)-2];staticconstuint8_tNS_INPUT_INPUTMODE_AUTO=0;staticconstuint8_tNS_INPUT_INPUTMODE_NUMERIC=1;staticconstuint8_tNS_INPUT_INPUTMODE_DIGIT=2;staticconstuint8_tNS_INPUT_INPUTMODE_UPPERCASE=3;staticconstuint8_tNS_INPUT_INPUTMODE_LOWERCASE=4;staticconstuint8_tNS_INPUT_INPUTMODE_TITLECASE=5;staticconstuint8_tNS_INPUT_INPUTMODE_AUTOCAPITALIZED=6;staticconstnsAttrValue::EnumTablekInputInputmodeTable[]={{"auto",NS_INPUT_INPUTMODE_AUTO},{"numeric",NS_INPUT_INPUTMODE_NUMERIC},{"digit",NS_INPUT_INPUTMODE_DIGIT},{"uppercase",NS_INPUT_INPUTMODE_UPPERCASE},{"lowercase",NS_INPUT_INPUTMODE_LOWERCASE},{"titlecase",NS_INPUT_INPUTMODE_TITLECASE},{"autocapitalized",NS_INPUT_INPUTMODE_AUTOCAPITALIZED},{nullptr,0}};// Default inputmode value is "auto".staticconstnsAttrValue::EnumTable*kInputDefaultInputmode=&kInputInputmodeTable[0];constDecimalHTMLInputElement::kStepScaleFactorDate=Decimal(86400000);constDecimalHTMLInputElement::kStepScaleFactorNumberRange=Decimal(1);constDecimalHTMLInputElement::kStepScaleFactorTime=Decimal(1000);constDecimalHTMLInputElement::kStepScaleFactorMonth=Decimal(1);constDecimalHTMLInputElement::kStepScaleFactorWeek=Decimal(7*86400000);constDecimalHTMLInputElement::kDefaultStepBase=Decimal(0);constDecimalHTMLInputElement::kDefaultStepBaseWeek=Decimal(-259200000);constDecimalHTMLInputElement::kDefaultStep=Decimal(1);constDecimalHTMLInputElement::kDefaultStepTime=Decimal(60);constDecimalHTMLInputElement::kStepAny=Decimal(0);constdoubleHTMLInputElement::kMinimumYear=1;constdoubleHTMLInputElement::kMaximumYear=275760;constdoubleHTMLInputElement::kMaximumWeekInMaximumYear=37;constdoubleHTMLInputElement::kMaximumDayInMaximumYear=13;constdoubleHTMLInputElement::kMaximumMonthInMaximumYear=9;constdoubleHTMLInputElement::kMaximumWeekInYear=53;constdoubleHTMLInputElement::kMsPerDay=24*60*60*1000;#define NS_INPUT_ELEMENT_STATE_IID \{ /* dc3b3d14-23e2-4479-b513-7b369343e3a0 */ \ 0xdc3b3d14, \ 0x23e2, \ 0x4479, \ {0xb5, 0x13, 0x7b, 0x36, 0x93, 0x43, 0xe3, 0xa0} \}#define PROGRESS_STR "progress"staticconstuint32_tkProgressEventInterval=50;// ms// An helper class for the dispatching of the 'change' event.// This class is used when the FilePicker finished its task (or when files and// directories are set by some chrome/test only method).// The task of this class is to postpone the dispatching of 'change' and 'input'// events at the end of the exploration of the directories.classDispatchChangeEventCallbackfinal:publicGetFilesCallback{public:explicitDispatchChangeEventCallback(HTMLInputElement*aInputElement):mInputElement(aInputElement){MOZ_ASSERT(aInputElement);}virtualvoidCallback(nsresultaStatus,constSequence<RefPtr<File>>&aFiles)override{nsTArray<OwningFileOrDirectory>array;for(uint32_ti=0;i<aFiles.Length();++i){OwningFileOrDirectory*element=array.AppendElement();element->SetAsFile()=aFiles[i];}mInputElement->SetFilesOrDirectories(array,true);Unused<<NS_WARN_IF(NS_FAILED(DispatchEvents()));}nsresultDispatchEvents(){nsresultrv=NS_OK;rv=nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),NS_LITERAL_STRING("input"),true,false);NS_WARNING_ASSERTION(NS_SUCCEEDED(rv),"DispatchTrustedEvent failed");rv=nsContentUtils::DispatchTrustedEvent(mInputElement->OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(mInputElement.get()),NS_LITERAL_STRING("change"),true,false);returnrv;}private:RefPtr<HTMLInputElement>mInputElement;};classHTMLInputElementStatefinal:publicnsISupports{public:NS_DECLARE_STATIC_IID_ACCESSOR(NS_INPUT_ELEMENT_STATE_IID)NS_DECL_ISUPPORTSboolIsCheckedSet(){returnmCheckedSet;}boolGetChecked(){returnmChecked;}voidSetChecked(boolaChecked){mChecked=aChecked;mCheckedSet=true;}constnsString&GetValue(){returnmValue;}voidSetValue(constnsAString&aValue){mValue=aValue;}voidGetFilesOrDirectories(nsPIDOMWindowInner*aWindow,nsTArray<OwningFileOrDirectory>&aResult)const{for(uint32_ti=0;i<mBlobImplsOrDirectoryPaths.Length();++i){if(mBlobImplsOrDirectoryPaths[i].mType==BlobImplOrDirectoryPath::eBlobImpl){RefPtr<File>file=File::Create(aWindow,mBlobImplsOrDirectoryPaths[i].mBlobImpl);MOZ_ASSERT(file);OwningFileOrDirectory*element=aResult.AppendElement();element->SetAsFile()=file;}else{MOZ_ASSERT(mBlobImplsOrDirectoryPaths[i].mType==BlobImplOrDirectoryPath::eDirectoryPath);nsCOMPtr<nsIFile>file;nsresultrv=NS_NewLocalFile(mBlobImplsOrDirectoryPaths[i].mDirectoryPath,true,getter_AddRefs(file));if(NS_WARN_IF(NS_FAILED(rv))){continue;}RefPtr<Directory>directory=Directory::Create(aWindow,file);MOZ_ASSERT(directory);OwningFileOrDirectory*element=aResult.AppendElement();element->SetAsDirectory()=directory;}}}voidSetFilesOrDirectories(constnsTArray<OwningFileOrDirectory>&aArray){mBlobImplsOrDirectoryPaths.Clear();for(uint32_ti=0;i<aArray.Length();++i){if(aArray[i].IsFile()){BlobImplOrDirectoryPath*data=mBlobImplsOrDirectoryPaths.AppendElement();data->mBlobImpl=aArray[i].GetAsFile()->Impl();data->mType=BlobImplOrDirectoryPath::eBlobImpl;}else{MOZ_ASSERT(aArray[i].IsDirectory());nsAutoStringfullPath;nsresultrv=aArray[i].GetAsDirectory()->GetFullRealPath(fullPath);if(NS_WARN_IF(NS_FAILED(rv))){continue;}BlobImplOrDirectoryPath*data=mBlobImplsOrDirectoryPaths.AppendElement();data->mDirectoryPath=fullPath;data->mType=BlobImplOrDirectoryPath::eDirectoryPath;}}}HTMLInputElementState():mValue(),mChecked(false),mCheckedSet(false){}protected:~HTMLInputElementState(){}nsStringmValue;structBlobImplOrDirectoryPath{RefPtr<BlobImpl>mBlobImpl;nsStringmDirectoryPath;enum{eBlobImpl,eDirectoryPath}mType;};nsTArray<BlobImplOrDirectoryPath>mBlobImplsOrDirectoryPaths;boolmChecked;boolmCheckedSet;};NS_DEFINE_STATIC_IID_ACCESSOR(HTMLInputElementState,NS_INPUT_ELEMENT_STATE_IID)NS_IMPL_ISUPPORTS(HTMLInputElementState,HTMLInputElementState)structHTMLInputElement::FileData{/** * The value of the input if it is a file input. This is the list of files or * directories DOM objects used when uploading a file. It is vital that this * is kept separate from mValue so that it won't be possible to 'leak' the * value from a text-input to a file-input. Additionally, the logic for this * value is kept as simple as possible to avoid accidental errors where the * wrong filename is used. Therefor the list of filenames is always owned by * this member, never by the frame. Whenever the frame wants to change the * filename it has to call SetFilesOrDirectories to update this member. */nsTArray<OwningFileOrDirectory>mFilesOrDirectories;RefPtr<GetFilesHelper>mGetFilesRecursiveHelper;RefPtr<GetFilesHelper>mGetFilesNonRecursiveHelper;/** * Hack for bug 1086684: Stash the .value when we're a file picker. */nsStringmFirstFilePath;RefPtr<FileList>mFileList;Sequence<RefPtr<FileSystemEntry>>mEntries;nsStringmStaticDocFileList;voidClearGetFilesHelpers(){if(mGetFilesRecursiveHelper){mGetFilesRecursiveHelper->Unlink();mGetFilesRecursiveHelper=nullptr;}if(mGetFilesNonRecursiveHelper){mGetFilesNonRecursiveHelper->Unlink();mGetFilesNonRecursiveHelper=nullptr;}}// Cycle Collection support.voidTraverse(nsCycleCollectionTraversalCallback&cb){FileData*tmp=this;NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFilesOrDirectories)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFileList)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mEntries)if(mGetFilesRecursiveHelper){mGetFilesRecursiveHelper->Traverse(cb);}if(mGetFilesNonRecursiveHelper){mGetFilesNonRecursiveHelper->Traverse(cb);}}voidUnlink(){FileData*tmp=this;NS_IMPL_CYCLE_COLLECTION_UNLINK(mFilesOrDirectories)NS_IMPL_CYCLE_COLLECTION_UNLINK(mFileList)NS_IMPL_CYCLE_COLLECTION_UNLINK(mEntries)ClearGetFilesHelpers();}};HTMLInputElement::nsFilePickerShownCallback::nsFilePickerShownCallback(HTMLInputElement*aInput,nsIFilePicker*aFilePicker):mFilePicker(aFilePicker),mInput(aInput){}NS_IMPL_ISUPPORTS(UploadLastDir::ContentPrefCallback,nsIContentPrefCallback2)NS_IMETHODIMPUploadLastDir::ContentPrefCallback::HandleCompletion(uint16_taReason){nsCOMPtr<nsIFile>localFile;nsAutoStringprefStr;if(aReason==nsIContentPrefCallback2::COMPLETE_ERROR||!mResult){Preferences::GetString("dom.input.fallbackUploadDir",prefStr);}if(prefStr.IsEmpty()&&mResult){nsCOMPtr<nsIVariant>pref;mResult->GetValue(getter_AddRefs(pref));pref->GetAsAString(prefStr);}if(!prefStr.IsEmpty()){localFile=do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);if(localFile&&NS_WARN_IF(NS_FAILED(localFile->InitWithPath(prefStr)))){localFile=nullptr;}}if(localFile){mFilePicker->SetDisplayDirectory(localFile);}else{// If no custom directory was set through the pref, default to// "desktop" directory for each platform.mFilePicker->SetDisplaySpecialDirectory(NS_LITERAL_STRING(NS_OS_DESKTOP_DIR));}mFilePicker->Open(mFpCallback);returnNS_OK;}NS_IMETHODIMPUploadLastDir::ContentPrefCallback::HandleResult(nsIContentPref*pref){mResult=pref;returnNS_OK;}NS_IMETHODIMPUploadLastDir::ContentPrefCallback::HandleError(nsresulterror){// HandleCompletion is always called (even with HandleError was called),// so we don't need to do anything special here.returnNS_OK;}namespace{/** * This may return nullptr if the DOM File's implementation of * File::mozFullPathInternal does not successfully return a non-empty * string that is a valid path. This can happen on Firefox OS, for example, * where the file picker can create Blobs. */staticalready_AddRefed<nsIFile>LastUsedDirectory(constOwningFileOrDirectory&aData){if(aData.IsFile()){nsAutoStringpath;ErrorResulterror;aData.GetAsFile()->GetMozFullPathInternal(path,error);if(error.Failed()||path.IsEmpty()){error.SuppressException();returnnullptr;}nsCOMPtr<nsIFile>localFile;nsresultrv=NS_NewLocalFile(path,true,getter_AddRefs(localFile));if(NS_WARN_IF(NS_FAILED(rv))){returnnullptr;}nsCOMPtr<nsIFile>parentFile;rv=localFile->GetParent(getter_AddRefs(parentFile));if(NS_WARN_IF(NS_FAILED(rv))){returnnullptr;}returnparentFile.forget();}MOZ_ASSERT(aData.IsDirectory());nsCOMPtr<nsIFile>localFile=aData.GetAsDirectory()->GetInternalNsIFile();MOZ_ASSERT(localFile);returnlocalFile.forget();}voidGetDOMFileOrDirectoryName(constOwningFileOrDirectory&aData,nsAString&aName){if(aData.IsFile()){aData.GetAsFile()->GetName(aName);}else{MOZ_ASSERT(aData.IsDirectory());ErrorResultrv;aData.GetAsDirectory()->GetName(aName,rv);if(NS_WARN_IF(rv.Failed())){rv.SuppressException();}}}voidGetDOMFileOrDirectoryPath(constOwningFileOrDirectory&aData,nsAString&aPath,ErrorResult&aRv){if(aData.IsFile()){aData.GetAsFile()->GetMozFullPathInternal(aPath,aRv);}else{MOZ_ASSERT(aData.IsDirectory());aData.GetAsDirectory()->GetFullRealPath(aPath);}}}// namespace/* static */boolHTMLInputElement::ValueAsDateEnabled(JSContext*cx,JSObject*obj){returnIsExperimentalFormsEnabled()||IsInputDateTimeEnabled()||IsInputDateTimeOthersEnabled();}NS_IMETHODIMPHTMLInputElement::nsFilePickerShownCallback::Done(int16_taResult){mInput->PickerClosed();if(aResult==nsIFilePicker::returnCancel){returnNS_OK;}int16_tmode;mFilePicker->GetMode(&mode);// Collect new selected filenamesnsTArray<OwningFileOrDirectory>newFilesOrDirectories;if(mode==static_cast<int16_t>(nsIFilePicker::modeOpenMultiple)){nsCOMPtr<nsISimpleEnumerator>iter;nsresultrv=mFilePicker->GetDomFileOrDirectoryEnumerator(getter_AddRefs(iter));NS_ENSURE_SUCCESS(rv,rv);if(!iter){returnNS_OK;}nsCOMPtr<nsISupports>tmp;boolhasMore=true;while(NS_SUCCEEDED(iter->HasMoreElements(&hasMore))&&hasMore){iter->GetNext(getter_AddRefs(tmp));nsCOMPtr<nsIDOMBlob>domBlob=do_QueryInterface(tmp);MOZ_ASSERT(domBlob,"Null file object from FilePicker's file enumerator?");if(!domBlob){continue;}OwningFileOrDirectory*element=newFilesOrDirectories.AppendElement();element->SetAsFile()=static_cast<File*>(domBlob.get());}}else{MOZ_ASSERT(mode==static_cast<int16_t>(nsIFilePicker::modeOpen)||mode==static_cast<int16_t>(nsIFilePicker::modeGetFolder));nsCOMPtr<nsISupports>tmp;nsresultrv=mFilePicker->GetDomFileOrDirectory(getter_AddRefs(tmp));NS_ENSURE_SUCCESS(rv,rv);nsCOMPtr<nsIDOMBlob>blob=do_QueryInterface(tmp);if(blob){RefPtr<File>file=static_cast<Blob*>(blob.get())->ToFile();MOZ_ASSERT(file);OwningFileOrDirectory*element=newFilesOrDirectories.AppendElement();element->SetAsFile()=file;}elseif(tmp){RefPtr<Directory>directory=static_cast<Directory*>(tmp.get());OwningFileOrDirectory*element=newFilesOrDirectories.AppendElement();element->SetAsDirectory()=directory;}}if(newFilesOrDirectories.IsEmpty()){returnNS_OK;}// Store the last used directory using the content pref service:nsCOMPtr<nsIFile>lastUsedDir=LastUsedDirectory(newFilesOrDirectories[0]);if(lastUsedDir){HTMLInputElement::gUploadLastDir->StoreLastUsedDirectory(mInput->OwnerDoc(),lastUsedDir);}// The text control frame (if there is one) isn't going to send a change// event because it will think this is done by a script.// So, we can safely send one by ourself.mInput->SetFilesOrDirectories(newFilesOrDirectories,true);RefPtr<DispatchChangeEventCallback>dispatchChangeEventCallback=newDispatchChangeEventCallback(mInput);if(IsWebkitDirPickerEnabled()&&mInput->HasAttr(kNameSpaceID_None,nsGkAtoms::webkitdirectory)){ErrorResulterror;GetFilesHelper*helper=mInput->GetOrCreateGetFilesHelper(true,error);if(NS_WARN_IF(error.Failed())){returnerror.StealNSResult();}helper->AddCallback(dispatchChangeEventCallback);returnNS_OK;}returndispatchChangeEventCallback->DispatchEvents();}NS_IMPL_ISUPPORTS(HTMLInputElement::nsFilePickerShownCallback,nsIFilePickerShownCallback)classnsColorPickerShownCallbackfinal:publicnsIColorPickerShownCallback{~nsColorPickerShownCallback(){}public:nsColorPickerShownCallback(HTMLInputElement*aInput,nsIColorPicker*aColorPicker):mInput(aInput),mColorPicker(aColorPicker),mValueChanged(false){}NS_DECL_ISUPPORTSNS_IMETHODUpdate(constnsAString&aColor)override;NS_IMETHODDone(constnsAString&aColor)override;private:/** * Updates the internals of the object using aColor as the new value. * If aTrustedUpdate is true, it will consider that aColor is a new value. * Otherwise, it will check that aColor is different from the current value. */nsresultUpdateInternal(constnsAString&aColor,boolaTrustedUpdate);RefPtr<HTMLInputElement>mInput;nsCOMPtr<nsIColorPicker>mColorPicker;boolmValueChanged;};nsresultnsColorPickerShownCallback::UpdateInternal(constnsAString&aColor,boolaTrustedUpdate){boolvalueChanged=false;nsAutoStringoldValue;if(aTrustedUpdate){valueChanged=true;}else{mInput->GetValue(oldValue,CallerType::System);}IgnoredErrorResultrv;mInput->SetValue(aColor,CallerType::System,rv);if(!aTrustedUpdate){nsAutoStringnewValue;mInput->GetValue(newValue,CallerType::System);if(!oldValue.Equals(newValue)){valueChanged=true;}}if(valueChanged){mValueChanged=true;returnnsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(mInput.get()),NS_LITERAL_STRING("input"),true,false);}returnNS_OK;}NS_IMETHODIMPnsColorPickerShownCallback::Update(constnsAString&aColor){returnUpdateInternal(aColor,true);}NS_IMETHODIMPnsColorPickerShownCallback::Done(constnsAString&aColor){/** * When Done() is called, we might be at the end of a serie of Update() calls * in which case mValueChanged is set to true and a change event will have to * be fired but we might also be in a one shot Done() call situation in which * case we should fire a change event iif the value actually changed. * UpdateInternal(bool) is taking care of that logic for us. */nsresultrv=NS_OK;mInput->PickerClosed();if(!aColor.IsEmpty()){UpdateInternal(aColor,false);}if(mValueChanged){rv=nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(mInput.get()),NS_LITERAL_STRING("change"),true,false);}returnrv;}NS_IMPL_ISUPPORTS(nsColorPickerShownCallback,nsIColorPickerShownCallback)boolHTMLInputElement::IsPopupBlocked()const{nsCOMPtr<nsPIDOMWindowOuter>win=OwnerDoc()->GetWindow();MOZ_ASSERT(win,"window should not be null");if(!win){returntrue;}// Check if page can open a popup without abuse regardless of allowed eventsif(win->GetPopupControlState()<=openBlocked){returnfalse;}nsCOMPtr<nsIPopupWindowManager>pm=do_GetService(NS_POPUPWINDOWMANAGER_CONTRACTID);if(!pm){returntrue;}uint32_tpermission;pm->TestPermission(OwnerDoc()->NodePrincipal(),&permission);returnpermission==nsIPopupWindowManager::DENY_POPUP;}nsresultHTMLInputElement::InitColorPicker(){if(mPickerRunning){NS_WARNING("Just one nsIColorPicker is allowed");returnNS_ERROR_FAILURE;}nsCOMPtr<nsIDocument>doc=OwnerDoc();nsCOMPtr<nsPIDOMWindowOuter>win=doc->GetWindow();if(!win){returnNS_ERROR_FAILURE;}if(IsPopupBlocked()){win->FirePopupBlockedEvent(doc,nullptr,EmptyString(),EmptyString());returnNS_OK;}// Get Loc titlensAutoStringtitle;nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"ColorPicker",title);nsCOMPtr<nsIColorPicker>colorPicker=do_CreateInstance("@mozilla.org/colorpicker;1");if(!colorPicker){returnNS_ERROR_FAILURE;}nsAutoStringinitialValue;GetNonFileValueInternal(initialValue);nsresultrv=colorPicker->Init(win,title,initialValue);NS_ENSURE_SUCCESS(rv,rv);nsCOMPtr<nsIColorPickerShownCallback>callback=newnsColorPickerShownCallback(this,colorPicker);rv=colorPicker->Open(callback);if(NS_SUCCEEDED(rv)){mPickerRunning=true;}returnrv;}nsresultHTMLInputElement::InitFilePicker(FilePickerTypeaType){if(mPickerRunning){NS_WARNING("Just one nsIFilePicker is allowed");returnNS_ERROR_FAILURE;}// Get parent nsPIDOMWindow object.nsCOMPtr<nsIDocument>doc=OwnerDoc();nsCOMPtr<nsPIDOMWindowOuter>win=doc->GetWindow();if(!win){returnNS_ERROR_FAILURE;}if(IsPopupBlocked()){win->FirePopupBlockedEvent(doc,nullptr,EmptyString(),EmptyString());returnNS_OK;}// Get Loc titlensAutoStringtitle;nsAutoStringokButtonLabel;if(aType==FILE_PICKER_DIRECTORY){nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"DirectoryUpload",title);nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"DirectoryPickerOkButtonLabel",okButtonLabel);}else{nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"FileUpload",title);}nsCOMPtr<nsIFilePicker>filePicker=do_CreateInstance("@mozilla.org/filepicker;1");if(!filePicker)returnNS_ERROR_FAILURE;int16_tmode;if(aType==FILE_PICKER_DIRECTORY){mode=static_cast<int16_t>(nsIFilePicker::modeGetFolder);}elseif(HasAttr(kNameSpaceID_None,nsGkAtoms::multiple)){mode=static_cast<int16_t>(nsIFilePicker::modeOpenMultiple);}else{mode=static_cast<int16_t>(nsIFilePicker::modeOpen);}nsresultrv=filePicker->Init(win,title,mode);NS_ENSURE_SUCCESS(rv,rv);if(!okButtonLabel.IsEmpty()){filePicker->SetOkButtonLabel(okButtonLabel);}// Native directory pickers ignore file type filters, so we don't spend// cycles adding them for FILE_PICKER_DIRECTORY.if(HasAttr(kNameSpaceID_None,nsGkAtoms::accept)&&aType!=FILE_PICKER_DIRECTORY){SetFilePickerFiltersFromAccept(filePicker);}else{filePicker->AppendFilters(nsIFilePicker::filterAll);}// Set default directory and filenamensAutoStringdefaultName;constnsTArray<OwningFileOrDirectory>&oldFiles=GetFilesOrDirectoriesInternal();nsCOMPtr<nsIFilePickerShownCallback>callback=newHTMLInputElement::nsFilePickerShownCallback(this,filePicker);if(!oldFiles.IsEmpty()&&aType!=FILE_PICKER_DIRECTORY){nsAutoStringpath;nsCOMPtr<nsIFile>parentFile=LastUsedDirectory(oldFiles[0]);if(parentFile){filePicker->SetDisplayDirectory(parentFile);}// Unfortunately nsIFilePicker doesn't allow multiple files to be// default-selected, so only select something by default if exactly// one file was selected before.if(oldFiles.Length()==1){nsAutoStringleafName;GetDOMFileOrDirectoryName(oldFiles[0],leafName);if(!leafName.IsEmpty()){filePicker->SetDefaultString(leafName);}}rv=filePicker->Open(callback);if(NS_SUCCEEDED(rv)){mPickerRunning=true;}returnrv;}HTMLInputElement::gUploadLastDir->FetchDirectoryAndDisplayPicker(doc,filePicker,callback);mPickerRunning=true;returnNS_OK;}#define CPS_PREF_NAME NS_LITERAL_STRING("browser.upload.lastDir")NS_IMPL_ISUPPORTS(UploadLastDir,nsIObserver,nsISupportsWeakReference)voidHTMLInputElement::InitUploadLastDir(){gUploadLastDir=newUploadLastDir();NS_ADDREF(gUploadLastDir);nsCOMPtr<nsIObserverService>observerService=mozilla::services::GetObserverService();if(observerService&&gUploadLastDir){observerService->AddObserver(gUploadLastDir,"browser:purge-session-history",true);}}voidHTMLInputElement::DestroyUploadLastDir(){NS_IF_RELEASE(gUploadLastDir);}nsresultUploadLastDir::FetchDirectoryAndDisplayPicker(nsIDocument*aDoc,nsIFilePicker*aFilePicker,nsIFilePickerShownCallback*aFpCallback){NS_PRECONDITION(aDoc,"aDoc is null");NS_PRECONDITION(aFilePicker,"aFilePicker is null");NS_PRECONDITION(aFpCallback,"aFpCallback is null");nsIURI*docURI=aDoc->GetDocumentURI();NS_PRECONDITION(docURI,"docURI is null");nsCOMPtr<nsILoadContext>loadContext=aDoc->GetLoadContext();nsCOMPtr<nsIContentPrefCallback2>prefCallback=newUploadLastDir::ContentPrefCallback(aFilePicker,aFpCallback);// Attempt to get the CPS, if it's not present we'll fallback to use the Desktop foldernsCOMPtr<nsIContentPrefService2>contentPrefService=do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);if(!contentPrefService){prefCallback->HandleCompletion(nsIContentPrefCallback2::COMPLETE_ERROR);returnNS_OK;}nsAutoCStringcstrSpec;docURI->GetSpec(cstrSpec);NS_ConvertUTF8toUTF16spec(cstrSpec);contentPrefService->GetByDomainAndName(spec,CPS_PREF_NAME,loadContext,prefCallback);returnNS_OK;}nsresultUploadLastDir::StoreLastUsedDirectory(nsIDocument*aDoc,nsIFile*aDir){NS_PRECONDITION(aDoc,"aDoc is null");if(!aDir){returnNS_OK;}nsCOMPtr<nsIURI>docURI=aDoc->GetDocumentURI();NS_PRECONDITION(docURI,"docURI is null");// Attempt to get the CPS, if it's not present we'll just returnnsCOMPtr<nsIContentPrefService2>contentPrefService=do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);if(!contentPrefService)returnNS_ERROR_NOT_AVAILABLE;nsAutoCStringcstrSpec;docURI->GetSpec(cstrSpec);NS_ConvertUTF8toUTF16spec(cstrSpec);// Find the parent of aFile, and store itnsStringunicodePath;aDir->GetPath(unicodePath);if(unicodePath.IsEmpty())// nothing to doreturnNS_OK;RefPtr<nsVariantCC>prefValue=newnsVariantCC();prefValue->SetAsAString(unicodePath);// Use the document's current load context to ensure that the content pref// service doesn't persistently store this directory for this domain if the// user is using private browsing:nsCOMPtr<nsILoadContext>loadContext=aDoc->GetLoadContext();returncontentPrefService->Set(spec,CPS_PREF_NAME,prefValue,loadContext,nullptr);}NS_IMETHODIMPUploadLastDir::Observe(nsISupports*aSubject,charconst*aTopic,char16_tconst*aData){if(strcmp(aTopic,"browser:purge-session-history")==0){nsCOMPtr<nsIContentPrefService2>contentPrefService=do_GetService(NS_CONTENT_PREF_SERVICE_CONTRACTID);if(contentPrefService)contentPrefService->RemoveByName(CPS_PREF_NAME,nullptr,nullptr);}returnNS_OK;}#ifdef ACCESSIBILITY//Helper methodstaticnsresultFireEventForAccessibility(nsIDOMHTMLInputElement*aTarget,nsPresContext*aPresContext,EventMessageaEventMessage);#endifnsTextEditorState*HTMLInputElement::sCachedTextEditorState=nullptr;boolHTMLInputElement::sShutdown=false;/* static */voidHTMLInputElement::ReleaseTextEditorState(nsTextEditorState*aState){if(!sShutdown&&!sCachedTextEditorState){aState->PrepareForReuse();sCachedTextEditorState=aState;}else{deleteaState;}}/* static */voidHTMLInputElement::Shutdown(){sShutdown=true;deletesCachedTextEditorState;sCachedTextEditorState=nullptr;}//// construction, destruction//HTMLInputElement::HTMLInputElement(already_AddRefed<mozilla::dom::NodeInfo>&aNodeInfo,FromParseraFromParser,FromCloneaFromClone):nsGenericHTMLFormElementWithState(aNodeInfo,kInputDefaultType->value),mAutocompleteAttrState(nsContentUtils::eAutocompleteAttrState_Unknown),mAutocompleteInfoState(nsContentUtils::eAutocompleteAttrState_Unknown),mDisabledChanged(false),mValueChanged(false),mLastValueChangeWasInteractive(false),mCheckedChanged(false),mChecked(false),mHandlingSelectEvent(false),mShouldInitChecked(false),mDoneCreating(aFromParser==NOT_FROM_PARSER&&aFromClone==FromClone::no),mInInternalActivate(false),mCheckedIsToggled(false),mIndeterminate(false),mInhibitRestoration(aFromParser&FROM_PARSER_FRAGMENT),mCanShowValidUI(true),mCanShowInvalidUI(true),mHasRange(false),mIsDraggingRange(false),mNumberControlSpinnerIsSpinning(false),mNumberControlSpinnerSpinsUp(false),mPickerRunning(false),mSelectionCached(true),mIsPreviewEnabled(false),mHasPatternAttribute(false){// If size is above 512, mozjemalloc allocates 1kB, see// memory/mozjemalloc/jemalloc.cstatic_assert(sizeof(HTMLInputElement)<=512,"Keep the size of HTMLInputElement under 512 to avoid ""performance regression!");// We are in a type=text so we now we currenty need a nsTextEditorState.mInputData.mState=nsTextEditorState::Construct(this,&sCachedTextEditorState);void*memory=mInputTypeMem;mInputType=InputType::Create(this,mType,memory);if(!gUploadLastDir)HTMLInputElement::InitUploadLastDir();// Set up our default state. By default we're enabled (since we're// a control type that can be disabled but not actually disabled// right now), optional, and valid. We are NOT readwrite by default// until someone calls UpdateEditableState on us, apparently! Also// by default we don't have to show validity UI and so forth.AddStatesSilently(NS_EVENT_STATE_ENABLED|NS_EVENT_STATE_OPTIONAL|NS_EVENT_STATE_VALID);UpdateApzAwareFlag();}HTMLInputElement::~HTMLInputElement(){if(mNumberControlSpinnerIsSpinning){StopNumberControlSpinnerSpin(eDisallowDispatchingEvents);}DestroyImageLoadingContent();FreeData();}voidHTMLInputElement::FreeData(){if(!IsSingleLineTextControl(false)){free(mInputData.mValue);mInputData.mValue=nullptr;}else{UnbindFromFrame(nullptr);ReleaseTextEditorState(mInputData.mState);mInputData.mState=nullptr;}if(mInputType){mInputType->DropReference();mInputType=nullptr;}}nsTextEditorState*HTMLInputElement::GetEditorState()const{if(!IsSingleLineTextControl(false)){returnnullptr;}MOZ_ASSERT(mInputData.mState,"Single line text controls need to have a state"" associated with them");returnmInputData.mState;}// nsISupportsNS_IMPL_CYCLE_COLLECTION_CLASS(HTMLInputElement)NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(HTMLInputElement,nsGenericHTMLFormElementWithState)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mValidity)NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControllers)if(tmp->IsSingleLineTextControl(false)){tmp->mInputData.mState->Traverse(cb);}if(tmp->mFileData){tmp->mFileData->Traverse(cb);}NS_IMPL_CYCLE_COLLECTION_TRAVERSE_ENDNS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(HTMLInputElement,nsGenericHTMLFormElementWithState)NS_IMPL_CYCLE_COLLECTION_UNLINK(mValidity)NS_IMPL_CYCLE_COLLECTION_UNLINK(mControllers)if(tmp->IsSingleLineTextControl(false)){tmp->mInputData.mState->Unlink();}if(tmp->mFileData){tmp->mFileData->Unlink();}//XXX should unlink more?NS_IMPL_CYCLE_COLLECTION_UNLINK_ENDNS_IMPL_ADDREF_INHERITED(HTMLInputElement,Element)NS_IMPL_RELEASE_INHERITED(HTMLInputElement,Element)// QueryInterface implementation for HTMLInputElementNS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLInputElement)NS_INTERFACE_TABLE_INHERITED(HTMLInputElement,nsIDOMHTMLInputElement,nsITextControlElement,imgINotificationObserver,nsIImageLoadingContent,imgIOnloadBlocker,nsIDOMNSEditableElement,nsIConstraintValidation)NS_INTERFACE_TABLE_TAIL_INHERITING(nsGenericHTMLFormElementWithState)// nsIDOMNodensresultHTMLInputElement::Clone(mozilla::dom::NodeInfo*aNodeInfo,nsINode**aResult,boolaPreallocateArrays)const{*aResult=nullptr;already_AddRefed<mozilla::dom::NodeInfo>ni=RefPtr<mozilla::dom::NodeInfo>(aNodeInfo).forget();RefPtr<HTMLInputElement>it=newHTMLInputElement(ni,NOT_FROM_PARSER,FromClone::yes);nsresultrv=const_cast<HTMLInputElement*>(this)->CopyInnerTo(it,aPreallocateArrays);NS_ENSURE_SUCCESS(rv,rv);switch(GetValueMode()){caseVALUE_MODE_VALUE:if(mValueChanged){// We don't have our default value anymore. Set our value on// the clone.nsAutoStringvalue;GetNonFileValueInternal(value);// SetValueInternal handles setting the VALUE_CHANGED bit for usrv=it->SetValueInternal(value,nsTextEditorState::eSetValue_Notify);NS_ENSURE_SUCCESS(rv,rv);}break;caseVALUE_MODE_FILENAME:if(it->OwnerDoc()->IsStaticDocument()){// We're going to be used in print preview. Since the doc is static// we can just grab the pretty string and use it as wallpaperGetDisplayFileName(it->mFileData->mStaticDocFileList);}else{it->mFileData->ClearGetFilesHelpers();it->mFileData->mFilesOrDirectories.Clear();it->mFileData->mFilesOrDirectories.AppendElements(mFileData->mFilesOrDirectories);}break;caseVALUE_MODE_DEFAULT_ON:if(mCheckedChanged){// We no longer have our original checked state. Set our// checked state on the clone.it->DoSetChecked(mChecked,false,true);// Then tell DoneCreatingElement() not to overwrite:it->mShouldInitChecked=false;}break;caseVALUE_MODE_DEFAULT:if(mType==NS_FORM_INPUT_IMAGE&&it->OwnerDoc()->IsStaticDocument()){CreateStaticImageClone(it);}break;}it->DoneCreatingElement();it->mLastValueChangeWasInteractive=mLastValueChangeWasInteractive;it.forget(aResult);returnNS_OK;}nsresultHTMLInputElement::BeforeSetAttr(int32_taNameSpaceID,nsIAtom*aName,constnsAttrValueOrString*aValue,boolaNotify){if(aNameSpaceID==kNameSpaceID_None){//// When name or type changes, radio should be removed from radio group.// (type changes are handled in the form itself currently)// If we are not done creating the radio, we also should not do it.//if((aName==nsGkAtoms::name||(aName==nsGkAtoms::type&&!mForm))&&mType==NS_FORM_INPUT_RADIO&&(mForm||mDoneCreating)){WillRemoveFromRadioGroup();}elseif(aNotify&&aName==nsGkAtoms::src&&mType==NS_FORM_INPUT_IMAGE){if(aValue){// Mark channel as urgent-start before load image if the image load is// initaiated by a user interaction.mUseUrgentStartForChannel=EventStateManager::IsHandlingUserInput();LoadImage(aValue->String(),true,aNotify,eImageLoadType_Normal);}else{// Null value means the attr got unset; drop the imageCancelImageRequests(aNotify);}}elseif(aNotify&&aName==nsGkAtoms::disabled){mDisabledChanged=true;}elseif(mType==NS_FORM_INPUT_RADIO&&aName==nsGkAtoms::required){nsCOMPtr<nsIRadioGroupContainer>container=GetRadioGroupContainer();if(container&&((aValue&&!HasAttr(aNameSpaceID,aName))||(!aValue&&HasAttr(aNameSpaceID,aName)))){nsAutoStringname;GetAttr(kNameSpaceID_None,nsGkAtoms::name,name);container->RadioRequiredWillChange(name,!!aValue);}}if(aName==nsGkAtoms::webkitdirectory){Telemetry::Accumulate(Telemetry::WEBKIT_DIRECTORY_USED,true);}}returnnsGenericHTMLFormElementWithState::BeforeSetAttr(aNameSpaceID,aName,aValue,aNotify);}nsresultHTMLInputElement::AfterSetAttr(int32_taNameSpaceID,nsIAtom*aName,constnsAttrValue*aValue,constnsAttrValue*aOldValue,boolaNotify){if(aNameSpaceID==kNameSpaceID_None){//// When name or type changes, radio should be added to radio group.// (type changes are handled in the form itself currently)// If we are not done creating the radio, we also should not do it.//if((aName==nsGkAtoms::name||(aName==nsGkAtoms::type&&!mForm))&&mType==NS_FORM_INPUT_RADIO&&(mForm||mDoneCreating)){AddedToRadioGroup();UpdateValueMissingValidityStateForRadio(false);}// If @value is changed and BF_VALUE_CHANGED is false, @value is the value// of the element so, if the value of the element is different than @value,// we have to re-set it. This is only the case when GetValueMode() returns// VALUE_MODE_VALUE.if(aName==nsGkAtoms::value&&!mValueChanged&&GetValueMode()==VALUE_MODE_VALUE){SetDefaultValueAsValue();}//// Checked must be set no matter what type of control it is, since// mChecked must reflect the new valueif(aName==nsGkAtoms::checked&&!mCheckedChanged){// Delay setting checked if we are creating this element (wait// until everything is set)if(!mDoneCreating){mShouldInitChecked=true;}else{DoSetChecked(DefaultChecked(),true,false);}}if(aName==nsGkAtoms::type){uint8_tnewType;if(!aValue){// We're now a text input.newType=kInputDefaultType->value;}else{newType=aValue->GetEnumValue();}if(newType!=mType){HandleTypeChange(newType,aNotify);}}if(aName==nsGkAtoms::required||aName==nsGkAtoms::disabled||aName==nsGkAtoms::readonly){if(aName==nsGkAtoms::disabled){// This *has* to be called *before* validity state check because// UpdateBarredFromConstraintValidation and// UpdateValueMissingValidityState depend on our disabled state.UpdateDisabledState(aNotify);}if(aName==nsGkAtoms::required&&DoesRequiredApply()){// This *has* to be called *before* UpdateValueMissingValidityState// because UpdateValueMissingValidityState depends on our required// state.UpdateRequiredState(!!aValue,aNotify);}UpdateValueMissingValidityState();// This *has* to be called *after* validity has changed.if(aName==nsGkAtoms::readonly||aName==nsGkAtoms::disabled){UpdateBarredFromConstraintValidation();}}elseif(aName==nsGkAtoms::maxlength){UpdateTooLongValidityState();}elseif(aName==nsGkAtoms::minlength){UpdateTooShortValidityState();}elseif(aName==nsGkAtoms::pattern){// Although pattern attribute only applies to single line text controls,// we set this flag for all input types to save having to check the type// here.mHasPatternAttribute=!!aValue;if(mDoneCreating){UpdatePatternMismatchValidityState();}}elseif(aName==nsGkAtoms::multiple){UpdateTypeMismatchValidityState();}elseif(aName==nsGkAtoms::max){UpdateHasRange();nsresultrv=mInputType->MinMaxStepAttrChanged();NS_ENSURE_SUCCESS(rv,rv);// Validity state must be updated *after* the UpdateValueDueToAttrChange// call above or else the following assert will not be valid.// We don't assert the state of underflow during creation since// DoneCreatingElement sanitizes.UpdateRangeOverflowValidityState();MOZ_ASSERT(!mDoneCreating||mType!=NS_FORM_INPUT_RANGE||!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),"HTML5 spec does not allow underflow for type=range");}elseif(aName==nsGkAtoms::min){UpdateHasRange();nsresultrv=mInputType->MinMaxStepAttrChanged();NS_ENSURE_SUCCESS(rv,rv);// See corresponding @max commentUpdateRangeUnderflowValidityState();UpdateStepMismatchValidityState();MOZ_ASSERT(!mDoneCreating||mType!=NS_FORM_INPUT_RANGE||!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),"HTML5 spec does not allow underflow for type=range");}elseif(aName==nsGkAtoms::step){nsresultrv=mInputType->MinMaxStepAttrChanged();NS_ENSURE_SUCCESS(rv,rv);// See corresponding @max commentUpdateStepMismatchValidityState();MOZ_ASSERT(!mDoneCreating||mType!=NS_FORM_INPUT_RANGE||!GetValidityState(VALIDITY_STATE_RANGE_UNDERFLOW),"HTML5 spec does not allow underflow for type=range");}elseif(aName==nsGkAtoms::dir&&aValue&&aValue->Equals(nsGkAtoms::_auto,eIgnoreCase)){SetDirectionFromValue(aNotify);}elseif(aName==nsGkAtoms::lang){if(mType==NS_FORM_INPUT_NUMBER){// Update the value that is displayed to the user to the new locale:nsAutoStringvalue;GetNonFileValueInternal(value);nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){numberControlFrame->SetValueOfAnonTextControl(value);}}}elseif(aName==nsGkAtoms::autocomplete){// Clear the cached @autocomplete attribute and autocompleteInfo state.mAutocompleteAttrState=nsContentUtils::eAutocompleteAttrState_Unknown;mAutocompleteInfoState=nsContentUtils::eAutocompleteAttrState_Unknown;}}returnnsGenericHTMLFormElementWithState::AfterSetAttr(aNameSpaceID,aName,aValue,aOldValue,aNotify);}voidHTMLInputElement::BeforeSetForm(boolaBindToTree){// No need to remove from radio group if we are just binding to tree.if(mType==NS_FORM_INPUT_RADIO&&!aBindToTree){WillRemoveFromRadioGroup();}}voidHTMLInputElement::AfterClearForm(boolaUnbindOrDelete){MOZ_ASSERT(!mForm);// Do not add back to radio group if we are releasing or unbinding from tree.if(mType==NS_FORM_INPUT_RADIO&&!aUnbindOrDelete){AddedToRadioGroup();UpdateValueMissingValidityStateForRadio(false);}}// nsIDOMHTMLInputElementNS_IMETHODIMPHTMLInputElement::GetForm(nsIDOMHTMLFormElement**aForm){returnnsGenericHTMLFormElementWithState::GetForm(aForm);}NS_IMPL_ACTION_ATTR(HTMLInputElement,FormAction,formaction)NS_IMPL_STRING_ATTR(HTMLInputElement,Name,name)NS_IMPL_BOOL_ATTR(HTMLInputElement,ReadOnly,readonly)NS_IMETHODIMPHTMLInputElement::GetAutocomplete(nsAString&aValue){if(!DoesAutocompleteApply()){returnNS_OK;}aValue.Truncate();constnsAttrValue*attributeVal=GetParsedAttr(nsGkAtoms::autocomplete);mAutocompleteAttrState=nsContentUtils::SerializeAutocompleteAttribute(attributeVal,aValue,mAutocompleteAttrState);returnNS_OK;}voidHTMLInputElement::GetAutocompleteInfo(Nullable<AutocompleteInfo>&aInfo){if(!DoesAutocompleteApply()){aInfo.SetNull();return;}constnsAttrValue*attributeVal=GetParsedAttr(nsGkAtoms::autocomplete);mAutocompleteInfoState=nsContentUtils::SerializeAutocompleteAttribute(attributeVal,aInfo.SetValue(),mAutocompleteInfoState,true);}voidHTMLInputElement::GetFormEnctype(nsAString&aValue){GetEnumAttr(nsGkAtoms::formenctype,"",kFormDefaultEnctype->tag,aValue);}voidHTMLInputElement::GetFormMethod(nsAString&aValue){GetEnumAttr(nsGkAtoms::formmethod,"",kFormDefaultMethod->tag,aValue);}voidHTMLInputElement::GetInputMode(nsAString&aValue){GetEnumAttr(nsGkAtoms::inputmode,kInputDefaultInputmode->tag,aValue);}voidHTMLInputElement::GetType(nsAString&aValue){GetEnumAttr(nsGkAtoms::type,kInputDefaultType->tag,aValue);}int32_tHTMLInputElement::TabIndexDefault(){return0;}uint32_tHTMLInputElement::Height(){if(mType!=NS_FORM_INPUT_IMAGE){return0;}returnGetWidthHeightForImage(mCurrentRequest).height;}NS_IMETHODIMPHTMLInputElement::GetIndeterminate(bool*aValue){*aValue=Indeterminate();returnNS_OK;}voidHTMLInputElement::SetIndeterminateInternal(boolaValue,boolaShouldInvalidate){mIndeterminate=aValue;if(aShouldInvalidate){// Repaint the framensIFrame*frame=GetPrimaryFrame();if(frame)frame->InvalidateFrameSubtree();}UpdateState(true);}NS_IMETHODIMPHTMLInputElement::SetIndeterminate(boolaValue){SetIndeterminateInternal(aValue,true);returnNS_OK;}uint32_tHTMLInputElement::Width(){if(mType!=NS_FORM_INPUT_IMAGE){return0;}returnGetWidthHeightForImage(mCurrentRequest).width;}voidHTMLInputElement::GetValue(nsAString&aValue,CallerTypeaCallerType){GetValueInternal(aValue,aCallerType);// Don't return non-sanitized value for types that are experimental on mobile// or datetime typesif(IsExperimentalMobileType(mType)||IsDateTimeInputType(mType)){SanitizeValue(aValue);}}voidHTMLInputElement::GetValueInternal(nsAString&aValue,CallerTypeaCallerType)const{if(mType!=NS_FORM_INPUT_FILE){GetNonFileValueInternal(aValue);return;}if(aCallerType==CallerType::System){aValue.Assign(mFileData->mFirstFilePath);return;}if(mFileData->mFilesOrDirectories.IsEmpty()){aValue.Truncate();return;}nsAutoStringfile;GetDOMFileOrDirectoryName(mFileData->mFilesOrDirectories[0],file);if(file.IsEmpty()){aValue.Truncate();return;}aValue.AssignLiteral("C:\\fakepath\\");aValue.Append(file);}voidHTMLInputElement::GetNonFileValueInternal(nsAString&aValue)const{switch(GetValueMode()){caseVALUE_MODE_VALUE:if(IsSingleLineTextControl(false)){mInputData.mState->GetValue(aValue,true);}elseif(!aValue.Assign(mInputData.mValue,fallible)){aValue.Truncate();}return;caseVALUE_MODE_FILENAME:NS_NOTREACHED("Someone screwed up here");// We'll just return empty string if someone does screw up.aValue.Truncate();return;caseVALUE_MODE_DEFAULT:// Treat defaultValue as value.GetAttr(kNameSpaceID_None,nsGkAtoms::value,aValue);return;caseVALUE_MODE_DEFAULT_ON:// Treat default value as value and returns "on" if no value.if(!GetAttr(kNameSpaceID_None,nsGkAtoms::value,aValue)){aValue.AssignLiteral("on");}return;}}boolHTMLInputElement::IsValueEmpty()const{if(GetValueMode()==VALUE_MODE_VALUE&&IsSingleLineTextControl(false)){return!mInputData.mState->HasNonEmptyValue();}nsAutoStringvalue;GetNonFileValueInternal(value);returnvalue.IsEmpty();}voidHTMLInputElement::ClearFiles(boolaSetValueChanged){nsTArray<OwningFileOrDirectory>data;SetFilesOrDirectories(data,aSetValueChanged);}int32_tHTMLInputElement::MonthsSinceJan1970(uint32_taYear,uint32_taMonth)const{return(aYear-1970)*12+aMonth-1;}/* static */DecimalHTMLInputElement::StringToDecimal(constnsAString&aValue){if(!IsASCII(aValue)){returnDecimal::nan();}NS_LossyConvertUTF16toASCIIasciiString(aValue);std::stringstdString=asciiString.get();returnDecimal::fromString(stdString);}DecimalHTMLInputElement::GetValueAsDecimal()const{DecimaldecimalValue;nsAutoStringstringValue;GetNonFileValueInternal(stringValue);return!mInputType->ConvertStringToNumber(stringValue,decimalValue)?Decimal::nan():decimalValue;}voidHTMLInputElement::SetValue(constnsAString&aValue,CallerTypeaCallerType,ErrorResult&aRv){// check security. Note that setting the value to the empty string is always// OK and gives pages a way to clear a file input if necessary.if(mType==NS_FORM_INPUT_FILE){if(!aValue.IsEmpty()){if(aCallerType!=CallerType::System){// setting the value of a "FILE" input widget requires// chrome privilegeaRv.Throw(NS_ERROR_DOM_SECURITY_ERR);return;}Sequence<nsString>list;if(!list.AppendElement(aValue,fallible)){aRv.Throw(NS_ERROR_OUT_OF_MEMORY);return;}MozSetFileNameArray(list,aRv);return;}else{ClearFiles(true);}}else{if(MayFireChangeOnBlur()){// If the value has been set by a script, we basically want to keep the// current change event state. If the element is ready to fire a change// event, we should keep it that way. Otherwise, we should make sure the// element will not fire any event because of the script interaction.//// NOTE: this is currently quite expensive work (too much string// manipulation). We should probably optimize that.nsAutoStringcurrentValue;GetValue(currentValue,aCallerType);// Some types sanitize value, so GetValue doesn't return pure// previous value correctly.nsresultrv=SetValueInternal(aValue,(IsExperimentalMobileType(mType)||IsDateTimeInputType(mType))?nullptr:&currentValue,nsTextEditorState::eSetValue_ByContent|nsTextEditorState::eSetValue_Notify|nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);if(NS_FAILED(rv)){aRv.Throw(rv);return;}if(mFocusedValue.Equals(currentValue)){GetValue(mFocusedValue,aCallerType);}}else{nsresultrv=SetValueInternal(aValue,nsTextEditorState::eSetValue_ByContent|nsTextEditorState::eSetValue_Notify|nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);if(NS_FAILED(rv)){aRv.Throw(rv);return;}}}}nsGenericHTMLElement*HTMLInputElement::GetList()const{nsAutoStringdataListId;GetAttr(kNameSpaceID_None,nsGkAtoms::list,dataListId);if(dataListId.IsEmpty()){returnnullptr;}//XXXsmaug How should this all work in case input element is in Shadow DOM.nsIDocument*doc=GetUncomposedDoc();if(!doc){returnnullptr;}Element*element=doc->GetElementById(dataListId);if(!element||!element->IsHTMLElement(nsGkAtoms::datalist)){returnnullptr;}returnstatic_cast<nsGenericHTMLElement*>(element);}NS_IMETHODIMPHTMLInputElement::GetList(nsIDOMHTMLElement**aValue){*aValue=nullptr;RefPtr<nsGenericHTMLElement>element=GetList();if(!element){returnNS_OK;}element.forget(aValue);returnNS_OK;}voidHTMLInputElement::SetValue(DecimalaValue,CallerTypeaCallerType){MOZ_ASSERT(!aValue.isInfinity(),"aValue must not be Infinity!");if(aValue.isNaN()){IgnoredErrorResultrv;SetValue(EmptyString(),aCallerType,rv);return;}nsAutoStringvalue;mInputType->ConvertNumberToString(aValue,value);IgnoredErrorResultrv;SetValue(value,aCallerType,rv);}Nullable<Date>HTMLInputElement::GetValueAsDate(ErrorResult&aRv){if(!IsDateTimeInputType(mType)){returnNullable<Date>();}switch(mType){caseNS_FORM_INPUT_DATE:{uint32_tyear,month,day;nsAutoStringvalue;GetNonFileValueInternal(value);if(!ParseDate(value,&year,&month,&day)){returnNullable<Date>();}JS::ClippedTimetime=JS::TimeClip(JS::MakeDate(year,month-1,day));returnNullable<Date>(Date(time));}caseNS_FORM_INPUT_TIME:{uint32_tmillisecond;nsAutoStringvalue;GetNonFileValueInternal(value);if(!ParseTime(value,&millisecond)){returnNullable<Date>();}JS::ClippedTimetime=JS::TimeClip(millisecond);MOZ_ASSERT(time.toDouble()==millisecond,"HTML times are restricted to the day after the epoch and ""never clip");returnNullable<Date>(Date(time));}caseNS_FORM_INPUT_MONTH:{uint32_tyear,month;nsAutoStringvalue;GetNonFileValueInternal(value);if(!ParseMonth(value,&year,&month)){returnNullable<Date>();}JS::ClippedTimetime=JS::TimeClip(JS::MakeDate(year,month-1,1));returnNullable<Date>(Date(time));}caseNS_FORM_INPUT_WEEK:{uint32_tyear,week;nsAutoStringvalue;GetNonFileValueInternal(value);if(!ParseWeek(value,&year,&week)){returnNullable<Date>();}doubledays=DaysSinceEpochFromWeek(year,week);JS::ClippedTimetime=JS::TimeClip(days*kMsPerDay);returnNullable<Date>(Date(time));}caseNS_FORM_INPUT_DATETIME_LOCAL:{uint32_tyear,month,day,timeInMs;nsAutoStringvalue;GetNonFileValueInternal(value);if(!ParseDateTimeLocal(value,&year,&month,&day,&timeInMs)){returnNullable<Date>();}JS::ClippedTimetime=JS::TimeClip(JS::MakeDate(year,month-1,day,timeInMs));returnNullable<Date>(Date(time));}}MOZ_ASSERT(false,"Unrecognized input type");aRv.Throw(NS_ERROR_UNEXPECTED);returnNullable<Date>();}voidHTMLInputElement::SetValueAsDate(constNullable<Date>&aDate,ErrorResult&aRv){if(!IsDateTimeInputType(mType)){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}// At this point we know we're not a file input, so we can just pass "not// system" as the caller type, since the caller type only matters in the file// input case.if(aDate.IsNull()||aDate.Value().IsUndefined()){SetValue(EmptyString(),CallerType::NonSystem,aRv);return;}doublemilliseconds=aDate.Value().TimeStamp().toDouble();if(mType!=NS_FORM_INPUT_MONTH){SetValue(Decimal::fromDouble(milliseconds),CallerType::NonSystem);return;}// type=month expects the value to be number of months.doubleyear=JS::YearFromTime(milliseconds);doublemonth=JS::MonthFromTime(milliseconds);if(IsNaN(year)||IsNaN(month)){SetValue(EmptyString(),CallerType::NonSystem,aRv);return;}int32_tmonths=MonthsSinceJan1970(year,month+1);SetValue(Decimal(int32_t(months)),CallerType::NonSystem);}voidHTMLInputElement::SetValueAsNumber(doubleaValueAsNumber,ErrorResult&aRv){// TODO: return TypeError when HTMLInputElement is converted to WebIDL, see// bug 825197.if(IsInfinite(aValueAsNumber)){aRv.Throw(NS_ERROR_INVALID_ARG);return;}if(!DoesValueAsNumberApply()){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}// At this point we know we're not a file input, so we can just pass "not// system" as the caller type, since the caller type only matters in the file// input case.SetValue(Decimal::fromDouble(aValueAsNumber),CallerType::NonSystem);}DecimalHTMLInputElement::GetMinimum()const{MOZ_ASSERT(DoesValueAsNumberApply(),"GetMinimum() should only be used for types that allow .valueAsNumber");// Only type=range has a default minimumDecimaldefaultMinimum=mType==NS_FORM_INPUT_RANGE?Decimal(0):Decimal::nan();if(!HasAttr(kNameSpaceID_None,nsGkAtoms::min)){returndefaultMinimum;}nsAutoStringminStr;GetAttr(kNameSpaceID_None,nsGkAtoms::min,minStr);Decimalmin;returnmInputType->ConvertStringToNumber(minStr,min)?min:defaultMinimum;}DecimalHTMLInputElement::GetMaximum()const{MOZ_ASSERT(DoesValueAsNumberApply(),"GetMaximum() should only be used for types that allow .valueAsNumber");// Only type=range has a default maximumDecimaldefaultMaximum=mType==NS_FORM_INPUT_RANGE?Decimal(100):Decimal::nan();if(!HasAttr(kNameSpaceID_None,nsGkAtoms::max)){returndefaultMaximum;}nsAutoStringmaxStr;GetAttr(kNameSpaceID_None,nsGkAtoms::max,maxStr);Decimalmax;returnmInputType->ConvertStringToNumber(maxStr,max)?max:defaultMaximum;}DecimalHTMLInputElement::GetStepBase()const{MOZ_ASSERT(IsDateTimeInputType(mType)||mType==NS_FORM_INPUT_NUMBER||mType==NS_FORM_INPUT_RANGE,"Check that kDefaultStepBase is correct for this new type");DecimalstepBase;// Do NOT use GetMinimum here - the spec says to use "the min content// attribute", not "the minimum".nsAutoStringminStr;if(GetAttr(kNameSpaceID_None,nsGkAtoms::min,minStr)&&mInputType->ConvertStringToNumber(minStr,stepBase)){returnstepBase;}// If @min is not a double, we should use @value.nsAutoStringvalueStr;if(GetAttr(kNameSpaceID_None,nsGkAtoms::value,valueStr)&&mInputType->ConvertStringToNumber(valueStr,stepBase)){returnstepBase;}if(mType==NS_FORM_INPUT_WEEK){returnkDefaultStepBaseWeek;}returnkDefaultStepBase;}nsresultHTMLInputElement::GetValueIfStepped(int32_taStep,StepCallerTypeaCallerType,Decimal*aNextStep){if(!DoStepDownStepUpApply()){returnNS_ERROR_DOM_INVALID_STATE_ERR;}DecimalstepBase=GetStepBase();Decimalstep=GetStep();if(step==kStepAny){if(aCallerType!=CALLED_FOR_USER_EVENT){returnNS_ERROR_DOM_INVALID_STATE_ERR;}// Allow the spin buttons and up/down arrow keys to do something sensible:step=GetDefaultStep();}Decimalminimum=GetMinimum();Decimalmaximum=GetMaximum();if(!maximum.isNaN()){// "max - (max - stepBase) % step" is the nearest valid value to max.maximum=maximum-NS_floorModulo(maximum-stepBase,step);if(!minimum.isNaN()){if(minimum>maximum){// Either the minimum was greater than the maximum prior to our// adjustment to align maximum on a step, or else (if we adjusted// maximum) there is no valid step between minimum and the unadjusted// maximum.returnNS_OK;}}}Decimalvalue=GetValueAsDecimal();boolvalueWasNaN=false;if(value.isNaN()){value=Decimal(0);valueWasNaN=true;}DecimalvalueBeforeStepping=value;DecimaldeltaFromStep=NS_floorModulo(value-stepBase,step);if(deltaFromStep!=Decimal(0)){if(aStep>0){value+=step-deltaFromStep;// partial stepvalue+=step*Decimal(aStep-1);// then remaining steps}elseif(aStep<0){value-=deltaFromStep;// partial stepvalue+=step*Decimal(aStep+1);// then remaining steps}}else{value+=step*Decimal(aStep);}if(value<minimum){value=minimum;deltaFromStep=NS_floorModulo(value-stepBase,step);if(deltaFromStep!=Decimal(0)){value+=step-deltaFromStep;}}if(value>maximum){value=maximum;deltaFromStep=NS_floorModulo(value-stepBase,step);if(deltaFromStep!=Decimal(0)){value-=deltaFromStep;}}if(!valueWasNaN&&// value="", resulting in us using "0"((aStep>0&&value<valueBeforeStepping)||(aStep<0&&value>valueBeforeStepping))){// We don't want step-up to effectively step down, or step-down to// effectively step up, so return;returnNS_OK;}*aNextStep=value;returnNS_OK;}nsresultHTMLInputElement::ApplyStep(int32_taStep){DecimalnextStep=Decimal::nan();// unchanged if value will not changensresultrv=GetValueIfStepped(aStep,CALLED_FOR_SCRIPT,&nextStep);if(NS_SUCCEEDED(rv)&&nextStep.isFinite()){// We know we're not a file input, so the caller type does not matter; just// pass "not system" to be safe.SetValue(nextStep,CallerType::NonSystem);}returnrv;}/* static */boolHTMLInputElement::IsExperimentalMobileType(uint8_taType){return(aType==NS_FORM_INPUT_DATE||aType==NS_FORM_INPUT_TIME)&&!IsInputDateTimeEnabled();}boolHTMLInputElement::IsDateTimeInputType(uint8_taType){returnaType==NS_FORM_INPUT_DATE||aType==NS_FORM_INPUT_TIME||aType==NS_FORM_INPUT_MONTH||aType==NS_FORM_INPUT_WEEK||aType==NS_FORM_INPUT_DATETIME_LOCAL;}voidHTMLInputElement::FlushFrames(){if(GetComposedDoc()){GetComposedDoc()->FlushPendingNotifications(FlushType::Frames);}}voidHTMLInputElement::MozGetFileNameArray(nsTArray<nsString>&aArray,ErrorResult&aRv){if(NS_WARN_IF(mType!=NS_FORM_INPUT_FILE)){return;}constnsTArray<OwningFileOrDirectory>&filesOrDirs=GetFilesOrDirectoriesInternal();for(uint32_ti=0;i<filesOrDirs.Length();i++){nsAutoStringstr;GetDOMFileOrDirectoryPath(filesOrDirs[i],str,aRv);if(NS_WARN_IF(aRv.Failed())){return;}aArray.AppendElement(str);}}voidHTMLInputElement::MozSetFileArray(constSequence<OwningNonNull<File>>&aFiles){if(NS_WARN_IF(mType!=NS_FORM_INPUT_FILE)){return;}nsCOMPtr<nsIGlobalObject>global=OwnerDoc()->GetScopeObject();MOZ_ASSERT(global);if(!global){return;}nsTArray<OwningFileOrDirectory>files;for(uint32_ti=0;i<aFiles.Length();++i){RefPtr<File>file=File::Create(global,aFiles[i].get()->Impl());MOZ_ASSERT(file);OwningFileOrDirectory*element=files.AppendElement();element->SetAsFile()=file;}SetFilesOrDirectories(files,true);}voidHTMLInputElement::MozSetFileNameArray(constSequence<nsString>&aFileNames,ErrorResult&aRv){if(NS_WARN_IF(mType!=NS_FORM_INPUT_FILE)){return;}if(XRE_IsContentProcess()){aRv.Throw(NS_ERROR_DOM_NOT_SUPPORTED_ERR);return;}nsTArray<OwningFileOrDirectory>files;for(uint32_ti=0;i<aFileNames.Length();++i){nsCOMPtr<nsIFile>file;if(StringBeginsWith(aFileNames[i],NS_LITERAL_STRING("file:"),nsASCIICaseInsensitiveStringComparator())){// Converts the URL string into the corresponding nsIFile if possible// A local file will be created if the URL string begins with file://NS_GetFileFromURLSpec(NS_ConvertUTF16toUTF8(aFileNames[i]),getter_AddRefs(file));}if(!file){// this is no "file://", try as local fileNS_NewLocalFile(aFileNames[i],false,getter_AddRefs(file));}if(!file){continue;// Not much we can do if the file doesn't exist}nsCOMPtr<nsIGlobalObject>global=OwnerDoc()->GetScopeObject();if(!global){aRv.Throw(NS_ERROR_FAILURE);return;}RefPtr<File>domFile=File::CreateFromFile(global,file);OwningFileOrDirectory*element=files.AppendElement();element->SetAsFile()=domFile;}SetFilesOrDirectories(files,true);}voidHTMLInputElement::MozSetDirectory(constnsAString&aDirectoryPath,ErrorResult&aRv){if(NS_WARN_IF(mType!=NS_FORM_INPUT_FILE)){return;}nsCOMPtr<nsIFile>file;aRv=NS_NewLocalFile(aDirectoryPath,true,getter_AddRefs(file));if(NS_WARN_IF(aRv.Failed())){return;}nsPIDOMWindowInner*window=OwnerDoc()->GetInnerWindow();if(NS_WARN_IF(!window)){aRv.Throw(NS_ERROR_FAILURE);return;}RefPtr<Directory>directory=Directory::Create(window,file);MOZ_ASSERT(directory);nsTArray<OwningFileOrDirectory>array;OwningFileOrDirectory*element=array.AppendElement();element->SetAsDirectory()=directory;SetFilesOrDirectories(array,true);}voidHTMLInputElement::GetDateTimeInputBoxValue(DateTimeValue&aValue){if(NS_WARN_IF(!IsDateTimeInputType(mType))||!mDateTimeInputBoxValue){return;}aValue=*mDateTimeInputBoxValue;}voidHTMLInputElement::UpdateDateTimeInputBox(constDateTimeValue&aValue){if(NS_WARN_IF(!IsDateTimeInputType(mType))){return;}nsDateTimeControlFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->SetValueFromPicker(aValue);}}voidHTMLInputElement::SetDateTimePickerState(boolaOpen){if(NS_WARN_IF(!IsDateTimeInputType(mType))){return;}nsDateTimeControlFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->SetPickerState(aOpen);}}voidHTMLInputElement::OpenDateTimePicker(constDateTimeValue&aInitialValue){if(NS_WARN_IF(!IsDateTimeInputType(mType))){return;}mDateTimeInputBoxValue=newDateTimeValue(aInitialValue);nsContentUtils::DispatchChromeEvent(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),NS_LITERAL_STRING("MozOpenDateTimePicker"),true,true);}voidHTMLInputElement::UpdateDateTimePicker(constDateTimeValue&aValue){if(NS_WARN_IF(!IsDateTimeInputType(mType))){return;}mDateTimeInputBoxValue=newDateTimeValue(aValue);nsContentUtils::DispatchChromeEvent(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),NS_LITERAL_STRING("MozUpdateDateTimePicker"),true,true);}voidHTMLInputElement::CloseDateTimePicker(){if(NS_WARN_IF(!IsDateTimeInputType(mType))){return;}nsContentUtils::DispatchChromeEvent(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),NS_LITERAL_STRING("MozCloseDateTimePicker"),true,true);}voidHTMLInputElement::SetFocusState(boolaIsFocused){if(NS_WARN_IF(!IsDateTimeInputType(mType))){return;}EventStatesfocusStates=NS_EVENT_STATE_FOCUS|NS_EVENT_STATE_FOCUSRING;if(aIsFocused){AddStates(focusStates);}else{RemoveStates(focusStates);}}voidHTMLInputElement::UpdateValidityState(){if(NS_WARN_IF(!IsDateTimeInputType(mType))){return;}// For now, datetime input box call this function only when the value may// become valid/invalid. For other validity states, they will be updated when// .value is actually changed.UpdateBadInputValidityState();UpdateState(true);}boolHTMLInputElement::MozIsTextField(boolaExcludePassword){// TODO: temporary until bug 888320 is fixed.if(IsExperimentalMobileType(mType)||IsDateTimeInputType(mType)){returnfalse;}returnIsSingleLineTextControl(aExcludePassword);}HTMLInputElement*HTMLInputElement::GetOwnerNumberControl(){if(IsInNativeAnonymousSubtree()&&mType==NS_FORM_INPUT_TEXT&&GetParent()&&GetParent()->GetParent()){HTMLInputElement*grandparent=HTMLInputElement::FromContentOrNull(GetParent()->GetParent());if(grandparent&&grandparent->mType==NS_FORM_INPUT_NUMBER){returngrandparent;}}returnnullptr;}voidHTMLInputElement::SetUserInput(constnsAString&aInput,nsIPrincipal&aSubjectPrincipal){if(mType==NS_FORM_INPUT_FILE&&!nsContentUtils::IsSystemPrincipal(&aSubjectPrincipal)){return;}SetUserInput(aInput);}NS_IMETHODIMPHTMLInputElement::SetUserInput(constnsAString&aValue){if(mType==NS_FORM_INPUT_FILE){Sequence<nsString>list;if(!list.AppendElement(aValue,fallible)){returnNS_ERROR_OUT_OF_MEMORY;}ErrorResultrv;MozSetFileNameArray(list,rv);returnrv.StealNSResult();}else{nsresultrv=SetValueInternal(aValue,nsTextEditorState::eSetValue_BySetUserInput|nsTextEditorState::eSetValue_Notify|nsTextEditorState::eSetValue_MoveCursorToEndIfValueChanged);NS_ENSURE_SUCCESS(rv,rv);}nsContentUtils::DispatchTrustedEvent(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),NS_LITERAL_STRING("input"),true,true);// If this element is not currently focused, it won't receive a change event for this// update through the normal channels. So fire a change event immediately, instead.if(!ShouldBlur(this)){FireChangeEventIfNeeded();}returnNS_OK;}nsIEditor*HTMLInputElement::GetEditor(){returnGetTextEditorFromState();}TextEditor*HTMLInputElement::GetTextEditorFromState(){nsTextEditorState*state=GetEditorState();if(state){returnstate->GetTextEditor();}returnnullptr;}NS_IMETHODIMP_(TextEditor*)HTMLInputElement::GetTextEditor(){returnGetTextEditorFromState();}NS_IMETHODIMP_(nsISelectionController*)HTMLInputElement::GetSelectionController(){nsTextEditorState*state=GetEditorState();if(state){returnstate->GetSelectionController();}returnnullptr;}nsFrameSelection*HTMLInputElement::GetConstFrameSelection(){nsTextEditorState*state=GetEditorState();if(state){returnstate->GetConstFrameSelection();}returnnullptr;}NS_IMETHODIMPHTMLInputElement::BindToFrame(nsTextControlFrame*aFrame){nsTextEditorState*state=GetEditorState();if(state){returnstate->BindToFrame(aFrame);}returnNS_ERROR_FAILURE;}NS_IMETHODIMP_(void)HTMLInputElement::UnbindFromFrame(nsTextControlFrame*aFrame){nsTextEditorState*state=GetEditorState();if(state&&aFrame){state->UnbindFromFrame(aFrame);}}NS_IMETHODIMPHTMLInputElement::CreateEditor(){nsTextEditorState*state=GetEditorState();if(state){returnstate->PrepareEditor();}returnNS_ERROR_FAILURE;}NS_IMETHODIMP_(Element*)HTMLInputElement::GetRootEditorNode(){nsTextEditorState*state=GetEditorState();if(state){returnstate->GetRootNode();}returnnullptr;}NS_IMETHODIMP_(Element*)HTMLInputElement::CreatePlaceholderNode(){nsTextEditorState*state=GetEditorState();if(state){NS_ENSURE_SUCCESS(state->CreatePlaceholderNode(),nullptr);returnstate->GetPlaceholderNode();}returnnullptr;}NS_IMETHODIMP_(Element*)HTMLInputElement::GetPlaceholderNode(){nsTextEditorState*state=GetEditorState();if(state){returnstate->GetPlaceholderNode();}returnnullptr;}NS_IMETHODIMP_(void)HTMLInputElement::UpdateOverlayTextVisibility(boolaNotify){nsTextEditorState*state=GetEditorState();if(state){state->UpdateOverlayTextVisibility(aNotify);}}NS_IMETHODIMP_(bool)HTMLInputElement::GetPlaceholderVisibility(){nsTextEditorState*state=GetEditorState();if(!state){returnfalse;}returnstate->GetPlaceholderVisibility();}NS_IMETHODIMP_(Element*)HTMLInputElement::CreatePreviewNode(){nsTextEditorState*state=GetEditorState();if(state){NS_ENSURE_SUCCESS(state->CreatePreviewNode(),nullptr);returnstate->GetPreviewNode();}returnnullptr;}NS_IMETHODIMP_(Element*)HTMLInputElement::GetPreviewNode(){nsTextEditorState*state=GetEditorState();if(state){returnstate->GetPreviewNode();}returnnullptr;}NS_IMETHODIMP_(void)HTMLInputElement::SetPreviewValue(constnsAString&aValue){nsTextEditorState*state=GetEditorState();if(state){state->SetPreviewText(aValue,true);}}NS_IMETHODIMP_(void)HTMLInputElement::GetPreviewValue(nsAString&aValue){nsTextEditorState*state=GetEditorState();if(state){state->GetPreviewText(aValue);}}NS_IMETHODIMP_(void)HTMLInputElement::EnablePreview(){if(mIsPreviewEnabled){return;}mIsPreviewEnabled=true;// Reconstruct the frame to append an anonymous preview nodensLayoutUtils::PostRestyleEvent(this,nsRestyleHint(0),nsChangeHint_ReconstructFrame);}NS_IMETHODIMP_(bool)HTMLInputElement::IsPreviewEnabled(){returnmIsPreviewEnabled;}NS_IMETHODIMP_(bool)HTMLInputElement::GetPreviewVisibility(){nsTextEditorState*state=GetEditorState();if(!state){returnfalse;}returnstate->GetPreviewVisibility();}voidHTMLInputElement::GetDisplayFileName(nsAString&aValue)const{MOZ_ASSERT(mFileData);if(OwnerDoc()->IsStaticDocument()){aValue=mFileData->mStaticDocFileList;return;}if(mFileData->mFilesOrDirectories.Length()==1){GetDOMFileOrDirectoryName(mFileData->mFilesOrDirectories[0],aValue);return;}nsAutoStringvalue;if(mFileData->mFilesOrDirectories.IsEmpty()){if((IsDirPickerEnabled()&&Allowdirs())||(IsWebkitDirPickerEnabled()&&HasAttr(kNameSpaceID_None,nsGkAtoms::webkitdirectory))){nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"NoDirSelected",value);}elseif(HasAttr(kNameSpaceID_None,nsGkAtoms::multiple)){nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"NoFilesSelected",value);}else{nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"NoFileSelected",value);}}else{nsStringcount;count.AppendInt(int(mFileData->mFilesOrDirectories.Length()));constchar16_t*params[]={count.get()};nsContentUtils::FormatLocalizedString(nsContentUtils::eFORMS_PROPERTIES,"XFilesSelected",params,value);}aValue=value;}constnsTArray<OwningFileOrDirectory>&HTMLInputElement::GetFilesOrDirectoriesInternal()const{returnmFileData->mFilesOrDirectories;}voidHTMLInputElement::SetFilesOrDirectories(constnsTArray<OwningFileOrDirectory>&aFilesOrDirectories,boolaSetValueChanged){MOZ_ASSERT(mFileData);mFileData->ClearGetFilesHelpers();if(IsWebkitFileSystemEnabled()){HTMLInputElementBinding::ClearCachedWebkitEntriesValue(this);mFileData->mEntries.Clear();}mFileData->mFilesOrDirectories.Clear();mFileData->mFilesOrDirectories.AppendElements(aFilesOrDirectories);AfterSetFilesOrDirectories(aSetValueChanged);}voidHTMLInputElement::SetFiles(nsIDOMFileList*aFiles,boolaSetValueChanged){MOZ_ASSERT(mFileData);RefPtr<FileList>files=static_cast<FileList*>(aFiles);mFileData->mFilesOrDirectories.Clear();mFileData->ClearGetFilesHelpers();if(IsWebkitFileSystemEnabled()){HTMLInputElementBinding::ClearCachedWebkitEntriesValue(this);mFileData->mEntries.Clear();}if(aFiles){uint32_tlistLength;aFiles->GetLength(&listLength);for(uint32_ti=0;i<listLength;i++){OwningFileOrDirectory*element=mFileData->mFilesOrDirectories.AppendElement();element->SetAsFile()=files->Item(i);}}AfterSetFilesOrDirectories(aSetValueChanged);}// This method is used for testing only.voidHTMLInputElement::MozSetDndFilesAndDirectories(constnsTArray<OwningFileOrDirectory>&aFilesOrDirectories){if(NS_WARN_IF(mType!=NS_FORM_INPUT_FILE)){return;}SetFilesOrDirectories(aFilesOrDirectories,true);if(IsWebkitFileSystemEnabled()){UpdateEntries(aFilesOrDirectories);}RefPtr<DispatchChangeEventCallback>dispatchChangeEventCallback=newDispatchChangeEventCallback(this);if(IsWebkitDirPickerEnabled()&&HasAttr(kNameSpaceID_None,nsGkAtoms::webkitdirectory)){ErrorResultrv;GetFilesHelper*helper=GetOrCreateGetFilesHelper(true/* recursionFlag */,rv);if(NS_WARN_IF(rv.Failed())){rv.SuppressException();return;}helper->AddCallback(dispatchChangeEventCallback);}else{dispatchChangeEventCallback->DispatchEvents();}}voidHTMLInputElement::AfterSetFilesOrDirectories(boolaSetValueChanged){// No need to flush here, if there's no frame at this point we// don't need to force creation of one just to tell it about this// new value. We just want the display to update as needed.nsIFormControlFrame*formControlFrame=GetFormControlFrame(false);if(formControlFrame){nsAutoStringreadableValue;GetDisplayFileName(readableValue);formControlFrame->SetFormProperty(nsGkAtoms::value,readableValue);}// Grab the full path here for any chrome callers who access our .value via a// CPOW. This path won't be called from a CPOW meaning the potential sync IPC// call under GetMozFullPath won't be rejected for not being urgent.// XXX Protected by the ifndef because the blob code doesn't allow us to send// this message in b2g.if(mFileData->mFilesOrDirectories.IsEmpty()){mFileData->mFirstFilePath.Truncate();}else{ErrorResultrv;GetDOMFileOrDirectoryPath(mFileData->mFilesOrDirectories[0],mFileData->mFirstFilePath,rv);if(NS_WARN_IF(rv.Failed())){rv.SuppressException();}}UpdateFileList();if(aSetValueChanged){SetValueChanged(true);}UpdateAllValidityStates(true);}voidHTMLInputElement::FireChangeEventIfNeeded(){// We're not exposing the GetValue return value anywhere here, so it's safe to// claim to be a system caller.nsAutoStringvalue;GetValue(value,CallerType::System);if(!MayFireChangeOnBlur()||mFocusedValue.Equals(value)){return;}// Dispatch the change event.mFocusedValue=value;nsContentUtils::DispatchTrustedEvent(OwnerDoc(),static_cast<nsIContent*>(this),NS_LITERAL_STRING("change"),true,false);}FileList*HTMLInputElement::GetFiles(){if(mType!=NS_FORM_INPUT_FILE){returnnullptr;}if(IsDirPickerEnabled()&&Allowdirs()&&(!IsWebkitDirPickerEnabled()||!HasAttr(kNameSpaceID_None,nsGkAtoms::webkitdirectory))){returnnullptr;}if(!mFileData->mFileList){mFileData->mFileList=newFileList(static_cast<nsIContent*>(this));UpdateFileList();}returnmFileData->mFileList;}voidHTMLInputElement::SetFiles(FileList*aFiles){if(mType!=NS_FORM_INPUT_FILE||!aFiles){return;}// Clear |mFileData->mFileList| to omit |UpdateFileList|if(mFileData->mFileList){mFileData->mFileList->Clear();mFileData->mFileList=nullptr;}// Update |mFileData->mFilesOrDirectories|SetFiles(aFiles,true);// Update |mFileData->mFileList| without copymFileData->mFileList=aFiles;}/* static */voidHTMLInputElement::HandleNumberControlSpin(void*aData){HTMLInputElement*input=static_cast<HTMLInputElement*>(aData);NS_ASSERTION(input->mNumberControlSpinnerIsSpinning,"Should have called nsRepeatService::Stop()");nsNumberControlFrame*numberControlFrame=do_QueryFrame(input->GetPrimaryFrame());if(input->mType!=NS_FORM_INPUT_NUMBER||!numberControlFrame){// Type has changed (and possibly our frame type hasn't been updated yet)// or else we've lost our frame. Either way, stop the timer and don't do// anything else.input->StopNumberControlSpinnerSpin();}else{input->StepNumberControlForUserEvent(input->mNumberControlSpinnerSpinsUp?1:-1);}}voidHTMLInputElement::UpdateFileList(){MOZ_ASSERT(mFileData);if(mFileData->mFileList){mFileData->mFileList->Clear();constnsTArray<OwningFileOrDirectory>&array=GetFilesOrDirectoriesInternal();for(uint32_ti=0;i<array.Length();++i){if(array[i].IsFile()){mFileData->mFileList->Append(array[i].GetAsFile());}}}}nsresultHTMLInputElement::SetValueInternal(constnsAString&aValue,constnsAString*aOldValue,uint32_taFlags){NS_PRECONDITION(GetValueMode()!=VALUE_MODE_FILENAME,"Don't call SetValueInternal for file inputs");// We want to remember if the SetValueInternal() call is being made for a XUL// element. We do that by looking at the parent node here, and if that node// is a XUL node, we consider our control a XUL control.nsIContent*parent=GetParent();if(parent&&parent->IsXULElement()){aFlags|=nsTextEditorState::eSetValue_ForXUL;}switch(GetValueMode()){caseVALUE_MODE_VALUE:{// At the moment, only single line text control have to sanitize their value// Because we have to create a new string for that, we should prevent doing// it if it's useless.nsAutoStringvalue(aValue);if(mDoneCreating){SanitizeValue(value);}// else DoneCreatingElement calls us again once mDoneCreating is trueboolsetValueChanged=!!(aFlags&nsTextEditorState::eSetValue_Notify);if(setValueChanged){SetValueChanged(true);}if(IsSingleLineTextControl(false)){if(!mInputData.mState->SetValue(value,aOldValue,aFlags)){returnNS_ERROR_OUT_OF_MEMORY;}if(mType==NS_FORM_INPUT_EMAIL){UpdateAllValidityStates(!mDoneCreating);}}else{free(mInputData.mValue);mInputData.mValue=ToNewUnicode(value);if(setValueChanged){SetValueChanged(true);}if(mType==NS_FORM_INPUT_NUMBER){// This has to happen before OnValueChanged is called because that// method needs the new value of our frame's anon text control.nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){numberControlFrame->SetValueOfAnonTextControl(value);}}elseif(mType==NS_FORM_INPUT_RANGE){nsRangeFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->UpdateForValueChange();}}elseif((mType==NS_FORM_INPUT_TIME||mType==NS_FORM_INPUT_DATE)&&!IsExperimentalMobileType(mType)&&!(aFlags&nsTextEditorState::eSetValue_BySetUserInput)){nsDateTimeControlFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->OnValueChanged();}}if(mDoneCreating){OnValueChanged(/* aNotify = */true,/* aWasInteractiveUserChange = */false);}// else DoneCreatingElement calls us again once mDoneCreating is true}if(mType==NS_FORM_INPUT_COLOR){// Update color frame, to reflect color changesnsColorControlFrame*colorControlFrame=do_QueryFrame(GetPrimaryFrame());if(colorControlFrame){colorControlFrame->UpdateColor();}}// This call might be useless in some situations because if the element is// a single line text control, nsTextEditorState::SetValue will call// nsHTMLInputElement::OnValueChanged which is going to call UpdateState()// if the element is focused. This bug 665547.if(PlaceholderApplies()&&HasAttr(kNameSpaceID_None,nsGkAtoms::placeholder)){UpdateState(true);}returnNS_OK;}caseVALUE_MODE_DEFAULT:caseVALUE_MODE_DEFAULT_ON:// If the value of a hidden input was changed, we mark it changed so that we// will know we need to save / restore the value. Yes, we are overloading// the meaning of ValueChanged just a teensy bit to save a measly byte of// storage space in HTMLInputElement. Yes, you are free to make a new flag,// NEED_TO_SAVE_VALUE, at such time as mBitField becomes a 16-bit value.if(mType==NS_FORM_INPUT_HIDDEN){SetValueChanged(true);}// Treat value == defaultValue for other input elements.returnnsGenericHTMLFormElementWithState::SetAttr(kNameSpaceID_None,nsGkAtoms::value,aValue,true);caseVALUE_MODE_FILENAME:returnNS_ERROR_UNEXPECTED;}// This return statement is required for some compilers.returnNS_OK;}NS_IMETHODIMPHTMLInputElement::SetValueChanged(boolaValueChanged){boolvalueChangedBefore=mValueChanged;mValueChanged=aValueChanged;if(valueChangedBefore!=aValueChanged){UpdateState(true);}returnNS_OK;}NS_IMETHODIMPHTMLInputElement::GetChecked(bool*aChecked){*aChecked=Checked();returnNS_OK;}voidHTMLInputElement::SetCheckedChanged(boolaCheckedChanged){DoSetCheckedChanged(aCheckedChanged,true);}voidHTMLInputElement::DoSetCheckedChanged(boolaCheckedChanged,boolaNotify){if(mType==NS_FORM_INPUT_RADIO){if(mCheckedChanged!=aCheckedChanged){nsCOMPtr<nsIRadioVisitor>visitor=newnsRadioSetCheckedChangedVisitor(aCheckedChanged);VisitGroup(visitor,aNotify);}}else{SetCheckedChangedInternal(aCheckedChanged);}}voidHTMLInputElement::SetCheckedChangedInternal(boolaCheckedChanged){boolcheckedChangedBefore=mCheckedChanged;mCheckedChanged=aCheckedChanged;// This method can't be called when we are not authorized to notify// so we do not need a aNotify parameter.if(checkedChangedBefore!=aCheckedChanged){UpdateState(true);}}NS_IMETHODIMPHTMLInputElement::SetChecked(boolaChecked){DoSetChecked(aChecked,true,true);returnNS_OK;}voidHTMLInputElement::DoSetChecked(boolaChecked,boolaNotify,boolaSetValueChanged){// If the user or JS attempts to set checked, whether it actually changes the// value or not, we say the value was changed so that defaultValue don't// affect it no more.if(aSetValueChanged){DoSetCheckedChanged(true,aNotify);}// Don't do anything if we're not changing whether it's checked (it would// screw up state actually, especially when you are setting radio button to// false)if(mChecked==aChecked){return;}// Set checkedif(mType!=NS_FORM_INPUT_RADIO){SetCheckedInternal(aChecked,aNotify);return;}// For radio button, we need to do some extra fun stuffif(aChecked){RadioSetChecked(aNotify);return;}nsIRadioGroupContainer*container=GetRadioGroupContainer();if(container){nsAutoStringname;GetAttr(kNameSpaceID_None,nsGkAtoms::name,name);container->SetCurrentRadioButton(name,nullptr);}// SetCheckedInternal is going to ask all radios to update their// validity state. We have to be sure the radio group container knows// the currently selected radio.SetCheckedInternal(false,aNotify);}voidHTMLInputElement::RadioSetChecked(boolaNotify){// Find the selected radio button so we can deselect itnsCOMPtr<nsIDOMHTMLInputElement>currentlySelected=GetSelectedRadioButton();// Deselect the currently selected radio buttonif(currentlySelected){// Pass true for the aNotify parameter since the currently selected// button is already in the document.static_cast<HTMLInputElement*>(currentlySelected.get())->SetCheckedInternal(false,true);}// Let the group know that we are now the One True Radio ButtonnsIRadioGroupContainer*container=GetRadioGroupContainer();if(container){nsAutoStringname;GetAttr(kNameSpaceID_None,nsGkAtoms::name,name);container->SetCurrentRadioButton(name,this);}// SetCheckedInternal is going to ask all radios to update their// validity state.SetCheckedInternal(true,aNotify);}nsIRadioGroupContainer*HTMLInputElement::GetRadioGroupContainer()const{NS_ASSERTION(mType==NS_FORM_INPUT_RADIO,"GetRadioGroupContainer should only be called when type='radio'");nsAutoStringname;GetAttr(kNameSpaceID_None,nsGkAtoms::name,name);if(name.IsEmpty()){returnnullptr;}if(mForm){returnmForm;}//XXXsmaug It isn't clear how this should work in Shadow DOM.returnstatic_cast<nsDocument*>(GetUncomposedDoc());}already_AddRefed<nsIDOMHTMLInputElement>HTMLInputElement::GetSelectedRadioButton()const{nsIRadioGroupContainer*container=GetRadioGroupContainer();if(!container){returnnullptr;}nsAutoStringname;GetAttr(kNameSpaceID_None,nsGkAtoms::name,name);nsCOMPtr<nsIDOMHTMLInputElement>selected=container->GetCurrentRadioButton(name);returnselected.forget();}nsresultHTMLInputElement::MaybeSubmitForm(nsPresContext*aPresContext){if(!mForm){// Nothing to do here.returnNS_OK;}nsCOMPtr<nsIPresShell>shell=aPresContext->GetPresShell();if(!shell){returnNS_OK;}// Get the default submit elementnsIFormControl*submitControl=mForm->GetDefaultSubmitElement();if(submitControl){nsCOMPtr<nsIContent>submitContent=do_QueryInterface(submitControl);NS_ASSERTION(submitContent,"Form control not implementing nsIContent?!");// Fire the button's onclick handler and let the button handle// submitting the form.WidgetMouseEventevent(true,eMouseClick,nullptr,WidgetMouseEvent::eReal);nsEventStatusstatus=nsEventStatus_eIgnore;shell->HandleDOMEventWithTarget(submitContent,&event,&status);}elseif(!mForm->ImplicitSubmissionIsDisabled()&&mForm->SubmissionCanProceed(nullptr)){// TODO: removing this code and have the submit event sent by the form,// bug 592124.// If there's only one text control, just submit the form// Hold strong ref across the eventRefPtr<mozilla::dom::HTMLFormElement>form=mForm;InternalFormEventevent(true,eFormSubmit);nsEventStatusstatus=nsEventStatus_eIgnore;shell->HandleDOMEventWithTarget(form,&event,&status);}returnNS_OK;}voidHTMLInputElement::SetCheckedInternal(boolaChecked,boolaNotify){// Set the valuemChecked=aChecked;// Notify the frameif(mType==NS_FORM_INPUT_CHECKBOX||mType==NS_FORM_INPUT_RADIO){nsIFrame*frame=GetPrimaryFrame();if(frame){frame->InvalidateFrameSubtree();}}UpdateAllValidityStates(aNotify);// Notify the document that the CSS :checked pseudoclass for this element// has changed state.UpdateState(aNotify);// Notify all radios in the group that value has changed, this is to let// radios to have the chance to update its states, e.g., :indeterminate.if(mType==NS_FORM_INPUT_RADIO){nsCOMPtr<nsIRadioVisitor>visitor=newnsRadioUpdateStateVisitor(this);VisitGroup(visitor,aNotify);}}voidHTMLInputElement::Blur(ErrorResult&aError){if(mType==NS_FORM_INPUT_NUMBER){// Blur our anonymous text control, if we have one. (DOM 'change' event// firing and other things depend on this.)nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){HTMLInputElement*textControl=numberControlFrame->GetAnonTextControl();if(textControl){textControl->Blur(aError);return;}}}if((mType==NS_FORM_INPUT_TIME||mType==NS_FORM_INPUT_DATE)&&!IsExperimentalMobileType(mType)){nsDateTimeControlFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->HandleBlurEvent();return;}}nsGenericHTMLElement::Blur(aError);}voidHTMLInputElement::Focus(ErrorResult&aError){if(mType==NS_FORM_INPUT_NUMBER){// Focus our anonymous text control, if we have one.nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){HTMLInputElement*textControl=numberControlFrame->GetAnonTextControl();if(textControl){textControl->Focus(aError);return;}}}if((mType==NS_FORM_INPUT_TIME||mType==NS_FORM_INPUT_DATE)&&!IsExperimentalMobileType(mType)){nsDateTimeControlFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->HandleFocusEvent();return;}}if(mType!=NS_FORM_INPUT_FILE){nsGenericHTMLElement::Focus(aError);return;}// For file inputs, focus the first button instead. In the case of there// being two buttons (when the picker is a directory picker) the user can// tab to the next one.nsIFrame*frame=GetPrimaryFrame();if(frame){for(nsIFrame*childFrame:frame->PrincipalChildList()){// See if the child is a button control.nsCOMPtr<nsIFormControl>formCtrl=do_QueryInterface(childFrame->GetContent());if(formCtrl&&formCtrl->ControlType()==NS_FORM_BUTTON_BUTTON){nsCOMPtr<nsIDOMElement>element=do_QueryInterface(formCtrl);nsIFocusManager*fm=nsFocusManager::GetFocusManager();if(fm&&element){fm->SetFocus(element,0);}break;}}}}#if !defined(ANDROID) && !defined(XP_MACOSX)boolHTMLInputElement::IsNodeApzAwareInternal()const{// Tell APZC we may handle mouse wheel event and do preventDefault when input// type is number.return(mType==NS_FORM_INPUT_NUMBER)||(mType==NS_FORM_INPUT_RANGE)||nsINode::IsNodeApzAwareInternal();}#endifboolHTMLInputElement::IsInteractiveHTMLContent(boolaIgnoreTabindex)const{returnmType!=NS_FORM_INPUT_HIDDEN||nsGenericHTMLFormElementWithState::IsInteractiveHTMLContent(aIgnoreTabindex);}voidHTMLInputElement::AsyncEventRunning(AsyncEventDispatcher*aEvent){nsImageLoadingContent::AsyncEventRunning(aEvent);}voidHTMLInputElement::Select(){if(mType==NS_FORM_INPUT_NUMBER){nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){numberControlFrame->HandleSelectCall();}return;}if(!IsSingleLineTextControl(false)){return;}// XXX Bug? We have to give the input focus before contents can be// selectedFocusTristatestate=FocusState();if(state==eUnfocusable){return;}nsTextEditorState*tes=GetEditorState();if(tes){RefPtr<nsFrameSelection>fs=tes->GetConstFrameSelection();if(fs&&fs->MouseDownRecorded()){// This means that we're being called while the frame selection has a mouse// down event recorded to adjust the caret during the mouse up event.// We are probably called from the focus event handler. We should override// the delayed caret data in this case to ensure that this select() call// takes effect.fs->SetDelayedCaretData(nullptr);}}nsIFocusManager*fm=nsFocusManager::GetFocusManager();RefPtr<nsPresContext>presContext=GetPresContext(eForComposedDoc);if(state==eInactiveWindow){if(fm)fm->SetFocus(this,nsIFocusManager::FLAG_NOSCROLL);SelectAll(presContext);return;}if(DispatchSelectEvent(presContext)&&fm){fm->SetFocus(this,nsIFocusManager::FLAG_NOSCROLL);// ensure that the element is actually focusednsCOMPtr<nsIDOMElement>focusedElement;fm->GetFocusedElement(getter_AddRefs(focusedElement));if(SameCOMIdentity(static_cast<nsIDOMNode*>(this),focusedElement)){// Now Select all the text!SelectAll(presContext);}}}boolHTMLInputElement::DispatchSelectEvent(nsPresContext*aPresContext){nsEventStatusstatus=nsEventStatus_eIgnore;// If already handling select event, don't dispatch a second.if(!mHandlingSelectEvent){WidgetEventevent(true,eFormSelect);mHandlingSelectEvent=true;EventDispatcher::Dispatch(static_cast<nsIContent*>(this),aPresContext,&event,nullptr,&status);mHandlingSelectEvent=false;}// If the DOM event was not canceled (e.g. by a JS event handler// returning false)return(status==nsEventStatus_eIgnore);}voidHTMLInputElement::SelectAll(nsPresContext*aPresContext){nsIFormControlFrame*formControlFrame=GetFormControlFrame(true);if(formControlFrame){formControlFrame->SetFormProperty(nsGkAtoms::select,EmptyString());}}boolHTMLInputElement::NeedToInitializeEditorForEvent(EventChainPreVisitor&aVisitor)const{// We only need to initialize the editor for single line input controls because they// are lazily initialized. We don't need to initialize the control for// certain types of events, because we know that those events are safe to be// handled without the editor being initialized. These events include:// mousein/move/out, overflow/underflow, DOM mutation, and void events. Void// events are dispatched frequently by async keyboard scrolling to focused// elements, so it's important to handle them to prevent excessive DOM// mutations.if(!IsSingleLineTextControl(false)||aVisitor.mEvent->mClass==eMutationEventClass){returnfalse;}switch(aVisitor.mEvent->mMessage){caseeVoidEvent:caseeMouseMove:caseeMouseEnterIntoWidget:caseeMouseExitFromWidget:caseeMouseOver:caseeMouseOut:caseeScrollPortUnderflow:caseeScrollPortOverflow:returnfalse;default:returntrue;}}boolHTMLInputElement::IsDisabledForEvents(EventMessageaMessage){returnIsElementDisabledForEvents(aMessage,GetPrimaryFrame());}nsresultHTMLInputElement::GetEventTargetParent(EventChainPreVisitor&aVisitor){// Do not process any DOM events if the element is disabledaVisitor.mCanHandle=false;if(IsDisabledForEvents(aVisitor.mEvent->mMessage)){returnNS_OK;}// Initialize the editor if needed.if(NeedToInitializeEditorForEvent(aVisitor)){nsITextControlFrame*textControlFrame=do_QueryFrame(GetPrimaryFrame());if(textControlFrame)textControlFrame->EnsureEditorInitialized();}//FIXME Allow submission etc. also when there is no prescontext, Bug 329509.if(!aVisitor.mPresContext){returnnsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);}//// Web pages expect the value of a radio button or checkbox to be set// *before* onclick and DOMActivate fire, and they expect that if they set// the value explicitly during onclick or DOMActivate it will not be toggled// or any such nonsense.// In order to support that (bug 57137 and 58460 are examples) we toggle// the checked attribute *first*, and then fire onclick. If the user// returns false, we reset the control to the old checked value. Otherwise,// we dispatch DOMActivate. If DOMActivate is cancelled, we also reset// the control to the old checked value. We need to keep track of whether// we've already toggled the state from onclick since the user could// explicitly dispatch DOMActivate on the element.//// This is a compatibility hack.//// Track whether we're in the outermost Dispatch invocation that will// cause activation of the input. That is, if we're a click event, or a// DOMActivate that was dispatched directly, this will be set, but if we're// a DOMActivate dispatched from click handling, it will not be set.WidgetMouseEvent*mouseEvent=aVisitor.mEvent->AsMouseEvent();boolouterActivateEvent=((mouseEvent&&mouseEvent->IsLeftClickEvent())||(aVisitor.mEvent->mMessage==eLegacyDOMActivate&&!mInInternalActivate));if(outerActivateEvent){aVisitor.mItemFlags|=NS_OUTER_ACTIVATE_EVENT;}booloriginalCheckedValue=false;if(outerActivateEvent){mCheckedIsToggled=false;switch(mType){caseNS_FORM_INPUT_CHECKBOX:{if(mIndeterminate){// indeterminate is always set to FALSE when the checkbox is toggledSetIndeterminateInternal(false,false);aVisitor.mItemFlags|=NS_ORIGINAL_INDETERMINATE_VALUE;}GetChecked(&originalCheckedValue);DoSetChecked(!originalCheckedValue,true,true);mCheckedIsToggled=true;}break;caseNS_FORM_INPUT_RADIO:{nsCOMPtr<nsIDOMHTMLInputElement>selectedRadioButton=GetSelectedRadioButton();aVisitor.mItemData=selectedRadioButton;originalCheckedValue=mChecked;if(!originalCheckedValue){DoSetChecked(true,true,true);mCheckedIsToggled=true;}}break;caseNS_FORM_INPUT_SUBMIT:caseNS_FORM_INPUT_IMAGE:if(mForm){// tell the form that we are about to enter a click handler.// that means that if there are scripted submissions, the// latest one will be deferred until after the exit point of the handler.mForm->OnSubmitClickBegin(this);}break;default:break;}}if(originalCheckedValue){aVisitor.mItemFlags|=NS_ORIGINAL_CHECKED_VALUE;}// If mNoContentDispatch is true we will not allow content to handle// this event. But to allow middle mouse button paste to work we must allow// middle clicks to go to text fields anyway.if(aVisitor.mEvent->mFlags.mNoContentDispatch){aVisitor.mItemFlags|=NS_NO_CONTENT_DISPATCH;}if(IsSingleLineTextControl(false)&&aVisitor.mEvent->mMessage==eMouseClick&&aVisitor.mEvent->AsMouseEvent()->button==WidgetMouseEvent::eMiddleButton){aVisitor.mEvent->mFlags.mNoContentDispatch=false;}// We must cache type because mType may change during JS event (bug 2369)aVisitor.mItemFlags|=mType;if(aVisitor.mEvent->mMessage==eFocus&&aVisitor.mEvent->IsTrusted()&&MayFireChangeOnBlur()&&// StartRangeThumbDrag already set mFocusedValue on 'mousedown' before// we get the 'focus' event.!mIsDraggingRange){GetValue(mFocusedValue,CallerType::System);}// Fire onchange (if necessary), before we do the blur, bug 357684.if(aVisitor.mEvent->mMessage==eBlur){// We set NS_PRE_HANDLE_BLUR_EVENT here and handle it in PreHandleEvent to// prevent breaking event target chain creation.aVisitor.mWantsPreHandleEvent=true;aVisitor.mItemFlags|=NS_PRE_HANDLE_BLUR_EVENT;}if(mType==NS_FORM_INPUT_RANGE&&(aVisitor.mEvent->mMessage==eFocus||aVisitor.mEvent->mMessage==eBlur)){// Just as nsGenericHTMLFormElementWithState::GetEventTargetParent calls// nsIFormControlFrame::SetFocus, we handle focus here.nsIFrame*frame=GetPrimaryFrame();if(frame){frame->InvalidateFrameSubtree();}}if((mType==NS_FORM_INPUT_TIME||mType==NS_FORM_INPUT_DATE)&&!IsExperimentalMobileType(mType)&&aVisitor.mEvent->mMessage==eFocus&&aVisitor.mEvent->mOriginalTarget==this){// If original target is this and not the anonymous text control, we should// pass the focus to the anonymous text control.nsDateTimeControlFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->HandleFocusEvent();}}if(mType==NS_FORM_INPUT_NUMBER&&aVisitor.mEvent->IsTrusted()){if(mNumberControlSpinnerIsSpinning){// If the timer is running the user has depressed the mouse on one of the// spin buttons. If the mouse exits the button we either want to reverse// the direction of spin if it has moved over the other button, or else// we want to end the spin. We do this here (rather than in// PostHandleEvent) because we don't want to let content preventDefault()// the end of the spin.if(aVisitor.mEvent->mMessage==eMouseMove){// Be aggressive about stopping the spin:boolstopSpin=true;nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){boololdNumberControlSpinTimerSpinsUpValue=mNumberControlSpinnerSpinsUp;switch(numberControlFrame->GetSpinButtonForPointerEvent(aVisitor.mEvent->AsMouseEvent())){casensNumberControlFrame::eSpinButtonUp:mNumberControlSpinnerSpinsUp=true;stopSpin=false;break;casensNumberControlFrame::eSpinButtonDown:mNumberControlSpinnerSpinsUp=false;stopSpin=false;break;}if(mNumberControlSpinnerSpinsUp!=oldNumberControlSpinTimerSpinsUpValue){nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){numberControlFrame->SpinnerStateChanged();}}}if(stopSpin){StopNumberControlSpinnerSpin();}}elseif(aVisitor.mEvent->mMessage==eMouseUp){StopNumberControlSpinnerSpin();}}if(aVisitor.mEvent->mMessage==eFocus||aVisitor.mEvent->mMessage==eBlur){if(aVisitor.mEvent->mMessage==eFocus){// Tell our frame it's getting focus so that it can make sure focus// is moved to our anonymous text control.nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){// This could kill the frame!numberControlFrame->HandleFocusEvent(aVisitor.mEvent);}}nsIFrame*frame=GetPrimaryFrame();if(frame&&frame->IsThemed()){// Our frame's nested <input type=text> will be invalidated when it// loses focus, but since we are also native themed we need to make// sure that our entire area is repainted since any focus highlight// from the theme should be removed from us (the repainting of the// sub-area occupied by the anon text control is not enough to do// that).frame->InvalidateFrame();}}}nsresultrv=nsGenericHTMLFormElementWithState::GetEventTargetParent(aVisitor);// We do this after calling the base class' GetEventTargetParent so that// nsIContent::GetEventTargetParent doesn't reset any change we make to// mCanHandle.if(mType==NS_FORM_INPUT_NUMBER&&aVisitor.mEvent->IsTrusted()&&aVisitor.mEvent->mOriginalTarget!=this){// <input type=number> has an anonymous <input type=text> descendant. If// 'input' or 'change' events are fired at that text control then we need// to do some special handling here.HTMLInputElement*textControl=nullptr;nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){textControl=numberControlFrame->GetAnonTextControl();}if(textControl&&aVisitor.mEvent->mOriginalTarget==textControl){if(aVisitor.mEvent->mMessage==eEditorInput){aVisitor.mWantsPreHandleEvent=true;// We set NS_PRE_HANDLE_INPUT_EVENT here and handle it in PreHandleEvent// to prevent breaking event target chain creation.aVisitor.mItemFlags|=NS_PRE_HANDLE_INPUT_EVENT;}elseif(aVisitor.mEvent->mMessage==eFormChange){// We cancel the DOM 'change' event that is fired for any change to our// anonymous text control since we fire our own 'change' events and// content shouldn't be seeing two 'change' events. Besides that we// (as a number) control have tighter restrictions on when our internal// value changes than our anon text control does, so in some cases// (if our text control's value doesn't parse as a number) we don't// want to fire a 'change' event at all.aVisitor.mCanHandle=false;}}}// Stop the event if the related target's first non-native ancestor is the// same as the original target's first non-native ancestor (we are moving// inside of the same element).if((mType==NS_FORM_INPUT_TIME||mType==NS_FORM_INPUT_DATE)&&!IsExperimentalMobileType(mType)&&aVisitor.mEvent->IsTrusted()&&(aVisitor.mEvent->mMessage==eFocus||aVisitor.mEvent->mMessage==eFocusIn||aVisitor.mEvent->mMessage==eFocusOut||aVisitor.mEvent->mMessage==eBlur)){nsCOMPtr<nsIContent>originalTarget=do_QueryInterface(aVisitor.mEvent->AsFocusEvent()->mOriginalTarget);nsCOMPtr<nsIContent>relatedTarget=do_QueryInterface(aVisitor.mEvent->AsFocusEvent()->mRelatedTarget);if(originalTarget&&relatedTarget&&originalTarget->FindFirstNonChromeOnlyAccessContent()==relatedTarget->FindFirstNonChromeOnlyAccessContent()){aVisitor.mCanHandle=false;}}returnrv;}nsresultHTMLInputElement::PreHandleEvent(EventChainVisitor&aVisitor){if(!aVisitor.mPresContext){returnnsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);}nsresultrv;if(aVisitor.mItemFlags&NS_PRE_HANDLE_BLUR_EVENT){MOZ_ASSERT(aVisitor.mEvent->mMessage==eBlur);// Experimental mobile types rely on the system UI to prevent users to not// set invalid values but we have to be extra-careful. Especially if the// option has been enabled on desktop.if(IsExperimentalMobileType(mType)){nsAutoStringaValue;GetNonFileValueInternal(aValue);rv=SetValueInternal(aValue,nsTextEditorState::eSetValue_Internal);NS_ENSURE_SUCCESS(rv,rv);}FireChangeEventIfNeeded();}rv=nsGenericHTMLFormElementWithState::PreHandleEvent(aVisitor);if(aVisitor.mItemFlags&NS_PRE_HANDLE_INPUT_EVENT){nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());MOZ_ASSERT(aVisitor.mEvent->mMessage==eEditorInput);MOZ_ASSERT(numberControlFrame);MOZ_ASSERT(numberControlFrame->GetAnonTextControl()==aVisitor.mEvent->mOriginalTarget);// Propogate the anon text control's new value to our HTMLInputElement:nsAutoStringvalue;numberControlFrame->GetValueOfAnonTextControl(value);numberControlFrame->HandlingInputEvent(true);AutoWeakFrameweakNumberControlFrame(numberControlFrame);rv=SetValueInternal(value,nsTextEditorState::eSetValue_BySetUserInput|nsTextEditorState::eSetValue_Notify);NS_ENSURE_SUCCESS(rv,rv);if(weakNumberControlFrame.IsAlive()){numberControlFrame->HandlingInputEvent(false);}}returnrv;}voidHTMLInputElement::StartRangeThumbDrag(WidgetGUIEvent*aEvent){mIsDraggingRange=true;mRangeThumbDragStartValue=GetValueAsDecimal();// Don't use CAPTURE_RETARGETTOELEMENT, as that breaks pseudo-class styling// of the thumb.nsIPresShell::SetCapturingContent(this,CAPTURE_IGNOREALLOWED);nsRangeFrame*rangeFrame=do_QueryFrame(GetPrimaryFrame());// Before we change the value, record the current value so that we'll// correctly send a 'change' event if appropriate. We need to do this here// because the 'focus' event is handled after the 'mousedown' event that// we're being called for (i.e. too late to update mFocusedValue, since we'll// have changed it by then).GetValue(mFocusedValue,CallerType::System);SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));}voidHTMLInputElement::FinishRangeThumbDrag(WidgetGUIEvent*aEvent){MOZ_ASSERT(mIsDraggingRange);if(nsIPresShell::GetCapturingContent()==this){nsIPresShell::SetCapturingContent(nullptr,0);// cancel capture}if(aEvent){nsRangeFrame*rangeFrame=do_QueryFrame(GetPrimaryFrame());SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aEvent));}mIsDraggingRange=false;FireChangeEventIfNeeded();}voidHTMLInputElement::CancelRangeThumbDrag(boolaIsForUserEvent){MOZ_ASSERT(mIsDraggingRange);mIsDraggingRange=false;if(nsIPresShell::GetCapturingContent()==this){nsIPresShell::SetCapturingContent(nullptr,0);// cancel capture}if(aIsForUserEvent){SetValueOfRangeForUserEvent(mRangeThumbDragStartValue);}else{// Don't dispatch an 'input' event - at least not using// DispatchTrustedEvent.// TODO: decide what we should do here - bug 851782.nsAutoStringval;mInputType->ConvertNumberToString(mRangeThumbDragStartValue,val);// TODO: What should we do if SetValueInternal fails? (The allocation// is small, so we should be fine here.)SetValueInternal(val,nsTextEditorState::eSetValue_BySetUserInput|nsTextEditorState::eSetValue_Notify);nsRangeFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->UpdateForValueChange();}RefPtr<AsyncEventDispatcher>asyncDispatcher=newAsyncEventDispatcher(this,NS_LITERAL_STRING("input"),true,false);asyncDispatcher->RunDOMEventWhenSafe();}}voidHTMLInputElement::SetValueOfRangeForUserEvent(DecimalaValue){MOZ_ASSERT(aValue.isFinite());DecimaloldValue=GetValueAsDecimal();nsAutoStringval;mInputType->ConvertNumberToString(aValue,val);// TODO: What should we do if SetValueInternal fails? (The allocation// is small, so we should be fine here.)SetValueInternal(val,nsTextEditorState::eSetValue_BySetUserInput|nsTextEditorState::eSetValue_Notify);nsRangeFrame*frame=do_QueryFrame(GetPrimaryFrame());if(frame){frame->UpdateForValueChange();}if(GetValueAsDecimal()!=oldValue){nsContentUtils::DispatchTrustedEvent(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),NS_LITERAL_STRING("input"),true,false);}}voidHTMLInputElement::StartNumberControlSpinnerSpin(){MOZ_ASSERT(!mNumberControlSpinnerIsSpinning);mNumberControlSpinnerIsSpinning=true;nsRepeatService::GetInstance()->Start(HandleNumberControlSpin,this,OwnerDoc(),NS_LITERAL_CSTRING("HandleNumberControlSpin"));// Capture the mouse so that we can tell if the pointer moves from one// spin button to the other, or to some other element:nsIPresShell::SetCapturingContent(this,CAPTURE_IGNOREALLOWED);nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){numberControlFrame->SpinnerStateChanged();}}voidHTMLInputElement::StopNumberControlSpinnerSpin(SpinnerStopStateaState){if(mNumberControlSpinnerIsSpinning){if(nsIPresShell::GetCapturingContent()==this){nsIPresShell::SetCapturingContent(nullptr,0);// cancel capture}nsRepeatService::GetInstance()->Stop(HandleNumberControlSpin,this);mNumberControlSpinnerIsSpinning=false;if(aState==eAllowDispatchingEvents){FireChangeEventIfNeeded();}nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){MOZ_ASSERT(aState==eAllowDispatchingEvents,"Shouldn't have primary frame for the element when we're not ""allowed to dispatch events to it anymore.");numberControlFrame->SpinnerStateChanged();}}}voidHTMLInputElement::StepNumberControlForUserEvent(int32_taDirection){// We can't use GetValidityState here because the validity state is not set// if the user hasn't previously taken an action to set or change the value,// according to the specs.if(HasBadInput()){// If the user has typed a value into the control and inadvertently made a// mistake (e.g. put a thousand separator at the wrong point) we do not// want to wipe out what they typed if they try to increment/decrement the// value. Better is to highlight the value as being invalid so that they// can correct what they typed.// We only do this if there actually is a value typed in by/displayed to// the user. (IsValid() can return false if the 'required' attribute is// set and the value is the empty string.)nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame&&!numberControlFrame->AnonTextControlIsEmpty()){// We pass 'true' for UpdateValidityUIBits' aIsFocused argument// regardless because we need the UI to update _now_ or the user will// wonder why the step behavior isn't functioning.UpdateValidityUIBits(true);UpdateState(true);return;}}DecimalnewValue=Decimal::nan();// unchanged if value will not changensresultrv=GetValueIfStepped(aDirection,CALLED_FOR_USER_EVENT,&newValue);if(NS_FAILED(rv)||!newValue.isFinite()){return;// value should not or will not change}nsAutoStringnewVal;mInputType->ConvertNumberToString(newValue,newVal);// TODO: What should we do if SetValueInternal fails? (The allocation// is small, so we should be fine here.)SetValueInternal(newVal,nsTextEditorState::eSetValue_BySetUserInput|nsTextEditorState::eSetValue_Notify);nsContentUtils::DispatchTrustedEvent(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),NS_LITERAL_STRING("input"),true,false);}staticboolSelectTextFieldOnFocus(){if(!gSelectTextFieldOnFocus){int32_tselectTextfieldsOnKeyFocus=-1;nsresultrv=LookAndFeel::GetInt(LookAndFeel::eIntID_SelectTextfieldsOnKeyFocus,&selectTextfieldsOnKeyFocus);if(NS_FAILED(rv)){gSelectTextFieldOnFocus=-1;}else{gSelectTextFieldOnFocus=selectTextfieldsOnKeyFocus!=0?1:-1;}}returngSelectTextFieldOnFocus==1;}boolHTMLInputElement::ShouldPreventDOMActivateDispatch(EventTarget*aOriginalTarget){/* * For the moment, there is only one situation where we actually want to * prevent firing a DOMActivate event: * - we are a <input type='file'> that just got a click event, * - the event was targeted to our button which should have sent a * DOMActivate event. */if(mType!=NS_FORM_INPUT_FILE){returnfalse;}nsCOMPtr<nsIContent>target=do_QueryInterface(aOriginalTarget);if(!target){returnfalse;}returntarget->GetParent()==this&&target->IsRootOfNativeAnonymousSubtree()&&target->AttrValueIs(kNameSpaceID_None,nsGkAtoms::type,nsGkAtoms::button,eCaseMatters);}nsresultHTMLInputElement::MaybeInitPickers(EventChainPostVisitor&aVisitor){// Open a file picker when we receive a click on a <input type='file'>, or// open a color picker when we receive a click on a <input type='color'>.// A click is handled in the following cases:// - preventDefault() has not been called (or something similar);// - it's the left mouse button.// We do not prevent non-trusted click because authors can already use// .click(). However, the pickers will follow the rules of popup-blocking.if(aVisitor.mEvent->DefaultPrevented()){returnNS_OK;}WidgetMouseEvent*mouseEvent=aVisitor.mEvent->AsMouseEvent();if(!(mouseEvent&&mouseEvent->IsLeftClickEvent())){returnNS_OK;}if(mType==NS_FORM_INPUT_FILE){// If the user clicked on the "Choose folder..." button we open the// directory picker, else we open the file picker.FilePickerTypetype=FILE_PICKER_FILE;nsCOMPtr<nsIContent>target=do_QueryInterface(aVisitor.mEvent->mOriginalTarget);if(target&&target->FindFirstNonChromeOnlyAccessContent()==this&&((IsDirPickerEnabled()&&Allowdirs())||(IsWebkitDirPickerEnabled()&&HasAttr(kNameSpaceID_None,nsGkAtoms::webkitdirectory)))){type=FILE_PICKER_DIRECTORY;}returnInitFilePicker(type);}if(mType==NS_FORM_INPUT_COLOR){returnInitColorPicker();}returnNS_OK;}/** * Return true if the input event should be ignore because of it's modifiers */staticboolIgnoreInputEventWithModifier(WidgetInputEvent*aEvent){returnaEvent->IsShift()||aEvent->IsControl()||aEvent->IsAlt()||aEvent->IsMeta()||aEvent->IsAltGraph()||aEvent->IsFn()||aEvent->IsOS();}nsresultHTMLInputElement::PostHandleEvent(EventChainPostVisitor&aVisitor){if(!aVisitor.mPresContext){// Hack alert! In order to open file picker even in case the element isn't// in document, try to init picker even without PresContext.returnMaybeInitPickers(aVisitor);}if(aVisitor.mEvent->mMessage==eFocus||aVisitor.mEvent->mMessage==eBlur){if(aVisitor.mEvent->mMessage==eBlur){if(mIsDraggingRange){FinishRangeThumbDrag();}elseif(mNumberControlSpinnerIsSpinning){StopNumberControlSpinnerSpin();}}UpdateValidityUIBits(aVisitor.mEvent->mMessage==eFocus);UpdateState(true);}nsresultrv=NS_OK;boolouterActivateEvent=!!(aVisitor.mItemFlags&NS_OUTER_ACTIVATE_EVENT);booloriginalCheckedValue=!!(aVisitor.mItemFlags&NS_ORIGINAL_CHECKED_VALUE);boolnoContentDispatch=!!(aVisitor.mItemFlags&NS_NO_CONTENT_DISPATCH);uint8_toldType=NS_CONTROL_TYPE(aVisitor.mItemFlags);// Ideally we would make the default action for click and space just dispatch// DOMActivate, and the default action for DOMActivate flip the checkbox/// radio state and fire onchange. However, for backwards compatibility, we// need to flip the state before firing click, and we need to fire click// when space is pressed. So, we just nest the firing of DOMActivate inside// the click event handling, and allow cancellation of DOMActivate to cancel// the click.if(aVisitor.mEventStatus!=nsEventStatus_eConsumeNoDefault&&!IsSingleLineTextControl(true)&&mType!=NS_FORM_INPUT_NUMBER){WidgetMouseEvent*mouseEvent=aVisitor.mEvent->AsMouseEvent();if(mouseEvent&&mouseEvent->IsLeftClickEvent()&&!ShouldPreventDOMActivateDispatch(aVisitor.mEvent->mOriginalTarget)){// DOMActive event should be trusted since the activation is actually// occurred even if the cause is an untrusted click event.InternalUIEventactEvent(true,eLegacyDOMActivate,mouseEvent);actEvent.mDetail=1;nsCOMPtr<nsIPresShell>shell=aVisitor.mPresContext->GetPresShell();if(shell){nsEventStatusstatus=nsEventStatus_eIgnore;mInInternalActivate=true;rv=shell->HandleDOMEventWithTarget(this,&actEvent,&status);mInInternalActivate=false;// If activate is cancelled, we must do the same as when click is// cancelled (revert the checkbox to its original value).if(status==nsEventStatus_eConsumeNoDefault){aVisitor.mEventStatus=status;}}}}if(outerActivateEvent){switch(oldType){caseNS_FORM_INPUT_SUBMIT:caseNS_FORM_INPUT_IMAGE:if(mForm){// tell the form that we are about to exit a click handler// so the form knows not to defer subsequent submissions// the pending ones that were created during the handler// will be flushed or forgoten.mForm->OnSubmitClickEnd();}break;default:break;}}// Reset the flag for other content besides this text fieldaVisitor.mEvent->mFlags.mNoContentDispatch=noContentDispatch;// now check to see if the event was "cancelled"if(mCheckedIsToggled&&outerActivateEvent){if(aVisitor.mEventStatus==nsEventStatus_eConsumeNoDefault){// if it was cancelled and a radio button, then set the old// selected btn to TRUE. if it is a checkbox then set it to its// original valueif(oldType==NS_FORM_INPUT_RADIO){nsCOMPtr<nsIDOMHTMLInputElement>selectedRadioButton=do_QueryInterface(aVisitor.mItemData);if(selectedRadioButton){selectedRadioButton->SetChecked(true);}// If there was no checked radio button or this one is no longer a// radio button we must reset it back to false to cancel the action.// See how the web of hack grows?if(!selectedRadioButton||mType!=NS_FORM_INPUT_RADIO){DoSetChecked(false,true,true);}}elseif(oldType==NS_FORM_INPUT_CHECKBOX){booloriginalIndeterminateValue=!!(aVisitor.mItemFlags&NS_ORIGINAL_INDETERMINATE_VALUE);SetIndeterminateInternal(originalIndeterminateValue,false);DoSetChecked(originalCheckedValue,true,true);}}else{// Fire input event and then change event.nsContentUtils::DispatchTrustedEvent<InternalEditorInputEvent>(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),eEditorInput,true,false);nsContentUtils::DispatchTrustedEvent<WidgetEvent>(OwnerDoc(),static_cast<nsIDOMHTMLInputElement*>(this),eFormChange,true,false);#ifdef ACCESSIBILITY// Fire an event to notify accessibilityif(mType==NS_FORM_INPUT_CHECKBOX){FireEventForAccessibility(this,aVisitor.mPresContext,eFormCheckboxStateChange);}else{FireEventForAccessibility(this,aVisitor.mPresContext,eFormRadioStateChange);// Fire event for the previous selected radio.nsCOMPtr<nsIDOMHTMLInputElement>previous=do_QueryInterface(aVisitor.mItemData);if(previous){FireEventForAccessibility(previous,aVisitor.mPresContext,eFormRadioStateChange);}}#endif}}if(NS_SUCCEEDED(rv)){WidgetKeyboardEvent*keyEvent=aVisitor.mEvent->AsKeyboardEvent();if(mType==NS_FORM_INPUT_NUMBER&&keyEvent&&keyEvent->mMessage==eKeyPress&&aVisitor.mEvent->IsTrusted()&&(keyEvent->mKeyCode==NS_VK_UP||keyEvent->mKeyCode==NS_VK_DOWN)&&!IgnoreInputEventWithModifier(keyEvent)){// We handle the up/down arrow keys specially for <input type=number>.// On some platforms the editor for the nested text control will// process these keys to send the cursor to the start/end of the text// control and as a result aVisitor.mEventStatus will already have been// set to nsEventStatus_eConsumeNoDefault. However, we know that// whenever the up/down arrow keys cause the value of the number// control to change the string in the text control will change, and// the cursor will be moved to the end of the text control, overwriting// the editor's handling of up/down keypress events. For that reason we// just ignore aVisitor.mEventStatus here and go ahead and handle the// event to increase/decrease the value of the number control.if(!aVisitor.mEvent->DefaultPreventedByContent()&&IsMutable()){StepNumberControlForUserEvent(keyEvent->mKeyCode==NS_VK_UP?1:-1);FireChangeEventIfNeeded();aVisitor.mEventStatus=nsEventStatus_eConsumeNoDefault;}}elseif(nsEventStatus_eIgnore==aVisitor.mEventStatus){switch(aVisitor.mEvent->mMessage){caseeFocus:{// see if we should select the contents of the textbox. This happens// for text and password fields when the field was focused by the// keyboard or a navigation, the platform allows it, and it wasn't// just because we raised a window.nsIFocusManager*fm=nsFocusManager::GetFocusManager();if(fm&&IsSingleLineTextControl(false)&&!aVisitor.mEvent->AsFocusEvent()->mFromRaise&&SelectTextFieldOnFocus()){nsIDocument*document=GetComposedDoc();if(document){uint32_tlastFocusMethod;fm->GetLastFocusMethod(document->GetWindow(),&lastFocusMethod);if(lastFocusMethod&(nsIFocusManager::FLAG_BYKEY|nsIFocusManager::FLAG_BYMOVEFOCUS)){RefPtr<nsPresContext>presContext=GetPresContext(eForComposedDoc);if(DispatchSelectEvent(presContext)){SelectAll(presContext);}}}}break;}caseeKeyPress:caseeKeyUp:{// For backwards compat, trigger checks/radios/buttons with// space or enter (bug 25300)WidgetKeyboardEvent*keyEvent=aVisitor.mEvent->AsKeyboardEvent();if((aVisitor.mEvent->mMessage==eKeyPress&&keyEvent->mKeyCode==NS_VK_RETURN)||(aVisitor.mEvent->mMessage==eKeyUp&&keyEvent->mKeyCode==NS_VK_SPACE)){switch(mType){caseNS_FORM_INPUT_CHECKBOX:caseNS_FORM_INPUT_RADIO:{// Checkbox and Radio try to submit on Enter pressif(keyEvent->mKeyCode!=NS_VK_SPACE){MaybeSubmitForm(aVisitor.mPresContext);break;// If we are submitting, do not send click event}// else fall through and treat Space like click...MOZ_FALLTHROUGH;}caseNS_FORM_INPUT_BUTTON:caseNS_FORM_INPUT_RESET:caseNS_FORM_INPUT_SUBMIT:caseNS_FORM_INPUT_IMAGE:// Bug 34418caseNS_FORM_INPUT_COLOR:{DispatchSimulatedClick(this,aVisitor.mEvent->IsTrusted(),aVisitor.mPresContext);aVisitor.mEventStatus=nsEventStatus_eConsumeNoDefault;}// case}// switch}if(aVisitor.mEvent->mMessage==eKeyPress&&mType==NS_FORM_INPUT_RADIO&&!keyEvent->IsAlt()&&!keyEvent->IsControl()&&!keyEvent->IsMeta()){boolisMovingBack=false;switch(keyEvent->mKeyCode){caseNS_VK_UP:caseNS_VK_LEFT:isMovingBack=true;MOZ_FALLTHROUGH;caseNS_VK_DOWN:caseNS_VK_RIGHT:// Arrow key pressed, focus+select prev/next radio buttonnsIRadioGroupContainer*container=GetRadioGroupContainer();if(container){nsAutoStringname;GetAttr(kNameSpaceID_None,nsGkAtoms::name,name);RefPtr<HTMLInputElement>selectedRadioButton;container->GetNextRadioButton(name,isMovingBack,this,getter_AddRefs(selectedRadioButton));if(selectedRadioButton){ErrorResulterror;selectedRadioButton->Focus(error);rv=error.StealNSResult();if(NS_SUCCEEDED(rv)){rv=DispatchSimulatedClick(selectedRadioButton,aVisitor.mEvent->IsTrusted(),aVisitor.mPresContext);if(NS_SUCCEEDED(rv)){aVisitor.mEventStatus=nsEventStatus_eConsumeNoDefault;}}}}}}/* * For some input types, if the user hits enter, the form is submitted. * * Bug 99920, bug 109463 and bug 147850: * (a) if there is a submit control in the form, click the first * submit control in the form. * (b) if there is just one text control in the form, submit by * sending a submit event directly to the form * (c) if there is more than one text input and no submit buttons, do * not submit, period. */if(aVisitor.mEvent->mMessage==eKeyPress&&keyEvent->mKeyCode==NS_VK_RETURN&&(IsSingleLineTextControl(false,mType)||mType==NS_FORM_INPUT_NUMBER||IsExperimentalMobileType(mType)||IsDateTimeInputType(mType))){FireChangeEventIfNeeded();rv=MaybeSubmitForm(aVisitor.mPresContext);NS_ENSURE_SUCCESS(rv,rv);}if(aVisitor.mEvent->mMessage==eKeyPress&&mType==NS_FORM_INPUT_RANGE&&!keyEvent->IsAlt()&&!keyEvent->IsControl()&&!keyEvent->IsMeta()&&(keyEvent->mKeyCode==NS_VK_LEFT||keyEvent->mKeyCode==NS_VK_RIGHT||keyEvent->mKeyCode==NS_VK_UP||keyEvent->mKeyCode==NS_VK_DOWN||keyEvent->mKeyCode==NS_VK_PAGE_UP||keyEvent->mKeyCode==NS_VK_PAGE_DOWN||keyEvent->mKeyCode==NS_VK_HOME||keyEvent->mKeyCode==NS_VK_END)){Decimalminimum=GetMinimum();Decimalmaximum=GetMaximum();MOZ_ASSERT(minimum.isFinite()&&maximum.isFinite());if(minimum<maximum){// else the value is locked to the minimumDecimalvalue=GetValueAsDecimal();Decimalstep=GetStep();if(step==kStepAny){step=GetDefaultStep();}MOZ_ASSERT(value.isFinite()&&step.isFinite());DecimalnewValue;switch(keyEvent->mKeyCode){caseNS_VK_LEFT:newValue=value+(GetComputedDirectionality()==eDir_RTL?step:-step);break;caseNS_VK_RIGHT:newValue=value+(GetComputedDirectionality()==eDir_RTL?-step:step);break;caseNS_VK_UP:// Even for horizontal range, "up" means "increase"newValue=value+step;break;caseNS_VK_DOWN:// Even for horizontal range, "down" means "decrease"newValue=value-step;break;caseNS_VK_HOME:newValue=minimum;break;caseNS_VK_END:newValue=maximum;break;caseNS_VK_PAGE_UP:// For PgUp/PgDn we jump 10% of the total range, unless step// requires us to jump more.newValue=value+std::max(step,(maximum-minimum)/Decimal(10));break;caseNS_VK_PAGE_DOWN:newValue=value-std::max(step,(maximum-minimum)/Decimal(10));break;}SetValueOfRangeForUserEvent(newValue);FireChangeEventIfNeeded();aVisitor.mEventStatus=nsEventStatus_eConsumeNoDefault;}}}break;// eKeyPress || eKeyUpcaseeMouseDown:caseeMouseUp:caseeMouseDoubleClick:{// cancel all of these events for buttons//XXXsmaug Why?WidgetMouseEvent*mouseEvent=aVisitor.mEvent->AsMouseEvent();if(mouseEvent->button==WidgetMouseEvent::eMiddleButton||mouseEvent->button==WidgetMouseEvent::eRightButton){if(mType==NS_FORM_INPUT_BUTTON||mType==NS_FORM_INPUT_RESET||mType==NS_FORM_INPUT_SUBMIT){if(aVisitor.mDOMEvent){aVisitor.mDOMEvent->StopPropagation();}else{rv=NS_ERROR_FAILURE;}}}if(mType==NS_FORM_INPUT_NUMBER&&aVisitor.mEvent->IsTrusted()){if(mouseEvent->button==WidgetMouseEvent::eLeftButton&&!IgnoreInputEventWithModifier(mouseEvent)){nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame){if(aVisitor.mEvent->mMessage==eMouseDown&&IsMutable()){switch(numberControlFrame->GetSpinButtonForPointerEvent(aVisitor.mEvent->AsMouseEvent())){casensNumberControlFrame::eSpinButtonUp:StepNumberControlForUserEvent(1);mNumberControlSpinnerSpinsUp=true;StartNumberControlSpinnerSpin();aVisitor.mEventStatus=nsEventStatus_eConsumeNoDefault;break;casensNumberControlFrame::eSpinButtonDown:StepNumberControlForUserEvent(-1);mNumberControlSpinnerSpinsUp=false;StartNumberControlSpinnerSpin();aVisitor.mEventStatus=nsEventStatus_eConsumeNoDefault;break;}}}}if(aVisitor.mEventStatus!=nsEventStatus_eConsumeNoDefault){// We didn't handle this to step up/down. Whatever this was, be// aggressive about stopping the spin. (And don't set// nsEventStatus_eConsumeNoDefault after doing so, since that// might prevent, say, the context menu from opening.)StopNumberControlSpinnerSpin();}}break;}#if !defined(ANDROID) && !defined(XP_MACOSX)caseeWheel:{// Handle wheel events as increasing / decreasing the input element's// value when it's focused and it's type is number or range.WidgetWheelEvent*wheelEvent=aVisitor.mEvent->AsWheelEvent();if(!aVisitor.mEvent->DefaultPrevented()&&aVisitor.mEvent->IsTrusted()&&IsMutable()&&wheelEvent&&wheelEvent->mDeltaY!=0&&wheelEvent->mDeltaMode!=nsIDOMWheelEvent::DOM_DELTA_PIXEL){if(mType==NS_FORM_INPUT_NUMBER){nsNumberControlFrame*numberControlFrame=do_QueryFrame(GetPrimaryFrame());if(numberControlFrame&&numberControlFrame->IsFocused()){StepNumberControlForUserEvent(wheelEvent->mDeltaY>0?-1:1);FireChangeEventIfNeeded();aVisitor.mEvent->PreventDefault();}}elseif(mType==NS_FORM_INPUT_RANGE&&nsContentUtils::IsFocusedContent(this)&&GetMinimum()<GetMaximum()){Decimalvalue=GetValueAsDecimal();Decimalstep=GetStep();if(step==kStepAny){step=GetDefaultStep();}MOZ_ASSERT(value.isFinite()&&step.isFinite());SetValueOfRangeForUserEvent(wheelEvent->mDeltaY<0?value+step:value-step);FireChangeEventIfNeeded();aVisitor.mEvent->PreventDefault();}}break;}#endifdefault:break;}if(outerActivateEvent){if(mForm&&(oldType==NS_FORM_INPUT_SUBMIT||oldType==NS_FORM_INPUT_IMAGE)){if(mType!=NS_FORM_INPUT_SUBMIT&&mType!=NS_FORM_INPUT_IMAGE){// If the type has changed to a non-submit type, then we want to// flush the stored submission if there is one (as if the submit()// was allowed to succeed)mForm->FlushPendingSubmission();}}switch(mType){caseNS_FORM_INPUT_RESET:caseNS_FORM_INPUT_SUBMIT:caseNS_FORM_INPUT_IMAGE:if(mForm){InternalFormEventevent(true,(mType==NS_FORM_INPUT_RESET)?eFormReset:eFormSubmit);event.mOriginator=this;nsEventStatusstatus=nsEventStatus_eIgnore;nsCOMPtr<nsIPresShell>presShell=aVisitor.mPresContext->GetPresShell();// If |nsIPresShell::Destroy| has been called due to// handling the event the pres context will return a null// pres shell. See bug 125624.// TODO: removing this code and have the submit event sent by the// form, see bug 592124.if(presShell&&(event.mMessage!=eFormSubmit||mForm->SubmissionCanProceed(this))){// Hold a strong ref while dispatchingRefPtr<mozilla::dom::HTMLFormElement>form(mForm);presShell->HandleDOMEventWithTarget(form,&event,&status);aVisitor.mEventStatus=nsEventStatus_eConsumeNoDefault;}}break;default:break;}//switch}//click or outer activate event}elseif(outerActivateEvent&&(oldType==NS_FORM_INPUT_SUBMIT||oldType==NS_FORM_INPUT_IMAGE)&&mForm){// tell the form to flush a possible pending submission.// the reason is that the script returned false (the event was// not ignored) so if there is a stored submission, it needs to// be submitted immediately.mForm->FlushPendingSubmission();}}// ifif(NS_SUCCEEDED(rv)&&mType==NS_FORM_INPUT_RANGE){PostHandleEventForRangeThumb(aVisitor);}returnMaybeInitPickers(aVisitor);}voidHTMLInputElement::PostHandleEventForRangeThumb(EventChainPostVisitor&aVisitor){MOZ_ASSERT(mType==NS_FORM_INPUT_RANGE);if((nsEventStatus_eConsumeNoDefault==aVisitor.mEventStatus&&!MozInputRangeIgnorePreventDefault())||!(aVisitor.mEvent->mClass==eMouseEventClass||aVisitor.mEvent->mClass==eTouchEventClass||aVisitor.mEvent->mClass==eKeyboardEventClass)){return;}nsRangeFrame*rangeFrame=do_QueryFrame(GetPrimaryFrame());if(!rangeFrame&&mIsDraggingRange){CancelRangeThumbDrag();return;}switch(aVisitor.mEvent->mMessage){caseeMouseDown:caseeTouchStart:{if(mIsDraggingRange){break;}if(nsIPresShell::GetCapturingContent()){break;// don't start drag if someone else is already capturing}WidgetInputEvent*inputEvent=aVisitor.mEvent->AsInputEvent();if(IgnoreInputEventWithModifier(inputEvent)){break;// ignore}if(aVisitor.mEvent->mMessage==eMouseDown){if(aVisitor.mEvent->AsMouseEvent()->buttons==WidgetMouseEvent::eLeftButtonFlag){StartRangeThumbDrag(inputEvent);}elseif(mIsDraggingRange){CancelRangeThumbDrag();}}else{if(aVisitor.mEvent->AsTouchEvent()->mTouches.Length()==1){StartRangeThumbDrag(inputEvent);}elseif(mIsDraggingRange){CancelRangeThumbDrag();}}aVisitor.mEvent->mFlags.mMultipleActionsPrevented=true;}break;caseeMouseMove:caseeTouchMove:if(!mIsDraggingRange){break;}if(nsIPresShell::GetCapturingContent()!=this){// Someone else grabbed capture.CancelRangeThumbDrag();break;}SetValueOfRangeForUserEvent(rangeFrame->GetValueAtEventPoint(aVisitor.mEvent->AsInputEvent()));aVisitor.mEvent->mFlags.mMultipleActionsPrevented=true;break;caseeMouseUp:caseeTouchEnd:if(!mIsDraggingRange){break;}// We don't check to see whether we are the capturing content here and// call CancelRangeThumbDrag() if that is the case. We just finish off// the drag and set our final value (unless someone has called// preventDefault() and prevents us getting here).FinishRangeThumbDrag(aVisitor.mEvent->AsInputEvent());aVisitor.mEvent->mFlags.mMultipleActionsPrevented=true;break;caseeKeyPress:if(mIsDraggingRange&&aVisitor.mEvent->AsKeyboardEvent()->mKeyCode==NS_VK_ESCAPE){CancelRangeThumbDrag();}break;caseeTouchCancel:if(mIsDraggingRange){CancelRangeThumbDrag();}break;default:break;}}voidHTMLInputElement::MaybeLoadImage(){// Our base URI may have changed; claim that our URI changed, and the// nsImageLoadingContent will decide whether a new image load is warranted.nsAutoStringuri;if(mType==NS_FORM_INPUT_IMAGE&&GetAttr(kNameSpaceID_None,nsGkAtoms::src,uri)&&(NS_FAILED(LoadImage(uri,false,true,eImageLoadType_Normal))||!LoadingEnabled())){CancelImageRequests(true);}}nsresultHTMLInputElement::BindToTree(nsIDocument*aDocument,nsIContent*aParent,nsIContent*aBindingParent,boolaCompileEventHandlers){nsresultrv=nsGenericHTMLFormElementWithState::BindToTree(aDocument,aParent,aBindingParent,aCompileEventHandlers);NS_ENSURE_SUCCESS(rv,rv);nsImageLoadingContent::BindToTree(aDocument,aParent,aBindingParent,aCompileEventHandlers);if(mType==NS_FORM_INPUT_IMAGE){// Our base URI may have changed; claim that our URI changed, and the// nsImageLoadingContent will decide whether a new image load is warranted.if(HasAttr(kNameSpaceID_None,nsGkAtoms::src)){// Mark channel as urgent-start before load image if the image load is// initaiated by a user interaction.mUseUrgentStartForChannel=EventStateManager::IsHandlingUserInput();// FIXME: Bug 660963 it would be nice if we could just have// ClearBrokenState update our state and do it fast...ClearBrokenState();RemoveStatesSilently(NS_EVENT_STATE_BROKEN);nsContentUtils::AddScriptRunner(NewRunnableMethod("dom::HTMLInputElement::MaybeLoadImage",this,&HTMLInputElement::MaybeLoadImage));}}// Add radio to document if we don't have a form already (if we do it's// already been added into that group)if(aDocument&&!mForm&&mType==NS_FORM_INPUT_RADIO){AddedToRadioGroup();}// Set direction based on value if dir=autoif(HasDirAuto()){SetDirectionFromValue(false);}// An element can't suffer from value missing if it is not in a document.// We have to check if we suffer from that as we are now in a document.UpdateValueMissingValidityState();// If there is a disabled fieldset in the parent chain, the element is now// barred from constraint validation and can't suffer from value missing// (call done before).UpdateBarredFromConstraintValidation();// And now make sure our state is up to dateUpdateState(false);if(mType==NS_FORM_INPUT_PASSWORD){if(IsInComposedDoc()){AsyncEventDispatcher*dispatcher=newAsyncEventDispatcher(this,NS_LITERAL_STRING("DOMInputPasswordAdded"),true,true);dispatcher->PostDOMEvent();}#ifdef EARLY_BETA_OR_EARLIERTelemetry::Accumulate(Telemetry::PWMGR_PASSWORD_INPUT_IN_FORM,!!mForm);#endif}returnrv;}voidHTMLInputElement::UnbindFromTree(boolaDeep,boolaNullParent){// If we have a form and are unbound from it,// nsGenericHTMLFormElementWithState::UnbindFromTree() will unset the form and// that takes care of form's WillRemove so we just have to take care// of the case where we're removing from the document and we don't// have a formif(!mForm&&mType==NS_FORM_INPUT_RADIO){WillRemoveFromRadioGroup();}nsImageLoadingContent::UnbindFromTree(aDeep,aNullParent);nsGenericHTMLFormElementWithState::UnbindFromTree(aDeep,aNullParent);// GetCurrentDoc is returning nullptr so we can update the value// missing validity state to reflect we are no longer into a doc.UpdateValueMissingValidityState();// We might be no longer disabled because of parent chain changed.UpdateBarredFromConstraintValidation();// And now make sure our state is up to dateUpdateState(false);}voidHTMLInputElement::HandleTypeChange(uint8_taNewType,boolaNotify){uint8_toldType=mType;MOZ_ASSERT(oldType!=aNewType);nsFocusManager*fm=nsFocusManager::GetFocusManager();if(fm){// Input element can represent very different kinds of UIs, and we may// need to flush styling even when focusing the already focused input// element.fm->NeedsFlushBeforeEventHandling(this);}if(aNewType==NS_FORM_INPUT_FILE||oldType==NS_FORM_INPUT_FILE){if(aNewType==NS_FORM_INPUT_FILE){mFileData.reset(newFileData());}else{mFileData->Unlink();mFileData=nullptr;}}if(oldType==NS_FORM_INPUT_RANGE&&mIsDraggingRange){CancelRangeThumbDrag(false);}ValueModeTypeaOldValueMode=GetValueMode();nsAutoStringaOldValue;if(aOldValueMode==VALUE_MODE_VALUE){// Doesn't matter what caller type we pass here, since we know we're not a// file input anyway.GetValue(aOldValue,CallerType::NonSystem);}nsTextEditorState::SelectionPropertiessp;if(GetEditorState()){mInputData.mState->SyncUpSelectionPropertiesBeforeDestruction();sp=mInputData.mState->GetSelectionProperties();}// We already have a copy of the value, lets free it and changes the type.FreeData();mType=aNewType;void*memory=mInputTypeMem;mInputType=InputType::Create(this,mType,memory);if(IsSingleLineTextControl()){mInputData.mState=nsTextEditorState::Construct(this,&sCachedTextEditorState);if(!sp.IsDefault()){mInputData.mState->SetSelectionProperties(sp);}}/** * The following code is trying to reproduce the algorithm described here: * http://www.whatwg.org/specs/web-apps/current-work/complete.html#input-type-change */switch(GetValueMode()){caseVALUE_MODE_DEFAULT:caseVALUE_MODE_DEFAULT_ON:// If the previous value mode was value, we need to set the value content// attribute to the previous value.// There is no value sanitizing algorithm for elements in this mode.if(aOldValueMode==VALUE_MODE_VALUE&&!aOldValue.IsEmpty()){SetAttr(kNameSpaceID_None,nsGkAtoms::value,aOldValue,true);}break;caseVALUE_MODE_VALUE:// If the previous value mode wasn't value, we have to set the value to// the value content attribute.// SetValueInternal is going to sanitize the value.{nsAutoStringvalue;if(aOldValueMode!=VALUE_MODE_VALUE){GetAttr(kNameSpaceID_None,nsGkAtoms::value,value);}else{value=aOldValue;}// TODO: What should we do if SetValueInternal fails? (The allocation// may potentially be big, but most likely we've failed to allocate// before the type change.)SetValueInternal(value,nsTextEditorState::eSetValue_Internal);}break;caseVALUE_MODE_FILENAME:default:// We don't care about the value.// There is no value sanitizing algorithm for elements in this mode.break;}// Updating mFocusedValue in consequence:// If the new type fires a change event on blur, but the previous type// doesn't, we should set mFocusedValue to the current value.// Otherwise, if the new type doesn't fire a change event on blur, but the// previous type does, we should clear out mFocusedValue.if(MayFireChangeOnBlur(mType)&&!MayFireChangeOnBlur(oldType)){GetValue(mFocusedValue,CallerType::System);}elseif(!IsSingleLineTextControl(false,mType)&&IsSingleLineTextControl(false,oldType)){mFocusedValue.Truncate();}// Update or clear our required states since we may have changed from a// required input type to a non-required input type or viceversa.if(DoesRequiredApply()){boolisRequired=HasAttr(kNameSpaceID_None,nsGkAtoms::required);UpdateRequiredState(isRequired,aNotify);}elseif(aNotify){RemoveStates(REQUIRED_STATES);}else{RemoveStatesSilently(REQUIRED_STATES);}UpdateHasRange();// Do not notify, it will be done after if needed.UpdateAllValidityStates(false);UpdateApzAwareFlag();UpdateBarredFromConstraintValidation();if(oldType==NS_FORM_INPUT_IMAGE){// We're no longer an image input. Cancel our image requests, if we have// any.CancelImageRequests(aNotify);}elseif(aNotify&&mType==NS_FORM_INPUT_IMAGE){// We just got switched to be an image input; we should see// whether we have an image to load;nsAutoStringsrc;if(GetAttr(kNameSpaceID_None,nsGkAtoms::src,src)){// Mark channel as urgent-start before load image if the image load is// initaiated by a user interaction.mUseUrgentStartForChannel=EventStateManager::IsHandlingUserInput();LoadImage(src,false,aNotify,eImageLoadType_Normal);}}if(mType==NS_FORM_INPUT_PASSWORD&&IsInComposedDoc()){AsyncEventDispatcher*dispatcher=newAsyncEventDispatcher(this,NS_LITERAL_STRING("DOMInputPasswordAdded"),true,true);dispatcher->PostDOMEvent();}}voidHTMLInputElement::SanitizeValue(nsAString&aValue){NS_ASSERTION(mDoneCreating,"The element creation should be finished!");switch(mType){caseNS_FORM_INPUT_TEXT:caseNS_FORM_INPUT_SEARCH:caseNS_FORM_INPUT_TEL:caseNS_FORM_INPUT_PASSWORD:{aValue.StripCRLF();}break;caseNS_FORM_INPUT_EMAIL:caseNS_FORM_INPUT_URL:{aValue.StripCRLF();aValue=nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(aValue);}break;caseNS_FORM_INPUT_NUMBER:{Decimalvalue;boolok=mInputType->ConvertStringToNumber(aValue,value);if(!ok){aValue.Truncate();}}break;caseNS_FORM_INPUT_RANGE:{Decimalminimum=GetMinimum();Decimalmaximum=GetMaximum();MOZ_ASSERT(minimum.isFinite()&&maximum.isFinite(),"type=range should have a default maximum/minimum");// We use this to avoid modifying the string unnecessarily, since that// may introduce rounding. This is set to true only if the value we// parse out from aValue needs to be sanitized.boolneedSanitization=false;Decimalvalue;boolok=mInputType->ConvertStringToNumber(aValue,value);if(!ok){needSanitization=true;// Set value to midway between minimum and maximum.value=maximum<=minimum?minimum:minimum+(maximum-minimum)/Decimal(2);}elseif(value<minimum||maximum<minimum){needSanitization=true;value=minimum;}elseif(value>maximum){needSanitization=true;value=maximum;}Decimalstep=GetStep();if(step!=kStepAny){DecimalstepBase=GetStepBase();// There could be rounding issues below when dealing with fractional// numbers, but let's ignore that until ECMAScript supplies us with a// decimal number type.DecimaldeltaToStep=NS_floorModulo(value-stepBase,step);if(deltaToStep!=Decimal(0)){// "suffering from a step mismatch"// Round the element's value to the nearest number for which the// element would not suffer from a step mismatch, and which is// greater than or equal to the minimum, and, if the maximum is not// less than the minimum, which is less than or equal to the// maximum, if there is a number that matches these constraints:MOZ_ASSERT(deltaToStep>Decimal(0),"stepBelow/stepAbove will be wrong");DecimalstepBelow=value-deltaToStep;DecimalstepAbove=value-deltaToStep+step;DecimalhalfStep=step/Decimal(2);boolstepAboveIsClosest=(stepAbove-value)<=halfStep;boolstepAboveInRange=stepAbove>=minimum&&stepAbove<=maximum;boolstepBelowInRange=stepBelow>=minimum&&stepBelow<=maximum;if((stepAboveIsClosest||!stepBelowInRange)&&stepAboveInRange){needSanitization=true;value=stepAbove;}elseif((!stepAboveIsClosest||!stepAboveInRange)&&stepBelowInRange){needSanitization=true;value=stepBelow;}}}if(needSanitization){charbuf[32];DebugOnly<bool>ok=value.toString(buf,ArrayLength(buf));aValue.AssignASCII(buf);MOZ_ASSERT(ok,"buf not big enough");}}break;caseNS_FORM_INPUT_DATE:{if(!aValue.IsEmpty()&&!IsValidDate(aValue)){aValue.Truncate();}}break;caseNS_FORM_INPUT_TIME:{if(!aValue.IsEmpty()&&!IsValidTime(aValue)){aValue.Truncate();}}break;caseNS_FORM_INPUT_MONTH:{if(!aValue.IsEmpty()&&!IsValidMonth(aValue)){aValue.Truncate();}}break;caseNS_FORM_INPUT_WEEK:{if(!aValue.IsEmpty()&&!IsValidWeek(aValue)){aValue.Truncate();}}break;caseNS_FORM_INPUT_DATETIME_LOCAL:{if(!aValue.IsEmpty()&&!IsValidDateTimeLocal(aValue)){aValue.Truncate();}else{NormalizeDateTimeLocal(aValue);}}break;caseNS_FORM_INPUT_COLOR:{if(IsValidSimpleColor(aValue)){ToLowerCase(aValue);}else{// Set default (black) color, if aValue wasn't parsed correctly.aValue.AssignLiteral("#000000");}}break;}}boolHTMLInputElement::IsValidSimpleColor(constnsAString&aValue)const{if(aValue.Length()!=7||aValue.First()!='#'){returnfalse;}for(inti=1;i<7;++i){if(!nsCRT::IsAsciiDigit(aValue[i])&&!(aValue[i]>='a'&&aValue[i]<='f')&&!(aValue[i]>='A'&&aValue[i]<='F')){returnfalse;}}returntrue;}boolHTMLInputElement::IsLeapYear(uint32_taYear)const{if((aYear%4==0&&aYear%100!=0)||(aYear%400==0)){returntrue;}returnfalse;}uint32_tHTMLInputElement::DayOfWeek(uint32_taYear,uint32_taMonth,uint32_taDay,boolisoWeek)const{// Tomohiko Sakamoto algorithm.intmonthTable[]={0,3,2,5,0,3,5,1,4,6,2,4};aYear-=aMonth<3;uint32_tday=(aYear+aYear/4-aYear/100+aYear/400+monthTable[aMonth-1]+aDay)%7;if(isoWeek){return((day+6)%7)+1;}returnday;}uint32_tHTMLInputElement::MaximumWeekInYear(uint32_taYear)const{intday=DayOfWeek(aYear,1,1,true);// January 1.// A year starting on Thursday or a leap year starting on Wednesday has 53// weeks. All other years have 52 weeks.returnday==4||(day==3&&IsLeapYear(aYear))?kMaximumWeekInYear:kMaximumWeekInYear-1;}boolHTMLInputElement::IsValidWeek(constnsAString&aValue)const{uint32_tyear,week;returnParseWeek(aValue,&year,&week);}boolHTMLInputElement::IsValidMonth(constnsAString&aValue)const{uint32_tyear,month;returnParseMonth(aValue,&year,&month);}boolHTMLInputElement::IsValidDate(constnsAString&aValue)const{uint32_tyear,month,day;returnParseDate(aValue,&year,&month,&day);}boolHTMLInputElement::IsValidDateTimeLocal(constnsAString&aValue)const{uint32_tyear,month,day,time;returnParseDateTimeLocal(aValue,&year,&month,&day,&time);}boolHTMLInputElement::ParseYear(constnsAString&aValue,uint32_t*aYear)const{if(aValue.Length()<4){returnfalse;}returnDigitSubStringToNumber(aValue,0,aValue.Length(),aYear)&&*aYear>0;}boolHTMLInputElement::ParseMonth(constnsAString&aValue,uint32_t*aYear,uint32_t*aMonth)const{// Parse the year, month values out a string formatted as 'yyyy-mm'.if(aValue.Length()<7){returnfalse;}uint32_tendOfYearOffset=aValue.Length()-3;if(aValue[endOfYearOffset]!='-'){returnfalse;}constnsAString&yearStr=Substring(aValue,0,endOfYearOffset);if(!ParseYear(yearStr,aYear)){returnfalse;}returnDigitSubStringToNumber(aValue,endOfYearOffset+1,2,aMonth)&&*aMonth>0&&*aMonth<=12;}boolHTMLInputElement::ParseWeek(constnsAString&aValue,uint32_t*aYear,uint32_t*aWeek)const{// Parse the year, month values out a string formatted as 'yyyy-Www'.if(aValue.Length()<8){returnfalse;}uint32_tendOfYearOffset=aValue.Length()-4;if(aValue[endOfYearOffset]!='-'){returnfalse;}if(aValue[endOfYearOffset+1]!='W'){returnfalse;}constnsAString&yearStr=Substring(aValue,0,endOfYearOffset);if(!ParseYear(yearStr,aYear)){returnfalse;}returnDigitSubStringToNumber(aValue,endOfYearOffset+2,2,aWeek)&&*aWeek>0&&*aWeek<=MaximumWeekInYear(*aYear);}boolHTMLInputElement::ParseDate(constnsAString&aValue,uint32_t*aYear,uint32_t*aMonth,uint32_t*aDay)const{/* * Parse the year, month, day values out a date string formatted as 'yyyy-mm-dd'. * -The year must be 4 or more digits long, and year > 0 * -The month must be exactly 2 digits long, and 01 <= month <= 12 * -The day must be exactly 2 digit long, and 01 <= day <= maxday * Where maxday is the number of days in the month 'month' and year 'year' */if(aValue.Length()<10){returnfalse;}uint32_tendOfMonthOffset=aValue.Length()-3;if(aValue[endOfMonthOffset]!='-'){returnfalse;}constnsAString&yearMonthStr=Substring(aValue,0,endOfMonthOffset);if(!ParseMonth(yearMonthStr,aYear,aMonth)){returnfalse;}returnDigitSubStringToNumber(aValue,endOfMonthOffset+1,2,aDay)&&*aDay>0&&*aDay<=NumberOfDaysInMonth(*aMonth,*aYear);}boolHTMLInputElement::ParseDateTimeLocal(constnsAString&aValue,uint32_t*aYear,uint32_t*aMonth,uint32_t*aDay,uint32_t*aTime)const{// Parse the year, month, day and time values out a string formatted as// 'yyyy-mm-ddThh:mm[:ss.s] or 'yyyy-mm-dd hh:mm[:ss.s]', where fractions of// seconds can be 1 to 3 digits.// The minimum length allowed is 16, which is of the form 'yyyy-mm-ddThh:mm'// or 'yyyy-mm-dd hh:mm'.if(aValue.Length()<16){returnfalse;}int32_tsepIndex=aValue.FindChar('T');if(sepIndex==-1){sepIndex=aValue.FindChar(' ');if(sepIndex==-1){returnfalse;}}constnsAString&dateStr=Substring(aValue,0,sepIndex);if(!ParseDate(dateStr,aYear,aMonth,aDay)){returnfalse;}constnsAString&timeStr=Substring(aValue,sepIndex+1,aValue.Length()-sepIndex+1);if(!ParseTime(timeStr,aTime)){returnfalse;}returntrue;}voidHTMLInputElement::NormalizeDateTimeLocal(nsAString&aValue)const{if(aValue.IsEmpty()){return;}// Use 'T' as the separator between date string and time string.int32_tsepIndex=aValue.FindChar(' ');if(sepIndex!=-1){aValue.Replace(sepIndex,1,NS_LITERAL_STRING("T"));}else{sepIndex=aValue.FindChar('T');}// Time expressed as the shortest possible string, which is hh:mm.if((aValue.Length()-sepIndex)==6){return;}// Fractions of seconds part is optional, ommit it if it's 0.if((aValue.Length()-sepIndex)>9){constuint32_tmillisecSepIndex=sepIndex+9;uint32_tmilliseconds;if(!DigitSubStringToNumber(aValue,millisecSepIndex+1,aValue.Length()-(millisecSepIndex+1),&milliseconds)){return;}if(milliseconds!=0){return;}aValue.Cut(millisecSepIndex,aValue.Length()-millisecSepIndex);}// Seconds part is optional, ommit it if it's 0.constuint32_tsecondSepIndex=sepIndex+6;uint32_tseconds;if(!DigitSubStringToNumber(aValue,secondSepIndex+1,aValue.Length()-(secondSepIndex+1),&seconds)){return;}if(seconds!=0){return;}aValue.Cut(secondSepIndex,aValue.Length()-secondSepIndex);}doubleHTMLInputElement::DaysSinceEpochFromWeek(uint32_taYear,uint32_taWeek)const{doubledays=JS::DayFromYear(aYear)+(aWeek-1)*7;uint32_tdayOneIsoWeekday=DayOfWeek(aYear,1,1,true);// If day one of that year is on/before Thursday, we should subtract the// days that belong to last year in our first week, otherwise, our first// days belong to last year's last week, and we should add those days// back.if(dayOneIsoWeekday<=4){days-=(dayOneIsoWeekday-1);}else{days+=(7-dayOneIsoWeekday+1);}returndays;}uint32_tHTMLInputElement::NumberOfDaysInMonth(uint32_taMonth,uint32_taYear)const{/* * Returns the number of days in a month. * Months that are |longMonths| always have 31 days. * Months that are not |longMonths| have 30 days except February (month 2). * February has 29 days during leap years which are years that are divisible by 400. * or divisible by 100 and 4. February has 28 days otherwise. */staticconstboollongMonths[]={true,false,true,false,true,false,true,true,false,true,false,true};MOZ_ASSERT(aMonth<=12&&aMonth>0);if(longMonths[aMonth-1]){return31;}if(aMonth!=2){return30;}returnIsLeapYear(aYear)?29:28;}/* static */boolHTMLInputElement::DigitSubStringToNumber(constnsAString&aStr,uint32_taStart,uint32_taLen,uint32_t*aRetVal){MOZ_ASSERT(aStr.Length()>(aStart+aLen-1));for(uint32_toffset=0;offset<aLen;++offset){if(!NS_IsAsciiDigit(aStr[aStart+offset])){returnfalse;}}nsresultec;*aRetVal=static_cast<uint32_t>(PromiseFlatString(Substring(aStr,aStart,aLen)).ToInteger(&ec));returnNS_SUCCEEDED(ec);}boolHTMLInputElement::IsValidTime(constnsAString&aValue)const{returnParseTime(aValue,nullptr);}/* static */boolHTMLInputElement::ParseTime(constnsAString&aValue,uint32_t*aResult){/* The string must have the following parts: * - HOURS: two digits, value being in [0, 23]; * - Colon (:); * - MINUTES: two digits, value being in [0, 59]; * - Optional: * - Colon (:); * - SECONDS: two digits, value being in [0, 59]; * - Optional: * - DOT (.); * - FRACTIONAL SECONDS: one to three digits, no value range. */// The following format is the shorter one allowed: "HH:MM".if(aValue.Length()<5){returnfalse;}uint32_thours;if(!DigitSubStringToNumber(aValue,0,2,&hours)||hours>23){returnfalse;}// Hours/minutes separator.if(aValue[2]!=':'){returnfalse;}uint32_tminutes;if(!DigitSubStringToNumber(aValue,3,2,&minutes)||minutes>59){returnfalse;}if(aValue.Length()==5){if(aResult){*aResult=((hours*60)+minutes)*60000;}returntrue;}// The following format is the next shorter one: "HH:MM:SS".if(aValue.Length()<8||aValue[5]!=':'){returnfalse;}uint32_tseconds;if(!DigitSubStringToNumber(aValue,6,2,&seconds)||seconds>59){returnfalse;}if(aValue.Length()==8){if(aResult){*aResult=(((hours*60)+minutes)*60+seconds)*1000;}returntrue;}// The string must follow this format now: "HH:MM:SS.{s,ss,sss}".// There can be 1 to 3 digits for the fractions of seconds.if(aValue.Length()==9||aValue.Length()>12||aValue[8]!='.'){returnfalse;}uint32_tfractionsSeconds;if(!DigitSubStringToNumber(aValue,9,aValue.Length()-9,&fractionsSeconds)){returnfalse;}if(aResult){*aResult=(((hours*60)+minutes)*60+seconds)*1000+// NOTE: there is 10.0 instead of 10 and static_cast<int> because// some old [and stupid] compilers can't just do the right thing.fractionsSeconds*pow(10.0,static_cast<int>(3-(aValue.Length()-9)));}returntrue;}/* static */boolHTMLInputElement::IsDateTimeTypeSupported(uint8_taDateTimeInputType){return((aDateTimeInputType==NS_FORM_INPUT_DATE||aDateTimeInputType==NS_FORM_INPUT_TIME)&&(IsInputDateTimeEnabled()||IsExperimentalFormsEnabled()))||((aDateTimeInputType==NS_FORM_INPUT_MONTH||aDateTimeInputType==NS_FORM_INPUT_WEEK||aDateTimeInputType==NS_FORM_INPUT_DATETIME_LOCAL)&&IsInputDateTimeOthersEnabled());}/* static */boolHTMLInputElement::IsWebkitDirPickerEnabled(){staticboolsWebkitDirPickerEnabled=false;staticboolsWebkitDirPickerPrefCached=false;if(!sWebkitDirPickerPrefCached){sWebkitDirPickerPrefCached=true;Preferences::AddBoolVarCache(&sWebkitDirPickerEnabled,"dom.webkitBlink.dirPicker.enabled",false);}returnsWebkitDirPickerEnabled;}/* static */boolHTMLInputElement::IsWebkitFileSystemEnabled(){staticboolsWebkitFileSystemEnabled=false;staticboolsWebkitFileSystemPrefCached=false;if(!sWebkitFileSystemPrefCached){sWebkitFileSystemPrefCached=true;Preferences::AddBoolVarCache(&sWebkitFileSystemEnabled,"dom.webkitBlink.filesystem.enabled",false);}returnsWebkitFileSystemEnabled;}/* static */boolHTMLInputElement::IsDirPickerEnabled(){staticboolsDirPickerEnabled=false;staticboolsDirPickerPrefCached=false;if(!sDirPickerPrefCached){sDirPickerPrefCached=true;Preferences::AddBoolVarCache(&sDirPickerEnabled,"dom.input.dirpicker",false);}returnsDirPickerEnabled;}/* static */boolHTMLInputElement::IsExperimentalFormsEnabled(){staticboolsExperimentalFormsEnabled=false;staticboolsExperimentalFormsPrefCached=false;if(!sExperimentalFormsPrefCached){sExperimentalFormsPrefCached=true;Preferences::AddBoolVarCache(&sExperimentalFormsEnabled,"dom.experimental_forms",false);}returnsExperimentalFormsEnabled;}/* static */boolHTMLInputElement::IsInputDateTimeEnabled(){staticboolsDateTimeEnabled=false;staticboolsDateTimePrefCached=false;if(!sDateTimePrefCached){sDateTimePrefCached=true;Preferences::AddBoolVarCache(&sDateTimeEnabled,"dom.forms.datetime",false);}returnsDateTimeEnabled;}/* static */boolHTMLInputElement::IsInputDateTimeOthersEnabled(){staticboolsDateTimeOthersEnabled=false;staticboolsDateTimeOthersPrefCached=false;if(!sDateTimeOthersPrefCached){sDateTimeOthersPrefCached=true;Preferences::AddBoolVarCache(&sDateTimeOthersEnabled,"dom.forms.datetime.others",false);}returnsDateTimeOthersEnabled;}/* static */boolHTMLInputElement::IsInputNumberEnabled(){staticboolsInputNumberEnabled=false;staticboolsInputNumberPrefCached=false;if(!sInputNumberPrefCached){sInputNumberPrefCached=true;Preferences::AddBoolVarCache(&sInputNumberEnabled,"dom.forms.number",false);}returnsInputNumberEnabled;}/* static */boolHTMLInputElement::IsInputColorEnabled(){staticboolsInputColorEnabled=false;staticboolsInputColorPrefCached=false;if(!sInputColorPrefCached){sInputColorPrefCached=true;Preferences::AddBoolVarCache(&sInputColorEnabled,"dom.forms.color",false);}returnsInputColorEnabled;}boolHTMLInputElement::ParseAttribute(int32_taNamespaceID,nsIAtom*aAttribute,constnsAString&aValue,nsAttrValue&aResult){// We can't make these static_asserts because kInputDefaultType and// kInputTypeTable aren't constexpr.MOZ_ASSERT(kInputDefaultType->value==NS_FORM_INPUT_TEXT,"Someone forgot to update kInputDefaultType when adding a new ""input type.");MOZ_ASSERT(kInputTypeTable[ArrayLength(kInputTypeTable)-1].tag==nullptr,"Last entry in the table must be the nullptr guard");MOZ_ASSERT(kInputTypeTable[ArrayLength(kInputTypeTable)-2].value==NS_FORM_INPUT_TEXT,"Next to last entry in the table must be the \"text\" entry");if(aNamespaceID==kNameSpaceID_None){if(aAttribute==nsGkAtoms::type){aResult.ParseEnumValue(aValue,kInputTypeTable,false,kInputDefaultType);int32_tnewType=aResult.GetEnumValue();if((newType==NS_FORM_INPUT_NUMBER&&!IsInputNumberEnabled())||(newType==NS_FORM_INPUT_COLOR&&!IsInputColorEnabled())||(IsDateTimeInputType(newType)&&!IsDateTimeTypeSupported(newType))){// There's no public way to set an nsAttrValue to an enum value, but we// can just re-parse with a table that doesn't have any types other than// "text" in it.aResult.ParseEnumValue(aValue,kInputDefaultType,false,kInputDefaultType);}returntrue;}if(aAttribute==nsGkAtoms::width){returnaResult.ParseSpecialIntValue(aValue);}if(aAttribute==nsGkAtoms::height){returnaResult.ParseSpecialIntValue(aValue);}if(aAttribute==nsGkAtoms::maxlength){returnaResult.ParseNonNegativeIntValue(aValue);}if(aAttribute==nsGkAtoms::minlength){returnaResult.ParseNonNegativeIntValue(aValue);}if(aAttribute==nsGkAtoms::size){returnaResult.ParsePositiveIntValue(aValue);}if(aAttribute==nsGkAtoms::border){returnaResult.ParseIntWithBounds(aValue,0);}if(aAttribute==nsGkAtoms::align){returnParseAlignValue(aValue,aResult);}if(aAttribute==nsGkAtoms::formmethod){returnaResult.ParseEnumValue(aValue,kFormMethodTable,false);}if(aAttribute==nsGkAtoms::formenctype){returnaResult.ParseEnumValue(aValue,kFormEnctypeTable,false);}if(aAttribute==nsGkAtoms::autocomplete){aResult.ParseAtomArray(aValue);returntrue;}if(aAttribute==nsGkAtoms::inputmode){returnaResult.ParseEnumValue(aValue,kInputInputmodeTable,false);}if(ParseImageAttribute(aAttribute,aValue,aResult)){// We have to call |ParseImageAttribute| unconditionally since we// don't know if we're going to have a type="image" attribute yet,// (or could have it set dynamically in the future). See bug// 214077.returntrue;}}returnnsGenericHTMLElement::ParseAttribute(aNamespaceID,aAttribute,aValue,aResult);}voidHTMLInputElement::MapAttributesIntoRule(constnsMappedAttributes*aAttributes,GenericSpecifiedValues*aData){constnsAttrValue*value=aAttributes->GetAttr(nsGkAtoms::type);if(value&&value->Type()==nsAttrValue::eEnum&&value->GetEnumValue()==NS_FORM_INPUT_IMAGE){nsGenericHTMLFormElementWithState::MapImageBorderAttributeInto(aAttributes,aData);nsGenericHTMLFormElementWithState::MapImageMarginAttributeInto(aAttributes,aData);nsGenericHTMLFormElementWithState::MapImageSizeAttributesInto(aAttributes,aData);// Images treat align as "float"nsGenericHTMLFormElementWithState::MapImageAlignAttributeInto(aAttributes,aData);}nsGenericHTMLFormElementWithState::MapCommonAttributesInto(aAttributes,aData);}nsChangeHintHTMLInputElement::GetAttributeChangeHint(constnsIAtom*aAttribute,int32_taModType)const{nsChangeHintretval=nsGenericHTMLFormElementWithState::GetAttributeChangeHint(aAttribute,aModType);if(aAttribute==nsGkAtoms::type||// The presence or absence of the 'directory' attribute determines what// buttons we show for type=file.aAttribute==nsGkAtoms::allowdirs||aAttribute==nsGkAtoms::webkitdirectory){retval|=nsChangeHint_ReconstructFrame;}elseif(mType==NS_FORM_INPUT_IMAGE&&(aAttribute==nsGkAtoms::alt||aAttribute==nsGkAtoms::value)){// We might need to rebuild our alt text. Just go ahead and// reconstruct our frame. This should be quite rare..retval|=nsChangeHint_ReconstructFrame;}elseif(aAttribute==nsGkAtoms::value){retval|=NS_STYLE_HINT_REFLOW;}elseif(aAttribute==nsGkAtoms::size&&IsSingleLineTextControl(false)){retval|=NS_STYLE_HINT_REFLOW;}elseif(PlaceholderApplies()&&aAttribute==nsGkAtoms::placeholder){retval|=nsChangeHint_ReconstructFrame;}returnretval;}NS_IMETHODIMP_(bool)HTMLInputElement::IsAttributeMapped(constnsIAtom*aAttribute)const{staticconstMappedAttributeEntryattributes[]={{&nsGkAtoms::align},{&nsGkAtoms::type},{nullptr},};staticconstMappedAttributeEntry*constmap[]={attributes,sCommonAttributeMap,sImageMarginSizeAttributeMap,sImageBorderAttributeMap,};returnFindAttributeDependence(aAttribute,map);}nsMapRuleToAttributesFuncHTMLInputElement::GetAttributeMappingFunction()const{return&MapAttributesIntoRule;}// Directory picking methods:boolHTMLInputElement::IsFilesAndDirectoriesSupported()const{// This method is supposed to return true if a file and directory picker// supports the selection of both files and directories *at the same time*.// Only Mac currently supports that. We could implement it for Mac, but// currently we do not.returnfalse;}voidHTMLInputElement::ChooseDirectory(ErrorResult&aRv){if(mType!=NS_FORM_INPUT_FILE){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}// Script can call this method directly, so even though we don't show the// "Pick Folder..." button on platforms that don't have a directory picker// we have to redirect to the file picker here.InitFilePicker(#if defined(ANDROID)// No native directory picker - redirect to plain file pickerFILE_PICKER_FILE#elseFILE_PICKER_DIRECTORY#endif);}already_AddRefed<Promise>HTMLInputElement::GetFilesAndDirectories(ErrorResult&aRv){if(mType!=NS_FORM_INPUT_FILE){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);returnnullptr;}nsCOMPtr<nsIGlobalObject>global=OwnerDoc()->GetScopeObject();MOZ_ASSERT(global);if(!global){returnnullptr;}RefPtr<Promise>p=Promise::Create(global,aRv);if(aRv.Failed()){returnnullptr;}constnsTArray<OwningFileOrDirectory>&filesAndDirs=GetFilesOrDirectoriesInternal();Sequence<OwningFileOrDirectory>filesAndDirsSeq;if(!filesAndDirsSeq.SetLength(filesAndDirs.Length(),mozilla::fallible_t())){p->MaybeReject(NS_ERROR_OUT_OF_MEMORY);returnp.forget();}for(uint32_ti=0;i<filesAndDirs.Length();++i){if(filesAndDirs[i].IsDirectory()){RefPtr<Directory>directory=filesAndDirs[i].GetAsDirectory();// In future we could refactor SetFilePickerFiltersFromAccept to return a// semicolon separated list of file extensions and include that in the// filter string passed here.directory->SetContentFilters(NS_LITERAL_STRING("filter-out-sensitive"));filesAndDirsSeq[i].SetAsDirectory()=directory;}else{MOZ_ASSERT(filesAndDirs[i].IsFile());// This file was directly selected by the user, so don't filter it.filesAndDirsSeq[i].SetAsFile()=filesAndDirs[i].GetAsFile();}}p->MaybeResolve(filesAndDirsSeq);returnp.forget();}already_AddRefed<Promise>HTMLInputElement::GetFiles(boolaRecursiveFlag,ErrorResult&aRv){if(mType!=NS_FORM_INPUT_FILE){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);returnnullptr;}GetFilesHelper*helper=GetOrCreateGetFilesHelper(aRecursiveFlag,aRv);if(NS_WARN_IF(aRv.Failed())){returnnullptr;}MOZ_ASSERT(helper);nsCOMPtr<nsIGlobalObject>global=OwnerDoc()->GetScopeObject();MOZ_ASSERT(global);if(!global){returnnullptr;}RefPtr<Promise>p=Promise::Create(global,aRv);if(aRv.Failed()){returnnullptr;}helper->AddPromise(p);returnp.forget();}// Controllers MethodsnsIControllers*HTMLInputElement::GetControllers(ErrorResult&aRv){//XXX: what about type "file"?if(IsSingleLineTextControl(false)){if(!mControllers){nsresultrv;mControllers=do_CreateInstance(kXULControllersCID,&rv);if(NS_FAILED(rv)){aRv.Throw(rv);returnnullptr;}nsCOMPtr<nsIController>controller(do_CreateInstance("@mozilla.org/editor/editorcontroller;1",&rv));if(NS_FAILED(rv)){aRv.Throw(rv);returnnullptr;}mControllers->AppendController(controller);controller=do_CreateInstance("@mozilla.org/editor/editingcontroller;1",&rv);if(NS_FAILED(rv)){aRv.Throw(rv);returnnullptr;}mControllers->AppendController(controller);}}returnmControllers;}NS_IMETHODIMPHTMLInputElement::GetControllers(nsIControllers**aResult){NS_ENSURE_ARG_POINTER(aResult);ErrorResultrv;RefPtr<nsIControllers>controller=GetControllers(rv);controller.forget(aResult);returnrv.StealNSResult();}int32_tHTMLInputElement::InputTextLength(CallerTypeaCallerType){nsAutoStringval;GetValue(val,aCallerType);returnval.Length();}voidHTMLInputElement::SetSelectionRange(uint32_taSelectionStart,uint32_taSelectionEnd,constOptional<nsAString>&aDirection,ErrorResult&aRv){if(!SupportsTextSelection()){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}nsTextEditorState*state=GetEditorState();MOZ_ASSERT(state,"SupportsTextSelection() returned true!");state->SetSelectionRange(aSelectionStart,aSelectionEnd,aDirection,aRv);}voidHTMLInputElement::SetRangeText(constnsAString&aReplacement,ErrorResult&aRv){if(!SupportsTextSelection()){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}nsTextEditorState*state=GetEditorState();MOZ_ASSERT(state,"SupportsTextSelection() returned true!");state->SetRangeText(aReplacement,aRv);}voidHTMLInputElement::SetRangeText(constnsAString&aReplacement,uint32_taStart,uint32_taEnd,SelectionModeaSelectMode,ErrorResult&aRv){if(!SupportsTextSelection()){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}nsTextEditorState*state=GetEditorState();MOZ_ASSERT(state,"SupportsTextSelection() returned true!");state->SetRangeText(aReplacement,aStart,aEnd,aSelectMode,aRv);}voidHTMLInputElement::GetValueFromSetRangeText(nsAString&aValue){GetNonFileValueInternal(aValue);}nsresultHTMLInputElement::SetValueFromSetRangeText(constnsAString&aValue){returnSetValueInternal(aValue,nsTextEditorState::eSetValue_ByContent|nsTextEditorState::eSetValue_Notify);}Nullable<uint32_t>HTMLInputElement::GetSelectionStart(ErrorResult&aRv){if(!SupportsTextSelection()){returnNullable<uint32_t>();}uint32_tselStart=GetSelectionStartIgnoringType(aRv);if(aRv.Failed()){returnNullable<uint32_t>();}returnNullable<uint32_t>(selStart);}uint32_tHTMLInputElement::GetSelectionStartIgnoringType(ErrorResult&aRv){uint32_tselEnd,selStart;GetSelectionRange(&selStart,&selEnd,aRv);returnselStart;}voidHTMLInputElement::SetSelectionStart(constNullable<uint32_t>&aSelectionStart,ErrorResult&aRv){if(!SupportsTextSelection()){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}nsTextEditorState*state=GetEditorState();MOZ_ASSERT(state,"SupportsTextSelection() returned true!");state->SetSelectionStart(aSelectionStart,aRv);}Nullable<uint32_t>HTMLInputElement::GetSelectionEnd(ErrorResult&aRv){if(!SupportsTextSelection()){returnNullable<uint32_t>();}uint32_tselEnd=GetSelectionEndIgnoringType(aRv);if(aRv.Failed()){returnNullable<uint32_t>();}returnNullable<uint32_t>(selEnd);}uint32_tHTMLInputElement::GetSelectionEndIgnoringType(ErrorResult&aRv){uint32_tselEnd,selStart;GetSelectionRange(&selStart,&selEnd,aRv);returnselEnd;}voidHTMLInputElement::SetSelectionEnd(constNullable<uint32_t>&aSelectionEnd,ErrorResult&aRv){if(!SupportsTextSelection()){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}nsTextEditorState*state=GetEditorState();MOZ_ASSERT(state,"SupportsTextSelection() returned true!");state->SetSelectionEnd(aSelectionEnd,aRv);}voidHTMLInputElement::GetSelectionRange(uint32_t*aSelectionStart,uint32_t*aSelectionEnd,ErrorResult&aRv){nsTextEditorState*state=GetEditorState();if(!state){// Not a text control.aRv.Throw(NS_ERROR_UNEXPECTED);return;}state->GetSelectionRange(aSelectionStart,aSelectionEnd,aRv);}voidHTMLInputElement::GetSelectionDirection(nsAString&aDirection,ErrorResult&aRv){if(!SupportsTextSelection()){aDirection.SetIsVoid(true);return;}nsTextEditorState*state=GetEditorState();MOZ_ASSERT(state,"SupportsTextSelection came back true!");state->GetSelectionDirectionString(aDirection,aRv);}voidHTMLInputElement::SetSelectionDirection(constnsAString&aDirection,ErrorResult&aRv){if(!SupportsTextSelection()){aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);return;}nsTextEditorState*state=GetEditorState();MOZ_ASSERT(state,"SupportsTextSelection came back true!");state->SetSelectionDirection(aDirection,aRv);}#ifdef ACCESSIBILITY/*static*/nsresultFireEventForAccessibility(nsIDOMHTMLInputElement*aTarget,nsPresContext*aPresContext,EventMessageaEventMessage){nsCOMPtr<mozilla::dom::Element>element=do_QueryInterface(aTarget);returnnsContentUtils::DispatchTrustedEvent<WidgetEvent>(element->OwnerDoc(),aTarget,aEventMessage,true,true);}#endifvoidHTMLInputElement::UpdateApzAwareFlag(){#if !defined(ANDROID) && !defined(XP_MACOSX)if((mType==NS_FORM_INPUT_NUMBER)||(mType==NS_FORM_INPUT_RANGE)){SetMayBeApzAware();}#endif}nsresultHTMLInputElement::SetDefaultValueAsValue(){NS_ASSERTION(GetValueMode()==VALUE_MODE_VALUE,"GetValueMode() should return VALUE_MODE_VALUE!");// The element has a content attribute value different from it's value when// it's in the value mode value.nsAutoStringresetVal;GetDefaultValue(resetVal);// SetValueInternal is going to sanitize the value.returnSetValueInternal(resetVal,nsTextEditorState::eSetValue_Internal);}voidHTMLInputElement::SetDirectionFromValue(boolaNotify){if(IsSingleLineTextControl(true)){nsAutoStringvalue;GetValue(value,CallerType::System);SetDirectionalityFromValue(this,value,aNotify);}}NS_IMETHODIMPHTMLInputElement::Reset(){// We should be able to reset all dirty flags regardless of the type.SetCheckedChanged(false);SetValueChanged(false);mLastValueChangeWasInteractive=false;switch(GetValueMode()){caseVALUE_MODE_VALUE:returnSetDefaultValueAsValue();caseVALUE_MODE_DEFAULT_ON:DoSetChecked(DefaultChecked(),true,false);returnNS_OK;caseVALUE_MODE_FILENAME:ClearFiles(false);returnNS_OK;caseVALUE_MODE_DEFAULT:default:returnNS_OK;}}NS_IMETHODIMPHTMLInputElement::SubmitNamesValues(HTMLFormSubmission*aFormSubmission){// Disabled elements don't submit// For type=reset, and type=button, we just never submit, period.// For type=image and type=button, we only submit if we were the button// pressed// For type=radio and type=checkbox, we only submit if checked=trueif(IsDisabled()||mType==NS_FORM_INPUT_RESET||mType==NS_FORM_INPUT_BUTTON||((mType==NS_FORM_INPUT_SUBMIT||mType==NS_FORM_INPUT_IMAGE)&&aFormSubmission->GetOriginatingElement()!=this)||((mType==NS_FORM_INPUT_RADIO||mType==NS_FORM_INPUT_CHECKBOX)&&!mChecked)){returnNS_OK;}// Get the namensAutoStringname;GetAttr(kNameSpaceID_None,nsGkAtoms::name,name);// Submit .x, .y for input type=imageif(mType==NS_FORM_INPUT_IMAGE){// Get a property set by the frame to find out where it was clicked.nsIntPoint*lastClickedPoint=static_cast<nsIntPoint*>(GetProperty(nsGkAtoms::imageClickedPoint));int32_tx,y;if(lastClickedPoint){// Convert the values to strings for submissionx=lastClickedPoint->x;y=lastClickedPoint->y;}else{x=y=0;}nsAutoStringxVal,yVal;xVal.AppendInt(x);yVal.AppendInt(y);if(!name.IsEmpty()){aFormSubmission->AddNameValuePair(name+NS_LITERAL_STRING(".x"),xVal);aFormSubmission->AddNameValuePair(name+NS_LITERAL_STRING(".y"),yVal);}else{// If the Image Element has no name, simply return x and y// to Nav and IE compatibility.aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("x"),xVal);aFormSubmission->AddNameValuePair(NS_LITERAL_STRING("y"),yVal);}returnNS_OK;}// If name not there, don't submitif(name.IsEmpty()){returnNS_OK;}//// Submit file if its input type=file and this encoding method accepts files//if(mType==NS_FORM_INPUT_FILE){// Submit filesconstnsTArray<OwningFileOrDirectory>&files=GetFilesOrDirectoriesInternal();if(files.IsEmpty()){aFormSubmission->AddNameBlobOrNullPair(name,nullptr);returnNS_OK;}for(uint32_ti=0;i<files.Length();++i){if(files[i].IsFile()){aFormSubmission->AddNameBlobOrNullPair(name,files[i].GetAsFile());}else{MOZ_ASSERT(files[i].IsDirectory());aFormSubmission->AddNameDirectoryPair(name,files[i].GetAsDirectory());}}