/* -*- 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 "nsPrinterBase.h" #include "nsPaperMargin.h" #include #include "nsPaper.h" #include "nsIPrintSettings.h" #include "PrintBackgroundTask.h" #include "mozilla/dom/Promise.h" using namespace mozilla; using mozilla::dom::Promise; using mozilla::gfx::MarginDouble; // The maximum error when considering a paper size equal, in points. // There is some variance in the actual sizes returned by printer drivers and // print servers for paper sizes. This is a best-guess based on initial // telemetry which should catch most near-miss dimensions. This should let us // get consistent paper size names even when the size isn't quite exactly the // correct size. static constexpr double kPaperSizePointsEpsilon = 4.0; // Basic implementation of nsIPrinterInfo class nsPrinterInfo : public nsIPrinterInfo { public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(nsPrinterInfo) NS_DECL_NSIPRINTERINFO nsPrinterInfo() = delete; nsPrinterInfo(nsPrinterBase& aPrinter, const nsPrinterBase::PrinterInfo& aPrinterInfo) : mDefaultSettings( CreatePlatformPrintSettings(aPrinterInfo.mDefaultSettings)) { mPaperList.SetCapacity(aPrinterInfo.mPaperList.Length()); for (const PaperInfo& info : aPrinterInfo.mPaperList) { mPaperList.AppendElement(MakeRefPtr(aPrinter, info)); } } private: virtual ~nsPrinterInfo() = default; nsTArray> mPaperList; RefPtr mDefaultSettings; }; NS_IMETHODIMP nsPrinterInfo::GetPaperList(nsTArray>& aPaperList) { aPaperList = mPaperList.Clone(); return NS_OK; } NS_IMETHODIMP nsPrinterInfo::GetDefaultSettings(nsIPrintSettings** aDefaultSettings) { NS_ENSURE_ARG_POINTER(aDefaultSettings); MOZ_ASSERT(mDefaultSettings); RefPtr settings = mDefaultSettings; settings.forget(aDefaultSettings); return NS_OK; } NS_IMPL_CYCLE_COLLECTION(nsPrinterInfo, mPaperList, mDefaultSettings) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterInfo) NS_INTERFACE_MAP_ENTRY(nsIPrinterInfo) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrinterInfo) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterInfo) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterInfo) template inline void ImplCycleCollectionTraverse( nsCycleCollectionTraversalCallback& aCallback, EnumeratedArray& aArray, const char* aName, uint32_t aFlags = 0) { aFlags |= CycleCollectionEdgeNameArrayFlag; for (Value& element : aArray) { ImplCycleCollectionTraverse(aCallback, element, aName, aFlags); } } template inline void ImplCycleCollectionUnlink( EnumeratedArray& aArray) { for (Value& element : aArray) { ImplCycleCollectionUnlink(element); } } namespace mozilla { 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 ResolveOrReject(Promise& aPromise, nsPrinterBase& aPrinter, const PrintSettingsInitializer& aResult) { aPromise.MaybeResolve( RefPtr(CreatePlatformPrintSettings(aResult))); } template <> void ResolveOrReject(Promise& aPromise, nsPrinterBase& aPrinter, const nsPrinterBase::PrinterInfo& aResult) { aPromise.MaybeResolve(MakeRefPtr(aPrinter, aResult)); } } // namespace mozilla template nsresult nsPrinterBase::AsyncPromiseAttributeGetter( JSContext* aCx, Promise** aResultPromise, AsyncAttribute aAttribute, BackgroundTask aBackgroundTask, Args... aArgs) { MOZ_ASSERT(NS_IsMainThread()); static constexpr EnumeratedArray attributeKeys{"SupportsDuplex"_ns, "SupportsColor"_ns, "SupportsMonochrome"_ns, "SupportsCollation"_ns, "PrinterInfo"_ns}; return mozilla::AsyncPromiseAttributeGetter( *this, mAsyncAttributePromises[aAttribute], aCx, aResultPromise, attributeKeys[aAttribute], aBackgroundTask, std::forward(aArgs)...); } NS_IMETHODIMP nsPrinterBase::GetSupportsDuplex(JSContext* aCx, Promise** aResultPromise) { return AsyncPromiseAttributeGetter(aCx, aResultPromise, AsyncAttribute::SupportsDuplex, &nsPrinterBase::SupportsDuplex); } NS_IMETHODIMP nsPrinterBase::GetSupportsColor(JSContext* aCx, Promise** aResultPromise) { return AsyncPromiseAttributeGetter(aCx, aResultPromise, AsyncAttribute::SupportsColor, &nsPrinterBase::SupportsColor); } NS_IMETHODIMP nsPrinterBase::GetSupportsMonochrome(JSContext* aCx, Promise** aResultPromise) { return AsyncPromiseAttributeGetter(aCx, aResultPromise, AsyncAttribute::SupportsMonochrome, &nsPrinterBase::SupportsMonochrome); } NS_IMETHODIMP nsPrinterBase::GetSupportsCollation(JSContext* aCx, Promise** aResultPromise) { return AsyncPromiseAttributeGetter(aCx, aResultPromise, AsyncAttribute::SupportsCollation, &nsPrinterBase::SupportsCollation); } NS_IMETHODIMP nsPrinterBase::GetPrinterInfo(JSContext* aCx, Promise** aResultPromise) { return AsyncPromiseAttributeGetter(aCx, aResultPromise, AsyncAttribute::PrinterInfo, &nsPrinterBase::CreatePrinterInfo); } void nsPrinterBase::QueryMarginsForPaper(Promise& aPromise, const nsString& aPaperId) { return SpawnPrintBackgroundTask(*this, aPromise, "MarginsForPaper"_ns, &nsPrinterBase::GetMarginsForPaper, aPaperId); } NS_IMPL_CYCLE_COLLECTION(nsPrinterBase, mAsyncAttributePromises) NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsPrinterBase) NS_INTERFACE_MAP_ENTRY(nsIPrinter) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIPrinter) NS_INTERFACE_MAP_END NS_IMPL_CYCLE_COLLECTING_ADDREF(nsPrinterBase) NS_IMPL_CYCLE_COLLECTING_RELEASE(nsPrinterBase) nsPrinterBase::nsPrinterBase(const CommonPaperInfoArray* aPaperInfoArray) : mCommonPaperInfo(aPaperInfoArray) { MOZ_DIAGNOSTIC_ASSERT(aPaperInfoArray, "Localized paper info was null"); } nsPrinterBase::~nsPrinterBase() = default; const PaperInfo* nsPrinterBase::FindCommonPaperSize( const gfx::SizeDouble& aSize) const { for (const PaperInfo& paper : *mCommonPaperInfo) { if (std::abs(paper.mSize.width - aSize.width) <= kPaperSizePointsEpsilon && std::abs(paper.mSize.height - aSize.height) <= kPaperSizePointsEpsilon) { return &paper; } } return nullptr; }