Bug 1363258 - Part 2: Factor ConvertNumberToString out of HTMLInputElement. r=smaug

MozReview-Commit-ID: 8ZHrdvpjr0m
This commit is contained in:
Jessica Jong
2017-05-10 17:03:46 +08:00
parent e5b97d1691
commit 13b5e022fc
8 changed files with 285 additions and 214 deletions

View File

@@ -1943,175 +1943,11 @@ HTMLInputElement::SetValue(Decimal aValue, CallerType aCallerType)
}
nsAutoString value;
ConvertNumberToString(aValue, value);
mInputType->ConvertNumberToString(aValue, value);
IgnoredErrorResult rv;
SetValue(value, aCallerType, rv);
}
bool
HTMLInputElement::ConvertNumberToString(Decimal aValue,
nsAString& aResultString) const
{
MOZ_ASSERT(DoesValueAsNumberApply(),
"ConvertNumberToString is only implemented for types implementing .valueAsNumber");
MOZ_ASSERT(aValue.isFinite(),
"aValue must be a valid non-Infinite number.");
aResultString.Truncate();
switch (mType) {
case NS_FORM_INPUT_NUMBER:
case NS_FORM_INPUT_RANGE:
{
char buf[32];
bool ok = aValue.toString(buf, ArrayLength(buf));
aResultString.AssignASCII(buf);
MOZ_ASSERT(ok, "buf not big enough");
return ok;
}
case NS_FORM_INPUT_DATE:
{
// The specs (and our JS APIs) require |aValue| to be truncated.
aValue = aValue.floor();
double year = JS::YearFromTime(aValue.toDouble());
double month = JS::MonthFromTime(aValue.toDouble());
double day = JS::DayFromTime(aValue.toDouble());
if (IsNaN(year) || IsNaN(month) || IsNaN(day)) {
return false;
}
aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year,
month + 1, day);
return true;
}
case NS_FORM_INPUT_TIME:
{
aValue = aValue.floor();
// Per spec, we need to truncate |aValue| and we should only represent
// times inside a day [00:00, 24:00[, which means that we should do a
// modulo on |aValue| using the number of milliseconds in a day (86400000).
uint32_t value =
NS_floorModulo(aValue, Decimal::fromDouble(kMsPerDay)).toDouble();
uint16_t milliseconds, seconds, minutes, hours;
if (!GetTimeFromMs(value, &hours, &minutes, &seconds, &milliseconds)) {
return false;
}
if (milliseconds != 0) {
aResultString.AppendPrintf("%02d:%02d:%02d.%03d",
hours, minutes, seconds, milliseconds);
} else if (seconds != 0) {
aResultString.AppendPrintf("%02d:%02d:%02d",
hours, minutes, seconds);
} else {
aResultString.AppendPrintf("%02d:%02d", hours, minutes);
}
return true;
}
case NS_FORM_INPUT_MONTH:
{
aValue = aValue.floor();
double month = NS_floorModulo(aValue, Decimal(12)).toDouble();
month = (month < 0 ? month + 12 : month);
double year = 1970 + (aValue.toDouble() - month) / 12;
// Maximum valid month is 275760-09.
if (year < kMinimumYear || year > kMaximumYear) {
return false;
}
if (year == kMaximumYear && month > 8) {
return false;
}
aResultString.AppendPrintf("%04.0f-%02.0f", year, month + 1);
return true;
}
case NS_FORM_INPUT_WEEK:
{
aValue = aValue.floor();
// Based on ISO 8601 date.
double year = JS::YearFromTime(aValue.toDouble());
double month = JS::MonthFromTime(aValue.toDouble());
double day = JS::DayFromTime(aValue.toDouble());
// Adding 1 since day starts from 0.
double dayInYear = JS::DayWithinYear(aValue.toDouble(), year) + 1;
// Adding 1 since month starts from 0.
uint32_t isoWeekday = DayOfWeek(year, month + 1, day, true);
// Target on Wednesday since ISO 8601 states that week 1 is the week
// with the first Thursday of that year.
uint32_t week = (dayInYear - isoWeekday + 10) / 7;
if (week < 1) {
year--;
if (year < 1) {
return false;
}
week = MaximumWeekInYear(year);
} else if (week > MaximumWeekInYear(year)) {
year++;
if (year > kMaximumYear ||
(year == kMaximumYear && week > kMaximumWeekInMaximumYear)) {
return false;
}
week = 1;
}
aResultString.AppendPrintf("%04.0f-W%02d", year, week);
return true;
}
case NS_FORM_INPUT_DATETIME_LOCAL:
{
aValue = aValue.floor();
uint32_t timeValue =
NS_floorModulo(aValue, Decimal::fromDouble(kMsPerDay)).toDouble();
uint16_t milliseconds, seconds, minutes, hours;
if (!GetTimeFromMs(timeValue,
&hours, &minutes, &seconds, &milliseconds)) {
return false;
}
double year = JS::YearFromTime(aValue.toDouble());
double month = JS::MonthFromTime(aValue.toDouble());
double day = JS::DayFromTime(aValue.toDouble());
if (IsNaN(year) || IsNaN(month) || IsNaN(day)) {
return false;
}
if (milliseconds != 0) {
aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d.%03d",
year, month + 1, day, hours, minutes,
seconds, milliseconds);
} else if (seconds != 0) {
aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d",
year, month + 1, day, hours, minutes,
seconds);
} else {
aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d",
year, month + 1, day, hours, minutes);
}
return true;
}
default:
MOZ_ASSERT(false, "Unrecognized input type");
return false;
}
}
Nullable<Date>
HTMLInputElement::GetValueAsDate(ErrorResult& aRv)
{
@@ -4146,7 +3982,7 @@ HTMLInputElement::CancelRangeThumbDrag(bool aIsForUserEvent)
// DispatchTrustedEvent.
// TODO: decide what we should do here - bug 851782.
nsAutoString val;
ConvertNumberToString(mRangeThumbDragStartValue, val);
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 |
@@ -4169,7 +4005,7 @@ HTMLInputElement::SetValueOfRangeForUserEvent(Decimal aValue)
Decimal oldValue = GetValueAsDecimal();
nsAutoString val;
ConvertNumberToString(aValue, val);
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 |
@@ -4272,7 +4108,7 @@ HTMLInputElement::StepNumberControlForUserEvent(int32_t aDirection)
}
nsAutoString newVal;
ConvertNumberToString(newValue, newVal);
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 |
@@ -5419,29 +5255,6 @@ HTMLInputElement::MaximumWeekInYear(uint32_t aYear) const
kMaximumWeekInYear : kMaximumWeekInYear - 1;
}
bool
HTMLInputElement::GetTimeFromMs(double aValue, uint16_t* aHours,
uint16_t* aMinutes, uint16_t* aSeconds,
uint16_t* aMilliseconds) const {
MOZ_ASSERT(aValue >= 0 && aValue < kMsPerDay,
"aValue must be milliseconds within a day!");
uint32_t value = floor(aValue);
*aMilliseconds = value % 1000;
value /= 1000;
*aSeconds = value % 60;
value /= 60;
*aMinutes = value % 60;
value /= 60;
*aHours = value;
return true;
}
bool
HTMLInputElement::IsValidWeek(const nsAString& aValue) const
{
@@ -7771,8 +7584,8 @@ HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
if (maximum.isNaN() || valueHigh <= maximum) {
nsAutoString valueLowStr, valueHighStr;
ConvertNumberToString(valueLow, valueLowStr);
ConvertNumberToString(valueHigh, valueHighStr);
mInputType->ConvertNumberToString(valueLow, valueLowStr);
mInputType->ConvertNumberToString(valueHigh, valueHighStr);
if (valueLowStr.Equals(valueHighStr)) {
const char16_t* params[] = { valueLowStr.get() };
@@ -7787,7 +7600,7 @@ HTMLInputElement::GetValidationMessage(nsAString& aValidationMessage,
}
} else {
nsAutoString valueLowStr;
ConvertNumberToString(valueLow, valueLowStr);
mInputType->ConvertNumberToString(valueLow, valueLowStr);
const char16_t* params[] = { valueLowStr.get() };
rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,