Home | History | Annotate | Download | only in shadow
      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 
     45 namespace blink {
     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 (!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 
    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 blink
    816 
    817 #endif
    818