Bug 1345361 - PaymentRequest constructrion implementation. r=baku
authorEden Chuang <echuang@mozilla.com>
Tue, 23 May 2017 07:32:19 +0800
changeset 1133476 d0a4ab3b36e14ec2252cfe96dea9d6e4a3f31dd3
parent 1133475 5bc1c758ab57c1885dceab4e7837e58af27b998c
child 1133477 e54fac94a777dc8d1f2e5f1edb390b5b03773d69
push id191872
push userechuang@mozilla.com
push dateMon, 22 May 2017 23:41:07 +0000
treeherdertry@e54fac94a777 [default view] [failures only]
reviewersbaku
bugs1345361
milestone55.0a1
Bug 1345361 - PaymentRequest constructrion implementation. r=baku
browser/installer/package-manifest.in
dom/base/nsGkAtomList.h
dom/bindings/Errors.msg
dom/interfaces/payments/moz.build
dom/interfaces/payments/nsIPaymentActionRequest.idl
dom/interfaces/payments/nsIPaymentRequest.idl
dom/interfaces/payments/nsIPaymentRequestService.idl
dom/ipc/PBrowser.ipdl
dom/ipc/TabChild.cpp
dom/ipc/TabChild.h
dom/ipc/TabParent.cpp
dom/ipc/TabParent.h
dom/moz.build
dom/payments/PaymentActionRequest.cpp
dom/payments/PaymentActionRequest.h
dom/payments/PaymentRequest.cpp
dom/payments/PaymentRequest.h
dom/payments/PaymentRequestData.cpp
dom/payments/PaymentRequestData.h
dom/payments/PaymentRequestManager.cpp
dom/payments/PaymentRequestManager.h
dom/payments/PaymentRequestModule.cpp
dom/payments/PaymentRequestService.cpp
dom/payments/PaymentRequestService.h
dom/payments/PaymentRequestUtils.cpp
dom/payments/PaymentRequestUtils.h
dom/payments/ipc/PPaymentRequest.ipdl
dom/payments/ipc/PaymentRequestChild.cpp
dom/payments/ipc/PaymentRequestChild.h
dom/payments/ipc/PaymentRequestParent.cpp
dom/payments/ipc/PaymentRequestParent.h
dom/payments/ipc/moz.build
dom/payments/moz.build
dom/payments/test/browser.ini
dom/payments/test/browser_multiple_construction.js
dom/payments/test/browser_payment_construction.js
dom/payments/test/browser_payment_in_different_tabs.js
dom/payments/test/head.js
dom/payments/test/multiple_payment_request.html
dom/payments/test/simple_payment_request.html
dom/webidl/PaymentRequest.webidl
dom/webidl/moz.build
mobile/android/installer/package-manifest.in
modules/libpref/init/all.js
--- a/browser/installer/package-manifest.in
+++ b/browser/installer/package-manifest.in
@@ -208,16 +208,17 @@
 @RESPATH@/components/dom_events.xpt
 @RESPATH@/components/dom_geolocation.xpt
 @RESPATH@/components/dom_media.xpt
 @RESPATH@/components/dom_network.xpt
 @RESPATH@/components/dom_notification.xpt
 @RESPATH@/components/dom_html.xpt
 @RESPATH@/components/dom_offline.xpt
 @RESPATH@/components/dom_json.xpt
+@RESPATH@/components/dom_payments.xpt
 @RESPATH@/components/dom_power.xpt
 @RESPATH@/components/dom_push.xpt
 @RESPATH@/components/dom_quota.xpt
 @RESPATH@/components/dom_range.xpt
 @RESPATH@/components/dom_security.xpt
 @RESPATH@/components/dom_sidebar.xpt
 @RESPATH@/components/dom_storage.xpt
 @RESPATH@/components/dom_stylesheets.xpt
--- a/dom/base/nsGkAtomList.h
+++ b/dom/base/nsGkAtomList.h
@@ -953,16 +953,18 @@ GK_ATOM(onscanningstatechanged, "onscann
 GK_ATOM(onscostatuschanged, "onscostatuschanged")
 GK_ATOM(onscroll, "onscroll")
 GK_ATOM(onselect, "onselect")
 GK_ATOM(onselectionchange, "onselectionchange")
 GK_ATOM(onselectstart, "onselectstart")
 GK_ATOM(onsending, "onsending")
 GK_ATOM(onsent, "onsent")
 GK_ATOM(onset, "onset")
+GK_ATOM(onshippingaddresschange, "onshippingaddresschange")
+GK_ATOM(onshippingoptionchange, "onshippingoptionchange")
 GK_ATOM(onshow, "onshow")
 GK_ATOM(onstatechange, "onstatechange")
 GK_ATOM(onstatuschanged, "onstatuschanged")
 GK_ATOM(onstkcommand, "onstkcommand")
 GK_ATOM(onstksessionend, "onstksessionend")
 GK_ATOM(onstorage, "onstorage")
 GK_ATOM(onstorageareachanged, "onstorageareachanged")
 GK_ATOM(onsubmit, "onsubmit")
--- a/dom/bindings/Errors.msg
+++ b/dom/bindings/Errors.msg
@@ -28,16 +28,17 @@ MSG_DEF(MSG_NOT_OBJECT, 1, JSEXN_TYPEERR
 MSG_DEF(MSG_NOT_CALLABLE, 1, JSEXN_TYPEERR, "{0} is not callable.")
 MSG_DEF(MSG_NOT_CONSTRUCTOR, 1, JSEXN_TYPEERR, "{0} is not a constructor.")
 MSG_DEF(MSG_DOES_NOT_IMPLEMENT_INTERFACE, 2, JSEXN_TYPEERR, "{0} does not implement interface {1}.")
 MSG_DEF(MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 2, JSEXN_TYPEERR, "'{0}' called on an object that does not implement interface {1}.")
 MSG_DEF(MSG_METHOD_THIS_UNWRAPPING_DENIED, 1, JSEXN_TYPEERR, "Permission to call '{0}' denied.")
 MSG_DEF(MSG_THIS_DOES_NOT_IMPLEMENT_INTERFACE, 1, JSEXN_TYPEERR, "\"this\" object does not implement interface {0}.")
 MSG_DEF(MSG_NOT_IN_UNION, 2, JSEXN_TYPEERR, "{0} could not be converted to any of: {1}.")
 MSG_DEF(MSG_ILLEGAL_CONSTRUCTOR, 0, JSEXN_TYPEERR, "Illegal constructor.")
+MSG_DEF(MSG_ILLEGAL_PR_CONSTRUCTOR, 1, JSEXN_TYPEERR, "TypeError:{0}")
 MSG_DEF(MSG_CONSTRUCTOR_WITHOUT_NEW, 1, JSEXN_TYPEERR, "Constructor {0} requires 'new'")
 MSG_DEF(MSG_ENFORCE_RANGE_NON_FINITE, 1, JSEXN_TYPEERR, "Non-finite value is out of range for {0}.")
 MSG_DEF(MSG_ENFORCE_RANGE_OUT_OF_RANGE, 1, JSEXN_TYPEERR, "Value is out of range for {0}.")
 MSG_DEF(MSG_NOT_SEQUENCE, 1, JSEXN_TYPEERR, "{0} can't be converted to a sequence.")
 MSG_DEF(MSG_NOT_DICTIONARY, 1, JSEXN_TYPEERR, "{0} can't be converted to a dictionary.")
 MSG_DEF(MSG_OVERLOAD_RESOLUTION_FAILED, 3, JSEXN_TYPEERR, "Argument {0} is not valid for any of the {1}-argument overloads of {2}.")
 MSG_DEF(MSG_GLOBAL_NOT_NATIVE, 0, JSEXN_TYPEERR, "Global is not a native object.")
 MSG_DEF(MSG_ENCODING_NOT_SUPPORTED, 1, JSEXN_RANGEERR, "The given encoding '{0}' is not supported.")
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/moz.build
@@ -0,0 +1,13 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+XPIDL_SOURCES += [
+    'nsIPaymentActionRequest.idl',
+    'nsIPaymentRequest.idl',
+    'nsIPaymentRequestService.idl',
+]
+
+XPIDL_MODULE = 'dom_payments'
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/nsIPaymentActionRequest.idl
@@ -0,0 +1,76 @@
+/* -*- 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"
+#include "nsIVariant.idl"
+#include "nsIPaymentRequest.idl"
+
+interface nsIArray;
+
+[builtinclass, uuid(7ddbe8be-beac-4952-96f6-619981dff7a6)]
+interface nsIPaymentActionRequest : nsISupports
+{
+  const uint32_t CREATE_ACTION = 1;
+  /*
+   *  The payment request identifier.
+   */
+  readonly attribute AString requestId;
+
+  /*
+   *  The type of the requested task.
+   */
+  readonly attribute uint32_t type;
+
+  /*
+   *  Initialize function for this request.
+   */
+  void init(in AString aRequestId,
+            in uint32_t aType);
+};
+
+[builtinclass, uuid(1d38dce6-8bcd-441b-aa94-68e300b6e175)]
+interface nsIPaymentCreateActionRequest : nsIPaymentActionRequest
+{
+  /*
+   *  The tab identifier
+   */
+  readonly attribute uint64_t tabId;
+
+  /*
+   *  The methodData information of the payment request.
+   */
+  readonly attribute nsIArray methodData;
+
+  /*
+   *  The Details information of the payment request.
+   */
+  readonly attribute nsIPaymentDetails details;
+
+  /*
+   *  The Options information of the payment request.
+   */
+  readonly attribute nsIPaymentOptions options;
+
+  /*
+   *  Initialize function the this request.
+   */
+  void initRequest(in AString aRequestId,
+                   in uint64_t aTabId,
+                   in nsIArray aMethodData,
+                   in nsIPaymentDetails aDetails,
+                   in nsIPaymentOptions aOptions);
+};
+
+%{C++
+#define NS_PAYMENT_ACTION_REQUEST_CID \
+  { 0x7ddbe8be, 0xbeac, 0x4952, { 0x96, 0xf6, 0x61, 0x99, 0x81, 0xdf, 0xf7, 0xa6 } }
+#define NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID \
+  "@mozilla.org/dom/payments/payment-action-request;1"
+
+#define NS_PAYMENT_CREATE_ACTION_REQUEST_CID \
+  { 0x1d38dce6, 0x8bcd, 0x441b, { 0xaa, 0x94, 0x68, 0xe3, 0x00, 0xb6, 0xe1, 0x75 } }
+#define NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID \
+  "@mozilla.org/dom/payments/payment-create-action-request;1"
+%}
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/nsIPaymentRequest.idl
@@ -0,0 +1,84 @@
+/* -*- 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"
+#include "nsIVariant.idl"
+
+interface nsIArray;
+
+[scriptable, builtinclass, uuid(2fe296cc-d917-4820-b492-aa42df23f9b4)]
+interface nsIPaymentMethodData : nsISupports
+{
+  readonly attribute nsIArray supportedMethods;
+  readonly attribute AString data;
+};
+
+[scriptable, builtinclass, uuid(d22a6f5f-767b-4fea-bf92-68b0b8003eba)]
+interface nsIPaymentCurrencyAmount : nsISupports
+{
+  readonly attribute AString currency;
+  readonly attribute AString value;
+};
+
+[scriptable, builtinclass, uuid(4f78a59f-b5ff-4fb5-ab48-3b37d0101b02)]
+interface nsIPaymentItem : nsISupports
+{
+  readonly attribute AString label;
+  readonly attribute nsIPaymentCurrencyAmount amount;
+  readonly attribute boolean pending;
+};
+
+[scriptable, builtinclass, uuid(74259861-c318-40e8-b3d5-518e701bed80)]
+interface nsIPaymentDetailsModifier : nsISupports
+{
+  readonly attribute nsIArray supportedMethods;
+  readonly attribute nsIPaymentItem total;
+  readonly attribute nsIArray additionalDisplayItems;
+  readonly attribute AString data;
+};
+
+[scriptable, builtinclass, uuid(68341551-3605-4381-b936-41e830aa88fb)]
+interface nsIPaymentShippingOption : nsISupports
+{
+  readonly attribute AString id;
+  readonly attribute AString label;
+  readonly attribute nsIPaymentCurrencyAmount amount;
+  attribute boolean selected;
+};
+
+[scriptable, builtinclass, uuid(73a5a3f1-45b9-4605-a6e6-7aa60daa9039)]
+interface nsIPaymentDetails : nsISupports
+{
+  readonly attribute AString id;
+  readonly attribute nsIPaymentItem totalItem;
+  readonly attribute nsIArray displayItems;
+  readonly attribute nsIArray shippingOptions;
+  readonly attribute nsIArray modifiers;
+  readonly attribute AString error;
+
+  void update(in nsIPaymentDetails aDetails);
+};
+
+[scriptable, builtinclass, uuid(d53f9f20-138e-47cc-9fd5-db16a3f6d301)]
+interface nsIPaymentOptions : nsISupports
+{
+  readonly attribute boolean requestPayerName;
+  readonly attribute boolean requestPayerEmail;
+  readonly attribute boolean requestPayerPhone;
+  readonly attribute boolean requestShipping;
+  readonly attribute AString shippingType;
+};
+
+[scriptable, builtinclass, uuid(2fa36783-d684-4487-b7a8-9def6ae3128f)]
+interface nsIPaymentRequest : nsISupports
+{
+  readonly attribute uint64_t tabId;
+  readonly attribute AString requestId;
+  readonly attribute nsIArray paymentMethods;
+  readonly attribute nsIPaymentDetails paymentDetails;
+  readonly attribute nsIPaymentOptions paymentOptions;
+
+  void updatePaymentDetails(in nsIPaymentDetails aDetails);
+};
new file mode 100644
--- /dev/null
+++ b/dom/interfaces/payments/nsIPaymentRequestService.idl
@@ -0,0 +1,35 @@
+/* -*- 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"
+#include "nsIVariant.idl"
+#include "nsIPaymentRequest.idl"
+#include "nsIPaymentActionRequest.idl"
+#include "nsISimpleEnumerator.idl"
+
+/*
+ *  nsPaymentRequestService is used to manage the created PaymentRequest in the
+ *  chrome process. It is also the IPC agent for payment UI to communicate with
+ *  merchant side.
+ */
+[scriptable, builtinclass, uuid(cccd665f-edf3-41fc-ab9b-fc55b37340aa)]
+interface nsIPaymentRequestService : nsISupports
+{
+  nsIPaymentRequest getPaymentRequestById(in AString requestId);
+  nsISimpleEnumerator enumerate();
+
+  /*
+   *  requestPayment is used to handle the asked action request of the payment
+   *  from content process.
+   */
+  void requestPayment(in nsIPaymentActionRequest aRequest);
+};
+
+%{C++
+#define NS_PAYMENT_REQUEST_SERVICE_CID \
+  { 0xcccd665f, 0xedf3, 0x41fc, { 0xab, 0x9b, 0xfc, 0x55, 0xb3, 0x73, 0x40, 0xaa } }
+#define NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID \
+  "@mozilla.org/dom/payments/payment-request-service;1"
+%}
--- a/dom/ipc/PBrowser.ipdl
+++ b/dom/ipc/PBrowser.ipdl
@@ -15,16 +15,17 @@ include protocol PFilePicker;
 include protocol PIndexedDBPermissionRequest;
 include protocol PRenderFrame;
 include protocol PPluginWidget;
 include protocol PRemotePrintJob;
 include protocol PChildToParentStream;
 include protocol PParentToChildStream;
 include protocol PFileDescriptorSet;
 include protocol PIPCBlobInputStream;
+include protocol PPaymentRequest;
 
 include DOMTypes;
 include IPCBlob;
 include IPCStream;
 include JavaScriptTypes;
 include URIParams;
 include PPrintingTypes;
 include PTabContext;
@@ -111,16 +112,17 @@ nested(upto inside_cpow) sync protocol P
 
     manages PColorPicker;
     manages PDocAccessible;
     manages PDocumentRenderer;
     manages PFilePicker;
     manages PIndexedDBPermissionRequest;
     manages PRenderFrame;
     manages PPluginWidget;
+    manages PPaymentRequest;
 
 both:
     async AsyncMessage(nsString aMessage, CpowEntry[] aCpows,
                        Principal aPrincipal, ClonedMessageData aData);
 
     /**
      * Create a layout frame (encapsulating a remote layer tree) for
      * the page that is currently loaded in the <browser>.
@@ -141,16 +143,18 @@ parent:
 
     /*
      * Creates a new remoted nsIWidget connection for windowed plugins
      * in e10s mode. This is always initiated from the child in response
      * to windowed plugin creation.
      */
     sync PPluginWidget();
 
+    async PPaymentRequest();
+
     /**
      * Return native data of root widget
      */
     nested(inside_cpow) sync GetWidgetNativeData() returns (WindowsHandle value);
 
     /**
      * Sends an NS_NATIVE_CHILD_OF_SHAREABLE_WINDOW to be adopted by the
      * widget's shareable window on the chrome side. Only used on Windows.
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -15,16 +15,17 @@
 #include "Layers.h"
 #include "ContentChild.h"
 #include "TabParent.h"
 #include "mozilla/Preferences.h"
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/ClearOnShutdown.h"
 #include "mozilla/EventListenerManager.h"
 #include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
+#include "mozilla/dom/PaymentRequestChild.h"
 #include "mozilla/dom/TelemetryScrollProbe.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/DocumentRendererChild.h"
 #include "mozilla/ipc/URIUtils.h"
 #include "mozilla/layers/APZChild.h"
 #include "mozilla/layers/APZCCallbackHelper.h"
 #include "mozilla/layers/APZCTreeManager.h"
 #include "mozilla/layers/APZCTreeManagerChild.h"
@@ -3209,16 +3210,35 @@ TabChild::CreatePluginWidget(nsIWidget* 
   if (NS_FAILED(rv)) {
     NS_WARNING("Creating native plugin widget on the chrome side failed.");
   }
   pluginWidget.forget(aOut);
   return rv;
 }
 #endif // XP_WIN
 
+PPaymentRequestChild*
+TabChild::AllocPPaymentRequestChild()
+{
+  MOZ_CRASH("We should never be manually allocating PPaymentRequestChild actors");
+  return nullptr;
+}
+
+bool
+TabChild::DeallocPPaymentRequestChild(PPaymentRequestChild* aActor)
+{
+  /*
+    No need to do anything here.
+    PaymentRequestManager takes care the deallocation by reference counting
+    mechanism. PaymentRequestChild::ActorDestory aslo calls PaymentRequestManager
+    to release the memory.
+  */
+  return true;
+}
+
 ScreenIntSize
 TabChild::GetInnerSize()
 {
   LayoutDeviceIntSize innerSize =
     RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
   return ViewAs<ScreenPixel>(innerSize, PixelCastJustification::LayoutDeviceIsScreenForTabDims);
 };
 
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -607,16 +607,22 @@ public:
   PPluginWidgetChild* AllocPPluginWidgetChild() override;
 
   bool DeallocPPluginWidgetChild(PPluginWidgetChild* aActor) override;
 
 #ifdef XP_WIN
   nsresult CreatePluginWidget(nsIWidget* aParent, nsIWidget** aOut);
 #endif
 
