ClientSourceOpChild.cpp (4376B)
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/. */ 6 7 #include "ClientSourceOpChild.h" 8 9 #include "ClientSource.h" 10 #include "ClientSourceChild.h" 11 #include "mozilla/Assertions.h" 12 13 namespace mozilla::dom { 14 15 ClientSource* ClientSourceOpChild::GetSource() const { 16 auto actor = static_cast<ClientSourceChild*>(Manager()); 17 return actor->GetSource(); 18 } 19 20 template <typename Method, typename... Args> 21 void ClientSourceOpChild::DoSourceOp(Method aMethod, Args&&... aArgs) { 22 RefPtr<ClientOpPromise> promise; 23 nsCOMPtr<nsISerialEventTarget> target; 24 25 // Some ClientSource operations can cause the ClientSource to be destroyed. 26 // This means we should reference the ClientSource pointer for the minimum 27 // possible to start the operation. Use an extra block scope here to help 28 // enforce this and prevent accidental usage later in the method. 29 { 30 ClientSource* source = GetSource(); 31 if (!source) { 32 CopyableErrorResult rv; 33 rv.ThrowAbortError("Unknown Client"); 34 (void)PClientSourceOpChild::Send__delete__(this, rv); 35 return; 36 } 37 38 target = source->EventTarget(); 39 40 // This may cause the ClientSource object to be destroyed. Do not 41 // use the source variable after this call. 42 promise = (source->*aMethod)(std::forward<Args>(aArgs)...); 43 } 44 45 // The ClientSource methods are required to always return a promise. If 46 // they encounter an error they should just immediately resolve or reject 47 // the promise as appropriate. 48 MOZ_DIAGNOSTIC_ASSERT(promise); 49 50 // Capture 'this' is safe here because we disconnect the promise 51 // ActorDestroy() which ensures neither lambda is called if the 52 // actor is destroyed before the source operation completes. 53 // 54 // Also capture the promise to ensure it lives until we get a reaction 55 // or the actor starts shutting down and we disconnect our Thenable. 56 // If the ClientSource is doing something async it may throw away the 57 // promise on its side if the global is closed. 58 promise 59 ->Then( 60 target, __func__, 61 [this, promise](const mozilla::dom::ClientOpResult& aResult) { 62 mPromiseRequestHolder.Complete(); 63 (void)PClientSourceOpChild::Send__delete__(this, aResult); 64 }, 65 [this, promise](const CopyableErrorResult& aRv) { 66 mPromiseRequestHolder.Complete(); 67 (void)PClientSourceOpChild::Send__delete__(this, aRv); 68 }) 69 ->Track(mPromiseRequestHolder); 70 } 71 72 void ClientSourceOpChild::ActorDestroy(ActorDestroyReason aReason) { 73 Cleanup(); 74 } 75 76 void ClientSourceOpChild::Init(const ClientOpConstructorArgs& aArgs) { 77 switch (aArgs.type()) { 78 case ClientOpConstructorArgs::TClientControlledArgs: { 79 DoSourceOp(&ClientSource::Control, aArgs.get_ClientControlledArgs()); 80 break; 81 } 82 case ClientOpConstructorArgs::TClientFocusArgs: { 83 DoSourceOp(&ClientSource::Focus, aArgs.get_ClientFocusArgs()); 84 break; 85 } 86 case ClientOpConstructorArgs::TClientPostMessageArgs: { 87 DoSourceOp(&ClientSource::PostMessage, aArgs.get_ClientPostMessageArgs()); 88 break; 89 } 90 case ClientOpConstructorArgs::TClientClaimArgs: { 91 MOZ_ASSERT_UNREACHABLE("shouldn't happen with parent intercept"); 92 break; 93 } 94 case ClientOpConstructorArgs::TClientGetInfoAndStateArgs: { 95 DoSourceOp(&ClientSource::GetInfoAndState, 96 aArgs.get_ClientGetInfoAndStateArgs()); 97 break; 98 } 99 case ClientOpConstructorArgs::TClientEvictBFCacheArgs: { 100 DoSourceOp(&ClientSource::EvictFromBFCacheOp); 101 break; 102 } 103 default: { 104 MOZ_ASSERT_UNREACHABLE("unknown client operation!"); 105 break; 106 } 107 } 108 109 mInitialized.Flip(); 110 111 if (mDeletionRequested) { 112 Cleanup(); 113 delete this; 114 } 115 } 116 117 void ClientSourceOpChild::ScheduleDeletion() { 118 if (mInitialized) { 119 Cleanup(); 120 delete this; 121 return; 122 } 123 124 mDeletionRequested.Flip(); 125 } 126 127 ClientSourceOpChild::~ClientSourceOpChild() { 128 MOZ_DIAGNOSTIC_ASSERT(mInitialized); 129 } 130 131 void ClientSourceOpChild::Cleanup() { 132 mPromiseRequestHolder.DisconnectIfExists(); 133 } 134 135 } // namespace mozilla::dom