DXR is a code search and navigation tool aimed at making sense of large projects. It supports full-text and regex searches as well as structural queries.

Line Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
/* -*- 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 "NumericInputTypes.h"

#include "mozilla/dom/HTMLInputElement.h"
#include "nsNumberControlFrame.h"
#include "nsTextEditorState.h"

bool
NumericInputTypeBase::IsRangeOverflow() const
{
  mozilla::Decimal maximum = mInputElement->GetMaximum();
  if (maximum.isNaN()) {
    return false;
  }

  mozilla::Decimal value = mInputElement->GetValueAsDecimal();
  if (value.isNaN()) {
    return false;
  }

  return value > maximum;
}

bool
NumericInputTypeBase::IsRangeUnderflow() const
{
  mozilla::Decimal minimum = mInputElement->GetMinimum();
  if (minimum.isNaN()) {
    return false;
  }

  mozilla::Decimal value = mInputElement->GetValueAsDecimal();
  if (value.isNaN()) {
    return false;
  }

  return value < minimum;
}

bool
NumericInputTypeBase::HasStepMismatch(bool aUseZeroIfValueNaN) const
{
  mozilla::Decimal value = mInputElement->GetValueAsDecimal();
  if (value.isNaN()) {
    if (aUseZeroIfValueNaN) {
      value = mozilla::Decimal(0);
    } else {
      // The element can't suffer from step mismatch if it's value isn't a number.
      return false;
    }
  }

  mozilla::Decimal step = mInputElement->GetStep();
  if (step == kStepAny) {
    return false;
  }

  // Value has to be an integral multiple of step.
  return NS_floorModulo(value - GetStepBase(), step) != mozilla::Decimal(0);
}

nsresult
NumericInputTypeBase::GetRangeOverflowMessage(nsAString& aMessage)
{
  // We want to show the value as parsed when it's a number
  mozilla::Decimal maximum = mInputElement->GetMaximum();
  MOZ_ASSERT(!maximum.isNaN());

  nsAutoString maxStr;
  char buf[32];
  mozilla::DebugOnly<bool> ok = maximum.toString(buf,
                                                 mozilla::ArrayLength(buf));
  maxStr.AssignASCII(buf);
  MOZ_ASSERT(ok, "buf not big enough");

  const char16_t* params[] = { maxStr.get() };
  return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
    "FormValidationNumberRangeOverflow", params, aMessage);
}

nsresult
NumericInputTypeBase::GetRangeUnderflowMessage(nsAString& aMessage)
{
  mozilla::Decimal minimum = mInputElement->GetMinimum();
  MOZ_ASSERT(!minimum.isNaN());

  nsAutoString minStr;
  char buf[32];
  mozilla::DebugOnly<bool> ok = minimum.toString(buf,
                                                 mozilla::ArrayLength(buf));
  minStr.AssignASCII(buf);
  MOZ_ASSERT(ok, "buf not big enough");

  const char16_t* params[] = { minStr.get() };
  return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
    "FormValidationNumberRangeUnderflow", params, aMessage);
}

bool
NumericInputTypeBase::ConvertStringToNumber(nsAString& aValue,
  mozilla::Decimal& aResultValue) const
{
  aResultValue = mozilla::dom::HTMLInputElement::StringToDecimal(aValue);
  if (!aResultValue.isFinite()) {
    return false;
  }
  return true;
}

bool
NumericInputTypeBase::ConvertNumberToString(mozilla::Decimal aValue,
                                            nsAString& aResultString) const
{
  MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");

  aResultString.Truncate();

  char buf[32];
  bool ok = aValue.toString(buf, mozilla::ArrayLength(buf));
  aResultString.AssignASCII(buf);
  MOZ_ASSERT(ok, "buf not big enough");

  return ok;
}

/* input type=numer */

bool
NumberInputType::IsValueMissing() const
{
  if (!mInputElement->IsRequired()) {
    return false;
  }

  if (!IsMutable()) {
    return false;
  }

  return IsValueEmpty();
}

bool
NumberInputType::HasBadInput() const
{
  nsAutoString value;
  GetNonFileValueInternal(value);
  if (!value.IsEmpty()) {
    // The input can't be bad, otherwise it would have been sanitized to the
    // empty string.
    NS_ASSERTION(!mInputElement->GetValueAsDecimal().isNaN(),
                 "Should have sanitized");
    return false;
  }
  nsNumberControlFrame* numberControlFrame =
    do_QueryFrame(GetPrimaryFrame());
  if (numberControlFrame &&
      !numberControlFrame->AnonTextControlIsEmpty()) {
    // The input the user entered failed to parse as a number.
    return true;
  }
  return false;
}

nsresult
NumberInputType::GetValueMissingMessage(nsAString& aMessage)
{
  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
    "FormValidationBadInputNumber", aMessage);
}

nsresult
NumberInputType::GetBadInputMessage(nsAString& aMessage)
{
  return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
    "FormValidationBadInputNumber", aMessage);
}

bool
NumberInputType::IsMutable() const
{
  return !mInputElement->IsDisabled() &&
         !mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
}

/* input type=range */
nsresult
RangeInputType::MinMaxStepAttrChanged()
{
  // The value may need to change when @min/max/step changes since the value may
  // have been invalid and can now change to a valid value, or vice versa. For
  // example, consider: <input type=range value=-1 max=1 step=3>. The valid
  // range is 0 to 1 while the nearest valid steps are -1 and 2 (the max value
  // having prevented there being a valid step in range). Changing @max to/from
  // 1 and a number greater than on equal to 3 should change whether we have a
  // step mismatch or not.
  // The value may also need to change between a value that results in a step
  // mismatch and a value that results in overflow. For example, if @max in the
  // example above were to change from 1 to -1.
  nsAutoString value;
  GetNonFileValueInternal(value);
  return SetValueInternal(value, nsTextEditorState::eSetValue_Internal);
}