3b337ddf0f11ea913b2a9ebea6ada93f401c8af4
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / shadow / DateTimeEditElement.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 "core/html/shadow/DateTimeEditElement.h"
29
30 #include "bindings/v8/ExceptionStatePlaceholder.h"
31 #include "core/HTMLNames.h"
32 #include "core/dom/Document.h"
33 #include "core/dom/Text.h"
34 #include "core/events/MouseEvent.h"
35 #include "core/html/forms/DateTimeFieldsState.h"
36 #include "core/html/shadow/DateTimeFieldElements.h"
37 #include "core/html/shadow/ShadowElementNames.h"
38 #include "core/rendering/style/RenderStyle.h"
39 #include "core/rendering/style/StyleInheritedData.h"
40 #include "platform/fonts/FontCache.h"
41 #include "platform/text/DateTimeFormat.h"
42 #include "platform/text/PlatformLocale.h"
43 #include "wtf/DateMath.h"
44
45 namespace WebCore {
46
47 using namespace HTMLNames;
48 using namespace WTF::Unicode;
49
50 class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
51     WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder);
52
53 public:
54     // The argument objects must be alive until this object dies.
55     DateTimeEditBuilder(DateTimeEditElement&, const DateTimeEditElement::LayoutParameters&, const DateComponents&);
56
57     bool build(const String&);
58
59 private:
60     bool needMillisecondField() const;
61     bool shouldAMPMFieldDisabled() const;
62     bool shouldDayOfMonthFieldDisabled() const;
63     bool shouldHourFieldDisabled() const;
64     bool shouldMillisecondFieldDisabled() const;
65     bool shouldMinuteFieldDisabled() const;
66     bool shouldSecondFieldDisabled() const;
67     bool shouldYearFieldDisabled() const;
68     inline const StepRange& stepRange() const { return m_parameters.stepRange; }
69     DateTimeNumericFieldElement::Step createStep(double msPerFieldUnit, double msPerFieldSize) const;
70
71     // DateTimeFormat::TokenHandler functions.
72     virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
73     virtual void visitLiteral(const String&) OVERRIDE FINAL;
74
75     DateTimeEditElement& m_editElement;
76     const DateComponents m_dateValue;
77     const DateTimeEditElement::LayoutParameters& m_parameters;
78     DateTimeNumericFieldElement::Range m_dayRange;
79     DateTimeNumericFieldElement::Range m_hour23Range;
80     DateTimeNumericFieldElement::Range m_minuteRange;
81     DateTimeNumericFieldElement::Range m_secondRange;
82     DateTimeNumericFieldElement::Range m_millisecondRange;
83 };
84
85 DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& dateValue)
86     : m_editElement(elemnt)
87     , m_dateValue(dateValue)
88     , m_parameters(layoutParameters)
89     , m_dayRange(1, 31)
90     , m_hour23Range(0, 23)
91     , m_minuteRange(0, 59)
92     , m_secondRange(0, 59)
93     , m_millisecondRange(0, 999)
94 {
95     if (m_dateValue.type() == DateComponents::Date || m_dateValue.type() == DateComponents::DateTimeLocal) {
96         if (m_parameters.minimum.type() != DateComponents::Invalid
97             && m_parameters.maximum.type() != DateComponents::Invalid
98             && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
99             && m_parameters.minimum.month() == m_parameters.maximum.month()
100             && m_parameters.minimum.monthDay() <= m_parameters.maximum.monthDay()) {
101             m_dayRange.minimum = m_parameters.minimum.monthDay();
102             m_dayRange.maximum = m_parameters.maximum.monthDay();
103         }
104     }
105
106     if (m_dateValue.type() == DateComponents::Time || m_dayRange.isSingleton()) {
107         if (m_parameters.minimum.type() != DateComponents::Invalid
108             && m_parameters.maximum.type() != DateComponents::Invalid
109             && m_parameters.minimum.hour() <= m_parameters.maximum.hour()) {
110             m_hour23Range.minimum = m_parameters.minimum.hour();
111             m_hour23Range.maximum = m_parameters.maximum.hour();
112         }
113     }
114
115     if (m_hour23Range.isSingleton() && m_parameters.minimum.minute() <= m_parameters.maximum.minute()) {
116         m_minuteRange.minimum = m_parameters.minimum.minute();
117         m_minuteRange.maximum = m_parameters.maximum.minute();
118     }
119     if (m_minuteRange.isSingleton() && m_parameters.minimum.second() <= m_parameters.maximum.second()) {
120         m_secondRange.minimum = m_parameters.minimum.second();
121         m_secondRange.maximum = m_parameters.maximum.second();
122     }
123     if (m_secondRange.isSingleton() && m_parameters.minimum.millisecond() <= m_parameters.maximum.millisecond()) {
124         m_millisecondRange.minimum = m_parameters.minimum.millisecond();
125         m_millisecondRange.maximum = m_parameters.maximum.millisecond();
126     }
127 }
128
129 bool DateTimeEditBuilder::build(const String& formatString)
130 {
131     m_editElement.resetFields();
132     return DateTimeFormat::parse(formatString, *this);
133 }
134
135 bool DateTimeEditBuilder::needMillisecondField() const
136 {
137     return m_dateValue.millisecond()
138         || !stepRange().minimum().remainder(static_cast<int>(msPerSecond)).isZero()
139         || !stepRange().step().remainder(static_cast<int>(msPerSecond)).isZero();
140 }
141
142 void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int count)
143 {
144     const int countForAbbreviatedMonth = 3;
145     const int countForFullMonth = 4;
146     const int countForNarrowMonth = 5;
147     Document& document = m_editElement.document();
148
149     switch (fieldType) {
150     case DateTimeFormat::FieldTypeDayOfMonth: {
151         RefPtrWillBeRawPtr<DateTimeFieldElement> field = DateTimeDayFieldElement::create(document, m_editElement, m_parameters.placeholderForDay, m_dayRange);
152         m_editElement.addField(field);
153         if (shouldDayOfMonthFieldDisabled()) {
154             field->setValueAsDate(m_dateValue);
155             field->setDisabled();
156         }
157         return;
158     }
159
160     case DateTimeFormat::FieldTypeHour11: {
161         DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
162         RefPtrWillBeRawPtr<DateTimeFieldElement> field = DateTimeHour11FieldElement::create(document, m_editElement, m_hour23Range, step);
163         m_editElement.addField(field);
164         if (shouldHourFieldDisabled()) {
165             field->setValueAsDate(m_dateValue);
166             field->setDisabled();
167         }
168         return;
169     }
170
171     case DateTimeFormat::FieldTypeHour12: {
172         DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
173         RefPtrWillBeRawPtr<DateTimeFieldElement> field = DateTimeHour12FieldElement::create(document, m_editElement, m_hour23Range, step);
174         m_editElement.addField(field);
175         if (shouldHourFieldDisabled()) {
176             field->setValueAsDate(m_dateValue);
177             field->setDisabled();
178         }
179         return;
180     }
181
182     case DateTimeFormat::FieldTypeHour23: {
183         DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
184         RefPtrWillBeRawPtr<DateTimeFieldElement> field = DateTimeHour23FieldElement::create(document, m_editElement, m_hour23Range, step);
185         m_editElement.addField(field);
186         if (shouldHourFieldDisabled()) {
187             field->setValueAsDate(m_dateValue);
188             field->setDisabled();
189         }
190         return;
191     }
192
193     case DateTimeFormat::FieldTypeHour24: {
194         DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
195         RefPtrWillBeRawPtr<DateTimeFieldElement> field = DateTimeHour24FieldElement::create(document, m_editElement, m_hour23Range, step);
196         m_editElement.addField(field);
197         if (shouldHourFieldDisabled()) {
198             field->setValueAsDate(m_dateValue);
199             field->setDisabled();
200         }
201         return;
202     }
203
204     case DateTimeFormat::FieldTypeMinute: {
205         DateTimeNumericFieldElement::Step step = createStep(msPerMinute, msPerHour);
206         RefPtrWillBeRawPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement, m_minuteRange, step);
207         m_editElement.addField(field);
208         if (shouldMinuteFieldDisabled()) {
209             field->setValueAsDate(m_dateValue);
210             field->setDisabled();
211         }
212         return;
213     }
214
215     case DateTimeFormat::FieldTypeMonth: // Fallthrough.
216     case DateTimeFormat::FieldTypeMonthStandAlone: {
217         int minMonth = 0, maxMonth = 11;
218         if (m_parameters.minimum.type() != DateComponents::Invalid
219             && m_parameters.maximum.type() != DateComponents::Invalid
220             && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
221             && m_parameters.minimum.month() <= m_parameters.maximum.month()) {
222             minMonth = m_parameters.minimum.month();
223             maxMonth = m_parameters.maximum.month();
224         }
225         RefPtrWillBeRawPtr<DateTimeFieldElement> field;
226         switch (count) {
227         case countForNarrowMonth: // Fallthrough.
228         case countForAbbreviatedMonth:
229             field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.shortMonthLabels() : m_parameters.locale.shortStandAloneMonthLabels(), minMonth, maxMonth);
230             break;
231         case countForFullMonth:
232             field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.monthLabels() : m_parameters.locale.standAloneMonthLabels(), minMonth, maxMonth);
233             break;
234         default:
235             field = DateTimeMonthFieldElement::create(document, m_editElement, m_parameters.placeholderForMonth, DateTimeNumericFieldElement::Range(minMonth + 1, maxMonth + 1));
236             break;
237         }
238         m_editElement.addField(field);
239         if (minMonth == maxMonth && minMonth == m_dateValue.month() && m_dateValue.type() != DateComponents::Month) {
240             field->setValueAsDate(m_dateValue);
241             field->setDisabled();
242         }
243         return;
244     }
245
246     case DateTimeFormat::FieldTypePeriod: {
247         RefPtrWillBeRawPtr<DateTimeFieldElement> field = DateTimeAMPMFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels());
248         m_editElement.addField(field);
249         if (shouldAMPMFieldDisabled()) {
250             field->setValueAsDate(m_dateValue);
251             field->setDisabled();
252         }
253         return;
254     }
255
256     case DateTimeFormat::FieldTypeSecond: {
257         DateTimeNumericFieldElement::Step step = createStep(msPerSecond, msPerMinute);
258         RefPtrWillBeRawPtr<DateTimeNumericFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement, m_secondRange, step);
259         m_editElement.addField(field);
260         if (shouldSecondFieldDisabled()) {
261             field->setValueAsDate(m_dateValue);
262             field->setDisabled();
263         }
264
265         if (needMillisecondField()) {
266             visitLiteral(m_parameters.locale.localizedDecimalSeparator());
267             visitField(DateTimeFormat::FieldTypeFractionalSecond, 3);
268         }
269         return;
270     }
271
272     case DateTimeFormat::FieldTypeFractionalSecond: {
273         DateTimeNumericFieldElement::Step step = createStep(1, msPerSecond);
274         RefPtrWillBeRawPtr<DateTimeNumericFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement, m_millisecondRange, step);
275         m_editElement.addField(field);
276         if (shouldMillisecondFieldDisabled()) {
277             field->setValueAsDate(m_dateValue);
278             field->setDisabled();
279         }
280         return;
281     }
282
283     case DateTimeFormat::FieldTypeWeekOfYear: {
284         DateTimeNumericFieldElement::Range range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber);
285         if (m_parameters.minimum.type() != DateComponents::Invalid
286             && m_parameters.maximum.type() != DateComponents::Invalid
287             && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
288             && m_parameters.minimum.week() <= m_parameters.maximum.week()) {
289             range.minimum = m_parameters.minimum.week();
290             range.maximum = m_parameters.maximum.week();
291         }
292         m_editElement.addField(DateTimeWeekFieldElement::create(document, m_editElement, range));
293         return;
294     }
295
296     case DateTimeFormat::FieldTypeYear: {
297         DateTimeYearFieldElement::Parameters yearParams;
298         if (m_parameters.minimum.type() == DateComponents::Invalid) {
299             yearParams.minimumYear = DateComponents::minimumYear();
300             yearParams.minIsSpecified = false;
301         } else {
302             yearParams.minimumYear = m_parameters.minimum.fullYear();
303             yearParams.minIsSpecified = true;
304         }
305         if (m_parameters.maximum.type() == DateComponents::Invalid) {
306             yearParams.maximumYear = DateComponents::maximumYear();
307             yearParams.maxIsSpecified = false;
308         } else {
309             yearParams.maximumYear = m_parameters.maximum.fullYear();
310             yearParams.maxIsSpecified = true;
311         }
312         if (yearParams.minimumYear > yearParams.maximumYear) {
313             std::swap(yearParams.minimumYear, yearParams.maximumYear);
314             std::swap(yearParams.minIsSpecified, yearParams.maxIsSpecified);
315         }
316         yearParams.placeholder = m_parameters.placeholderForYear;
317         RefPtrWillBeRawPtr<DateTimeFieldElement> field = DateTimeYearFieldElement::create(document, m_editElement, yearParams);
318         m_editElement.addField(field);
319         if (shouldYearFieldDisabled()) {
320             field->setValueAsDate(m_dateValue);
321             field->setDisabled();
322         }
323         return;
324     }
325
326     default:
327         return;
328     }
329 }
330
331 bool DateTimeEditBuilder::shouldAMPMFieldDisabled() const
332 {
333     return shouldHourFieldDisabled()
334         || (m_hour23Range.minimum < 12 && m_hour23Range.maximum < 12 && m_dateValue.hour() < 12)
335         || (m_hour23Range.minimum >= 12 && m_hour23Range.maximum >= 12 && m_dateValue.hour() >= 12);
336 }
337
338 bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled() const
339 {
340     return m_dayRange.isSingleton() && m_dayRange.minimum == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date;
341 }
342
343 bool DateTimeEditBuilder::shouldHourFieldDisabled() const
344 {
345     if (m_hour23Range.isSingleton() && m_hour23Range.minimum == m_dateValue.hour()
346         && !(shouldMinuteFieldDisabled() && shouldSecondFieldDisabled() && shouldMillisecondFieldDisabled()))
347         return true;
348
349     if (m_dateValue.type() == DateComponents::Time)
350         return false;
351     ASSERT(m_dateValue.type() == DateComponents::DateTimeLocal);
352
353     if (shouldDayOfMonthFieldDisabled()) {
354         ASSERT(m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear());
355         ASSERT(m_parameters.minimum.month() == m_parameters.maximum.month());
356         return false;
357     }
358
359     const Decimal decimalMsPerDay(static_cast<int>(msPerDay));
360     Decimal hourPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerDay) / static_cast<int>(msPerHour)).floor();
361     return hourPartOfMinimum == m_dateValue.hour() && stepRange().step().remainder(decimalMsPerDay).isZero();
362 }
363
364 bool DateTimeEditBuilder::shouldMillisecondFieldDisabled() const
365 {
366     if (m_millisecondRange.isSingleton() && m_millisecondRange.minimum == m_dateValue.millisecond())
367         return true;
368
369     const Decimal decimalMsPerSecond(static_cast<int>(msPerSecond));
370     return stepRange().minimum().abs().remainder(decimalMsPerSecond) == m_dateValue.millisecond() && stepRange().step().remainder(decimalMsPerSecond).isZero();
371 }
372
373 bool DateTimeEditBuilder::shouldMinuteFieldDisabled() const
374 {
375     if (m_minuteRange.isSingleton() && m_minuteRange.minimum == m_dateValue.minute())
376         return true;
377
378     const Decimal decimalMsPerHour(static_cast<int>(msPerHour));
379     Decimal minutePartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerHour) / static_cast<int>(msPerMinute)).floor();
380     return minutePartOfMinimum == m_dateValue.minute() && stepRange().step().remainder(decimalMsPerHour).isZero();
381 }
382
383 bool DateTimeEditBuilder::shouldSecondFieldDisabled() const
384 {
385     if (m_secondRange.isSingleton() && m_secondRange.minimum == m_dateValue.second())
386         return true;
387
388     const Decimal decimalMsPerMinute(static_cast<int>(msPerMinute));
389     Decimal secondPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerMinute) / static_cast<int>(msPerSecond)).floor();
390     return secondPartOfMinimum == m_dateValue.second() && stepRange().step().remainder(decimalMsPerMinute).isZero();
391 }
392
393 bool DateTimeEditBuilder::shouldYearFieldDisabled() const
394 {
395     return m_parameters.minimum.type() != DateComponents::Invalid
396         && m_parameters.maximum.type() != DateComponents::Invalid
397         && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
398         && m_parameters.minimum.fullYear() == m_dateValue.fullYear();
399 }
400
401 void DateTimeEditBuilder::visitLiteral(const String& text)
402 {
403     DEFINE_STATIC_LOCAL(AtomicString, textPseudoId, ("-webkit-datetime-edit-text", AtomicString::ConstructFromLiteral));
404     ASSERT(text.length());
405     RefPtrWillBeRawPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document());
406     element->setShadowPseudoId(textPseudoId);
407     if (m_parameters.locale.isRTL() && text.length()) {
408         Direction dir = direction(text[0]);
409         if (dir == SegmentSeparator || dir == WhiteSpaceNeutral || dir == OtherNeutral)
410             element->appendChild(Text::create(m_editElement.document(), String(&rightToLeftMark, 1)));
411     }
412     element->appendChild(Text::create(m_editElement.document(), text));
413     m_editElement.fieldsWrapperElement()->appendChild(element);
414 }
415
416 DateTimeNumericFieldElement::Step DateTimeEditBuilder::createStep(double msPerFieldUnit, double msPerFieldSize) const
417 {
418     const Decimal msPerFieldUnitDecimal(static_cast<int>(msPerFieldUnit));
419     const Decimal msPerFieldSizeDecimal(static_cast<int>(msPerFieldSize));
420     Decimal stepMilliseconds = stepRange().step();
421     ASSERT(!msPerFieldUnitDecimal.isZero());
422     ASSERT(!msPerFieldSizeDecimal.isZero());
423     ASSERT(!stepMilliseconds.isZero());
424
425     DateTimeNumericFieldElement::Step step(1, 0);
426
427     if (stepMilliseconds.remainder(msPerFieldSizeDecimal).isZero())
428         stepMilliseconds = msPerFieldSizeDecimal;
429
430     if (msPerFieldSizeDecimal.remainder(stepMilliseconds).isZero() && stepMilliseconds.remainder(msPerFieldUnitDecimal).isZero()) {
431         step.step = static_cast<int>((stepMilliseconds / msPerFieldUnitDecimal).toDouble());
432         step.stepBase = static_cast<int>((stepRange().stepBase() / msPerFieldUnitDecimal).floor().remainder(msPerFieldSizeDecimal / msPerFieldUnitDecimal).toDouble());
433     }
434     return step;
435 }
436
437 // ----------------------------
438
439 DateTimeEditElement::EditControlOwner::~EditControlOwner()
440 {
441 }
442
443 DateTimeEditElement::DateTimeEditElement(Document& document, EditControlOwner& editControlOwner)
444     : HTMLDivElement(document)
445     , m_editControlOwner(&editControlOwner)
446 {
447     setHasCustomStyleCallbacks();
448 }
449
450 DateTimeEditElement::~DateTimeEditElement()
451 {
452 #if !ENABLE(OILPAN)
453     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
454         m_fields[fieldIndex]->removeEventHandler();
455 #endif
456 }
457
458 void DateTimeEditElement::trace(Visitor* visitor)
459 {
460 #if ENABLE(OILPAN)
461     visitor->trace(m_fields);
462 #endif
463     visitor->trace(m_editControlOwner);
464     HTMLDivElement::trace(visitor);
465 }
466
467 inline Element* DateTimeEditElement::fieldsWrapperElement() const
468 {
469     ASSERT(firstChild());
470     return toElement(firstChild());
471 }
472
473 void DateTimeEditElement::addField(PassRefPtrWillBeRawPtr<DateTimeFieldElement> field)
474 {
475     if (m_fields.size() == m_fields.capacity())
476         return;
477     m_fields.append(field.get());
478     fieldsWrapperElement()->appendChild(field);
479 }
480
481 bool DateTimeEditElement::anyEditableFieldsHaveValues() const
482 {
483     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
484         if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue())
485             return true;
486     }
487     return false;
488 }
489
490 void DateTimeEditElement::blurByOwner()
491 {
492     if (DateTimeFieldElement* field = focusedField())
493         field->blur();
494 }
495
496 PassRefPtrWillBeRawPtr<DateTimeEditElement> DateTimeEditElement::create(Document& document, EditControlOwner& editControlOwner)
497 {
498     RefPtrWillBeRawPtr<DateTimeEditElement> container = adoptRefWillBeNoop(new DateTimeEditElement(document, editControlOwner));
499     container->setShadowPseudoId(AtomicString("-webkit-datetime-edit", AtomicString::ConstructFromLiteral));
500     container->setAttribute(idAttr, ShadowElementNames::dateTimeEdit());
501     return container.release();
502 }
503
504 PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer()
505 {
506     // FIXME: This is a kind of layout. We might want to introduce new renderer.
507     FontCachePurgePreventer fontCachePurgePreventer;
508     RefPtr<RenderStyle> originalStyle = originalStyleForRenderer();
509     RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
510     float width = 0;
511     for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) {
512         if (!child->isElementNode())
513             continue;
514         Element* childElement = toElement(child);
515         if (childElement->isDateTimeFieldElement()) {
516             // We need to pass the Font of this element because child elements
517             // can't resolve inherited style at this timing.
518             width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font());
519         } else {
520             // ::-webkit-datetime-edit-text case. It has no
521             // border/padding/margin in html.css.
522             width += style->font().width(childElement->textContent());
523         }
524     }
525     style->setWidth(Length(ceilf(width), Fixed));
526     style->setUnique();
527     return style.release();
528 }
529
530 void DateTimeEditElement::didBlurFromField()
531 {
532     if (m_editControlOwner)
533         m_editControlOwner->didBlurFromControl();
534 }
535
536 void DateTimeEditElement::didFocusOnField()
537 {
538     if (m_editControlOwner)
539         m_editControlOwner->didFocusOnControl();
540 }
541
542 void DateTimeEditElement::disabledStateChanged()
543 {
544     updateUIState();
545 }
546
547 DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const
548 {
549     return fieldIndex < m_fields.size() ? m_fields[fieldIndex].get() : 0;
550 }
551
552 size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const
553 {
554     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
555         if (m_fields[fieldIndex] == &field)
556             return fieldIndex;
557     }
558     return invalidFieldIndex;
559 }
560
561 void DateTimeEditElement::focusIfNoFocus()
562 {
563     if (focusedFieldIndex() != invalidFieldIndex)
564         return;
565     focusOnNextFocusableField(0);
566 }
567
568 void DateTimeEditElement::focusByOwner(Element* oldFocusedElement)
569 {
570     if (oldFocusedElement && oldFocusedElement->isDateTimeFieldElement()) {
571         DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedElement);
572         size_t index = fieldIndexOf(*oldFocusedField);
573         if (index != invalidFieldIndex && oldFocusedField->isFocusable()) {
574             oldFocusedField->focus();
575             return;
576         }
577     }
578     focusOnNextFocusableField(0);
579 }
580
581 DateTimeFieldElement* DateTimeEditElement::focusedField() const
582 {
583     return fieldAt(focusedFieldIndex());
584 }
585
586 size_t DateTimeEditElement::focusedFieldIndex() const
587 {
588     Element* const focusedFieldElement = document().focusedElement();
589     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
590         if (m_fields[fieldIndex] == focusedFieldElement)
591             return fieldIndex;
592     }
593     return invalidFieldIndex;
594 }
595
596 void DateTimeEditElement::fieldValueChanged()
597 {
598     if (m_editControlOwner)
599         m_editControlOwner->editControlValueChanged();
600 }
601
602 bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex)
603 {
604     for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) {
605         if (m_fields[fieldIndex]->isFocusable()) {
606             m_fields[fieldIndex]->focus();
607             return true;
608         }
609     }
610     return false;
611 }
612
613 bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field)
614 {
615     const size_t startFieldIndex = fieldIndexOf(field);
616     if (startFieldIndex == invalidFieldIndex)
617         return false;
618     return focusOnNextFocusableField(startFieldIndex + 1);
619 }
620
621 bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field)
622 {
623     const size_t startFieldIndex = fieldIndexOf(field);
624     if (startFieldIndex == invalidFieldIndex)
625         return false;
626     size_t fieldIndex = startFieldIndex;
627     while (fieldIndex > 0) {
628         --fieldIndex;
629         if (m_fields[fieldIndex]->isFocusable()) {
630             m_fields[fieldIndex]->focus();
631             return true;
632         }
633     }
634     return false;
635 }
636
637 bool DateTimeEditElement::isDateTimeEditElement() const
638 {
639     return true;
640 }
641
642 bool DateTimeEditElement::isDisabled() const
643 {
644     return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled();
645 }
646
647 bool DateTimeEditElement::isFieldOwnerDisabled() const
648 {
649     return isDisabled();
650 }
651
652 bool DateTimeEditElement::isFieldOwnerReadOnly() const
653 {
654     return isReadOnly();
655 }
656
657 bool DateTimeEditElement::isReadOnly() const
658 {
659     return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly();
660 }
661
662 void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue)
663 {
664     DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral));
665     if (!firstChild()) {
666         RefPtrWillBeRawPtr<HTMLDivElement> element = HTMLDivElement::create(document());
667         element->setShadowPseudoId(fieldsWrapperPseudoId);
668         appendChild(element.get());
669     }
670     Element* fieldsWrapper = fieldsWrapperElement();
671
672     size_t focusedFieldIndex = this->focusedFieldIndex();
673     DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex);
674     const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom;
675
676     DateTimeEditBuilder builder(*this, layoutParameters, dateValue);
677     Node* lastChildToBeRemoved = fieldsWrapper->lastChild();
678     if (!builder.build(layoutParameters.dateTimeFormat) || m_fields.isEmpty()) {
679         lastChildToBeRemoved = fieldsWrapper->lastChild();
680         builder.build(layoutParameters.fallbackDateTimeFormat);
681     }
682
683     if (focusedFieldIndex != invalidFieldIndex) {
684         for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
685             if (m_fields[fieldIndex]->shadowPseudoId() == focusedFieldId) {
686                 focusedFieldIndex = fieldIndex;
687                 break;
688             }
689         }
690         if (DateTimeFieldElement* field = fieldAt(std::min(focusedFieldIndex, m_fields.size() - 1)))
691             field->focus();
692     }
693
694     if (lastChildToBeRemoved) {
695         for (Node* childNode = fieldsWrapper->firstChild(); childNode; childNode = fieldsWrapper->firstChild()) {
696             fieldsWrapper->removeChild(childNode);
697             if (childNode == lastChildToBeRemoved)
698                 break;
699         }
700         setNeedsStyleRecalc(SubtreeStyleChange);
701     }
702 }
703
704 AtomicString DateTimeEditElement::localeIdentifier() const
705 {
706     return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom;
707 }
708
709 void DateTimeEditElement::fieldDidChangeValueByKeyboard()
710 {
711     if (m_editControlOwner)
712         m_editControlOwner->editControlDidChangeValueByKeyboard();
713 }
714
715 void DateTimeEditElement::readOnlyStateChanged()
716 {
717     updateUIState();
718 }
719
720 void DateTimeEditElement::resetFields()
721 {
722     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
723         m_fields[fieldIndex]->removeEventHandler();
724     m_fields.shrink(0);
725 }
726
727 void DateTimeEditElement::defaultEventHandler(Event* event)
728 {
729     // In case of control owner forward event to control, e.g. DOM
730     // dispatchEvent method.
731     if (DateTimeFieldElement* field = focusedField()) {
732         field->defaultEventHandler(event);
733         if (event->defaultHandled())
734             return;
735     }
736
737     HTMLDivElement::defaultEventHandler(event);
738 }
739
740 void DateTimeEditElement::setValueAsDate(const LayoutParameters& layoutParameters, const DateComponents& date)
741 {
742     layout(layoutParameters, date);
743     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
744         m_fields[fieldIndex]->setValueAsDate(date);
745 }
746
747 void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
748 {
749     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
750         m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState);
751 }
752
753 void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters, const DateComponents& dateForReadOnlyField)
754 {
755     layout(layoutParameters, dateForReadOnlyField);
756     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
757         m_fields[fieldIndex]->setEmptyValue(DateTimeFieldElement::DispatchNoEvent);
758 }
759
760 bool DateTimeEditElement::hasFocusedField()
761 {
762     return focusedFieldIndex() != invalidFieldIndex;
763 }
764
765 void DateTimeEditElement::setOnlyYearMonthDay(const DateComponents& date)
766 {
767     ASSERT(date.type() == DateComponents::Date);
768
769     if (!m_editControlOwner)
770         return;
771
772     DateTimeFieldsState dateTimeFieldsState = valueAsDateTimeFieldsState();
773     dateTimeFieldsState.setYear(date.fullYear());
774     dateTimeFieldsState.setMonth(date.month() + 1);
775     dateTimeFieldsState.setDayOfMonth(date.monthDay());
776     setValueAsDateTimeFieldsState(dateTimeFieldsState);
777     m_editControlOwner->editControlValueChanged();
778 }
779
780 void DateTimeEditElement::stepDown()
781 {
782     if (DateTimeFieldElement* const field = focusedField())
783         field->stepDown();
784 }
785
786 void DateTimeEditElement::stepUp()
787 {
788     if (DateTimeFieldElement* const field = focusedField())
789         field->stepUp();
790 }
791
792 void DateTimeEditElement::updateUIState()
793 {
794     if (isDisabled()) {
795         if (DateTimeFieldElement* field = focusedField())
796             field->blur();
797     }
798 }
799
800 String DateTimeEditElement::value() const
801 {
802     if (!m_editControlOwner)
803         return emptyString();
804     return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState());
805 }
806
807 DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const
808 {
809     DateTimeFieldsState dateTimeFieldsState;
810     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
811         m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState);
812     return dateTimeFieldsState;
813 }
814
815 } // namespace WebCore
816
817 #endif