Bug 1942006 - Upstream a variety of Servo-specific code from Servo's downstream fork...
[gecko.git] / widget / PrintBackgroundTask.h
blob57d5d794d415eb5292291456024debea936f1499
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef mozilla_PrintBackgroundTask_h_
7 #define mozilla_PrintBackgroundTask_h_
9 #include "mozilla/dom/Promise.h"
10 #include "mozilla/ErrorResult.h"
12 #include <tuple>
13 #include <utility>
15 // A helper to resolve a DOM Promise with the result of a const method, executed
16 // in another thread.
18 // Once in the main thread, the caller can turn the result of the method into a
19 // JSValue by specializing ResolveOrReject.
20 namespace mozilla {
22 template <typename T, typename Result>
23 void ResolveOrReject(dom::Promise& aPromise, T&, Result& aResult) {
24 aPromise.MaybeResolve(std::forward<Result>(aResult));
27 template <typename T, typename Result, typename... Args>
28 using PrintBackgroundTask = Result (T::*)(Args...) const;
30 template <typename T, typename Result, typename... Args>
31 void SpawnPrintBackgroundTask(
32 T& aReceiver, dom::Promise& aPromise,
33 PrintBackgroundTask<T, Result, Args...> aBackgroundTask, Args... aArgs) {
34 auto promiseHolder = MakeRefPtr<nsMainThreadPtrHolder<dom::Promise>>(
35 "nsPrinterBase::SpawnBackgroundTaskPromise", &aPromise);
36 // We actually want to allow to access the printer data from the callback, so
37 // disable strict checking. They should of course only access immutable
38 // members.
39 auto holder = MakeRefPtr<nsMainThreadPtrHolder<T>>(
40 "nsPrinterBase::SpawnBackgroundTaskPrinter", &aReceiver,
41 /* strict = */ false);
42 // See
43 // https://stackoverflow.com/questions/47496358/c-lambdas-how-to-capture-variadic-parameter-pack-from-the-upper-scope
44 // about the tuple shenanigans. It could be improved with C++20
45 NS_DispatchBackgroundTask(
46 NS_NewRunnableFunction(
47 "SpawnPrintBackgroundTask",
48 [holder = std::move(holder), promiseHolder = std::move(promiseHolder),
49 backgroundTask = aBackgroundTask,
50 aArgs = std::make_tuple(std::forward<Args>(aArgs)...)] {
51 Result result = std::apply(
52 [&](auto&&... args) {
53 return (holder->get()->*backgroundTask)(args...);
55 std::move(aArgs));
56 NS_DispatchToMainThread(NS_NewRunnableFunction(
57 "SpawnPrintBackgroundTaskResolution",
58 [holder = std::move(holder),
59 promiseHolder = std::move(promiseHolder),
60 result = std::move(result)] {
61 ResolveOrReject(*promiseHolder->get(), *holder->get(),
62 result);
63 }));
64 }),
65 NS_DISPATCH_EVENT_MAY_BLOCK);
68 // Gets a fresh promise into aResultPromise, that resolves whenever the print
69 // background task finishes.
70 template <typename T, typename Result, typename... Args>
71 nsresult PrintBackgroundTaskPromise(
72 T& aReceiver, JSContext* aCx, dom::Promise** aResultPromise,
73 PrintBackgroundTask<T, Result, Args...> aTask, Args... aArgs) {
74 ErrorResult rv;
75 RefPtr<dom::Promise> promise =
76 dom::Promise::Create(xpc::CurrentNativeGlobal(aCx), rv);
77 if (MOZ_UNLIKELY(rv.Failed())) {
78 return rv.StealNSResult();
81 SpawnPrintBackgroundTask(aReceiver, *promise, aTask,
82 std::forward<Args>(aArgs)...);
84 promise.forget(aResultPromise);
85 return NS_OK;
88 // Resolves an async attribute via a background task, creating and storing a
89 // promise as needed in aPromiseSlot.
90 template <typename T, typename Result, typename... Args>
91 nsresult AsyncPromiseAttributeGetter(
92 T& aReceiver, RefPtr<dom::Promise>& aPromiseSlot, JSContext* aCx,
93 dom::Promise** aResultPromise,
94 PrintBackgroundTask<T, Result, Args...> aTask, Args... aArgs) {
95 if (RefPtr<dom::Promise> existing = aPromiseSlot) {
96 existing.forget(aResultPromise);
97 return NS_OK;
100 nsresult rv = PrintBackgroundTaskPromise(aReceiver, aCx, aResultPromise,
101 aTask, std::forward<Args>(aArgs)...);
102 NS_ENSURE_SUCCESS(rv, rv);
104 aPromiseSlot = *aResultPromise;
105 return NS_OK;
108 } // namespace mozilla
110 #endif