Bug 1734943 [wpt PR 31170] - Correct scrolling contents cull rect, a=testonly
[gecko.git] / widget / nsPrinterListCUPS.cpp
blob7074d13233adb7bbbb7365bfd0963e23e3c982d5
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "nsPrinterListCUPS.h"
7 #include "mozilla/IntegerRange.h"
8 #include "mozilla/Maybe.h"
9 #include "nsCUPSShim.h"
10 #include "nsPrinterCUPS.h"
11 #include "nsString.h"
12 #include "prenv.h"
14 // Use a local static to initialize the CUPS shim lazily, when it's needed.
15 // This is used in order to avoid a global constructor.
16 static nsCUPSShim& CupsShim() {
17 static nsCUPSShim sCupsShim;
18 return sCupsShim;
21 using PrinterInfo = nsPrinterListBase::PrinterInfo;
23 /**
24 * Retrieves a human-readable name for the printer from CUPS.
25 * https://www.cups.org/doc/cupspm.html#basic-destination-information
27 static void GetDisplayNameForPrinter(const cups_dest_t& aDest,
28 nsAString& aName) {
29 // macOS clients expect prettified printer names
30 // while GTK clients expect non-prettified names.
31 // If you change this, please change NamedPrinter accordingly.
32 #ifdef XP_MACOSX
33 const char* displayName = CupsShim().cupsGetOption(
34 "printer-info", aDest.num_options, aDest.options);
35 if (displayName) {
36 CopyUTF8toUTF16(MakeStringSpan(displayName), aName);
38 #endif
41 NS_IMETHODIMP
42 nsPrinterListCUPS::InitPrintSettingsFromPrinter(
43 const nsAString& aPrinterName, nsIPrintSettings* aPrintSettings) {
44 MOZ_ASSERT(aPrintSettings);
46 // Set a default file name.
47 nsAutoString filename;
48 nsresult rv = aPrintSettings->GetToFileName(filename);
49 if (NS_FAILED(rv) || filename.IsEmpty()) {
50 const char* path = PR_GetEnv("PWD");
51 if (!path) {
52 path = PR_GetEnv("HOME");
55 if (path) {
56 CopyUTF8toUTF16(mozilla::MakeStringSpan(path), filename);
57 filename.AppendLiteral("/mozilla.pdf");
58 } else {
59 filename.AssignLiteral("mozilla.pdf");
62 aPrintSettings->SetToFileName(filename);
65 aPrintSettings->SetIsInitializedFromPrinter(true);
66 return NS_OK;
69 static int CupsDestCallback(void* user_data, unsigned aFlags,
70 cups_dest_t* aDest) {
71 MOZ_ASSERT(user_data);
72 auto* printerInfoList = static_cast<nsTArray<PrinterInfo>*>(user_data);
74 cups_dest_t* ownedDest = nullptr;
75 mozilla::DebugOnly<const int> numCopied =
76 CupsShim().cupsCopyDest(aDest, 0, &ownedDest);
77 MOZ_ASSERT(numCopied == 1);
79 nsString name;
80 GetDisplayNameForPrinter(*aDest, name);
82 printerInfoList->AppendElement(PrinterInfo{std::move(name), ownedDest});
84 return aFlags == CUPS_DEST_FLAGS_MORE ? 1 : 0;
87 nsTArray<PrinterInfo> nsPrinterListCUPS::Printers() const {
88 if (!CupsShim().InitOkay()) {
89 return {};
92 nsTArray<PrinterInfo> printerInfoList;
93 if (!CupsShim().cupsEnumDests(
94 CUPS_DEST_FLAGS_NONE,
95 0 /* timeout, 0 timeout shouldn't be a problem since we are masking
96 CUPS_PRINTER_DISCOVERED */
98 nullptr /* cancel* */, CUPS_PRINTER_LOCAL,
99 CUPS_PRINTER_FAX | CUPS_PRINTER_SCANNER | CUPS_PRINTER_DISCOVERED,
100 &CupsDestCallback, &printerInfoList)) {
101 return {};
104 return printerInfoList;
107 RefPtr<nsIPrinter> nsPrinterListCUPS::CreatePrinter(PrinterInfo aInfo) const {
108 return mozilla::MakeRefPtr<nsPrinterCUPS>(
109 mCommonPaperInfo, CupsShim(), std::move(aInfo.mName),
110 static_cast<cups_dest_t*>(aInfo.mCupsHandle));
113 mozilla::Maybe<PrinterInfo> nsPrinterListCUPS::PrinterByName(
114 nsString aPrinterName) const {
115 mozilla::Maybe<PrinterInfo> rv;
116 if (!CupsShim().InitOkay()) {
117 return rv;
120 // Will contain the printer, if found. This must be fully owned, and not a
121 // member of another array of printers.
122 cups_dest_t* printer = nullptr;
124 #ifdef XP_MACOSX
125 // On OS X the printer name given to this function is the readable/display
126 // name and not the CUPS name, so we iterate over all the printers for now.
127 // See bug 1659807 for one approach to improve perf here.
129 nsAutoCString printerName;
130 CopyUTF16toUTF8(aPrinterName, printerName);
131 cups_dest_t* printers = nullptr;
132 const auto numPrinters = CupsShim().cupsGetDests(&printers);
133 for (auto i : mozilla::IntegerRange(0, numPrinters)) {
134 const char* const displayName = CupsShim().cupsGetOption(
135 "printer-info", printers[i].num_options, printers[i].options);
136 if (printerName == displayName) {
137 // The second arg to CupsShim().cupsCopyDest is called num_dests, but
138 // it actually copies num_dests + 1 elements.
139 CupsShim().cupsCopyDest(printers + i, 0, &printer);
140 break;
143 CupsShim().cupsFreeDests(numPrinters, printers);
145 #else
146 // On GTK, we only ever show the CUPS name of printers, so we can use
147 // cupsGetNamedDest directly.
149 const auto printerName = NS_ConvertUTF16toUTF8(aPrinterName);
150 printer = CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT, printerName.get(),
151 nullptr);
153 #endif
155 if (printer) {
156 // Since the printer name had to be passed by-value, we can move the
157 // name from that.
158 rv.emplace(PrinterInfo{std::move(aPrinterName), printer});
160 return rv;
163 mozilla::Maybe<PrinterInfo> nsPrinterListCUPS::PrinterBySystemName(
164 nsString aPrinterName) const {
165 mozilla::Maybe<PrinterInfo> rv;
166 if (!CupsShim().InitOkay()) {
167 return rv;
170 const auto printerName = NS_ConvertUTF16toUTF8(aPrinterName);
171 if (cups_dest_t* const printer = CupsShim().cupsGetNamedDest(
172 CUPS_HTTP_DEFAULT, printerName.get(), nullptr)) {
173 rv.emplace(PrinterInfo{std::move(aPrinterName), printer});
175 return rv;
178 nsresult nsPrinterListCUPS::SystemDefaultPrinterName(nsAString& aName) const {
179 aName.Truncate();
181 if (!CupsShim().InitOkay()) {
182 return NS_OK;
185 // Passing in nullptr for the name will return the default, if any.
186 cups_dest_t* dest =
187 CupsShim().cupsGetNamedDest(CUPS_HTTP_DEFAULT, /* name */ nullptr,
188 /* instance */ nullptr);
189 if (!dest) {
190 return NS_OK;
193 GetDisplayNameForPrinter(*dest, aName);
194 if (aName.IsEmpty()) {
195 CopyUTF8toUTF16(mozilla::MakeStringSpan(dest->name), aName);
198 CupsShim().cupsFreeDests(1, dest);
199 return NS_OK;