Bug 825294 - Add framework for datepicker widgets to input[type=date]. r=smaug
authorJordan <jordandev678@gmail.com>
Mon, 20 Jun 2016 15:55:00 +0200
changeset 327272 14ac8b409bcd40985ef2abe2ee63ad3b08ab7c69
parent 327271 1c11f8a655264ade01742bc0970fab9396c31a7e
child 327273 6a5167669bd2e88fd0eeb6f1232dbe2838c22c49
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs825294
milestone50.0a1
Bug 825294 - Add framework for datepicker widgets to input[type=date]. r=smaug -Add framework for datepicker widgets -Split date input preference from dom.experimental_forms to dom.forms.date
dom/html/HTMLInputElement.cpp
dom/html/HTMLInputElement.h
dom/html/test/forms/test_experimental_forms_pref.html
dom/html/test/forms/test_valueAsDate_pref.html
dom/ipc/DatePickerParent.cpp
dom/ipc/DatePickerParent.h
dom/ipc/PBrowser.ipdl
dom/ipc/PDatePicker.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/ipc/moz.build
dom/locales/en-US/chrome/layout/HtmlForm.properties
dom/webidl/HTMLInputElement.webidl
widget/moz.build
widget/nsContentProcessWidgetFactory.cpp
widget/nsDatePickerProxy.cpp
widget/nsDatePickerProxy.h
widget/nsIDatePicker.idl
widget/nsWidgetsCID.h
--- a/dom/html/HTMLInputElement.cpp
+++ b/dom/html/HTMLInputElement.cpp
@@ -107,22 +107,25 @@
 #include "mozilla/Preferences.h"
 #include "mozilla/MathAlgorithms.h"
 
 #include "nsIIDNService.h"
 
 #include <limits>
 
 #include "nsIColorPicker.h"
+#include "nsIDatePicker.h"
 #include "nsIStringEnumerator.h"
 #include "HTMLSplitOnSpacesTokenizer.h"
 #include "nsIController.h"
 #include "nsIMIMEInfo.h"
 #include "nsFrameSelection.h"
 
+#include "nsIConsoleService.h"
+
 // input type=date
 #include "js/Date.h"
 
 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Input)
 
 // XXX align=left, hspace, vspace, border? other nav4 attrs
 
 static NS_DEFINE_CID(kXULControllersCID,  NS_XULCONTROLLERS_CID);
@@ -933,16 +936,23 @@ GetDOMFileOrDirectoryPath(const OwningFi
   } else {
     MOZ_ASSERT(aData.IsDirectory());
     aData.GetAsDirectory()->GetFullRealPath(aPath);
   }
 }
 
 } // namespace
 
+/* static */
+bool
+HTMLInputElement::ValueAsDateEnabled(JSContext* cx, JSObject* obj)
+{
+  return Preferences::GetBool("dom.experimental_forms", false) ||
+    Preferences::GetBool("dom.forms.datepicker", false);
+}
 
 NS_IMETHODIMP
 HTMLInputElement::nsFilePickerShownCallback::Done(int16_t aResult)
 {
   mInput->PickerClosed();
 
   if (aResult == nsIFilePicker::returnCancel) {
     return NS_OK;
@@ -1136,16 +1146,69 @@ nsColorPickerShownCallback::Done(const n
                                               false);
   }
 
   return rv;
 }
 
 NS_IMPL_ISUPPORTS(nsColorPickerShownCallback, nsIColorPickerShownCallback)
 
+class DatePickerShownCallback final : public nsIDatePickerShownCallback
+{
+  ~DatePickerShownCallback() {}
+public:
+  DatePickerShownCallback(HTMLInputElement* aInput,
+                          nsIDatePicker* aDatePicker)
+    : mInput(aInput)
+    , mDatePicker(aDatePicker)
+  {}
+
+  NS_DECL_ISUPPORTS
+
+  NS_IMETHOD Done(const nsAString& aDate) override;
+  NS_IMETHOD Cancel() override;
+
+private:
+  RefPtr<HTMLInputElement> mInput;
+  nsCOMPtr<nsIDatePicker> mDatePicker;
+};
+
+NS_IMETHODIMP
+DatePickerShownCallback::Cancel()
+{
+  mInput->PickerClosed();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DatePickerShownCallback::Done(const nsAString& aDate)
+{
+  nsAutoString oldValue;
+
+  mInput->PickerClosed();
+  mInput->GetValue(oldValue);
+
+  if(!oldValue.Equals(aDate)){
+    mInput->SetValue(aDate);
+    nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
+                            static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
+                            NS_LITERAL_STRING("input"), true,
+                            false);
+    return nsContentUtils::DispatchTrustedEvent(mInput->OwnerDoc(),
+                            static_cast<nsIDOMHTMLInputElement*>(mInput.get()),
+                            NS_LITERAL_STRING("change"), true,
+                            false);
+  }
+
+  return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(DatePickerShownCallback, nsIDatePickerShownCallback)
+
+
 bool
 HTMLInputElement::IsPopupBlocked() const
 {
   nsCOMPtr<nsPIDOMWindowOuter> win = OwnerDoc()->GetWindow();
   MOZ_ASSERT(win, "window should not be null");
   if (!win) {
     return true;
   }
@@ -1161,16 +1224,66 @@ HTMLInputElement::IsPopupBlocked() const
   }
 
   uint32_t permission;
   pm->TestPermission(OwnerDoc()->NodePrincipal(), &permission);
   return permission == nsIPopupWindowManager::DENY_POPUP;
 }
 
 nsresult
