tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

InputType.cpp (13248B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/InputType.h"
      8 
      9 #include "mozilla/Assertions.h"
     10 #include "mozilla/Likely.h"
     11 #include "mozilla/dom/ButtonInputTypes.h"
     12 #include "mozilla/dom/CheckableInputTypes.h"
     13 #include "mozilla/dom/ColorInputType.h"
     14 #include "mozilla/dom/DateTimeInputTypes.h"
     15 #include "mozilla/dom/FileInputType.h"
     16 #include "mozilla/dom/HTMLInputElement.h"
     17 #include "mozilla/dom/HiddenInputType.h"
     18 #include "mozilla/dom/NumericInputTypes.h"
     19 #include "mozilla/dom/SingleLineTextInputTypes.h"
     20 #include "nsContentUtils.h"
     21 #include "nsIFormControl.h"
     22 
     23 using namespace mozilla;
     24 using namespace mozilla::dom;
     25 
     26 constexpr Decimal InputType::kStepAny;
     27 
     28 /* static */ UniquePtr<InputType, InputType::DoNotDelete> InputType::Create(
     29    HTMLInputElement* aInputElement, FormControlType aType, void* aMemory) {
     30  UniquePtr<InputType, InputType::DoNotDelete> inputType;
     31  switch (aType) {
     32    // Single line text
     33    case FormControlType::InputText:
     34      inputType.reset(TextInputType::Create(aInputElement, aMemory));
     35      break;
     36    case FormControlType::InputTel:
     37      inputType.reset(TelInputType::Create(aInputElement, aMemory));
     38      break;
     39    case FormControlType::InputEmail:
     40      inputType.reset(EmailInputType::Create(aInputElement, aMemory));
     41      break;
     42    case FormControlType::InputSearch:
     43      inputType.reset(SearchInputType::Create(aInputElement, aMemory));
     44      break;
     45    case FormControlType::InputPassword:
     46      inputType.reset(PasswordInputType::Create(aInputElement, aMemory));
     47      break;
     48    case FormControlType::InputUrl:
     49      inputType.reset(URLInputType::Create(aInputElement, aMemory));
     50      break;
     51    // Button
     52    case FormControlType::InputButton:
     53      inputType.reset(ButtonInputType::Create(aInputElement, aMemory));
     54      break;
     55    case FormControlType::InputSubmit:
     56      inputType.reset(SubmitInputType::Create(aInputElement, aMemory));
     57      break;
     58    case FormControlType::InputImage:
     59      inputType.reset(ImageInputType::Create(aInputElement, aMemory));
     60      break;
     61    case FormControlType::InputReset:
     62      inputType.reset(ResetInputType::Create(aInputElement, aMemory));
     63      break;
     64    // Checkable
     65    case FormControlType::InputCheckbox:
     66      inputType.reset(CheckboxInputType::Create(aInputElement, aMemory));
     67      break;
     68    case FormControlType::InputRadio:
     69      inputType.reset(RadioInputType::Create(aInputElement, aMemory));
     70      break;
     71    // Numeric
     72    case FormControlType::InputNumber:
     73      inputType.reset(NumberInputType::Create(aInputElement, aMemory));
     74      break;
     75    case FormControlType::InputRange:
     76      inputType.reset(RangeInputType::Create(aInputElement, aMemory));
     77      break;
     78    // DateTime
     79    case FormControlType::InputDate:
     80      inputType.reset(DateInputType::Create(aInputElement, aMemory));
     81      break;
     82    case FormControlType::InputTime:
     83      inputType.reset(TimeInputType::Create(aInputElement, aMemory));
     84      break;
     85    case FormControlType::InputMonth:
     86      inputType.reset(MonthInputType::Create(aInputElement, aMemory));
     87      break;
     88    case FormControlType::InputWeek:
     89      inputType.reset(WeekInputType::Create(aInputElement, aMemory));
     90      break;
     91    case FormControlType::InputDatetimeLocal:
     92      inputType.reset(DateTimeLocalInputType::Create(aInputElement, aMemory));
     93      break;
     94    // Others
     95    case FormControlType::InputColor:
     96      inputType.reset(ColorInputType::Create(aInputElement, aMemory));
     97      break;
     98    case FormControlType::InputFile:
     99      inputType.reset(FileInputType::Create(aInputElement, aMemory));
    100      break;
    101    case FormControlType::InputHidden:
    102      inputType.reset(HiddenInputType::Create(aInputElement, aMemory));
    103      break;
    104    default:
    105      inputType.reset(TextInputType::Create(aInputElement, aMemory));
    106  }
    107 
    108  return inputType;
    109 }
    110 
    111 bool InputType::IsMutable() const { return !mInputElement->IsDisabled(); }
    112 
    113 bool InputType::IsValueEmpty() const { return mInputElement->IsValueEmpty(); }
    114 
    115 void InputType::GetNonFileValueInternal(nsAString& aValue) const {
    116  return mInputElement->GetNonFileValueInternal(aValue);
    117 }
    118 
    119 nsresult InputType::SetValueInternal(const nsAString& aValue,
    120                                     const ValueSetterOptions& aOptions) {
    121  RefPtr<HTMLInputElement> inputElement(mInputElement);
    122  return inputElement->SetValueInternal(aValue, aOptions);
    123 }
    124 
    125 nsIFrame* InputType::GetPrimaryFrame() const {
    126  return mInputElement->GetPrimaryFrame();
    127 }
    128 
    129 void InputType::DropReference() {
    130  // Drop our (non ref-counted) reference.
    131  mInputElement = nullptr;
    132 }
    133 
    134 bool InputType::IsTooLong() const { return false; }
    135 
    136 bool InputType::IsTooShort() const { return false; }
    137 
    138 bool InputType::IsValueMissing() const { return false; }
    139 
    140 bool InputType::HasTypeMismatch() const { return false; }
    141 
    142 Maybe<bool> InputType::HasPatternMismatch() const { return Some(false); }
    143 
    144 bool InputType::IsRangeOverflow() const { return false; }
    145 
    146 bool InputType::IsRangeUnderflow() const { return false; }
    147 
    148 bool InputType::HasStepMismatch() const { return false; }
    149 
    150 bool InputType::HasBadInput() const { return false; }
    151 
    152 nsresult InputType::GetValidationMessage(
    153    nsAString& aValidationMessage,
    154    nsIConstraintValidation::ValidityStateType aType) {
    155  aValidationMessage.Truncate();
    156 
    157  switch (aType) {
    158    case nsIConstraintValidation::VALIDITY_STATE_TOO_LONG: {
    159      int32_t maxLength = mInputElement->MaxLength();
    160      int32_t textLength = mInputElement->InputTextLength(CallerType::System);
    161      nsAutoString strMaxLength;
    162      nsAutoString strTextLength;
    163 
    164      strMaxLength.AppendInt(maxLength);
    165      strTextLength.AppendInt(textLength);
    166 
    167      return nsContentUtils::FormatMaybeLocalizedString(
    168          aValidationMessage, nsContentUtils::eDOM_PROPERTIES,
    169          "FormValidationTextTooLong", mInputElement->OwnerDoc(), strMaxLength,
    170          strTextLength);
    171    }
    172    case nsIConstraintValidation::VALIDITY_STATE_TOO_SHORT: {
    173      int32_t minLength = mInputElement->MinLength();
    174      int32_t textLength = mInputElement->InputTextLength(CallerType::System);
    175      nsAutoString strMinLength;
    176      nsAutoString strTextLength;
    177 
    178      strMinLength.AppendInt(minLength);
    179      strTextLength.AppendInt(textLength);
    180 
    181      return nsContentUtils::FormatMaybeLocalizedString(
    182          aValidationMessage, nsContentUtils::eDOM_PROPERTIES,
    183          "FormValidationTextTooShort", mInputElement->OwnerDoc(), strMinLength,
    184          strTextLength);
    185    }
    186    case nsIConstraintValidation::VALIDITY_STATE_VALUE_MISSING:
    187      return GetValueMissingMessage(aValidationMessage);
    188    case nsIConstraintValidation::VALIDITY_STATE_TYPE_MISMATCH: {
    189      return GetTypeMismatchMessage(aValidationMessage);
    190    }
    191    case nsIConstraintValidation::VALIDITY_STATE_PATTERN_MISMATCH: {
    192      nsAutoString title;
    193      mInputElement->GetAttr(nsGkAtoms::title, title);
    194 
    195      if (title.IsEmpty()) {
    196        return nsContentUtils::GetMaybeLocalizedString(
    197            nsContentUtils::eDOM_PROPERTIES, "FormValidationPatternMismatch",
    198            mInputElement->OwnerDoc(), aValidationMessage);
    199      }
    200 
    201      if (title.Length() >
    202          nsIConstraintValidation::sContentSpecifiedMaxLengthMessage) {
    203        title.Truncate(
    204            nsIConstraintValidation::sContentSpecifiedMaxLengthMessage);
    205      }
    206      return nsContentUtils::FormatMaybeLocalizedString(
    207          aValidationMessage, nsContentUtils::eDOM_PROPERTIES,
    208          "FormValidationPatternMismatchWithTitle", mInputElement->OwnerDoc(),
    209          title);
    210    }
    211    case nsIConstraintValidation::VALIDITY_STATE_RANGE_OVERFLOW:
    212      return GetRangeOverflowMessage(aValidationMessage);
    213    case nsIConstraintValidation::VALIDITY_STATE_RANGE_UNDERFLOW:
    214      return GetRangeUnderflowMessage(aValidationMessage);
    215    case nsIConstraintValidation::VALIDITY_STATE_STEP_MISMATCH: {
    216      Decimal value = mInputElement->GetValueAsDecimal();
    217      if (MOZ_UNLIKELY(NS_WARN_IF(value.isNaN()))) {
    218        // TODO(bug 1651070): This should ideally never happen, but we don't
    219        // deal with lang changes correctly, so it could.
    220        return GetBadInputMessage(aValidationMessage);
    221      }
    222 
    223      Decimal step = mInputElement->GetStep();
    224      MOZ_ASSERT(step != kStepAny && step > Decimal(0));
    225 
    226      Decimal stepBase = mInputElement->GetStepBase();
    227 
    228      Decimal valueLow = value - NS_floorModulo(value - stepBase, step);
    229      Decimal valueHigh = value + step - NS_floorModulo(value - stepBase, step);
    230 
    231      Decimal maximum = mInputElement->GetMaximum();
    232 
    233      if (maximum.isNaN() || valueHigh <= maximum) {
    234        nsAutoString valueLowStr, valueHighStr;
    235        ConvertNumberToString(valueLow, Localized::Yes, valueLowStr);
    236        ConvertNumberToString(valueHigh, Localized::Yes, valueHighStr);
    237 
    238        if (valueLowStr.Equals(valueHighStr)) {
    239          return nsContentUtils::FormatMaybeLocalizedString(
    240              aValidationMessage, nsContentUtils::eDOM_PROPERTIES,
    241              "FormValidationStepMismatchOneValue", mInputElement->OwnerDoc(),
    242              valueLowStr);
    243        }
    244        return nsContentUtils::FormatMaybeLocalizedString(
    245            aValidationMessage, nsContentUtils::eDOM_PROPERTIES,
    246            "FormValidationStepMismatch", mInputElement->OwnerDoc(),
    247            valueLowStr, valueHighStr);
    248      }
    249 
    250      nsAutoString valueLowStr;
    251      ConvertNumberToString(valueLow, Localized::Yes, valueLowStr);
    252 
    253      return nsContentUtils::FormatMaybeLocalizedString(
    254          aValidationMessage, nsContentUtils::eDOM_PROPERTIES,
    255          "FormValidationStepMismatchOneValue", mInputElement->OwnerDoc(),
    256          valueLowStr);
    257    }
    258    case nsIConstraintValidation::VALIDITY_STATE_BAD_INPUT:
    259      return GetBadInputMessage(aValidationMessage);
    260    default:
    261      MOZ_ASSERT_UNREACHABLE("Unknown validity state");
    262      return NS_ERROR_UNEXPECTED;
    263  }
    264 }
    265 
    266 nsresult InputType::GetValueMissingMessage(nsAString& aMessage) {
    267  return nsContentUtils::GetMaybeLocalizedString(
    268      nsContentUtils::eDOM_PROPERTIES, "FormValidationValueMissing",
    269      mInputElement->OwnerDoc(), aMessage);
    270 }
    271 
    272 nsresult InputType::GetTypeMismatchMessage(nsAString& aMessage) {
    273  return NS_ERROR_UNEXPECTED;
    274 }
    275 
    276 nsresult InputType::GetRangeOverflowMessage(nsAString& aMessage) {
    277  return NS_ERROR_UNEXPECTED;
    278 }
    279 
    280 nsresult InputType::GetRangeUnderflowMessage(nsAString& aMessage) {
    281  return NS_ERROR_UNEXPECTED;
    282 }
    283 
    284 nsresult InputType::GetBadInputMessage(nsAString& aMessage) {
    285  return NS_ERROR_UNEXPECTED;
    286 }
    287 
    288 auto InputType::ConvertStringToNumber(const nsAString& aValue) const
    289    -> StringToNumberResult {
    290  NS_WARNING("InputType::ConvertStringToNumber called");
    291  return {};
    292 }
    293 
    294 bool InputType::ConvertNumberToString(Decimal, Localized, nsAString&) const {
    295  NS_WARNING("InputType::ConvertNumberToString called");
    296  return false;
    297 }
    298 
    299 bool InputType::ParseDate(const nsAString& aValue, uint32_t* aYear,
    300                          uint32_t* aMonth, uint32_t* aDay) const {
    301  // TODO: move this function and implementation to DateTimeInpuTypeBase when
    302  // refactoring is completed. Now we can only call HTMLInputElement::ParseDate
    303  // from here, since the method is protected and only InputType is a friend
    304  // class.
    305  return mInputElement->ParseDate(aValue, aYear, aMonth, aDay);
    306 }
    307 
    308 bool InputType::ParseTime(const nsAString& aValue, uint32_t* aResult) const {
    309  // see comment in InputType::ParseDate().
    310  return HTMLInputElement::ParseTime(aValue, aResult);
    311 }
    312 
    313 bool InputType::ParseMonth(const nsAString& aValue, uint32_t* aYear,
    314                           uint32_t* aMonth) const {
    315  // see comment in InputType::ParseDate().
    316  return mInputElement->ParseMonth(aValue, aYear, aMonth);
    317 }
    318 
    319 bool InputType::ParseWeek(const nsAString& aValue, uint32_t* aYear,
    320                          uint32_t* aWeek) const {
    321  // see comment in InputType::ParseDate().
    322  return mInputElement->ParseWeek(aValue, aYear, aWeek);
    323 }
    324 
    325 bool InputType::ParseDateTimeLocal(const nsAString& aValue, uint32_t* aYear,
    326                                   uint32_t* aMonth, uint32_t* aDay,
    327                                   uint32_t* aTime) const {
    328  // see comment in InputType::ParseDate().
    329  return mInputElement->ParseDateTimeLocal(aValue, aYear, aMonth, aDay, aTime);
    330 }
    331 
    332 int32_t InputType::MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const {
    333  // see comment in InputType::ParseDate().
    334  return mInputElement->MonthsSinceJan1970(aYear, aMonth);
    335 }
    336 
    337 double InputType::DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const {
    338  // see comment in InputType::ParseDate().
    339  return mInputElement->DaysSinceEpochFromWeek(aYear, aWeek);
    340 }
    341 
    342 uint32_t InputType::DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
    343                              bool isoWeek) const {
    344  // see comment in InputType::ParseDate().
    345  return mInputElement->DayOfWeek(aYear, aMonth, aDay, isoWeek);
    346 }
    347 
    348 uint32_t InputType::MaximumWeekInYear(uint32_t aYear) const {
    349  // see comment in InputType::ParseDate().
    350  return mInputElement->MaximumWeekInYear(aYear);
    351 }