Merge from Chromium at DEPS revision r198571

This commit was generated by merge_to_master.py.

Change-Id: I3a7f89ea6b8c017335bd52739166aed708cad1e5
diff --git a/Source/core/html/shadow/DateTimeEditElement.cpp b/Source/core/html/shadow/DateTimeEditElement.cpp
new file mode 100644
index 0000000..1e323a1
--- /dev/null
+++ b/Source/core/html/shadow/DateTimeEditElement.cpp
@@ -0,0 +1,798 @@
+/*
+ * Copyright (C) 2012 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "config.h"
+#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
+#include "core/html/shadow/DateTimeEditElement.h"
+
+#include "HTMLNames.h"
+#include "core/css/StyleResolver.h"
+#include "core/dom/KeyboardEvent.h"
+#include "core/dom/MouseEvent.h"
+#include "core/dom/Text.h"
+#include "core/html/DateTimeFieldsState.h"
+#include "core/html/shadow/DateTimeFieldElements.h"
+#include "core/html/shadow/DateTimeSymbolicFieldElement.h"
+#include "core/page/EventHandler.h"
+#include "core/platform/DateComponents.h"
+#include "core/platform/graphics/FontCache.h"
+#include "core/platform/text/DateTimeFormat.h"
+#include "core/platform/text/PlatformLocale.h"
+#include "core/rendering/style/RenderStyle.h"
+#include <wtf/DateMath.h>
+#include <wtf/text/StringBuilder.h>
+
+namespace WebCore {
+
+using namespace HTMLNames;
+using namespace WTF::Unicode;
+
+class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
+    WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder);
+
+public:
+    // The argument objects must be alive until this object dies.
+    DateTimeEditBuilder(DateTimeEditElement&, const DateTimeEditElement::LayoutParameters&, const DateComponents&);
+
+    bool build(const String&);
+
+private:
+    bool needMillisecondField() const;
+    bool shouldAMPMFieldDisabled() const;
+    bool shouldDayOfMonthFieldDisabled() const;
+    bool shouldHourFieldDisabled() const;
+    bool shouldMillisecondFieldDisabled() const;
+    bool shouldMinuteFieldDisabled() const;
+    bool shouldSecondFieldDisabled() const;
+    bool shouldYearFieldDisabled() const;
+    inline const StepRange& stepRange() const { return m_parameters.stepRange; }
+    DateTimeNumericFieldElement::Step createStep(double msPerFieldUnit, double msPerFieldSize) const;
+
+    // DateTimeFormat::TokenHandler functions.
+    virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
+    virtual void visitLiteral(const String&) OVERRIDE FINAL;
+
+    DateTimeEditElement& m_editElement;
+    const DateComponents m_dateValue;
+    const DateTimeEditElement::LayoutParameters& m_parameters;
+    DateTimeNumericFieldElement::Range m_dayRange;
+    DateTimeNumericFieldElement::Range m_hour23Range;
+    DateTimeNumericFieldElement::Range m_minuteRange;
+    DateTimeNumericFieldElement::Range m_secondRange;
+    DateTimeNumericFieldElement::Range m_millisecondRange;
+};
+
+DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& dateValue)
+    : m_editElement(elemnt)
+    , m_dateValue(dateValue)
+    , m_parameters(layoutParameters)
+    , m_dayRange(1, 31)
+    , m_hour23Range(0, 23)
+    , m_minuteRange(0, 59)
+    , m_secondRange(0, 59)
+    , m_millisecondRange(0, 999)
+{
+    if (m_dateValue.type() == DateComponents::Date
+        || m_dateValue.type() == DateComponents::DateTimeLocal
+        || m_dateValue.type() == DateComponents::DateTime) {
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+            && m_parameters.minimum.month() == m_parameters.maximum.month()
+            && m_parameters.minimum.monthDay() <= m_parameters.maximum.monthDay()) {
+            m_dayRange.minimum = m_parameters.minimum.monthDay();
+            m_dayRange.maximum = m_parameters.maximum.monthDay();
+        }
+    }
+
+    if (m_dateValue.type() == DateComponents::Time || m_dayRange.isSingleton()) {
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.hour() <= m_parameters.maximum.hour()) {
+            m_hour23Range.minimum = m_parameters.minimum.hour();
+            m_hour23Range.maximum = m_parameters.maximum.hour();
+        }
+    }
+
+    if (m_hour23Range.isSingleton() && m_parameters.minimum.minute() <= m_parameters.maximum.minute()) {
+        m_minuteRange.minimum = m_parameters.minimum.minute();
+        m_minuteRange.maximum = m_parameters.maximum.minute();
+    }
+    if (m_minuteRange.isSingleton() && m_parameters.minimum.second() <= m_parameters.maximum.second()) {
+        m_secondRange.minimum = m_parameters.minimum.second();
+        m_secondRange.maximum = m_parameters.maximum.second();
+    }
+    if (m_secondRange.isSingleton() && m_parameters.minimum.millisecond() <= m_parameters.maximum.millisecond()) {
+        m_millisecondRange.minimum = m_parameters.minimum.millisecond();
+        m_millisecondRange.maximum = m_parameters.maximum.millisecond();
+    }
+}
+
+bool DateTimeEditBuilder::build(const String& formatString)
+{
+    m_editElement.resetFields();
+    return DateTimeFormat::parse(formatString, *this);
+}
+
+bool DateTimeEditBuilder::needMillisecondField() const
+{
+    return m_dateValue.millisecond()
+        || !stepRange().minimum().remainder(static_cast<int>(msPerSecond)).isZero()
+        || !stepRange().step().remainder(static_cast<int>(msPerSecond)).isZero();
+}
+
+void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int count)
+{
+    const int countForAbbreviatedMonth = 3;
+    const int countForFullMonth = 4;
+    const int countForNarrowMonth = 5;
+    Document* const document = m_editElement.document();
+
+    switch (fieldType) {
+    case DateTimeFormat::FieldTypeDayOfMonth: {
+        RefPtr<DateTimeFieldElement> field = DateTimeDayFieldElement::create(document, m_editElement, m_parameters.placeholderForDay, m_dayRange);
+        m_editElement.addField(field);
+        if (shouldDayOfMonthFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour11: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour11FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour12: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour12FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour23: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour23FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeHour24: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
+        RefPtr<DateTimeFieldElement> field = DateTimeHour24FieldElement::create(document, m_editElement, m_hour23Range, step);
+        m_editElement.addField(field);
+        if (shouldHourFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeMinute: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerMinute, msPerHour);
+        RefPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement, m_minuteRange, step);
+        m_editElement.addField(field);
+        if (shouldMinuteFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeMonth: // Fallthrough.
+    case DateTimeFormat::FieldTypeMonthStandAlone: {
+        int minMonth = 0, maxMonth = 11;
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+            && m_parameters.minimum.month() <= m_parameters.maximum.month()) {
+            minMonth = m_parameters.minimum.month();
+            maxMonth = m_parameters.maximum.month();
+        }
+        RefPtr<DateTimeFieldElement> field;
+        switch (count) {
+        case countForNarrowMonth: // Fallthrough.
+        case countForAbbreviatedMonth:
+            field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.shortMonthLabels() : m_parameters.locale.shortStandAloneMonthLabels(), minMonth, maxMonth);
+            break;
+        case countForFullMonth:
+            field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.monthLabels() : m_parameters.locale.standAloneMonthLabels(), minMonth, maxMonth);
+            break;
+        default:
+            field = DateTimeMonthFieldElement::create(document, m_editElement, m_parameters.placeholderForMonth, DateTimeNumericFieldElement::Range(minMonth + 1, maxMonth + 1));
+            break;
+        }
+        m_editElement.addField(field);
+        if (minMonth == maxMonth && minMonth == m_dateValue.month() && m_dateValue.type() != DateComponents::Month) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypePeriod: {
+        RefPtr<DateTimeFieldElement> field = DateTimeAMPMFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels());
+        m_editElement.addField(field);
+        if (shouldAMPMFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeSecond: {
+        DateTimeNumericFieldElement::Step step = createStep(msPerSecond, msPerMinute);
+        RefPtr<DateTimeNumericFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement, m_secondRange, step);
+        m_editElement.addField(field);
+        if (shouldSecondFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+
+        if (needMillisecondField()) {
+            visitLiteral(m_parameters.locale.localizedDecimalSeparator());
+            visitField(DateTimeFormat::FieldTypeFractionalSecond, 3);
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeFractionalSecond: {
+        DateTimeNumericFieldElement::Step step = createStep(1, msPerSecond);
+        RefPtr<DateTimeNumericFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement, m_millisecondRange, step);
+        m_editElement.addField(field);
+        if (shouldMillisecondFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeWeekOfYear: {
+        DateTimeNumericFieldElement::Range range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber);
+        if (m_parameters.minimum.type() != DateComponents::Invalid
+            && m_parameters.maximum.type() != DateComponents::Invalid
+            && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+            && m_parameters.minimum.week() <= m_parameters.maximum.week()) {
+            range.minimum = m_parameters.minimum.week();
+            range.maximum = m_parameters.maximum.week();
+        }
+        m_editElement.addField(DateTimeWeekFieldElement::create(document, m_editElement, range));
+        return;
+    }
+
+    case DateTimeFormat::FieldTypeYear: {
+        DateTimeYearFieldElement::Parameters yearParams;
+        if (m_parameters.minimum.type() == DateComponents::Invalid) {
+            yearParams.minimumYear = DateComponents::minimumYear();
+            yearParams.minIsSpecified = false;
+        } else {
+            yearParams.minimumYear = m_parameters.minimum.fullYear();
+            yearParams.minIsSpecified = true;
+        }
+        if (m_parameters.maximum.type() == DateComponents::Invalid) {
+            yearParams.maximumYear = DateComponents::maximumYear();
+            yearParams.maxIsSpecified = false;
+        } else {
+            yearParams.maximumYear = m_parameters.maximum.fullYear();
+            yearParams.maxIsSpecified = true;
+        }
+        if (yearParams.minimumYear > yearParams.maximumYear) {
+            std::swap(yearParams.minimumYear, yearParams.maximumYear);
+            std::swap(yearParams.minIsSpecified, yearParams.maxIsSpecified);
+        }
+        yearParams.placeholder = m_parameters.placeholderForYear;
+        RefPtr<DateTimeFieldElement> field = DateTimeYearFieldElement::create(document, m_editElement, yearParams);
+        m_editElement.addField(field);
+        if (shouldYearFieldDisabled()) {
+            field->setValueAsDate(m_dateValue);
+            field->setDisabled();
+        }
+        return;
+    }
+
+    default:
+        return;
+    }
+}
+
+bool DateTimeEditBuilder::shouldAMPMFieldDisabled() const
+{
+    return shouldHourFieldDisabled()
+        || (m_hour23Range.minimum < 12 && m_hour23Range.maximum < 12 && m_dateValue.hour() < 12)
+        || (m_hour23Range.minimum >= 12 && m_hour23Range.maximum >= 12 && m_dateValue.hour() >= 12);
+}
+
+bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled() const
+{
+    return m_dayRange.isSingleton() && m_dayRange.minimum == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date;
+}
+
+bool DateTimeEditBuilder::shouldHourFieldDisabled() const
+{
+    if (m_hour23Range.isSingleton() && m_hour23Range.minimum == m_dateValue.hour()
+        && !(shouldMinuteFieldDisabled() && shouldSecondFieldDisabled() && shouldMillisecondFieldDisabled()))
+        return true;
+
+    if (m_dateValue.type() == DateComponents::Time)
+        return false;
+    ASSERT(m_dateValue.type() == DateComponents::DateTimeLocal || m_dateValue.type() == DateComponents::DateTime);
+
+    if (shouldDayOfMonthFieldDisabled()) {
+        ASSERT(m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear());
+        ASSERT(m_parameters.minimum.month() == m_parameters.maximum.month());
+        return false;
+    }
+
+    const Decimal decimalMsPerDay(static_cast<int>(msPerDay));
+    Decimal hourPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerDay) / static_cast<int>(msPerHour)).floor();
+    return hourPartOfMinimum == m_dateValue.hour() && stepRange().step().remainder(decimalMsPerDay).isZero();
+}
+
+bool DateTimeEditBuilder::shouldMillisecondFieldDisabled() const
+{
+    if (m_millisecondRange.isSingleton() && m_millisecondRange.minimum == m_dateValue.millisecond())
+        return true;
+
+    const Decimal decimalMsPerSecond(static_cast<int>(msPerSecond));
+    return stepRange().minimum().abs().remainder(decimalMsPerSecond) == m_dateValue.millisecond() && stepRange().step().remainder(decimalMsPerSecond).isZero();
+}
+
+bool DateTimeEditBuilder::shouldMinuteFieldDisabled() const
+{
+    if (m_minuteRange.isSingleton() && m_minuteRange.minimum == m_dateValue.minute())
+        return true;
+
+    const Decimal decimalMsPerHour(static_cast<int>(msPerHour));
+    Decimal minutePartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerHour) / static_cast<int>(msPerMinute)).floor();
+    return minutePartOfMinimum == m_dateValue.minute() && stepRange().step().remainder(decimalMsPerHour).isZero();
+}
+
+bool DateTimeEditBuilder::shouldSecondFieldDisabled() const
+{
+    if (m_secondRange.isSingleton() && m_secondRange.minimum == m_dateValue.second())
+        return true;
+
+    const Decimal decimalMsPerMinute(static_cast<int>(msPerMinute));
+    Decimal secondPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerMinute) / static_cast<int>(msPerSecond)).floor();
+    return secondPartOfMinimum == m_dateValue.second() && stepRange().step().remainder(decimalMsPerMinute).isZero();
+}
+
+bool DateTimeEditBuilder::shouldYearFieldDisabled() const
+{
+    return m_parameters.minimum.type() != DateComponents::Invalid
+        && m_parameters.maximum.type() != DateComponents::Invalid
+        && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
+        && m_parameters.minimum.fullYear() == m_dateValue.fullYear();
+}
+
+void DateTimeEditBuilder::visitLiteral(const String& text)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, textPseudoId, ("-webkit-datetime-edit-text", AtomicString::ConstructFromLiteral));
+    ASSERT(text.length());
+    RefPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document());
+    element->setPseudo(textPseudoId);
+    if (m_parameters.locale.isRTL() && text.length()) {
+        Direction dir = direction(text[0]);
+        if (dir == SegmentSeparator || dir == WhiteSpaceNeutral || dir == OtherNeutral)
+            element->appendChild(Text::create(m_editElement.document(), String(&rightToLeftMark, 1)));
+    }
+    element->appendChild(Text::create(m_editElement.document(), text));
+    m_editElement.fieldsWrapperElement()->appendChild(element);
+}
+
+DateTimeNumericFieldElement::Step DateTimeEditBuilder::createStep(double msPerFieldUnit, double msPerFieldSize) const
+{
+    const Decimal msPerFieldUnitDecimal(static_cast<int>(msPerFieldUnit));
+    const Decimal msPerFieldSizeDecimal(static_cast<int>(msPerFieldSize));
+    Decimal stepMilliseconds = stepRange().step();
+    ASSERT(!msPerFieldUnitDecimal.isZero());
+    ASSERT(!msPerFieldSizeDecimal.isZero());
+    ASSERT(!stepMilliseconds.isZero());
+
+    DateTimeNumericFieldElement::Step step(1, 0);
+
+    if (stepMilliseconds.remainder(msPerFieldSizeDecimal).isZero())
+        stepMilliseconds = msPerFieldSizeDecimal;
+
+    if (msPerFieldSizeDecimal.remainder(stepMilliseconds).isZero() && stepMilliseconds.remainder(msPerFieldUnitDecimal).isZero()) {
+        step.step = static_cast<int>((stepMilliseconds / msPerFieldUnitDecimal).toDouble());
+        step.stepBase = static_cast<int>((stepRange().stepBase() / msPerFieldUnitDecimal).floor().remainder(msPerFieldSizeDecimal / msPerFieldUnitDecimal).toDouble());
+    }
+    return step;
+}
+
+// ----------------------------
+
+DateTimeEditElement::EditControlOwner::~EditControlOwner()
+{
+}
+
+DateTimeEditElement::DateTimeEditElement(Document* document, EditControlOwner& editControlOwner)
+    : HTMLDivElement(divTag, document)
+    , m_editControlOwner(&editControlOwner)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, dateTimeEditPseudoId, ("-webkit-datetime-edit", AtomicString::ConstructFromLiteral));
+    setPseudo(dateTimeEditPseudoId);
+    setHasCustomStyleCallbacks();
+}
+
+DateTimeEditElement::~DateTimeEditElement()
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->removeEventHandler();
+}
+
+inline Element* DateTimeEditElement::fieldsWrapperElement() const
+{
+    ASSERT(firstChild());
+    return toElement(firstChild());
+}
+
+void DateTimeEditElement::addField(PassRefPtr<DateTimeFieldElement> field)
+{
+    if (m_fields.size() == m_fields.capacity())
+        return;
+    m_fields.append(field.get());
+    fieldsWrapperElement()->appendChild(field);
+}
+
+bool DateTimeEditElement::anyEditableFieldsHaveValues() const
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue())
+            return true;
+    }
+    return false;
+}
+
+void DateTimeEditElement::blurByOwner()
+{
+    if (DateTimeFieldElement* field = focusedField())
+        field->blur();
+}
+
+PassRefPtr<DateTimeEditElement> DateTimeEditElement::create(Document* document, EditControlOwner& editControlOwner)
+{
+    RefPtr<DateTimeEditElement> container = adoptRef(new DateTimeEditElement(document, editControlOwner));
+    return container.release();
+}
+
+PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer()
+{
+    // FIXME: This is a kind of layout. We might want to introduce new renderer.
+    FontCachePurgePreventer fontCachePurgePreventer;
+    RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForElement(this);
+    RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
+    float width = 0;
+    for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) {
+        if (!child->isElementNode())
+            continue;
+        Element* childElement = toElement(child);
+        if (childElement->isDateTimeFieldElement()) {
+            // We need to pass the Font of this element because child elements
+            // can't resolve inherited style at this timing.
+            width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font());
+        } else {
+            // ::-webkit-datetime-edit-text case. It has no
+            // border/padding/margin in html.css.
+            width += style->font().width(childElement->textContent());
+        }
+    }
+    style->setWidth(Length(ceilf(width), Fixed));
+    return style.release();
+}
+
+void DateTimeEditElement::didBlurFromField()
+{
+    if (m_editControlOwner)
+        m_editControlOwner->didBlurFromControl();
+}
+
+void DateTimeEditElement::didFocusOnField()
+{
+    if (m_editControlOwner)
+        m_editControlOwner->didFocusOnControl();
+}
+
+void DateTimeEditElement::disabledStateChanged()
+{
+    updateUIState();
+}
+
+DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const
+{
+    return fieldIndex < m_fields.size() ? m_fields[fieldIndex] : 0;
+}
+
+size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (m_fields[fieldIndex] == &field)
+            return fieldIndex;
+    }
+    return invalidFieldIndex;
+}
+
+void DateTimeEditElement::focusIfNoFocus()
+{
+    if (focusedFieldIndex() != invalidFieldIndex)
+        return;
+    focusOnNextFocusableField(0);
+}
+
+void DateTimeEditElement::focusByOwner(Node* oldFocusedNode)
+{
+    if (oldFocusedNode && oldFocusedNode->isElementNode() && toElement(oldFocusedNode)->isDateTimeFieldElement()) {
+        DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedNode);
+        size_t index = fieldIndexOf(*oldFocusedField);
+        if (index != invalidFieldIndex && oldFocusedField->isFocusable()) {
+            oldFocusedField->focus();
+            return;
+        }
+    }
+    focusOnNextFocusableField(0);
+}
+
+DateTimeFieldElement* DateTimeEditElement::focusedField() const
+{
+    return fieldAt(focusedFieldIndex());
+}
+
+size_t DateTimeEditElement::focusedFieldIndex() const
+{
+    Node* const focusedFieldNode = document()->focusedNode();
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (m_fields[fieldIndex] == focusedFieldNode)
+            return fieldIndex;
+    }
+    return invalidFieldIndex;
+}
+
+void DateTimeEditElement::fieldValueChanged()
+{
+    if (m_editControlOwner)
+        m_editControlOwner->editControlValueChanged();
+}
+
+bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex)
+{
+    for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) {
+        if (m_fields[fieldIndex]->isFocusable()) {
+            m_fields[fieldIndex]->focus();
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field)
+{
+    const size_t startFieldIndex = fieldIndexOf(field);
+    if (startFieldIndex == invalidFieldIndex)
+        return false;
+    return focusOnNextFocusableField(startFieldIndex + 1);
+}
+
+bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field)
+{
+    const size_t startFieldIndex = fieldIndexOf(field);
+    if (startFieldIndex == invalidFieldIndex)
+        return false;
+    size_t fieldIndex = startFieldIndex;
+    while (fieldIndex > 0) {
+        --fieldIndex;
+        if (m_fields[fieldIndex]->isFocusable()) {
+            m_fields[fieldIndex]->focus();
+            return true;
+        }
+    }
+    return false;
+}
+
+bool DateTimeEditElement::isDisabled() const
+{
+    return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled();
+}
+
+bool DateTimeEditElement::isFieldOwnerDisabled() const
+{
+    return isDisabled();
+}
+
+bool DateTimeEditElement::isFieldOwnerReadOnly() const
+{
+    return isReadOnly();
+}
+
+bool DateTimeEditElement::isReadOnly() const
+{
+    return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly();
+}
+
+void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue)
+{
+    DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral));
+    if (!firstChild()) {
+        RefPtr<HTMLDivElement> element = HTMLDivElement::create(document());
+        element->setPseudo(fieldsWrapperPseudoId);
+        appendChild(element.get());
+    }
+    Element* fieldsWrapper = fieldsWrapperElement();
+
+    size_t focusedFieldIndex = this->focusedFieldIndex();
+    DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex);
+    const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom;
+
+    DateTimeEditBuilder builder(*this, layoutParameters, dateValue);
+    Node* lastChildToBeRemoved = fieldsWrapper->lastChild();
+    if (!builder.build(layoutParameters.dateTimeFormat) || m_fields.isEmpty()) {
+        lastChildToBeRemoved = fieldsWrapper->lastChild();
+        builder.build(layoutParameters.fallbackDateTimeFormat);
+    }
+
+    if (focusedFieldIndex != invalidFieldIndex) {
+        for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
+            if (m_fields[fieldIndex]->shadowPseudoId() == focusedFieldId) {
+                focusedFieldIndex = fieldIndex;
+                break;
+            }
+        }
+        if (DateTimeFieldElement* field = fieldAt(std::min(focusedFieldIndex, m_fields.size() - 1)))
+            field->focus();
+    }
+
+    if (lastChildToBeRemoved) {
+        for (Node* childNode = fieldsWrapper->firstChild(); childNode; childNode = fieldsWrapper->firstChild()) {
+            fieldsWrapper->removeChild(childNode);
+            if (childNode == lastChildToBeRemoved)
+                break;
+        }
+        setNeedsStyleRecalc();
+    }
+}
+
+AtomicString DateTimeEditElement::localeIdentifier() const
+{
+    return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom;
+}
+
+void DateTimeEditElement::readOnlyStateChanged()
+{
+    updateUIState();
+}
+
+void DateTimeEditElement::resetFields()
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->removeEventHandler();
+    m_fields.shrink(0);
+}
+
+void DateTimeEditElement::defaultEventHandler(Event* event)
+{
+    // In case of control owner forward event to control, e.g. DOM
+    // dispatchEvent method.
+    if (DateTimeFieldElement* field = focusedField()) {
+        field->defaultEventHandler(event);
+        if (event->defaultHandled())
+            return;
+    }
+
+    HTMLDivElement::defaultEventHandler(event);
+}
+
+void DateTimeEditElement::setValueAsDate(const LayoutParameters& layoutParameters, const DateComponents& date)
+{
+    layout(layoutParameters, date);
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->setValueAsDate(date);
+}
+
+void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
+{
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState);
+}
+
+void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters, const DateComponents& dateForReadOnlyField)
+{
+    layout(layoutParameters, dateForReadOnlyField);
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->setEmptyValue(DateTimeFieldElement::DispatchNoEvent);
+}
+
+bool DateTimeEditElement::hasFocusedField()
+{
+    return focusedFieldIndex() != invalidFieldIndex;
+}
+
+void DateTimeEditElement::setOnlyYearMonthDay(const DateComponents& date)
+{
+    ASSERT(date.type() == DateComponents::Date);
+
+    if (!m_editControlOwner)
+        return;
+
+    DateTimeFieldsState dateTimeFieldsState = valueAsDateTimeFieldsState();
+    dateTimeFieldsState.setYear(date.fullYear());
+    dateTimeFieldsState.setMonth(date.month() + 1);
+    dateTimeFieldsState.setDayOfMonth(date.monthDay());
+    setValueAsDateTimeFieldsState(dateTimeFieldsState);
+    m_editControlOwner->editControlValueChanged();
+}
+
+void DateTimeEditElement::stepDown()
+{
+    if (DateTimeFieldElement* const field = focusedField())
+        field->stepDown();
+}
+
+void DateTimeEditElement::stepUp()
+{
+    if (DateTimeFieldElement* const field = focusedField())
+        field->stepUp();
+}
+
+void DateTimeEditElement::updateUIState()
+{
+    if (isDisabled()) {
+        if (DateTimeFieldElement* field = focusedField())
+            field->blur();
+    }
+}
+
+String DateTimeEditElement::value() const
+{
+    if (!m_editControlOwner)
+        return emptyString();
+    return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState());
+}
+
+DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const
+{
+    DateTimeFieldsState dateTimeFieldsState;
+    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
+        m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState);
+    return dateTimeFieldsState;
+}
+
+} // namespace WebCore
+
+#endif