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 302208 14ac8b409bcd40985ef2abe2ee63ad3b08ab7c69
parent 302207 1c11f8a655264ade01742bc0970fab9396c31a7e
child 302209 6a5167669bd2e88fd0eeb6f1232dbe2838c22c49
push id30356
push usercbook@mozilla.com
push dateWed, 22 Jun 2016 11:45:58 +0000
treeherdermozilla-central@4e17dca08962 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs825294
milestone50.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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, \