LCOV - code coverage report
Current view: top level - dom/html/input - DateTimeInputTypes.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 199 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "DateTimeInputTypes.h"
       8             : 
       9             : #include "js/Date.h"
      10             : #include "mozilla/dom/HTMLInputElement.h"
      11             : #include "nsDateTimeControlFrame.h"
      12             : 
      13             : const double DateTimeInputTypeBase::kMinimumYear = 1;
      14             : const double DateTimeInputTypeBase::kMaximumYear = 275760;
      15             : const double DateTimeInputTypeBase::kMaximumMonthInMaximumYear = 9;
      16             : const double DateTimeInputTypeBase::kMaximumWeekInMaximumYear = 37;
      17             : const double DateTimeInputTypeBase::kMsPerDay = 24 * 60 * 60 * 1000;
      18             : 
      19             : /* static */ bool
      20           0 : DateTimeInputTypeBase::IsInputDateTimeEnabled()
      21             : {
      22             :   static bool sDateTimeEnabled = false;
      23             :   static bool sDateTimePrefCached = false;
      24           0 :   if (!sDateTimePrefCached) {
      25           0 :     sDateTimePrefCached = true;
      26             :     mozilla::Preferences::AddBoolVarCache(&sDateTimeEnabled,
      27             :                                           "dom.forms.datetime",
      28           0 :                                           false);
      29             :   }
      30             : 
      31           0 :   return sDateTimeEnabled;
      32             : }
      33             : 
      34             : bool
      35           0 : DateTimeInputTypeBase::IsMutable() const
      36             : {
      37           0 :   return !mInputElement->IsDisabled() &&
      38           0 :          !mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::readonly);
      39             : }
      40             : 
      41             : bool
      42           0 : DateTimeInputTypeBase::IsValueMissing() const
      43             : {
      44           0 :   if (!mInputElement->HasAttr(kNameSpaceID_None, nsGkAtoms::required)) {
      45           0 :     return false;
      46             :   }
      47             : 
      48           0 :   if (!IsMutable()) {
      49           0 :     return false;
      50             :   }
      51             : 
      52           0 :   return IsValueEmpty();
      53             : }
      54             : 
      55             : bool
      56           0 : DateTimeInputTypeBase::IsRangeOverflow() const
      57             : {
      58           0 :   mozilla::Decimal maximum = mInputElement->GetMaximum();
      59           0 :   if (maximum.isNaN()) {
      60           0 :     return false;
      61             :   }
      62             : 
      63           0 :   mozilla::Decimal value = mInputElement->GetValueAsDecimal();
      64           0 :   if (value.isNaN()) {
      65           0 :     return false;
      66             :   }
      67             : 
      68           0 :   return value > maximum;
      69             : }
      70             : 
      71             : bool
      72           0 : DateTimeInputTypeBase::IsRangeUnderflow() const
      73             : {
      74           0 :   mozilla::Decimal minimum = mInputElement->GetMinimum();
      75           0 :   if (minimum.isNaN()) {
      76           0 :     return false;
      77             :   }
      78             : 
      79           0 :   mozilla::Decimal value = mInputElement->GetValueAsDecimal();
      80           0 :   if (value.isNaN()) {
      81           0 :     return false;
      82             :   }
      83             : 
      84           0 :   return value < minimum;
      85             : }
      86             : 
      87             : bool
      88           0 : DateTimeInputTypeBase::HasStepMismatch(bool aUseZeroIfValueNaN) const
      89             : {
      90           0 :   mozilla::Decimal value = mInputElement->GetValueAsDecimal();
      91           0 :   if (value.isNaN()) {
      92           0 :     if (aUseZeroIfValueNaN) {
      93           0 :       value = mozilla::Decimal(0);
      94             :     } else {
      95             :       // The element can't suffer from step mismatch if it's value isn't a number.
      96           0 :       return false;
      97             :     }
      98             :   }
      99             : 
     100           0 :   mozilla::Decimal step = mInputElement->GetStep();
     101           0 :   if (step == kStepAny) {
     102           0 :     return false;
     103             :   }
     104             : 
     105             :   // Value has to be an integral multiple of step.
     106           0 :   return NS_floorModulo(value - GetStepBase(), step) != mozilla::Decimal(0);
     107             : }
     108             : 
     109             : bool
     110           0 : DateTimeInputTypeBase::HasBadInput() const
     111             : {
     112           0 :   nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
     113           0 :   if (!frame) {
     114           0 :     return false;
     115             :   }
     116             : 
     117           0 :   return frame->HasBadInput();;
     118             : }
     119             : 
     120             : nsresult
     121           0 : DateTimeInputTypeBase::GetRangeOverflowMessage(nsXPIDLString& aMessage)
     122             : {
     123           0 :   nsAutoString maxStr;
     124           0 :   mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::max, maxStr);
     125             : 
     126           0 :   const char16_t* params[] = { maxStr.get() };
     127             :   return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     128           0 :     "FormValidationDateTimeRangeOverflow", params, aMessage);
     129             : }
     130             : 
     131             : nsresult
     132           0 : DateTimeInputTypeBase::GetRangeUnderflowMessage(nsXPIDLString& aMessage)
     133             : {
     134           0 :   nsAutoString minStr;
     135           0 :   mInputElement->GetAttr(kNameSpaceID_None, nsGkAtoms::min, minStr);
     136             : 
     137           0 :   const char16_t* params[] = { minStr.get() };
     138             :   return nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     139           0 :     "FormValidationDateTimeRangeUnderflow", params, aMessage);
     140             : }
     141             : 
     142             : nsresult
     143           0 : DateTimeInputTypeBase::MinMaxStepAttrChanged()
     144             : {
     145           0 :   nsDateTimeControlFrame* frame = do_QueryFrame(GetPrimaryFrame());
     146           0 :   if (frame) {
     147           0 :     frame->OnMinMaxStepAttrChanged();
     148             :   }
     149             : 
     150           0 :   return NS_OK;
     151             : }
     152             : 
     153             : bool
     154           0 : DateTimeInputTypeBase::GetTimeFromMs(double aValue, uint16_t* aHours,
     155             :                                      uint16_t* aMinutes, uint16_t* aSeconds,
     156             :                                      uint16_t* aMilliseconds) const {
     157           0 :   MOZ_ASSERT(aValue >= 0 && aValue < kMsPerDay,
     158             :              "aValue must be milliseconds within a day!");
     159             : 
     160           0 :   uint32_t value = floor(aValue);
     161             : 
     162           0 :   *aMilliseconds = value % 1000;
     163           0 :   value /= 1000;
     164             : 
     165           0 :   *aSeconds = value % 60;
     166           0 :   value /= 60;
     167             : 
     168           0 :   *aMinutes = value % 60;
     169           0 :   value /= 60;
     170             : 
     171           0 :   *aHours = value;
     172             : 
     173           0 :   return true;
     174             : }
     175             : 
     176             : // input type=date
     177             : 
     178             : nsresult
     179           0 : DateInputType::GetBadInputMessage(nsXPIDLString& aMessage)
     180             : {
     181           0 :   if (!IsInputDateTimeEnabled()) {
     182           0 :     return NS_ERROR_UNEXPECTED;
     183             :   }
     184             : 
     185             :   return nsContentUtils::GetLocalizedString(nsContentUtils::eDOM_PROPERTIES,
     186           0 :     "FormValidationInvalidDate", aMessage);
     187             : }
     188             : 
     189             : bool
     190           0 : DateInputType::ConvertStringToNumber(nsAString& aValue,
     191             :                                      mozilla::Decimal& aResultValue) const
     192             : {
     193             :   uint32_t year, month, day;
     194           0 :   if (!ParseDate(aValue, &year, &month, &day)) {
     195           0 :     return false;
     196             :   }
     197             : 
     198           0 :   JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, day));
     199           0 :   if (!time.isValid()) {
     200           0 :     return false;
     201             :   }
     202             : 
     203           0 :   aResultValue = mozilla::Decimal::fromDouble(time.toDouble());
     204           0 :   return true;
     205             : }
     206             : 
     207             : bool
     208           0 : DateInputType::ConvertNumberToString(mozilla::Decimal aValue,
     209             :                                      nsAString& aResultString) const
     210             : {
     211           0 :   MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
     212             : 
     213           0 :   aResultString.Truncate();
     214             : 
     215             :   // The specs (and our JS APIs) require |aValue| to be truncated.
     216           0 :   aValue = aValue.floor();
     217             : 
     218           0 :   double year = JS::YearFromTime(aValue.toDouble());
     219           0 :   double month = JS::MonthFromTime(aValue.toDouble());
     220           0 :   double day = JS::DayFromTime(aValue.toDouble());
     221             : 
     222           0 :   if (mozilla::IsNaN(year) || mozilla::IsNaN(month) || mozilla::IsNaN(day)) {
     223           0 :     return false;
     224             :   }
     225             : 
     226           0 :   aResultString.AppendPrintf("%04.0f-%02.0f-%02.0f", year, month + 1, day);
     227           0 :   return true;
     228             : }
     229             : 
     230             : // input type=time
     231             : 
     232             : bool
     233           0 : TimeInputType::ConvertStringToNumber(nsAString& aValue,
     234             :                                      mozilla::Decimal& aResultValue) const
     235             : {
     236             :   uint32_t milliseconds;
     237           0 :   if (!ParseTime(aValue, &milliseconds)) {
     238           0 :     return false;
     239             :   }
     240             : 
     241           0 :   aResultValue = mozilla::Decimal(int32_t(milliseconds));
     242           0 :   return true;
     243             : }
     244             : 
     245             : bool
     246           0 : TimeInputType::ConvertNumberToString(mozilla::Decimal aValue,
     247             :                                      nsAString& aResultString) const
     248             : {
     249           0 :   MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
     250             : 
     251           0 :   aResultString.Truncate();
     252             : 
     253           0 :   aValue = aValue.floor();
     254             :   // Per spec, we need to truncate |aValue| and we should only represent
     255             :   // times inside a day [00:00, 24:00[, which means that we should do a
     256             :   // modulo on |aValue| using the number of milliseconds in a day (86400000).
     257             :   uint32_t value =
     258           0 :     NS_floorModulo(aValue, mozilla::Decimal::fromDouble(kMsPerDay)).toDouble();
     259             : 
     260             :   uint16_t milliseconds, seconds, minutes, hours;
     261           0 :   if (!GetTimeFromMs(value, &hours, &minutes, &seconds, &milliseconds)) {
     262           0 :     return false;
     263             :   }
     264             : 
     265           0 :   if (milliseconds != 0) {
     266           0 :     aResultString.AppendPrintf("%02d:%02d:%02d.%03d",
     267           0 :                                hours, minutes, seconds, milliseconds);
     268           0 :   } else if (seconds != 0) {
     269           0 :     aResultString.AppendPrintf("%02d:%02d:%02d",
     270           0 :                                hours, minutes, seconds);
     271             :   } else {
     272           0 :     aResultString.AppendPrintf("%02d:%02d", hours, minutes);
     273             :   }
     274             : 
     275           0 :   return true;
     276             : }
     277             : 
     278             : // input type=week
     279             : 
     280             : bool
     281           0 : WeekInputType::ConvertStringToNumber(nsAString& aValue,
     282             :                                      mozilla::Decimal& aResultValue) const
     283             : {
     284             :   uint32_t year, week;
     285           0 :   if (!ParseWeek(aValue, &year, &week)) {
     286           0 :     return false;
     287             :   }
     288             : 
     289           0 :   if (year < kMinimumYear || year > kMaximumYear) {
     290           0 :     return false;
     291             :   }
     292             : 
     293             :   // Maximum week is 275760-W37, the week of 275760-09-13.
     294           0 :   if (year == kMaximumYear && week > kMaximumWeekInMaximumYear) {
     295           0 :     return false;
     296             :   }
     297             : 
     298           0 :   double days = DaysSinceEpochFromWeek(year, week);
     299           0 :   aResultValue = mozilla::Decimal::fromDouble(days * kMsPerDay);
     300           0 :   return true;
     301             : }
     302             : 
     303             : bool
     304           0 : WeekInputType::ConvertNumberToString(mozilla::Decimal aValue,
     305             :                                      nsAString& aResultString) const
     306             : {
     307           0 :   MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
     308             : 
     309           0 :   aResultString.Truncate();
     310             : 
     311           0 :   aValue = aValue.floor();
     312             : 
     313             :   // Based on ISO 8601 date.
     314           0 :   double year = JS::YearFromTime(aValue.toDouble());
     315           0 :   double month = JS::MonthFromTime(aValue.toDouble());
     316           0 :   double day = JS::DayFromTime(aValue.toDouble());
     317             :   // Adding 1 since day starts from 0.
     318           0 :   double dayInYear = JS::DayWithinYear(aValue.toDouble(), year) + 1;
     319             : 
     320             :   // Adding 1 since month starts from 0.
     321           0 :   uint32_t isoWeekday = DayOfWeek(year, month + 1, day, true);
     322             :   // Target on Wednesday since ISO 8601 states that week 1 is the week
     323             :   // with the first Thursday of that year.
     324           0 :   uint32_t week = (dayInYear - isoWeekday + 10) / 7;
     325             : 
     326           0 :   if (week < 1) {
     327           0 :     year--;
     328           0 :     if (year < 1) {
     329           0 :       return false;
     330             :     }
     331           0 :     week = MaximumWeekInYear(year);
     332           0 :   } else if (week > MaximumWeekInYear(year)) {
     333           0 :     year++;
     334           0 :     if (year > kMaximumYear ||
     335           0 :         (year == kMaximumYear && week > kMaximumWeekInMaximumYear)) {
     336           0 :       return false;
     337             :     }
     338           0 :     week = 1;
     339             :   }
     340             : 
     341           0 :   aResultString.AppendPrintf("%04.0f-W%02d", year, week);
     342           0 :   return true;
     343             : }
     344             : 
     345             : // input type=month
     346             : 
     347             : bool
     348           0 : MonthInputType::ConvertStringToNumber(nsAString& aValue,
     349             :                                       mozilla::Decimal& aResultValue) const
     350             : {
     351             :   uint32_t year, month;
     352           0 :   if (!ParseMonth(aValue, &year, &month)) {
     353           0 :     return false;
     354             :   }
     355             : 
     356           0 :   if (year < kMinimumYear || year > kMaximumYear) {
     357           0 :     return false;
     358             :   }
     359             : 
     360             :   // Maximum valid month is 275760-09.
     361           0 :   if (year == kMaximumYear && month > kMaximumMonthInMaximumYear) {
     362           0 :     return false;
     363             :   }
     364             : 
     365           0 :   int32_t months = MonthsSinceJan1970(year, month);
     366           0 :   aResultValue = mozilla::Decimal(int32_t(months));
     367           0 :   return true;
     368             : }
     369             : 
     370             : bool
     371           0 : MonthInputType::ConvertNumberToString(mozilla::Decimal aValue,
     372             :                                       nsAString& aResultString) const
     373             : {
     374           0 :   MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
     375             : 
     376           0 :   aResultString.Truncate();
     377             : 
     378           0 :   aValue = aValue.floor();
     379             : 
     380           0 :   double month = NS_floorModulo(aValue, mozilla::Decimal(12)).toDouble();
     381           0 :   month = (month < 0 ? month + 12 : month);
     382             : 
     383           0 :   double year = 1970 + (aValue.toDouble() - month) / 12;
     384             : 
     385             :   // Maximum valid month is 275760-09.
     386           0 :   if (year < kMinimumYear || year > kMaximumYear) {
     387           0 :     return false;
     388             :   }
     389             : 
     390           0 :   if (year == kMaximumYear && month > 8) {
     391           0 :     return false;
     392             :   }
     393             : 
     394           0 :   aResultString.AppendPrintf("%04.0f-%02.0f", year, month + 1);
     395           0 :   return true;
     396             : 
     397             : }
     398             : 
     399             : // input type=datetime-local
     400             : 
     401             : bool
     402           0 : DateTimeLocalInputType::ConvertStringToNumber(
     403             :   nsAString& aValue, mozilla::Decimal& aResultValue) const
     404             : {
     405             :   uint32_t year, month, day, timeInMs;
     406           0 :   if (!ParseDateTimeLocal(aValue, &year, &month, &day, &timeInMs)) {
     407           0 :     return false;
     408             :   }
     409             : 
     410             :   JS::ClippedTime time = JS::TimeClip(JS::MakeDate(year, month - 1, day,
     411           0 :                                                    timeInMs));
     412           0 :   if (!time.isValid()) {
     413           0 :     return false;
     414             :   }
     415             : 
     416           0 :   aResultValue = mozilla::Decimal::fromDouble(time.toDouble());
     417           0 :   return true;
     418             : }
     419             : 
     420             : bool
     421           0 : DateTimeLocalInputType::ConvertNumberToString(mozilla::Decimal aValue,
     422             :                                               nsAString& aResultString) const
     423             : {
     424           0 :   MOZ_ASSERT(aValue.isFinite(), "aValue must be a valid non-Infinite number.");
     425             : 
     426           0 :   aResultString.Truncate();
     427             : 
     428           0 :   aValue = aValue.floor();
     429             : 
     430             :   uint32_t timeValue =
     431           0 :     NS_floorModulo(aValue, mozilla::Decimal::fromDouble(kMsPerDay)).toDouble();
     432             : 
     433             :   uint16_t milliseconds, seconds, minutes, hours;
     434           0 :   if (!GetTimeFromMs(timeValue, &hours, &minutes, &seconds, &milliseconds)) {
     435           0 :     return false;
     436             :   }
     437             : 
     438           0 :   double year = JS::YearFromTime(aValue.toDouble());
     439           0 :   double month = JS::MonthFromTime(aValue.toDouble());
     440           0 :   double day = JS::DayFromTime(aValue.toDouble());
     441             : 
     442           0 :   if (mozilla::IsNaN(year) || mozilla::IsNaN(month) || mozilla::IsNaN(day)) {
     443           0 :     return false;
     444             :   }
     445             : 
     446           0 :   if (milliseconds != 0) {
     447           0 :     aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d.%03d",
     448             :                                year, month + 1, day, hours, minutes,
     449           0 :                                seconds, milliseconds);
     450           0 :   } else if (seconds != 0) {
     451           0 :     aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d:%02d",
     452             :                                year, month + 1, day, hours, minutes,
     453           0 :                                seconds);
     454             :   } else {
     455           0 :     aResultString.AppendPrintf("%04.0f-%02.0f-%02.0fT%02d:%02d",
     456           0 :                                year, month + 1, day, hours, minutes);
     457             :   }
     458             : 
     459           0 :   return true;
     460             : }

Generated by: LCOV version 1.13