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/core/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
45namespace blink {
46
47using namespace HTMLNames;
48using namespace WTF::Unicode;
49
50class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
51    WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder);
52
53public:
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
59private:
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
85DateTimeEditBuilder::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
129bool DateTimeEditBuilder::build(const String& formatString)
130{
131    m_editElement.resetFields();
132    return DateTimeFormat::parse(formatString, *this);
133}
134
135bool 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
142void 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
331bool 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
338bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled() const
339{
340    return m_dayRange.isSingleton() && m_dayRange.minimum == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date;
341}
342
343bool 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
364bool 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
373bool 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
383bool 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
393bool 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
401void 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
416DateTimeNumericFieldElement::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
439DateTimeEditElement::EditControlOwner::~EditControlOwner()
440{
441}
442
443DateTimeEditElement::DateTimeEditElement(Document& document, EditControlOwner& editControlOwner)
444    : HTMLDivElement(document)
445    , m_editControlOwner(&editControlOwner)
446{
447    setHasCustomStyleCallbacks();
448}
449
450DateTimeEditElement::~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
458void 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
467inline Element* DateTimeEditElement::fieldsWrapperElement() const
468{
469    ASSERT(firstChild());
470    return toElement(firstChild());
471}
472
473void 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
481bool 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
490void DateTimeEditElement::blurByOwner()
491{
492    if (DateTimeFieldElement* field = focusedField())
493        field->blur();
494}
495
496PassRefPtrWillBeRawPtr<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
504PassRefPtr<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
530void DateTimeEditElement::didBlurFromField()
531{
532    if (m_editControlOwner)
533        m_editControlOwner->didBlurFromControl();
534}
535
536void DateTimeEditElement::didFocusOnField()
537{
538    if (m_editControlOwner)
539        m_editControlOwner->didFocusOnControl();
540}
541
542void DateTimeEditElement::disabledStateChanged()
543{
544    updateUIState();
545}
546
547DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const
548{
549    return fieldIndex < m_fields.size() ? m_fields[fieldIndex].get() : 0;
550}
551
552size_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
561void DateTimeEditElement::focusIfNoFocus()
562{
563    if (focusedFieldIndex() != invalidFieldIndex)
564        return;
565    focusOnNextFocusableField(0);
566}
567
568void 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
581DateTimeFieldElement* DateTimeEditElement::focusedField() const
582{
583    return fieldAt(focusedFieldIndex());
584}
585
586size_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
596void DateTimeEditElement::fieldValueChanged()
597{
598    if (m_editControlOwner)
599        m_editControlOwner->editControlValueChanged();
600}
601
602bool 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
613bool 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
621bool 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
637bool DateTimeEditElement::isDateTimeEditElement() const
638{
639    return true;
640}
641
642bool DateTimeEditElement::isDisabled() const
643{
644    return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled();
645}
646
647bool DateTimeEditElement::isFieldOwnerDisabled() const
648{
649    return isDisabled();
650}
651
652bool DateTimeEditElement::isFieldOwnerReadOnly() const
653{
654    return isReadOnly();
655}
656
657bool DateTimeEditElement::isReadOnly() const
658{
659    return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly();
660}
661
662void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue)
663{
664    DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral));
665    if (!hasChildren()) {
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
704AtomicString DateTimeEditElement::localeIdentifier() const
705{
706    return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom;
707}
708
709void DateTimeEditElement::fieldDidChangeValueByKeyboard()
710{
711    if (m_editControlOwner)
712        m_editControlOwner->editControlDidChangeValueByKeyboard();
713}
714
715void DateTimeEditElement::readOnlyStateChanged()
716{
717    updateUIState();
718}
719
720void 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
727void 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
740void 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
747void 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
753void 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
760bool DateTimeEditElement::hasFocusedField()
761{
762    return focusedFieldIndex() != invalidFieldIndex;
763}
764
765void 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
780void DateTimeEditElement::stepDown()
781{
782    if (DateTimeFieldElement* const field = focusedField())
783        field->stepDown();
784}
785
786void DateTimeEditElement::stepUp()
787{
788    if (DateTimeFieldElement* const field = focusedField())
789        field->stepUp();
790}
791
792void DateTimeEditElement::updateUIState()
793{
794    if (isDisabled()) {
795        if (DateTimeFieldElement* field = focusedField())
796            field->blur();
797    }
798}
799
800String DateTimeEditElement::value() const
801{
802    if (!m_editControlOwner)
803        return emptyString();
804    return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState());
805}
806
807DateTimeFieldsState 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 blink
816
817#endif
818