#include "printing/backend/cups_ipp_helper.h"
#include <cups/cups.h>
#include <algorithm>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
#include "base/containers/contains.h"
#include "base/containers/fixed_flat_map.h"
#include "base/containers/fixed_flat_set.h"
#include "base/logging.h"
#include "base/numerics/clamped_math.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_util.h"
#include "build/build_config.h"
#include "printing/backend/cups_connection.h"
#include "printing/backend/cups_ipp_constants.h"
#include "printing/backend/cups_printer.h"
#include "printing/backend/print_backend_consts.h"
#include "printing/backend/print_backend_utils.h"
#include "printing/mojom/print.mojom.h"
#include "printing/printing_utils.h"
#include "printing/units.h"
#if BUILDFLAG(IS_CHROMEOS)
#include "base/functional/callback.h"
#include "base/metrics/histogram_functions.h"
#include "base/no_destructor.h"
#include "printing/backend/ipp_handler_map.h"
#include "printing/backend/ipp_handlers.h"
#include "printing/printing_features.h"
#endif
namespace printing {
#if BUILDFLAG(IS_CHROMEOS)
constexpr int kPinMinimumLength = 4;
#endif
namespace {
constexpr double kMMPerInch = …;
constexpr double kCmPerInch = …;
constexpr auto kColorMap = …;
constexpr auto kDuplexMap = …;
mojom::ColorModel ColorModelFromIppColor(std::string_view ipp_color) { … }
mojom::DuplexMode DuplexModeFromIpp(std::string_view ipp_duplex) { … }
mojom::ColorModel DefaultColorModel(const CupsOptionProvider& printer) { … }
std::vector<mojom::ColorModel> SupportedColorModels(
const CupsOptionProvider& printer) { … }
void ExtractColor(const CupsOptionProvider& printer,
PrinterSemanticCapsAndDefaults* printer_info) { … }
void ExtractDuplexModes(const CupsOptionProvider& printer,
PrinterSemanticCapsAndDefaults* printer_info) { … }
void CopiesRange(const CupsOptionProvider& printer,
int* lower_bound,
int* upper_bound) { … }
void ExtractCopies(const CupsOptionProvider& printer,
PrinterSemanticCapsAndDefaults* printer_info) { … }
std::optional<gfx::Size> GetResolution(ipp_attribute_t* attr, int i) { … }
void ExtractResolutions(const CupsOptionProvider& printer,
PrinterSemanticCapsAndDefaults* printer_info) { … }
std::optional<PrinterSemanticCapsAndDefaults::Paper>
PaperFromMediaColDatabaseEntry(ipp_t* db_entry) { … }
bool PaperIsBorderless(const PrinterSemanticCapsAndDefaults::Paper& paper) { … }
PrinterSemanticCapsAndDefaults::Papers SupportedPapers(
const CupsPrinter& printer) { … }
void CorrectDefaultMediaType(PrinterSemanticCapsAndDefaults*& printer_info) { … }
void ExtractMediaTypes(const CupsOptionProvider& printer,
PrinterSemanticCapsAndDefaults* printer_info) { … }
bool CollateCapable(const CupsOptionProvider& printer) { … }
bool CollateDefault(const CupsOptionProvider& printer) { … }
#if BUILDFLAG(IS_CHROMEOS)
bool PinSupported(const CupsOptionProvider& printer) {
ipp_attribute_t* attr = printer.GetSupportedOptionValues(kIppPin);
if (!attr)
return false;
int password_maximum_length_supported = ippGetInteger(attr, 0);
if (password_maximum_length_supported < kPinMinimumLength)
return false;
std::vector<std::string_view> values =
printer.GetSupportedOptionValueStrings(kIppPinEncryption);
return base::Contains(values, kPinEncryptionNone);
}
size_t AddAttributes(const CupsOptionProvider& printer,
const char* attr_group_name,
AdvancedCapabilities* caps) {
ipp_attribute_t* attr = printer.GetSupportedOptionValues(attr_group_name);
if (!attr)
return 0;
int num_options = ippGetCount(attr);
static const base::NoDestructor<HandlerMap> handlers(GenerateHandlers());
static constexpr auto kOptionsToIgnore =
base::MakeFixedFlatSet<std::string_view>(
{"finishings-col", "ipp-attribute-fidelity", "job-name",
"number-up-layout"});
std::vector<std::string> unknown_options;
size_t attr_count = 0;
for (int i = 0; i < num_options; i++) {
const char* option_name = ippGetString(attr, i, nullptr);
if (base::Contains(kOptionsToIgnore, option_name)) {
continue;
}
auto it = handlers->find(option_name);
if (it == handlers->end()) {
unknown_options.emplace_back(option_name);
continue;
}
size_t previous_size = caps->size();
it->second.Run(printer, option_name, caps);
if (caps->size() > previous_size)
attr_count++;
}
if (!unknown_options.empty()) {
LOG(WARNING) << "Unknown IPP options: "
<< base::JoinString(unknown_options, ", ");
}
return attr_count;
}
size_t AddInputTray(const CupsOptionProvider& printer,
AdvancedCapabilities* caps) {
size_t previous_size = caps->size();
KeywordHandler(printer, kIppMediaSource, caps);
return caps->size() - previous_size;
}
void ExtractAdvancedCapabilities(const CupsOptionProvider& printer,
PrinterSemanticCapsAndDefaults* printer_info) {
AdvancedCapabilities* options = &printer_info->advanced_capabilities;
size_t attr_count = AddInputTray(printer, options);
attr_count += AddAttributes(printer, kIppJobAttributes, options);
attr_count += AddAttributes(printer, kIppDocumentAttributes, options);
base::UmaHistogramCounts1000("Printing.CUPS.IppAttributesCount", attr_count);
}
#endif
}
PrinterSemanticCapsAndDefaults::Paper DefaultPaper(const CupsPrinter& printer) { … }
void CapsAndDefaultsFromPrinter(const CupsPrinter& printer,
PrinterSemanticCapsAndDefaults* printer_info) { … }
gfx::Rect GetPrintableAreaForSize(const CupsPrinter& printer,
const gfx::Size& size_um) { … }
ScopedIppPtr WrapIpp(ipp_t* ipp) { … }
void IppDeleter::operator()(ipp_t* ipp) const { … }
std::optional<MediaColData> ExtractMediaColData(ipp_t* db_entry) { … }
ScopedIppPtr NewMediaCollection(const MediaColData& data) { … }
void FilterMediaColSizes(ScopedIppPtr& attributes) { … }
}