diff --git a/.eslintignore b/.eslintignore index 1d23b919c616..bf90515d6887 100644 --- a/.eslintignore +++ b/.eslintignore @@ -217,6 +217,7 @@ dom/messagechannel/** dom/network/** dom/notification/** dom/offline/** +dom/payments/** dom/performance/** dom/permission/** dom/plugins/** diff --git a/browser/installer/package-manifest.in b/browser/installer/package-manifest.in index b9dd49fba7f9..512e2a9f9589 100644 --- a/browser/installer/package-manifest.in +++ b/browser/installer/package-manifest.in @@ -213,6 +213,7 @@ @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 diff --git a/dom/base/nsGkAtomList.h b/dom/base/nsGkAtomList.h index 37ff0c4a69cf..18cc787301db 100644 --- a/dom/base/nsGkAtomList.h +++ b/dom/base/nsGkAtomList.h @@ -958,6 +958,8 @@ 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") diff --git a/dom/bindings/Errors.msg b/dom/bindings/Errors.msg index dd2f15e3ebee..3d5c07846490 100644 --- a/dom/bindings/Errors.msg +++ b/dom/bindings/Errors.msg @@ -33,6 +33,7 @@ MSG_DEF(MSG_METHOD_THIS_UNWRAPPING_DENIED, 1, JSEXN_TYPEERR, "Permission to call 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}.") diff --git a/dom/interfaces/payments/moz.build b/dom/interfaces/payments/moz.build new file mode 100644 index 000000000000..c0ef2471dd15 --- /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' diff --git a/dom/interfaces/payments/nsIPaymentActionRequest.idl b/dom/interfaces/payments/nsIPaymentActionRequest.idl new file mode 100644 index 000000000000..42de8a639b66 --- /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" +%} diff --git a/dom/interfaces/payments/nsIPaymentRequest.idl b/dom/interfaces/payments/nsIPaymentRequest.idl new file mode 100644 index 000000000000..c88405e43224 --- /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); +}; diff --git a/dom/interfaces/payments/nsIPaymentRequestService.idl b/dom/interfaces/payments/nsIPaymentRequestService.idl new file mode 100644 index 000000000000..9000afc8d299 --- /dev/null +++ b/dom/interfaces/payments/nsIPaymentRequestService.idl @@ -0,0 +1,40 @@ +/* -*- 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(); + + /* + * This method is only for testing. + */ + void cleanup(); + + /* + * 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" +%} diff --git a/dom/ipc/PBrowser.ipdl b/dom/ipc/PBrowser.ipdl index fe344bae9ac4..6d3dcb404b50 100644 --- a/dom/ipc/PBrowser.ipdl +++ b/dom/ipc/PBrowser.ipdl @@ -19,6 +19,7 @@ include protocol PChildToParentStream; include protocol PParentToChildStream; include protocol PFileDescriptorSet; include protocol PIPCBlobInputStream; +include protocol PPaymentRequest; include DOMTypes; include IPCBlob; @@ -115,6 +116,7 @@ nested(upto inside_cpow) sync protocol PBrowser manages PIndexedDBPermissionRequest; manages PRenderFrame; manages PPluginWidget; + manages PPaymentRequest; both: async AsyncMessage(nsString aMessage, CpowEntry[] aCpows, @@ -145,6 +147,8 @@ parent: */ sync PPluginWidget(); + async PPaymentRequest(); + /** * Return native data of root widget */ diff --git a/dom/ipc/TabChild.cpp b/dom/ipc/TabChild.cpp index 1c67f4b14819..ddc7517d3c8d 100644 --- a/dom/ipc/TabChild.cpp +++ b/dom/ipc/TabChild.cpp @@ -20,6 +20,7 @@ #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" @@ -3208,6 +3209,19 @@ TabChild::CreatePluginWidget(nsIWidget* aParent, nsIWidget** aOut) } #endif // XP_WIN +PPaymentRequestChild* +TabChild::AllocPPaymentRequestChild() +{ + MOZ_CRASH("We should never be manually allocating PPaymentRequestChild actors"); + return nullptr; +} + +bool +TabChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor) +{ + return true; +} + ScreenIntSize TabChild::GetInnerSize() { diff --git a/dom/ipc/TabChild.h b/dom/ipc/TabChild.h index 8559965c97d3..fab8f49ab9a1 100644 --- a/dom/ipc/TabChild.h +++ b/dom/ipc/TabChild.h @@ -620,6 +620,12 @@ public: nsresult CreatePluginWidget(nsIWidget* aParent, nsIWidget** aOut); #endif + virtual PPaymentRequestChild* + AllocPPaymentRequestChild() override; + + virtual bool + DeallocPPaymentRequestChild(PPaymentRequestChild* aActor) override; + LayoutDeviceIntPoint GetClientOffset() const { return mClientOffset; } LayoutDeviceIntPoint GetChromeDisplacement() const { return mChromeDisp; }; diff --git a/dom/ipc/TabParent.cpp b/dom/ipc/TabParent.cpp index eb5e9d0ec73a..8c2e98d77b73 100644 --- a/dom/ipc/TabParent.cpp +++ b/dom/ipc/TabParent.cpp @@ -19,6 +19,7 @@ #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" @@ -2859,6 +2860,21 @@ TabParent::DeallocPPluginWidgetParent(mozilla::plugins::PPluginWidgetParent* aAc return true; } +PPaymentRequestParent* +TabParent::AllocPPaymentRequestParent() +{ + RefPtr actor = new PaymentRequestParent(GetTabId()); + return actor.forget().take(); +} + +bool +TabParent::DeallocPPaymentRequestParent(PPaymentRequestParent* aActor) +{ + RefPtr actor = + dont_AddRef(static_cast(aActor)); + return true; +} + nsresult TabParent::HandleEvent(nsIDOMEvent* aEvent) { diff --git a/dom/ipc/TabParent.h b/dom/ipc/TabParent.h index a2bf67326468..dfa8fa7ae4db 100644 --- a/dom/ipc/TabParent.h +++ b/dom/ipc/TabParent.h @@ -553,6 +553,12 @@ public: 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; } diff --git a/dom/moz.build b/dom/moz.build index 4c2f05a5ada7..528ce553a2f4 100644 --- a/dom/moz.build +++ b/dom/moz.build @@ -36,6 +36,7 @@ interfaces = [ 'svg', 'smil', 'push', + 'payments', ] DIRS += ['interfaces/' + i for i in interfaces] @@ -105,6 +106,7 @@ DIRS += [ 'xhr', 'worklet', 'script', + 'payments', ] if CONFIG['OS_ARCH'] == 'WINNT': diff --git a/dom/payments/PaymentActionRequest.cpp b/dom/payments/PaymentActionRequest.cpp new file mode 100644 index 000000000000..d2803e5b8979 --- /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 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 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 options = mOptions; + options.forget(aOptions); + return NS_OK; +} + +} // end of namespace dom +} // end of namespace mozilla diff --git a/dom/payments/PaymentActionRequest.h b/dom/payments/PaymentActionRequest.h new file mode 100644 index 000000000000..7efb348a575a --- /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 mMethodData; + nsCOMPtr mDetails; + nsCOMPtr mOptions; +}; + +} // end of namespace dom +} // end of namespace mozilla + +#endif diff --git a/dom/payments/PaymentRequest.cpp b/dom/payments/PaymentRequest.cpp new file mode 100644 index 000000000000..36ad9b255192 --- /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::IsValidNumber(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::IsValidDetailsInit(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 IsValidDetailsBase(aDetails, aErrorMsg); +} + +bool +PaymentRequest::IsValidDetailsBase(const PaymentDetailsBase& aDetails, nsAString& aErrorMsg) +{ + // Check the amount.value of each item in the display items + if (aDetails.mDisplayItems.WasPassed()) { + const Sequence& displayItems = aDetails.mDisplayItems.Value(); + for (const PaymentItem& displayItem : displayItems) { + if (!IsValidNumber(displayItem.mLabel, + displayItem.mAmount.mValue, aErrorMsg)) { + return false; + } + } + } + + // Check the shipping option + if (aDetails.mShippingOptions.WasPassed()) { + const Sequence& shippingOptions = aDetails.mShippingOptions.Value(); + for (const PaymentShippingOption& shippingOption : shippingOptions) { + if (!IsValidNumber(NS_LITERAL_STRING("details.shippingOptions"), + shippingOption.mAmount.mValue, aErrorMsg)) { + return false; + } + } + } + + // Check payment details modifiers + if (aDetails.mModifiers.WasPassed()) { + const Sequence& 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& displayItems = modifier.mAdditionalDisplayItems.Value(); + for (const PaymentItem& displayItem : displayItems) { + if (!IsValidNumber(displayItem.mLabel, + displayItem.mAmount.mValue, aErrorMsg)) { + return false; + } + } + } + } + } + + return true; +} + +already_AddRefed +PaymentRequest::Constructor(const GlobalObject& aGlobal, + const Sequence& aMethodData, + const PaymentDetailsInit& aDetails, + const PaymentOptions& aOptions, + ErrorResult& aRv) +{ + nsCOMPtr 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 (!IsValidDetailsInit(aDetails, message)) { + aRv.ThrowTypeError(message); + return nullptr; + } + + RefPtr manager = PaymentRequestManager::GetSingleton(); + if (NS_WARN_IF(!manager)) { + return nullptr; + } + + // Create PaymentRequest and set its |mId| + RefPtr 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::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 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 +PaymentRequest::Show(ErrorResult& aRv) +{ + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; +} + +already_AddRefed +PaymentRequest::CanMakePayment(ErrorResult& aRv) +{ + aRv.Throw(NS_ERROR_FAILURE); + return nullptr; +} + +already_AddRefed +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 +PaymentRequest::GetShippingType() const +{ + return nullptr; +} + +PaymentRequest::~PaymentRequest() +{ +} + +JSObject* +PaymentRequest::WrapObject(JSContext* aCx, JS::Handle aGivenProto) +{ + return PaymentRequestBinding::Wrap(aCx, this, aGivenProto); +} + +} // namespace dom +} // namespace mozilla diff --git a/dom/payments/PaymentRequest.h b/dom/payments/PaymentRequest.h new file mode 100644 index 000000000000..7d984224761f --- /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 aGivenProto) override; + + static already_AddRefed + CreatePaymentRequest(nsPIDOMWindowInner* aWindow, nsresult& aRv); + + static bool PrefEnabled(JSContext* aCx, JSObject* aObj); + + static bool + IsValidNumber(const nsAString& aItem, + const nsAString& aStr, + nsAString& aErrorMsg); + static bool + IsPositiveNumber(const nsAString& aItem, + const nsAString& aStr, + nsAString& aErrorMsg); + + static bool + IsValidDetailsInit(const PaymentDetailsInit& aDetails, + nsAString& aErrorMsg); + static bool + IsValidDetailsBase(const PaymentDetailsBase& aDetails, + nsAString& aErrorMsg); + + static already_AddRefed + Constructor(const GlobalObject& aGlobal, + const Sequence& aMethodData, + const PaymentDetailsInit& aDetails, + const PaymentOptions& aOptions, + ErrorResult& aRv); + + already_AddRefed Show(ErrorResult& aRv); + already_AddRefed Abort(ErrorResult& aRv); + already_AddRefed 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 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 diff --git a/dom/payments/PaymentRequestData.cpp b/dom/payments/PaymentRequestData.cpp new file mode 100644 index 000000000000..1aeebe573486 --- /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 supportedMethods; + nsresult rv = ConvertStringstoISupportsStrings(aIPCMethodData.supportedMethods(), + getter_AddRefs(supportedMethods)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + nsCOMPtr 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 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 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 amount; + nsresult rv = PaymentCurrencyAmount::Create(aIPCItem.amount(), + getter_AddRefs(amount)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + nsCOMPtr 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 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 total; + nsresult rv = PaymentItem::Create(aIPCModifier.total(), getter_AddRefs(total)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr supportedMethods; + rv = ConvertStringstoISupportsStrings(aIPCModifier.supportedMethods(), + getter_AddRefs(supportedMethods)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr displayItems; + if (aIPCModifier.additionalDisplayItemsPassed()) { + nsCOMPtr items = do_CreateInstance(NS_ARRAY_CONTRACTID); + MOZ_ASSERT(items); + for (const IPCPaymentItem& item : aIPCModifier.additionalDisplayItems()) { + nsCOMPtr 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 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 supportedMethods = mSupportedMethods; + supportedMethods.forget(aSupportedMethods); + return NS_OK; +} + +NS_IMETHODIMP +PaymentDetailsModifier::GetTotal(nsIPaymentItem** aTotal) +{ + NS_ENSURE_ARG_POINTER(aTotal); + MOZ_ASSERT(mTotal); + nsCOMPtr total = mTotal; + total.forget(aTotal); + return NS_OK; +} + +NS_IMETHODIMP +PaymentDetailsModifier::GetAdditionalDisplayItems(nsIArray** aAdditionalDisplayItems) +{ + NS_ENSURE_ARG_POINTER(aAdditionalDisplayItems); + nsCOMPtr 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 amount; + nsresult rv = PaymentCurrencyAmount::Create(aIPCOption.amount(), getter_AddRefs(amount)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + nsCOMPtr 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 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 total; + nsresult rv = PaymentItem::Create(aIPCDetails.total(), getter_AddRefs(total)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsCOMPtr displayItems; + if (aIPCDetails.displayItemsPassed()) { + nsCOMPtr items = do_CreateInstance(NS_ARRAY_CONTRACTID); + MOZ_ASSERT(items); + for (const IPCPaymentItem& displayItem : aIPCDetails.displayItems()) { + nsCOMPtr 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 shippingOptions; + if (aIPCDetails.shippingOptionsPassed()) { + nsCOMPtr options = do_CreateInstance(NS_ARRAY_CONTRACTID); + MOZ_ASSERT(options); + for (const IPCPaymentShippingOption& shippingOption : aIPCDetails.shippingOptions()) { + nsCOMPtr 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 modifiers; + if (aIPCDetails.modifiersPassed()) { + nsCOMPtr detailsModifiers = do_CreateInstance(NS_ARRAY_CONTRACTID); + MOZ_ASSERT(detailsModifiers); + for (const IPCPaymentDetailsModifier& modifier : aIPCDetails.modifiers()) { + nsCOMPtr 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 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 total = mTotalItem; + total.forget(aTotalItem); + return NS_OK; +} + +NS_IMETHODIMP +PaymentDetails::GetDisplayItems(nsIArray** aDisplayItems) +{ + NS_ENSURE_ARG_POINTER(aDisplayItems); + nsCOMPtr displayItems = mDisplayItems; + displayItems.forget(aDisplayItems); + return NS_OK; +} + +NS_IMETHODIMP +PaymentDetails::GetShippingOptions(nsIArray** aShippingOptions) +{ + NS_ENSURE_ARG_POINTER(aShippingOptions); + nsCOMPtr options = mShippingOptions; + options.forget(aShippingOptions); + return NS_OK; +} + +NS_IMETHODIMP +PaymentDetails::GetModifiers(nsIArray** aModifiers) +{ + NS_ENSURE_ARG_POINTER(aModifiers); + nsCOMPtr 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 displayItems; + rv = aDetails->GetDisplayItems(getter_AddRefs(displayItems)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + if (displayItems) { + mDisplayItems = displayItems; + } + + nsCOMPtr shippingOptions; + rv = aDetails->GetShippingOptions(getter_AddRefs(shippingOptions)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + if (shippingOptions) { + mShippingOptions = shippingOptions; + } + + nsCOMPtr 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 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 methods = mPaymentMethods; + methods.forget(aPaymentMethods); + return NS_OK; +} + +NS_IMETHODIMP +PaymentRequest::GetPaymentDetails(nsIPaymentDetails** aPaymentDetails) +{ + NS_ENSURE_ARG_POINTER(aPaymentDetails); + MOZ_ASSERT(mPaymentDetails); + nsCOMPtr details = mPaymentDetails; + details.forget(aPaymentDetails); + return NS_OK; +} + +NS_IMETHODIMP +PaymentRequest::GetPaymentOptions(nsIPaymentOptions** aPaymentOptions) +{ + NS_ENSURE_ARG_POINTER(aPaymentOptions); + MOZ_ASSERT(mPaymentOptions); + nsCOMPtr 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 diff --git a/dom/payments/PaymentRequestData.h b/dom/payments/PaymentRequestData.h new file mode 100644 index 000000000000..4e4c695e426f --- /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 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 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 mSupportedMethods; + nsCOMPtr mTotal; + nsCOMPtr 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 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 mTotalItem; + nsCOMPtr mDisplayItems; + nsCOMPtr mShippingOptions; + nsCOMPtr 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 mPaymentMethods; + nsCOMPtr mPaymentDetails; + nsCOMPtr mPaymentOptions; +}; + +} // end of namespace payment +} // end of namespace dom +} // end of namespace mozilla + +#endif diff --git a/dom/payments/PaymentRequestManager.cpp b/dom/payments/PaymentRequestManager.cpp new file mode 100644 index 000000000000..6cc40b190a9c --- /dev/null +++ b/dom/payments/PaymentRequestManager.cpp @@ -0,0 +1,394 @@ +/* -*- 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(JSContext* aCx, JS::HandleObject aObject, nsAString& aSerializedObject){ + nsCOMPtr serializer = do_CreateInstance("@mozilla.org/dom/json;1"); + if (NS_WARN_IF(!serializer)) { + return NS_ERROR_FAILURE; + } + JS::RootedValue value(aCx, JS::ObjectValue(*aObject)); + //JS::Value value = JS::ObjectValue(*aObject); + return serializer->EncodeFromJSVal(value.address(), aCx, aSerializedObject); +} + +nsresult +ConvertMethodData(const PaymentMethodData& aMethodData, + IPCPaymentMethodData& aIPCMethodData) +{ + // Convert Sequence to nsTArray + nsTArray supportedMethods; + for (const nsString& method : aMethodData.mSupportedMethods) { + supportedMethods.AppendElement(method); + } + + // Convert JSObject to a serialized string + nsAutoString serializedData; + if (aMethodData.mData.WasPassed()) { + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + MOZ_ASSERT(cx); + JS::RootedObject object(cx, aMethodData.mData.Value()); + nsresult rv = SerializeFromJSObject(cx, object, 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 to nsTArray + nsTArray supportedMethods; + for (const nsString& method : aModifier.mSupportedMethods) { + supportedMethods.AppendElement(method); + } + + // Convert JSObject to a serialized string + nsAutoString serializedData; + if (aModifier.mData.WasPassed()) { + JSContext* cx = nsContentUtils::GetCurrentJSContext(); + MOZ_ASSERT(cx); + JS::RootedObject object(cx, aModifier.mData.Value()); + nsresult rv = SerializeFromJSObject(cx, object, serializedData); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + } + + IPCPaymentItem total; + ConvertItem(aModifier.mTotal, total); + + nsTArray 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& aDisplayItems, + nsTArray& aShippingOptions, + nsTArray& 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 displayItems; + nsTArray shippingOptions; + nsTArray 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(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 gPaymentManager; + +nsresult +PaymentRequestManager::GetPaymentChild(PaymentRequest* aRequest, + PaymentRequestChild** aChild) +{ + NS_ENSURE_ARG_POINTER(aRequest); + NS_ENSURE_ARG_POINTER(aChild); + *aChild = nullptr; + + RefPtr 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 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.Iter(); !iter.Done(); iter.Next()) { + RefPtr child = iter.Data(); + if (NS_WARN_IF(!child)) { + return NS_ERROR_FAILURE; + } + if (child == aPaymentChild) { + iter.Remove(); + return NS_OK; + } + } + return NS_OK; +} + +nsresult +PaymentRequestManager::ReleasePaymentChild(PaymentRequest* aRequest) +{ + NS_ENSURE_ARG_POINTER(aRequest); + + RefPtr 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::GetSingleton() +{ + if (!gPaymentManager) { + gPaymentManager = new PaymentRequestManager(); + ClearOnShutdown(&gPaymentManager); + } + RefPtr manager = gPaymentManager; + return manager.forget(); +} + +already_AddRefed +PaymentRequestManager::GetPaymentRequestById(const nsAString& aRequestId) +{ + for (const RefPtr& request : mRequestQueue) { + if (request->Equals(aRequestId)) { + RefPtr paymentRequest = request; + return paymentRequest.forget(); + } + } + return nullptr; +} + +nsresult +PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow, + const Sequence& aMethodData, + const PaymentDetailsInit& aDetails, + const PaymentOptions& aOptions, + PaymentRequest** aRequest) +{ + MOZ_ASSERT(NS_IsMainThread()); + NS_ENSURE_ARG_POINTER(aRequest); + *aRequest = nullptr; + + nsresult rv; + nsTArray 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::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 requestChild; + rv = GetPaymentChild(paymentRequest, getter_AddRefs(requestChild)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return rv; + } + + nsAutoString internalId; + paymentRequest->GetInternalId(internalId); + IPCPaymentCreateActionRequest request(internalId, + 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 diff --git a/dom/payments/PaymentRequestManager.h b/dom/payments/PaymentRequestManager.h new file mode 100644 index 000000000000..d81fe181246a --- /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 GetSingleton(); + + already_AddRefed + 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& 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> mRequestQueue; + nsRefPtrHashtable, PaymentRequestChild> mPaymentChildHash; +}; + +} // end of namespace dom +} // end of namespace mozilla + +#endif diff --git a/dom/payments/PaymentRequestModule.cpp b/dom/payments/PaymentRequestModule.cpp new file mode 100644 index 000000000000..05c614ca3a51 --- /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; diff --git a/dom/payments/PaymentRequestService.cpp b/dom/payments/PaymentRequestService.cpp new file mode 100644 index 000000000000..2bc5cef0a0c9 --- /dev/null +++ b/dom/payments/PaymentRequestService.cpp @@ -0,0 +1,201 @@ +/* -*- 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 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 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 request = + gPaymentService->GetPaymentRequestByIndex(mIndex); + if (NS_WARN_IF(!request)) { + return NS_ERROR_FAILURE; + } + nsCOMPtr 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::GetSingleton() +{ + MOZ_ASSERT(NS_IsMainThread()); + if (!gPaymentService) { + gPaymentService = new PaymentRequestService(); + ClearOnShutdown(&gPaymentService); + } + RefPtr service = gPaymentService; + return service.forget(); +} + +uint32_t +PaymentRequestService::NumPayments() const +{ + return mRequestQueue.Length(); +} + +already_AddRefed +PaymentRequestService::GetPaymentRequestByIndex(const uint32_t aIndex) +{ + if (aIndex >= mRequestQueue.Length()) { + return nullptr; + } + nsCOMPtr 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 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 enumerator = new PaymentRequestEnumerator(); + enumerator.forget(aEnumerator); + return NS_OK; +} + +NS_IMETHODIMP +PaymentRequestService::Cleanup() +{ + mRequestQueue.Clear(); + 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 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 methodData; + rv = request->GetMethodData(getter_AddRefs(methodData)); + if (NS_WARN_IF(NS_FAILED(rv) || !methodData)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr details; + rv = request->GetDetails(getter_AddRefs(details)); + if (NS_WARN_IF(NS_FAILED(rv) || !details)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr options; + rv = request->GetOptions(getter_AddRefs(options)); + if (NS_WARN_IF(NS_FAILED(rv) || !options)) { + return NS_ERROR_FAILURE; + } + + nsCOMPtr 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 diff --git a/dom/payments/PaymentRequestService.h b/dom/payments/PaymentRequestService.h new file mode 100644 index 000000000000..1a8f2c142ebb --- /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 GetSingleton(); + + already_AddRefed + GetPaymentRequestByIndex(const uint32_t index); + + uint32_t NumPayments() const; + +private: + ~PaymentRequestService() = default; + + FallibleTArray> mRequestQueue; +}; + +} // end of namespace dom +} // end of namespace mozilla + +#endif diff --git a/dom/payments/PaymentRequestUtils.cpp b/dom/payments/PaymentRequestUtils.cpp new file mode 100644 index 000000000000..dc4158257c0c --- /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& aStrings, + nsIArray** aIStrings) +{ + NS_ENSURE_ARG_POINTER(aIStrings); + *aIStrings = nullptr; + nsCOMPtr iStrings = do_CreateInstance(NS_ARRAY_CONTRACTID); + for (const nsString& string : aStrings) { + nsCOMPtr 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& 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 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 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 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 diff --git a/dom/payments/PaymentRequestUtils.h b/dom/payments/PaymentRequestUtils.h new file mode 100644 index 000000000000..2814927994d7 --- /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& aStrings, + nsIArray** aIStrings); + +nsresult +ConvertISupportsStringstoStrings(nsIArray* aIStrings, + nsTArray& aStrings); + +nsresult +CopyISupportsStrings(nsIArray* aSourceStrings, nsIArray** aTargetStrings); + +} // end of namespace dom +} // end of namespace mozilla + +#endif diff --git a/dom/payments/ipc/PPaymentRequest.ipdl b/dom/payments/ipc/PPaymentRequest.ipdl new file mode 100644 index 000000000000..5d14bc8173d5 --- /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 diff --git a/dom/payments/ipc/PaymentRequestChild.cpp b/dom/payments/ipc/PaymentRequestChild.cpp new file mode 100644 index 000000000000..495e309044e9 --- /dev/null +++ b/dom/payments/ipc/PaymentRequestChild.cpp @@ -0,0 +1,53 @@ +/* -*- 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 manager = PaymentRequestManager::GetSingleton(); + MOZ_ASSERT(manager); + manager->ReleasePaymentChild(this); +} + +void +PaymentRequestChild::MaybeDelete() +{ + if (mActorAlive) { + mActorAlive = false; + Send__delete__(this); + } +} + +bool +PaymentRequestChild::SendRequestPayment(const IPCPaymentActionRequest& aAction) +{ + return PPaymentRequestChild::SendRequestPayment(aAction); +} + +} // end of namespace dom +} // end of namespace mozilla diff --git a/dom/payments/ipc/PaymentRequestChild.h b/dom/payments/ipc/PaymentRequestChild.h new file mode 100644 index 000000000000..c632f7a58f0c --- /dev/null +++ b/dom/payments/ipc/PaymentRequestChild.h @@ -0,0 +1,37 @@ +/* -*- 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 SendRequestPayment(const IPCPaymentActionRequest& aAction); + + bool mActorAlive; +}; + +} // end of namespace dom +} // end of namespace mozilla + +#endif diff --git a/dom/payments/ipc/PaymentRequestParent.cpp b/dom/payments/ipc/PaymentRequestParent.cpp new file mode 100644 index 000000000000..fbd609c9ed31 --- /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 actionRequest; + nsresult rv; + switch (aRequest.type()) { + case IPCPaymentActionRequest::TIPCPaymentCreateActionRequest: { + IPCPaymentCreateActionRequest request = aRequest; + + nsCOMPtr methodData = do_CreateInstance(NS_ARRAY_CONTRACTID); + MOZ_ASSERT(methodData); + for (IPCPaymentMethodData data : request.methodData()) { + nsCOMPtr 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 details; + rv = payments::PaymentDetails::Create(request.details(), getter_AddRefs(details)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_FAIL_NO_REASON(this); + } + + nsCOMPtr options; + rv = payments::PaymentOptions::Create(request.options(), getter_AddRefs(options)); + if (NS_WARN_IF(NS_FAILED(rv))) { + return IPC_FAIL_NO_REASON(this); + } + + nsCOMPtr 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 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 diff --git a/dom/payments/ipc/PaymentRequestParent.h b/dom/payments/ipc/PaymentRequestParent.h new file mode 100644 index 000000000000..95c193c42cbe --- /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 diff --git a/dom/payments/ipc/moz.build b/dom/payments/ipc/moz.build new file mode 100644 index 000000000000..86d76c257fc2 --- /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' diff --git a/dom/payments/moz.build b/dom/payments/moz.build new file mode 100644 index 000000000000..52ffa275463c --- /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'] diff --git a/dom/payments/test/browser.ini b/dom/payments/test/browser.ini new file mode 100644 index 000000000000..ac7582c37004 --- /dev/null +++ b/dom/payments/test/browser.ini @@ -0,0 +1,11 @@ +[DEFAULT] +# skip-if !e10s will be removed once non-e10s is supported +skip-if = !e10s +support-files = + head.js + simple_payment_request.html + multiple_payment_request.html + +[browser_payment_construction.js] +[browser_multiple_construction.js] +[browser_payment_in_different_tabs.js] diff --git a/dom/payments/test/browser_multiple_construction.js b/dom/payments/test/browser_multiple_construction.js new file mode 100644 index 000000000000..5df84a337e2f --- /dev/null +++ b/dom/payments/test/browser_multiple_construction.js @@ -0,0 +1,32 @@ +"use strict"; + +// kTestRoot is from head.js +const kTestPage = kTestRoot + "multiple_payment_request.html"; + +registerCleanupFunction(cleanup); + +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); + } + ); +}); diff --git a/dom/payments/test/browser_payment_construction.js b/dom/payments/test/browser_payment_construction.js new file mode 100644 index 000000000000..c037d3d549c6 --- /dev/null +++ b/dom/payments/test/browser_payment_construction.js @@ -0,0 +1,26 @@ +"use strict"; + +// kTestRoot is from head.js +const kTestPage = kTestRoot + "simple_payment_request.html"; + +registerCleanupFunction(cleanup); + +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); + } + ); +}); diff --git a/dom/payments/test/browser_payment_in_different_tabs.js b/dom/payments/test/browser_payment_in_different_tabs.js new file mode 100644 index 000000000000..081f11760b8c --- /dev/null +++ b/dom/payments/test/browser_payment_in_different_tabs.js @@ -0,0 +1,33 @@ +"use strict"; + +// kTestRoot is from head.js +const kTestPage = kTestRoot + "simple_payment_request.html"; + +registerCleanupFunction(cleanup); + +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); + } + ); + } + ); +}); diff --git a/dom/payments/test/head.js b/dom/payments/test/head.js new file mode 100644 index 000000000000..f36e747670e2 --- /dev/null +++ b/dom/payments/test/head.js @@ -0,0 +1,120 @@ +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'"); +} + +function cleanup() { + const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService); + if (paymentSrv) { + paymentSrv.cleanup(); + } +} diff --git a/dom/payments/test/multiple_payment_request.html b/dom/payments/test/multiple_payment_request.html new file mode 100644 index 000000000000..2be7c8d169f4 --- /dev/null +++ b/dom/payments/test/multiple_payment_request.html @@ -0,0 +1,84 @@ + + + + Payment Request Testing + + + + + + + diff --git a/dom/payments/test/simple_payment_request.html b/dom/payments/test/simple_payment_request.html new file mode 100644 index 000000000000..9d0e565b1821 --- /dev/null +++ b/dom/payments/test/simple_payment_request.html @@ -0,0 +1,23 @@ + + + + Payment Request Testing + + + + + + + diff --git a/dom/webidl/PaymentRequest.webidl b/dom/webidl/PaymentRequest.webidl new file mode 100644 index 000000000000..1f80967f88cd --- /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 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 supportedMethods; + PaymentItem total; + sequence additionalDisplayItems; + object data; +}; + +dictionary PaymentDetailsBase { + sequence displayItems; + sequence shippingOptions; + sequence 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 methodData, PaymentDetailsInit details, + optional PaymentOptions options), + SecureContext, + Func="mozilla::dom::PaymentRequest::PrefEnabled"] +interface PaymentRequest : EventTarget { + /* TODO : Add show() support in Bug 1345366 + [NewObject] + Promise show(); + */ + [NewObject] + Promise abort(); + [NewObject] + Promise 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; +}; diff --git a/dom/webidl/moz.build b/dom/webidl/moz.build index 0c43e18e4b46..3affc3c436c1 100644 --- a/dom/webidl/moz.build +++ b/dom/webidl/moz.build @@ -721,6 +721,7 @@ WEBIDL_FILES = [ 'PaintWorkletGlobalScope.webidl', 'PannerNode.webidl', 'ParentNode.webidl', + 'PaymentRequest.webidl', 'Performance.webidl', 'PerformanceEntry.webidl', 'PerformanceMark.webidl', diff --git a/mobile/android/installer/package-manifest.in b/mobile/android/installer/package-manifest.in index 41827d93e74c..00fbc3ff1da6 100644 --- a/mobile/android/installer/package-manifest.in +++ b/mobile/android/installer/package-manifest.in @@ -126,6 +126,7 @@ @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 diff --git a/modules/libpref/init/all.js b/modules/libpref/init/all.js index 6ddf05451a17..5ed643c2554f 100644 --- a/modules/libpref/init/all.js +++ b/modules/libpref/init/all.js @@ -5714,6 +5714,9 @@ pref("dom.moduleScripts.enabled", false); // 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