+HTMLInputElement::InitDatePicker()
+{
+  if (!Preferences::GetBool("dom.forms.datepicker", false)) {
+    return NS_OK;
+  }
+
+  if (mPickerRunning) {
+    NS_WARNING("Just one nsIDatePicker is allowed");
+    return NS_ERROR_FAILURE;
+  }
+
+  nsCOMPtr<nsIDocument> doc = OwnerDoc();
+
+  nsCOMPtr<nsPIDOMWindowOuter> win = doc->GetWindow();
+  if (!win) {
+    return NS_ERROR_FAILURE;
+  }
+
+  if (IsPopupBlocked()) {
+    win->FirePopupBlockedEvent(doc, nullptr, EmptyString(), EmptyString());
+    return NS_OK;
+  }
+
+  // Get Loc title
+  nsXPIDLString title;
+  nsContentUtils::GetLocalizedString(nsContentUtils::eFORMS_PROPERTIES,
+                                     "DatePicker", title);
+
+  nsresult rv;
+  nsCOMPtr<nsIDatePicker> datePicker = do_CreateInstance("@mozilla.org/datepicker;1", &rv);
+  if (!datePicker) {
+    return rv;
+  }
+
+  nsAutoString initialValue;
+  GetValueInternal(initialValue);
+  rv = datePicker->Init(win, title, initialValue);
+
+  nsCOMPtr<nsIDatePickerShownCallback> callback =
+    new DatePickerShownCallback(this, datePicker);
+
+  rv = datePicker->Open(callback);
+  if (NS_SUCCEEDED(rv)) {
+    mPickerRunning = true;
+  }
+
+  return rv;
+}
+
+nsresult
 HTMLInputElement::InitColorPicker()
 {
   if (mPickerRunning) {
     NS_WARNING("Just one nsIColorPicker is allowed");
     return NS_ERROR_FAILURE;
   }
 
   nsCOMPtr<nsIDocument> doc = OwnerDoc();
@@ -2015,17 +2128,18 @@ NS_IMETHODIMP
 HTMLInputElement::GetValue(nsAString& aValue)
 {
   nsresult rv = GetValueInternal(aValue);
   if (NS_FAILED(rv)) {
     return rv;
   }
 
   // Don't return non-sanitized value for types that are experimental on mobile.
-  if (IsExperimentalMobileType(mType)) {
+  //  or date types
+  if (IsExperimentalMobileType(mType) || mType == NS_FORM_INPUT_DATE) {
     SanitizeValue(aValue);
   }
 
   return NS_OK;
 }
 
 nsresult
 HTMLInputElement::GetValueInternal(nsAString& aValue) const
@@ -2649,16 +2763,25 @@ HTMLInputElement::ApplyStep(int32_t aSte
 
   if (NS_SUCCEEDED(rv) && nextStep.isFinite()) {
     SetValue(nextStep);
   }
 
   return rv;
 }
 
+/* static */
+bool
+HTMLInputElement::IsExperimentalMobileType(uint8_t aType)
+{
+  return aType == NS_FORM_INPUT_TIME ||
+    (aType == NS_FORM_INPUT_DATE &&
+     !Preferences::GetBool("dom.forms.datepicker", false));
+}
+
 NS_IMETHODIMP
 HTMLInputElement::StepDown(int32_t n, uint8_t optional_argc)
 {
   return ApplyStep(optional_argc ? -n : -1);
 }
 
 NS_IMETHODIMP
 HTMLInputElement::StepUp(int32_t n, uint8_t optional_argc)
@@ -2838,17 +2961,17 @@ HTMLInputElement::MozSetDirectory(const 
 
   SetFilesOrDirectories(array, true);
 }
 
 bool
 HTMLInputElement::MozIsTextField(bool aExcludePassword)
 {
   // TODO: temporary until bug 773205 is fixed.
-  if (IsExperimentalMobileType(mType)) {
+  if (IsExperimentalMobileType(mType) || mType == NS_FORM_INPUT_DATE) {
     return false;
   }
 
   return IsSingleLineTextControl(aExcludePassword);
 }
 
 HTMLInputElement*
 HTMLInputElement::GetOwnerNumberControl()
@@ -3870,17 +3993,17 @@ HTMLInputElement::PreHandleEvent(EventCh
     GetValue(mFocusedValue);
   }
 
   // Fire onchange (if necessary), before we do the blur, bug 357684.
   if (aVisitor.mEvent->mMessage == eBlur) {
     // Experimental mobile types rely on the system UI to prevent users to not
     // set invalid values but we have to be extra-careful. Especially if the
     // option has been enabled on desktop.
-    if (IsExperimentalMobileType(mType)) {
+    if (IsExperimentalMobileType(mType) || mType == NS_FORM_INPUT_DATE) {
       nsAutoString aValue;
       GetValueInternal(aValue);
       nsresult rv =
         SetValueInternal(aValue, nsTextEditorState::eSetValue_Internal);
       NS_ENSURE_SUCCESS(rv, rv);
     }
     FireChangeEventIfNeeded();
   }
@@ -4286,16 +4409,20 @@ HTMLInputElement::MaybeInitPickers(Event
                  "be reached");
       type = FILE_PICKER_DIRECTORY;
     }
     return InitFilePicker(type);
   }
   if (mType == NS_FORM_INPUT_COLOR) {
     return InitColorPicker();
   }
+  if (mType == NS_FORM_INPUT_DATE) {
+    return InitDatePicker();
+  }
+
   return NS_OK;
 }
 
 nsresult
 HTMLInputElement::PostHandleEvent(EventChainPostVisitor& aVisitor)
 {
   if (!aVisitor.mPresContext) {
     // Hack alert! In order to open file picker even in case the element isn't
@@ -4567,17 +4694,18 @@ HTMLInputElement::PostHandleEvent(EventC
            * (c) if there is more than one text input and no submit buttons, do
            *     not submit, period.
            */
 
           if (aVisitor.mEvent->mMessage == eKeyPress &&
               keyEvent->mKeyCode == NS_VK_RETURN &&
                (IsSingleLineTextControl(false, mType) ||
                 mType == NS_FORM_INPUT_NUMBER ||
-                IsExperimentalMobileType(mType))) {
+                IsExperimentalMobileType(mType) ||
+                mType == NS_FORM_INPUT_DATE)) {
             FireChangeEventIfNeeded();
             rv = MaybeSubmitForm(aVisitor.mPresContext);
             NS_ENSURE_SUCCESS(rv, rv);
           }
 
           if (aVisitor.mEvent->mMessage == eKeyPress &&
               mType == NS_FORM_INPUT_RANGE && !keyEvent->IsAlt() &&
               !keyEvent->IsControl() && !keyEvent->IsMeta() &&
--- a/dom/html/HTMLInputElement.h
+++ b/dom/html/HTMLInputElement.h
@@ -265,16 +265,19 @@ public:
                                            nsGenericHTMLFormElementWithState)
 
   static UploadLastDir* gUploadLastDir;
   // create and destroy the static UploadLastDir object for remembering
   // which directory was last used on a site-by-site basis
   static void InitUploadLastDir();
   static void DestroyUploadLastDir();
 
+  //If the valueAsDate attribute should be enabled in webIDL
+  static bool ValueAsDateEnabled(JSContext* cx, JSObject* obj);
+
   void MaybeLoadImage();
 
   void SetSelectionProperties(const nsTextEditorState::SelectionProperties& aProps)
   {
     MOZ_ASSERT(mType == NS_FORM_INPUT_NUMBER);
     mSelectionCached = true;
     mSelectionProperties = aProps;
   }
@@ -1241,20 +1244,17 @@ protected:
    *
    * @param aStep The value used to be multiplied against the step value.
    */
   nsresult ApplyStep(int32_t aStep);
 
   /**
    * Returns if the current type is an experimental mobile type.
    */
-  static bool IsExperimentalMobileType(uint8_t aType)
-  {
-    return aType == NS_FORM_INPUT_DATE || aType == NS_FORM_INPUT_TIME;
-  }
+  static bool IsExperimentalMobileType(uint8_t aType);
 
   /**
    * Flushes the layout frame tree to make sure we have up-to-date frames.
    */
   void FlushFrames();
 
   /**
    * Returns true if the element should prevent dispatching another DOMActivate.
@@ -1271,16 +1271,17 @@ protected:
   nsresult MaybeInitPickers(EventChainPostVisitor& aVisitor);
 
   enum FilePickerType {
     FILE_PICKER_FILE,
     FILE_PICKER_DIRECTORY
   };
   nsresult InitFilePicker(FilePickerType aType);
   nsresult InitColorPicker();
+  nsresult InitDatePicker();
 
   /**
    * Use this function before trying to open a picker.
    * It checks if the page is allowed to open a new pop-up.
    * If it returns true, you should not create the picker.
    *
    * @return true if popup should be blocked, false otherwise
    */
--- a/dom/html/test/forms/test_experimental_forms_pref.html
+++ b/dom/html/test/forms/test_experimental_forms_pref.html
@@ -15,29 +15,37 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none" >
 </div>
 <pre id="test">
 <script type="application/javascript">
 
   var input = document.createElement("input");
 
   SimpleTest.waitForExplicitFinish();
-  SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", false]]}, function() {
+  SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms", false], ["dom.forms.datepicker",false]]}, function() {
     input.type = "date";
     is(input.type, "text", "input type shouldn't be date when the experimental forms are disabled");
     is(input.getAttribute('type'), "date", "input 'type' attribute should not change");
 
-    SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms",true]]}, function() {
-      // Change the type of input to text and then back to date, 
+    SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms",true], ["dom.forms.datepicker",false]]}, function() {
+      // Change the type of input to text and then back to date,
       // so that HTMLInputElement::ParseAttribute gets called with the pref enabled.
       input.type = "text";
       input.type = "date";
       is(input.type, "date", "input type should be date when the experimental forms are enabled");
       is(input.getAttribute('type'), "date", "input 'type' attribute should not change");
-    
-      SimpleTest.finish();
+
+      SpecialPowers.pushPrefEnv({'set': [["dom.experimental_forms",false], ["dom.forms.datepicker",true]]}, function() {
+        // Change the type of input to text and then back to date,
+        // so that HTMLInputElement::ParseAttribute gets called with the pref enabled.
+        input.type = "text";
+        input.type = "date";
+        is(input.type, "date", "input type should be date when the datepicker is enabled");
+        is(input.getAttribute('type'), "date", "input 'type' attribute should not change");
+
+        SimpleTest.finish();
+      });
     });
   });
