From 4bfe2ce33f881d551f46b8561294c82b695415ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Emilio=20Cobos=20=C3=81lvarez?= Date: Wed, 5 Aug 2020 11:26:13 +0000 Subject: [PATCH] Bug 1655558 - Retrieve the paper margins lazily on Windows. r=jwatt,bobowen This is no worse than what we were doing. In the future, instead of just querying the margin we may want to query extra information that requires a DC in windows too or what not, for example. Differential Revision: https://phabricator.services.mozilla.com/D85919 --- .../chrome/test_get_printer_paper_sizes.html | 23 +++-- widget/moz.build | 2 + widget/nsIPaper.idl | 20 +--- widget/nsIPaperMargin.idl | 16 ++++ widget/nsPaper.cpp | 64 ++++++++----- widget/nsPaper.h | 57 ++++++------ widget/nsPaperMargin.cpp | 32 +++++++ widget/nsPaperMargin.h | 29 ++++++ widget/nsPrinter.h | 4 + widget/nsPrinterBase.cpp | 92 ++++++++++++++----- widget/nsPrinterBase.h | 21 +++-- widget/nsPrinterCUPS.cpp | 20 ++-- widget/nsPrinterCUPS.h | 6 ++ widget/windows/nsPrinterWin.cpp | 51 +++++----- widget/windows/nsPrinterWin.h | 1 + 15 files changed, 297 insertions(+), 141 deletions(-) create mode 100644 widget/nsIPaperMargin.idl create mode 100644 widget/nsPaperMargin.cpp create mode 100644 widget/nsPaperMargin.h diff --git a/layout/base/tests/chrome/test_get_printer_paper_sizes.html b/layout/base/tests/chrome/test_get_printer_paper_sizes.html index 069787406d3c..0b9cdbd0654d 100644 --- a/layout/base/tests/chrome/test_get_printer_paper_sizes.html +++ b/layout/base/tests/chrome/test_get_printer_paper_sizes.html @@ -26,7 +26,8 @@ async function run() { for (let paper of paperList) { paper.QueryInterface(Ci.nsIPaper); - info(`${paper.name}: ${paper.width}x${paper.height} with margin: ${paper.unwriteableMarginTop} ${paper.unwriteableMarginRight} ${paper.unwriteableMarginBottom} ${paper.unwriteableMarginLeft}`); + info(`${paper.name}: ${paper.width}x${paper.height}`); + isnot(paper.name, null, "Paper name should never be null."); isnot(paper.name, "", "Paper name should never be empty."); @@ -36,20 +37,24 @@ async function run() { isnot(paper.height, null, "Paper height should never be null."); ok(paper.height > 0.0, "Paper height should be greater than zero."); - isnot(paper.unwriteableMarginTop, null, "Paper unwriteableMarginTop should never be null."); - ok(paper.unwriteableMarginTop >= 0.0, "Paper unwriteableMarginTop should be greater than or equal to zero."); - isnot(paper.unwriteableMarginBottom, null, "Paper unwriteableMarginBottom should never be null."); - ok(paper.unwriteableMarginBottom >= 0.0, "Paper unwriteableMarginBottom should be greater than or equal to zero."); + let margin = await paper.unwriteableMargin; + margin.QueryInterface(Ci.nsIPaperMargin); - isnot(paper.unwriteableMarginLeft, null, "Paper unwriteableMarginLeft should never be null."); - ok(paper.unwriteableMarginLeft >= 0.0, "Paper unwriteableMarginLeft should be greater than or equal to zero."); + info(`with margin: ${margin.top} ${margin.right} ${margin.bottom} ${margin.left}`); + is(typeof(margin.top), 'number', "Paper unwriteable margin top should be a number."); + is(typeof(margin.right), 'number', "Paper unwriteable margin right should be a number."); + is(typeof(margin.bottom), 'number', "Paper unwriteable margin bottom should be a number."); + is(typeof(margin.left), 'number', "Paper unwriteable margin left should be a number."); - isnot(paper.unwriteableMarginRight, null, "Paper unwriteableMarginRight should never be null."); - ok(paper.unwriteableMarginRight >= 0.0, "Paper unwriteableMarginRight should be greater than or equal to zero."); + ok(margin.top >= 0.0, "Paper unwriteable margin top should be greater than or equal to zero."); + ok(margin.right >= 0.0, "Paper unwriteable margin right should be greater than or equal to zero."); + ok(margin.bottom >= 0.0, "Paper unwriteable bottom right should be greater than or equal to zero."); + ok(margin.left >= 0.0, "Paper unwriteable margin left should be greater than or equal to zero."); } } } catch (e) { + ok(false, `Shouldn't throw: ${e}`); Cu.reportError(e); } SimpleTest.finish(); diff --git a/widget/moz.build b/widget/moz.build index c23e0c48329e..d147dc2e7d04 100644 --- a/widget/moz.build +++ b/widget/moz.build @@ -110,6 +110,7 @@ XPIDL_SOURCES += [ 'nsIGfxInfo.idl', 'nsIGfxInfoDebug.idl', 'nsIPaper.idl', + 'nsIPaperMargin.idl', 'nsIPrinter.idl', 'nsIPrinterList.idl', 'nsIPrintSession.idl', @@ -237,6 +238,7 @@ if CONFIG['MOZ_XUL'] and CONFIG['NS_PRINTING']: UNIFIED_SOURCES += [ 'nsDeviceContextSpecProxy.cpp', 'nsPaper.cpp', + 'nsPaperMargin.cpp', 'nsPrinterBase.cpp', 'nsPrintSession.cpp', 'nsPrintSettingsService.cpp', diff --git a/widget/nsIPaper.idl b/widget/nsIPaper.idl index 7a69ff1e1f46..6427d1d9cf54 100644 --- a/widget/nsIPaper.idl +++ b/widget/nsIPaper.idl @@ -23,23 +23,5 @@ interface nsIPaper : nsISupports */ readonly attribute double height; - /** - * The unwritable margin at the top of the paper in points. - */ - readonly attribute double unwriteableMarginTop; - - /** - * The unwritable margin at the bottom of the paper in points. - */ - readonly attribute double unwriteableMarginBottom; - - /** - * The unwritable margin at the left of the paper in points. - */ - readonly attribute double unwriteableMarginLeft; - - /** - * The unwritable margin at the right of the paper in points. - */ - readonly attribute double unwriteableMarginRight; + [implicit_jscontext] readonly attribute Promise unwriteableMargin; }; diff --git a/widget/nsIPaperMargin.idl b/widget/nsIPaperMargin.idl new file mode 100644 index 000000000000..80242f63b3a8 --- /dev/null +++ b/widget/nsIPaperMargin.idl @@ -0,0 +1,16 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsISupports.idl" + +// A margin for a sheet of paper. +[builtinclass, scriptable, uuid(0858d1a7-b646-4b15-a1e8-7eb5ab572d0a)] +interface nsIPaperMargin : nsISupports +{ + [infallible] readonly attribute double top; + [infallible] readonly attribute double right; + [infallible] readonly attribute double bottom; + [infallible] readonly attribute double left; +}; diff --git a/widget/nsPaper.cpp b/widget/nsPaper.cpp index 4e1f7337391b..75452e90466e 100644 --- a/widget/nsPaper.cpp +++ b/widget/nsPaper.cpp @@ -4,8 +4,27 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPaper.h" +#include "nsPaperMargin.h" +#include "nsPrinterBase.h" +#include "mozilla/ErrorResult.h" +#include "mozilla/dom/Promise.h" -NS_IMPL_ISUPPORTS(nsPaper, nsIPaper); +using mozilla::ErrorResult; + +NS_IMPL_CYCLE_COLLECTION(nsPaper, mMarginPromise, mPrinter) + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPaper) + NS_INTERFACE_MAP_ENTRY(nsIPaper) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPaper) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPaper) +NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPaper) + +nsPaper::nsPaper(nsPrinterBase& aPrinter, const mozilla::PaperInfo& aInfo) + : mPrinter(&aPrinter), mInfo(aInfo) {} + +nsPaper::~nsPaper() = default; NS_IMETHODIMP nsPaper::GetName(nsAString& aName) { @@ -16,41 +35,38 @@ nsPaper::GetName(nsAString& aName) { NS_IMETHODIMP nsPaper::GetWidth(double* aWidth) { NS_ENSURE_ARG_POINTER(aWidth); - *aWidth = mInfo.mWidth; + *aWidth = mInfo.mSize.Width(); return NS_OK; } NS_IMETHODIMP nsPaper::GetHeight(double* aHeight) { NS_ENSURE_ARG_POINTER(aHeight); - *aHeight = mInfo.mHeight; + *aHeight = mInfo.mSize.Height(); return NS_OK; } NS_IMETHODIMP -nsPaper::GetUnwriteableMarginTop(double* aUnwriteableMarginTop) { - NS_ENSURE_ARG_POINTER(aUnwriteableMarginTop); - *aUnwriteableMarginTop = mInfo.mUnwriteableMarginTop; - return NS_OK; -} +nsPaper::GetUnwriteableMargin(JSContext* aCx, Promise** aPromise) { + if (RefPtr existing = mMarginPromise) { + existing.forget(aPromise); + return NS_OK; + } + ErrorResult rv; + RefPtr promise = Promise::Create(xpc::CurrentNativeGlobal(aCx), rv); + if (MOZ_UNLIKELY(rv.Failed())) { + return rv.StealNSResult(); + } -NS_IMETHODIMP -nsPaper::GetUnwriteableMarginBottom(double* aUnwriteableMarginBottom) { - NS_ENSURE_ARG_POINTER(aUnwriteableMarginBottom); - *aUnwriteableMarginBottom = mInfo.mUnwriteableMarginBottom; - return NS_OK; -} + mMarginPromise = promise; -NS_IMETHODIMP -nsPaper::GetUnwriteableMarginLeft(double* aUnwriteableMarginLeft) { - NS_ENSURE_ARG_POINTER(aUnwriteableMarginLeft); - *aUnwriteableMarginLeft = mInfo.mUnwriteableMarginLeft; - return NS_OK; -} + if (mInfo.mUnwriteableMargin) { + auto margin = mozilla::MakeRefPtr(*mInfo.mUnwriteableMargin); + mMarginPromise->MaybeResolve(margin); + } else { + mPrinter->QueryMarginsForPaper(*mMarginPromise, mInfo.mPaperId); + } -NS_IMETHODIMP -nsPaper::GetUnwriteableMarginRight(double* aUnwriteableMarginRight) { - NS_ENSURE_ARG_POINTER(aUnwriteableMarginRight); - *aUnwriteableMarginRight = mInfo.mUnwriteableMarginRight; + promise.forget(aPromise); return NS_OK; } diff --git a/widget/nsPaper.h b/widget/nsPaper.h index 296e97a3c60b..ae60bc047bed 100644 --- a/widget/nsPaper.h +++ b/widget/nsPaper.h @@ -7,52 +7,55 @@ #define nsPaper_h__ #include "mozilla/dom/ToJSValue.h" -#include "js/TypeDecls.h" +#include "mozilla/gfx/Point.h" +#include "mozilla/gfx/Rect.h" +#include "mozilla/Maybe.h" #include "nsIPaper.h" #include "nsISupportsImpl.h" #include "js/RootingAPI.h" #include "nsString.h" +struct JSContext; + namespace mozilla { // Simple struct that can be used off the main thread to hold all the info from // an nsPaper instance. struct PaperInfo { + using MarginDouble = mozilla::gfx::MarginDouble; + using SizeDouble = mozilla::gfx::SizeDouble; + const nsString mName; - const double mWidth; - const double mHeight; - const double mUnwriteableMarginTop; - const double mUnwriteableMarginRight; - const double mUnwriteableMarginBottom; - const double mUnwriteableMarginLeft; + + SizeDouble mSize; + + // The margins may not be known by some back-ends. + const Maybe mUnwriteableMargin; + + // The paper id from the device, this is only useful on Windows, right now. + uint64_t mPaperId{0}; }; } // namespace mozilla -class nsPaper final : public nsIPaper { - public: - NS_DECL_ISUPPORTS - NS_DECL_NSIPAPER - nsPaper() = delete; +class nsPrinterBase; - explicit nsPaper(const mozilla::PaperInfo& aInfo) : mInfo(aInfo) {} +class nsPaper final : public nsIPaper { + using Promise = mozilla::dom::Promise; + + public: + NS_DECL_CYCLE_COLLECTING_ISUPPORTS + NS_DECL_CYCLE_COLLECTION_CLASS(nsPaper) + NS_DECL_NSIPAPER + + nsPaper() = delete; + nsPaper(nsPrinterBase&, const mozilla::PaperInfo&); private: - ~nsPaper() = default; + ~nsPaper(); + RefPtr mPrinter; + RefPtr mMarginPromise; const mozilla::PaperInfo mInfo; }; -namespace mozilla { - -// Turns this into a JSValue by wrapping it in an nsPaper struct. -// -// FIXME: If using WebIDL dictionaries we'd get this for ~free... -MOZ_MUST_USE inline bool ToJSValue(JSContext* aCx, const PaperInfo& aInfo, - JS::MutableHandleValue aValue) { - RefPtr paper = new nsPaper(aInfo); - return dom::ToJSValue(aCx, paper, aValue); -} - -} // namespace mozilla - #endif /* nsPaper_h__ */ diff --git a/widget/nsPaperMargin.cpp b/widget/nsPaperMargin.cpp new file mode 100644 index 000000000000..1e6171cd16cd --- /dev/null +++ b/widget/nsPaperMargin.cpp @@ -0,0 +1,32 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "nsPaperMargin.h" + +NS_IMPL_ISUPPORTS(nsPaperMargin, nsIPaperMargin) + +NS_IMETHODIMP +nsPaperMargin::GetTop(double* aTop) { + *aTop = mMargin.top; + return NS_OK; +} + +NS_IMETHODIMP +nsPaperMargin::GetRight(double* aRight) { + *aRight = mMargin.right; + return NS_OK; +} + +NS_IMETHODIMP +nsPaperMargin::GetBottom(double* aBottom) { + *aBottom = mMargin.bottom; + return NS_OK; +} + +NS_IMETHODIMP +nsPaperMargin::GetLeft(double* aLeft) { + *aLeft = mMargin.left; + return NS_OK; +} diff --git a/widget/nsPaperMargin.h b/widget/nsPaperMargin.h new file mode 100644 index 000000000000..594b266c0045 --- /dev/null +++ b/widget/nsPaperMargin.h @@ -0,0 +1,29 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef nsPaperMargin_h_ +#define nsPaperMargin_h_ + +#include "nsISupportsImpl.h" +#include "nsIPaperMargin.h" +#include "mozilla/gfx/Rect.h" + +class nsPaperMargin final : public nsIPaperMargin { + using MarginDouble = mozilla::gfx::MarginDouble; + + public: + NS_DECL_ISUPPORTS + NS_DECL_NSIPAPERMARGIN + + nsPaperMargin() = delete; + + explicit nsPaperMargin(const MarginDouble& aMargin) : mMargin(aMargin) {} + + private: + ~nsPaperMargin() = default; + const MarginDouble mMargin; +}; + +#endif diff --git a/widget/nsPrinter.h b/widget/nsPrinter.h index 94b20e4fce93..d19cfba6bcfc 100644 --- a/widget/nsPrinter.h +++ b/widget/nsPrinter.h @@ -16,6 +16,10 @@ class nsPrinter final : public nsPrinterBase { bool SupportsDuplex() const final { return false; } bool SupportsColor() const final { return false; } nsTArray PaperList() const final { return {}; } + MarginDouble GetMarginsForPaper(uint64_t) const final { + MOZ_ASSERT_UNREACHABLE("We have no paper so this shouldn't be reached"); + return {}; + } nsPrinter() = delete; diff --git a/widget/nsPrinterBase.cpp b/widget/nsPrinterBase.cpp index 249354bea7f3..4c5156d52975 100644 --- a/widget/nsPrinterBase.cpp +++ b/widget/nsPrinterBase.cpp @@ -4,11 +4,15 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "nsPrinterBase.h" +#include "nsPaperMargin.h" +#include #include "nsPrinter.h" #include "nsPaper.h" #include "mozilla/dom/Promise.h" using namespace mozilla; +using mozilla::dom::Promise; +using mozilla::gfx::MarginDouble; template inline void ImplCycleCollectionTraverse( @@ -30,9 +34,65 @@ inline void ImplCycleCollectionUnlink( } template +void ResolveOrReject(Promise& aPromise, nsPrinterBase&, T& aResult) { + aPromise.MaybeResolve(std::forward(aResult)); +} + +template <> +void ResolveOrReject(Promise& aPromise, nsPrinterBase&, + const MarginDouble& aResult) { + auto margin = MakeRefPtr(aResult); + aPromise.MaybeResolve(margin); +} + +template <> +void ResolveOrReject(Promise& aPromise, nsPrinterBase& aPrinter, + const nsTArray& aResult) { + nsTArray> result; + result.SetCapacity(aResult.Length()); + for (const PaperInfo& info : aResult) { + result.AppendElement(MakeRefPtr(aPrinter, info)); + } + aPromise.MaybeResolve(result); +} + +template +void nsPrinterBase::SpawnBackgroundTask( + Promise& aPromise, BackgroundTask aBackgroundTask, + Args... aArgs) { + auto promiseHolder = MakeRefPtr>( + "nsPrinterBase::SpawnBackgroundTaskPromise", &aPromise); + // We actually want to allow to access the printer data from the callback, so + // disable strict checking. They should of course only access immutable + // members. + auto holder = MakeRefPtr>( + "nsPrinterBase::SpawnBackgroundTaskPrinter", this, /* strict = */ false); + // See + // https://stackoverflow.com/questions/47496358/c-lambdas-how-to-capture-variadic-parameter-pack-from-the-upper-scope + // about the tuple shenanigans. It could be improved with C++20 + NS_DispatchBackgroundTask(NS_NewRunnableFunction( + "nsPrinterBase::SpawnBackgroundTask", + [holder = std::move(holder), promiseHolder = std::move(promiseHolder), + aBackgroundTask, aArgs = std::make_tuple(std::forward(aArgs)...)] { + T result = std::apply( + [&](auto&&... args) { + return (holder->get()->*aBackgroundTask)(args...); + }, + std::move(aArgs)); + NS_DispatchToMainThread(NS_NewRunnableFunction( + "nsPrinterBase::SpawnBackgroundTaskResolution", + [holder = std::move(holder), + promiseHolder = std::move(promiseHolder), + result = std::move(result)] { + ResolveOrReject(*promiseHolder->get(), *holder->get(), result); + })); + })); +} + +template nsresult nsPrinterBase::AsyncPromiseAttributeGetter( JSContext* aCx, Promise** aResultPromise, AsyncAttribute aAttribute, - AsyncAttributeBackgroundTask aBackgroundTask) { + BackgroundTask aBackgroundTask, Args... aArgs) { MOZ_ASSERT(NS_IsMainThread()); if (RefPtr existing = mAsyncAttributePromises[aAttribute]) { existing.forget(aResultPromise); @@ -45,29 +105,10 @@ nsresult nsPrinterBase::AsyncPromiseAttributeGetter( return rv.StealNSResult(); } - // We actually want to allow to access the printer data from the callback, so - // disable strict checking. They should of course only access immutable - // members. - auto holder = MakeRefPtr>( - "nsPrinterBase::AsyncPromiseAttributeGetter", this, /* strict = */ false); - NS_DispatchBackgroundTask(NS_NewRunnableFunction( - "nsPrinterBase::AsyncPromiseAttributeGetter", - [holder = std::move(holder), aAttribute, aBackgroundTask] { - T result = (holder->get()->*aBackgroundTask)(); - NS_DispatchToMainThread(NS_NewRunnableFunction( - "nsPrinterBase::AsyncPromiseAttributeGetterResult", - [holder = std::move(holder), result = std::move(result), - aAttribute] { - nsPrinterBase* printer = holder->get(); - // There could be no promise, could've been CC'd or what not. - if (Promise* p = printer->mAsyncAttributePromises[aAttribute]) { - p->MaybeResolve(result); - } - })); - })); + RefPtr promise = mAsyncAttributePromises[aAttribute]; + SpawnBackgroundTask(*promise, aBackgroundTask, aArgs...); - RefPtr existing = mAsyncAttributePromises[aAttribute]; - existing.forget(aResultPromise); + promise.forget(aResultPromise); return NS_OK; } @@ -92,6 +133,11 @@ NS_IMETHODIMP nsPrinterBase::GetPaperList(JSContext* aCx, &nsPrinterBase::PaperList); } +void nsPrinterBase::QueryMarginsForPaper(Promise& aPromise, uint64_t aPaperId) { + return SpawnBackgroundTask( + aPromise, &nsPrinterBase::GetMarginsForPaper, aPaperId); +} + NS_IMPL_CYCLE_COLLECTION(nsPrinterBase, mAsyncAttributePromises) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterBase) diff --git a/widget/nsPrinterBase.h b/widget/nsPrinterBase.h index 3a9132032ed7..9adca8b94959 100644 --- a/widget/nsPrinterBase.h +++ b/widget/nsPrinterBase.h @@ -6,6 +6,7 @@ #ifndef nsPrinterBase_h__ #define nsPrinterBase_h__ +#include "mozilla/gfx/Rect.h" #include "nsIPrinter.h" #include "nsCycleCollectionParticipant.h" #include "nsISupportsImpl.h" @@ -25,6 +26,7 @@ class Promise; class nsPrinterBase : public nsIPrinter { public: using Promise = mozilla::dom::Promise; + using MarginDouble = mozilla::gfx::MarginDouble; NS_IMETHOD GetSupportsDuplex(JSContext*, Promise**) final; NS_IMETHOD GetSupportsColor(JSContext*, Promise**) final; @@ -37,6 +39,8 @@ class nsPrinterBase : public nsIPrinter { nsPrinterBase(const nsPrinterBase&) = delete; nsPrinterBase(nsPrinterBase&&) = delete; + void QueryMarginsForPaper(Promise&, uint64_t aPaperId); + private: enum class AsyncAttribute { SupportsDuplex = 0, @@ -46,14 +50,18 @@ class nsPrinterBase : public nsIPrinter { Last, }; - template - using AsyncAttributeBackgroundTask = T (nsPrinterBase::*)() const; + template + using BackgroundTask = T (nsPrinterBase::*)(Args...) const; + + // Resolves a promise when a background task finishes. + template + void SpawnBackgroundTask(Promise&, BackgroundTask, Args... aArgs); // Resolves an async attribute via a background task. - template - nsresult AsyncPromiseAttributeGetter(JSContext* aCx, Promise** aResultPromise, - AsyncAttribute, - AsyncAttributeBackgroundTask); + template + nsresult AsyncPromiseAttributeGetter(JSContext*, Promise**, AsyncAttribute, + BackgroundTask, + Args... aArgs); protected: nsPrinterBase(); @@ -64,6 +72,7 @@ class nsPrinterBase : public nsIPrinter { virtual bool SupportsDuplex() const = 0; virtual bool SupportsColor() const = 0; virtual nsTArray PaperList() const = 0; + virtual MarginDouble GetMarginsForPaper(uint64_t aPaperId) const = 0; private: mozilla::EnumeratedArray nsPrinterCUPS::PaperList() const { +nsTArray nsPrinterCUPS::PaperList() const { if (!mPrinterInfo) { return {}; } @@ -72,7 +74,7 @@ nsTArray nsPrinterCUPS::PaperList() const { return {}; } - nsTArray paperList; + nsTArray paperList; for (int i = 0; i < paperCount; ++i) { cups_size_t info; int getInfoSucceded = mShim.mCupsGetDestMediaByIndex( @@ -96,14 +98,14 @@ nsTArray nsPrinterCUPS::PaperList() const { NS_ConvertUTF8toUTF16 name(localizedName); const double kPointsPerHundredthMillimeter = 0.0283465; - paperList.AppendElement(mozilla::PaperInfo{ + paperList.AppendElement(PaperInfo{ std::move(name), - info.width * kPointsPerHundredthMillimeter, - info.length * kPointsPerHundredthMillimeter, - info.top * kPointsPerHundredthMillimeter, - info.right * kPointsPerHundredthMillimeter, - info.bottom * kPointsPerHundredthMillimeter, - info.left * kPointsPerHundredthMillimeter, + {info.width * kPointsPerHundredthMillimeter, + info.length * kPointsPerHundredthMillimeter}, + Some(MarginDouble{info.top * kPointsPerHundredthMillimeter, + info.right * kPointsPerHundredthMillimeter, + info.bottom * kPointsPerHundredthMillimeter, + info.left * kPointsPerHundredthMillimeter}), }); } diff --git a/widget/nsPrinterCUPS.h b/widget/nsPrinterCUPS.h index 89be105c3be5..0d9f94fbfce5 100644 --- a/widget/nsPrinterCUPS.h +++ b/widget/nsPrinterCUPS.h @@ -19,6 +19,12 @@ class nsPrinterCUPS final : public nsPrinterBase { bool SupportsDuplex() const final; bool SupportsColor() const final; nsTArray PaperList() const final; + MarginDouble GetMarginsForPaper(uint64_t) const final { + MOZ_ASSERT_UNREACHABLE( + "The CUPS API requires us to always get the margin when fetching the " + "paper list so there should be no need to query it separately"); + return {}; + } nsPrinterCUPS() = delete; diff --git a/widget/windows/nsPrinterWin.cpp b/widget/windows/nsPrinterWin.cpp index 1bf5fef6631b..dbf320ed29b1 100644 --- a/widget/windows/nsPrinterWin.cpp +++ b/widget/windows/nsPrinterWin.cpp @@ -96,7 +96,6 @@ nsTArray nsPrinterWin::PaperList() const { return {}; } - static const wchar_t kDriverName[] = L"WINSPOOL"; nsTArray paperList; paperList.SetCapacity(paperNames.Length()); for (size_t i = 0; i < paperNames.Length(); ++i) { @@ -112,34 +111,38 @@ nsTArray nsPrinterWin::PaperList() const { continue; } - WORD id = paperIds[i]; - - // Now get the margin info. - // We need a DEVMODE to set the paper size on the context. - DEVMODEW devmode = {}; - devmode.dmSize = sizeof(DEVMODEW); - devmode.dmFields = DM_PAPERSIZE; - devmode.dmPaperSize = id; - - // Create an information context, so that we can get margin information. - // Note: this blocking call interacts with the driver and can be slow. - nsAutoHDC printerDc( - ::CreateICW(kDriverName, mName.get(), nullptr, &devmode)); - - auto marginInInches = - WinUtils::GetUnwriteableMarginsForDeviceInInches(printerDc); - + // We don't resolve the margins eagerly because they're really expensive (on + // the order of seconds for some drivers). nsDependentSubstring name(paperNames[i].cbegin(), nameLength); paperList.AppendElement(mozilla::PaperInfo{ nsString(name), - width, - height, - marginInInches.top * POINTS_PER_INCH_FLOAT, - marginInInches.right * POINTS_PER_INCH_FLOAT, - marginInInches.bottom * POINTS_PER_INCH_FLOAT, - marginInInches.left * POINTS_PER_INCH_FLOAT, + {width, height}, + Nothing(), + paperIds[i], }); } return paperList; } + +mozilla::gfx::MarginDouble nsPrinterWin::GetMarginsForPaper( + uint64_t aPaperId) const { + static const wchar_t kDriverName[] = L"WINSPOOL"; + // Now get the margin info. + // We need a DEVMODE to set the paper size on the context. + DEVMODEW devmode = {}; + devmode.dmSize = sizeof(DEVMODEW); + devmode.dmFields = DM_PAPERSIZE; + devmode.dmPaperSize = aPaperId; + + // Create an information context, so that we can get margin information. + // Note: this blocking call interacts with the driver and can be slow. + nsAutoHDC printerDc(::CreateICW(kDriverName, mName.get(), nullptr, &devmode)); + + auto margin = WinUtils::GetUnwriteableMarginsForDeviceInInches(printerDc); + margin.top *= POINTS_PER_INCH_FLOAT; + margin.right *= POINTS_PER_INCH_FLOAT; + margin.bottom *= POINTS_PER_INCH_FLOAT; + margin.left *= POINTS_PER_INCH_FLOAT; + return margin; +} diff --git a/widget/windows/nsPrinterWin.h b/widget/windows/nsPrinterWin.h index 4b54c2e54486..48415fa30937 100644 --- a/widget/windows/nsPrinterWin.h +++ b/widget/windows/nsPrinterWin.h @@ -15,6 +15,7 @@ class nsPrinterWin final : public nsPrinterBase { bool SupportsDuplex() const final; bool SupportsColor() const final; nsTArray PaperList() const final; + MarginDouble GetMarginsForPaper(uint64_t aId) const final; nsPrinterWin() = delete; static already_AddRefed Create(const nsAString& aName);