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