diff options
Diffstat (limited to 'widget/nsPrinterCUPS.h')
-rw-r--r-- | widget/nsPrinterCUPS.h | 181 |
1 files changed, 181 insertions, 0 deletions
diff --git a/widget/nsPrinterCUPS.h b/widget/nsPrinterCUPS.h new file mode 100644 index 0000000000..3ecf1cb982 --- /dev/null +++ b/widget/nsPrinterCUPS.h @@ -0,0 +1,181 @@ +/* -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil; tab-width: 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 nsPrinterCUPS_h___ +#define nsPrinterCUPS_h___ + +#include "nsPrinterBase.h" +#include "nsPrintSettingsImpl.h" +#include "nsCUPSShim.h" +#include "nsString.h" + +#include "mozilla/DataMutex.h" +#include "mozilla/FunctionRef.h" +#include "mozilla/RecursiveMutex.h" + +/** + * @brief Interface to help implementing nsIPrinter using a CUPS printer. + */ +class nsPrinterCUPS final : public nsPrinterBase { + public: + NS_IMETHOD GetName(nsAString& aName) override; + NS_IMETHOD GetSystemName(nsAString& aName) override; + bool SupportsDuplex() const final; + bool SupportsColor() const final; + bool SupportsMonochrome() const final; + bool SupportsCollation() const final; + PrinterInfo CreatePrinterInfo() const final; + MarginDouble GetMarginsForPaper(nsString aPaperId) 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; + + nsPrinterCUPS(const mozilla::CommonPaperInfoArray* aArray, + const nsCUPSShim& aShim, nsString aDisplayName, + cups_dest_t* aPrinter) + : nsPrinterBase(aArray), + mShim(aShim), + mDisplayName(std::move(aDisplayName)), + mPrinterInfoMutex(CUPSPrinterInfo{aPrinter}, + "nsPrinterCUPS::mPrinterInfoMutex") {} + + static void ForEachExtraMonochromeSetting( + mozilla::FunctionRef<void(const nsACString&, const nsACString&)>); + + private: + struct CUPSPrinterInfo { + explicit constexpr CUPSPrinterInfo(cups_dest_t* aPrinter) + : mPrinter(aPrinter) {} + cups_dest_t* mPrinter; + cups_dinfo_t* mPrinterInfo = nullptr; + uint64_t mCUPSMajor = 0; + uint64_t mCUPSMinor = 0; + uint64_t mCUPSPatch = 0; + + // Whether we have attempted to fetch mPrinterInfo with CUPS_HTTP_DEFAULT. + bool mTriedInitWithDefault = false; + // Whether we have attempted to fetch mPrinterInfo with a connection. + bool mTriedInitWithConnection = false; + CUPSPrinterInfo() = delete; + CUPSPrinterInfo(const CUPSPrinterInfo&) = delete; + CUPSPrinterInfo(CUPSPrinterInfo&& aOther) + : mPrinter(aOther.mPrinter), + mPrinterInfo(aOther.mPrinterInfo), + mCUPSMajor(aOther.mCUPSMajor), + mCUPSMinor(aOther.mCUPSMinor), + mCUPSPatch(aOther.mCUPSPatch) { + aOther.mPrinter = nullptr; + aOther.mPrinterInfo = nullptr; + } + }; + + using PrinterInfoMutex = + mozilla::DataMutexBase<CUPSPrinterInfo, mozilla::RecursiveMutex>; + + using PrinterInfoLock = PrinterInfoMutex::AutoLock; + + ~nsPrinterCUPS(); + + /** + * Retrieves the localized name for a given media (paper). + * Returns nullptr if the name cannot be localized. + */ + const char* LocalizeMediaName(http_t& aConnection, cups_size_t& aMedia) const; + + void GetPrinterName(nsAString& aName) const; + + // Little util for getting support flags using the direct CUPS names. + bool Supports(const char* aOption, const char* aValue) const; + + // Returns support value if CUPS meets the minimum version, otherwise returns + // |aDefault| + bool IsCUPSVersionAtLeast(uint64_t aCUPSMajor, uint64_t aCUPSMinor, + uint64_t aCUPSPatch) const; + + const char* FindCUPSOption(PrinterInfoLock& aLock, const char* name) const { + const cups_dest_t* const printer = aLock->mPrinter; + return mShim.cupsGetOption(name, printer->num_options, printer->options); + } + + class Connection { + public: + http_t* GetConnection(cups_dest_t* aDest); + + inline explicit Connection(const nsCUPSShim& aShim) : mShim(aShim) {} + Connection() = delete; + ~Connection(); + + protected: + const nsCUPSShim& mShim; + http_t* mConnection = CUPS_HTTP_DEFAULT; + bool mWasInited = false; + }; + + PrintSettingsInitializer DefaultSettings(Connection& aConnection) const; + nsTArray<mozilla::PaperInfo> PaperList(Connection& aConnection) const; + /** + * Attempts to populate the CUPSPrinterInfo object. + * This usually works with the CUPS default connection, + * but has been known to require an established connection + * on older versions of Ubuntu (18 and below). + */ + PrinterInfoLock TryEnsurePrinterInfo( + http_t* const aConnection = CUPS_HTTP_DEFAULT) const { + PrinterInfoLock lock = mPrinterInfoMutex.Lock(); + TryEnsurePrinterInfo(lock, aConnection); + return lock; + } + + /** + * TryEnsurePrinterInfo that uses a caller-provided PrinterInfoLock. + * + * This can be used to avoid unnecessarily redundant locking of + * mPrinterInfoLock when getting a connection through + * Connection::GetConnection and then passing that into TryEnsurePrinterInfo. + */ + void TryEnsurePrinterInfo(PrinterInfoLock& aLock, + http_t* const aConnection) const; + + const nsCUPSShim& mShim; + nsString mDisplayName; + mutable PrinterInfoMutex mPrinterInfoMutex; +}; + +// There's no standard setting in Core Printing for monochrome. Or rather, +// there is (PMSetColorMode) but it does nothing. Similarly, the relevant gtk +// setting only works on Windows, yay. +// +// So on CUPS the right setting to use depends on the print driver. So we set / +// look for a variety of driver-specific keys that are known to work across +// printers. +// +// We set all the known settings, because the alternative to that is parsing ppd +// files from the printer and find the relevant known choices that can apply, +// and that is a lot more complex, similarly sketchy (requires the same amount +// of driver-specific knowledge), and requires using deprecated CUPS APIs. +#define CUPS_EACH_MONOCHROME_PRINTER_SETTING(macro_) \ + macro_("ColorModel", "Gray") /* Generic */ \ + macro_("BRMonoColor", "Mono") /* Brother */ \ + macro_("BRPrintQuality", "Black") /* Brother */ \ + macro_("CNIJGrayScale", "1") /* Canon */ \ + macro_("CNGrayscale", "True") /* Canon */ \ + macro_("INK", "MONO") /* Epson */ \ + macro_("HPColorMode", "GrayscalePrint") /* HP */ \ + macro_("ColorMode", "Mono") /* Samsung */ \ + macro_("PrintoutMode", "Normal.Gray") /* Foomatic */ \ + macro_("ProcessColorModel", "Mono") /* Samsung */ \ + macro_("ARCMode", "CMBW") /* Sharp */ \ + macro_("XRXColor", "BW") /* Xerox */ \ + macro_("XROutputColor", "PrintAsGrayscale") /* Xerox, bug 1676191#c32 */ \ + macro_("SelectColor", "Grayscale") /* Konica Minolta */ \ + macro_("OKControl", "Gray") /* Oki */ \ + macro_("BLW", "TrueM") /* Lexmark */ \ + macro_("EPRendering", "None") /* Epson */ + +#endif /* nsPrinterCUPS_h___ */ |