+  virtual PPaymentRequestChild*
+  AllocPPaymentRequestChild() override;
+
+  virtual bool
+  DeallocPPaymentRequestChild(PPaymentRequestChild*) override;
+
   LayoutDeviceIntPoint GetClientOffset() const { return mClientOffset; }
   LayoutDeviceIntPoint GetChromeDisplacement() const { return mChromeDisp; };
 
   bool IPCOpen() const { return mIPCOpen; }
 
   bool ParentIsActive() const
   {
     return mParentIsActive;
--- a/dom/ipc/TabParent.cpp
+++ b/dom/ipc/TabParent.cpp
@@ -14,16 +14,17 @@
 #endif
 #include "mozilla/BrowserElementParent.h"
 #include "mozilla/dom/ContentBridgeParent.h"
 #include "mozilla/dom/ContentParent.h"
 #include "mozilla/dom/DataTransfer.h"
 #include "mozilla/dom/Event.h"
 #include "mozilla/dom/indexedDB/ActorsParent.h"
 #include "mozilla/dom/IPCBlobUtils.h"
+#include "mozilla/dom/PaymentRequestParent.h"
 #include "mozilla/EventStateManager.h"
 #include "mozilla/gfx/2D.h"
 #include "mozilla/gfx/DataSurfaceHelpers.h"
 #include "mozilla/gfx/GPUProcessManager.h"
 #include "mozilla/Hal.h"
 #include "mozilla/IMEStateManager.h"
 #include "mozilla/ipc/DocumentRendererParent.h"
 #include "mozilla/jsipc/CrossProcessObjectWrappers.h"
@@ -2863,16 +2864,31 @@ TabParent::AllocPPluginWidgetParent()
 
 bool
 TabParent::DeallocPPluginWidgetParent(mozilla::plugins::PPluginWidgetParent* aActor)
 {
   delete aActor;
   return true;
 }
 
+PPaymentRequestParent*
+TabParent::AllocPPaymentRequestParent()
+{
+  RefPtr<PaymentRequestParent> actor = new PaymentRequestParent(GetTabId());
+  return actor.forget().take();
+}
+
+bool
+TabParent::DeallocPPaymentRequestParent(PPaymentRequestParent* aActor)
+{
+  RefPtr<PaymentRequestParent> actor =
+    dont_AddRef(static_cast<PaymentRequestParent*>(aActor));
+  return true;
+}
+
 nsresult
 TabParent::HandleEvent(nsIDOMEvent* aEvent)
 {
   nsAutoString eventType;
   aEvent->GetType(eventType);
 
   if (eventType.EqualsLiteral("MozUpdateWindowPos") && !mIsDestroyed) {
     // This event is sent when the widget moved.  Therefore we only update
--- a/dom/ipc/TabParent.h
+++ b/dom/ipc/TabParent.h
@@ -549,16 +549,22 @@ public:
   /**
    * Native widget remoting protocol for use with windowed plugins with e10s.
    */
   virtual PPluginWidgetParent* AllocPPluginWidgetParent() override;
 
   virtual bool
   DeallocPPluginWidgetParent(PPluginWidgetParent* aActor) override;
 
+  virtual PPaymentRequestParent*
+  AllocPPaymentRequestParent() override;
+
+  virtual bool
+  DeallocPPaymentRequestParent(PPaymentRequestParent* aActor) override;
+
   void SetInitedByParent() { mInitedByParent = true; }
 
   bool IsInitedByParent() const { return mInitedByParent; }
 
   bool SendLoadRemoteScript(const nsString& aURL,
                             const bool& aRunInGlobalScope);
 
   void LayerTreeUpdate(uint64_t aEpoch, bool aActive);
--- a/dom/moz.build
+++ b/dom/moz.build
@@ -31,16 +31,17 @@ interfaces = [
     'storage',
     'json',
     'offline',
     'geolocation',
     'notification',
     'svg',
     'smil',
     'push',
+    'payments',
 ]
 
 DIRS += ['interfaces/' + i for i in interfaces]
 
 DIRS += [
     'animation',
     'base',
     'bindings',
@@ -100,16 +101,17 @@ DIRS += [
     'vr',
     'u2f',
     'console',
     'performance',
     'webbrowserpersist',
     'xhr',
     'worklet',
     'script',
+    'payments',
 ]
 
 if CONFIG['OS_ARCH'] == 'WINNT':
     DIRS += ['plugins/ipc/hangui']
 
 if CONFIG['MOZ_SECUREELEMENT']:
     DIRS += ['secureelement']
 
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentActionRequest.cpp
@@ -0,0 +1,110 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsArrayUtils.h"
+#include "nsIMutableArray.h"
+#include "PaymentActionRequest.h"
+#include "PaymentRequestData.h"
+
+using namespace mozilla::dom::payments;
+
+namespace mozilla {
+namespace dom {
+
+/* PaymentActionRequest */
+
+NS_IMPL_ISUPPORTS(PaymentActionRequest,
+                  nsIPaymentActionRequest)
+
+NS_IMETHODIMP
+PaymentActionRequest::Init(const nsAString& aRequestId,
+                           const uint32_t aType)
+{
+  mRequestId = aRequestId;
+  mType = aType;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentActionRequest::GetRequestId(nsAString& aRequestId)
+{
+  aRequestId = mRequestId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentActionRequest::GetType(uint32_t* aType)
+{
+  *aType = mType;
+  return NS_OK;
+}
+
+/* PaymentCreateActionRequest */
+
+NS_IMPL_ISUPPORTS_INHERITED(PaymentCreateActionRequest,
+                            PaymentActionRequest,
+                            nsIPaymentCreateActionRequest)
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::InitRequest(const nsAString& aRequestId,
+                                        const uint64_t aTabId,
+                                        nsIArray* aMethodData,
+                                        nsIPaymentDetails* aDetails,
+                                        nsIPaymentOptions* aOptions)
+{
+  NS_ENSURE_ARG_POINTER(aMethodData);
+  NS_ENSURE_ARG_POINTER(aDetails);
+  NS_ENSURE_ARG_POINTER(aOptions);
+  Init(aRequestId, nsIPaymentActionRequest::CREATE_ACTION);
+  mTabId = aTabId;
+  mMethodData = aMethodData;
+  mDetails = aDetails;
+  mOptions = aOptions;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetTabId(uint64_t* aTabId)
+{
+  NS_ENSURE_ARG_POINTER(aTabId);
+  *aTabId = mTabId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetMethodData(nsIArray** aMethodData)
+{
+  NS_ENSURE_ARG_POINTER(aMethodData);
+  *aMethodData = nullptr;
+  MOZ_ASSERT(mMethodData);
+  nsCOMPtr<nsIArray> methodData = mMethodData;
+  methodData.forget(aMethodData);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetDetails(nsIPaymentDetails** aDetails)
+{
+  NS_ENSURE_ARG_POINTER(aDetails);
+  *aDetails = nullptr;
+  MOZ_ASSERT(mDetails);
+  nsCOMPtr<nsIPaymentDetails> details = mDetails;
+  details.forget(aDetails);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCreateActionRequest::GetOptions(nsIPaymentOptions** aOptions)
+{
+  NS_ENSURE_ARG_POINTER(aOptions);
+  *aOptions = nullptr;
+  MOZ_ASSERT(mOptions);
+  nsCOMPtr<nsIPaymentOptions> options = mOptions;
+  options.forget(aOptions);
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentActionRequest.h
@@ -0,0 +1,56 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentActionRequest_h
+#define mozilla_dom_PaymentActionRequest_h
+
+#include "nsIPaymentActionRequest.h"
+#include "nsCOMPtr.h"
+#include "nsCOMArray.h"
+#include "nsIArray.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentActionRequest : public nsIPaymentActionRequest
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTACTIONREQUEST
+
+  PaymentActionRequest() = default;
+
+protected:
+  virtual ~PaymentActionRequest() = default;
+
+  nsString mRequestId;
+  uint32_t mType;
+};
+
+class PaymentCreateActionRequest final : public nsIPaymentCreateActionRequest
+                                       , public PaymentActionRequest
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_FORWARD_NSIPAYMENTACTIONREQUEST(PaymentActionRequest::)
+  NS_DECL_NSIPAYMENTCREATEACTIONREQUEST
+
+  PaymentCreateActionRequest() = default;
+
+private:
+  ~PaymentCreateActionRequest() = default;
+
+  uint64_t mTabId;
+  nsCOMPtr<nsIArray> mMethodData;
+  nsCOMPtr<nsIPaymentDetails> mDetails;
+  nsCOMPtr<nsIPaymentOptions> mOptions;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequest.cpp
@@ -0,0 +1,281 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/dom/PaymentRequest.h"
+#include "nsContentUtils.h"
+#include "PaymentRequestManager.h"
+
+namespace mozilla {
+namespace dom {
+
+NS_IMPL_CYCLE_COLLECTION_CLASS(PaymentRequest)
+
+NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(PaymentRequest,
+                                               DOMEventTargetHelper)
+  // Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
+  // DOMEventTargetHelper does it for us.
+NS_IMPL_CYCLE_COLLECTION_TRACE_END
+
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(PaymentRequest,
+                                                  DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
+
+NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(PaymentRequest,
+                                                DOMEventTargetHelper)
+NS_IMPL_CYCLE_COLLECTION_UNLINK_END
+
+NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(PaymentRequest)
+NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
+
+NS_IMPL_ADDREF_INHERITED(PaymentRequest, DOMEventTargetHelper)
+NS_IMPL_RELEASE_INHERITED(PaymentRequest, DOMEventTargetHelper)
+
+bool
+PaymentRequest::PrefEnabled(JSContext* aCx, JSObject* aObj)
+{
+  return Preferences::GetBool("dom.payments.request.enabled");
+}
+
+bool
+PaymentRequest::IsVaildNumber(const nsAString& aItem,
+                              const nsAString& aStr,
+                              nsAString& aErrorMsg)
+{
+  nsAutoString aValue(aStr);
+  nsresult error = NS_OK;
+  aValue.ToFloat(&error);
+  if (NS_FAILED(error)) {
+    aErrorMsg.AssignLiteral("The amount.value of \"");
+    aErrorMsg.Append(aItem);
+    aErrorMsg.AppendLiteral("\"(");
+    aErrorMsg.Append(aValue);
+    aErrorMsg.AppendLiteral(") must be a valid decimal monetary value.");
+    return false;
+  }
+  return true;
+}
+
+bool
+PaymentRequest::IsPositiveNumber(const nsAString& aItem,
+                                 const nsAString& aStr,
+                                 nsAString& aErrorMsg)
+{
+  nsAutoString aValue(aStr);
+  nsresult error = NS_OK;
+  float value = aValue.ToFloat(&error);
+  if (NS_FAILED(error) || value < 0) {
+    aErrorMsg.AssignLiteral("The amount.value of \"");
+    aErrorMsg.Append(aItem);
+    aErrorMsg.AppendLiteral("\"(");
+    aErrorMsg.Append(aValue);
+    aErrorMsg.AppendLiteral(") must be a valid and positive decimal monetary value.");
+    return false;
+  }
+  return true;
+}
+
+bool
+PaymentRequest::IsVaildDetailsInit(const PaymentDetailsInit& aDetails, nsAString& aErrorMsg)
+{
+  // Check the amount.value of detail.total
+  if (!IsPositiveNumber(NS_LITERAL_STRING("details.total"),
+                        aDetails.mTotal.mAmount.mValue, aErrorMsg)) {
+    return false;
+  }
+
+  return IsVaildDetailsBase(aDetails, aErrorMsg);
+}
+
+bool
+PaymentRequest::IsVaildDetailsBase(const PaymentDetailsBase& aDetails, nsAString& aErrorMsg)
+{
+  // Check the amount.value of each item in the display items
+  if (aDetails.mDisplayItems.WasPassed()) {
+    const Sequence<PaymentItem>& displayItems = aDetails.mDisplayItems.Value();
+    for (const PaymentItem& displayItem : displayItems) {
+      if (!IsVaildNumber(displayItem.mLabel,
+                         displayItem.mAmount.mValue, aErrorMsg)) {
+        return false;
+      }
+    }
+  }
+
+  // Check the shipping option
+  if (aDetails.mShippingOptions.WasPassed()) {
+    const Sequence<PaymentShippingOption>& shippingOptions = aDetails.mShippingOptions.Value();
+    for (const PaymentShippingOption& shippingOption : shippingOptions) {
+      if (!IsVaildNumber(NS_LITERAL_STRING("details.shippingOptions"),
+                         shippingOption.mAmount.mValue, aErrorMsg)) {
+        return false;
+      }
+    }
+  }
+
+  // Check payment details modifiers
+  if (aDetails.mModifiers.WasPassed()) {
+    const Sequence<PaymentDetailsModifier>& modifiers = aDetails.mModifiers.Value();
+    for (const PaymentDetailsModifier& modifier : modifiers) {
+      if (!IsPositiveNumber(NS_LITERAL_STRING("details.modifiers.total"),
+                            modifier.mTotal.mAmount.mValue, aErrorMsg)) {
+        return false;
+      }
+      if (modifier.mAdditionalDisplayItems.WasPassed()) {
+        const Sequence<PaymentItem>& displayItems = modifier.mAdditionalDisplayItems.Value();
+        for (const PaymentItem& displayItem : displayItems) {
+          if (!IsVaildNumber(displayItem.mLabel,
+                             displayItem.mAmount.mValue, aErrorMsg)) {
+            return false;
+          }
+        }
+      }
+    }
+  }
+
+  return true;
+}
+
+already_AddRefed<PaymentRequest>
+PaymentRequest::Constructor(const GlobalObject& aGlobal,
+                            const Sequence<PaymentMethodData>& aMethodData,
+                            const PaymentDetailsInit& aDetails,
+                            const PaymentOptions& aOptions,
+                            ErrorResult& aRv)
+{
+  nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal.GetAsSupports());
+  if (!window) {
+    aRv.Throw(NS_ERROR_UNEXPECTED);
+    return nullptr;
+  }
+
+  // [TODO] Bug 1318988 - Implement `allowPaymentRequest` on iframe
+
+  // Check payment methods is done by webidl
+
+  // Check payment details
+  nsAutoString message;
+  if (!IsVaildDetailsInit(aDetails, message)) {
+    aRv.ThrowTypeError<MSG_ILLEGAL_PR_CONSTRUCTOR>(message);
+    return nullptr;
+  }
+
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  if (NS_WARN_IF(!manager)) {
+    return nullptr;
+  }
+
+  // Create PaymentRequest and set its |mId|
+  RefPtr<PaymentRequest> request;
+  nsresult rv = manager->CreatePayment(window, aMethodData, aDetails,
+                                       aOptions, getter_AddRefs(request));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return nullptr;
+  }
+
+  return request.forget();
+}
+
+already_AddRefed<PaymentRequest>
+PaymentRequest::CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv)
+{
+  // Generate a unique id for identification
+  nsID uuid;
+  aRv = nsContentUtils::GenerateUUIDInPlace(uuid);
+  if (NS_WARN_IF(NS_FAILED(aRv))) {
+    return nullptr;
+  }
+  char buffer[NSID_LENGTH];
+  uuid.ToProvidedString(buffer);
+  nsAutoString id;
+  CopyASCIItoUTF16(buffer, id);
+
+  RefPtr<PaymentRequest> request = new PaymentRequest(aWindow, id);
+  return request.forget();
+}
+
+PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId)
+  : DOMEventTargetHelper(aWindow)
+  , mInternalId(aInternalId)
+  , mUpdating(false)
+  , mState(eCreated)
+{
+  MOZ_ASSERT(aWindow);
+}
+
+already_AddRefed<Promise>
+PaymentRequest::Show(ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_FAILURE);
+  return nullptr;
+}
+
+already_AddRefed<Promise>
+PaymentRequest::CanMakePayment(ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_FAILURE);
+  return nullptr;
+}
+
+already_AddRefed<Promise>
+PaymentRequest::Abort(ErrorResult& aRv)
+{
+  aRv.Throw(NS_ERROR_FAILURE);
+  return nullptr;
+}
+
+void
+PaymentRequest::GetId(nsAString& aRetVal) const
+{
+  aRetVal = mId;
+}
+
+void
+PaymentRequest::GetInternalId(nsAString& aRetVal)
+{
+  aRetVal = mInternalId;
+}
+
+void
+PaymentRequest::SetId(const nsAString& aId)
+{
+  mId = aId;
+}
+
+bool
+PaymentRequest::Equals(const nsAString& aInternalId) const
+{
+  return mInternalId.Equals(aInternalId);
+}
+
+void
+PaymentRequest::SetUpdating(bool aUpdating)
+{
+  mUpdating = aUpdating;
+}
+
+void
+PaymentRequest::GetShippingOption(nsAString& aRetVal) const
+{
+  aRetVal = mShippingOption;
+}
+
+Nullable<PaymentShippingType>
+PaymentRequest::GetShippingType() const
+{
+  return nullptr;
+}
+
+PaymentRequest::~PaymentRequest()
+{
+}
+
+JSObject*
+PaymentRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
+{
+  return PaymentRequestBinding::Wrap(aCx, this, aGivenProto);
+}
+
+} // namespace dom
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequest.h
@@ -0,0 +1,110 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentRequest_h
+#define mozilla_dom_PaymentRequest_h
+
+#include "mozilla/DOMEventTargetHelper.h"
+#include "mozilla/dom/PaymentRequestBinding.h"
+#include "mozilla/dom/Promise.h"
+#include "mozilla/ErrorResult.h"
+#include "nsWrapperCache.h"
+
+namespace mozilla {
+namespace dom {
+
+class EventHandlerNonNull;
+class PaymentResponse;
+
+class PaymentRequest final : public DOMEventTargetHelper
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+
+  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(PaymentRequest, DOMEventTargetHelper)
+
+  virtual JSObject* WrapObject(JSContext* aCx,
+                               JS::Handle<JSObject*> aGivenProto) override;
+
+  static already_AddRefed<PaymentRequest>
+  CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv);
+
+  static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
+
+  static bool
+  IsVaildNumber(const nsAString& aItem,
+                const nsAString& aStr,
+                nsAString& aErrorMsg);
+  static bool
+  IsPositiveNumber(const nsAString& aItem,
+                   const nsAString& aStr,
+                   nsAString& aErrorMsg);
+
+  static bool
+  IsVaildDetailsInit(const PaymentDetailsInit& aDetails,
+                     nsAString& aErrorMsg);
+  static bool
+  IsVaildDetailsBase(const PaymentDetailsBase& aDetails,
+                     nsAString& aErrorMsg);
+
+  static already_AddRefed<PaymentRequest>
+  Constructor(const GlobalObject& aGlobal,
+              const Sequence<PaymentMethodData>& aMethodData,
+              const PaymentDetailsInit& aDetails,
+              const PaymentOptions& aOptions,
+              ErrorResult& aRv);
+
+  already_AddRefed<Promise> Show(ErrorResult& aRv);
+  already_AddRefed<Promise> Abort(ErrorResult& aRv);
+  already_AddRefed<Promise> CanMakePayment(ErrorResult& aRv);
+
+  void GetId(nsAString& aRetVal) const;
+  void GetInternalId(nsAString& aRetVal);
+  void SetId(const nsAString& aId);
+
+  bool Equals(const nsAString& aInternalId) const;
+
+  void SetUpdating(bool aUpdating);
+
+  void GetShippingOption(nsAString& aRetVal) const;
+
+  Nullable<PaymentShippingType> GetShippingType() const;
+
+  IMPL_EVENT_HANDLER(shippingaddresschange);
+  IMPL_EVENT_HANDLER(shippingoptionchange);
+
+protected:
+  ~PaymentRequest();
+
+  PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId);
+
+  // Id for internal identification
+  nsString mInternalId;
+  // Id for communicating with merchant side
+  // mId is initialized to details.id if it exists
+  // otherwise, mId has the same value as mInternalId.
+  nsString mId;
+  // It is populated when the user chooses a shipping option.
+  nsString mShippingOption;
+
+  // "true" when there is a pending updateWith() call to update the payment request
+  // and "false" otherwise.
+  bool mUpdating;
+  // The error is set in AbortUpdate(). The value is NS_OK by default.
+  //nsresult mUpdateError;
+
+  enum {
+    eUnknown,
+    eCreated,
+    eInteractive,
+    eClosed
+  } mState;
+};
+
+} // namespace dom
+} // namespace mozilla
+
+#endif // mozilla_dom_PaymentRequest_h
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestData.cpp
@@ -0,0 +1,660 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsArrayUtils.h"
+#include "nsIMutableArray.h"
+#include "nsISupportsPrimitives.h"
+#include "PaymentRequestData.h"
+#include "PaymentRequestUtils.h"
+
+namespace mozilla {
+namespace dom {
+namespace payments {
+
+/* PaymentMethodData */
+
+NS_IMPL_ISUPPORTS(PaymentMethodData,
+                  nsIPaymentMethodData)
+
+PaymentMethodData::PaymentMethodData(nsIArray* aSupportedMethods,
+                                     const nsAString& aData)
+  : mSupportedMethods(aSupportedMethods)
+  , mData(aData)
+{
+}
+
+nsresult
+PaymentMethodData::Create(const IPCPaymentMethodData& aIPCMethodData,
+                          nsIPaymentMethodData** aMethodData)
+{
+  NS_ENSURE_ARG_POINTER(aMethodData);
+  nsCOMPtr<nsIArray> supportedMethods;
+  nsresult rv = ConvertStringstoISupportsStrings(aIPCMethodData.supportedMethods(),
+                                                 getter_AddRefs(supportedMethods));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  nsCOMPtr<nsIPaymentMethodData> methodData =
+    new PaymentMethodData(supportedMethods, aIPCMethodData.data());
+  methodData.forget(aMethodData);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentMethodData::GetSupportedMethods(nsIArray** aSupportedMethods)
+{
+  NS_ENSURE_ARG_POINTER(aSupportedMethods);
+  MOZ_ASSERT(mSupportedMethods);
+  nsCOMPtr<nsIArray> supportedMethods = mSupportedMethods;
+  supportedMethods.forget(aSupportedMethods);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentMethodData::GetData(nsAString& aData)
+{
+  aData = mData;
+  return NS_OK;
+}
+
+/* PaymentCurrencyAmount */
+
+NS_IMPL_ISUPPORTS(PaymentCurrencyAmount,
+                  nsIPaymentCurrencyAmount)
+
+PaymentCurrencyAmount::PaymentCurrencyAmount(const nsAString& aCurrency,
+                                             const nsAString& aValue)
+  : mCurrency(aCurrency)
+  , mValue(aValue)
+{
+}
+
+nsresult
+PaymentCurrencyAmount::Create(const IPCPaymentCurrencyAmount& aIPCAmount,
+                              nsIPaymentCurrencyAmount** aAmount)
+{
+  NS_ENSURE_ARG_POINTER(aAmount);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount =
+    new PaymentCurrencyAmount(aIPCAmount.currency(), aIPCAmount.value());
+  amount.forget(aAmount);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCurrencyAmount::GetCurrency(nsAString& aCurrency)
+{
+  aCurrency = mCurrency;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentCurrencyAmount::GetValue(nsAString& aValue)
+{
+  aValue = mValue;
+  return NS_OK;
+}
+
+/* PaymentItem */
+
+NS_IMPL_ISUPPORTS(PaymentItem,
+                  nsIPaymentItem)
+
+PaymentItem::PaymentItem(const nsAString& aLabel,
+                         nsIPaymentCurrencyAmount* aAmount,
+                         const bool aPending)
+  : mLabel(aLabel)
+  , mAmount(aAmount)
+  , mPending(aPending)
+{
+}
+
+nsresult
+PaymentItem::Create(const IPCPaymentItem& aIPCItem, nsIPaymentItem** aItem)
+{
+  NS_ENSURE_ARG_POINTER(aItem);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount;
+  nsresult rv = PaymentCurrencyAmount::Create(aIPCItem.amount(),
+                                              getter_AddRefs(amount));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  nsCOMPtr<nsIPaymentItem> item =
+    new PaymentItem(aIPCItem.label(), amount, aIPCItem.pending());
+  item.forget(aItem);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentItem::GetLabel(nsAString& aLabel)
+{
+  aLabel = mLabel;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentItem::GetAmount(nsIPaymentCurrencyAmount** aAmount)
+{
+  NS_ENSURE_ARG_POINTER(aAmount);
+  MOZ_ASSERT(mAmount);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount = mAmount;
+  amount.forget(aAmount);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentItem::GetPending(bool* aPending)
+{
+  NS_ENSURE_ARG_POINTER(aPending);
+  *aPending = mPending;
+  return NS_OK;
+}
+
+/* PaymentDetailsModifier */
+
+NS_IMPL_ISUPPORTS(PaymentDetailsModifier,
+                  nsIPaymentDetailsModifier)
+
+PaymentDetailsModifier::PaymentDetailsModifier(nsIArray* aSupportedMethods,
+                                               nsIPaymentItem* aTotal,
+                                               nsIArray* aAdditionalDisplayItems,
+                                               const nsAString& aData)
+  : mSupportedMethods(aSupportedMethods)
+  , mTotal(aTotal)
+  , mAdditionalDisplayItems(aAdditionalDisplayItems)
+  , mData(aData)
+{
+}
+
+nsresult
+PaymentDetailsModifier::Create(const IPCPaymentDetailsModifier& aIPCModifier,
+                               nsIPaymentDetailsModifier** aModifier)
+{
+  NS_ENSURE_ARG_POINTER(aModifier);
+  nsCOMPtr<nsIPaymentItem> total;
+  nsresult rv = PaymentItem::Create(aIPCModifier.total(), getter_AddRefs(total));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> supportedMethods;
+  rv = ConvertStringstoISupportsStrings(aIPCModifier.supportedMethods(),
+                                        getter_AddRefs(supportedMethods));
+   if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> displayItems;
+  if (aIPCModifier.additionalDisplayItemsPassed()) {
+    nsCOMPtr<nsIMutableArray> items = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(items);
+    for (const IPCPaymentItem& item : aIPCModifier.additionalDisplayItems()) {
+      nsCOMPtr<nsIPaymentItem> additionalItem;
+      rv = PaymentItem::Create(item, getter_AddRefs(additionalItem));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = items->AppendElement(additionalItem, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    displayItems = items.forget();
+  }
+  nsCOMPtr<nsIPaymentDetailsModifier> modifier =
+    new PaymentDetailsModifier(supportedMethods, total, displayItems, aIPCModifier.data());
+  modifier.forget(aModifier);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetSupportedMethods(nsIArray** aSupportedMethods)
+{
+  NS_ENSURE_ARG_POINTER(aSupportedMethods);
+  MOZ_ASSERT(mSupportedMethods);
+  nsCOMPtr<nsIArray> supportedMethods = mSupportedMethods;
+  supportedMethods.forget(aSupportedMethods);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetTotal(nsIPaymentItem** aTotal)
+{
+  NS_ENSURE_ARG_POINTER(aTotal);
+  MOZ_ASSERT(mTotal);
+  nsCOMPtr<nsIPaymentItem> total = mTotal;
+  total.forget(aTotal);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetAdditionalDisplayItems(nsIArray** aAdditionalDisplayItems)
+{
+  NS_ENSURE_ARG_POINTER(aAdditionalDisplayItems);
+  nsCOMPtr<nsIArray> additionalItems = mAdditionalDisplayItems;
+  additionalItems.forget(aAdditionalDisplayItems);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetailsModifier::GetData(nsAString& aData)
+{
+  aData = mData;
+  return NS_OK;
+}
+
+/* PaymentShippingOption */
+
+NS_IMPL_ISUPPORTS(PaymentShippingOption,
+                  nsIPaymentShippingOption)
+
+PaymentShippingOption::PaymentShippingOption(const nsAString& aId,
+                                             const nsAString& aLabel,
+                                             nsIPaymentCurrencyAmount* aAmount,
+                                             const bool aSelected)
+  : mId(aId)
+  , mLabel(aLabel)
+  , mAmount(aAmount)
+  , mSelected(aSelected)
+{
+}
+
+nsresult
+PaymentShippingOption::Create(const IPCPaymentShippingOption& aIPCOption,
+                              nsIPaymentShippingOption** aOption)
+{
+  NS_ENSURE_ARG_POINTER(aOption);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount;
+  nsresult rv = PaymentCurrencyAmount::Create(aIPCOption.amount(), getter_AddRefs(amount));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  nsCOMPtr<nsIPaymentShippingOption> option =
+    new PaymentShippingOption(aIPCOption.id(), aIPCOption.label(), amount, aIPCOption.selected());
+  option.forget(aOption);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetId(nsAString& aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetLabel(nsAString& aLabel)
+{
+  aLabel = mLabel;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetAmount(nsIPaymentCurrencyAmount** aAmount)
+{
+  NS_ENSURE_ARG_POINTER(aAmount);
+  MOZ_ASSERT(mAmount);
+  nsCOMPtr<nsIPaymentCurrencyAmount> amount = mAmount;
+  amount.forget(aAmount);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::GetSelected(bool* aSelected)
+{
+  NS_ENSURE_ARG_POINTER(aSelected);
+  *aSelected = mSelected;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentShippingOption::SetSelected(bool aSelected)
+{
+  mSelected = aSelected;
+  return NS_OK;
+}
+
+/* PaymentDetails */
+
+NS_IMPL_ISUPPORTS(PaymentDetails,
+                  nsIPaymentDetails)
+
+PaymentDetails::PaymentDetails(const nsAString& aId,
+                               nsIPaymentItem* aTotalItem,
+                               nsIArray* aDisplayItems,
+                               nsIArray* aShippingOptions,
+                               nsIArray* aModifiers,
+                               const nsAString& aError)
+  : mId(aId)
+  , mTotalItem(aTotalItem)
+  , mDisplayItems(aDisplayItems)
+  , mShippingOptions(aShippingOptions)
+  , mModifiers(aModifiers)
+  , mError(aError)
+{
+}
+
+nsresult
+PaymentDetails::Create(const IPCPaymentDetails& aIPCDetails,
+                       nsIPaymentDetails** aDetails)
+{
+  NS_ENSURE_ARG_POINTER(aDetails);
+
+  nsCOMPtr<nsIPaymentItem> total;
+  nsresult rv = PaymentItem::Create(aIPCDetails.total(), getter_AddRefs(total));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> displayItems;
+  if (aIPCDetails.displayItemsPassed()) {
+    nsCOMPtr<nsIMutableArray> items = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(items);
+    for (const IPCPaymentItem& displayItem : aIPCDetails.displayItems()) {
+      nsCOMPtr<nsIPaymentItem> item;
+      rv = PaymentItem::Create(displayItem, getter_AddRefs(item));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = items->AppendElement(item, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    displayItems = items.forget();
+  }
+
+  nsCOMPtr<nsIArray> shippingOptions;
+  if (aIPCDetails.shippingOptionsPassed()) {
+    nsCOMPtr<nsIMutableArray> options = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(options);
+    for (const IPCPaymentShippingOption& shippingOption : aIPCDetails.shippingOptions()) {
+      nsCOMPtr<nsIPaymentShippingOption> option;
+      rv = PaymentShippingOption::Create(shippingOption, getter_AddRefs(option));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = options->AppendElement(option, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    shippingOptions = options.forget();
+  }
+
+  nsCOMPtr<nsIArray> modifiers;
+  if (aIPCDetails.modifiersPassed()) {
+    nsCOMPtr<nsIMutableArray> detailsModifiers = do_CreateInstance(NS_ARRAY_CONTRACTID);
+    MOZ_ASSERT(detailsModifiers);
+    for (const IPCPaymentDetailsModifier& modifier : aIPCDetails.modifiers()) {
+      nsCOMPtr<nsIPaymentDetailsModifier> detailsModifier;
+      rv = PaymentDetailsModifier::Create(modifier, getter_AddRefs(detailsModifier));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      rv = detailsModifiers->AppendElement(detailsModifier, false);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+    }
+    modifiers = detailsModifiers.forget();
+  }
+
+  nsCOMPtr<nsIPaymentDetails> details =
+    new PaymentDetails(aIPCDetails.id(), total, displayItems, shippingOptions,
+                       modifiers, aIPCDetails.error());
+
+  details.forget(aDetails);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetId(nsAString& aId)
+{
+  aId = mId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetTotalItem(nsIPaymentItem** aTotalItem)
+{
+  NS_ENSURE_ARG_POINTER(aTotalItem);
+  MOZ_ASSERT(mTotalItem);
+  nsCOMPtr<nsIPaymentItem> total = mTotalItem;
+  total.forget(aTotalItem);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetDisplayItems(nsIArray** aDisplayItems)
+{
+  NS_ENSURE_ARG_POINTER(aDisplayItems);
+  nsCOMPtr<nsIArray> displayItems = mDisplayItems;
+  displayItems.forget(aDisplayItems);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetShippingOptions(nsIArray** aShippingOptions)
+{
+  NS_ENSURE_ARG_POINTER(aShippingOptions);
+  nsCOMPtr<nsIArray> options = mShippingOptions;
+  options.forget(aShippingOptions);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetModifiers(nsIArray** aModifiers)
+{
+  NS_ENSURE_ARG_POINTER(aModifiers);
+  nsCOMPtr<nsIArray> modifiers = mModifiers;
+  modifiers.forget(aModifiers);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::GetError(nsAString& aError)
+{
+  aError = mError;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentDetails::Update(nsIPaymentDetails* aDetails)
+{
+  MOZ_ASSERT(aDetails);
+  /*
+   * According to the spec [1], update the attributes if they present in new
+   * details (i.e., PaymentDetailsUpdate); otherwise, keep original value.
+   * Note |id| comes only from initial details (i.e., PaymentDetailsInit) and
+   * |error| only from new details.
+   *
+   *   [1] https://www.w3.org/TR/payment-request/#updatewith-method
+   */
+
+  nsresult rv = aDetails->GetTotalItem(getter_AddRefs(mTotalItem));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  nsCOMPtr<nsIArray> displayItems;
+  rv = aDetails->GetDisplayItems(getter_AddRefs(displayItems));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (displayItems) {
+    mDisplayItems = displayItems;
+  }
+
+  nsCOMPtr<nsIArray> shippingOptions;
+  rv = aDetails->GetShippingOptions(getter_AddRefs(shippingOptions));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (shippingOptions) {
+    mShippingOptions = shippingOptions;
+  }
+
+  nsCOMPtr<nsIArray> modifiers;
+  rv = aDetails->GetModifiers(getter_AddRefs(modifiers));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  if (modifiers) {
+    mModifiers = modifiers;
+  }
+
+  rv = aDetails->GetError(mError);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  return NS_OK;
+
+}
+/* PaymentOptions */
+
+NS_IMPL_ISUPPORTS(PaymentOptions,
+                  nsIPaymentOptions)
+
+PaymentOptions::PaymentOptions(const bool aRequestPayerName,
+                               const bool aRequestPayerEmail,
+                               const bool aRequestPayerPhone,
+                               const bool aRequestShipping,
+                               const nsAString& aShippingType)
+  : mRequestPayerName(aRequestPayerName)
+  , mRequestPayerEmail(aRequestPayerEmail)
+  , mRequestPayerPhone(aRequestPayerPhone)
+  , mRequestShipping(aRequestShipping)
+  , mShippingType(aShippingType)
+{
+}
+
+nsresult
+PaymentOptions::Create(const IPCPaymentOptions& aIPCOptions,
+                       nsIPaymentOptions** aOptions)
+{
+  NS_ENSURE_ARG_POINTER(aOptions);
+
+  nsCOMPtr<nsIPaymentOptions> options =
+    new PaymentOptions(aIPCOptions.requestPayerName(),
+                       aIPCOptions.requestPayerEmail(),
+                       aIPCOptions.requestPayerPhone(),
+                       aIPCOptions.requestShipping(),
+                       aIPCOptions.shippingType());
+  options.forget(aOptions);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestPayerName(bool* aRequestPayerName)
+{
+  NS_ENSURE_ARG_POINTER(aRequestPayerName);
+  *aRequestPayerName = mRequestPayerName;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestPayerEmail(bool* aRequestPayerEmail)
+{
+  NS_ENSURE_ARG_POINTER(aRequestPayerEmail);
+  *aRequestPayerEmail = mRequestPayerEmail;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestPayerPhone(bool* aRequestPayerPhone)
+{
+  NS_ENSURE_ARG_POINTER(aRequestPayerPhone);
+  *aRequestPayerPhone = mRequestPayerPhone;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetRequestShipping(bool* aRequestShipping)
+{
+  NS_ENSURE_ARG_POINTER(aRequestShipping);
+  *aRequestShipping = mRequestShipping;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentOptions::GetShippingType(nsAString& aShippingType)
+{
+  aShippingType = mShippingType;
+  return NS_OK;
+}
+
+/* PaymentReqeust */
+
+NS_IMPL_ISUPPORTS(PaymentRequest,
+                  nsIPaymentRequest)
+
+PaymentRequest::PaymentRequest(const uint64_t aTabId,
+                               const nsAString& aRequestId,
+                               nsIArray* aPaymentMethods,
+                               nsIPaymentDetails* aPaymentDetails,
+                               nsIPaymentOptions* aPaymentOptions)
+  : mTabId(aTabId)
+  , mRequestId(aRequestId)
+  , mPaymentMethods(aPaymentMethods)
+  , mPaymentDetails(aPaymentDetails)
+  , mPaymentOptions(aPaymentOptions)
+{
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetTabId(uint64_t* aTabId)
+{
+  NS_ENSURE_ARG_POINTER(aTabId);
+  *aTabId = mTabId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetRequestId(nsAString& aRequestId)
+{
+  aRequestId = mRequestId;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetPaymentMethods(nsIArray** aPaymentMethods)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentMethods);
+  MOZ_ASSERT(mPaymentMethods);
+  nsCOMPtr<nsIArray> methods = mPaymentMethods;
+  methods.forget(aPaymentMethods);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetPaymentDetails(nsIPaymentDetails** aPaymentDetails)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentDetails);
+  MOZ_ASSERT(mPaymentDetails);
+  nsCOMPtr<nsIPaymentDetails> details = mPaymentDetails;
+  details.forget(aPaymentDetails);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::GetPaymentOptions(nsIPaymentOptions** aPaymentOptions)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentOptions);
+  MOZ_ASSERT(mPaymentOptions);
+  nsCOMPtr<nsIPaymentOptions> options = mPaymentOptions;
+  options.forget(aPaymentOptions);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequest::UpdatePaymentDetails(nsIPaymentDetails* aPaymentDetails)
+{
+  MOZ_ASSERT(aPaymentDetails);
+  return mPaymentDetails->Update(aPaymentDetails);
+}
+
+} // end of namespace payment
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestData.h
@@ -0,0 +1,199 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentRequestData_h
+#define mozilla_dom_PaymentRequestData_h
+
+#include "nsIPaymentRequest.h"
+#include "nsCOMPtr.h"
+#include "mozilla/dom/PPaymentRequest.h"
+
+namespace mozilla {
+namespace dom {
+namespace payments {
+
+class PaymentMethodData final : public nsIPaymentMethodData
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTMETHODDATA
+
+  static nsresult Create(const IPCPaymentMethodData& aIPCMethodData,
+                         nsIPaymentMethodData** aMethodData);
+
+private:
+  PaymentMethodData(nsIArray* aSupportedMethods,
+                    const nsAString& aData);
+
+  ~PaymentMethodData() = default;
+
+  nsCOMPtr<nsIArray> mSupportedMethods;
+  nsString mData;
+};
+
+class PaymentCurrencyAmount final : public nsIPaymentCurrencyAmount
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTCURRENCYAMOUNT
+
+  static nsresult Create(const IPCPaymentCurrencyAmount& aIPCAmount,
+                         nsIPaymentCurrencyAmount** aAmount);
+
+private:
+  PaymentCurrencyAmount(const nsAString& aCurrency,
+                        const nsAString& aValue);
+
+  ~PaymentCurrencyAmount() = default;
+
+  nsString mCurrency;
+  nsString mValue;
+};
+
+class PaymentItem final : public nsIPaymentItem
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTITEM
+
+  static nsresult Create(const IPCPaymentItem& aIPCItem, nsIPaymentItem** aItem);
+
+private:
+  PaymentItem(const nsAString& aLabel,
+              nsIPaymentCurrencyAmount* aAmount,
+              const bool aPending);
+
+  ~PaymentItem() = default;
+
+  nsString mLabel;
+  nsCOMPtr<nsIPaymentCurrencyAmount> mAmount;
+  bool mPending;
+};
+
+class PaymentDetailsModifier final : public nsIPaymentDetailsModifier
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTDETAILSMODIFIER
+
+  static nsresult Create(const IPCPaymentDetailsModifier& aIPCModifier,
+                         nsIPaymentDetailsModifier** aModifier);
+
+private:
+  PaymentDetailsModifier(nsIArray* aSupportedMethods,
+                         nsIPaymentItem* aTotal,
+                         nsIArray* aAdditionalDisplayItems,
+                         const nsAString& aData);
+
+  ~PaymentDetailsModifier() = default;
+
+  nsCOMPtr<nsIArray> mSupportedMethods;
+  nsCOMPtr<nsIPaymentItem> mTotal;
+  nsCOMPtr<nsIArray> mAdditionalDisplayItems;
+  nsString mData;
+};
+
+class PaymentShippingOption final : public nsIPaymentShippingOption
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTSHIPPINGOPTION
+
+  static nsresult Create(const IPCPaymentShippingOption& aIPCOption,
+                         nsIPaymentShippingOption** aOption);
+
+private:
+  PaymentShippingOption(const nsAString& aId,
+                        const nsAString& aLabel,
+                        nsIPaymentCurrencyAmount* aAmount,
+                        const bool aSelected=false);
+
+  ~PaymentShippingOption() = default;
+
+  nsString mId;
+  nsString mLabel;
+  nsCOMPtr<nsIPaymentCurrencyAmount> mAmount;
+  bool mSelected;
+};
+
+class PaymentDetails final : public nsIPaymentDetails
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTDETAILS
+
+
+  static nsresult Create(const IPCPaymentDetails& aIPCDetails,
+                         nsIPaymentDetails** aDetails);
+private:
+  PaymentDetails(const nsAString& aId,
+                 nsIPaymentItem* aTotalItem,
+                 nsIArray* aDisplayItems,
+                 nsIArray* aShippingOptions,
+                 nsIArray* aModifiers,
+                 const nsAString& aError);
+
+  ~PaymentDetails() = default;
+
+  nsString mId;
+  nsCOMPtr<nsIPaymentItem> mTotalItem;
+  nsCOMPtr<nsIArray> mDisplayItems;
+  nsCOMPtr<nsIArray> mShippingOptions;
+  nsCOMPtr<nsIArray> mModifiers;
+  nsString mError;
+};
+
+class PaymentOptions final : public nsIPaymentOptions
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTOPTIONS
+
+  static nsresult Create(const IPCPaymentOptions& aIPCOptions,
+                         nsIPaymentOptions** aOptions);
+
+private:
+  PaymentOptions(const bool aRequestPayerName,
+                 const bool aRequestPayerEmail,
+                 const bool aRequestPayerPhone,
+                 const bool aRequestShipping,
+                 const nsAString& aShippintType);
+  ~PaymentOptions() = default;
+
+  bool mRequestPayerName;
+  bool mRequestPayerEmail;
+  bool mRequestPayerPhone;
+  bool mRequestShipping;
+  nsString mShippingType;
+};
+
+class PaymentRequest final : public nsIPaymentRequest
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTREQUEST
+
+  PaymentRequest(const uint64_t aTabId,
+                 const nsAString& aRequestId,
+                 nsIArray* aPaymentMethods,
+                 nsIPaymentDetails* aPaymentDetails,
+                 nsIPaymentOptions* aPaymentOptions);
+
+private:
+  ~PaymentRequest() = default;
+
+  uint64_t mTabId;
+  nsString mRequestId;
+  nsCOMPtr<nsIArray> mPaymentMethods;
+  nsCOMPtr<nsIPaymentDetails> mPaymentDetails;
+  nsCOMPtr<nsIPaymentOptions> mPaymentOptions;
+};
+
+} // end of namespace payment
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -0,0 +1,386 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "PaymentRequestManager.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/dom/ContentChild.h"
+#include "mozilla/dom/TabChild.h"
+#include "mozilla/dom/PaymentRequestChild.h"
+#include "nsContentUtils.h"
+#include "nsIJSON.h"
+#include "nsString.h"
+
+namespace mozilla {
+namespace dom {
+namespace {
+
+/*
+ *  Following Convert* functions are used for convert PaymentRequest structs
+ *  to transferable structs for IPC.
+ */
+nsresult
+SerializeFromJSObject(JSObject* aObject, nsAString& aSerializedObject){
+  nsCOMPtr<nsIJSON> serializer = do_CreateInstance("@mozilla.org/dom/json;1");
+  if (NS_WARN_IF(!serializer)) {
+    return NS_ERROR_FAILURE;
+  }
+  JS::Value value = JS::ObjectValue(*aObject);
+  JSContext* cx = nsContentUtils::GetCurrentJSContext();
+  MOZ_ASSERT(cx);
+  return serializer->EncodeFromJSVal(&value, cx, aSerializedObject);
+}
+
+nsresult
+ConvertMethodData(const PaymentMethodData& aMethodData,
+                  IPCPaymentMethodData& aIPCMethodData)
+{
+  // Convert Sequence<nsString> to nsTArray<nsString>
+  nsTArray<nsString> supportedMethods;
+  for (const nsString& method : aMethodData.mSupportedMethods) {
+    supportedMethods.AppendElement(method);
+  }
+
+  // Convert JSObject to a serialized string
+  nsAutoString serializedData;
+  if (aMethodData.mData.WasPassed()) {
+    nsresult rv = SerializeFromJSObject(aMethodData.mData.Value(), serializedData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+  aIPCMethodData = IPCPaymentMethodData(supportedMethods, serializedData);
+  return NS_OK;
+}
+
+void
+ConvertCurrencyAmount(const PaymentCurrencyAmount& aAmount,
+                      IPCPaymentCurrencyAmount& aIPCCurrencyAmount)
+{
+  aIPCCurrencyAmount = IPCPaymentCurrencyAmount(aAmount.mCurrency, aAmount.mValue);
+}
+
+void
+ConvertItem(const PaymentItem& aItem, IPCPaymentItem& aIPCItem)
+{
+  IPCPaymentCurrencyAmount amount;
+  ConvertCurrencyAmount(aItem.mAmount, amount);
+  aIPCItem = IPCPaymentItem(aItem.mLabel, amount, aItem.mPending);
+}
+
+nsresult
+ConvertModifier(const PaymentDetailsModifier& aModifier,
+                IPCPaymentDetailsModifier& aIPCModifier)
+{
+  // Convert Sequence<nsString> to nsTArray<nsString>
+  nsTArray<nsString> supportedMethods;
+  for (const nsString& method : aModifier.mSupportedMethods) {
+    supportedMethods.AppendElement(method);
+  }
+
+  // Convert JSObject to a serialized string
+  nsAutoString serializedData;
+  if (aModifier.mData.WasPassed()) {
+    nsresult rv = SerializeFromJSObject(aModifier.mData.Value(), serializedData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+
+  IPCPaymentItem total;
+  ConvertItem(aModifier.mTotal, total);
+
+  nsTArray<IPCPaymentItem> additionalDisplayItems;
+  if (aModifier.mAdditionalDisplayItems.WasPassed()) {
+    for (const PaymentItem& item : aModifier.mAdditionalDisplayItems.Value()) {
+      IPCPaymentItem displayItem;
+      ConvertItem(item, displayItem);
+      additionalDisplayItems.AppendElement(displayItem);
+    }
+  }
+  aIPCModifier = IPCPaymentDetailsModifier(supportedMethods,
+                                          total,
+                                          additionalDisplayItems,
+                                          serializedData,
+                                          aModifier.mAdditionalDisplayItems.WasPassed());
+  return NS_OK;
+}
+
+void
+ConvertShippingOption(const PaymentShippingOption& aOption,
+                      IPCPaymentShippingOption& aIPCOption)
+{
+  IPCPaymentCurrencyAmount amount;
+  ConvertCurrencyAmount(aOption.mAmount, amount);
+  aIPCOption = IPCPaymentShippingOption(aOption.mId, aOption.mLabel, amount, aOption.mSelected);
+}
+
+nsresult
+ConvertDetailsBase(const PaymentDetailsBase& aDetails,
+                   nsTArray<IPCPaymentItem>& aDisplayItems,
+                   nsTArray<IPCPaymentShippingOption>& aShippingOptions,
+                   nsTArray<IPCPaymentDetailsModifier>& aModifiers)
+{
+  if (aDetails.mDisplayItems.WasPassed()) {
+    for (const PaymentItem& item : aDetails.mDisplayItems.Value()) {
+      IPCPaymentItem displayItem;
+      ConvertItem(item, displayItem);
+      aDisplayItems.AppendElement(displayItem);
+    }
+  }
+  if (aDetails.mShippingOptions.WasPassed()) {
+    for (const PaymentShippingOption& option : aDetails.mShippingOptions.Value()) {
+      IPCPaymentShippingOption shippingOption;
+      ConvertShippingOption(option, shippingOption);
+      aShippingOptions.AppendElement(shippingOption);
+    }
+  }
+  if (aDetails.mModifiers.WasPassed()) {
+    for (const PaymentDetailsModifier& modifier : aDetails.mModifiers.Value()) {
+      IPCPaymentDetailsModifier detailsModifier;
+      nsresult rv = ConvertModifier(modifier, detailsModifier);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+      aModifiers.AppendElement(detailsModifier);
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+ConvertDetailsInit(const PaymentDetailsInit& aDetails,
+                   IPCPaymentDetails& aIPCDetails)
+{
+  // Convert PaymentDetailsBase members
+  nsTArray<IPCPaymentItem> displayItems;
+  nsTArray<IPCPaymentShippingOption> shippingOptions;
+  nsTArray<IPCPaymentDetailsModifier> modifiers;
+  nsresult rv = ConvertDetailsBase(aDetails, displayItems, shippingOptions, modifiers);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  // Convert |id|
+  nsString id(EmptyString());
+  if (aDetails.mId.WasPassed()) {
+    id = aDetails.mId.Value();
+  }
+
+  // Convert required |total|
+  IPCPaymentItem total;
+  ConvertItem(aDetails.mTotal, total);
+
+  aIPCDetails = IPCPaymentDetails(id,
+                                  total,
+                                  displayItems,
+                                  shippingOptions,
+                                  modifiers,
+                                  EmptyString(), // error message
+                                  aDetails.mDisplayItems.WasPassed(),
+                                  aDetails.mShippingOptions.WasPassed(),
+                                  aDetails.mModifiers.WasPassed());
+  return NS_OK;
+}
+
+void
+ConvertOptions(const PaymentOptions& aOptions,
+               IPCPaymentOptions& aIPCOption)
+{
+  uint8_t shippingTypeIndex = static_cast<uint8_t>(aOptions.mShippingType);
+  nsString shippingType(NS_LITERAL_STRING("shipping"));
+  if (shippingTypeIndex < ArrayLength(PaymentShippingTypeValues::strings)) {
+    shippingType.AssignASCII(
+      PaymentShippingTypeValues::strings[shippingTypeIndex].value);
+  }
+  aIPCOption = IPCPaymentOptions(aOptions.mRequestPayerName,
+                                 aOptions.mRequestPayerEmail,
+                                 aOptions.mRequestPayerPhone,
+                                 aOptions.mRequestShipping,
+                                 shippingType);
+}
+} // end of namespace
+
+/* PaymentRequestManager */
+
+StaticRefPtr<PaymentRequestManager> gPaymentManager;
+
+nsresult
+PaymentRequestManager::GetPaymentChild(PaymentRequest* aRequest,
+                                       PaymentRequestChild** aChild)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+  NS_ENSURE_ARG_POINTER(aChild);
+  *aChild = nullptr;
+
+  RefPtr<PaymentRequestChild> paymentChild;
+  if (mPaymentChildHash.Get(aRequest, getter_AddRefs(paymentChild))) {
+    paymentChild.forget(aChild);
+    return NS_OK;
+  }
+
+  nsPIDOMWindowInner* win = aRequest->GetOwner();
+  NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
+  TabChild* tabChild = TabChild::GetFrom(win->GetDocShell());
+  NS_ENSURE_TRUE(tabChild, NS_ERROR_FAILURE);
+  nsAutoString requestId;
+  aRequest->GetInternalId(requestId);
+
+  // Only one payment request can interact with user at the same time.
+  // Before we create a new PaymentRequestChild, make sure there is no other
+  // payment request are interacting on the same tab.
+  for (auto iter = mPaymentChildHash.ConstIter(); !iter.Done(); iter.Next()) {
+    RefPtr<PaymentRequest> request = iter.Key();
+    if (request->Equals(requestId)) {
+      continue;
+    }
+    nsPIDOMWindowInner* requestOwner = request->GetOwner();
+    NS_ENSURE_TRUE(requestOwner, NS_ERROR_FAILURE);
+    TabChild* tmpChild = TabChild::GetFrom(requestOwner->GetDocShell());
+    NS_ENSURE_TRUE(tmpChild, NS_ERROR_FAILURE);
+    if (tmpChild->GetTabId() == tabChild->GetTabId()) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
+  paymentChild = new PaymentRequestChild();
+  tabChild->SendPPaymentRequestConstructor(paymentChild);
+  if (!mPaymentChildHash.Put(aRequest, paymentChild, mozilla::fallible) ) {
+    return NS_ERROR_OUT_OF_MEMORY;
+  }
+  paymentChild.forget(aChild);
+  return NS_OK;
+}
+
+nsresult
+PaymentRequestManager::ReleasePaymentChild(PaymentRequestChild* aPaymentChild)
+{
+  NS_ENSURE_ARG_POINTER(aPaymentChild);
+  for (auto iter = mPaymentChildHash.ConstIter(); !iter.Done(); iter.Next()) {
+    RefPtr<PaymentRequestChild> child = iter.Data();
+    if (NS_WARN_IF(!child)) {
+      return NS_ERROR_FAILURE;
+    }
+    if (child == aPaymentChild) {
+      return ReleasePaymentChild(iter.Key());
+    }
+  }
+  return NS_OK;
+}
+
+nsresult
+PaymentRequestManager::ReleasePaymentChild(PaymentRequest* aRequest)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+
+  RefPtr<PaymentRequestChild> paymentChild;
+  if(!mPaymentChildHash.Remove(aRequest, getter_AddRefs(paymentChild))) {
+    return NS_ERROR_FAILURE;
+  }
+  if (NS_WARN_IF(!paymentChild)) {
+    return NS_ERROR_FAILURE;
+  }
+  paymentChild->MaybeDelete();
+  return NS_OK;
+}
+
+already_AddRefed<PaymentRequestManager>
+PaymentRequestManager::GetSingleton()
+{
+  if (!gPaymentManager) {
+    gPaymentManager = new PaymentRequestManager();
+    ClearOnShutdown(&gPaymentManager);
+  }
+  RefPtr<PaymentRequestManager> manager = gPaymentManager;
+  return manager.forget();
+}
+
+already_AddRefed<PaymentRequest>
+PaymentRequestManager::GetPaymentRequestById(const nsAString& aRequestId)
+{
+  for (const RefPtr<PaymentRequest>& request : mRequestQueue) {
+    if (request->Equals(aRequestId)) {
+      RefPtr<PaymentRequest> paymentRequest = request;
+      return paymentRequest.forget();
+    }
+  }
+  return nullptr;
+}
+
+nsresult
+PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow,
+                                     const Sequence<PaymentMethodData>& aMethodData,
+                                     const PaymentDetailsInit& aDetails,
+                                     const PaymentOptions& aOptions,
+                                     PaymentRequest** aRequest)
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  NS_ENSURE_ARG_POINTER(aRequest);
+  *aRequest = nullptr;
+
+  nsresult rv;
+  nsTArray<IPCPaymentMethodData> methodData;
+  for (const PaymentMethodData& data : aMethodData) {
+    IPCPaymentMethodData ipcMethodData;
+    rv = ConvertMethodData(data, ipcMethodData);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    methodData.AppendElement(ipcMethodData);
+  }
+
+  IPCPaymentDetails details;
+  rv = ConvertDetailsInit(aDetails, details);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  IPCPaymentOptions options;
+  ConvertOptions(aOptions, options);
+
+  RefPtr<PaymentRequest> paymentRequest = PaymentRequest::CreatePaymentRequest(aWindow, rv);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  /*
+   *  Set request's |mId| to details.id if details.id exists.
+   *  Otherwise, set |mId| to internal id.
+   */
+  nsAutoString requestId;
+  if (aDetails.mId.WasPassed() && !aDetails.mId.Value().IsEmpty()) {
+    requestId = aDetails.mId.Value();
+  } else {
+    paymentRequest->GetInternalId(requestId);
+  }
+  paymentRequest->SetId(requestId);
+
+  RefPtr<PaymentRequestChild> requestChild;
+  rv = GetPaymentChild(paymentRequest, getter_AddRefs(requestChild));
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  IPCPaymentCreateActionRequest request(requestId,
+                                        methodData,
+                                        details,
+                                        options);
+  rv = requestChild->RequestPayment(request);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  rv = ReleasePaymentChild(paymentRequest);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+
+  mRequestQueue.AppendElement(paymentRequest);
+  paymentRequest.forget(aRequest);
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestManager.h
@@ -0,0 +1,65 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentRequestManager_h
+#define mozilla_dom_PaymentRequestManager_h
+
+#include "nsISupports.h"
+#include "PaymentRequest.h"
+#include "mozilla/dom/PaymentRequestBinding.h"
+#include "nsCOMPtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentRequestChild;
+
+/*
+ *  PaymentRequestManager is a singleton used to manage the created PaymentRequests.
+ *  It is also the communication agent to chrome proces.
+ */
+class PaymentRequestManager final
+{
+public:
+  NS_INLINE_DECL_REFCOUNTING(PaymentRequestManager)
+
+  static already_AddRefed<PaymentRequestManager> GetSingleton();
+
+  already_AddRefed<PaymentRequest>
+  GetPaymentRequestById(const nsAString& aRequestId);
+
+  /*
+   *  This method is used to create PaymentRequest object and send corresponding
+   *  data to chrome process for internal payment creation, such that content
+   *  process can ask specific task by sending requestId only.
+   */
+  nsresult
+  CreatePayment(nsPIDOMWindowInner* aWindow,
+                const Sequence<PaymentMethodData>& aMethodData,
+                const PaymentDetailsInit& aDetails,
+                const PaymentOptions& aOptions,
+                PaymentRequest** aRequest);
+
+  nsresult
+  ReleasePaymentChild(PaymentRequestChild* aPaymentChild);
+protected:
+  PaymentRequestManager() = default;
+  ~PaymentRequestManager() = default;
+
+  nsresult GetPaymentChild(PaymentRequest* aRequest,
+                           PaymentRequestChild** aPaymentChild);
+  nsresult ReleasePaymentChild(PaymentRequest* aRequest);
+
+  // The container for the created PaymentRequests
+  nsTArray<RefPtr<PaymentRequest>> mRequestQueue;
+  nsRefPtrHashtable<nsRefPtrHashKey<PaymentRequest>, PaymentRequestChild> mPaymentChildHash;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestModule.cpp
@@ -0,0 +1,52 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "PaymentActionRequest.h"
+#include "PaymentRequestService.h"
+
+using mozilla::dom::PaymentActionRequest;
+using mozilla::dom::PaymentCreateActionRequest;
+using mozilla::dom::PaymentRequestService;
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentActionRequest)
+NS_GENERIC_FACTORY_CONSTRUCTOR(PaymentCreateActionRequest)
+NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(PaymentRequestService,
+                                         PaymentRequestService::GetSingleton)
+
+NS_DEFINE_NAMED_CID(NS_PAYMENT_ACTION_REQUEST_CID);
+NS_DEFINE_NAMED_CID(NS_PAYMENT_CREATE_ACTION_REQUEST_CID);
+NS_DEFINE_NAMED_CID(NS_PAYMENT_REQUEST_SERVICE_CID);
+
+static const mozilla::Module::CIDEntry kPaymentRequestCIDs[] = {
+  { &kNS_PAYMENT_ACTION_REQUEST_CID, false, nullptr, PaymentActionRequestConstructor},
+  { &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID, false, nullptr, PaymentCreateActionRequestConstructor},
+  { &kNS_PAYMENT_REQUEST_SERVICE_CID, true, nullptr, PaymentRequestServiceConstructor },
+  { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kPaymentRequestContracts[] = {
+  { NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_ACTION_REQUEST_CID },
+  { NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID, &kNS_PAYMENT_CREATE_ACTION_REQUEST_CID },
+  { NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID, &kNS_PAYMENT_REQUEST_SERVICE_CID },
+  { nullptr }
+};
+
+static const mozilla::Module::CategoryEntry kPaymentRequestCategories[] = {
+  { "payment-request", "PaymentActionRequest", NS_PAYMENT_ACTION_REQUEST_CONTRACT_ID },
+  { "payment-request", "PaymentCreateActionRequest", NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID },
+  { "payment-request", "PaymentRequestService", NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID },
+  { nullptr }
+};
+
+static const mozilla::Module kPaymentRequestModule = {
+  mozilla::Module::kVersion,
+  kPaymentRequestCIDs,
+  kPaymentRequestContracts,
+  kPaymentRequestCategories
+};
+
+NSMODULE_DEFN(PaymentRequestModule) = &kPaymentRequestModule;
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestService.cpp
@@ -0,0 +1,194 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/ClearOnShutdown.h"
+#include "PaymentRequestData.h"
+#include "PaymentRequestService.h"
+
+namespace mozilla {
+namespace dom {
+
+StaticRefPtr<PaymentRequestService> gPaymentService;
+
+namespace {
+
+class PaymentRequestEnumerator final : public nsISimpleEnumerator
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSISIMPLEENUMERATOR
+
+  PaymentRequestEnumerator()
+    : mIndex(0)
+  {}
+private:
+  ~PaymentRequestEnumerator() = default;
+  uint32_t mIndex;
+};
+
+NS_IMPL_ISUPPORTS(PaymentRequestEnumerator, nsISimpleEnumerator)
+
+NS_IMETHODIMP
+PaymentRequestEnumerator::HasMoreElements(bool* aReturn)
+{
+  NS_ENSURE_ARG_POINTER(aReturn);
+  *aReturn = false;
+  if (NS_WARN_IF(!gPaymentService)) {
+    return NS_ERROR_FAILURE;
+  }
+  RefPtr<PaymentRequestService> service = gPaymentService;
+  *aReturn = mIndex < service->NumPayments();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestEnumerator::GetNext(nsISupports** aItem)
+{
+  NS_ENSURE_ARG_POINTER(aItem);
+  if (NS_WARN_IF(!gPaymentService)) {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsIPaymentRequest> request =
+    gPaymentService->GetPaymentRequestByIndex(mIndex);
+  if (NS_WARN_IF(!request)) {
+    return NS_ERROR_FAILURE;
+  }
+  nsCOMPtr<nsISupports> item = do_QueryInterface(request);
+  if (NS_WARN_IF(!item)) {
+    return NS_ERROR_FAILURE;
+  }
+  mIndex++;
+  item.forget(aItem);
+  return NS_OK;
+}
+
+} // end of anonymous namespace
+
+/* PaymentRequestService */
+
+NS_IMPL_ISUPPORTS(PaymentRequestService,
+                  nsIPaymentRequestService)
+
+already_AddRefed<PaymentRequestService>
+PaymentRequestService::GetSingleton()
+{
+  MOZ_ASSERT(NS_IsMainThread());
+  if (!gPaymentService) {
+    gPaymentService = new PaymentRequestService();
+    ClearOnShutdown(&gPaymentService);
+  }
+  RefPtr<PaymentRequestService> service = gPaymentService;
+  return service.forget();
+}
+
+uint32_t
+PaymentRequestService::NumPayments() const
+{
+  return mRequestQueue.Length();
+}
+
+already_AddRefed<nsIPaymentRequest>
+PaymentRequestService::GetPaymentRequestByIndex(const uint32_t aIndex)
+{
+  if (aIndex >= mRequestQueue.Length()) {
+    return nullptr;
+  }
+  nsCOMPtr<nsIPaymentRequest> request = mRequestQueue[aIndex];
+  MOZ_ASSERT(request);
+  return request.forget();
+}
+
+NS_IMETHODIMP
+PaymentRequestService::GetPaymentRequestById(const nsAString& aRequestId,
+                                             nsIPaymentRequest** aRequest)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+  *aRequest = nullptr;
+  uint32_t numRequests = mRequestQueue.Length();
+  for (uint32_t index = 0; index < numRequests; ++index) {
+    nsCOMPtr<nsIPaymentRequest> request = mRequestQueue[index];
+    MOZ_ASSERT(request);
+    nsAutoString requestId;
+    nsresult rv = request->GetRequestId(requestId);
+    NS_ENSURE_SUCCESS(rv, rv);
+    if (requestId == aRequestId) {
+      request.forget(aRequest);
+      break;
+    }
+  }
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestService::Enumerate(nsISimpleEnumerator** aEnumerator)
+{
+  NS_ENSURE_ARG_POINTER(aEnumerator);
+  nsCOMPtr<nsISimpleEnumerator> enumerator = new PaymentRequestEnumerator();
+  enumerator.forget(aEnumerator);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+PaymentRequestService::RequestPayment(nsIPaymentActionRequest* aRequest)
+{
+  NS_ENSURE_ARG_POINTER(aRequest);
+  uint32_t type;
+  nsresult rv = aRequest->GetType(&type);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  switch (type) {
+    case nsIPaymentActionRequest::CREATE_ACTION: {
+      nsCOMPtr<nsIPaymentCreateActionRequest> request =
+        do_QueryInterface(aRequest);
+      MOZ_ASSERT(request);
+      uint64_t tabId;
+      rv = request->GetTabId(&tabId);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      nsString requestId;
+      rv = request->GetRequestId(requestId);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return rv;
+      }
+
+      nsCOMPtr<nsIArray> methodData;
+      rv = request->GetMethodData(getter_AddRefs(methodData));
+      if (NS_WARN_IF(NS_FAILED(rv) || !methodData)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      nsCOMPtr<nsIPaymentDetails> details;
+      rv = request->GetDetails(getter_AddRefs(details));
+      if (NS_WARN_IF(NS_FAILED(rv) || !details)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      nsCOMPtr<nsIPaymentOptions> options;
+      rv = request->GetOptions(getter_AddRefs(options));
+      if (NS_WARN_IF(NS_FAILED(rv) || !options)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      nsCOMPtr<nsIPaymentRequest> payment =
+         new payments::PaymentRequest(tabId, requestId, methodData, details, options);
+
+      if (!mRequestQueue.AppendElement(payment, mozilla::fallible)) {
+        return NS_ERROR_OUT_OF_MEMORY;
+      }
+      break;
+    }
+    default: {
+      return NS_ERROR_FAILURE;
+    }
+  }
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestService.h
@@ -0,0 +1,45 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentRequestService_h
+#define mozilla_dom_PaymentRequestService_h
+
+#include "nsIPaymentRequest.h"
+#include "nsIPaymentRequestService.h"
+#include "nsISimpleEnumerator.h"
+#include "nsCOMPtr.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+// The implmentation of nsIPaymentRequestService
+
+class PaymentRequestService final : public nsIPaymentRequestService
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIPAYMENTREQUESTSERVICE
+
+  PaymentRequestService() = default;
+
+  static already_AddRefed<PaymentRequestService> GetSingleton();
+
+  already_AddRefed<nsIPaymentRequest>
+  GetPaymentRequestByIndex(const uint32_t index);
+
+  uint32_t NumPayments() const;
+
+private:
+  ~PaymentRequestService() = default;
+
+  FallibleTArray<nsCOMPtr<nsIPaymentRequest>> mRequestQueue;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestUtils.cpp
@@ -0,0 +1,90 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "nsArrayUtils.h"
+#include "PaymentRequestUtils.h"
+#include "nsIMutableArray.h"
+#include "nsISupportsPrimitives.h"
+
+namespace mozilla {
+namespace dom {
+
+nsresult
+ConvertStringstoISupportsStrings(const nsTArray<nsString>& aStrings,
+                                 nsIArray** aIStrings)
+{
+  NS_ENSURE_ARG_POINTER(aIStrings);
+  *aIStrings = nullptr;
+  nsCOMPtr<nsIMutableArray> iStrings = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  for (const nsString& string : aStrings) {
+    nsCOMPtr<nsISupportsString> iString =
+      do_CreateInstance(NS_SUPPORTS_STRING_CONTRACTID);
+    if (NS_WARN_IF(!iString)) {
+      return NS_ERROR_FAILURE;
+    }
+    nsresult rv = iString->SetData(string);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    rv = iStrings->AppendElement(iString, false);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+  }
+  iStrings.forget(aIStrings);
+  return NS_OK;
+}
+
+nsresult
+ConvertISupportsStringstoStrings(nsIArray* aIStrings,
+                                 nsTArray<nsString>& aStrings)
+{
+  NS_ENSURE_ARG_POINTER(aIStrings);
+  uint32_t length;
+  aStrings.Clear();
+  nsresult rv = aIStrings->GetLength(&length);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  for (uint32_t index = 0; index < length; ++index) {
+    nsCOMPtr<nsISupportsString> iString = do_QueryElementAt(aIStrings, index);
+    if (NS_WARN_IF(!iString)) {
+      return NS_ERROR_FAILURE;
+    }
+    nsString string;
+    rv = iString->GetData(string);
+    if (NS_WARN_IF(NS_FAILED(rv))) {
+      return rv;
+    }
+    aStrings.AppendElement(string);
+  }
+  return NS_OK;
+}
+
+nsresult
+CopyISupportsStrings(nsIArray* aSourceStrings, nsIArray** aTargetStrings)
+{
+  NS_ENSURE_ARG_POINTER(aTargetStrings);
+  *aTargetStrings = nullptr;
+  nsCOMPtr<nsIMutableArray> strings = do_CreateInstance(NS_ARRAY_CONTRACTID);
+  uint32_t length;
+  nsresult rv = aSourceStrings->GetLength(&length);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return rv;
+  }
+  for (uint32_t index = 0; index < length; ++index) {
+    nsCOMPtr<nsISupportsString> string = do_QueryElementAt(aSourceStrings, index);
+    if (NS_WARN_IF(!string)) {
+      return NS_ERROR_FAILURE;
+    }
+    strings->AppendElement(string, false);
+  }
+  strings.forget(aTargetStrings);
+  return NS_OK;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/PaymentRequestUtils.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentRequestUtils_h
+#define mozilla_dom_PaymentRequestUtils_h
+
+#include "nsIArray.h"
+#include "nsTArray.h"
+
+namespace mozilla {
+namespace dom {
+
+nsresult
+ConvertStringstoISupportsStrings(const nsTArray<nsString>& aStrings,
+                                 nsIArray** aIStrings);
+
+nsresult
+ConvertISupportsStringstoStrings(nsIArray* aIStrings,
+                                 nsTArray<nsString>& aStrings);
+
+nsresult
+CopyISupportsStrings(nsIArray* aSourceStrings, nsIArray** aTargetStrings);
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PPaymentRequest.ipdl
@@ -0,0 +1,94 @@
+/* -*- Mode: C++; c-basic-offset: 2; 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 {
+
+struct IPCPaymentMethodData
+{
+  nsString[] supportedMethods;
+  nsString data;
+};
+
+struct IPCPaymentCurrencyAmount
+{
+  nsString currency;
+  nsString value;
+};
+
+struct IPCPaymentItem
+{
+  nsString label;
+  IPCPaymentCurrencyAmount amount;
+  bool pending;
+};
+
+struct IPCPaymentDetailsModifier
+{
+  nsString[] supportedMethods;
+  IPCPaymentItem total;
+  IPCPaymentItem[] additionalDisplayItems;
+  nsString data;
+  bool additionalDisplayItemsPassed;
+};
+
+struct IPCPaymentShippingOption
+{
+  nsString id;
+  nsString label;
+  IPCPaymentCurrencyAmount amount;
+  bool selected;
+};
+
+struct IPCPaymentDetails
+{
+  nsString id;
+  IPCPaymentItem total;
+  IPCPaymentItem[] displayItems;
+  IPCPaymentShippingOption[] shippingOptions;
+  IPCPaymentDetailsModifier[] modifiers;
+  nsString error;
+  bool displayItemsPassed;
+  bool shippingOptionsPassed;
+  bool modifiersPassed;
+};
+
+struct IPCPaymentOptions
+{
+  bool requestPayerName;
+  bool requestPayerEmail;
+  bool requestPayerPhone;
+  bool requestShipping;
+  nsString shippingType;
+};
+
+struct IPCPaymentCreateActionRequest
+{
+  nsString requestId;
+  IPCPaymentMethodData[] methodData;
+  IPCPaymentDetails details;
+  IPCPaymentOptions options;
+};
+
+union IPCPaymentActionRequest
+{
+  IPCPaymentCreateActionRequest;
+};
+
+sync protocol PPaymentRequest
+{
+  manager PBrowser;
+
+parent:
+  async __delete__();
+
+  async RequestPayment(IPCPaymentActionRequest aAction);
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestChild.cpp
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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 "PaymentRequestChild.h"
+#include "mozilla/dom/PaymentRequestManager.h"
+
+namespace mozilla {
+namespace dom {
+
+PaymentRequestChild::PaymentRequestChild()
+  : mActorAlive(true)
+{
+}
+
+nsresult
+PaymentRequestChild::RequestPayment(const IPCPaymentActionRequest& aAction)
+{
+  if (!mActorAlive) {
+    return NS_ERROR_FAILURE;
+  }
+  SendRequestPayment(aAction);
+  return NS_OK;
+}
+
+void
+PaymentRequestChild::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorAlive = false;
+  RefPtr<PaymentRequestChild> actor = this;
+  RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+  MOZ_ASSERT(manager);
+  manager->ReleasePaymentChild(actor);
+}
+
+void
+PaymentRequestChild::MaybeDelete()
+{
+  if (mActorAlive) {
+    mActorAlive = false;
+    Send__delete__(this);
+  }
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestChild.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentRequestChild_h
+#define mozilla_dom_PaymentRequestChild_h
+
+#include "mozilla/dom/PPaymentRequestChild.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentRequestChild final : public PPaymentRequestChild
+{
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaymentRequestChild);
+public:
+  PaymentRequestChild();
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+
+  void MaybeDelete();
+
+  nsresult RequestPayment(const IPCPaymentActionRequest& aAction);
+private:
+  ~PaymentRequestChild() = default;
+
+  bool mActorAlive;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestParent.cpp
@@ -0,0 +1,109 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/ipc/InputStreamUtils.h"
+#include "nsArrayUtils.h"
+#include "nsCOMPtr.h"
+#include "nsIMutableArray.h"
+#include "nsIPaymentActionRequest.h"
+#include "nsIPaymentRequestService.h"
+#include "nsISupportsPrimitives.h"
+#include "nsServiceManagerUtils.h"
+#include "PaymentRequestData.h"
+#include "PaymentRequestParent.h"
+
+namespace mozilla {
+namespace dom {
+
+PaymentRequestParent::PaymentRequestParent(uint64_t aTabId)
+  : mActorAlived(true)
+  , mTabId(aTabId)
+{
+}
+
+mozilla::ipc::IPCResult
+PaymentRequestParent::RecvRequestPayment(const IPCPaymentActionRequest& aRequest)
+{
+  MOZ_ASSERT(mActorAlived);
+  nsCOMPtr<nsIPaymentActionRequest> actionRequest;
+  nsresult rv;
+  switch (aRequest.type()) {
+    case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: {
+      IPCPaymentCreateActionRequest request = aRequest;
+
+      nsCOMPtr<nsIMutableArray> methodData = do_CreateInstance(NS_ARRAY_CONTRACTID);
+      MOZ_ASSERT(methodData);
+      for (IPCPaymentMethodData data : request.methodData()) {
+        nsCOMPtr<nsIPaymentMethodData> method;
+        rv = payments::PaymentMethodData::Create(data, getter_AddRefs(method));
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return IPC_FAIL_NO_REASON(this);
+        }
+        rv = methodData->AppendElement(method, false);
+        if (NS_WARN_IF(NS_FAILED(rv))) {
+          return IPC_FAIL_NO_REASON(this);
+        }
+      }
+
+      nsCOMPtr<nsIPaymentDetails> details;
+      rv = payments::PaymentDetails::Create(request.details(), getter_AddRefs(details));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+
+      nsCOMPtr<nsIPaymentOptions> options;
+      rv = payments::PaymentOptions::Create(request.options(), getter_AddRefs(options));
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+
+      nsCOMPtr<nsIPaymentCreateActionRequest> createRequest =
+        do_CreateInstance(NS_PAYMENT_CREATE_ACTION_REQUEST_CONTRACT_ID);
+      if (NS_WARN_IF(!createRequest)) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+      rv = createRequest->InitRequest(request.requestId(),
+                                      mTabId,
+                                      methodData,
+                                      details,
+                                      options);
+      if (NS_WARN_IF(NS_FAILED(rv))) {
+        return IPC_FAIL_NO_REASON(this);
+      }
+
+      actionRequest = do_QueryInterface(createRequest);
+      MOZ_ASSERT(actionRequest);
+      break;
+    }
+    default: {
+      return IPC_FAIL(this, "Unexpected request type");
+    }
+  }
+  nsCOMPtr<nsIPaymentRequestService> service =
+    do_GetService(NS_PAYMENT_REQUEST_SERVICE_CONTRACT_ID);
+  MOZ_ASSERT(service);
+  rv = service->RequestPayment(actionRequest);
+  if (NS_WARN_IF(NS_FAILED(rv))) {
+    return IPC_FAIL_NO_REASON(this);
+  }
+  return IPC_OK();
+}
+
+mozilla::ipc::IPCResult
+PaymentRequestParent::Recv__delete__()
+{
+  mActorAlived = false;
+  return IPC_OK();
+}
+
+void
+PaymentRequestParent::ActorDestroy(ActorDestroyReason aWhy)
+{
+  mActorAlived = false;
+}
+
+} // end of namespace dom
+} // end of namespace mozilla
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/PaymentRequestParent.h
@@ -0,0 +1,40 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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_PaymentRequestParent_h
+#define mozilla_dom_PaymentRequestParent_h
+
+#include "mozilla/dom/PPaymentRequestParent.h"
+#include "nsISupports.h"
+
+namespace mozilla {
+namespace dom {
+
+class PaymentRequestParent final : public PPaymentRequestParent
+{
+public:
+  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaymentRequestParent)
+
+  explicit PaymentRequestParent(uint64_t aTabId);
+
+protected:
+  mozilla::ipc::IPCResult
+  RecvRequestPayment(const IPCPaymentActionRequest& aRequest) override;
+
+  mozilla::ipc::IPCResult Recv__delete__() override;
+
+  void ActorDestroy(ActorDestroyReason aWhy) override;
+private:
+  ~PaymentRequestParent() = default;
+
+  bool mActorAlived;
+  uint64_t mTabId;
+};
+
+} // end of namespace dom
+} // end of namespace mozilla
+
+#endif
new file mode 100644
--- /dev/null
+++ b/dom/payments/ipc/moz.build
@@ -0,0 +1,23 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+EXPORTS.mozilla.dom += [
+    'PaymentRequestChild.h',
+    'PaymentRequestParent.h',
+]
+
+UNIFIED_SOURCES += [
+    'PaymentRequestChild.cpp',
+    'PaymentRequestParent.cpp',
+]
+
+IPDL_SOURCES += [
+    'PPaymentRequest.ipdl',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
new file mode 100644
--- /dev/null
+++ b/dom/payments/moz.build
@@ -0,0 +1,35 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+DIRS += [
+    'ipc',
+]
+
+EXPORTS += [
+    'PaymentRequestData.h',
+    'PaymentRequestService.h',
+]
+
+EXPORTS.mozilla.dom += [
+    'PaymentRequest.h',
+    'PaymentRequestManager.h',
+]
+
+UNIFIED_SOURCES += [
+    'PaymentActionRequest.cpp',
+    'PaymentRequest.cpp',
+    'PaymentRequestData.cpp',
+    'PaymentRequestManager.cpp',
+    'PaymentRequestModule.cpp',
+    'PaymentRequestService.cpp',
+    'PaymentRequestUtils.cpp',
+]
+
+include('/ipc/chromium/chromium-config.mozbuild')
+
+FINAL_LIBRARY = 'xul'
+
+BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser.ini
@@ -0,0 +1,12 @@
+[DEFAULT]
+support-files =
+  head.js
+  simple_payment_request.html
+  multiple_payment_request.html
+
+skipif = !e10s
+[browser_payment_construction.js]
+skipif = !e10s
+[browser_multiple_construction.js]
+skipif = !e10s
+[browser_payment_in_different_tabs.js]
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser_multiple_construction.js
@@ -0,0 +1,30 @@
+"use strict";
+
+// kTestRoot is from head.js
+const kTestPage = kTestRoot + "multiple_payment_request.html";
+
+add_task(function*() {
+  Services.prefs.setBoolPref("dom.payments.request.enabled", true);
+  yield BrowserTestUtils.withNewTab(kTestPage,
+    function*(browser) {
+
+      const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+      ok(paymentSrv, "Fail to get PaymentRequestService.");
+
+      const paymentEnum = paymentSrv.enumerate();
+      ok(paymentEnum.hasMoreElements(), "PaymentRequestService should have at least one payment request.");
+      while (paymentEnum.hasMoreElements()) {
+        let payment = paymentEnum.getNext().QueryInterface(Ci.nsIPaymentRequest);
+        ok(payment, "Fail to get existing payment request.");
+        if (payment.paymentDetails.id == "complex details") {
+          checkComplexPayment(payment);
+        } else if (payment.paymentDetails.id == "simple details") {
+          checkSimplePayment(payment);
+        } else {
+          ok(false, "Unknown payment.");
+        }
+      }
+      Services.prefs.setBoolPref("dom.payments.request.enabled", false);
+    }
+  );
+});
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser_payment_construction.js
@@ -0,0 +1,24 @@
+"use strict";
+
+// kTestRoot is from head.js
+const kTestPage = kTestRoot + "simple_payment_request.html";
+
+add_task(function*() {
+  Services.prefs.setBoolPref("dom.payments.request.enabled", true);
+  yield BrowserTestUtils.withNewTab(kTestPage,
+    function*(browser) {
+
+      const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+      ok(paymentSrv, "Fail to get PaymentRequestService.");
+
+      const paymentEnum = paymentSrv.enumerate();
+      ok(paymentEnum.hasMoreElements(), "PaymentRequestService should have at least one payment request.");
+      while (paymentEnum.hasMoreElements()) {
+        let payment = paymentEnum.getNext().QueryInterface(Ci.nsIPaymentRequest);
+        ok(payment, "Fail to get existing payment request.");
+        checkSimplePayment(payment);
+      }
+      Services.prefs.setBoolPref("dom.payments.request.enabled", false);
+    }
+  );
+});
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/browser_payment_in_different_tabs.js
@@ -0,0 +1,31 @@
+"use strict";
+
+// kTestRoot is from head.js
+const kTestPage = kTestRoot + "simple_payment_request.html";
+
+add_task(function*() {
+  Services.prefs.setBoolPref("dom.payments.request.enabled", true);
+  yield BrowserTestUtils.withNewTab(kTestPage,
+    function*(browser) {
+      yield BrowserTestUtils.withNewTab(kTestPage,
+        function*(browser) {
+          const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
+          ok(paymentSrv, "Fail to get PaymentRequestService.");
+
+          const paymentEnum = paymentSrv.enumerate();
+          ok(paymentEnum.hasMoreElements(), "PaymentRequestService should have at least one payment request.");
+          let tabIds = [];
+          while (paymentEnum.hasMoreElements()) {
+            let payment = paymentEnum.getNext().QueryInterface(Ci.nsIPaymentRequest);
+            ok(payment, "Fail to get existing payment request.");
+            checkSimplePayment(payment);
+            tabIds.push(payment.tabId);
+          }
+          is(tabIds.length, 2, "TabId array length should be 2.");
+          ok(tabIds[0] != tabIds[1], "TabIds should be different.");
+          Services.prefs.setBoolPref("dom.payments.request.enabled", false);
+        }
+      );
+    }
+  );
+});
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/head.js
@@ -0,0 +1,115 @@
+const kTestRoot = getRootDirectory(gTestPath).replace("chrome://mochitests/content",
+                                                      "https://example.com");
+
+function checkSimplePayment(aSimplePayment)
+{
+  // checking the passed PaymentMethods parameter
+  is(aSimplePayment.paymentMethods.length, 1, "paymentMethods' length should be 1.");
+
+  const methodData = aSimplePayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
+  ok(methodData, "Fail to get payment methodData.");
+  is(methodData.supportedMethods.length, 2, "supportedMethods' length should be 2.");
+  let supportedMethod = methodData.supportedMethods.queryElementAt(0, Ci.nsISupportsString);
+  is(supportedMethod, "MyPay", "1st supported method should be 'MyPay'.");
+  supportedMethod = methodData.supportedMethods.queryElementAt(1, Ci.nsISupportsString);
+  is(supportedMethod, "TestPay", "2nd supported method should be 'TestPay'.");
+  is(methodData.data, "", "method data should be empty");
+
+  // checking the passed PaymentDetails parameter
+  const details = aSimplePayment.paymentDetails;
+  is(details.id, "simple details", "details.id should be 'simple details'.");
+  is(details.totalItem.label, "Donation", "total item's label should be 'Donation'.");
+  is(details.totalItem.amount.currency, "USD", "total item's currency should be 'USD'.");
+  is(details.totalItem.amount.value, "55.00", "total item's value should be '55.00'.");
+
+  ok(!details.displayItems, "details.displayItems should be undefined.");
+  ok(!details.modifiers, "details.modifiers should be undefined.");
+  ok(!details.shippingOptions, "details.shippingOptions should be undefined.");
+
+  // checking the default generated PaymentOptions parameter
+  const paymentOptions = aSimplePayment.paymentOptions;
+  ok(!paymentOptions.requestPayerName, "payerName option should be false");
+  ok(!paymentOptions.requestPayerEmail, "payerEmail option should be false");
+  ok(!paymentOptions.requestPayerPhone, "payerPhone option should be false");
+  ok(!paymentOptions.requestShipping, "requestShipping option should be false");
+  is(paymentOptions.shippingType, "shipping", "shippingType option should be 'shipping'");
+}
+
+function checkComplexPayment(aPayment)
+{
+  // checking the passed PaymentMethods parameter
+  is(aPayment.paymentMethods.length, 1, "paymentMethods' length should be 1.");
+
+  const methodData = aPayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
+  ok(methodData, "Fail to get payment methodData.");
+  is(methodData.supportedMethods.length, 2, "supportedMethods' length should be 2.");
+  let supportedMethod = methodData.supportedMethods.queryElementAt(0, Ci.nsISupportsString);
+  is(supportedMethod, "MyPay", "1st supported method should be 'MyPay'.");
+  supportedMethod = methodData.supportedMethods.queryElementAt(1, Ci.nsISupportsString);
+  is(supportedMethod, "TestPay", "2nd supported method should be 'TestPay'.");
+  is(methodData.data, "", "method data should be empty");
+
+  // checking the passed PaymentDetails parameter
+  const details = aPayment.paymentDetails;
+  is(details.id, "complex details", "details.id should be 'complex details'.");
+  is(details.totalItem.label, "Donation", "total item's label should be 'Donation'.");
+  is(details.totalItem.amount.currency, "USD", "total item's currency should be 'USD'.");
+  is(details.totalItem.amount.value, "55.00", "total item's value should be '55.00'.");
+
+  const displayItems = details.displayItems;
+  is(displayItems.length, 2, "displayItems' length should be 2.");
+  let item = displayItems.queryElementAt(0, Ci.nsIPaymentItem);
+  is(item.label, "Original donation amount", "1st display item's label should be 'Original donation amount'.");
+  is(item.amount.currency, "USD", "1st display item's currency should be 'USD'.");
+  is(item.amount.value, "-65.00", "1st display item's value should be '-65.00'.");
+  item = displayItems.queryElementAt(1, Ci.nsIPaymentItem);
+  is(item.label, "Friends and family discount", "2nd display item's label should be 'Friends and family discount'.");
+  is(item.amount.currency, "USD", "2nd display item's currency should be 'USD'.");
+  is(item.amount.value, "10.00", "2nd display item's value should be '10.00'.");
+
+  const modifiers = details.modifiers;
+  is(modifiers.length, 1, "modifiers' length should be 1.");
+
+  const modifier = modifiers.queryElementAt(0, Ci.nsIPaymentDetailsModifier);
+  const modifierSupportedMethods = modifier.supportedMethods;
+  is(modifierSupportedMethods.length, 1, "modifier's supported methods length should be 1.");
+  supportedMethod = modifierSupportedMethods.queryElementAt(0, Ci.nsISupportsString);
+  is(supportedMethod, "MyPay", "modifier's supported method name should be 'MyPay'.");
+  is(modifier.total.label, "Discounted donation", "modifier's total label should be 'Discounted donation'.");
+  is(modifier.total.amount.currency, "USD", "modifier's total currency should be 'USD'.");
+  is(modifier.total.amount.value, "45.00", "modifier's total value should be '45.00'.");
+
+  const additionalItems = modifier.additionalDisplayItems;
+  is(additionalItems.length, "1", "additionalDisplayItems' length should be 1.");
+  const additionalItem = additionalItems.queryElementAt(0, Ci.nsIPaymentItem);
+  is(additionalItem.label, "MyPay discount", "additional item's label should be 'MyPay discount'.");
+  is(additionalItem.amount.currency, "USD", "additional item's currency should be 'USD'.");
+  is(additionalItem.amount.value, "-10.00", "additional item's value should be '-10.00'.");
+  is(modifier.data, "{\"discountProgramParticipantId\":\"86328764873265\"}",
+     "modifier's data should be '{\"discountProgramParticipantId\":\"86328764873265\"}'.");
+
+  const shippingOptions = details.shippingOptions;
+  is(shippingOptions.length, 2, "shippingOptions' length should be 2.");
+
+  let shippingOption = shippingOptions.queryElementAt(0, Ci.nsIPaymentShippingOption);
+  is(shippingOption.id, "NormalShipping", "1st shippingOption's id should be 'NoramlShpping'.");
+  is(shippingOption.label, "NormalShipping", "1st shippingOption's lable should be 'NormalShipping'.");
+  is(shippingOption.amount.currency, "USD", "1st shippingOption's amount currency should be 'USD'.");
+  is(shippingOption.amount.value, "10.00", "1st shippingOption's amount value should be '10.00'.");
+  ok(shippingOption.selected, "1st shippingOption should be selected.");
+
+  shippingOption = shippingOptions.queryElementAt(1, Ci.nsIPaymentShippingOption);
+  is(shippingOption.id, "FastShipping", "2nd shippingOption's id should be 'FastShpping'.");
+  is(shippingOption.label, "FastShipping", "2nd shippingOption's lable should be 'FastShipping'.");
+  is(shippingOption.amount.currency, "USD", "2nd shippingOption's amount currency should be 'USD'.");
+  is(shippingOption.amount.value, "30.00", "2nd shippingOption's amount value should be '30.00'.");
+  ok(!shippingOption.selected, "2nd shippingOption should not be selected.");
+
+  // checking the passed PaymentOptions parameter
+  const paymentOptions = aPayment.paymentOptions;
+  ok(paymentOptions.requestPayerName, "payerName option should be true");
+  ok(paymentOptions.requestPayerEmail, "payerEmail option should be true");
+  ok(paymentOptions.requestPayerPhone, "payerPhone option should be true");
+  ok(paymentOptions.requestShipping, "requestShipping option should be true");
+  is(paymentOptions.shippingType, "shipping", "shippingType option should be 'shipping'");
+}
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/multiple_payment_request.html
@@ -0,0 +1,84 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Payment Request Testing</title>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+    <meta content="utf-8" http-equiv="encoding">
+  </head>
+  <body>
+    <script type="text/javascript">
+    const supportedInstruments = [{
+      supportedMethods: [ "MyPay", "TestPay" ]
+    }];
+    const complexDetails = {
+      id: "complex details",
+      total: {
+        label: "Donation",
+        amount: { currency: "USD", value: "55.00" }
+      },
+      displayItems: [
+        {
+          label: "Original donation amount",
+          amount: { currency: "USD", value: "-65.00", }
+        },
+        {
+          label: "Friends and family discount",
+          amount: { currency: "USD", value: "10.00", }
+        }
+      ],
+      modifiers: [
+        {
+          supportedMethods: ["MyPay"],
+          total: {
+            label: "Discounted donation",
+            amount: { currency: "USD", value: "45.00", }
+          },
+          additionalDisplayItems: [
+            {
+              label: "MyPay discount",
+              amount: { currency: "USD", value: "-10.00", }
+            }
+          ],
+          data: { discountProgramParticipantId: "86328764873265", }
+        },
+      ],
+      shippingOptions: [
+        {
+          id: "NormalShipping",
+          label: "NormalShipping",
+          amount: { currency: "USD", value: "10.00", },
+          selected: true,
+        },
+        {
+          id: "FastShipping",
+          label: "FastShipping",
+          amount: { currency: "USD", value: "30.00", },
+          selected: false,
+        },
+      ],
+    };
+
+    const simpleDetails = {
+      id: "simple details",
+      total: {
+        label: "Donation",
+        amount: { currency: "USD", value: "55.00" }
+      },
+    };
+
+    const options = {
+      requestPayerName: true,
+      requestPayerEmail: true,
+      requestPayerPhone: true,
+      requestShipping: true,
+      shippingType: "shipping",
+    };
+
+    const paymentRequest1 = new PaymentRequest(supportedInstruments,
+                                               complexDetails,
+                                               options);
+    const paymentRequest2 = new PaymentRequest(supportedInstruments,
+                                               simpleDetails);
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/payments/test/simple_payment_request.html
@@ -0,0 +1,23 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <title>Payment Request Testing</title>
+    <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+    <meta content="utf-8" http-equiv="encoding">
+  </head>
+  <body>
+    <script type="text/javascript">
+    const supportedInstruments = [{
+      supportedMethods: [ "MyPay", "TestPay" ]
+    }];
+    const details = {
+      id: "simple details",
+      total: {
+        label: "Donation",
+        amount: { currency: "USD", value: "55.00" }
+      },
+    };
+    const payRequest = new PaymentRequest(supportedInstruments, details);
+    </script>
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/dom/webidl/PaymentRequest.webidl
@@ -0,0 +1,89 @@
+/* -*- Mode: IDL; 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/.
+ *
+ * The origin of this WebIDL file is
+ *   https://www.w3.org/TR/payment-request/#paymentrequest-interface
+ */
+
+dictionary PaymentMethodData {
+  required sequence<DOMString> supportedMethods;
+           object              data;
+};
+
+dictionary PaymentCurrencyAmount {
+  required DOMString currency;
+  required DOMString value;
+           DOMString currencySystem = "urn:iso:std:iso:4217";
+};
+
+dictionary PaymentItem {
+  required DOMString             label;
+  required PaymentCurrencyAmount amount;
+           boolean               pending = false;
+};
+
+dictionary PaymentShippingOption {
+  required DOMString             id;
+  required DOMString             label;
+  required PaymentCurrencyAmount amount;
+           boolean               selected = false;
+};
+
+dictionary PaymentDetailsModifier {
+  required sequence<DOMString>   supportedMethods;
+           PaymentItem           total;
+           sequence<PaymentItem> additionalDisplayItems;
+           object                data;
+};
+
+dictionary PaymentDetailsBase {
+  sequence<PaymentItem>            displayItems;
+  sequence<PaymentShippingOption>  shippingOptions;
+  sequence<PaymentDetailsModifier> modifiers;
+};
+
+dictionary PaymentDetailsInit : PaymentDetailsBase {
+           DOMString   id;
+  required PaymentItem total;
+};
+
+enum PaymentShippingType {
+  "shipping",
+  "delivery",
+  "pickup"
+};
+
+dictionary PaymentOptions {
+  boolean             requestPayerName = false;
+  boolean             requestPayerEmail = false;
+  boolean             requestPayerPhone = false;
+  boolean             requestShipping = false;
+  PaymentShippingType shippingType = "shipping";
+};
+
+[Constructor(sequence<PaymentMethodData> methodData, PaymentDetailsInit details,
+             optional PaymentOptions options),
+ SecureContext,
+ Func="mozilla::dom::PaymentRequest::PrefEnabled"]
+interface PaymentRequest : EventTarget {
+  /* TODO : Add show() support in Bug 1345366
+  [NewObject]
+  Promise<PaymentResponse> show();
+   */
+  [NewObject]
+  Promise<void>            abort();
+  [NewObject]
+  Promise<boolean>         canMakePayment();
+
+  readonly attribute DOMString            id;
+  /* TODO : Add PaymentAddress support in Bug 1345369
+  readonly attribute PaymentAddress?      shippingAddress;
+   */
+  readonly attribute DOMString?           shippingOption;
+  readonly attribute PaymentShippingType? shippingType;
+
+           attribute EventHandler         onshippingaddresschange;
+           attribute EventHandler         onshippingoptionchange;
+};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -716,16 +716,17 @@ WEBIDL_FILES = [
     'OfflineResourceList.webidl',
     'OffscreenCanvas.webidl',
     'OscillatorNode.webidl',
     'PaintRequest.webidl',
     'PaintRequestList.webidl',
     'PaintWorkletGlobalScope.webidl',
     'PannerNode.webidl',
     'ParentNode.webidl',
+    'PaymentRequest.webidl',
     'Performance.webidl',
     'PerformanceEntry.webidl',
     'PerformanceMark.webidl',
     'PerformanceMeasure.webidl',
     'PerformanceNavigation.webidl',
     'PerformanceObserver.webidl',
     'PerformanceObserverEntryList.webidl',
     'PerformanceResourceTiming.webidl',
--- a/mobile/android/installer/package-manifest.in
+++ b/mobile/android/installer/package-manifest.in
@@ -121,16 +121,17 @@
 @BINPATH@/components/dom_file.xpt
 @BINPATH@/components/dom_geolocation.xpt
 @BINPATH@/components/dom_media.xpt
 @BINPATH@/components/dom_network.xpt
 @BINPATH@/components/dom_notification.xpt
 @BINPATH@/components/dom_html.xpt
 @BINPATH@/components/dom_offline.xpt
 @BINPATH@/components/dom_json.xpt
+@BINPATH@/components/dom_payments.xpt
 @BINPATH@/components/dom_power.xpt
 #ifdef MOZ_ANDROID_GCM
 @BINPATH@/components/dom_push.xpt
 #endif
 @BINPATH@/components/dom_quota.xpt
 @BINPATH@/components/dom_range.xpt
 @BINPATH@/components/dom_security.xpt
 @BINPATH@/components/dom_sidebar.xpt
--- a/modules/libpref/init/all.js
+++ b/modules/libpref/init/all.js
@@ -5704,16 +5704,19 @@ pref("dom.IntersectionObserver.enabled",
 
 // Whether module scripts (<script type="module">) are enabled for content.
 pref("dom.moduleScripts.enabled", false);
 
 // Maximum amount of time in milliseconds consecutive setTimeout()/setInterval()
 // callback are allowed to run before yielding the event loop.
 pref("dom.timeout.max_consecutive_callbacks_ms", 4);
 
+// Use this preference to house "Payment Request API" during development
+pref("dom.payments.request.enabled", false);
+
 #ifdef FUZZING
 pref("fuzzing.enabled", false);
 #endif
 
 // Set advanced layers preferences here to have them show up in about:config or
 // to be overridable in reftest.list files. They should pretty much all be set
 // to a value of 2, and the conditional-pref code in gfxPrefs.h will convert
 // it to a boolean as appropriate. In particular, do NOT add ifdefs here to