Add a calendar picker indicator to date-type input fields
https://bugs.webkit.org/show_bug.cgi?id=80478

Reviewed by Hajime Morita.

Source/WebCore:

Add an indicator to date-type controls. The bahevior change is enclosed
with ENABLE_CALENDAR_PICKER.

- Remove spin buttons from date-type controls.
It's not so helpful if we have a calendar picker. We introduce
TextFieldInputType::shouldHaveSpinButton().

- Add CalendarPickerElement.
This is added into a shadow tree of a date-type control. It uses
RenderDetailsMarker.

We're going to add click handler and so on to CalendarPickerElement.

Test: fast/forms/date/date-appearance.html

* WebCore.gypi: Add CalendarPickerElement.{cpp,h}
* css/html.css:
(input::-webkit-calendar-picker-indicator):
* html/DateInputType.cpp:
(WebCore::DateInputType::createShadowSubtree): Insert CalendarPickerElement.
(WebCore::DateInputType::needsContainer):
Alwyas return true because we have an extra decoration element.
(WebCore::DateInputType::shouldHaveSpinButton):
Always return false to disable spin button.
* html/DateInputType.h:
(DateInputType): Add declarations.
* html/TextFieldInputType.cpp:
(WebCore::TextFieldInputType::shouldHaveSpinButton):
(WebCore::TextFieldInputType::createShadowSubtree): Move some code to shouldHaveSpinButton().
* html/TextFieldInputType.h:
(TextFieldInputType): Add a declartion.
* html/shadow/CalendarPickerElement.cpp:
(WebCore::CalendarPickerElement::CalendarPickerElement):
(WebCore::CalendarPickerElement::create):
(WebCore::CalendarPickerElement::createRenderer): Creates RenderDetailsMarker.
* html/shadow/CalendarPickerElement.h: Added.
* rendering/RenderDetailsMarker.cpp:
(WebCore::RenderDetailsMarker::isOpen): Always show a down arrow if this is in <input>.
* rendering/RenderDetailsMarker.h:

Source/WebKit/chromium:

* features.gypi: Enable CALENDAR_PICKER for non-Android platforms. This
doesn't affect any bahevior because INPUT_TYPE_DATE is disabled.

LayoutTests:

* fast/forms/date/date-appearance.html: Added.
* platform/chromium-mac-snowleopard/fast/forms/date/date-appearance-expected.png: Added.
* platform/chromium-mac-snowleopard/fast/forms/date/date-appearance-expected.txt: Added.

git-svn-id: svn://svn.chromium.org/blink/trunk@112839 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 41434a8..3cb73cf 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,50 @@
+2012-04-02  Kent Tamura  <tkent@chromium.org>
+
+        Add a calendar picker indicator to date-type input fields
+        https://bugs.webkit.org/show_bug.cgi?id=80478
+
+        Reviewed by Hajime Morita.
+
+        Add an indicator to date-type controls. The bahevior change is enclosed
+        with ENABLE_CALENDAR_PICKER.
+
+        - Remove spin buttons from date-type controls.
+        It's not so helpful if we have a calendar picker. We introduce
+        TextFieldInputType::shouldHaveSpinButton().
+
+        - Add CalendarPickerElement.
+        This is added into a shadow tree of a date-type control. It uses
+        RenderDetailsMarker.
+
+        We're going to add click handler and so on to CalendarPickerElement.
+
+        Test: fast/forms/date/date-appearance.html
+
+        * WebCore.gypi: Add CalendarPickerElement.{cpp,h}
+        * css/html.css:
+        (input::-webkit-calendar-picker-indicator):
+        * html/DateInputType.cpp:
+        (WebCore::DateInputType::createShadowSubtree): Insert CalendarPickerElement.
+        (WebCore::DateInputType::needsContainer):
+        Alwyas return true because we have an extra decoration element.
+        (WebCore::DateInputType::shouldHaveSpinButton):
+        Always return false to disable spin button.
+        * html/DateInputType.h:
+        (DateInputType): Add declarations.
+        * html/TextFieldInputType.cpp:
+        (WebCore::TextFieldInputType::shouldHaveSpinButton):
+        (WebCore::TextFieldInputType::createShadowSubtree): Move some code to shouldHaveSpinButton().
+        * html/TextFieldInputType.h:
+        (TextFieldInputType): Add a declartion.
+        * html/shadow/CalendarPickerElement.cpp:
+        (WebCore::CalendarPickerElement::CalendarPickerElement):
+        (WebCore::CalendarPickerElement::create):
+        (WebCore::CalendarPickerElement::createRenderer): Creates RenderDetailsMarker.
+        * html/shadow/CalendarPickerElement.h: Added.
+        * rendering/RenderDetailsMarker.cpp:
+        (WebCore::RenderDetailsMarker::isOpen): Always show a down arrow if this is in <input>.
+        * rendering/RenderDetailsMarker.h:
+
 2012-04-02  Andrey Kosyakov  <caseq@chromium.org>
 
         Web Inspector: make timeline overview a view
