Bug 1442453 - Create a single IPC actor per PaymentRequest. r=baku
There isn't any need to create an actor per call to the parent. This patch
lines up PaymentRequest with PPaymentRequestChild objects and links them
together. It also simplifies the maps and arrays we use to keep track of these
objects.
There's one tricky bit to note in this patch: in the case that a promise is
passed to paymentRequest.show(), we don't notify the parent process until the
promise resolves (when we call either UpdatePayment or AbortUpdate). In that
case, I needed to distinguish between an "update" because of the promise
resolving or a call to updateWith on an shippingaddresschange event in order
to get the bookkeeping right with the mActivePayments hashtable. In that case,
the PaymentRequest is kept alive by mShowingRequest alone. In all other cases,
mActivePayments keeps the PaymentRequest alive until we resolve or reject the
correct promise.
MozReview-Commit-ID: HoHjn8eqC4T
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -3434,16 +3434,17 @@ TabChild::AllocPPaymentRequestChild()
{
MOZ_CRASH("We should never be manually allocating PPaymentRequestChild actors");
return nullptr;
}
bool
TabChild::DeallocPPaymentRequestChild(PPaymentRequestChild* actor)
{
+ delete actor;
return true;
}
ScreenIntSize
TabChild::GetInnerSize()
{
LayoutDeviceIntSize innerSize =
RoundedToInt(mUnscaledInnerSize * mPuppetWidget->GetDefaultScale());
--- a/dom/payments/PaymentRequest.cpp
+++ b/dom/payments/PaymentRequest.cpp
@@ -2,16 +2,17 @@
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "BasicCardPayment.h"
#include "mozilla/dom/Element.h"
#include "mozilla/dom/PaymentRequest.h"
+#include "mozilla/dom/PaymentRequestChild.h"
#include "mozilla/dom/PaymentResponse.h"
#include "mozilla/EventStateManager.h"
#include "nsContentUtils.h"
#include "nsIURLParser.h"
#include "nsNetCID.h"
#include "PaymentRequestManager.h"
namespace mozilla {
@@ -626,18 +627,20 @@ PaymentRequest::CreatePaymentRequest(nsP
}
PaymentRequest::PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId)
: DOMEventTargetHelper(aWindow)
, mInternalId(aInternalId)
, mShippingAddress(nullptr)
, mUpdating(false)
, mRequestShipping(false)
+ , mDeferredShow(false)
, mUpdateError(NS_OK)
, mState(eCreated)
+ , mIPC(nullptr)
{
MOZ_ASSERT(aWindow);
}
already_AddRefed<Promise>
PaymentRequest::CanMakePayment(ErrorResult& aRv)
{
if (mState != eCreated) {
@@ -708,16 +711,17 @@ PaymentRequest::Show(const Optional<Owni
mState = eClosed;
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
if (aDetailsPromise.WasPassed()) {
aDetailsPromise.Value().AppendNativeHandler(this);
mUpdating = true;
+ mDeferredShow = true;
}
nsresult rv = manager->ShowPayment(mInternalId);
if (NS_WARN_IF(NS_FAILED(rv))) {
if (rv == NS_ERROR_ABORT) {
promise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
} else {
promise->MaybeReject(NS_ERROR_DOM_NOT_ALLOWED_ERR);
@@ -802,17 +806,20 @@ PaymentRequest::Abort(ErrorResult& aRv)
return nullptr;
}
RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
if (NS_WARN_IF(!manager)) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
- nsresult rv = manager->AbortPayment(mInternalId);
+
+ // It's possible for to call this between show and its promise resolving.
+ nsresult rv = manager->AbortPayment(this, mDeferredShow);
+ mDeferredShow = false;
if (NS_WARN_IF(NS_FAILED(rv))) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
mAbortPromise = promise;
return promise.forget();
}
@@ -847,39 +854,41 @@ PaymentRequest::RespondAbortPayment(bool
RejectShowPayment(NS_ERROR_DOM_ABORT_ERR);
} else {
mAbortPromise->MaybeReject(NS_ERROR_DOM_INVALID_STATE_ERR);
mAbortPromise = nullptr;
}
}
nsresult
-PaymentRequest::UpdatePayment(JSContext* aCx, const PaymentDetailsUpdate& aDetails)
+PaymentRequest::UpdatePayment(JSContext* aCx, const PaymentDetailsUpdate& aDetails,
+ bool aDeferredShow)
{
NS_ENSURE_ARG_POINTER(aCx);
RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
if (NS_WARN_IF(!manager)) {
return NS_ERROR_FAILURE;
}
- nsresult rv = manager->UpdatePayment(aCx, mInternalId, aDetails, mRequestShipping);
+ nsresult rv = manager->UpdatePayment(aCx, this, aDetails, mRequestShipping,
+ aDeferredShow);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
void
-PaymentRequest::AbortUpdate(nsresult aRv)
+PaymentRequest::AbortUpdate(nsresult aRv, bool aDeferredShow)
{
MOZ_ASSERT(NS_FAILED(aRv));
// Close down any remaining user interface.
RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
MOZ_ASSERT(manager);
- nsresult rv = manager->AbortPayment(mInternalId);
+ nsresult rv = manager->AbortPayment(this, aDeferredShow);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
// Remember update error |aRv| and do the following steps in RespondShowPayment.
// 1. Set target.state to closed
// 2. Reject the promise target.acceptPromise with exception "aRv"
// 3. Abort the algorithm with update error
@@ -1014,43 +1023,50 @@ PaymentRequest::ResolvedCallback(JSConte
mUpdating = false;
if (NS_WARN_IF(!aValue.isObject())) {
return;
}
// Converting value to a PaymentDetailsUpdate dictionary
PaymentDetailsUpdate details;
if (!details.Init(aCx, aValue)) {
- AbortUpdate(NS_ERROR_DOM_TYPE_ERR);
+ AbortUpdate(NS_ERROR_DOM_TYPE_ERR, mDeferredShow);
JS_ClearPendingException(aCx);
return;
}
nsresult rv = IsValidDetailsUpdate(details, mRequestShipping);
if (NS_FAILED(rv)) {
- AbortUpdate(rv);
+ AbortUpdate(rv, mDeferredShow);
return;
}
// Update the PaymentRequest with the new details
- if (NS_FAILED(UpdatePayment(aCx, details))) {
- AbortUpdate(NS_ERROR_DOM_ABORT_ERR);
+ if (NS_FAILED(UpdatePayment(aCx, details, mDeferredShow))) {
+ AbortUpdate(NS_ERROR_DOM_ABORT_ERR, mDeferredShow);
return;
}
+
+ mDeferredShow = false;
}
void
PaymentRequest::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
+ MOZ_ASSERT(mDeferredShow);
mUpdating = false;
- AbortUpdate(NS_ERROR_DOM_ABORT_ERR);
+ AbortUpdate(NS_ERROR_DOM_ABORT_ERR, mDeferredShow);
+ mDeferredShow = false;
}
PaymentRequest::~PaymentRequest()
{
+ if (mIPC) {
+ mIPC->MaybeDelete();
+ }
}
JSObject*
PaymentRequest::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PaymentRequestBinding::Wrap(aCx, this, aGivenProto);
}
--- a/dom/payments/PaymentRequest.h
+++ b/dom/payments/PaymentRequest.h
@@ -15,16 +15,17 @@
#include "nsWrapperCache.h"
#include "PaymentRequestUpdateEvent.h"
namespace mozilla {
namespace dom {
class EventHandlerNonNull;
class PaymentAddress;
+class PaymentRequestChild;
class PaymentResponse;
class PaymentRequest final : public DOMEventTargetHelper
, public PromiseNativeHandler
{
public:
NS_DECL_ISUPPORTS_INHERITED
@@ -130,18 +131,19 @@ public:
const nsAString& aRecipient,
const nsAString& aPhone);
void SetShippingOption(const nsAString& aShippingOption);
void GetShippingOption(nsAString& aRetVal) const;
nsresult UpdateShippingOption(const nsAString& aShippingOption);
- nsresult UpdatePayment(JSContext* aCx, const PaymentDetailsUpdate& aDetails);
- void AbortUpdate(nsresult aRv);
+ nsresult UpdatePayment(JSContext* aCx, const PaymentDetailsUpdate& aDetails,
+ bool aDeferredShow);
+ void AbortUpdate(nsresult aRv, bool aDeferredShow);
void SetShippingType(const Nullable<PaymentShippingType>& aShippingType);
Nullable<PaymentShippingType> GetShippingType() const;
inline void ShippingWasRequested()
{
mRequestShipping = true;
}
@@ -149,16 +151,26 @@ public:
void
ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
void
RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue) override;
IMPL_EVENT_HANDLER(shippingaddresschange);
IMPL_EVENT_HANDLER(shippingoptionchange);
+ void SetIPC(PaymentRequestChild* aChild)
+ {
+ mIPC = aChild;
+ }
+
+ PaymentRequestChild* GetIPC()
+ {
+ return mIPC;
+ }
+
protected:
~PaymentRequest();
nsresult DispatchUpdateEvent(const nsAString& aType);
PaymentRequest(nsPIDOMWindowInner* aWindow, const nsAString& aInternalId);
// Id for internal identification
@@ -186,23 +198,30 @@ protected:
// "true" when there is a pending updateWith() call to update the payment request
// and "false" otherwise.
bool mUpdating;
// Whether shipping was requested. This models [[options]].requestShipping,
// but we don't actually store the full [[options]] internal slot.
bool mRequestShipping;
+
+ // True if the user passed a promise to show, causing us to defer telling the
+ // front end about it.
+ bool mDeferredShow;
+
// The error is set in AbortUpdate(). The value is NS_OK by default.
nsresult mUpdateError;
enum {
eUnknown,
eCreated,
eInteractive,
eClosed
} mState;
+
+ PaymentRequestChild* mIPC;
};
} // namespace dom
} // namespace mozilla
#endif // mozilla_dom_PaymentRequest_h
--- a/dom/payments/PaymentRequestManager.cpp
+++ b/dom/payments/PaymentRequestManager.cpp
@@ -247,125 +247,101 @@ ConvertOptions(const PaymentOptions& aOp
shippingType);
}
} // end of namespace
/* PaymentRequestManager */
StaticRefPtr<PaymentRequestManager> gPaymentManager;
-nsresult
-PaymentRequestManager::GetPaymentChild(PaymentRequest* aRequest,
- PaymentRequestChild** aChild)
+PaymentRequestChild*
+PaymentRequestManager::GetPaymentChild(PaymentRequest* aRequest)
{
- NS_ENSURE_ARG_POINTER(aRequest);
- NS_ENSURE_ARG_POINTER(aChild);
- *aChild = nullptr;
+ MOZ_ASSERT(aRequest);
- RefPtr<PaymentRequestChild> paymentChild;
- if (mPaymentChildHash.Get(aRequest, getter_AddRefs(paymentChild))) {
- paymentChild.forget(aChild);
- return NS_OK;
+ if (PaymentRequestChild* child = aRequest->GetIPC()) {
+ return child;
}
nsPIDOMWindowInner* win = aRequest->GetOwner();
- NS_ENSURE_TRUE(win, NS_ERROR_FAILURE);
+ NS_ENSURE_TRUE(win, nullptr);
TabChild* tabChild = TabChild::GetFrom(win->GetDocShell());
- NS_ENSURE_TRUE(tabChild, NS_ERROR_FAILURE);
+ NS_ENSURE_TRUE(tabChild, nullptr);
nsAutoString requestId;
aRequest->GetInternalId(requestId);
- paymentChild = new PaymentRequestChild();
+ PaymentRequestChild* paymentChild = new PaymentRequestChild(aRequest);
tabChild->SendPPaymentRequestConstructor(paymentChild);
- if (!mPaymentChildHash.Put(aRequest, paymentChild, mozilla::fallible) ) {
- return NS_ERROR_OUT_OF_MEMORY;
+ if (!mPaymentChildHash.Put(requestId, aRequest, mozilla::fallible) ) {
+ paymentChild->MaybeDelete();
+ return nullptr;
}
- paymentChild.forget(aChild);
- return NS_OK;
+
+ return paymentChild;
}
nsresult
-PaymentRequestManager::ReleasePaymentChild(PaymentRequestChild* aPaymentChild)
+PaymentRequestManager::ReleasePaymentChild(const nsAString& aId)
{
- NS_ENSURE_ARG_POINTER(aPaymentChild);
- for (auto iter = mPaymentChildHash.Iter(); !iter.Done(); iter.Next()) {
- RefPtr<PaymentRequestChild> 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<PaymentRequestChild> paymentChild;
- if(!mPaymentChildHash.Remove(aRequest, getter_AddRefs(paymentChild))) {
- return NS_ERROR_FAILURE;
- }
- if (NS_WARN_IF(!paymentChild)) {
- return NS_ERROR_FAILURE;
- }
- paymentChild->MaybeDelete();
+ mPaymentChildHash.Remove(aId);
return NS_OK;
}
nsresult
PaymentRequestManager::SendRequestPayment(PaymentRequest* aRequest,
const IPCPaymentActionRequest& aAction,
- bool aReleaseAfterSend)
+ bool aResponseExpected)
{
- RefPtr<PaymentRequestChild> requestChild;
- nsresult rv = GetPaymentChild(aRequest, getter_AddRefs(requestChild));
+ PaymentRequestChild* requestChild = GetPaymentChild(aRequest);
+ nsresult rv = requestChild->RequestPayment(aAction);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- rv = requestChild->RequestPayment(aAction);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- if (aReleaseAfterSend) {
- rv = ReleasePaymentChild(aRequest);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
+ if (aResponseExpected) {
+ auto count = mActivePayments.LookupForAdd(aRequest);
+ if (count) {
+ count.Data()++;
+ } else {
+ count.OrInsert([]() { return 1; });
}
}
return NS_OK;
}
+void
+PaymentRequestManager::NotifyRequestDone(PaymentRequest* aRequest)
+{
+ auto entry = mActivePayments.Lookup(aRequest);
+ MOZ_ASSERT(entry);
+ MOZ_ASSERT(entry.Data() > 0);
+
+ uint32_t count = --entry.Data();
+ if (count == 0) {
+ entry.Remove();
+ }
+}
+
already_AddRefed<PaymentRequestManager>
PaymentRequestManager::GetSingleton()
{
if (!gPaymentManager) {
gPaymentManager = new PaymentRequestManager();
ClearOnShutdown(&gPaymentManager);
}
RefPtr<PaymentRequestManager> manager = gPaymentManager;
return manager.forget();
}
already_AddRefed<PaymentRequest>
PaymentRequestManager::GetPaymentRequestById(const nsAString& aRequestId)
{
- for (const RefPtr<PaymentRequest>& request : mRequestQueue) {
- if (request->Equals(aRequestId)) {
- RefPtr<PaymentRequest> paymentRequest = request;
- return paymentRequest.forget();
- }
- }
- return nullptr;
+ // TODO Pass PaymentRequestChild objects around instead of strings.
+ RefPtr<PaymentRequest> request = mPaymentChildHash.Get(aRequestId);
+ return request.forget();
}
void
GetSelectedShippingOption(const PaymentDetailsBase& aDetails,
nsAString& aOption)
{
SetDOMStringToNull(aOption);
if (!aDetails.mShippingOptions.WasPassed()) {
@@ -455,21 +431,20 @@ PaymentRequestManager::CreatePayment(JSC
IPCPaymentCreateActionRequest action(internalId,
IPC::Principal(aTopLevelPrincipal),
methodData,
details,
options,
shippingOption);
- rv = SendRequestPayment(request, action, true);
+ rv = SendRequestPayment(request, action, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- mRequestQueue.AppendElement(request);
request.forget(aRequest);
return NS_OK;
}
nsresult
PaymentRequestManager::CanMakePayment(const nsAString& aRequestId)
{
RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
@@ -499,27 +474,30 @@ PaymentRequestManager::ShowPayment(const
IPCPaymentShowActionRequest action(requestId);
rv = SendRequestPayment(request, action);
}
mShowingRequest = request;
return rv;
}
nsresult
-PaymentRequestManager::AbortPayment(const nsAString& aRequestId)
+PaymentRequestManager::AbortPayment(PaymentRequest* aRequest, bool aDeferredShow)
{
RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
if (!request) {
return NS_ERROR_FAILURE;
}
+ MOZ_ASSERT(request == mShowingRequest);
nsAutoString requestId(aRequestId);
IPCPaymentAbortActionRequest action(requestId);
- return SendRequestPayment(request, action);
+ // If aDeferredShow is true, then show was called with a promise that was
+ // rejected. In that case, we need to remember that we called show earlier.
+ return SendRequestPayment(aRequest, action, aDeferredShow);
}
nsresult
PaymentRequestManager::CompletePayment(const nsAString& aRequestId,
const PaymentComplete& aComplete)
{
RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
if (!request) {
@@ -531,24 +509,25 @@ PaymentRequestManager::CompletePayment(c
if (completeIndex < ArrayLength(PaymentCompleteValues::strings)) {
completeStatusString.AssignASCII(
PaymentCompleteValues::strings[completeIndex].value);
}
nsAutoString requestId(aRequestId);
IPCPaymentCompleteActionRequest action(requestId, completeStatusString);
- return SendRequestPayment(request, action);
+ return SendRequestPayment(request, action, false);
}
nsresult
PaymentRequestManager::UpdatePayment(JSContext* aCx,
const nsAString& aRequestId,
const PaymentDetailsUpdate& aDetails,
- bool aRequestShipping)
+ bool aRequestShipping,
+ bool aDeferredShow)
{
NS_ENSURE_ARG_POINTER(aCx);
RefPtr<PaymentRequest> request = GetPaymentRequestById(aRequestId);
if (!request) {
return NS_ERROR_UNEXPECTED;
}
IPCPaymentDetails details;
nsresult rv = ConvertDetailsUpdate(aCx, aDetails, details, aRequestShipping);
@@ -560,34 +539,34 @@ PaymentRequestManager::UpdatePayment(JSC
SetDOMStringToNull(shippingOption);
if (aRequestShipping) {
GetSelectedShippingOption(aDetails, shippingOption);
request->SetShippingOption(shippingOption);
}
nsAutoString requestId(aRequestId);
IPCPaymentUpdateActionRequest action(requestId, details, shippingOption);
- return SendRequestPayment(request, action);
+
+ // If aDeferredShow is true, then this call serves as the ShowUpdate call for
+ // this request.
+ return SendRequestPayment(aRequest, action, aDeferredShow);
}
nsresult
PaymentRequestManager::RespondPayment(const IPCPaymentActionResponse& aResponse)
{
switch (aResponse.type()) {
case IPCPaymentActionResponse::TIPCPaymentCanMakeActionResponse: {
const IPCPaymentCanMakeActionResponse& response = aResponse;
RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
if (NS_WARN_IF(!request)) {
return NS_ERROR_FAILURE;
}
request->RespondCanMakePayment(response.result());
- nsresult rv = ReleasePaymentChild(request);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
+ NotifyRequestDone(request);
break;
}
case IPCPaymentActionResponse::TIPCPaymentShowActionResponse: {
const IPCPaymentShowActionResponse& response = aResponse;
RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
if (NS_WARN_IF(!request)) {
return NS_ERROR_FAILURE;
}
@@ -614,56 +593,44 @@ PaymentRequestManager::RespondPayment(co
response.data(),
response.payerName(),
response.payerEmail(),
response.payerPhone(),
rejectedReason);
if (NS_FAILED(rejectedReason)) {
MOZ_ASSERT(mShowingRequest == request);
mShowingRequest = nullptr;
- mRequestQueue.RemoveElement(request);
- nsresult rv = ReleasePaymentChild(request);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
+ NotifyRequestDone(aRequest);
}
break;
}
case IPCPaymentActionResponse::TIPCPaymentAbortActionResponse: {
const IPCPaymentAbortActionResponse& response = aResponse;
RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
if (NS_WARN_IF(!request)) {
return NS_ERROR_FAILURE;
}
request->RespondAbortPayment(response.isSucceeded());
if (response.isSucceeded()) {
MOZ_ASSERT(mShowingRequest == request);
- mRequestQueue.RemoveElement(request);
}
mShowingRequest = nullptr;
- nsresult rv = ReleasePaymentChild(request);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
+ NotifyRequestDone(request);
break;
}
case IPCPaymentActionResponse::TIPCPaymentCompleteActionResponse: {
const IPCPaymentCompleteActionResponse& response = aResponse;
RefPtr<PaymentRequest> request = GetPaymentRequestById(response.requestId());
if (NS_WARN_IF(!request)) {
return NS_ERROR_FAILURE;
}
request->RespondComplete();
MOZ_ASSERT(mShowingRequest == request);
mShowingRequest = nullptr;
- mRequestQueue.RemoveElement(request);
- nsresult rv = ReleasePaymentChild(request);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
+ NotifyRequestDone(request);
break;
}
default: {
return NS_ERROR_FAILURE;
}
}
return NS_OK;
}
--- a/dom/payments/PaymentRequestManager.h
+++ b/dom/payments/PaymentRequestManager.h
@@ -44,49 +44,54 @@ public:
CreatePayment(JSContext* aCx,
nsPIDOMWindowInner* aWindow,
nsIPrincipal* aTopLevelPrincipal,
const Sequence<PaymentMethodData>& aMethodData,
const PaymentDetailsInit& aDetails,
const PaymentOptions& aOptions,
PaymentRequest** aRequest);
- nsresult CanMakePayment(const nsAString& aRequestId);
- nsresult ShowPayment(const nsAString& aRequestId);
- nsresult AbortPayment(const nsAString& aRequestId);
- nsresult CompletePayment(const nsAString& aRequestId,
+ nsresult CanMakePayment(PaymentRequest* aRequest);
+ nsresult ShowPayment(PaymentRequest* aRequest);
+ nsresult AbortPayment(PaymentRequest* aRequest, bool aDeferredShow);
+ nsresult CompletePayment(PaymentRequest* aRequest,
const PaymentComplete& aComplete);
nsresult UpdatePayment(JSContext* aCx,
const nsAString& aRequestId,
const PaymentDetailsUpdate& aDetails,
- bool aRequestShipping);
+ bool aRequestShipping,
+ bool aDeferredShow);
nsresult RespondPayment(const IPCPaymentActionResponse& aResponse);
nsresult ChangeShippingAddress(const nsAString& aRequestId,
const IPCPaymentAddress& aAddress);
nsresult ChangeShippingOption(const nsAString& aRequestId,
const nsAString& aOption);
nsresult
- ReleasePaymentChild(PaymentRequestChild* aPaymentChild);
+ ReleasePaymentChild(const nsAString& aId);
private:
PaymentRequestManager() = default;
- ~PaymentRequestManager() = default;
+ ~PaymentRequestManager()
+ {
+ MOZ_ASSERT(mActivePayments.Count() == 0);
+ }
- nsresult GetPaymentChild(PaymentRequest* aRequest,
- PaymentRequestChild** aPaymentChild);
- nsresult ReleasePaymentChild(PaymentRequest* aRequest);
+ PaymentRequestChild* GetPaymentChild(PaymentRequest* aRequest);
nsresult SendRequestPayment(PaymentRequest* aRequest,
const IPCPaymentActionRequest& action,
- bool aReleaseAfterSend = false);
+ bool aResponseExpected = true);
+
+ void NotifyRequestDone(PaymentRequest* aRequest);
// The container for the created PaymentRequests
- nsTArray<RefPtr<PaymentRequest>> mRequestQueue;
- nsRefPtrHashtable<nsRefPtrHashKey<PaymentRequest>, PaymentRequestChild> mPaymentChildHash;
+ nsDataHashtable<nsStringHashKey, PaymentRequest*> mPaymentChildHash;
+ // Strong pointer to requests with ongoing IPC messages to the parent.
+ nsDataHashtable<nsRefPtrHashKey<PaymentRequest>, uint32_t> mActivePayments;
RefPtr<PaymentRequest> mShowingRequest;
};
} // end of namespace dom
} // end of namespace mozilla
#endif
--- a/dom/payments/PaymentRequestUpdateEvent.cpp
+++ b/dom/payments/PaymentRequestUpdateEvent.cpp
@@ -59,47 +59,47 @@ PaymentRequestUpdateEvent::ResolvedCallb
if (NS_WARN_IF(!aValue.isObject()) || !mWaitForUpdate) {
return;
}
// Converting value to a PaymentDetailsUpdate dictionary
PaymentDetailsUpdate details;
if (!details.Init(aCx, aValue)) {
- mRequest->AbortUpdate(NS_ERROR_TYPE_ERR);
+ mRequest->AbortUpdate(NS_ERROR_TYPE_ERR, false);
JS_ClearPendingException(aCx);
return;
}
// Validate and canonicalize the details
// requestShipping must be true here. PaymentRequestUpdateEvent is only
// dispatched when shippingAddress/shippingOption is changed, and it also means
// Options.RequestShipping must be true while creating the corresponding
// PaymentRequest.
nsresult rv = mRequest->IsValidDetailsUpdate(details, true/*aRequestShipping*/);
if (NS_FAILED(rv)) {
- mRequest->AbortUpdate(rv);
+ mRequest->AbortUpdate(rv, false);
return;
}
// Update the PaymentRequest with the new details
- if (NS_FAILED(mRequest->UpdatePayment(aCx, details))) {
- mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR);
+ if (NS_FAILED(mRequest->UpdatePayment(aCx, details, false))) {
+ mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR, false);
return;
}
mWaitForUpdate = false;
mRequest->SetUpdating(false);
}
void
PaymentRequestUpdateEvent::RejectedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue)
{
MOZ_ASSERT(mRequest);
- mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR);
+ mRequest->AbortUpdate(NS_ERROR_DOM_ABORT_ERR, false);
mWaitForUpdate = false;
mRequest->SetUpdating(false);
}
void
PaymentRequestUpdateEvent::UpdateWith(Promise& aPromise, ErrorResult& aRv)
{
if (!IsTrusted()) {
--- a/dom/payments/ipc/PaymentRequestChild.cpp
+++ b/dom/payments/ipc/PaymentRequestChild.cpp
@@ -1,106 +1,122 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PaymentRequestChild.h"
+#include "mozilla/dom/PaymentRequest.h"
#include "mozilla/dom/PaymentRequestManager.h"
namespace mozilla {
namespace dom {
-PaymentRequestChild::PaymentRequestChild()
- : mActorAlive(true)
+PaymentRequestChild::PaymentRequestChild(PaymentRequest* aRequest)
+ : mRequest(aRequest)
{
+ mRequest->SetIPC(this);
}
nsresult
PaymentRequestChild::RequestPayment(const IPCPaymentActionRequest& aAction)
{
- if (!mActorAlive) {
+ if (!mRequest) {
return NS_ERROR_FAILURE;
}
if (!SendRequestPayment(aAction)) {
return NS_ERROR_FAILURE;
}
return NS_OK;
}
mozilla::ipc::IPCResult
PaymentRequestChild::RecvRespondPayment(const IPCPaymentActionResponse& aResponse)
{
- if (!mActorAlive) {
+ if (!mRequest) {
return IPC_FAIL_NO_REASON(this);
}
const IPCPaymentActionResponse& response = aResponse;
RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
MOZ_ASSERT(manager);
nsresult rv = manager->RespondPayment(response);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
PaymentRequestChild::RecvChangeShippingAddress(const nsString& aRequestId,
const IPCPaymentAddress& aAddress)
{
- if (!mActorAlive) {
+ if (!mRequest) {
return IPC_FAIL_NO_REASON(this);
}
RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
MOZ_ASSERT(manager);
nsresult rv = manager->ChangeShippingAddress(aRequestId, aAddress);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
mozilla::ipc::IPCResult
PaymentRequestChild::RecvChangeShippingOption(const nsString& aRequestId,
const nsString& aOption)
{
- if (!mActorAlive) {
+ if (!mRequest) {
return IPC_FAIL_NO_REASON(this);
}
RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
MOZ_ASSERT(manager);
nsresult rv = manager->ChangeShippingOption(aRequestId, aOption);
if (NS_WARN_IF(NS_FAILED(rv))) {
return IPC_FAIL_NO_REASON(this);
}
return IPC_OK();
}
void
PaymentRequestChild::ActorDestroy(ActorDestroyReason aWhy)
{
- mActorAlive = false;
- RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
- MOZ_ASSERT(manager);
- nsresult rv = manager->ReleasePaymentChild(this);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- MOZ_ASSERT(false);
+ if (mRequest) {
+ DetachFromRequest();
}
}
void
PaymentRequestChild::MaybeDelete()
{
- if (mActorAlive) {
- mActorAlive = false;
+ if (mRequest) {
+ DetachFromRequest();
Send__delete__(this);
}
}
bool
PaymentRequestChild::SendRequestPayment(const IPCPaymentActionRequest& aAction)
{
return PPaymentRequestChild::SendRequestPayment(aAction);
}
+void
+PaymentRequestChild::DetachFromRequest()
+{
+ MOZ_ASSERT(mRequest);
+ nsAutoString id;
+ mRequest->GetInternalId(id);
+
+ RefPtr<PaymentRequestManager> manager = PaymentRequestManager::GetSingleton();
+ MOZ_ASSERT(manager);
+ nsresult rv = manager->ReleasePaymentChild(id);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ MOZ_ASSERT(false);
+ }
+
+ mRequest->SetIPC(nullptr);
+ mRequest = nullptr;
+}
+
} // end of namespace dom
} // end of namespace mozilla
--- a/dom/payments/ipc/PaymentRequestChild.h
+++ b/dom/payments/ipc/PaymentRequestChild.h
@@ -7,21 +7,22 @@
#ifndef mozilla_dom_PaymentRequestChild_h
#define mozilla_dom_PaymentRequestChild_h
#include "mozilla/dom/PPaymentRequestChild.h"
namespace mozilla {
namespace dom {
+class PaymentRequest;
+
class PaymentRequestChild final : public PPaymentRequestChild
{
- NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PaymentRequestChild);
public:
- PaymentRequestChild();
+ explicit PaymentRequestChild(PaymentRequest* aRequest);
void MaybeDelete();
nsresult RequestPayment(const IPCPaymentActionRequest& aAction);
protected:
mozilla::ipc::IPCResult
RecvRespondPayment(const IPCPaymentActionResponse& aResponse) override;
@@ -35,16 +36,16 @@ protected:
const nsString& aOption) override;
void ActorDestroy(ActorDestroyReason aWhy) override;
private:
~PaymentRequestChild() = default;
bool SendRequestPayment(const IPCPaymentActionRequest& aAction);
-
- bool mActorAlive;
+ void DetachFromRequest();
+ PaymentRequest* MOZ_NON_OWNING_REF mRequest;
};
} // end of namespace dom
} // end of namespace mozilla
#endif