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 #ifndef mozilla_dom_InputType_h__
8 #define mozilla_dom_InputType_h__
9 
10 #include <stdint.h>
11 #include "mozilla/Decimal.h"
12 #include "mozilla/Maybe.h"
13 #include "mozilla/TextControlState.h"
14 #include "mozilla/UniquePtr.h"
15 #include "nsIConstraintValidation.h"
16 #include "nsString.h"
17 #include "nsError.h"
18 
19 // This must come outside of any namespace, or else it won't overload with the
20 // double based version in nsMathUtils.h
NS_floorModulo(mozilla::Decimal x,mozilla::Decimal y)21 inline mozilla::Decimal NS_floorModulo(mozilla::Decimal x, mozilla::Decimal y) {
22   return (x - y * (x / y).floor());
23 }
24 
25 class nsIFrame;
26 
27 namespace mozilla {
28 namespace dom {
29 class HTMLInputElement;
30 
31 /**
32  * A common superclass for different types of a HTMLInputElement.
33  */
34 class InputType {
35  public:
36   using ValueSetterOption = TextControlState::ValueSetterOption;
37   using ValueSetterOptions = TextControlState::ValueSetterOptions;
38 
39   // Custom deleter for UniquePtr<InputType> to avoid freeing memory
40   // pre-allocated for InputType, but we still need to call the destructor
41   // explictly.
42   struct DoNotDelete {
operatorDoNotDelete43     void operator()(InputType* p) { p->~InputType(); }
44   };
45 
46   static UniquePtr<InputType, DoNotDelete> Create(
47       HTMLInputElement* aInputElement, FormControlType, void* aMemory);
48 
49   virtual ~InputType() = default;
50 
51   // Float value returned by GetStep() when the step attribute is set to 'any'.
52   static const Decimal kStepAny;
53 
54   /**
55    * Drop the reference to the input element.
56    */
57   void DropReference();
58 
MinAndMaxLengthApply()59   virtual bool MinAndMaxLengthApply() const { return false; }
60   virtual bool IsTooLong() const;
61   virtual bool IsTooShort() const;
62   virtual bool IsValueMissing() const;
63   virtual bool HasTypeMismatch() const;
64   // May return Nothing() if the JS engine failed to evaluate the regex.
65   virtual Maybe<bool> HasPatternMismatch() const;
66   virtual bool IsRangeOverflow() const;
67   virtual bool IsRangeUnderflow() const;
68   virtual bool HasStepMismatch(bool aUseZeroIfValueNaN) const;
69   virtual bool HasBadInput() const;
70 
71   nsresult GetValidationMessage(
72       nsAString& aValidationMessage,
73       nsIConstraintValidation::ValidityStateType aType);
74   virtual nsresult GetValueMissingMessage(nsAString& aMessage);
75   virtual nsresult GetTypeMismatchMessage(nsAString& aMessage);
76   virtual nsresult GetRangeOverflowMessage(nsAString& aMessage);
77   virtual nsresult GetRangeUnderflowMessage(nsAString& aMessage);
78   virtual nsresult GetBadInputMessage(nsAString& aMessage);
79 
80   MOZ_CAN_RUN_SCRIPT virtual nsresult MinMaxStepAttrChanged();
81 
82   /**
83    * Convert a string to a Decimal number in a type specific way,
84    * http://www.whatwg.org/specs/web-apps/current-work/multipage/the-input-element.html#concept-input-value-string-number
85    * ie parse a date string to a timestamp if type=date,
86    * or parse a number string to its value if type=number.
87    * @param aValue the string to be parsed.
88    * @param aResultValue the number as a Decimal.
89    * @result whether the parsing was successful.
90    */
91   virtual bool ConvertStringToNumber(nsAString& aValue,
92                                      Decimal& aResultValue) const;
93 
94   /**
95    * Convert a Decimal to a string in a type specific way, ie convert a
96    * timestamp to a date string if type=date or append the number string
97    * representing the value if type=number.
98    *
99    * @param aValue the Decimal to be converted
100    * @param aResultString [out] the string representing the Decimal
101    * @return whether the function succeeded, it will fail if the current input's
102    *         type is not supported or the number can't be converted to a string
103    *         as expected by the type.
104    */
105   virtual bool ConvertNumberToString(Decimal aValue,
106                                      nsAString& aResultString) const;
107 
108  protected:
InputType(HTMLInputElement * aInputElement)109   explicit InputType(HTMLInputElement* aInputElement)
110       : mInputElement(aInputElement) {}
111 
112   /**
113    * Get the mutable state of the element.
114    * When the element isn't mutable (immutable), the value or checkedness
115    * should not be changed by the user.
116    *
117    * See:
118    * https://html.spec.whatwg.org/multipage/forms.html#the-input-element:concept-fe-mutable
119    */
120   virtual bool IsMutable() const;
121 
122   /**
123    * Returns whether the input element's current value is the empty string.
124    * This only makes sense for some input types; does NOT make sense for file
125    * inputs.
126    *
127    * @return whether the input element's current value is the empty string.
128    */
129   bool IsValueEmpty() const;
130 
131   // A getter for callers that know we're not dealing with a file input, so they
132   // don't have to think about the caller type.
133   void GetNonFileValueInternal(nsAString& aValue) const;
134 
135   /**
136    * Setting the input element's value.
137    *
138    * @param aValue      String to set.
139    * @param aOptions    See TextControlState::ValueSetterOption.
140    */
141   MOZ_CAN_RUN_SCRIPT nsresult
142   SetValueInternal(const nsAString& aValue, const ValueSetterOptions& aOptions);
143 
144   /**
145    * Return the base used to compute if a value matches step.
146    * Basically, it's the min attribute if present and a default value otherwise.
147    *
148    * @return The step base.
149    */
150   Decimal GetStepBase() const;
151 
152   /**
153    * Get the primary frame for the input element.
154    */
155   nsIFrame* GetPrimaryFrame() const;
156 
157   /**
158    * Parse a date string of the form yyyy-mm-dd
159    *
160    * @param aValue the string to be parsed.
161    * @return the date in aYear, aMonth, aDay.
162    * @return whether the parsing was successful.
163    */
164   bool ParseDate(const nsAString& aValue, uint32_t* aYear, uint32_t* aMonth,
165                  uint32_t* aDay) const;
166 
167   /**
168    * Returns the time expressed in milliseconds of |aValue| being parsed as a
169    * time following the HTML specifications:
170    * https://html.spec.whatwg.org/multipage/infrastructure.html#parse-a-time-string
171    *
172    * Note: |aResult| can be null.
173    *
174    * @param aValue the string to be parsed.
175    * @param aResult the time expressed in milliseconds representing the time
176    * [out]
177    * @return whether the parsing was successful.
178    */
179   bool ParseTime(const nsAString& aValue, uint32_t* aResult) const;
180 
181   /**
182    * Parse a month string of the form yyyy-mm
183    *
184    * @param the string to be parsed.
185    * @return the year and month in aYear and aMonth.
186    * @return whether the parsing was successful.
187    */
188   bool ParseMonth(const nsAString& aValue, uint32_t* aYear,
189                   uint32_t* aMonth) const;
190 
191   /**
192    * Parse a week string of the form yyyy-Www
193    *
194    * @param the string to be parsed.
195    * @return the year and week in aYear and aWeek.
196    * @return whether the parsing was successful.
197    */
198   bool ParseWeek(const nsAString& aValue, uint32_t* aYear,
199                  uint32_t* aWeek) const;
200 
201   /**
202    * Parse a datetime-local string of the form yyyy-mm-ddThh:mm[:ss.s] or
203    * yyyy-mm-dd hh:mm[:ss.s], where fractions of seconds can be 1 to 3 digits.
204    *
205    * @param the string to be parsed.
206    * @return the date in aYear, aMonth, aDay and time expressed in milliseconds
207    *         in aTime.
208    * @return whether the parsing was successful.
209    */
210   bool ParseDateTimeLocal(const nsAString& aValue, uint32_t* aYear,
211                           uint32_t* aMonth, uint32_t* aDay,
212                           uint32_t* aTime) const;
213 
214   /**
215    * This methods returns the number of months between January 1970 and the
216    * given year and month.
217    */
218   int32_t MonthsSinceJan1970(uint32_t aYear, uint32_t aMonth) const;
219 
220   /**
221    * This methods returns the number of days since epoch for a given year and
222    * week.
223    */
224   double DaysSinceEpochFromWeek(uint32_t aYear, uint32_t aWeek) const;
225 
226   /**
227    * This methods returns the day of the week given a date. If @isoWeek is true,
228    * 7=Sunday, otherwise, 0=Sunday.
229    */
230   uint32_t DayOfWeek(uint32_t aYear, uint32_t aMonth, uint32_t aDay,
231                      bool isoWeek) const;
232 
233   /**
234    * This methods returns the maximum number of week in a given year, the
235    * result is either 52 or 53.
236    */
237   uint32_t MaximumWeekInYear(uint32_t aYear) const;
238 
239   HTMLInputElement* mInputElement;
240 };
241 
242 }  // namespace dom
243 }  // namespace mozilla
244 
245 #endif /* mozilla_dom_InputType_h__ */
246