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/dom/Promise.h"
15 using namespace mozilla
;
16 using mozilla::dom::Promise
;
17 using mozilla::gfx::MarginDouble
;
19 // The maximum error when considering a paper size equal, in points.
20 // There is some variance in the actual sizes returned by printer drivers and
21 // print servers for paper sizes. This is a best-guess based on initial
22 // telemetry which should catch most near-miss dimensions. This should let us
23 // get consistent paper size names even when the size isn't quite exactly the
25 static constexpr double kPaperSizePointsEpsilon
= 4.0;
27 // Basic implementation of nsIPrinterInfo
28 class nsPrinterInfo
: public nsIPrinterInfo
{
30 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
31 NS_DECL_CYCLE_COLLECTION_CLASS(nsPrinterInfo
)
32 NS_DECL_NSIPRINTERINFO
33 nsPrinterInfo() = delete;
34 nsPrinterInfo(nsPrinterBase
& aPrinter
,
35 const nsPrinterBase::PrinterInfo
& aPrinterInfo
)
37 CreatePlatformPrintSettings(aPrinterInfo
.mDefaultSettings
)) {
38 mPaperList
.SetCapacity(aPrinterInfo
.mPaperList
.Length());
39 for (const PaperInfo
& info
: aPrinterInfo
.mPaperList
) {
40 mPaperList
.AppendElement(MakeRefPtr
<nsPaper
>(aPrinter
, info
));
43 // Update the printer's default settings with the global settings.
44 nsCOMPtr
<nsIPrintSettingsService
> printSettingsSvc
=
45 do_GetService("@mozilla.org/gfx/printsettings-service;1");
46 if (printSettingsSvc
) {
47 // Passing false as the second parameter means we don't get the printer
49 printSettingsSvc
->InitPrintSettingsFromPrefs(
50 mDefaultSettings
, false, nsIPrintSettings::kInitSaveAll
);
55 virtual ~nsPrinterInfo() = default;
57 nsTArray
<RefPtr
<nsIPaper
>> mPaperList
;
58 RefPtr
<nsIPrintSettings
> mDefaultSettings
;
62 nsPrinterInfo::GetPaperList(nsTArray
<RefPtr
<nsIPaper
>>& aPaperList
) {
63 aPaperList
= mPaperList
.Clone();
68 nsPrinterInfo::GetDefaultSettings(nsIPrintSettings
** aDefaultSettings
) {
69 NS_ENSURE_ARG_POINTER(aDefaultSettings
);
70 MOZ_ASSERT(mDefaultSettings
);
71 RefPtr
<nsIPrintSettings
> settings
= mDefaultSettings
;
72 settings
.forget(aDefaultSettings
);
76 NS_IMPL_CYCLE_COLLECTION(nsPrinterInfo
, mPaperList
, mDefaultSettings
)
78 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterInfo
)
79 NS_INTERFACE_MAP_ENTRY(nsIPrinterInfo
)
80 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIPrinterInfo
)
83 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterInfo
)
84 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterInfo
)
86 template <typename Index
, Index Size
, typename Value
>
87 inline void ImplCycleCollectionTraverse(
88 nsCycleCollectionTraversalCallback
& aCallback
,
89 EnumeratedArray
<Index
, Size
, Value
>& aArray
, const char* aName
,
90 uint32_t aFlags
= 0) {
91 aFlags
|= CycleCollectionEdgeNameArrayFlag
;
92 for (Value
& element
: aArray
) {
93 ImplCycleCollectionTraverse(aCallback
, element
, aName
, aFlags
);
97 template <typename Index
, Index Size
, typename Value
>
98 inline void ImplCycleCollectionUnlink(
99 EnumeratedArray
<Index
, Size
, Value
>& aArray
) {
100 for (Value
& element
: aArray
) {
101 ImplCycleCollectionUnlink(element
);
108 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
&,
109 const MarginDouble
& aResult
) {
110 auto margin
= MakeRefPtr
<nsPaperMargin
>(aResult
);
111 aPromise
.MaybeResolve(margin
);
115 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
& aPrinter
,
116 const nsTArray
<PaperInfo
>& aResult
) {
117 nsTArray
<RefPtr
<nsPaper
>> result
;
118 result
.SetCapacity(aResult
.Length());
119 for (const PaperInfo
& info
: aResult
) {
120 result
.AppendElement(MakeRefPtr
<nsPaper
>(aPrinter
, info
));
122 aPromise
.MaybeResolve(result
);
126 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
& aPrinter
,
127 const PrintSettingsInitializer
& aResult
) {
128 aPromise
.MaybeResolve(
129 RefPtr
<nsIPrintSettings
>(CreatePlatformPrintSettings(aResult
)));
133 void ResolveOrReject(Promise
& aPromise
, nsPrinterBase
& aPrinter
,
134 const nsPrinterBase::PrinterInfo
& aResult
) {
135 aPromise
.MaybeResolve(MakeRefPtr
<nsPrinterInfo
>(aPrinter
, aResult
));
138 } // namespace mozilla
140 template <typename T
, typename
... Args
>
141 nsresult
nsPrinterBase::AsyncPromiseAttributeGetter(
142 JSContext
* aCx
, Promise
** aResultPromise
, AsyncAttribute aAttribute
,
143 BackgroundTask
<T
, Args
...> aBackgroundTask
, Args
... aArgs
) {
144 MOZ_ASSERT(NS_IsMainThread());
146 static constexpr EnumeratedArray
<AsyncAttribute
, AsyncAttribute::Last
,
148 attributeKeys
{"SupportsDuplex"_ns
, "SupportsColor"_ns
,
149 "SupportsMonochrome"_ns
, "SupportsCollation"_ns
,
151 return mozilla::AsyncPromiseAttributeGetter(
152 *this, mAsyncAttributePromises
[aAttribute
], aCx
, aResultPromise
,
153 attributeKeys
[aAttribute
], aBackgroundTask
, std::forward
<Args
>(aArgs
)...);
156 NS_IMETHODIMP
nsPrinterBase::CopyFromWithValidation(
157 nsIPrintSettings
* aSettingsToCopyFrom
, JSContext
* aCx
,
158 Promise
** aResultPromise
) {
159 MOZ_ASSERT(NS_IsMainThread());
160 MOZ_ASSERT(aResultPromise
);
162 ErrorResult errorResult
;
163 RefPtr
<dom::Promise
> promise
=
164 dom::Promise::Create(xpc::CurrentNativeGlobal(aCx
), errorResult
);
165 if (MOZ_UNLIKELY(errorResult
.Failed())) {
166 return errorResult
.StealNSResult();
169 nsCOMPtr
<nsIPrintSettings
> settings
;
170 MOZ_ALWAYS_SUCCEEDS(aSettingsToCopyFrom
->Clone(getter_AddRefs(settings
)));
171 nsString printerName
;
172 MOZ_ALWAYS_SUCCEEDS(GetName(printerName
));
173 MOZ_ALWAYS_SUCCEEDS(settings
->SetPrinterName(printerName
));
174 promise
->MaybeResolve(settings
);
175 promise
.forget(aResultPromise
);
180 NS_IMETHODIMP
nsPrinterBase::GetSupportsDuplex(JSContext
* aCx
,
181 Promise
** aResultPromise
) {
182 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
183 AsyncAttribute::SupportsDuplex
,
184 &nsPrinterBase::SupportsDuplex
);
187 NS_IMETHODIMP
nsPrinterBase::GetSupportsColor(JSContext
* aCx
,
188 Promise
** aResultPromise
) {
189 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
190 AsyncAttribute::SupportsColor
,
191 &nsPrinterBase::SupportsColor
);
194 NS_IMETHODIMP
nsPrinterBase::GetSupportsMonochrome(JSContext
* aCx
,
195 Promise
** aResultPromise
) {
196 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
197 AsyncAttribute::SupportsMonochrome
,
198 &nsPrinterBase::SupportsMonochrome
);
201 NS_IMETHODIMP
nsPrinterBase::GetSupportsCollation(JSContext
* aCx
,
202 Promise
** aResultPromise
) {
203 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
204 AsyncAttribute::SupportsCollation
,
205 &nsPrinterBase::SupportsCollation
);
208 NS_IMETHODIMP
nsPrinterBase::GetPrinterInfo(JSContext
* aCx
,
209 Promise
** aResultPromise
) {
210 return AsyncPromiseAttributeGetter(aCx
, aResultPromise
,
211 AsyncAttribute::PrinterInfo
,
212 &nsPrinterBase::CreatePrinterInfo
);
215 void nsPrinterBase::QueryMarginsForPaper(Promise
& aPromise
,
216 const nsString
& aPaperId
) {
217 return SpawnPrintBackgroundTask(*this, aPromise
, "MarginsForPaper"_ns
,
218 &nsPrinterBase::GetMarginsForPaper
, aPaperId
);
221 NS_IMPL_CYCLE_COLLECTION(nsPrinterBase
, mAsyncAttributePromises
)
223 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterBase
)
224 NS_INTERFACE_MAP_ENTRY(nsIPrinter
)
225 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIPrinter
)
228 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterBase
)
229 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterBase
)
231 nsPrinterBase::nsPrinterBase(const CommonPaperInfoArray
* aPaperInfoArray
)
232 : mCommonPaperInfo(aPaperInfoArray
) {
233 MOZ_DIAGNOSTIC_ASSERT(aPaperInfoArray
, "Localized paper info was null");
235 nsPrinterBase::~nsPrinterBase() = default;
237 const PaperInfo
* nsPrinterBase::FindCommonPaperSize(
238 const gfx::SizeDouble
& aSize
) const {
239 for (const PaperInfo
& paper
: *mCommonPaperInfo
) {
240 if (std::abs(paper
.mSize
.width
- aSize
.width
) <= kPaperSizePointsEpsilon
&&
241 std::abs(paper
.mSize
.height
- aSize
.height
) <=
242 kPaperSizePointsEpsilon
) {