ebfee334949f130f0bfd1ecb172cda3e01a13b2b
[WebKit-https.git] / Source / WebCore / html / shadow / DateTimeFieldElements.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
28 #include "DateTimeFieldElements.h"
29
30 #include "DateComponents.h"
31 #include "DateTimeFieldsState.h"
32 #include "LocalizedStrings.h"
33 #include <wtf/CurrentTime.h>
34 #include <wtf/DateMath.h>
35
36 namespace WebCore {
37
38 DateTimeAMPMFieldElement::DateTimeAMPMFieldElement(Document* document, FieldOwner& fieldOwner, const Vector<String>& ampmLabels)
39     : DateTimeSymbolicFieldElement(document, fieldOwner, ampmLabels, 0, 1)
40 {
41 }
42
43 PassRefPtr<DateTimeAMPMFieldElement> DateTimeAMPMFieldElement::create(Document* document, FieldOwner& fieldOwner, const Vector<String>& ampmLabels)
44 {
45     DEFINE_STATIC_LOCAL(AtomicString, ampmPsuedoId, ("-webkit-datetime-edit-ampm-field", AtomicString::ConstructFromLiteral));
46     RefPtr<DateTimeAMPMFieldElement> field = adoptRef(new DateTimeAMPMFieldElement(document, fieldOwner, ampmLabels));
47     field->initialize(ampmPsuedoId, AXAMPMFieldText());
48     return field.release();
49 }
50
51 void DateTimeAMPMFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
52 {
53     if (hasValue())
54         dateTimeFieldsState.setAMPM(valueAsInteger() ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
55     else
56         dateTimeFieldsState.setAMPM(DateTimeFieldsState::AMPMValueEmpty);
57 }
58
59 void DateTimeAMPMFieldElement::setValueAsDate(const DateComponents& date)
60 {
61     setValueAsInteger(date.hour() >= 12 ? 1 : 0);
62 }
63
64 void DateTimeAMPMFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
65 {
66     if (dateTimeFieldsState.hasAMPM())
67         setValueAsInteger(dateTimeFieldsState.ampm());
68     else
69         setEmptyValue();
70 }
71
72 // ----------------------------
73
74 DateTimeDayFieldElement::DateTimeDayFieldElement(Document* document, FieldOwner& fieldOwner, const String& placeholder, int minimum, int maximum)
75     : DateTimeNumericFieldElement(document, fieldOwner, minimum, maximum, placeholder)
76 {
77 }
78
79 PassRefPtr<DateTimeDayFieldElement> DateTimeDayFieldElement::create(Document* document, FieldOwner& fieldOwner, const String& placeholder, int minimum, int maximum)
80 {
81     DEFINE_STATIC_LOCAL(AtomicString, dayPsuedoId, ("-webkit-datetime-edit-day-field", AtomicString::ConstructFromLiteral));
82     RefPtr<DateTimeDayFieldElement> field = adoptRef(new DateTimeDayFieldElement(document, fieldOwner, placeholder.isEmpty() ? ASCIILiteral("--") : placeholder, minimum, maximum));
83     field->initialize(dayPsuedoId, AXDayOfMonthFieldText());
84     return field.release();
85 }
86
87 void DateTimeDayFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
88 {
89     dateTimeFieldsState.setDayOfMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
90 }
91
92 void DateTimeDayFieldElement::setValueAsDate(const DateComponents& date)
93 {
94     setValueAsInteger(date.monthDay());
95 }
96
97 void DateTimeDayFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
98 {
99     if (!dateTimeFieldsState.hasDayOfMonth()) {
100         setEmptyValue();
101         return;
102     }
103
104     const unsigned value = dateTimeFieldsState.dayOfMonth();
105     if (range().isInRange(static_cast<int>(value))) {
106         setValueAsInteger(value);
107         return;
108     }
109
110     setEmptyValue();
111 }
112
113 int DateTimeDayFieldElement::clampValueForHardLimits(int value) const
114 {
115     return Range(1, 31).clampValue(value);
116 }
117
118 // ----------------------------
119
120 DateTimeHourFieldElement::DateTimeHourFieldElement(Document* document, FieldOwner& fieldOwner, int minimum, int maximum, const DateTimeNumericFieldElement::Parameters& parameters)
121     : DateTimeNumericFieldElement(document, fieldOwner, minimum, maximum, "--", parameters)
122     , m_alignment(maximum + maximum % 2)
123 {
124     ASSERT((!minimum && (maximum == 11 || maximum == 23)) || (minimum == 1 && (maximum == 12 || maximum == 24)));
125 }
126
127 PassRefPtr<DateTimeHourFieldElement> DateTimeHourFieldElement::create(Document* document, FieldOwner& fieldOwner, int minimum, int maximum, const DateTimeNumericFieldElement::Parameters& parameters)
128 {
129     DEFINE_STATIC_LOCAL(AtomicString, hourPsuedoId, ("-webkit-datetime-edit-hour-field", AtomicString::ConstructFromLiteral));
130     RefPtr<DateTimeHourFieldElement> field = adoptRef(new DateTimeHourFieldElement(document, fieldOwner, minimum, maximum, parameters));
131     field->initialize(hourPsuedoId, AXHourFieldText());
132     return field.release();
133 }
134
135 void DateTimeHourFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
136 {
137     if (!hasValue()) {
138         dateTimeFieldsState.setHour(DateTimeFieldsState::emptyValue);
139         return;
140     }
141
142     const int value = valueAsInteger();
143
144     switch (maximum()) {
145     case 11:
146         dateTimeFieldsState.setHour(value ? value : 12);
147         return;
148     case 12:
149         dateTimeFieldsState.setHour(value);
150         return;
151     case 23:
152         dateTimeFieldsState.setHour(value ? value % 12 : 12);
153         dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
154         return;
155     case 24:
156         if (value == 24) {
157             dateTimeFieldsState.setHour(12);
158             dateTimeFieldsState.setAMPM(DateTimeFieldsState::AMPMValueAM);
159             return;
160         }
161         dateTimeFieldsState.setHour(value == 12 ? 12 : value % 12);
162         dateTimeFieldsState.setAMPM(value >= 12 ? DateTimeFieldsState::AMPMValuePM : DateTimeFieldsState::AMPMValueAM);
163         return;
164     default:
165         ASSERT_NOT_REACHED();
166     }
167 }
168
169 void DateTimeHourFieldElement::setValueAsDate(const DateComponents& date)
170 {
171     setValueAsInteger(date.hour());
172 }
173
174 void DateTimeHourFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
175 {
176     if (!dateTimeFieldsState.hasHour()) {
177         setEmptyValue();
178         return;
179     }
180
181     const int hour12 = dateTimeFieldsState.hour();
182
183     if (hour12 < 1 || hour12 > 12) {
184         setEmptyValue();
185         return;
186     }
187
188     switch (maximum()) {
189     case 11:
190         DateTimeNumericFieldElement::setValueAsInteger(hour12 % 12);
191         return;
192     case 12:
193         DateTimeNumericFieldElement::setValueAsInteger(hour12);
194         return;
195     case 23:
196         if (dateTimeFieldsState.ampm() == DateTimeFieldsState::AMPMValuePM)
197             DateTimeNumericFieldElement::setValueAsInteger((hour12 + 12) % 24);
198         else
199             DateTimeNumericFieldElement::setValueAsInteger(hour12 % 12);
200         return;
201     case 24:
202         if (dateTimeFieldsState.ampm() == DateTimeFieldsState::AMPMValuePM)
203             DateTimeNumericFieldElement::setValueAsInteger(hour12 == 12 ? 12 : hour12 + 12);
204         else
205             DateTimeNumericFieldElement::setValueAsInteger(hour12);
206         return;
207     default:
208         ASSERT_NOT_REACHED();
209     }
210 }
211
212 void DateTimeHourFieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
213 {
214     value = Range(0, 24 - range().maximum % 2).clampValue(value) % m_alignment;
215     DateTimeNumericFieldElement::setValueAsInteger(range().minimum && !value ? m_alignment : value, eventBehavior);
216 }
217
218 // ----------------------------
219
220 DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement(Document* document, FieldOwner& fieldOwner, const DateTimeNumericFieldElement::Parameters& parameters)
221     : DateTimeNumericFieldElement(document, fieldOwner, 0, 999, "---", parameters)
222 {
223 }
224
225 PassRefPtr<DateTimeMillisecondFieldElement> DateTimeMillisecondFieldElement::create(Document* document, FieldOwner& fieldOwner, const DateTimeNumericFieldElement::Parameters& parameters)
226 {
227     DEFINE_STATIC_LOCAL(AtomicString, millisecondPsuedoId, ("-webkit-datetime-edit-millisecond-field", AtomicString::ConstructFromLiteral));
228     RefPtr<DateTimeMillisecondFieldElement> field = adoptRef(new DateTimeMillisecondFieldElement(document, fieldOwner, parameters));
229     field->initialize(millisecondPsuedoId, AXMillisecondFieldText());
230     return field.release();
231 }
232
233 void DateTimeMillisecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
234 {
235     dateTimeFieldsState.setMillisecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
236 }
237
238 void DateTimeMillisecondFieldElement::setValueAsDate(const DateComponents& date)
239 {
240     setValueAsInteger(date.millisecond());
241 }
242
243 void DateTimeMillisecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
244 {
245     if (!dateTimeFieldsState.hasMillisecond()) {
246         setEmptyValue();
247         return;
248     }
249
250     const unsigned value = dateTimeFieldsState.millisecond();
251     if (value > static_cast<unsigned>(maximum())) {
252         setEmptyValue();
253         return;
254     }
255
256     setValueAsInteger(value);
257 }
258
259 // ----------------------------
260
261 DateTimeMinuteFieldElement::DateTimeMinuteFieldElement(Document* document, FieldOwner& fieldOwner, const DateTimeNumericFieldElement::Parameters& parameters)
262     : DateTimeNumericFieldElement(document, fieldOwner, 0, 59, "--", parameters)
263 {
264 }
265
266 PassRefPtr<DateTimeMinuteFieldElement> DateTimeMinuteFieldElement::create(Document* document, FieldOwner& fieldOwner, const DateTimeNumericFieldElement::Parameters& parameters)
267 {
268     DEFINE_STATIC_LOCAL(AtomicString, minutePsuedoId, ("-webkit-datetime-edit-minute-field", AtomicString::ConstructFromLiteral));
269     RefPtr<DateTimeMinuteFieldElement> field = adoptRef(new DateTimeMinuteFieldElement(document, fieldOwner, parameters));
270     field->initialize(minutePsuedoId, AXMinuteFieldText());
271     return field.release();
272 }
273
274 void DateTimeMinuteFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
275 {
276     dateTimeFieldsState.setMinute(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
277 }
278
279 void DateTimeMinuteFieldElement::setValueAsDate(const DateComponents& date)
280 {
281     setValueAsInteger(date.minute());
282 }
283
284 void DateTimeMinuteFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
285 {
286     if (!dateTimeFieldsState.hasMinute()) {
287         setEmptyValue();
288         return;
289     }
290
291     const unsigned value = dateTimeFieldsState.minute();
292     if (value > static_cast<unsigned>(maximum())) {
293         setEmptyValue();
294         return;
295     }
296
297     setValueAsInteger(value);
298 }
299
300 // ----------------------------
301
302 DateTimeMonthFieldElement::DateTimeMonthFieldElement(Document* document, FieldOwner& fieldOwner, const String& placeholder, int minimum, int maximum)
303     : DateTimeNumericFieldElement(document, fieldOwner, minimum, maximum, placeholder)
304 {
305 }
306
307 PassRefPtr<DateTimeMonthFieldElement> DateTimeMonthFieldElement::create(Document* document, FieldOwner& fieldOwner, const String& placeholder, int minimum, int maximum)
308 {
309     DEFINE_STATIC_LOCAL(AtomicString, monthPsuedoId, ("-webkit-datetime-edit-month-field", AtomicString::ConstructFromLiteral));
310     RefPtr<DateTimeMonthFieldElement> field = adoptRef(new DateTimeMonthFieldElement(document, fieldOwner, placeholder.isEmpty() ? ASCIILiteral("--") : placeholder, minimum, maximum));
311     field->initialize(monthPsuedoId, AXMonthFieldText());
312     return field.release();
313 }
314
315 void DateTimeMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
316 {
317     dateTimeFieldsState.setMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
318 }
319
320 void DateTimeMonthFieldElement::setValueAsDate(const DateComponents& date)
321 {
322     setValueAsInteger(date.month() + 1);
323 }
324
325 void DateTimeMonthFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
326 {
327     if (!dateTimeFieldsState.hasMonth()) {
328         setEmptyValue();
329         return;
330     }
331
332     const unsigned value = dateTimeFieldsState.month();
333     if (range().isInRange(static_cast<int>(value))) {
334         setValueAsInteger(value);
335         return;
336     }
337
338     setEmptyValue();
339 }
340
341 int DateTimeMonthFieldElement::clampValueForHardLimits(int value) const
342 {
343     return Range(1, 12).clampValue(value);
344 }
345
346 // ----------------------------
347
348 DateTimeSecondFieldElement::DateTimeSecondFieldElement(Document* document, FieldOwner& fieldOwner, const DateTimeNumericFieldElement::Parameters& parameters)
349     : DateTimeNumericFieldElement(document, fieldOwner, 0, 59, "--", parameters)
350 {
351 }
352
353 PassRefPtr<DateTimeSecondFieldElement> DateTimeSecondFieldElement::create(Document* document, FieldOwner& fieldOwner, const DateTimeNumericFieldElement::Parameters& parameters)
354 {
355     DEFINE_STATIC_LOCAL(AtomicString, secondPsuedoId, ("-webkit-datetime-edit-second-field", AtomicString::ConstructFromLiteral));
356     RefPtr<DateTimeSecondFieldElement> field = adoptRef(new DateTimeSecondFieldElement(document, fieldOwner, parameters));
357     field->initialize(secondPsuedoId, AXSecondFieldText());
358     return field.release();
359 }
360
361 void DateTimeSecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
362 {
363     dateTimeFieldsState.setSecond(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
364 }
365
366 void DateTimeSecondFieldElement::setValueAsDate(const DateComponents& date)
367 {
368     setValueAsInteger(date.second());
369 }
370
371 void DateTimeSecondFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
372 {
373     if (!dateTimeFieldsState.hasSecond()) {
374         setEmptyValue();
375         return;
376     }
377
378     const unsigned value = dateTimeFieldsState.second();
379     if (value > static_cast<unsigned>(maximum())) {
380         setEmptyValue();
381         return;
382     }
383
384     setValueAsInteger(value);
385 }
386
387 // ----------------------------
388
389 DateTimeSymbolicMonthFieldElement::DateTimeSymbolicMonthFieldElement(Document* document, FieldOwner& fieldOwner, const Vector<String>& labels, int minimum, int maximum)
390     : DateTimeSymbolicFieldElement(document, fieldOwner, labels, minimum, maximum)
391 {
392 }
393
394 PassRefPtr<DateTimeSymbolicMonthFieldElement> DateTimeSymbolicMonthFieldElement::create(Document* document, FieldOwner& fieldOwner, const Vector<String>& labels, int minimum, int maximum)
395 {
396     DEFINE_STATIC_LOCAL(AtomicString, monthPsuedoId, ("-webkit-datetime-edit-month-field", AtomicString::ConstructFromLiteral));
397     RefPtr<DateTimeSymbolicMonthFieldElement> field = adoptRef(new DateTimeSymbolicMonthFieldElement(document, fieldOwner, labels, minimum, maximum));
398     field->initialize(monthPsuedoId, AXMonthFieldText());
399     return field.release();
400 }
401
402 void DateTimeSymbolicMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
403 {
404     if (!hasValue())
405         dateTimeFieldsState.setMonth(DateTimeFieldsState::emptyValue);
406     ASSERT(valueAsInteger() < static_cast<int>(symbolsSize()));
407     dateTimeFieldsState.setMonth(valueAsInteger() + 1);
408 }
409
410 void DateTimeSymbolicMonthFieldElement::setValueAsDate(const DateComponents& date)
411 {
412     setValueAsInteger(date.month());
413 }
414
415 void DateTimeSymbolicMonthFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
416 {
417     if (!dateTimeFieldsState.hasMonth()) {
418         setEmptyValue();
419         return;
420     }
421
422     const unsigned value = dateTimeFieldsState.month() - 1;
423     if (value >= symbolsSize()) {
424         setEmptyValue();
425         return;
426     }
427
428     setValueAsInteger(value);
429 }
430
431 // ----------------------------
432
433 DateTimeWeekFieldElement::DateTimeWeekFieldElement(Document* document, FieldOwner& fieldOwner, int minimum, int maximum)
434     : DateTimeNumericFieldElement(document, fieldOwner, minimum, maximum, "--")
435 {
436 }
437
438 PassRefPtr<DateTimeWeekFieldElement> DateTimeWeekFieldElement::create(Document* document, FieldOwner& fieldOwner, int minimum, int maximum)
439 {
440     DEFINE_STATIC_LOCAL(AtomicString, weekPsuedoId, ("-webkit-datetime-edit-week-field", AtomicString::ConstructFromLiteral));
441     RefPtr<DateTimeWeekFieldElement> field = adoptRef(new DateTimeWeekFieldElement(document, fieldOwner, minimum, maximum));
442     field->initialize(weekPsuedoId, AXWeekOfYearFieldText());
443     return field.release();
444 }
445
446 void DateTimeWeekFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
447 {
448     dateTimeFieldsState.setWeekOfYear(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
449 }
450
451 void DateTimeWeekFieldElement::setValueAsDate(const DateComponents& date)
452 {
453     setValueAsInteger(date.week());
454 }
455
456 void DateTimeWeekFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
457 {
458     if (!dateTimeFieldsState.hasWeekOfYear()) {
459         setEmptyValue();
460         return;
461     }
462
463     const unsigned value = dateTimeFieldsState.weekOfYear();
464     if (range().isInRange(static_cast<int>(value))) {
465         setValueAsInteger(value);
466         return;
467     }
468
469     setEmptyValue();
470 }
471
472 int DateTimeWeekFieldElement::clampValueForHardLimits(int value) const
473 {
474     return Range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber).clampValue(value);
475 }
476
477 // ----------------------------
478
479 DateTimeYearFieldElement::DateTimeYearFieldElement(Document* document, FieldOwner& fieldOwner, const DateTimeYearFieldElement::Parameters& parameters)
480     : DateTimeNumericFieldElement(document, fieldOwner, parameters.minimumYear, parameters.maximumYear, parameters.placeholder.isEmpty() ? ASCIILiteral("----") : parameters.placeholder)
481     , m_minIsSpecified(parameters.minIsSpecified)
482     , m_maxIsSpecified(parameters.maxIsSpecified)
483 {
484     ASSERT(parameters.minimumYear >= DateComponents::minimumYear());
485     ASSERT(parameters.maximumYear <= DateComponents::maximumYear());
486 }
487
488 PassRefPtr<DateTimeYearFieldElement> DateTimeYearFieldElement::create(Document* document, FieldOwner& fieldOwner, const DateTimeYearFieldElement::Parameters& parameters)
489 {
490     DEFINE_STATIC_LOCAL(AtomicString, yearPsuedoId, ("-webkit-datetime-edit-year-field", AtomicString::ConstructFromLiteral));
491     RefPtr<DateTimeYearFieldElement> field = adoptRef(new DateTimeYearFieldElement(document, fieldOwner, parameters));
492     field->initialize(yearPsuedoId, AXYearFieldText());
493     return field.release();
494 }
495
496 int DateTimeYearFieldElement::clampValueForHardLimits(int value) const
497 {
498     return Range(DateComponents::minimumYear(), DateComponents::maximumYear()).clampValue(value);
499 }
500
501 static int currentFullYear()
502 {
503     double current = currentTimeMS();
504     double utcOffset = calculateUTCOffset();
505     double dstOffset = calculateDSTOffset(current, utcOffset);
506     int offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute);
507     current += offset * msPerMinute;
508
509     DateComponents date;
510     date.setMillisecondsSinceEpochForMonth(current);
511     return date.fullYear();
512 }
513
514 int DateTimeYearFieldElement::defaultValueForStepDown() const
515 {
516     return m_maxIsSpecified ? DateTimeNumericFieldElement::defaultValueForStepDown() : currentFullYear();
517 }
518
519 int DateTimeYearFieldElement::defaultValueForStepUp() const
520 {
521     return m_minIsSpecified ? DateTimeNumericFieldElement::defaultValueForStepUp() : currentFullYear();
522 }
523
524 void DateTimeYearFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& dateTimeFieldsState)
525 {
526     dateTimeFieldsState.setYear(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
527 }
528
529 void DateTimeYearFieldElement::setValueAsDate(const DateComponents& date)
530 {
531     setValueAsInteger(date.fullYear());
532 }
533
534 void DateTimeYearFieldElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
535 {
536     if (!dateTimeFieldsState.hasYear()) {
537         setEmptyValue();
538         return;
539     }
540
541     const unsigned value = dateTimeFieldsState.year();
542     if (range().isInRange(static_cast<int>(value))) {
543         setValueAsInteger(value);
544         return;
545     }
546
547     setEmptyValue();
548 }
549
550 } // namespace WebCore
551
552 #endif