diff --git a/Source/WebCore/WebCore.gypi b/Source/WebCore/WebCore.gypi
index 8a6f791..17ea551 100644
--- a/Source/WebCore/WebCore.gypi
+++ b/Source/WebCore/WebCore.gypi
@@ -5697,6 +5697,8 @@
             'html/parser/TextViewSourceParser.h',
             'html/parser/XSSAuditor.cpp',
             'html/parser/XSSAuditor.h',
+            'html/shadow/CalendarPickerElement.cpp',
+            'html/shadow/CalendarPickerElement.h',
             'html/shadow/ContentSelectorQuery.cpp',
             'html/shadow/ContentSelectorQuery.h',
             'html/shadow/DetailsMarkerControl.cpp',
diff --git a/Source/WebCore/css/html.css b/Source/WebCore/css/html.css
index c107bd8..212bd7a 100644
--- a/Source/WebCore/css/html.css
+++ b/Source/WebCore/css/html.css
@@ -668,6 +668,15 @@
 
 #endif // defined(ENABLE_INPUT_TYPE_COLOR) && ENABLE_INPUT_TYPE_COLOR
 
+#if defined(ENABLE_CALENDAR_PICKER) && ENABLE_CALENDAR_PICKER
+input::-webkit-calendar-picker-indicator {
+    display: inline-block;
+    width: 0.66em;
+    height: 0.66em;
+    -webkit-margin-end: 0.2em;
+}
+#endif // ENABLE_CALENDAR_PICKER
+
 select {
     -webkit-appearance: menulist;
     -webkit-box-sizing: border-box;
diff --git a/Source/WebCore/html/DateInputType.cpp b/Source/WebCore/html/DateInputType.cpp
index 7b83e3d..24bdd8b 100644
--- a/Source/WebCore/html/DateInputType.cpp
+++ b/Source/WebCore/html/DateInputType.cpp
@@ -31,6 +31,7 @@
 #include "config.h"
 #include "DateInputType.h"
 
+#include "CalendarPickerElement.h"
 #include "DateComponents.h"
 #include "HTMLInputElement.h"
 #include "HTMLNames.h"
@@ -98,6 +99,24 @@
     return date->setMillisecondsSinceEpochForDate(value);
 }
 
+#if ENABLE(CALENDAR_PICKER)
+void DateInputType::createShadowSubtree()
+{
+    BaseDateAndTimeInputType::createShadowSubtree();
+    containerElement()->insertBefore(CalendarPickerElement::create(element()->document()), innerBlockElement()->nextSibling(), ASSERT_NO_EXCEPTION);
+}
+
+bool DateInputType::needsContainer() const
+{
+    return true;
+}
+
+bool DateInputType::shouldHaveSpinButton() const
+{
+    return false;
+}
+#endif // ENABLE(CALENDAR_PICKER)
+
 } // namespace WebCore
 
 #endif
diff --git a/Source/WebCore/html/DateInputType.h b/Source/WebCore/html/DateInputType.h
index afb1895..f020e2e 100644
--- a/Source/WebCore/html/DateInputType.h
+++ b/Source/WebCore/html/DateInputType.h
@@ -52,6 +52,13 @@
     virtual bool parsedStepValueShouldBeInteger() const OVERRIDE;
     virtual bool parseToDateComponentsInternal(const UChar*, unsigned length, DateComponents*) const OVERRIDE;
     virtual bool setMillisecondToDateComponents(double, DateComponents*) const OVERRIDE;
+#if ENABLE(CALENDAR_PICKER)
+    virtual void createShadowSubtree() OVERRIDE;
+
+    // TextFieldInputType functions
+    virtual bool needsContainer() const OVERRIDE;
+    virtual bool shouldHaveSpinButton() const OVERRIDE;
+#endif
 };
 
 } // namespace WebCore
diff --git a/Source/WebCore/html/TextFieldInputType.cpp b/Source/WebCore/html/TextFieldInputType.cpp
index 5c30466..5e4962b 100644
--- a/Source/WebCore/html/TextFieldInputType.cpp
+++ b/Source/WebCore/html/TextFieldInputType.cpp
@@ -212,6 +212,13 @@
 #endif
 }
 
