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 #include "nsPrinterBase.h"
7 #include "nsPaperMargin.h"
10 #include "nsIPrintSettings.h"
11 #include "nsPrintSettingsService.h"
12 #include "PrintBackgroundTask.h"
13 #include "mozilla/EnumeratedArrayCycleCollection.h"
14 #include "mozilla/dom/Promise.h"
16 using namespace mozilla
;
17 using mozilla::dom::Promise
;
18 using mozilla::gfx::MarginDouble
;
20 // The maximum error when considering a paper size equal, in points.
21 // There is some variance in the actual sizes returned by printer drivers and
22 // print servers for paper sizes. This is a best-guess based on initial
23 // telemetry which should catch most near-miss dimensions. This should let us
24 // get consistent paper size names even when the size isn't quite exactly the
26 static constexpr double kPaperSizePointsEpsilon
= 4.0;
28 // Basic implementation of nsIPrinterInfo
29 class nsPrinterInfo
: public nsIPrinterInfo
{
31 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
32 NS_DECL_CYCLE_COLLECTION_CLASS(nsPrinterInfo
)
33 NS_DECL_NSIPRINTERINFO
34 nsPrinterInfo() = delete;
35 nsPrinterInfo(nsPrinterBase
& aPrinter
,
36 const nsPrinterBase::PrinterInfo
& aPrinterInfo
)
38 CreatePlatformPrintSettings(aPrinterInfo
.mDefaultSettings
)) {
39 mPaperList
.SetCapacity(aPrinterInfo
.mPaperList
.Length());
40 for (const PaperInfo
& info
: aPrinterInfo
.mPaperList
) {
41 mPaperList
.AppendElement(MakeRefPtr
<nsPaper
>(aPrinter
, info
));
44 // Update the printer's default settings with the global settings.
45 nsCOMPtr
<nsIPrintSettingsService
> printSettingsSvc
=
46 do_GetService("@mozilla.org/gfx/printsettings-service;1");
47 if (printSettingsSvc
) {
48 // Passing false as the second parameter means we don't get the printer
50 printSettingsSvc
->InitPrintSettingsFromPrefs(
51 mDefaultSettings
, false, nsIPrintSettings::kInitSaveAll
);
56 virtual ~nsPrinterInfo() = default;
58 nsTArray
<RefPtr
<nsIPaper
>> mPaperList
;
59 RefPtr
<nsIPrintSettings
> mDefaultSettings
;
63 nsPrinterInfo::GetPaperList(nsTArray
<RefPtr
<nsIPaper
>>& aPaperList
) {
64 aPaperList
= mPaperList
.Clone();
69 nsPrinterInfo::GetDefaultSettings(nsIPrintSettings
** aDefaultSettings
) {
70 NS_ENSURE_ARG_POINTER(aDefaultSettings
);
71 MOZ_ASSERT(mDefaultSettings
);
72 RefPtr
<nsIPrintSettings
> settings
= mDefaultSettings
;
73 settings
.forget(aDefaultSettings
);
77 NS_IMPL_CYCLE_COLLECTION(nsPrinterInfo
, mPaperList
, mDefaultSettings
)
79 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterInfo
)
80 NS_INTERFACE_MAP_ENTRY(nsIPrinterInfo
)
81 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIPrinterInfo
)
84 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterInfo
)
85 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterInfo
)
90 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
&,
91 const MarginDouble
& aResult
) {
92 auto margin
= MakeRefPtr
<nsPaperMargin
>(aResult
);
93 aPromise
.MaybeResolve(margin
);
97 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
& aPrinter
,
98 const nsTArray
<PaperInfo
>& aResult
) {
99 nsTArray
<RefPtr
<nsPaper
>> result
;
100 result
.SetCapacity(aResult
.Length());
101 for (const PaperInfo
& info
: aResult
) {
102 result
.AppendElement(MakeRefPtr
<nsPaper
>(aPrinter
, info
));
104 aPromise
.MaybeResolve(result
);
108 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
& aPrinter
,
109 const PrintSettingsInitializer
& aResult
) {
110 aPromise
.MaybeResolve(
111 RefPtr
<nsIPrintSettings
>(CreatePlatformPrintSettings(aResult
)));
115 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
& aPrinter
,
116 const nsPrinterBase::PrinterInfo
& aResult
) {
117 aPromise
.MaybeResolve(MakeRefPtr
<nsPrinterInfo
>(aPrinter
, aResult
));
120 } // namespace mozilla
122 template <typename T
, typename
... Args
>
123 nsresult
nsPrinterBase::AsyncPromiseAttributeGetter(
124 JSContext
* aCx
, Promise
** aResultPromise
, AsyncAttribute aAttribute
,
125 BackgroundTask
<T
, Args
...> aBackgroundTask
, Args
... aArgs
) {
126 MOZ_ASSERT(NS_IsMainThread());
128 static constexpr EnumeratedArray
<AsyncAttribute
, nsLiteralCString
,
129 size_t(AsyncAttribute::Last
)>
130 attributeKeys
{"SupportsDuplex"_ns
, "SupportsColor"_ns
,
131 "SupportsMonochrome"_ns
, "SupportsCollation"_ns
,
133 return mozilla::AsyncPromiseAttributeGetter(
134 *this, mAsyncAttributePromises
[aAttribute
], aCx
, aResultPromise
,
135 attributeKeys
[aAttribute
], aBackgroundTask
, std::forward
<Args
>(aArgs
)...);
138 NS_IMETHODIMP
nsPrinterBase::CopyFromWithValidation(
139 nsIPrintSettings
* aSettingsToCopyFrom
, JSContext
* aCx
,
140 Promise
** aResultPromise
) {
141 MOZ_ASSERT(NS_IsMainThread());
142 MOZ_ASSERT(aResultPromise
);
144 ErrorResult errorResult
;
145 RefPtr
<dom::Promise
> promise
=
146 dom::Promise::Create(xpc::CurrentNativeGlobal(aCx
), errorResult
);
147 if (MOZ_UNLIKELY(errorResult
.Failed())) {
148 return errorResult
.StealNSResult();
151 nsCOMPtr
<nsIPrintSettings
> settings
;
152 MOZ_ALWAYS_SUCCEEDS(aSettingsToCopyFrom
->Clone(getter_AddRefs(settings
)));
153 nsString printerName
;
154 MOZ_ALWAYS_SUCCEEDS(GetName(printerName
));
155 MOZ_ALWAYS_SUCCEEDS(settings
->SetPrinterName(printerName
));
156 promise
->MaybeResolve(settings
);
157 promise
.forget(aResultPromise
);
162 NS_IMETHODIMP
nsPrinterBase::GetSupportsDuplex(JSContext
* aCx
,
163 Promise
** aResultPromise
) {
164 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
165 AsyncAttribute::SupportsDuplex
,
166 &nsPrinterBase::SupportsDuplex
);
169 NS_IMETHODIMP
nsPrinterBase::GetSupportsColor(JSContext
* aCx
,
170 Promise
** aResultPromise
) {
171 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
172 AsyncAttribute::SupportsColor
,
173 &nsPrinterBase::SupportsColor
);
176 NS_IMETHODIMP
nsPrinterBase::GetSupportsMonochrome(JSContext
* aCx
,
177 Promise
** aResultPromise
) {
178 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
179 AsyncAttribute::SupportsMonochrome
,
180 &nsPrinterBase::SupportsMonochrome
);
183 NS_IMETHODIMP
nsPrinterBase::GetSupportsCollation(JSContext
* aCx
,
184 Promise
** aResultPromise
) {
185 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
186 AsyncAttribute::SupportsCollation
,
187 &nsPrinterBase::SupportsCollation
);
190 NS_IMETHODIMP
nsPrinterBase::GetPrinterInfo(JSContext
* aCx
,
191 Promise
** aResultPromise
) {
192 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
193 AsyncAttribute::PrinterInfo
,
194 &nsPrinterBase::CreatePrinterInfo
);
197 void nsPrinterBase::QueryMarginsForPaper(Promise
& aPromise
,
198 const nsString
& aPaperId
) {
199 return SpawnPrintBackgroundTask(*this, aPromise
, "MarginsForPaper"_ns
,
200 &nsPrinterBase::GetMarginsForPaper
, aPaperId
);
203 NS_IMPL_CYCLE_COLLECTION(nsPrinterBase
, mAsyncAttributePromises
)
205 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterBase
)
206 NS_INTERFACE_MAP_ENTRY(nsIPrinter
)
207 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIPrinter
)
210 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterBase
)
211 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterBase
)
213 nsPrinterBase::nsPrinterBase(const CommonPaperInfoArray
* aPaperInfoArray
)
214 : mCommonPaperInfo(aPaperInfoArray
) {
215 MOZ_DIAGNOSTIC_ASSERT(aPaperInfoArray
, "Localized paper info was null");
217 nsPrinterBase::~nsPrinterBase() = default;
219 const PaperInfo
* nsPrinterBase::FindCommonPaperSize(
220 const gfx::SizeDouble
& aSize
) const {
221 for (const PaperInfo
& paper
: *mCommonPaperInfo
) {
222 if (std::abs(paper
.mSize
.width
- aSize
.width
) <= kPaperSizePointsEpsilon
&&
223 std::abs(paper
.mSize
.height
- aSize
.height
) <=
224 kPaperSizePointsEpsilon
) {