-
 </script>
 </pre>
 </body>
 </html>
--- a/dom/html/test/forms/test_valueAsDate_pref.html
+++ b/dom/html/test/forms/test_valueAsDate_pref.html
@@ -6,34 +6,42 @@ https://bugzilla.mozilla.org/show_bug.cg
 <head>
   <meta charset="utf-8">
   <title>Test for Bug 874640</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
   <script type="application/javascript">
 
   /** Test for Bug 874640 **/
-  var states = [ 'true', 'false', 'end' ];
-  var pref = SpecialPowers.getBoolPref("dom.experimental_forms");
+  var states = [
+        //dom.experimental_forms, dom.forms.datepicker, expectedValueAsDate
+	[ 'true', 'true', 'true' ],
+	[ 'true', 'false', 'true' ],
+	[ 'false', 'true', 'true' ],
+	[ 'false', 'false', 'false' ],
+        'end'
+  ];
 
   SimpleTest.waitForExplicitFinish();
 
   function runTest(iframe) {
     var state = states.shift();
 
     if (state == 'end') {
       SimpleTest.finish();
       return;
     }
 
-    SpecialPowers.pushPrefEnv({"set":[["dom.experimental_forms", state === 'true']]}, 
+    SpecialPowers.pushPrefEnv({"set":[
+      ["dom.experimental_forms", state[0] === 'true'],
+      ["dom.forms.datepicker", state[1] === 'true']]},
       function() {
         iframe.src = 'data:text/html,<script>' +
                  'parent.is("valueAsDate" in document.createElement("input"), ' +
-                 state + ', "valueAsDate presence state should be ' + state + '");' +
+                 state[2] + ', "valueAsDate presence state should be ' + state[2] + '");' +
                  '<\/script>'
      });
   }
 
   </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=874640">Mozilla Bug 874640</a>
new file mode 100644
--- /dev/null
+++ b/dom/ipc/DatePickerParent.cpp
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "DatePickerParent.h"
+#include "nsComponentManagerUtils.h"
+#include "nsIDocument.h"
+#include "nsIDOMWindow.h"
+#include "mozilla/unused.h"
+#include "mozilla/dom/Element.h"
+#include "mozilla/dom/TabParent.h"
+
+using mozilla::Unused;
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS(DatePickerParent::DatePickerShownCallback,
+                  nsIDatePickerShownCallback);
+
+NS_IMETHODIMP
+DatePickerParent::DatePickerShownCallback::Cancel()
+{
+  if (mDatePickerParent) {
+    Unused << mDatePickerParent->SendCancel();
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+DatePickerParent::DatePickerShownCallback::Done(const nsAString& aDate)
+{
+  if (mDatePickerParent) {
+    Unused << mDatePickerParent->Send__delete__(mDatePickerParent,
+                                                nsString(aDate));
+  }
+  return NS_OK;
+}
+
+void
+DatePickerParent::DatePickerShownCallback::Destroy()
+{
+  mDatePickerParent = nullptr;
+}
+
+bool
+DatePickerParent::CreateDatePicker()
+{
+  mPicker = do_CreateInstance("@mozilla.org/datepicker;1");
+  if (!mPicker) {
+    return false;
+  }
+
+  Element* ownerElement = TabParent::GetFrom(Manager())->GetOwnerElement();
+  if (!ownerElement) {
+    return false;
+  }
+
+  nsCOMPtr<mozIDOMWindowProxy> window = do_QueryInterface(ownerElement->OwnerDoc()->GetWindow());
+  if (!window) {
+    return false;
+  }
+
+  return NS_SUCCEEDED(mPicker->Init(window, mTitle, mInitialDate));
+}
+
+bool
+DatePickerParent::RecvOpen()
+{
+  if (!CreateDatePicker()) {
+    Unused << Send__delete__(this, mInitialDate);
+    return true;
+  }
+
+  mCallback = new DatePickerShownCallback(this);
+
+  mPicker->Open(mCallback);
+  return true;
+};
+
+void
+DatePickerParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  if (mCallback) {
+    mCallback->Destroy();
+  }
+}
new file mode 100644
--- /dev/null
+++ b/dom/ipc/DatePickerParent.h
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef mozilla_dom_DatePickerParent_h
+#define mozilla_dom_DatePickerParent_h
+
+#include "mozilla/dom/PDatePickerParent.h"
+#include "nsIDatePicker.h"
+
+namespace mozilla {
+namespace dom {
+
+class DatePickerParent : public PDatePickerParent
+{
+ public:
+  DatePickerParent(const nsString& aTitle,
+                   const nsString& aInitialDate)
+  : mTitle(aTitle)
+  , mInitialDate(aInitialDate)
+  {}
+
+  virtual bool RecvOpen() override;
+  virtual void ActorDestroy(ActorDestroyReason aWhy) override;
+
+  class DatePickerShownCallback final
+    : public nsIDatePickerShownCallback
+  {
+  public:
+    explicit DatePickerShownCallback(DatePickerParent* aDatePickerParnet)
+      : mDatePickerParent(aDatePickerParnet)
+    {}
+
+    NS_DECL_ISUPPORTS
+    NS_DECL_NSIDATEPICKERSHOWNCALLBACK
+
+    void Destroy();
+
+  private:
+    ~DatePickerShownCallback() {}
+    DatePickerParent* mDatePickerParent;
+  };
+
+ private:
+  virtual ~DatePickerParent() {}
+
+  bool CreateDatePicker();
+
+  RefPtr<DatePickerShownCallback> mCallback;
+  nsCOMPtr<nsIDatePicker> mPicker;
+
+  nsString mTitle;
+  nsString mInitialDate;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_DatePickerParent_h
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -4,16 +4,17 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 include protocol PBlob;
 include protocol PColorPicker;
 include protocol PContent;
 include protocol PContentBridge;
+include protocol PDatePicker;
 include protocol PDocAccessible;
 include protocol PDocumentRenderer;
 include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
 include protocol PRenderFrame;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include DOMTypes;
@@ -106,16 +107,17 @@ union OptionalShmem
   Shmem;
 };
 
 prio(normal upto urgent) sync protocol PBrowser
 {
     manager PContent or PContentBridge;
 
     manages PColorPicker;
+    manages PDatePicker;
     manages PDocAccessible;
     manages PDocumentRenderer;
     manages PFilePicker;
     manages PIndexedDBPermissionRequest;
     manages PRenderFrame;
     manages PPluginWidget;
 
 both:
@@ -415,16 +417,22 @@ parent:
     async HideTooltip();
 
     /**
      * Create an asynchronous color picker on the parent side,
      * but don't open it yet.
      */
     async PColorPicker(nsString title, nsString initialColor);
 
+    /**
+     * Create an asynchronous date picker on the parent side,
+     * but don't open it yet.
+     */
+    async PDatePicker(nsString title, nsString initialDate);
+
     async PFilePicker(nsString aTitle, int16_t aMode);
 
     /**
      * Initiates an asynchronous request for one of the special indexedDB
      * permissions for the provided principal.
      *
      * @param principal
      *   The principal of the request.
new file mode 100644
--- /dev/null
+++ b/dom/ipc/PDatePicker.ipdl
@@ -0,0 +1,27 @@
+/* -*- Mode: C++; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 8 -*- */
+/* vim: set sw=4 ts=8 et tw=80 ft=cpp : */
+
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+include protocol PBrowser;
+
+namespace mozilla {
+namespace dom {
+
+protocol PDatePicker
+{
+    manager PBrowser;
+
+parent:
+    async Open();
+
+child:
+    async Cancel();
+
+    async __delete__(nsString color);
+};
+
+} // namespace dom
+} // namespace mozilla
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -97,16 +97,17 @@
 #include "ipc/nsGUIEventIPC.h"
 #include "mozilla/gfx/Matrix.h"
 #include "UnitTransforms.h"
 #include "ClientLayerManager.h"
 #include "LayersLogging.h"
 #include "nsIOService.h"
 #include "nsDOMClassInfoID.h"
 #include "nsColorPickerProxy.h"
+#include "nsDatePickerProxy.h"
 #include "nsContentPermissionHelper.h"
 #include "nsPresShell.h"
 #include "nsIAppsService.h"
 #include "nsNetUtil.h"
 #include "nsIPermissionManager.h"
 #include "nsIURILoader.h"
 #include "nsIScriptError.h"
 #include "mozilla/EventForwards.h"
@@ -2279,16 +2280,31 @@ TabChild::AllocPColorPickerChild(const n
 bool
 TabChild::DeallocPColorPickerChild(PColorPickerChild* aColorPicker)
 {
   nsColorPickerProxy* picker = static_cast<nsColorPickerProxy*>(aColorPicker);
   NS_RELEASE(picker);
   return true;
 }
 
+PDatePickerChild*
+TabChild::AllocPDatePickerChild(const nsString&, const nsString&)
+{
+  NS_RUNTIMEABORT("unused");
+  return nullptr;
+}
+
+bool
+TabChild::DeallocPDatePickerChild(PDatePickerChild* aDatePicker)
+{
+  nsDatePickerProxy* picker = static_cast<nsDatePickerProxy*>(aDatePicker);
+  NS_RELEASE(picker);
+  return true;
+}
+
 PFilePickerChild*
 TabChild::AllocPFilePickerChild(const nsString&, const int16_t&)
 {
   NS_RUNTIMEABORT("unused");
   return nullptr;
 }
 
 bool
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -448,16 +448,20 @@ public:
 
 
   virtual PColorPickerChild*
   AllocPColorPickerChild(const nsString& aTitle,
                          const nsString& aInitialColor) override;
 
   virtual bool DeallocPColorPickerChild(PColorPickerChild* aActor) override;
 
+    virtual PDatePickerChild*
+    AllocPDatePickerChild(const nsString& title, const nsString& initialDate) override;
+    virtual bool DeallocPDatePickerChild(PDatePickerChild* actor) override;
+
   virtual PFilePickerChild*
   AllocPFilePickerChild(const nsString& aTitle, const int16_t& aMode) override;
 
   virtual bool
   DeallocPFilePickerChild(PFilePickerChild* aActor) override;
 
   virtual PIndexedDBPermissionRequestChild*
   AllocPIndexedDBPermissionRequestChild(const Principal& aPrincipal) override;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -75,16 +75,17 @@
 #include "nsPresShell.h"
 #include "nsPrintfCString.h"
 #include "nsServiceManagerUtils.h"
 #include "nsThreadUtils.h"
 #include "private/pprio.h"
 #include "PermissionMessageUtils.h"
 #include "StructuredCloneData.h"
 #include "ColorPickerParent.h"
+#include "DatePickerParent.h"
 #include "FilePickerParent.h"
 #include "TabChild.h"
 #include "LoadContext.h"
 #include "nsNetCID.h"
 #include "nsIAuthInformation.h"
 #include "nsIAuthPromptCallback.h"
 #include "nsAuthInformationHolder.h"
 #include "nsICancelable.h"
@@ -2582,16 +2583,30 @@ TabParent::AllocPColorPickerParent(const
 
 bool
 TabParent::DeallocPColorPickerParent(PColorPickerParent* actor)
 {
   delete actor;
   return true;
 }
 
+PDatePickerParent*
+TabParent::AllocPDatePickerParent(const nsString& aTitle,
+                                  const nsString& aInitialDate)
+{
+  return new DatePickerParent(aTitle, aInitialDate);
+}
+
+bool
+TabParent::DeallocPDatePickerParent(PDatePickerParent* actor)
+{
+  delete actor;
+  return true;
+}
+
 PRenderFrameParent*
 TabParent::AllocPRenderFrameParent()
 {
   MOZ_ASSERT(ManagedPRenderFrameParent().IsEmpty());
   RefPtr<nsFrameLoader> frameLoader = GetFrameLoader();
   uint64_t layersId = 0;
   bool success = false;
 
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -374,16 +374,20 @@ public:
 
   virtual PColorPickerParent*
   AllocPColorPickerParent(const nsString& aTitle,
                           const nsString& aInitialColor) override;
 
   virtual bool
   DeallocPColorPickerParent(PColorPickerParent* aColorPicker) override;
 
+  virtual PDatePickerParent*
+  AllocPDatePickerParent(const nsString& aTitle, const nsString& aInitialDate) override;
+  virtual bool DeallocPDatePickerParent(PDatePickerParent* aDatePicker) override;
+
   virtual PDocAccessibleParent*
   AllocPDocAccessibleParent(PDocAccessibleParent*, const uint64_t&) override;
 
   virtual bool DeallocPDocAccessibleParent(PDocAccessibleParent*) override;
 
   virtual bool
   RecvPDocAccessibleConstructor(PDocAccessibleParent* aDoc,
                                 PDocAccessibleParent* aParentDoc,
--- a/dom/ipc/moz.build
+++ b/dom/ipc/moz.build
@@ -56,16 +56,17 @@ UNIFIED_SOURCES += [
     'AppProcessChecker.cpp',
     'ColorPickerParent.cpp',
     'ContentBridgeChild.cpp',
     'ContentBridgeParent.cpp',
     'ContentParent.cpp',
     'ContentProcess.cpp',
     'ContentProcessManager.cpp',
     'CrashReporterParent.cpp',
+    'DatePickerParent.cpp',
     'FilePickerParent.cpp',
     'nsIContentChild.cpp',
     'nsIContentParent.cpp',
     'NuwaChild.cpp',
     'NuwaParent.cpp',
     'PermissionMessageUtils.cpp',
     'PreallocatedProcessManager.cpp',
     'ProcessPriorityManager.cpp',
@@ -97,16 +98,17 @@ IPDL_SOURCES += [
     'PBrowserOrId.ipdlh',
     'PColorPicker.ipdl',
     'PContent.ipdl',
     'PContentBridge.ipdl',
     'PContentPermission.ipdlh',
     'PContentPermissionRequest.ipdl',
     'PCrashReporter.ipdl',
     'PCycleCollectWithLogs.ipdl',
+    'PDatePicker.ipdl',
     'PDocumentRenderer.ipdl',
     'PFilePicker.ipdl',
     'PMemoryReportRequest.ipdl',
     'PNuwa.ipdl',
     'PPluginWidget.ipdl',
     'PProcessHangMonitor.ipdl',
     'PScreenManager.ipdl',
     'PTabContext.ipdlh',
--- a/dom/locales/en-US/chrome/layout/HtmlForm.properties
+++ b/dom/locales/en-US/chrome/layout/HtmlForm.properties
@@ -25,16 +25,17 @@ NoFileSelected=No file selected.
 # LOCALIZATION NOTE (NoFilesSelected): this string is shown on a
 # <input type='file' multiple> when there is no file selected yet.
 NoFilesSelected=No files selected.
 # LOCALIZATION NOTE (XFilesSelected): this string is shown on a
 # <input type='file' multiple> when there are more than one selected file.
 # %S will be a number greater or equal to 2.
 XFilesSelected=%S files selected.
 ColorPicker=Choose a color
+DatePicker=Choose a date
 # LOCALIZATION NOTE (AndNMoreFiles): Semi-colon list of plural forms. 
 # See: http://developer.mozilla.org/en/docs/Localization_and_Plurals 
 # This string is shown at the end of the tooltip text for <input type='file'
 # multiple> when there are more than 21 files selected (when we will only list
 # the first 20, plus an "and X more" line). #1 represents the number of files
 # minus 20 and will always be a number equal to or greater than 2. So the
 # singular case will never be used.
 AndNMoreFiles=and one more;and #1 more
--- a/dom/webidl/HTMLInputElement.webidl
+++ b/dom/webidl/HTMLInputElement.webidl
@@ -83,17 +83,17 @@ interface HTMLInputElement : HTMLElement
   [Pure, SetterThrows]
            attribute DOMString step;
   [Pure, SetterThrows]
            attribute DOMString type;
   [Pure, SetterThrows]
            attribute DOMString defaultValue;
   [Pure, TreatNullAs=EmptyString, Throws]
            attribute DOMString value;
-  [Throws, Pref="dom.experimental_forms"]
+  [Throws, Func="HTMLInputElement::ValueAsDateEnabled"]
            attribute Date? valueAsDate;
   [Pure, SetterThrows]
            attribute unrestricted double valueAsNumber;
            attribute unsigned long width;
 
   [Throws]
   void stepUp(optional long n = 1);
   [Throws]
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -60,16 +60,17 @@ XPIDL_SOURCES += [
     'nsIBaseWindow.idl',
     'nsIBidiKeyboard.idl',
     'nsIClipboard.idl',
     'nsIClipboardDragDropHookList.idl',
     'nsIClipboardDragDropHooks.idl',
     'nsIClipboardHelper.idl',
     'nsIClipboardOwner.idl',
     'nsIColorPicker.idl',
+    'nsIDatePicker.idl',
     'nsIDisplayInfo.idl',
     'nsIDragService.idl',
     'nsIDragSession.idl',
     'nsIFilePicker.idl',
     'nsIFormatConverter.idl',
     'nsIGfxInfo.idl',
     'nsIGfxInfoDebug.idl',
     'nsIIdleService.idl',
@@ -142,16 +143,17 @@ UNIFIED_SOURCES += [
     'GfxInfoWebGL.cpp',
     'InputData.cpp',
     'nsBaseAppShell.cpp',
     'nsBaseScreen.cpp',
     'nsClipboardHelper.cpp',
     'nsClipboardProxy.cpp',
     'nsColorPickerProxy.cpp',
     'nsContentProcessWidgetFactory.cpp',
+    'nsDatePickerProxy.cpp',
     'nsDragServiceProxy.cpp',
     'nsFilePickerProxy.cpp',
     'nsHTMLFormatConverter.cpp',
     'nsIdleService.cpp',
     'nsIWidgetListener.cpp',
     'nsPrimitiveHelpers.cpp',
     'nsPrintSettingsImpl.cpp',
     'nsScreenManagerProxy.cpp',
--- a/widget/nsContentProcessWidgetFactory.cpp
+++ b/widget/nsContentProcessWidgetFactory.cpp
@@ -4,59 +4,65 @@
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "mozilla/ModuleUtils.h"
 #include "nsWidgetsCID.h"
 #include "nsClipboardProxy.h"
 #include "nsColorPickerProxy.h"
+#include "nsDatePickerProxy.h"
 #include "nsDragServiceProxy.h"
 #include "nsFilePickerProxy.h"
 #include "nsScreenManagerProxy.h"
 #include "mozilla/widget/PuppetBidiKeyboard.h"
 
 using namespace mozilla;
 using namespace mozilla::widget;
 
 #ifndef MOZ_WIDGET_GONK
 
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsColorPickerProxy)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsDatePickerProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsDragServiceProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsFilePickerProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerProxy)
 NS_GENERIC_FACTORY_CONSTRUCTOR(PuppetBidiKeyboard)
 
 NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID);
 NS_DEFINE_NAMED_CID(NS_COLORPICKER_CID);
+NS_DEFINE_NAMED_CID(NS_DATEPICKER_CID);
 NS_DEFINE_NAMED_CID(NS_DRAGSERVICE_CID);
 NS_DEFINE_NAMED_CID(NS_FILEPICKER_CID);
 NS_DEFINE_NAMED_CID(PUPPETBIDIKEYBOARD_CID);
 NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID);
 
 static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
     { &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_COLORPICKER_CID, false, nullptr, nsColorPickerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
+    { &kNS_DATEPICKER_CID, false, nullptr, nsDatePickerProxyConstructor,
+      Module::CONTENT_PROCESS_ONLY },
     { &kNS_DRAGSERVICE_CID, false, nullptr, nsDragServiceProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_FILEPICKER_CID, false, nullptr, nsFilePickerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerProxyConstructor,
       Module::CONTENT_PROCESS_ONLY },
     { &kPUPPETBIDIKEYBOARD_CID, false, NULL, PuppetBidiKeyboardConstructor,
       mozilla::Module::CONTENT_PROCESS_ONLY },
     { nullptr }
 };
 
 static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
     { "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/colorpicker;1", &kNS_COLORPICKER_CID, Module::CONTENT_PROCESS_ONLY },
+    { "@mozilla.org/datepicker;1", &kNS_DATEPICKER_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/filepicker;1", &kNS_FILEPICKER_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/widget/dragservice;1", &kNS_DRAGSERVICE_CID, Module::CONTENT_PROCESS_ONLY },
     { "@mozilla.org/widget/bidikeyboard;1", &kPUPPETBIDIKEYBOARD_CID,
       Module::CONTENT_PROCESS_ONLY },
     { nullptr }
 };
 
new file mode 100644
--- /dev/null
+++ b/widget/nsDatePickerProxy.cpp
@@ -0,0 +1,61 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsDatePickerProxy.h"
+
+#include "mozilla/dom/TabChild.h"
+
+using namespace mozilla::dom;
+
+NS_IMPL_ISUPPORTS(nsDatePickerProxy, nsIDatePicker)
+
+/* void init (in nsIDOMWindow parent, in AString title, in short mode); */
+NS_IMETHODIMP
+nsDatePickerProxy::Init(mozIDOMWindowProxy* aParent, const nsAString& aTitle,
+                         const nsAString& aInitialDate)
+{
+  TabChild* tabChild = TabChild::GetFrom(aParent);
+  if (!tabChild) {
+    return NS_ERROR_FAILURE;
+  }
+
+  tabChild->SendPDatePickerConstructor(this,
+                                       nsString(aTitle),
+                                       nsString(aInitialDate));
+  NS_ADDREF_THIS(); //Released in DeallocPDatePickerChild
+  return NS_OK;
+}
+
+/* void open (in nsIDatePickerShownCallback aDatePickerShownCallback); */
+NS_IMETHODIMP
+nsDatePickerProxy::Open(nsIDatePickerShownCallback* aDatePickerShownCallback)
+{
+  NS_ENSURE_STATE(!mCallback);
+  mCallback = aDatePickerShownCallback;
+
+  SendOpen();
+  return NS_OK;
+}
+
+bool
+nsDatePickerProxy::RecvCancel()
+{
+  if (mCallback) {
+    mCallback->Cancel();
+    mCallback = nullptr;
+  }
+  return true;
+}
+
+bool
+nsDatePickerProxy::Recv__delete__(const nsString& aDate)
+{
+  if (mCallback) {
+    mCallback->Done(aDate);
+    mCallback = nullptr;
+  }
+  return true;
+}
new file mode 100644
--- /dev/null
+++ b/widget/nsDatePickerProxy.h
@@ -0,0 +1,33 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef nsDatePickerProxy_h
+#define nsDatePickerProxy_h
+
+#include "nsIDatePicker.h"
+
+#include "mozilla/dom/PDatePickerChild.h"
+
+class nsDatePickerProxy final : public nsIDatePicker,
+                                public mozilla::dom::PDatePickerChild
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIDATEPICKER
+
+  nsDatePickerProxy() {}
+
+  virtual bool RecvCancel() override;
+  virtual bool Recv__delete__(const nsString& aDate) override;
+
+private:
+  ~nsDatePickerProxy() {}
+
+  nsCOMPtr<nsIDatePickerShownCallback> mCallback;
+  nsString mTitle;
+  nsString mInitialDate;
+};
+
+#endif // nsDatePickerProxy_h
new file mode 100644
--- /dev/null
+++ b/widget/nsIDatePicker.idl
@@ -0,0 +1,50 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "nsISupports.idl"
+
+interface mozIDOMWindowProxy;
+
+[scriptable, uuid(13388a28-1b0b-4218-a31b-588f7a4ec26c)]
+interface nsIDatePickerShownCallback : nsISupports
+{
+ /**
+  * Callback called when the user selects cancel in the date picker
+  * This callback can not be called after done() is called.
+  */
+ void cancel();
+
+ /**
+  * Callback called when the user has finished selecting the date
+  *
+  * @param  date  The new selected date value following the format "YYYY-MM-DD"
+  */
+  void done(in AString date);
+};
+
+[scriptable, uuid(7becfc64-966b-4d53-87d2-9161f36bd3b3)]
+interface nsIDatePicker : nsISupports
+{
+ /**
+  * Initialize the date picker widget. The date picker will not be shown until
+  * open() is called.
+  * If the initialDate parameter does not follow the format "YYYY-MM-DD" then
+  * the behavior will be unspecified.
+  *
+  * @param      parent       nsIDOMWindow parent. This dialog will be dependent
+  *                          on this parent. parent may be null.
+  * @param      title        The title for the date picker widget.
+  * @param      initialDate  The date to show when the widget is opened. The
+  *                          parameter has to follow the format "YYYY-MM-DD"
+  */
+  void init(in mozIDOMWindowProxy parent, in AString title, in AString initialDate);
+
+ /**
+  * Opens the date dialog asynchrounously.
+  * The results are provided via the callback object.
+  */
+  void open(in nsIDatePickerShownCallback callback);
+};
--- a/widget/nsWidgetsCID.h
+++ b/widget/nsWidgetsCID.h
@@ -28,16 +28,21 @@
 { 0xe221df9b, 0x3d66, 0x4045, \
     {0x9a, 0x66, 0x57, 0x20, 0x94, 0x9f, 0x8d, 0x10} }
 
 /* 0f872c8c-3ee6-46bd-92a2-69652c6b474e */
 #define NS_COLORPICKER_CID \
 { 0x0f872c8c, 0x3ee6, 0x46bd, \
   { 0x92, 0xa2, 0x69, 0x65, 0x2c, 0x6b, 0x47, 0x4e } }
 
+/* 0ca832f8-978a-4dc7-a57d-adb803925d39 */
+#define NS_DATEPICKER_CID \
+{ 0x0ca832f8, 0x978a, 0x4dc7, \
+  { 0xa5, 0x7d, 0xad, 0xb8, 0x03, 0x92, 0x5d, 0x39 } }
+
 /* 2d96b3df-c051-11d1-a827-0040959a28c9 */
 #define NS_APPSHELL_CID \
 { 0x2d96b3df, 0xc051, 0x11d1, \
     {0xa8, 0x27, 0x00, 0x40, 0x95, 0x9a, 0x28, 0xc9} }
 
 /* 2d96b3e0-c051-11d1-a827-0040959a28c9 */
 #define NS_TOOLKIT_CID \
  { 0x2d96b3e0, 0xc051, 0x11d1, \