1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "ClientSourceOpChild.h"
9 #include "ClientSource.h"
10 #include "ClientSourceChild.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/Unused.h"
14 namespace mozilla::dom
{
16 ClientSource
* ClientSourceOpChild::GetSource() const {
17 auto actor
= static_cast<ClientSourceChild
*>(Manager());
18 return actor
->GetSource();
21 template <typename Method
, typename
... Args
>
22 void ClientSourceOpChild::DoSourceOp(Method aMethod
, Args
&&... aArgs
) {
23 RefPtr
<ClientOpPromise
> promise
;
24 nsCOMPtr
<nsISerialEventTarget
> target
;
26 // Some ClientSource operations can cause the ClientSource to be destroyed.
27 // This means we should reference the ClientSource pointer for the minimum
28 // possible to start the operation. Use an extra block scope here to help
29 // enforce this and prevent accidental usage later in the method.
31 ClientSource
* source
= GetSource();
33 CopyableErrorResult rv
;
34 rv
.ThrowAbortError("Unknown Client");
35 Unused
<< PClientSourceOpChild::Send__delete__(this, rv
);
39 target
= source
->EventTarget();
41 // This may cause the ClientSource object to be destroyed. Do not
42 // use the source variable after this call.
43 promise
= (source
->*aMethod
)(std::forward
<Args
>(aArgs
)...);
46 // The ClientSource methods are required to always return a promise. If
47 // they encounter an error they should just immediately resolve or reject
48 // the promise as appropriate.
49 MOZ_DIAGNOSTIC_ASSERT(promise
);
51 // Capture 'this' is safe here because we disconnect the promise
52 // ActorDestroy() which ensures neither lambda is called if the
53 // actor is destroyed before the source operation completes.
55 // Also capture the promise to ensure it lives until we get a reaction
56 // or the actor starts shutting down and we disconnect our Thenable.
57 // If the ClientSource is doing something async it may throw away the
58 // promise on its side if the global is closed.
62 [this, promise
](const mozilla::dom::ClientOpResult
& aResult
) {
63 mPromiseRequestHolder
.Complete();
64 Unused
<< PClientSourceOpChild::Send__delete__(this, aResult
);
66 [this, promise
](const CopyableErrorResult
& aRv
) {
67 mPromiseRequestHolder
.Complete();
68 Unused
<< PClientSourceOpChild::Send__delete__(this, aRv
);
70 ->Track(mPromiseRequestHolder
);
73 void ClientSourceOpChild::ActorDestroy(ActorDestroyReason aReason
) {
77 void ClientSourceOpChild::Init(const ClientOpConstructorArgs
& aArgs
) {
78 switch (aArgs
.type()) {
79 case ClientOpConstructorArgs::TClientControlledArgs
: {
80 DoSourceOp(&ClientSource::Control
, aArgs
.get_ClientControlledArgs());
83 case ClientOpConstructorArgs::TClientFocusArgs
: {
84 DoSourceOp(&ClientSource::Focus
, aArgs
.get_ClientFocusArgs());
87 case ClientOpConstructorArgs::TClientPostMessageArgs
: {
88 DoSourceOp(&ClientSource::PostMessage
, aArgs
.get_ClientPostMessageArgs());
91 case ClientOpConstructorArgs::TClientClaimArgs
: {
92 MOZ_ASSERT_UNREACHABLE("shouldn't happen with parent intercept");
95 case ClientOpConstructorArgs::TClientGetInfoAndStateArgs
: {
96 DoSourceOp(&ClientSource::GetInfoAndState
,
97 aArgs
.get_ClientGetInfoAndStateArgs());
100 case ClientOpConstructorArgs::TClientEvictBFCacheArgs
: {
101 DoSourceOp(&ClientSource::EvictFromBFCacheOp
);
105 MOZ_ASSERT_UNREACHABLE("unknown client operation!");
112 if (mDeletionRequested
) {
118 void ClientSourceOpChild::ScheduleDeletion() {
125 mDeletionRequested
.Flip();
128 ClientSourceOpChild::~ClientSourceOpChild() {
129 MOZ_DIAGNOSTIC_ASSERT(mInitialized
);
132 void ClientSourceOpChild::Cleanup() {
133 mPromiseRequestHolder
.DisconnectIfExists();
136 } // namespace mozilla::dom