+bool TextFieldInputType::shouldHaveSpinButton() const
+{
+    Document* document = element()->document();
+    RefPtr<RenderTheme> theme = document->page() ? document->page()->theme() : RenderTheme::defaultTheme();
+    return theme->shouldHaveSpinButton(element());
+}
+
 void TextFieldInputType::createShadowSubtree()
 {
     ASSERT(element()->hasShadowRoot());
@@ -221,10 +228,9 @@
     ASSERT(!m_innerSpinButton);
 
     Document* document = element()->document();
-    RefPtr<RenderTheme> theme = document->page() ? document->page()->theme() : RenderTheme::defaultTheme();
     ChromeClient* chromeClient = document->page() ? document->page()->chrome()->client() : 0;
-    bool shouldHaveSpinButton = theme->shouldHaveSpinButton(element());
     bool shouldAddDecorations = chromeClient && chromeClient->willAddTextFieldDecorationsTo(element());
+    bool shouldHaveSpinButton = this->shouldHaveSpinButton();
     bool createsContainer = shouldHaveSpinButton || needsContainer() || shouldAddDecorations;
 
     ExceptionCode ec = 0;
diff --git a/Source/WebCore/html/TextFieldInputType.h b/Source/WebCore/html/TextFieldInputType.h
index d26e28a..26b436e 100644
--- a/Source/WebCore/html/TextFieldInputType.h
+++ b/Source/WebCore/html/TextFieldInputType.h
@@ -59,6 +59,7 @@
 
 protected:
     virtual bool needsContainer() const;
+    virtual bool shouldHaveSpinButton() const;
     virtual void createShadowSubtree() OVERRIDE;
     virtual void destroyShadowSubtree() OVERRIDE;
     virtual void disabledAttributeChanged() OVERRIDE;
diff --git a/Source/WebCore/html/shadow/CalendarPickerElement.cpp b/Source/WebCore/html/shadow/CalendarPickerElement.cpp
new file mode 100644
index 0000000..41a3d20
--- /dev/null
+++ b/Source/WebCore/html/shadow/CalendarPickerElement.cpp
@@ -0,0 +1,61 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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"
+#include "CalendarPickerElement.h"
+
+#if ENABLE(CALENDAR_PICKER)
+
+#include "HTMLNames.h"
+#include "RenderDetailsMarker.h"
+
+namespace WebCore {
+
+using namespace HTMLNames;
+
+inline CalendarPickerElement::CalendarPickerElement(Document* document)
+    : HTMLDivElement(divTag, document)
+{
+    setShadowPseudoId("-webkit-calendar-picker-indicator");
+}
+
+PassRefPtr<CalendarPickerElement> CalendarPickerElement::create(Document* document)
+{
+    return adoptRef(new CalendarPickerElement(document));
+}
+
+RenderObject* CalendarPickerElement::createRenderer(RenderArena* arena, RenderStyle*)
+{
+    return new (arena) RenderDetailsMarker(this);
+}
+
+}
+
+#endif
diff --git a/Source/WebCore/html/shadow/CalendarPickerElement.h b/Source/WebCore/html/shadow/CalendarPickerElement.h
new file mode 100644
index 0000000..51c9b8f
--- /dev/null
+++ b/Source/WebCore/html/shadow/CalendarPickerElement.h
@@ -0,0 +1,49 @@
+/*
+ * 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:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * 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.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER OR 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.
+ */
+
+#ifndef CalendarPickerElement_h
+#define CalendarPickerElement_h
+
+#include "HTMLDivElement.h"
+
+namespace WebCore {
+
+class CalendarPickerElement : public HTMLDivElement {
+public:
+    static PassRefPtr<CalendarPickerElement> create(Document*);
+
+private:
+    CalendarPickerElement(Document*);
+    virtual RenderObject* createRenderer(RenderArena*, RenderStyle*) OVERRIDE;
+    // FIXME: add click handling.
+};
+
+}
+#endif
diff --git a/Source/WebCore/rendering/RenderDetailsMarker.cpp b/Source/WebCore/rendering/RenderDetailsMarker.cpp
index bcffaac..da7e235 100644
--- a/Source/WebCore/rendering/RenderDetailsMarker.cpp
+++ b/Source/WebCore/rendering/RenderDetailsMarker.cpp
@@ -21,7 +21,7 @@
 #include "config.h"
 #include "RenderDetailsMarker.h"
 
-#if ENABLE(DETAILS)
+#if ENABLE(DETAILS) || ENABLE(CALENDAR_PICKER)
 
 #include "Element.h"
 #include "GraphicsContext.h"
@@ -140,8 +140,12 @@
 bool RenderDetailsMarker::isOpen() const
 {
     for (RenderObject* renderer = parent(); renderer; renderer = renderer->parent()) {
-        if (renderer->node() && renderer->node()->hasTagName(detailsTag))
+        if (!renderer->node())
+            continue;
+        if (renderer->node()->hasTagName(detailsTag))
             return !toElement(renderer->node())->getAttribute(openAttr).isNull();
+        if (renderer->node()->hasTagName(inputTag))
+            return true;
     }
 
     return false;
diff --git a/Source/WebCore/rendering/RenderDetailsMarker.h b/Source/WebCore/rendering/RenderDetailsMarker.h
index 3afac55..1be4e85 100644
--- a/Source/WebCore/rendering/RenderDetailsMarker.h
+++ b/Source/WebCore/rendering/RenderDetailsMarker.h
@@ -21,7 +21,7 @@
 #ifndef RenderDetailsMarker_h
 #define RenderDetailsMarker_h
 
-#if ENABLE(DETAILS)
+#if ENABLE(DETAILS) || ENABLE(CALENDAR_PICKER)
 
 #include "RenderBlock.h"