Reland "Migrate from IPP media/media-supported to media-col/media-col-database"
This is a reland of commit 7635617eba
Fixes a few printing UI tests that were failing on Mac.
Original change's description:
> Migrate from IPP media/media-supported to media-col/media-col-database
>
> Effects of getting the supported paper sizes from CUPS using
> media-col-database instead of media-supported:
> * We get paper sizes as actual dimensions in PWG units instead of having
> to parse them from strings.
> * The vendor ID for each paper size is now determined from its
> dimensions instead of the other way around.
> * Paper display names are now based solely on dimensions, so we can end
> the long game of whack-a-mole trying to get non-standard and duplicate
> paper sizes to display and sort properly.
> * When de-duplicating sizes with borderless variants, we now determine
> whether a size is borderless using its actual margins instead of
> vendor ID heuristics.
> * Dimensions are now formatted properly for the current locale when
> generating display names for unregistered sizes.
> * The algorithm used to determine whether an unregistered size is inches
> or millimeters is better than the one used in CUPS, accounting for
> eighths and tenths of an inch. For example, the size that used to
> display as "200.03 x 148.17 mm" is now properly rendered as
> "7.875 x 5.833 in".
>
> Effects of sending the paper size for a print job using media-col
> instead of media:
> * We now send the "media-source" (input tray) as part of media-col, in
> accordance with IPP standards. Before, we had to use the standalone
> "media-source" attribute, which was a non-standard extension
> implemented in the ChromeOS fork of CUPS.
> * Sending media-col opens the way for work to begin in earnest on media
> type support and borderless printing.
> * We no longer use libcups' janky cupsDestMedia* functions for anything.
>
> Bug: b:199547118
> Test: do print jobs and verify the size, source, and margins are correct
> Test: check the paper size list in the UI for various printers
> Change-Id: I9030283ae22d1f71b20f0237e664af4943fc58c4
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4257505
> Reviewed-by: Lei Zhang <thestig@chromium.org>
> Commit-Queue: Bryan Cain <bryancain@chromium.org>
> Reviewed-by: Benjamin Gordon <bmgordon@chromium.org>
> Code-Coverage: Findit <findit-for-me@appspot.gserviceaccount.com>
> Cr-Commit-Position: refs/heads/main@{#1135611}
Bug: b:199547118
Change-Id: I505e3b82a560b0128c4526acd5ae6c039ee3ab58
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4517541
Reviewed-by: Benjamin Gordon <bmgordon@chromium.org>
Reviewed-by: Lei Zhang <thestig@chromium.org>
Commit-Queue: Bryan Cain <bryancain@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1144269}
This commit is contained in:

committed by
Chromium LUCI CQ

parent
26cba3f8c6
commit
fef8037fe5
base/i18n
chrome
browser
common
printing
backend
cups_ipp_constants.cccups_ipp_constants.hcups_ipp_helper.cccups_ipp_helper.hcups_ipp_helper_unittest.cccups_printer.cccups_printer.hmock_cups_printer.hprint_backend_utils.ccprint_backend_utils.hprint_backend_utils_unittest.cc
printing_context_chromeos.ccprinting_context_chromeos.hprinting_context_chromeos_unittest.cc@ -65,6 +65,12 @@ std::u16string FormatNumber(int64_t number) {
|
||||
}
|
||||
|
||||
std::u16string FormatDouble(double number, int fractional_digits) {
|
||||
return FormatDouble(number, fractional_digits, fractional_digits);
|
||||
}
|
||||
|
||||
std::u16string FormatDouble(double number,
|
||||
int min_fractional_digits,
|
||||
int max_fractional_digits) {
|
||||
icu::NumberFormat* number_format =
|
||||
g_number_format_float.Get().number_format.get();
|
||||
|
||||
@ -72,8 +78,8 @@ std::u16string FormatDouble(double number, int fractional_digits) {
|
||||
// As a fallback, just return the raw number in a string.
|
||||
return ASCIIToUTF16(StringPrintf("%f", number));
|
||||
}
|
||||
number_format->setMaximumFractionDigits(fractional_digits);
|
||||
number_format->setMinimumFractionDigits(fractional_digits);
|
||||
number_format->setMaximumFractionDigits(max_fractional_digits);
|
||||
number_format->setMinimumFractionDigits(min_fractional_digits);
|
||||
icu::UnicodeString ustr;
|
||||
number_format->format(number, ustr);
|
||||
|
||||
|
@ -17,12 +17,24 @@ namespace base {
|
||||
// Ex: FormatNumber(1234567) => "1,234,567" in English, "1.234.567" in German
|
||||
BASE_I18N_EXPORT std::u16string FormatNumber(int64_t number);
|
||||
|
||||
// Return a number formatted with separators in the user's locale.
|
||||
// Return a number formatted with separators in the user's locale, with
|
||||
// `fractional_digits` digits after the decimal point.
|
||||
// Ex: FormatDouble(1234567.8, 1)
|
||||
// => "1,234,567.8" in English, "1.234.567,8" in German
|
||||
BASE_I18N_EXPORT std::u16string FormatDouble(double number,
|
||||
int fractional_digits);
|
||||
|
||||
// Return a number formatted with separators in the user's locale, with up to
|
||||
// `max_fractional_digits` digits after the decimal point, and eliminating
|
||||
// trailing zeroes after `min_fractional_digits`.
|
||||
// Ex: FormatDouble(1234567.8, 0, 4)
|
||||
// => "1,234,567.8" in English, "1.234.567,8" in German
|
||||
// Ex: FormatDouble(1234567.888888, 0, 4)
|
||||
// => "1,234,567.8889" in English, "1.234.567,8889" in German
|
||||
BASE_I18N_EXPORT std::u16string FormatDouble(double number,
|
||||
int min_fractional_digits,
|
||||
int max_fractional_digits);
|
||||
|
||||
// Return a percentage formatted with space and symbol in the user's locale.
|
||||
// Ex: FormatPercent(12) => "12%" in English, "12 %" in Romanian
|
||||
BASE_I18N_EXPORT std::u16string FormatPercent(int number);
|
||||
|
@ -45,7 +45,7 @@ TEST(NumberFormattingTest, FormatNumber) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NumberFormattingTest, FormatDouble) {
|
||||
TEST(NumberFormattingTest, FormatDoubleWithFixedFractionalDigits) {
|
||||
static const struct {
|
||||
double number;
|
||||
int frac_digits;
|
||||
@ -91,6 +91,55 @@ TEST(NumberFormattingTest, FormatDouble) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NumberFormattingTest, FormatDoubleWithFractionalDigitRange) {
|
||||
static const struct {
|
||||
double number;
|
||||
int min_frac_digits;
|
||||
int max_frac_digits;
|
||||
const char* expected_english;
|
||||
const char* expected_german;
|
||||
} cases[] = {
|
||||
{0.0, 0, 0, "0", "0"},
|
||||
#if !BUILDFLAG(IS_ANDROID)
|
||||
// Bionic can't printf negative zero correctly.
|
||||
{-0.0, 0, 4, "-0", "-0"},
|
||||
#endif
|
||||
{1024.2, 0, 0, "1,024", "1.024"},
|
||||
{-1024.223, 0, 2, "-1,024.22", "-1.024,22"},
|
||||
{std::numeric_limits<double>::max(), 0, 6,
|
||||
"179,769,313,486,231,570,000,000,000,000,000,000,000,000,000,000,000,"
|
||||
"000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
|
||||
"000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
|
||||
"000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
|
||||
"000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
|
||||
"000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,000,"
|
||||
"000",
|
||||
"179.769.313.486.231.570.000.000.000.000.000.000.000.000.000.000.000."
|
||||
"000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
|
||||
"000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
|
||||
"000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
|
||||
"000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
|
||||
"000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000.000."
|
||||
"000"},
|
||||
{std::numeric_limits<double>::min(), 2, 2, "0.00", "0,00"},
|
||||
{-42.7, 0, 3, "-42.7", "-42,7"},
|
||||
};
|
||||
|
||||
test::ScopedRestoreICUDefaultLocale restore_locale;
|
||||
for (const auto& i : cases) {
|
||||
i18n::SetICUDefaultLocale("en");
|
||||
ResetFormattersForTesting();
|
||||
EXPECT_EQ(i.expected_english,
|
||||
UTF16ToUTF8(FormatDouble(i.number, i.min_frac_digits,
|
||||
i.max_frac_digits)));
|
||||
i18n::SetICUDefaultLocale("de");
|
||||
ResetFormattersForTesting();
|
||||
EXPECT_EQ(i.expected_german,
|
||||
UTF16ToUTF8(FormatDouble(i.number, i.min_frac_digits,
|
||||
i.max_frac_digits)));
|
||||
}
|
||||
}
|
||||
|
||||
TEST(NumberFormattingTest, FormatPercent) {
|
||||
static const struct {
|
||||
int64_t number;
|
||||
|
@ -238,8 +238,7 @@ std::unique_ptr<printing::PrintSettings> ParsePrintTicket(
|
||||
}
|
||||
cloud_devices::printer::Media media_value = media.value();
|
||||
printing::PrintSettings::RequestedMedia requested_media;
|
||||
if (media_value.size_um.width() <= 0 || media_value.size_um.height() <= 0 ||
|
||||
media_value.vendor_id.empty()) {
|
||||
if (media_value.size_um.width() <= 0 || media_value.size_um.height() <= 0) {
|
||||
LOG(ERROR) << "Loaded invalid media from print ticket.";
|
||||
return nullptr;
|
||||
}
|
||||
@ -306,8 +305,7 @@ bool CheckSettingsAndCapabilitiesCompatibility(
|
||||
capabilities.papers,
|
||||
[&requested_media](
|
||||
const printing::PrinterSemanticCapsAndDefaults::Paper& paper) {
|
||||
return paper.size_um == requested_media.size_microns &&
|
||||
paper.vendor_id == requested_media.vendor_id;
|
||||
return paper.size_um == requested_media.size_microns;
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -905,9 +905,16 @@ IN_PROC_BROWSER_TEST_P(SystemAccessProcessPrintBrowserTest,
|
||||
print_view_manager.snooped_params();
|
||||
ASSERT_TRUE(snooped_params);
|
||||
EXPECT_EQ(test::kPrinterCapabilitiesDpi, snooped_params->params->dpi);
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
EXPECT_EQ(kLegalPhysicalSize, snooped_params->params->page_size);
|
||||
EXPECT_EQ(kLegalPrintableArea, snooped_params->params->printable_area);
|
||||
EXPECT_EQ(kLegalExpectedContentSize, snooped_params->params->content_size);
|
||||
#else
|
||||
EXPECT_EQ(kLetterPhysicalSize, snooped_params->params->page_size);
|
||||
EXPECT_EQ(kLetterPrintableArea, snooped_params->params->printable_area);
|
||||
EXPECT_EQ(kLetterExpectedContentSize, snooped_params->params->content_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if BUILDFLAG(ENABLE_OOP_PRINTING)
|
||||
@ -935,9 +942,16 @@ IN_PROC_BROWSER_TEST_P(SystemAccessProcessPrintBrowserTest,
|
||||
print_view_manager.snooped_params();
|
||||
ASSERT_TRUE(snooped_params);
|
||||
EXPECT_EQ(test::kPrinterCapabilitiesDpi, snooped_params->params->dpi);
|
||||
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
EXPECT_EQ(kLetterPhysicalSize, snooped_params->params->page_size);
|
||||
EXPECT_EQ(kLetterPrintableArea, snooped_params->params->printable_area);
|
||||
EXPECT_EQ(kLetterExpectedContentSize, snooped_params->params->content_size);
|
||||
#else
|
||||
EXPECT_EQ(kLegalPhysicalSize, snooped_params->params->page_size);
|
||||
EXPECT_EQ(kLegalPrintableArea, snooped_params->params->printable_area);
|
||||
EXPECT_EQ(kLegalExpectedContentSize, snooped_params->params->content_size);
|
||||
#endif
|
||||
}
|
||||
|
||||
IN_PROC_BROWSER_TEST_F(SystemAccessProcessSandboxedServicePrintBrowserTest,
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -19,9 +19,9 @@ enum class MediaSizeGroup {
|
||||
};
|
||||
|
||||
struct MediaSizeInfo {
|
||||
std::u16string name;
|
||||
std::string vendor_id;
|
||||
std::u16string display_name;
|
||||
MediaSizeGroup sort_group;
|
||||
bool registered_size;
|
||||
};
|
||||
|
||||
struct PaperWithSizeInfo {
|
||||
@ -31,13 +31,12 @@ struct PaperWithSizeInfo {
|
||||
PrinterSemanticCapsAndDefaults::Paper paper;
|
||||
};
|
||||
|
||||
// Maps a paper vendor ID to a localized name and sort group. The returned name
|
||||
// will be automatically generated if the vendor ID does not have a known
|
||||
// mapping. If the vendor ID is not a valid PWG self-describing media name,
|
||||
// the returned name will be empty. The returned names are u16strings to
|
||||
// facilitate subsequent sorting; they need to be converted to UTF-8 before
|
||||
// updating a `Paper` object.
|
||||
MediaSizeInfo LocalizePaperDisplayName(const std::string& vendor_id);
|
||||
// Maps a paper size to a vendor ID, localized display name and sort group. The
|
||||
// returned ID and name will be automatically generated if the size does not
|
||||
// have a known mapping. The display names are u16strings to facilitate
|
||||
// subsequent sorting; they need to be converted to UTF-8 before updating a
|
||||
// `Paper` object.
|
||||
MediaSizeInfo LocalizePaperDisplayName(const gfx::Size& size_um);
|
||||
|
||||
// Sorts a list of paper sizes in place by using the paired sort groups.
|
||||
void SortPaperDisplayNames(std::vector<PaperWithSizeInfo>& papers);
|
||||
|
@ -21,38 +21,62 @@ using Paper = PrinterSemanticCapsAndDefaults::Paper;
|
||||
namespace {
|
||||
|
||||
struct MediaInfoTestCase {
|
||||
const char* vendor_id;
|
||||
gfx::Size size_um;
|
||||
std::string expected_vendor_id;
|
||||
std::u16string expected_localized_name;
|
||||
MediaSizeGroup expected_group;
|
||||
};
|
||||
|
||||
void VerifyLocalizedInfo(const MediaInfoTestCase& test_case) {
|
||||
MediaSizeInfo info = LocalizePaperDisplayName(test_case.vendor_id);
|
||||
EXPECT_EQ(info.name, test_case.expected_localized_name);
|
||||
MediaSizeInfo info = LocalizePaperDisplayName(test_case.size_um);
|
||||
EXPECT_EQ(info.vendor_id, test_case.expected_vendor_id);
|
||||
EXPECT_EQ(info.display_name, test_case.expected_localized_name);
|
||||
EXPECT_EQ(info.sort_group, test_case.expected_group);
|
||||
}
|
||||
|
||||
void VerifyPaperSizeMatch(const PaperWithSizeInfo& lhs,
|
||||
const PaperWithSizeInfo& rhs) {
|
||||
EXPECT_EQ(lhs.size_info.name, rhs.size_info.name);
|
||||
EXPECT_EQ(lhs.size_info.vendor_id, rhs.size_info.vendor_id);
|
||||
EXPECT_EQ(lhs.size_info.display_name, rhs.size_info.display_name);
|
||||
EXPECT_EQ(lhs.size_info.sort_group, rhs.size_info.sort_group);
|
||||
EXPECT_EQ(lhs.paper, rhs.paper);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// Verifies that we localize some common names.
|
||||
TEST(PrintMediaL10N, LocalizeSomeCommonNames) {
|
||||
// Verifies that we localize some common paper sizes.
|
||||
TEST(PrintMediaL10N, LocalizeSomeCommonSizes) {
|
||||
const MediaInfoTestCase kTestCases[] = {
|
||||
{"na_c_17x22in", u"17 x 22 in", MediaSizeGroup::kSizeIn},
|
||||
{"iso_a0_841x1189mm", u"A0", MediaSizeGroup::kSizeNamed},
|
||||
{"iso_a1_594x841mm", u"A1", MediaSizeGroup::kSizeNamed},
|
||||
{"iso_a4_210x297mm", u"A4", MediaSizeGroup::kSizeNamed},
|
||||
{"na_govt-legal_8x13in", u"8 x 13 in", MediaSizeGroup::kSizeIn},
|
||||
{"na_govt-letter_8x10in", u"8 x 10 in", MediaSizeGroup::kSizeIn},
|
||||
{"na_letter_8.5x11in", u"Letter", MediaSizeGroup::kSizeNamed},
|
||||
{"oe_photo-l_3.5x5in", u"3.5 x 5 in", MediaSizeGroup::kSizeIn},
|
||||
{"om_business-card_55x91mm", u"55 x 91 mm", MediaSizeGroup::kSizeMm},
|
||||
{{431800, 558800},
|
||||
"na_c_17x22in",
|
||||
u"17 x 22 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
{{841000, 1189000},
|
||||
"iso_a0_841x1189mm",
|
||||
u"A0",
|
||||
MediaSizeGroup::kSizeNamed},
|
||||
{{594000, 841000}, "iso_a1_594x841mm", u"A1", MediaSizeGroup::kSizeNamed},
|
||||
{{210000, 297000}, "iso_a4_210x297mm", u"A4", MediaSizeGroup::kSizeNamed},
|
||||
{{203200, 330200},
|
||||
"na_govt-legal_8x13in",
|
||||
u"8 x 13 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
{{203200, 254000},
|
||||
"na_govt-letter_8x10in",
|
||||
u"8 x 10 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
{{215900, 279400},
|
||||
"na_letter_8.5x11in",
|
||||
u"Letter",
|
||||
MediaSizeGroup::kSizeNamed},
|
||||
{{88900, 127000},
|
||||
"oe_photo-l_3.5x5in",
|
||||
u"3.5 x 5 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
{{55000, 91000},
|
||||
"om_business-card_55x91mm",
|
||||
u"55 x 91 mm",
|
||||
MediaSizeGroup::kSizeMm},
|
||||
};
|
||||
|
||||
for (const auto& test_case : kTestCases) {
|
||||
@ -60,66 +84,38 @@ TEST(PrintMediaL10N, LocalizeSomeCommonNames) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that we return the empty string when no localization is
|
||||
// found for a given media name.
|
||||
TEST(PrintMediaL10N, DoWithoutCommonName) {
|
||||
// Verifies that we generate a sensible vendor ID and display name when no
|
||||
// localization is found for a given media size.
|
||||
TEST(PrintMediaL10N, LocalizeNonStandardSizes) {
|
||||
const MediaInfoTestCase kTestCases[] = {
|
||||
{"", u"", MediaSizeGroup::kSizeNamed},
|
||||
{"lorem_ipsum_8x10", u"", MediaSizeGroup::kSizeNamed},
|
||||
{"q_e_d_130x200mm", u"", MediaSizeGroup::kSizeNamed},
|
||||
{"not at all a valid vendor ID", u"", MediaSizeGroup::kSizeNamed},
|
||||
};
|
||||
|
||||
for (const auto& test_case : kTestCases) {
|
||||
VerifyLocalizedInfo(test_case);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that duplicates have the same localization.
|
||||
TEST(PrintMediaL10N, LocalizeDuplicateNames) {
|
||||
const struct {
|
||||
const char* duplicate_vendor_id;
|
||||
const char* vendor_id;
|
||||
} kTestCases[] = {
|
||||
{"oe_photo-s10r_10x15in", "na_10x15_10x15in"},
|
||||
{"om_large-photo_200x300", "om_large-photo_200x300mm"},
|
||||
{"om_postfix_114x229mm", "iso_c6c5_114x229mm"},
|
||||
{"prc_10_324x458mm", "iso_c3_324x458mm"},
|
||||
{"prc_3_125x176mm", "iso_b6_125x176mm"},
|
||||
{"prc_5_110x220mm", "iso_dl_110x220mm"},
|
||||
{"iso_id-3_88x125mm", "iso_b7_88x125mm"},
|
||||
{"na_letter_8.5x11in", "na_card-letter_8.5x11in"},
|
||||
{"na_letter_8.5x11in", "na_letter.fb_8.5x11in"},
|
||||
{"na_letter_8.5x11in", "na_card-letter.fb_8.5x11in"},
|
||||
};
|
||||
|
||||
for (const auto& test_case : kTestCases) {
|
||||
MediaSizeInfo duplicate =
|
||||
LocalizePaperDisplayName(test_case.duplicate_vendor_id);
|
||||
MediaSizeInfo original = LocalizePaperDisplayName(test_case.vendor_id);
|
||||
|
||||
EXPECT_EQ(duplicate.name, original.name);
|
||||
EXPECT_EQ(duplicate.sort_group, original.sort_group);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that we generate names for unrecognized sizes correctly.
|
||||
TEST(PrintMediaL10N, LocalizeSelfDescribingSizes) {
|
||||
const MediaInfoTestCase kTestCases[] = {
|
||||
{"invalid_size", u"", MediaSizeGroup::kSizeNamed},
|
||||
{"om_photo-31x41_310x410mm", u"310 x 410 mm", MediaSizeGroup::kSizeMm},
|
||||
{"om_t-4-x-7_4x7in", u"4 x 7 in", MediaSizeGroup::kSizeIn},
|
||||
{"om_4-x-7_101.6x180.6mm", u"4 X 7 (101.6 x 180.6 mm)",
|
||||
MediaSizeGroup::kSizeNamed},
|
||||
{"om_custom-1_209.9x297.04mm", u"Custom 1 (209.9 x 297.04 mm)",
|
||||
MediaSizeGroup::kSizeNamed},
|
||||
{"om_double-postcard-rotated_200.03x148.17mm",
|
||||
u"Double Postcard Rotated (200.03 x 148.17 mm)",
|
||||
MediaSizeGroup::kSizeNamed},
|
||||
{"oe_photo-8x10-tab_8x10.5in", u"Photo 8x10 Tab (8 x 10.5 in)",
|
||||
MediaSizeGroup::kSizeNamed},
|
||||
{"na_card-letter_8.5x11in", u"Letter", MediaSizeGroup::kSizeNamed},
|
||||
{"na_letter.fb_8.5x11in", u"Letter", MediaSizeGroup::kSizeNamed},
|
||||
{{310000, 410000},
|
||||
"om_310000x410000um_310x410mm",
|
||||
u"310 x 410 mm",
|
||||
MediaSizeGroup::kSizeMm},
|
||||
{{101600, 177800},
|
||||
"om_101600x177800um_101x177mm",
|
||||
u"4 x 7 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
{{101600, 180620},
|
||||
"om_101600x180620um_101x180mm",
|
||||
u"4 x 7.111 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
{{209900, 297040},
|
||||
"om_209900x297040um_209x297mm",
|
||||
u"210 x 297 mm",
|
||||
MediaSizeGroup::kSizeMm},
|
||||
{{200030, 148170},
|
||||
"om_200030x148170um_200x148mm",
|
||||
u"200 x 148 mm",
|
||||
MediaSizeGroup::kSizeMm},
|
||||
{{203200, 266700},
|
||||
"om_203200x266700um_203x266mm",
|
||||
u"8 x 10.5 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
{{133350, 180620},
|
||||
"om_133350x180620um_133x180mm",
|
||||
u"5.25 x 7.111 in",
|
||||
MediaSizeGroup::kSizeIn},
|
||||
};
|
||||
|
||||
for (const auto& test_case : kTestCases) {
|
||||
@ -129,15 +125,13 @@ TEST(PrintMediaL10N, LocalizeSelfDescribingSizes) {
|
||||
|
||||
// Verifies that paper sizes are returned in the expected order of groups.
|
||||
TEST(PrintMediaL10N, SortGroupsOrdered) {
|
||||
PaperWithSizeInfo mm = {
|
||||
MediaSizeInfo{u"mm", MediaSizeGroup::kSizeMm, /*registered_size=*/false},
|
||||
Paper{"metric", "mm", gfx::Size()}};
|
||||
PaperWithSizeInfo in = {
|
||||
MediaSizeInfo{u"in", MediaSizeGroup::kSizeIn, /*registered_size=*/false},
|
||||
Paper{"inches", "in", gfx::Size()}};
|
||||
PaperWithSizeInfo named = {MediaSizeInfo{u"named", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
Paper{"named size", "named", gfx::Size()}};
|
||||
PaperWithSizeInfo mm = {MediaSizeInfo{"", u"mm", MediaSizeGroup::kSizeMm},
|
||||
Paper{"metric", "mm", gfx::Size()}};
|
||||
PaperWithSizeInfo in = {MediaSizeInfo{"", u"in", MediaSizeGroup::kSizeIn},
|
||||
Paper{"inches", "in", gfx::Size()}};
|
||||
PaperWithSizeInfo named = {
|
||||
MediaSizeInfo{"", u"named", MediaSizeGroup::kSizeNamed},
|
||||
Paper{"named size", "named", gfx::Size()}};
|
||||
|
||||
std::vector<PaperWithSizeInfo> papers = {mm, named, in};
|
||||
std::vector<PaperWithSizeInfo> expected = {in, mm, named};
|
||||
@ -147,48 +141,40 @@ TEST(PrintMediaL10N, SortGroupsOrdered) {
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that inch paper sizes are sorted by width, height, name.
|
||||
// Verifies that inch paper sizes are sorted by width, then height.
|
||||
TEST(PrintMediaL10N, SortInchSizes) {
|
||||
PaperWithSizeInfo p1 = {
|
||||
MediaSizeInfo{u"1x3", MediaSizeGroup::kSizeIn, /*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"1x3", MediaSizeGroup::kSizeIn},
|
||||
Paper{"1x3", "in", gfx::Size(1, 3), gfx::Rect(0, 0, 1, 3)}};
|
||||
PaperWithSizeInfo p2 = {
|
||||
MediaSizeInfo{u"2x1", MediaSizeGroup::kSizeIn, /*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"2x1", MediaSizeGroup::kSizeIn},
|
||||
Paper{"2x1", "in", gfx::Size(2, 1), gfx::Rect(0, 0, 2, 1)}};
|
||||
PaperWithSizeInfo p3 = {
|
||||
MediaSizeInfo{u"2x2", MediaSizeGroup::kSizeIn, /*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"2x2", MediaSizeGroup::kSizeIn},
|
||||
Paper{"2x2", "in", gfx::Size(2, 2), gfx::Rect(0, 0, 2, 2)}};
|
||||
PaperWithSizeInfo p4 = {
|
||||
MediaSizeInfo{u"2x2 B", MediaSizeGroup::kSizeIn,
|
||||
/*registered_size=*/false},
|
||||
Paper{"2x2 B", "in", gfx::Size(2, 2), gfx::Rect(0, 0, 2, 2)}};
|
||||
|
||||
std::vector<PaperWithSizeInfo> papers = {p4, p1, p2, p3};
|
||||
std::vector<PaperWithSizeInfo> expected = {p1, p2, p3, p4};
|
||||
std::vector<PaperWithSizeInfo> papers = {p2, p3, p1};
|
||||
std::vector<PaperWithSizeInfo> expected = {p1, p2, p3};
|
||||
SortPaperDisplayNames(papers);
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
VerifyPaperSizeMatch(papers[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that mm paper sizes are sorted by width, height, name.
|
||||
// Verifies that mm paper sizes are sorted by width, then height.
|
||||
TEST(PrintMediaL10N, SortMmSizes) {
|
||||
PaperWithSizeInfo p1 = {
|
||||
MediaSizeInfo{u"1x3", MediaSizeGroup::kSizeMm, /*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"1x3", MediaSizeGroup::kSizeMm},
|
||||
Paper{"1x3", "mm", gfx::Size(1, 3), gfx::Rect(0, 0, 1, 3)}};
|
||||
PaperWithSizeInfo p2 = {
|
||||
MediaSizeInfo{u"2x1", MediaSizeGroup::kSizeMm, /*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"2x1", MediaSizeGroup::kSizeMm},
|
||||
Paper{"2x1", "mm", gfx::Size(2, 1), gfx::Rect(0, 0, 2, 1)}};
|
||||
PaperWithSizeInfo p3 = {
|
||||
MediaSizeInfo{u"2x2", MediaSizeGroup::kSizeMm, /*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"2x2", MediaSizeGroup::kSizeMm},
|
||||
Paper{"2x2", "mm", gfx::Size(2, 2), gfx::Rect(0, 0, 2, 2)}};
|
||||
PaperWithSizeInfo p4 = {
|
||||
MediaSizeInfo{u"2x2 B", MediaSizeGroup::kSizeMm,
|
||||
/*registered_size=*/false},
|
||||
Paper{"2x2 B", "mm", gfx::Size(2, 2), gfx::Rect(0, 0, 2, 2)}};
|
||||
|
||||
std::vector<PaperWithSizeInfo> papers = {p4, p1, p2, p3};
|
||||
std::vector<PaperWithSizeInfo> expected = {p1, p2, p3, p4};
|
||||
std::vector<PaperWithSizeInfo> papers = {p2, p3, p1};
|
||||
std::vector<PaperWithSizeInfo> expected = {p1, p2, p3};
|
||||
SortPaperDisplayNames(papers);
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
VerifyPaperSizeMatch(papers[i], expected[i]);
|
||||
@ -198,20 +184,16 @@ TEST(PrintMediaL10N, SortMmSizes) {
|
||||
// Verifies that named paper sizes are sorted by name, width, height.
|
||||
TEST(PrintMediaL10N, SortNamedSizes) {
|
||||
PaperWithSizeInfo p1 = {
|
||||
MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"AAA", MediaSizeGroup::kSizeNamed},
|
||||
Paper{"AAA", "name", gfx::Size(50, 50), gfx::Rect(0, 0, 50, 50)}};
|
||||
PaperWithSizeInfo p2 = {
|
||||
MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"BBB", MediaSizeGroup::kSizeNamed},
|
||||
Paper{"BBB", "name1", gfx::Size(1, 3), gfx::Rect(0, 0, 1, 3)}};
|
||||
PaperWithSizeInfo p3 = {
|
||||
MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"BBB", MediaSizeGroup::kSizeNamed},
|
||||
Paper{"BBB", "name2", gfx::Size(2, 2), gfx::Rect(0, 0, 2, 2)}};
|
||||
PaperWithSizeInfo p4 = {
|
||||
MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
MediaSizeInfo{"", u"BBB", MediaSizeGroup::kSizeNamed},
|
||||
Paper{"BBB", "name3", gfx::Size(2, 3), gfx::Rect(0, 0, 2, 3)}};
|
||||
|
||||
std::vector<PaperWithSizeInfo> papers = {p4, p1, p2, p3};
|
||||
@ -222,59 +204,4 @@ TEST(PrintMediaL10N, SortNamedSizes) {
|
||||
}
|
||||
}
|
||||
|
||||
TEST(PrintMediaL10N, RemoveBorderlessSizes) {
|
||||
PaperWithSizeInfo p1 = {MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
Paper{"AAA", "oe_aaa.fb_8x10in", gfx::Size(8, 10)}};
|
||||
PaperWithSizeInfo p2 = {MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed},
|
||||
Paper{"BBB", "oe_bbb_4x6in", gfx::Size(4, 6)}};
|
||||
PaperWithSizeInfo p3 = {
|
||||
MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeNamed},
|
||||
Paper{"BBB", "oe_bbb.borderless_4x6in", gfx::Size(4, 6)}};
|
||||
PaperWithSizeInfo p4 = {MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
Paper{"AAA", "oe_aaa.8x10in", gfx::Size(8, 10)}};
|
||||
|
||||
std::vector<PaperWithSizeInfo> papers = {p1, p2, p3, p4};
|
||||
std::vector<PaperWithSizeInfo> expected = {p4, p2};
|
||||
SortPaperDisplayNames(papers);
|
||||
ASSERT_EQ(papers.size(), expected.size());
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
VerifyPaperSizeMatch(papers[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Verifies that PWG registered size names sort above unregistered names with
|
||||
// the same dimensions.
|
||||
TEST(PrintMediaL10N, SortNonstandardSizes) {
|
||||
PaperWithSizeInfo p1 = {
|
||||
MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
Paper{"AAA", "na_card-letter_8.5x11in", gfx::Size(9, 11)}};
|
||||
PaperWithSizeInfo p2 = {
|
||||
MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/false},
|
||||
Paper{"AAA", "na_card-letter_8x9in", gfx::Size(8, 11)}};
|
||||
PaperWithSizeInfo p3 = {
|
||||
MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeIn, /*registered_size=*/false},
|
||||
Paper{"AAA", "oe_aaa.8x10in", gfx::Size(8, 10)}};
|
||||
PaperWithSizeInfo p4 = {MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeNamed,
|
||||
/*registered_size=*/true},
|
||||
Paper{"AAA", "na_letter_8.5x11in", gfx::Size(9, 11)}};
|
||||
PaperWithSizeInfo p5 = {
|
||||
MediaSizeInfo{u"BBB", MediaSizeGroup::kSizeIn, /*registered_size=*/true},
|
||||
Paper{"BBB", "na_govt-letter_8x10in", gfx::Size(8, 10)}};
|
||||
PaperWithSizeInfo p6 = {
|
||||
MediaSizeInfo{u"AAA", MediaSizeGroup::kSizeIn, /*registered_size=*/true},
|
||||
Paper{"AAA", "na_govt-letter_8x10in", gfx::Size(8, 10)}};
|
||||
|
||||
std::vector<PaperWithSizeInfo> papers = {p1, p2, p3, p4, p5, p6};
|
||||
std::vector<PaperWithSizeInfo> expected = {p6, p5, p3, p4, p2, p1};
|
||||
SortPaperDisplayNames(papers);
|
||||
ASSERT_EQ(papers.size(), expected.size());
|
||||
for (size_t i = 0; i < expected.size(); i++) {
|
||||
VerifyPaperSizeMatch(papers[i], expected[i]);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace printing
|
||||
|
@ -59,22 +59,19 @@ namespace {
|
||||
|
||||
#if BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
|
||||
// Iterate on the `Papers` of a given printer `info` and set the
|
||||
// `display_name` members, localizing where possible. We expect the
|
||||
// backend to have populated non-empty display names already, so we
|
||||
// don't touch media display names that we can't localize.
|
||||
// The `Papers` will be sorted in place when this function returns.
|
||||
void PopulateAndSortAllPaperDisplayNames(PrinterSemanticCapsAndDefaults& info) {
|
||||
MediaSizeInfo default_paper_display =
|
||||
LocalizePaperDisplayName(info.default_paper.vendor_id);
|
||||
if (!default_paper_display.name.empty()) {
|
||||
info.default_paper.display_name =
|
||||
base::UTF16ToUTF8(default_paper_display.name);
|
||||
}
|
||||
// `display_name` members, localizing where possible, as well as the `vendor_id`
|
||||
// members. The `Papers` will be sorted in place when this function returns.
|
||||
void PopulateAndSortAllPaperNames(PrinterSemanticCapsAndDefaults& info) {
|
||||
MediaSizeInfo default_paper =
|
||||
LocalizePaperDisplayName(info.default_paper.size_um);
|
||||
info.default_paper.vendor_id = default_paper.vendor_id;
|
||||
info.default_paper.display_name =
|
||||
base::UTF16ToUTF8(default_paper.display_name);
|
||||
|
||||
// Pair the paper entries with their sort info so they can be sorted.
|
||||
std::vector<PaperWithSizeInfo> size_list;
|
||||
for (PrinterSemanticCapsAndDefaults::Paper& paper : info.papers) {
|
||||
size_list.emplace_back(LocalizePaperDisplayName(paper.vendor_id),
|
||||
size_list.emplace_back(LocalizePaperDisplayName(paper.size_um),
|
||||
std::move(paper));
|
||||
}
|
||||
|
||||
@ -83,9 +80,8 @@ void PopulateAndSortAllPaperDisplayNames(PrinterSemanticCapsAndDefaults& info) {
|
||||
info.papers.clear();
|
||||
for (auto& pair : size_list) {
|
||||
auto& paper = info.papers.emplace_back(std::move(pair.paper));
|
||||
if (!pair.size_info.name.empty()) {
|
||||
paper.display_name = base::UTF16ToUTF8(pair.size_info.name);
|
||||
}
|
||||
paper.vendor_id = pair.size_info.vendor_id;
|
||||
paper.display_name = base::UTF16ToUTF8(pair.size_info.display_name);
|
||||
}
|
||||
}
|
||||
#endif // BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
|
||||
@ -119,16 +115,17 @@ base::Value AssemblePrinterCapabilities(const std::string& device_name,
|
||||
return base::Value();
|
||||
|
||||
#if BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
|
||||
bool populate_paper_display_names = true;
|
||||
bool populate_paper_names = true;
|
||||
#if BUILDFLAG(IS_MAC)
|
||||
// Paper display name localization requires standardized vendor ID names
|
||||
// populated by CUPS IPP. If the CUPS IPP backend is not enabled, localization
|
||||
// will not properly occur.
|
||||
populate_paper_display_names =
|
||||
// Paper display name localization and vendor ID assignment is intended for
|
||||
// use with the CUPS IPP backend. If the CUPS IPP backend is not enabled,
|
||||
// localization will not properly occur.
|
||||
populate_paper_names =
|
||||
base::FeatureList::IsEnabled(features::kCupsIppPrintingBackend);
|
||||
#endif
|
||||
if (populate_paper_display_names)
|
||||
PopulateAndSortAllPaperDisplayNames(*caps);
|
||||
if (populate_paper_names) {
|
||||
PopulateAndSortAllPaperNames(*caps);
|
||||
}
|
||||
#endif // BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
|
@ -206,7 +206,11 @@ TEST_F(PrinterCapabilitiesTest, UserDefinedPapers) {
|
||||
|
||||
// Verify the 3 paper sizes are the ones in |caps->papers|, followed by the
|
||||
// ones in |user_defined_papers|.
|
||||
#if BUILDFLAG(PRINT_MEDIA_L10N_ENABLED)
|
||||
VerifyPaper((*media_option)[0], "0 x 0 mm", "om_100x234um_0x0mm", {100, 234});
|
||||
#else
|
||||
VerifyPaper((*media_option)[0], "printer_foo", "printer_vendor", {100, 234});
|
||||
#endif
|
||||
VerifyPaper((*media_option)[1], "foo", "vendor", {200, 300});
|
||||
VerifyPaper((*media_option)[2], "bar", "vendor", {600, 600});
|
||||
}
|
||||
@ -272,7 +276,8 @@ TEST_F(PrinterCapabilitiesTest, PaperLocalizationsApplied) {
|
||||
|
||||
// Verify the paper sizes are the ones in `caps->papers` in the correct
|
||||
// order.
|
||||
VerifyPaper((*media_option)[0], "2 x 3 in", "oe_2x3_2x3in", {50800, 76200});
|
||||
VerifyPaper((*media_option)[0], "2 x 3 in", "om_50800x76200um_50x76mm",
|
||||
{50800, 76200});
|
||||
VerifyPaper((*media_option)[1], "3.5 x 5 in", "oe_photo-l_3.5x5in",
|
||||
{88900, 127000});
|
||||
VerifyPaper((*media_option)[2], "4 x 4 in", "oe_square-photo_4x4in",
|
||||
@ -281,18 +286,19 @@ TEST_F(PrinterCapabilitiesTest, PaperLocalizationsApplied) {
|
||||
{101600, 152400});
|
||||
VerifyPaper((*media_option)[4], "5 x 5 in", "oe_square-photo_5x5in",
|
||||
{127000, 127000});
|
||||
VerifyPaper((*media_option)[5], "1 x 1 mm", "om_1-x-1_1x1mm", {1000, 1000});
|
||||
VerifyPaper((*media_option)[6], "210 x 330 mm", "om_folio_210x330mm",
|
||||
VerifyPaper((*media_option)[5], "9 x 12.1 in", "om_228600x307340um_228x307mm",
|
||||
{228600, 307340});
|
||||
VerifyPaper((*media_option)[6], "1 x 1 mm", "om_1000x1000um_1x1mm",
|
||||
{1000, 1000});
|
||||
VerifyPaper((*media_option)[7], "210 x 330 mm", "om_folio_210x330mm",
|
||||
{210000, 330000});
|
||||
VerifyPaper((*media_option)[7], "215 x 315 mm", "om_folio-sp_215x315mm",
|
||||
VerifyPaper((*media_option)[8], "215 x 315 mm", "om_folio-sp_215x315mm",
|
||||
{215000, 315000});
|
||||
VerifyPaper((*media_option)[8], "215 x 400 mm", "om_photo-21x40_215x400mm",
|
||||
{215000, 400000});
|
||||
VerifyPaper((*media_option)[9], "A4", "iso_a4_210x297mm", {210000, 297000});
|
||||
VerifyPaper((*media_option)[10], "Custom 1 (9 x 12.1 in)",
|
||||
"na_custom-1_9x12.1in", {228600, 307340});
|
||||
VerifyPaper((*media_option)[11], "Custom 2 (299.6 x 405.3 mm)",
|
||||
"na_custom-2_299.6x405.3mm", {299600, 405300});
|
||||
VerifyPaper((*media_option)[9], "215 x 400 mm",
|
||||
"om_215000x400000um_215x400mm", {215000, 400000});
|
||||
VerifyPaper((*media_option)[10], "300 x 405 mm",
|
||||
"om_299600x405300um_299x405mm", {299600, 405300});
|
||||
VerifyPaper((*media_option)[11], "A4", "iso_a4_210x297mm", {210000, 297000});
|
||||
VerifyPaper((*media_option)[12], "Letter", "na_letter_8.5x11in",
|
||||
{215900, 279400});
|
||||
VerifyPaper((*media_option)[13], "foo", "vendor", {200, 300});
|
||||
|
@ -19,13 +19,18 @@ constexpr char kIppLastDocument[] = "last-document"; // RFC 8011
|
||||
constexpr char kIppPin[] = "job-password"; // PWG 5100.11
|
||||
constexpr char kIppPinEncryption[] = "job-password-encryption"; // PWG 5100.11
|
||||
constexpr char kIppPrinterUri[] = "printer-uri"; // RFC 8011
|
||||
constexpr char kIppRequestedAttributes[] = "requested-attributes"; // RFC 8011
|
||||
constexpr char kIppRequestingUserName[] = "requesting-user-name"; // RFC 8011
|
||||
|
||||
// printer attributes
|
||||
constexpr char kIppMediaColDatabase[] = "media-col-database";
|
||||
|
||||
// job attributes
|
||||
constexpr char kIppCollate[] = "multiple-document-handling"; // PWG 5100.19
|
||||
constexpr char kIppCopies[] = CUPS_COPIES;
|
||||
constexpr char kIppColor[] = CUPS_PRINT_COLOR_MODE;
|
||||
constexpr char kIppMedia[] = CUPS_MEDIA;
|
||||
constexpr char kIppMediaCol[] = "media-col"; // PWG 5100.7
|
||||
constexpr char kIppDuplex[] = CUPS_SIDES;
|
||||
constexpr char kIppResolution[] = "printer-resolution"; // RFC 8011
|
||||
|
||||
@ -33,6 +38,16 @@ constexpr char kIppResolution[] = "printer-resolution"; // RFC 8011
|
||||
constexpr char kCollated[] = "separate-documents-collated-copies";
|
||||
constexpr char kUncollated[] = "separate-documents-uncollated-copies";
|
||||
|
||||
// media-col collection members (all from PWG 5100.7)
|
||||
constexpr char kIppMediaBottomMargin[] = "media-bottom-margin";
|
||||
constexpr char kIppMediaLeftMargin[] = "media-left-margin";
|
||||
constexpr char kIppMediaRightMargin[] = "media-right-margin";
|
||||
constexpr char kIppMediaSize[] = "media-size";
|
||||
constexpr char kIppMediaSource[] = "media-source";
|
||||
constexpr char kIppMediaTopMargin[] = "media-top-margin";
|
||||
constexpr char kIppXDimension[] = "x-dimension";
|
||||
constexpr char kIppYDimension[] = "y-dimension";
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
|
||||
constexpr char kIppDocumentAttributes[] =
|
||||
@ -44,6 +59,7 @@ constexpr char kPinEncryptionNone[] = "none";
|
||||
constexpr char kOptionFalse[] = "false";
|
||||
constexpr char kOptionTrue[] = "true";
|
||||
|
||||
// client-info
|
||||
constexpr char kIppClientInfo[] = "client-info";
|
||||
constexpr char kIppClientName[] = "client-name";
|
||||
constexpr char kIppClientPatches[] = "client-patches";
|
||||
|
@ -19,13 +19,18 @@ COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppLastDocument[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppPin[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppPinEncryption[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppPrinterUri[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppRequestedAttributes[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppRequestingUserName[];
|
||||
|
||||
// printer attributes
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaColDatabase[];
|
||||
|
||||
// job attributes
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppCollate[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppCopies[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppColor[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMedia[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaCol[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppDuplex[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppResolution[];
|
||||
|
||||
@ -33,6 +38,16 @@ COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppResolution[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kCollated[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kUncollated[];
|
||||
|
||||
// media-col collection members
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaBottomMargin[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaLeftMargin[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaRightMargin[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaSize[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaSource[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppMediaTopMargin[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppXDimension[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppYDimension[];
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppDocumentAttributes[];
|
||||
@ -43,6 +58,7 @@ COMPONENT_EXPORT(PRINT_BACKEND) extern const char kPinEncryptionNone[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kOptionFalse[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kOptionTrue[];
|
||||
|
||||
// client-info
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppClientInfo[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppClientName[];
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) extern const char kIppClientPatches[];
|
||||
|
@ -12,7 +12,9 @@
|
||||
|
||||
#include "base/containers/contains.h"
|
||||
#include "base/containers/fixed_flat_set.h"
|
||||
#include "base/containers/flat_map.h"
|
||||
#include "base/logging.h"
|
||||
#include "base/numerics/clamped_math.h"
|
||||
#include "base/strings/string_piece.h"
|
||||
#include "base/strings/string_util.h"
|
||||
#include "build/build_config.h"
|
||||
@ -244,23 +246,112 @@ void ExtractResolutions(const CupsOptionProvider& printer,
|
||||
}
|
||||
}
|
||||
|
||||
absl::optional<PrinterSemanticCapsAndDefaults::Paper>
|
||||
PaperFromMediaColDatabaseEntry(ipp_t* db_entry) {
|
||||
DCHECK(db_entry);
|
||||
|
||||
ipp_t* media_size = ippGetCollection(
|
||||
ippFindAttribute(db_entry, kIppMediaSize, IPP_TAG_BEGIN_COLLECTION), 0);
|
||||
ipp_attribute_t* width_attr =
|
||||
ippFindAttribute(media_size, kIppXDimension, IPP_TAG_INTEGER);
|
||||
ipp_attribute_t* height_attr =
|
||||
ippFindAttribute(media_size, kIppYDimension, IPP_TAG_INTEGER);
|
||||
|
||||
if (!width_attr || !height_attr) {
|
||||
// If x-dimension and y-dimension don't have IPP_TAG_INTEGER, they are
|
||||
// custom size ranges, so we want to skip this "size".
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
int width = ippGetInteger(width_attr, 0);
|
||||
int height = ippGetInteger(height_attr, 0);
|
||||
|
||||
ipp_attribute_t* bottom_attr =
|
||||
ippFindAttribute(db_entry, kIppMediaBottomMargin, IPP_TAG_INTEGER);
|
||||
ipp_attribute_t* left_attr =
|
||||
ippFindAttribute(db_entry, kIppMediaLeftMargin, IPP_TAG_INTEGER);
|
||||
ipp_attribute_t* right_attr =
|
||||
ippFindAttribute(db_entry, kIppMediaRightMargin, IPP_TAG_INTEGER);
|
||||
ipp_attribute_t* top_attr =
|
||||
ippFindAttribute(db_entry, kIppMediaTopMargin, IPP_TAG_INTEGER);
|
||||
DCHECK(bottom_attr);
|
||||
DCHECK(left_attr);
|
||||
DCHECK(right_attr);
|
||||
DCHECK(top_attr);
|
||||
int bottom_margin = ippGetInteger(bottom_attr, 0);
|
||||
int left_margin = ippGetInteger(left_attr, 0);
|
||||
int right_margin = ippGetInteger(right_attr, 0);
|
||||
int top_margin = ippGetInteger(top_attr, 0);
|
||||
|
||||
if (width <= 0 || height <= 0 || bottom_margin < 0 || top_margin < 0 ||
|
||||
left_margin < 0 || right_margin < 0 ||
|
||||
width <= base::ClampedNumeric<int>(left_margin) + right_margin ||
|
||||
height <= base::ClampedNumeric<int>(bottom_margin) + top_margin) {
|
||||
LOG(WARNING) << "Invalid media-col-database entry:"
|
||||
<< " x-dimension=" << width << " y-dimension=" << height
|
||||
<< " media-bottom-margin=" << bottom_margin
|
||||
<< " media-left-margin=" << left_margin
|
||||
<< " media-right-margin=" << right_margin
|
||||
<< " media-top-margin=" << top_margin;
|
||||
return absl::nullopt;
|
||||
}
|
||||
|
||||
PrinterSemanticCapsAndDefaults::Paper paper;
|
||||
paper.size_um =
|
||||
gfx::Size(width * kMicronsPerPwgUnit, height * kMicronsPerPwgUnit);
|
||||
paper.printable_area_um = PrintableAreaFromSizeAndPwgMargins(
|
||||
paper.size_um, bottom_margin, left_margin, right_margin, top_margin);
|
||||
|
||||
return paper;
|
||||
}
|
||||
|
||||
bool PaperIsBorderless(const PrinterSemanticCapsAndDefaults::Paper& paper) {
|
||||
return paper.printable_area_um.x() == 0 && paper.printable_area_um.y() == 0 &&
|
||||
paper.printable_area_um.width() == paper.size_um.width() &&
|
||||
paper.printable_area_um.height() == paper.size_um.height();
|
||||
}
|
||||
|
||||
PrinterSemanticCapsAndDefaults::Papers SupportedPapers(
|
||||
const CupsPrinter& printer) {
|
||||
std::vector<base::StringPiece> papers =
|
||||
printer.GetSupportedOptionValueStrings(kIppMedia);
|
||||
PrinterSemanticCapsAndDefaults::Papers parsed_papers;
|
||||
parsed_papers.reserve(papers.size());
|
||||
for (base::StringPiece paper : papers) {
|
||||
PrinterSemanticCapsAndDefaults::Paper parsed =
|
||||
ParsePaper(paper, printer.GetMediaMarginsByName(std::string(paper)));
|
||||
// If a paper fails to parse reasonably, we should avoid propagating
|
||||
// it - e.g. CUPS is known to give out empty vendor IDs at times:
|
||||
// https://crbug.com/920295#c23
|
||||
if (!parsed.display_name.empty()) {
|
||||
parsed_papers.push_back(parsed);
|
||||
auto size_compare = [](const gfx::Size& a, const gfx::Size& b) {
|
||||
auto result = a.width() - b.width();
|
||||
if (result == 0) {
|
||||
result = a.height() - b.height();
|
||||
}
|
||||
return result < 0;
|
||||
};
|
||||
std::map<gfx::Size, PrinterSemanticCapsAndDefaults::Paper,
|
||||
decltype(size_compare)>
|
||||
paper_map;
|
||||
|
||||
ipp_attribute_t* attr = printer.GetMediaColDatabase();
|
||||
int count = ippGetCount(attr);
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
ipp_t* db_entry = ippGetCollection(attr, i);
|
||||
|
||||
absl::optional<PrinterSemanticCapsAndDefaults::Paper> paper_opt =
|
||||
PaperFromMediaColDatabaseEntry(db_entry);
|
||||
if (!paper_opt.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& paper = paper_opt.value();
|
||||
if (auto existing_entry = paper_map.find(paper.size_um);
|
||||
existing_entry != paper_map.end()) {
|
||||
// Prefer non-borderless versions of paper sizes.
|
||||
if (PaperIsBorderless(existing_entry->second)) {
|
||||
existing_entry->second = paper;
|
||||
}
|
||||
} else {
|
||||
paper_map.emplace(paper.size_um, paper);
|
||||
}
|
||||
}
|
||||
|
||||
PrinterSemanticCapsAndDefaults::Papers parsed_papers;
|
||||
for (const auto& entry : paper_map) {
|
||||
parsed_papers.push_back(entry.second);
|
||||
}
|
||||
return parsed_papers;
|
||||
}
|
||||
|
||||
@ -340,10 +431,6 @@ size_t AddAttributes(const CupsOptionProvider& printer,
|
||||
size_t AddInputTray(const CupsOptionProvider& printer,
|
||||
AdvancedCapabilities* caps) {
|
||||
size_t previous_size = caps->size();
|
||||
// b/151324273: CUPS doesn't implement media-source in media-col-database like
|
||||
// it should according to the IPP specs. However, it does implement a naked
|
||||
// media-source attribute which we can use until the proper changes can be
|
||||
// made to media-col-database.
|
||||
KeywordHandler(printer, "media-source", caps);
|
||||
return caps->size() - previous_size;
|
||||
}
|
||||
@ -361,15 +448,17 @@ void ExtractAdvancedCapabilities(const CupsOptionProvider& printer,
|
||||
} // namespace
|
||||
|
||||
PrinterSemanticCapsAndDefaults::Paper DefaultPaper(const CupsPrinter& printer) {
|
||||
ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppMedia);
|
||||
ipp_attribute_t* attr = printer.GetDefaultOptionValue(kIppMediaCol);
|
||||
if (!attr)
|
||||
return PrinterSemanticCapsAndDefaults::Paper();
|
||||
const char* const media_name = ippGetString(attr, 0, nullptr);
|
||||
if (!media_name) {
|
||||
ipp_t* media_col_default = ippGetCollection(attr, 0);
|
||||
if (!media_col_default) {
|
||||
return PrinterSemanticCapsAndDefaults::Paper();
|
||||
}
|
||||
|
||||
return ParsePaper(media_name, printer.GetMediaMarginsByName(media_name));
|
||||
PrinterSemanticCapsAndDefaults::Paper paper;
|
||||
return PaperFromMediaColDatabaseEntry(media_col_default)
|
||||
.value_or(PrinterSemanticCapsAndDefaults::Paper());
|
||||
}
|
||||
|
||||
void CapsAndDefaultsFromPrinter(const CupsPrinter& printer,
|
||||
@ -393,6 +482,37 @@ void CapsAndDefaultsFromPrinter(const CupsPrinter& printer,
|
||||
ExtractResolutions(printer, printer_info);
|
||||
}
|
||||
|
||||
gfx::Rect GetPrintableAreaForSize(const CupsPrinter& printer,
|
||||
const gfx::Size& size_um) {
|
||||
ipp_attribute_t* attr = printer.GetMediaColDatabase();
|
||||
int count = ippGetCount(attr);
|
||||
gfx::Rect result(0, 0, size_um.width(), size_um.height());
|
||||
|
||||
for (int i = 0; i < count; i++) {
|
||||
ipp_t* db_entry = ippGetCollection(attr, i);
|
||||
|
||||
absl::optional<PrinterSemanticCapsAndDefaults::Paper> paper_opt =
|
||||
PaperFromMediaColDatabaseEntry(db_entry);
|
||||
if (!paper_opt.has_value()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto& paper = paper_opt.value();
|
||||
if (paper.size_um != size_um) {
|
||||
continue;
|
||||
}
|
||||
|
||||
result = paper.printable_area_um;
|
||||
|
||||
// If this is a borderless size, try to find a non-borderless version.
|
||||
if (!PaperIsBorderless(paper)) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
ScopedIppPtr WrapIpp(ipp_t* ipp) {
|
||||
return ScopedIppPtr(ipp, &ippDelete);
|
||||
}
|
||||
|
@ -31,6 +31,11 @@ COMPONENT_EXPORT(PRINT_BACKEND)
|
||||
void CapsAndDefaultsFromPrinter(const CupsPrinter& printer,
|
||||
PrinterSemanticCapsAndDefaults* printer_info);
|
||||
|
||||
// Gets the printer margins for the provided paper size.
|
||||
COMPONENT_EXPORT(PRINT_BACKEND)
|
||||
gfx::Rect GetPrintableAreaForSize(const CupsPrinter& printer,
|
||||
const gfx::Size& size_um);
|
||||
|
||||
// Wraps `ipp` in unique_ptr with appropriate deleter
|
||||
COMPONENT_EXPORT(PRINT_BACKEND) ScopedIppPtr WrapIpp(ipp_t* ipp);
|
||||
|
||||
|
@ -35,13 +35,6 @@ class MockCupsPrinterWithMarginsAndAttributes : public MockCupsPrinter {
|
||||
MockCupsPrinterWithMarginsAndAttributes() = default;
|
||||
~MockCupsPrinterWithMarginsAndAttributes() override = default;
|
||||
|
||||
// CupsPrinter:
|
||||
CupsMediaMargins GetMediaMarginsByName(
|
||||
const std::string& media_id) const override {
|
||||
const auto margins = margins_.find(media_id);
|
||||
return margins != margins_.end() ? margins->second : CupsMediaMargins();
|
||||
}
|
||||
|
||||
// CupsOptionProvider:
|
||||
ipp_attribute_t* GetSupportedOptionValues(
|
||||
const char* option_name) const override {
|
||||
@ -77,6 +70,11 @@ class MockCupsPrinterWithMarginsAndAttributes : public MockCupsPrinter {
|
||||
return attr != default_attributes_.end() ? attr->second : nullptr;
|
||||
}
|
||||
|
||||
// CupsOptionProvider:
|
||||
ipp_attribute_t* GetMediaColDatabase() const override {
|
||||
return media_col_database_;
|
||||
}
|
||||
|
||||
// CupsOptionProvider:
|
||||
bool CheckOptionSupported(const char* name,
|
||||
const char* value) const override {
|
||||
@ -84,11 +82,6 @@ class MockCupsPrinterWithMarginsAndAttributes : public MockCupsPrinter {
|
||||
return false;
|
||||
}
|
||||
|
||||
void SetMediaMarginsByName(base::StringPiece media_id,
|
||||
const CupsMediaMargins& margins) {
|
||||
margins_[media_id] = margins;
|
||||
}
|
||||
|
||||
void SetSupportedOptions(base::StringPiece name, ipp_attribute_t* attribute) {
|
||||
supported_attributes_[name] = attribute;
|
||||
}
|
||||
@ -97,10 +90,14 @@ class MockCupsPrinterWithMarginsAndAttributes : public MockCupsPrinter {
|
||||
default_attributes_[name] = attribute;
|
||||
}
|
||||
|
||||
void SetMediaColDatabase(ipp_attribute_t* attribute) {
|
||||
media_col_database_ = attribute;
|
||||
}
|
||||
|
||||
private:
|
||||
std::map<base::StringPiece, ipp_attribute_t*> supported_attributes_;
|
||||
std::map<base::StringPiece, ipp_attribute_t*> default_attributes_;
|
||||
std::map<base::StringPiece, CupsMediaMargins> margins_;
|
||||
ipp_attribute_t* media_col_database_;
|
||||
};
|
||||
|
||||
class PrintBackendCupsIppHelperTest : public ::testing::Test {
|
||||
@ -145,12 +142,83 @@ ipp_attribute_t* MakeStringCollection(ipp_t* ipp,
|
||||
strings.size(), nullptr, strings.data());
|
||||
}
|
||||
|
||||
struct media_info {
|
||||
int width;
|
||||
int height;
|
||||
int bottom_margin;
|
||||
int left_margin;
|
||||
int right_margin;
|
||||
int top_margin;
|
||||
std::map<const char*, const char*> keyword_attrs;
|
||||
bool is_range;
|
||||
int width_max;
|
||||
int height_max;
|
||||
};
|
||||
|
||||
ScopedIppPtr MakeMediaCol(const media_info& info) {
|
||||
ScopedIppPtr media_col = WrapIpp(ippNew());
|
||||
ScopedIppPtr media_size = WrapIpp(ippNew());
|
||||
|
||||
if (info.is_range) {
|
||||
ippAddRange(media_size.get(), IPP_TAG_ZERO, "x-dimension", info.width,
|
||||
info.width_max);
|
||||
ippAddRange(media_size.get(), IPP_TAG_ZERO, "y-dimension", info.height,
|
||||
info.height_max);
|
||||
} else {
|
||||
ippAddInteger(media_size.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
"x-dimension", info.width);
|
||||
ippAddInteger(media_size.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
"y-dimension", info.height);
|
||||
}
|
||||
|
||||
ippAddCollection(media_col.get(), IPP_TAG_ZERO, "media-size",
|
||||
media_size.get());
|
||||
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
"media-bottom-margin", info.bottom_margin);
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
"media-left-margin", info.left_margin);
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
"media-right-margin", info.right_margin);
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
"media-top-margin", info.top_margin);
|
||||
|
||||
for (auto& it : info.keyword_attrs) {
|
||||
ippAddString(media_col.get(), IPP_TAG_ZERO, IPP_TAG_KEYWORD, it.first,
|
||||
nullptr, it.second);
|
||||
}
|
||||
|
||||
return media_col;
|
||||
}
|
||||
|
||||
ipp_attribute_t* MakeMediaColDefault(ipp_t* ipp, const media_info& info) {
|
||||
ScopedIppPtr media_col = MakeMediaCol(info);
|
||||
return ippAddCollection(ipp, IPP_TAG_ZERO, "TEST_DATA", media_col.get());
|
||||
}
|
||||
|
||||
ipp_attribute_t* MakeMediaColDatabase(ipp_t* ipp,
|
||||
const std::vector<media_info>& media) {
|
||||
std::vector<ScopedIppPtr> collections;
|
||||
std::vector<const ipp_t*> raw_collections;
|
||||
|
||||
for (auto info : media) {
|
||||
ScopedIppPtr entry = MakeMediaCol(info);
|
||||
raw_collections.emplace_back(entry.get());
|
||||
collections.emplace_back(std::move(entry));
|
||||
}
|
||||
|
||||
return ippAddCollections(ipp, IPP_TAG_PRINTER, "TEST_DATA",
|
||||
raw_collections.size(), raw_collections.data());
|
||||
}
|
||||
|
||||
TEST_F(PrintBackendCupsIppHelperTest, DefaultPaper) {
|
||||
const CupsPrinter::CupsMediaMargins kMargins = {10, 10, 10, 10};
|
||||
EXPECT_EQ(ParsePaper("", kMargins), DefaultPaper(*printer_));
|
||||
printer_->SetOptionDefault("media", MakeString(ipp_, "iso_a4_210x297mm"));
|
||||
printer_->SetMediaMarginsByName("iso_a4_210x297mm", kMargins);
|
||||
EXPECT_EQ(ParsePaper("iso_a4_210x297mm", kMargins), DefaultPaper(*printer_));
|
||||
EXPECT_EQ(PrinterSemanticCapsAndDefaults::Paper(), DefaultPaper(*printer_));
|
||||
printer_->SetOptionDefault(
|
||||
"media-col",
|
||||
MakeMediaColDefault(ipp_, {21000, 29700, 10, 10, 10, 10, {}}));
|
||||
PrinterSemanticCapsAndDefaults::Paper default_paper = DefaultPaper(*printer_);
|
||||
EXPECT_EQ(default_paper.size_um.width(), 210000);
|
||||
EXPECT_EQ(default_paper.size_um.height(), 297000);
|
||||
}
|
||||
|
||||
TEST_F(PrintBackendCupsIppHelperTest, CopiesCapable) {
|
||||
@ -224,42 +292,47 @@ TEST_F(PrintBackendCupsIppHelperTest, DuplexNotSupported) {
|
||||
}
|
||||
|
||||
TEST_F(PrintBackendCupsIppHelperTest, A4PaperSupported) {
|
||||
printer_->SetSupportedOptions(
|
||||
"media", MakeStringCollection(ipp_, {"iso_a4_210x297mm"}));
|
||||
printer_->SetMediaColDatabase(
|
||||
MakeMediaColDatabase(ipp_, {{21000, 29700, 10, 10, 10, 10, {}}}));
|
||||
|
||||
PrinterSemanticCapsAndDefaults caps;
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
|
||||
PrinterSemanticCapsAndDefaults::Paper paper = caps.papers[0];
|
||||
// media display name localization is handled more fully in
|
||||
// AssemblePrinterSettings().
|
||||
EXPECT_EQ("iso a4", paper.display_name);
|
||||
EXPECT_EQ("iso_a4_210x297mm", paper.vendor_id);
|
||||
EXPECT_EQ(210000, paper.size_um.width());
|
||||
EXPECT_EQ(297000, paper.size_um.height());
|
||||
}
|
||||
|
||||
TEST_F(PrintBackendCupsIppHelperTest, LegalPaperDefault) {
|
||||
printer_->SetOptionDefault("media", MakeString(ipp_, "na_legal_8.5x14in"));
|
||||
// na_legal_8.5x14in
|
||||
printer_->SetOptionDefault(
|
||||
"media-col",
|
||||
MakeMediaColDefault(ipp_, {21590, 35560, 10, 10, 10, 10, {}}));
|
||||
|
||||
PrinterSemanticCapsAndDefaults caps;
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
// media display name localization is handled more fully in
|
||||
// AssemblePrinterSettings().
|
||||
EXPECT_EQ("na legal", caps.default_paper.display_name);
|
||||
EXPECT_EQ("na_legal_8.5x14in", caps.default_paper.vendor_id);
|
||||
EXPECT_EQ(215900, caps.default_paper.size_um.width());
|
||||
EXPECT_EQ(355600, caps.default_paper.size_um.height());
|
||||
}
|
||||
|
||||
// Tests that CapsAndDefaultsFromPrinter() does not propagate papers
|
||||
// with badly formatted vendor IDs - such papers will not transform into
|
||||
// meaningful ParsedPaper instances and are sometimes inimical to
|
||||
// ARC++.
|
||||
TEST_F(PrintBackendCupsIppHelperTest, OmitPapersWithoutVendorIds) {
|
||||
printer_->SetSupportedOptions(
|
||||
"media", MakeStringCollection(ipp_, {"jis_b5_182x257mm", "invalidsize",
|
||||
"", "iso_b5_176x250mm"}));
|
||||
// Tests that CapsAndDefaultsFromPrinter() does not propagate papers with
|
||||
// invalid sizes or margins to the Chromium print backend.
|
||||
TEST_F(PrintBackendCupsIppHelperTest, OmitPapersWithInvalidSizes) {
|
||||
printer_->SetMediaColDatabase(
|
||||
MakeMediaColDatabase(ipp_, {
|
||||
{18200, 25700, 100, 100, 100, 100, {}},
|
||||
{0, 29700, 100, 100, 100, 100, {}},
|
||||
{-1, 29700, 100, 100, 100, 100, {}},
|
||||
{21000, 0, 100, 100, 100, 100, {}},
|
||||
{21000, -1, 100, 100, 100, 100, {}},
|
||||
{21000, 29700, -1, 100, 100, 100, {}},
|
||||
{21000, 29700, 100, -1, 100, 100, {}},
|
||||
{21000, 29700, 100, 100, -1, 100, {}},
|
||||
{21000, 29700, 100, 100, 100, -1, {}},
|
||||
{21000, 29700, 100, 10500, 10500, 100, {}},
|
||||
{21000, 29700, 14850, 100, 100, 14850, {}},
|
||||
{17600, 25000, 100, 100, 100, 100, {}},
|
||||
}));
|
||||
|
||||
PrinterSemanticCapsAndDefaults caps;
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
@ -269,54 +342,179 @@ TEST_F(PrintBackendCupsIppHelperTest, OmitPapersWithoutVendorIds) {
|
||||
// preceding call to CapsAndDefaultsFromPrinter() will have dropped
|
||||
// these invalid sizes.
|
||||
ASSERT_EQ(2U, caps.papers.size());
|
||||
|
||||
// While not directly pertinent to this test, we expect a certain
|
||||
// format for the other supported papers.
|
||||
EXPECT_THAT(
|
||||
caps.papers,
|
||||
testing::UnorderedElementsAre(
|
||||
testing::Field(&PrinterSemanticCapsAndDefaults::Paper::display_name,
|
||||
"jis b5"),
|
||||
testing::Field(&PrinterSemanticCapsAndDefaults::Paper::display_name,
|
||||
"iso b5")));
|
||||
for (const auto& paper : caps.papers) {
|
||||
EXPECT_NE(21000, paper.size_um.width());
|
||||
EXPECT_NE(29700, paper.size_um.height());
|
||||
}
|
||||
}
|
||||
|
||||
// Tests that CapsAndDefaultsFromPrinter() does not propagate the
|
||||
// special IPP values that CUPS happens to expose to the Chromium print
|
||||
// backend.
|
||||
TEST_F(PrintBackendCupsIppHelperTest, OmitPapersWithSpecialVendorIds) {
|
||||
// Maintainer's note: there's no reason why a printer would deliver
|
||||
// two discrete sizes for custom_min* and custom_max*; in practice,
|
||||
// we always see the fully qualified custom_m(in|ax)_<DIMENSIONS>
|
||||
// delivered to the Chromium print backend.
|
||||
printer_->SetSupportedOptions(
|
||||
"media",
|
||||
MakeStringCollection(
|
||||
ipp_, {"na_number-11_4.5x10.375in", "custom_max", "custom_min_0x0in",
|
||||
"na_govt-letter_8x10in", "custom_min",
|
||||
"custom_max_1000x1000in", "iso_b0_1000x1414mm"}));
|
||||
// Tests that CapsAndDefaultsFromPrinter() does not propagate custom size ranges
|
||||
// from the media-col-database to the Chromium print backend.
|
||||
TEST_F(PrintBackendCupsIppHelperTest, OmitPapersWithSizeRanges) {
|
||||
printer_->SetMediaColDatabase(MakeMediaColDatabase(
|
||||
ipp_, {
|
||||
{11430, 26352, 100, 100, 100, 100, {}},
|
||||
{0, 0, 100, 100, 100, 100, {}, true, 2540000, 2540000},
|
||||
{20320, 25400, 100, 100, 100, 100, {}},
|
||||
{100000, 141400, 100, 100, 100, 100, {}},
|
||||
}));
|
||||
|
||||
PrinterSemanticCapsAndDefaults caps;
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
|
||||
// The printer reports that it supports seven media sizes, four of
|
||||
// which are not meant for users' eyes (``custom_min*'' and
|
||||
// ``custom_max*''). The preceding call to
|
||||
// CapsAndDefaultsFromPrinter() will have dropped these sizes,
|
||||
// refusing to propagate them out of the backend.
|
||||
// The printer reports that it supports four media sizes, one of which is not
|
||||
// meant for users' eyes (the size range). The preceding call to
|
||||
// CapsAndDefaultsFromPrinter() will have dropped these sizes, refusing to
|
||||
// propagate them out of the backend.
|
||||
ASSERT_EQ(3U, caps.papers.size());
|
||||
}
|
||||
|
||||
// While not directly pertinent to this test, we expect a certain
|
||||
// format for the other supported papers.
|
||||
EXPECT_THAT(
|
||||
caps.papers,
|
||||
testing::UnorderedElementsAre(
|
||||
testing::Field(&PrinterSemanticCapsAndDefaults::Paper::display_name,
|
||||
"na number-11"),
|
||||
testing::Field(&PrinterSemanticCapsAndDefaults::Paper::display_name,
|
||||
"na govt-letter"),
|
||||
testing::Field(&PrinterSemanticCapsAndDefaults::Paper::display_name,
|
||||
"iso b0")));
|
||||
// Tests that when the media-col-database contains both bordered and borderless
|
||||
// versions of a size, CapsAndDefaultsFromPrinter() takes the bordered version
|
||||
// and drops the borderless version.
|
||||
TEST_F(PrintBackendCupsIppHelperTest, PreferBorderedSizes) {
|
||||
PrinterSemanticCapsAndDefaults caps;
|
||||
|
||||
printer_->SetMediaColDatabase(
|
||||
MakeMediaColDatabase(ipp_, {
|
||||
{21000, 29700, 100, 100, 100, 100, {}},
|
||||
{21000, 29700, 0, 0, 0, 0, {}},
|
||||
}));
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
ASSERT_EQ(1U, caps.papers.size());
|
||||
EXPECT_NE(gfx::Rect(0, 0, 210000, 297000), caps.papers[0].printable_area_um);
|
||||
|
||||
printer_->SetMediaColDatabase(
|
||||
MakeMediaColDatabase(ipp_, {
|
||||
{21000, 29700, 0, 0, 0, 0, {}},
|
||||
{21000, 29700, 100, 100, 100, 100, {}},
|
||||
}));
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
ASSERT_EQ(1U, caps.papers.size());
|
||||
EXPECT_NE(gfx::Rect(0, 0, 210000, 297000), caps.papers[0].printable_area_um);
|
||||
|
||||
// If the only available version of a size is borderless, go ahead and use it.
|
||||
// Not sure if any actual printers do this, but it's allowed by the IPP spec.
|
||||
printer_->SetMediaColDatabase(
|
||||
MakeMediaColDatabase(ipp_, {
|
||||
{21000, 29700, 0, 0, 0, 0, {}},
|
||||
}));
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
ASSERT_EQ(1U, caps.papers.size());
|
||||
EXPECT_EQ(gfx::Rect(0, 0, 210000, 297000), caps.papers[0].printable_area_um);
|
||||
}
|
||||
|
||||
// At the time of this writing, there are no media-source or media-type
|
||||
// attributes in the media-col-database that cupsd gives us. However, according
|
||||
// to the IPP spec, each paper size *should* have a separate variant for each
|
||||
// supported combination of size and type. So make sure behavior doesn't change
|
||||
// and we don't create duplicate paper sizes when/if CUPS improves in the
|
||||
// future.
|
||||
TEST_F(PrintBackendCupsIppHelperTest, NoDuplicateSizes) {
|
||||
printer_->SetMediaColDatabase(MakeMediaColDatabase(
|
||||
ipp_,
|
||||
{
|
||||
{21000,
|
||||
29700,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
{{"media-type", "stationery"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
{{"media-type", "stationery"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
500,
|
||||
500,
|
||||
500,
|
||||
500,
|
||||
{{"media-type", "stationery"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
{{"media-type", "photographic"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{{"media-type", "photographic"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
{{"media-type", "photographic-high-gloss"},
|
||||
{"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{{"media-type", "photographic-high-gloss"},
|
||||
{"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
{{"media-type", "photographic-glossy"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{{"media-type", "photographic-glossy"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
{{"media-type", "photographic-semi-gloss"},
|
||||
{"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{{"media-type", "photographic-semi-gloss"},
|
||||
{"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
300,
|
||||
{{"media-type", "photographic-matte"}, {"media-source", "main"}}},
|
||||
{21000,
|
||||
29700,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
{{"media-type", "photographic-matte"}, {"media-source", "main"}}},
|
||||
}));
|
||||
|
||||
PrinterSemanticCapsAndDefaults caps;
|
||||
CapsAndDefaultsFromPrinter(*printer_, &caps);
|
||||
|
||||
ASSERT_EQ(1U, caps.papers.size());
|
||||
}
|
||||
|
||||
#if BUILDFLAG(IS_CHROMEOS)
|
||||
|
@ -26,7 +26,9 @@ namespace printing {
|
||||
class CupsPrinterImpl : public CupsPrinter {
|
||||
public:
|
||||
CupsPrinterImpl(http_t* http, ScopedDestination dest)
|
||||
: cups_http_(http), destination_(std::move(dest)) {
|
||||
: cups_http_(http),
|
||||
destination_(std::move(dest)),
|
||||
printer_attributes_(WrapIpp(nullptr)) {
|
||||
DCHECK(cups_http_);
|
||||
DCHECK(destination_);
|
||||
|
||||
@ -117,6 +119,16 @@ class CupsPrinterImpl : public CupsPrinter {
|
||||
return supported == 1;
|
||||
}
|
||||
|
||||
// CupsOptionProvider
|
||||
ipp_attribute_t* GetMediaColDatabase() const override {
|
||||
if (!EnsurePrinterAttributes()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return ippFindAttribute(printer_attributes_.get(), kIppMediaColDatabase,
|
||||
IPP_TAG_BEGIN_COLLECTION);
|
||||
}
|
||||
|
||||
bool ToPrinterInfo(PrinterBasicInfo* printer_info) const override {
|
||||
const cups_dest_t* printer = destination_.get();
|
||||
|
||||
@ -275,22 +287,37 @@ class CupsPrinterImpl : public CupsPrinter {
|
||||
return status == IPP_STATUS_OK;
|
||||
}
|
||||
|
||||
CupsMediaMargins GetMediaMarginsByName(
|
||||
const std::string& media_id) const override {
|
||||
cups_size_t cups_media;
|
||||
if (!EnsureDestInfo() ||
|
||||
!cupsGetDestMediaByName(cups_http_, destination_.get(),
|
||||
dest_info_.get(), media_id.c_str(),
|
||||
CUPS_MEDIA_FLAGS_DEFAULT, &cups_media)) {
|
||||
return {0, 0, 0, 0};
|
||||
private:
|
||||
// Sends the request to populate `printer_attributes_` if it's not already
|
||||
// populated.
|
||||
bool EnsurePrinterAttributes() const {
|
||||
if (printer_attributes_) {
|
||||
return true;
|
||||
}
|
||||
return {cups_media.bottom, cups_media.left, cups_media.right,
|
||||
cups_media.top};
|
||||
|
||||
ScopedIppPtr request = CreateRequest(IPP_OP_GET_PRINTER_ATTRIBUTES, "");
|
||||
// The requested attributes can be changed to "all","media-col-database" if
|
||||
// we want to directly query printer attributes other than
|
||||
// media-col-database in the future.
|
||||
constexpr const char* kRequestedAttributes[] = {kIppMediaColDatabase};
|
||||
ippAddStrings(request.get(), IPP_TAG_OPERATION, IPP_TAG_KEYWORD,
|
||||
kIppRequestedAttributes, std::size(kRequestedAttributes),
|
||||
nullptr, kRequestedAttributes);
|
||||
|
||||
// cupsDoRequest() takes ownership of the request and frees it for us.
|
||||
printer_attributes_.reset(
|
||||
cupsDoRequest(cups_http_, request.release(), resource_path_.c_str()));
|
||||
|
||||
if (ippGetStatusCode(printer_attributes_.get()) != IPP_STATUS_OK) {
|
||||
printer_attributes_.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
// internal helper function to initialize an IPP request
|
||||
ScopedIppPtr CreateRequest(ipp_op_t op, const std::string& username) {
|
||||
ScopedIppPtr CreateRequest(ipp_op_t op, const std::string& username) const {
|
||||
const char* c_username = username.empty() ? cupsUser() : username.c_str();
|
||||
|
||||
ipp_t* request = ippNewRequest(op);
|
||||
@ -303,7 +330,9 @@ class CupsPrinterImpl : public CupsPrinter {
|
||||
}
|
||||
|
||||
// internal helper function to copy attributes to an IPP request
|
||||
void CopyAttributeGroup(ipp_t* request, ipp_t* attributes, ipp_tag_t group) {
|
||||
void CopyAttributeGroup(ipp_t* request,
|
||||
ipp_t* attributes,
|
||||
ipp_tag_t group) const {
|
||||
for (ipp_attribute_t* attr = ippFirstAttribute(attributes); attr;
|
||||
attr = ippNextAttribute(attributes)) {
|
||||
if (ippGetGroupTag(attr) == group) {
|
||||
@ -326,6 +355,9 @@ class CupsPrinterImpl : public CupsPrinter {
|
||||
|
||||
// resource path used to connect to this printer
|
||||
std::string resource_path_;
|
||||
|
||||
// printer attributes that describe the supported options
|
||||
mutable ScopedIppPtr printer_attributes_;
|
||||
};
|
||||
|
||||
std::unique_ptr<CupsPrinter> CupsPrinter::Create(http_t* http,
|
||||
|
@ -42,6 +42,10 @@ class COMPONENT_EXPORT(PRINT_BACKEND) CupsOptionProvider {
|
||||
// Returns true if the `value` is supported by option `name`.
|
||||
virtual bool CheckOptionSupported(const char* name,
|
||||
const char* value) const = 0;
|
||||
|
||||
// Returns the IPP "media-col-database" attribute for this printer.
|
||||
// ipp_attribute_t* is owned by CupsOptionProvider.
|
||||
virtual ipp_attribute_t* GetMediaColDatabase() const = 0;
|
||||
};
|
||||
|
||||
// Represents a CUPS printer.
|
||||
@ -50,18 +54,6 @@ class COMPONENT_EXPORT(PRINT_BACKEND) CupsOptionProvider {
|
||||
// share an http connection which the CupsConnection closes on destruction.
|
||||
class COMPONENT_EXPORT(PRINT_BACKEND) CupsPrinter : public CupsOptionProvider {
|
||||
public:
|
||||
// Represents the margins that CUPS reports for some given media.
|
||||
// Its members are valued in PWG units (100ths of mm).
|
||||
// This struct approximates a cups_size_t, which is BLRT.
|
||||
// `bottom`, `left`, `right`, and `top` express inward encroachment by
|
||||
// margins, away from the edges of the paper.
|
||||
struct CupsMediaMargins {
|
||||
int bottom;
|
||||
int left;
|
||||
int right;
|
||||
int top;
|
||||
};
|
||||
|
||||
~CupsPrinter() override = default;
|
||||
|
||||
// Create a printer with a connection defined by `http` and `dest`.
|
||||
@ -124,16 +116,6 @@ class COMPONENT_EXPORT(PRINT_BACKEND) CupsPrinter : public CupsOptionProvider {
|
||||
// Cancel the print job `job_id`. Returns true if the operation succeeded.
|
||||
// Returns false if it failed for any reason.
|
||||
virtual bool CancelJob(int job_id) = 0;
|
||||
|
||||
// Queries CUPS for the margins of the media named by `media_id`.
|
||||
//
|
||||
// A `media_id` is any vendor ID known to CUPS for a given printer.
|
||||
// Vendor IDs are exemplified by the keys of the big map in
|
||||
// print_media_l10n.cc.
|
||||
//
|
||||
// Returns all zeroes if the CUPS API call fails.
|
||||
virtual CupsMediaMargins GetMediaMarginsByName(
|
||||
const std::string& media_id) const = 0;
|
||||
};
|
||||
|
||||
} // namespace printing
|
||||
|
@ -38,13 +38,12 @@ class MockCupsPrinter : public CupsPrinter {
|
||||
MOCK_METHOD0(FinishDocument, bool());
|
||||
MOCK_METHOD2(CloseJob, ipp_status_t(int job_id, const std::string& username));
|
||||
MOCK_METHOD1(CancelJob, bool(int job_id));
|
||||
MOCK_CONST_METHOD1(GetMediaMarginsByName,
|
||||
CupsMediaMargins(const std::string& media_id));
|
||||
|
||||
MOCK_CONST_METHOD1(GetSupportedOptionValues,
|
||||
ipp_attribute_t*(const char* option_name));
|
||||
MOCK_CONST_METHOD1(GetSupportedOptionValueStrings,
|
||||
std::vector<base::StringPiece>(const char* option_name));
|
||||
MOCK_CONST_METHOD0(GetMediaColDatabase, ipp_attribute_t*());
|
||||
MOCK_CONST_METHOD1(GetDefaultOptionValue,
|
||||
ipp_attribute_t*(const char* option_name));
|
||||
MOCK_CONST_METHOD2(CheckOptionSupported,
|
||||
|
@ -106,52 +106,49 @@ gfx::Size ParsePaperSize(base::StringPiece value) {
|
||||
}
|
||||
|
||||
#if BUILDFLAG(USE_CUPS)
|
||||
PrinterSemanticCapsAndDefaults::Paper ParsePaper(
|
||||
base::StringPiece value,
|
||||
const CupsPrinter::CupsMediaMargins& margins) {
|
||||
std::vector<base::StringPiece> pieces = GetStringPiecesIfValid(value);
|
||||
if (pieces.empty()) {
|
||||
return PrinterSemanticCapsAndDefaults::Paper();
|
||||
}
|
||||
|
||||
base::StringPiece dimensions = pieces.back();
|
||||
|
||||
PrinterSemanticCapsAndDefaults::Paper paper;
|
||||
paper.vendor_id = std::string(value);
|
||||
paper.size_um = DimensionsToMicrons(dimensions);
|
||||
if (paper.size_um.IsEmpty()) {
|
||||
return PrinterSemanticCapsAndDefaults::Paper();
|
||||
}
|
||||
|
||||
gfx::Rect PrintableAreaFromSizeAndPwgMargins(const gfx::Size& size_um,
|
||||
int bottom_pwg,
|
||||
int left_pwg,
|
||||
int right_pwg,
|
||||
int top_pwg) {
|
||||
// The margins of the printable area are expressed in PWG units (100ths of
|
||||
// mm).
|
||||
int printable_area_left_um = margins.left * kMicronsPerPwgUnit;
|
||||
int printable_area_bottom_um = margins.bottom * kMicronsPerPwgUnit;
|
||||
// mm) in the IPP 'media-col-database' attribute.
|
||||
int printable_area_left_um = left_pwg * kMicronsPerPwgUnit;
|
||||
int printable_area_bottom_um = bottom_pwg * kMicronsPerPwgUnit;
|
||||
int printable_area_width_um =
|
||||
paper.size_um.width() -
|
||||
((margins.left + margins.right) * kMicronsPerPwgUnit);
|
||||
int printable_area_length_um =
|
||||
paper.size_um.height() -
|
||||
((margins.top + margins.bottom) * kMicronsPerPwgUnit);
|
||||
paper.printable_area_um =
|
||||
gfx::Rect(printable_area_left_um, printable_area_bottom_um,
|
||||
printable_area_width_um, printable_area_length_um);
|
||||
size_um.width() - ((left_pwg + right_pwg) * kMicronsPerPwgUnit);
|
||||
int printable_area_height_um =
|
||||
size_um.height() - ((top_pwg + bottom_pwg) * kMicronsPerPwgUnit);
|
||||
return gfx::Rect(printable_area_left_um, printable_area_bottom_um,
|
||||
printable_area_width_um, printable_area_height_um);
|
||||
}
|
||||
|
||||
// Default to the paper size if printable area is empty.
|
||||
// We've seen some drivers have a printable area that goes out of bounds
|
||||
// of the paper size. In those cases, set the printable area to be the
|
||||
// size. (See crbug.com/1412305.)
|
||||
const gfx::Rect size_um_rect = gfx::Rect(paper.size_um);
|
||||
if (paper.printable_area_um.IsEmpty() ||
|
||||
!size_um_rect.Contains(paper.printable_area_um)) {
|
||||
paper.printable_area_um = size_um_rect;
|
||||
}
|
||||
void PwgMarginsFromSizeAndPrintableArea(const gfx::Size& size_um,
|
||||
const gfx::Rect& printable_area_um,
|
||||
int* bottom_pwg,
|
||||
int* left_pwg,
|
||||
int* right_pwg,
|
||||
int* top_pwg) {
|
||||
DCHECK(bottom_pwg);
|
||||
DCHECK(left_pwg);
|
||||
DCHECK(right_pwg);
|
||||
DCHECK(top_pwg);
|
||||
|
||||
// Omits the final token describing the media dimensions.
|
||||
pieces.pop_back();
|
||||
paper.display_name = base::JoinString(pieces, " ");
|
||||
// These values in microns were obtained in the first place by converting
|
||||
// from PWG units, so we can losslessly convert them back.
|
||||
int bottom_um = printable_area_um.y();
|
||||
int left_um = printable_area_um.x();
|
||||
int right_um = size_um.width() - printable_area_um.right();
|
||||
int top_um = size_um.height() - printable_area_um.bottom();
|
||||
DCHECK_EQ(bottom_um % kMicronsPerPwgUnit, 0);
|
||||
DCHECK_EQ(left_um % kMicronsPerPwgUnit, 0);
|
||||
DCHECK_EQ(right_um % kMicronsPerPwgUnit, 0);
|
||||
DCHECK_EQ(top_um % kMicronsPerPwgUnit, 0);
|
||||
|
||||
return paper;
|
||||
*bottom_pwg = bottom_um / kMicronsPerPwgUnit;
|
||||
*left_pwg = left_um / kMicronsPerPwgUnit;
|
||||
*right_pwg = right_um / kMicronsPerPwgUnit;
|
||||
*top_pwg = top_um / kMicronsPerPwgUnit;
|
||||
}
|
||||
#endif // BUILDFLAG(USE_CUPS)
|
||||
|
||||
|
@ -33,18 +33,26 @@ COMPONENT_EXPORT(PRINT_BACKEND)
|
||||
gfx::Size ParsePaperSize(base::StringPiece value);
|
||||
|
||||
#if BUILDFLAG(USE_CUPS)
|
||||
// Parses the media name expressed by `value` into a Paper. Returns an
|
||||
// empty Paper if `value` does not contain the display name nor the dimension,
|
||||
// `value` contains a prefix of media sizes not meant for users' eyes, or if the
|
||||
// paper size is empty.
|
||||
// `margins` is used to calculate the Paper's printable area.
|
||||
// We don't handle l10n here. We do populate the display_name member with the
|
||||
// prettified vendor ID, but fully expect the caller to clobber this if a better
|
||||
// localization exists.
|
||||
// Calculates a paper's printable area in microns from its size in microns and
|
||||
// its four margins in PWG units.
|
||||
COMPONENT_EXPORT(PRINT_BACKEND)
|
||||
PrinterSemanticCapsAndDefaults::Paper ParsePaper(
|
||||
base::StringPiece value,
|
||||
const CupsPrinter::CupsMediaMargins& margins);
|
||||
gfx::Rect PrintableAreaFromSizeAndPwgMargins(const gfx::Size& size_um,
|
||||
int bottom_pwg,
|
||||
int left_pwg,
|
||||
int right_pwg,
|
||||
int top_pwg);
|
||||
|
||||
// Calculates a paper's four margins in PWG units from its size and printable
|
||||
// area in microns. Since the size and printable area were converted from PWG
|
||||
// units in the first place, the margins in PWG units can be reconstructed
|
||||
// losslessly.
|
||||
COMPONENT_EXPORT(PRINT_BACKEND)
|
||||
void PwgMarginsFromSizeAndPrintableArea(const gfx::Size& size_um,
|
||||
const gfx::Rect& printable_area_um,
|
||||
int* bottom_pwg,
|
||||
int* left_pwg,
|
||||
int* right_pwg,
|
||||
int* top_pwg);
|
||||
#endif // BUILDFLAG(USE_CUPS)
|
||||
|
||||
} // namespace printing
|
||||
|
@ -56,93 +56,27 @@ TEST(PrintBackendUtilsTest, ParsePaperSizeBadOneDimension) {
|
||||
|
||||
#if BUILDFLAG(USE_CUPS)
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperA4) {
|
||||
constexpr CupsPrinter::CupsMediaMargins kMargins = {500, 500, 500, 500};
|
||||
PrinterSemanticCapsAndDefaults::Paper paper =
|
||||
ParsePaper("iso_a4_210x297mm", kMargins);
|
||||
EXPECT_EQ(gfx::Size(210000, 297000), paper.size_um);
|
||||
EXPECT_EQ("iso_a4_210x297mm", paper.vendor_id);
|
||||
EXPECT_EQ("iso a4", paper.display_name);
|
||||
EXPECT_EQ(gfx::Rect(5000, 5000, 200000, 287000), paper.printable_area_um);
|
||||
TEST(PrintBackendUtilsCupsTest, PrintableAreaFromMarginsA4) {
|
||||
// margins in PWG units (1 PWG unit = 1/100 mm = 10 um)
|
||||
int bottom = 100;
|
||||
int left = 200;
|
||||
int right = 300;
|
||||
int top = 400;
|
||||
gfx::Size size_um = {210000, 297000};
|
||||
gfx::Rect printable_area_um =
|
||||
PrintableAreaFromSizeAndPwgMargins(size_um, bottom, left, right, top);
|
||||
EXPECT_EQ(gfx::Rect(2000, 1000, 205000, 292000), printable_area_um);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperNaLetter) {
|
||||
constexpr CupsPrinter::CupsMediaMargins kMargins = {500, 500, 500, 500};
|
||||
PrinterSemanticCapsAndDefaults::Paper paper =
|
||||
ParsePaper("na_letter_8.5x11in", kMargins);
|
||||
EXPECT_EQ(gfx::Size(215900, 279400), paper.size_um);
|
||||
EXPECT_EQ("na_letter_8.5x11in", paper.vendor_id);
|
||||
EXPECT_EQ("na letter", paper.display_name);
|
||||
EXPECT_EQ(gfx::Rect(5000, 5000, 205900, 269400), paper.printable_area_um);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperNaIndex4x6) {
|
||||
// Note that "na_index-4x6_4x6in" has a dimension within the media name. Test
|
||||
// that parsing is not affected.
|
||||
constexpr CupsPrinter::CupsMediaMargins kMargins = {500, 500, 500, 500};
|
||||
PrinterSemanticCapsAndDefaults::Paper paper =
|
||||
ParsePaper("na_index-4x6_4x6in", kMargins);
|
||||
EXPECT_EQ(gfx::Size(101600, 152400), paper.size_um);
|
||||
EXPECT_EQ("na_index-4x6_4x6in", paper.vendor_id);
|
||||
EXPECT_EQ("na index-4x6", paper.display_name);
|
||||
EXPECT_EQ(gfx::Rect(5000, 5000, 91600, 142400), paper.printable_area_um);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperNaNumber10) {
|
||||
// Test that a paper size with a fractional dimension is not affected by
|
||||
// rounding errors.
|
||||
constexpr CupsPrinter::CupsMediaMargins kMargins = {1000, 1000, 1000, 1000};
|
||||
PrinterSemanticCapsAndDefaults::Paper paper =
|
||||
ParsePaper("na_number-10_4.125x9.5in", kMargins);
|
||||
EXPECT_EQ(gfx::Size(104775, 241300), paper.size_um);
|
||||
EXPECT_EQ("na_number-10_4.125x9.5in", paper.vendor_id);
|
||||
EXPECT_EQ("na number-10", paper.display_name);
|
||||
EXPECT_EQ(gfx::Rect(10000, 10000, 84775, 221300), paper.printable_area_um);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperBadUnit) {
|
||||
PrinterSemanticCapsAndDefaults::Paper paper_bad =
|
||||
ParsePaper("bad_unit_666x666bad", CupsPrinter::CupsMediaMargins());
|
||||
EXPECT_EQ(PrinterSemanticCapsAndDefaults::Paper(), paper_bad);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperBadOneDimension) {
|
||||
PrinterSemanticCapsAndDefaults::Paper paper_bad =
|
||||
ParsePaper("bad_one_dimension_666mm", CupsPrinter::CupsMediaMargins());
|
||||
EXPECT_EQ(PrinterSemanticCapsAndDefaults::Paper(), paper_bad);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperOutOfBoundsMargins) {
|
||||
// Given invalid margins, the printable area cannot be calculated correctly.
|
||||
// The printable area should be set to the paper size as default.
|
||||
constexpr CupsPrinter::CupsMediaMargins kMargins = {100, 100, 300000, 100};
|
||||
PrinterSemanticCapsAndDefaults::Paper paper =
|
||||
ParsePaper("iso_a4_210x297mm", kMargins);
|
||||
EXPECT_EQ(gfx::Size(210000, 297000), paper.size_um);
|
||||
EXPECT_EQ("iso_a4_210x297mm", paper.vendor_id);
|
||||
EXPECT_EQ("iso a4", paper.display_name);
|
||||
EXPECT_EQ(gfx::Rect(0, 0, 210000, 297000), paper.printable_area_um);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperEmptyPrintableArea) {
|
||||
// If the printable area is empty, the printable area should be set to the
|
||||
// paper size.
|
||||
constexpr CupsPrinter::CupsMediaMargins kMargins = {29700, 0, 0, 0};
|
||||
PrinterSemanticCapsAndDefaults::Paper paper =
|
||||
ParsePaper("iso_a4_210x297mm", kMargins);
|
||||
EXPECT_EQ(gfx::Size(210000, 297000), paper.size_um);
|
||||
EXPECT_EQ("iso_a4_210x297mm", paper.vendor_id);
|
||||
EXPECT_EQ("iso a4", paper.display_name);
|
||||
EXPECT_EQ(gfx::Rect(0, 0, 210000, 297000), paper.printable_area_um);
|
||||
}
|
||||
|
||||
TEST(PrintBackendUtilsCupsTest, ParsePaperEmptySizeWithPrintableArea) {
|
||||
// If the paper size is empty, the Paper should be invalid, even when provided
|
||||
// a printable area.
|
||||
constexpr CupsPrinter::CupsMediaMargins kMargins = {1000, 1000, 1000, 1000};
|
||||
PrinterSemanticCapsAndDefaults::Paper paper_bad =
|
||||
ParsePaper("bad_unit_666x666bad", kMargins);
|
||||
EXPECT_EQ(PrinterSemanticCapsAndDefaults::Paper(), paper_bad);
|
||||
TEST(PrintBackendUtilsCupsTest, MarginsFromPrintableAreaA4) {
|
||||
int bottom, left, right, top;
|
||||
PwgMarginsFromSizeAndPrintableArea({210000, 297000},
|
||||
{2000, 1000, 205000, 292000}, &bottom,
|
||||
&left, &right, &top);
|
||||
EXPECT_EQ(100, bottom);
|
||||
EXPECT_EQ(200, left);
|
||||
EXPECT_EQ(300, right);
|
||||
EXPECT_EQ(400, top);
|
||||
}
|
||||
|
||||
#endif // BUILDFLAG(USE_CUPS)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include "printing/backend/cups_ipp_constants.h"
|
||||
#include "printing/backend/cups_ipp_helper.h"
|
||||
#include "printing/backend/cups_printer.h"
|
||||
#include "printing/backend/print_backend_utils.h"
|
||||
#include "printing/buildflags/buildflags.h"
|
||||
#include "printing/client_info_helpers.h"
|
||||
#include "printing/metafile.h"
|
||||
@ -96,48 +97,53 @@ void EncodeClientInfo(const std::vector<mojom::IppClientInfo>& client_infos,
|
||||
raw_option_values.size(), raw_option_values.data());
|
||||
}
|
||||
|
||||
// Construct the IPP media-col attribute specifying media size, margins, source,
|
||||
// etc., and add it to 'options'.
|
||||
void EncodeMediaCol(ipp_t* options,
|
||||
const gfx::Size& size_um,
|
||||
const gfx::Rect& printable_area_um,
|
||||
const std::string& source) {
|
||||
// The size and printable area in microns were calculated from the size and
|
||||
// margins in PWG units, so we can losslessly convert them back.
|
||||
DCHECK_EQ(size_um.width() % kMicronsPerPwgUnit, 0);
|
||||
DCHECK_EQ(size_um.height() % kMicronsPerPwgUnit, 0);
|
||||
int width = size_um.width() / kMicronsPerPwgUnit;
|
||||
int height = size_um.height() / kMicronsPerPwgUnit;
|
||||
int bottom_margin = 0, left_margin = 0, right_margin = 0, top_margin = 0;
|
||||
PwgMarginsFromSizeAndPrintableArea(size_um, printable_area_um, &bottom_margin,
|
||||
&left_margin, &right_margin, &top_margin);
|
||||
|
||||
ScopedIppPtr media_col = WrapIpp(ippNew());
|
||||
ScopedIppPtr media_size = WrapIpp(ippNew());
|
||||
ippAddInteger(media_size.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER, kIppXDimension,
|
||||
width);
|
||||
ippAddInteger(media_size.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER, kIppYDimension,
|
||||
height);
|
||||
ippAddCollection(media_col.get(), IPP_TAG_ZERO, kIppMediaSize,
|
||||
media_size.get());
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
kIppMediaBottomMargin, bottom_margin);
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
kIppMediaLeftMargin, left_margin);
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
kIppMediaRightMargin, right_margin);
|
||||
ippAddInteger(media_col.get(), IPP_TAG_ZERO, IPP_TAG_INTEGER,
|
||||
kIppMediaTopMargin, top_margin);
|
||||
if (!source.empty()) {
|
||||
ippAddString(media_col.get(), IPP_TAG_ZERO, IPP_TAG_KEYWORD,
|
||||
kIppMediaSource, nullptr, source.c_str());
|
||||
}
|
||||
|
||||
ippAddCollection(options, IPP_TAG_JOB, kIppMediaCol, media_col.get());
|
||||
}
|
||||
|
||||
std::string GetCollateString(bool collate) {
|
||||
return collate ? kCollated : kUncollated;
|
||||
}
|
||||
|
||||
// Given an integral `value` expressed in PWG units (1/100 mm), returns
|
||||
// the same value expressed in device units.
|
||||
int PwgUnitsToDeviceUnits(int value, float micrometers_per_device_unit) {
|
||||
return ConvertUnitFloat(value, micrometers_per_device_unit, 10);
|
||||
}
|
||||
|
||||
// Given a `media_size`, the specification of the media's `margins`, and
|
||||
// the number of micrometers per device unit, returns the rectangle
|
||||
// bounding the apparent printable area of said media.
|
||||
gfx::Rect RepresentPrintableArea(const gfx::Size& media_size,
|
||||
const CupsPrinter::CupsMediaMargins& margins,
|
||||
float micrometers_per_device_unit) {
|
||||
// These values express inward encroachment by margins, away from the
|
||||
// edges of the `media_size`.
|
||||
int left_bound =
|
||||
PwgUnitsToDeviceUnits(margins.left, micrometers_per_device_unit);
|
||||
int bottom_bound =
|
||||
PwgUnitsToDeviceUnits(margins.bottom, micrometers_per_device_unit);
|
||||
int right_bound =
|
||||
PwgUnitsToDeviceUnits(margins.right, micrometers_per_device_unit);
|
||||
int top_bound =
|
||||
PwgUnitsToDeviceUnits(margins.top, micrometers_per_device_unit);
|
||||
|
||||
// These values express the bounding box of the printable area on the
|
||||
// page.
|
||||
int printable_width = media_size.width() - (left_bound + right_bound);
|
||||
int printable_height = media_size.height() - (top_bound + bottom_bound);
|
||||
|
||||
if (printable_width > 0 && printable_height > 0) {
|
||||
return {left_bound, bottom_bound, printable_width, printable_height};
|
||||
}
|
||||
|
||||
return {0, 0, media_size.width(), media_size.height()};
|
||||
}
|
||||
|
||||
void SetPrintableArea(PrintSettings* settings,
|
||||
const PrintSettings::RequestedMedia& media,
|
||||
const CupsPrinter::CupsMediaMargins& margins) {
|
||||
const gfx::Rect& printable_area_um) {
|
||||
if (!media.size_microns.IsEmpty()) {
|
||||
float device_microns_per_device_unit =
|
||||
static_cast<float>(kMicronsPerInch) / settings->device_units_per_inch();
|
||||
@ -145,8 +151,11 @@ void SetPrintableArea(PrintSettings* settings,
|
||||
gfx::Size(media.size_microns.width() / device_microns_per_device_unit,
|
||||
media.size_microns.height() / device_microns_per_device_unit);
|
||||
|
||||
gfx::Rect paper_rect = RepresentPrintableArea(
|
||||
paper_size, margins, device_microns_per_device_unit);
|
||||
gfx::Rect paper_rect =
|
||||
gfx::Rect(printable_area_um.x() / device_microns_per_device_unit,
|
||||
printable_area_um.y() / device_microns_per_device_unit,
|
||||
printable_area_um.width() / device_microns_per_device_unit,
|
||||
printable_area_um.height() / device_microns_per_device_unit);
|
||||
settings->SetPrinterPrintableArea(paper_size, paper_rect,
|
||||
/*landscape_needs_flip=*/true);
|
||||
}
|
||||
@ -154,7 +163,8 @@ void SetPrintableArea(PrintSettings* settings,
|
||||
|
||||
} // namespace
|
||||
|
||||
ScopedIppPtr SettingsToIPPOptions(const PrintSettings& settings) {
|
||||
ScopedIppPtr SettingsToIPPOptions(const PrintSettings& settings,
|
||||
const gfx::Rect& printable_area_um) {
|
||||
ScopedIppPtr scoped_options = WrapIpp(ippNew());
|
||||
ipp_t* options = scoped_options.get();
|
||||
|
||||
@ -179,9 +189,6 @@ ScopedIppPtr SettingsToIPPOptions(const PrintSettings& settings) {
|
||||
// color
|
||||
ippAddString(options, IPP_TAG_JOB, IPP_TAG_KEYWORD, kIppColor, nullptr,
|
||||
GetIppColorModelForModel(settings.color()).c_str());
|
||||
// paper size
|
||||
ippAddString(options, IPP_TAG_JOB, IPP_TAG_KEYWORD, kIppMedia, nullptr,
|
||||
settings.requested_media().vendor_id.c_str());
|
||||
// copies
|
||||
ippAddInteger(options, IPP_TAG_JOB, IPP_TAG_INTEGER, kIppCopies,
|
||||
settings.copies());
|
||||
@ -203,11 +210,17 @@ ScopedIppPtr SettingsToIPPOptions(const PrintSettings& settings) {
|
||||
}
|
||||
|
||||
std::map<std::string, std::vector<int>> multival;
|
||||
std::string media_source;
|
||||
for (const auto& setting : settings.advanced_settings()) {
|
||||
const std::string& key = setting.first;
|
||||
const std::string& value = setting.second.GetString();
|
||||
if (value.empty())
|
||||
if (value.empty()) {
|
||||
continue;
|
||||
}
|
||||
if (key == kIppMediaSource) {
|
||||
media_source = value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check for multivalue enum ("attribute/value").
|
||||
size_t pos = key.find('/');
|
||||
@ -227,6 +240,11 @@ ScopedIppPtr SettingsToIPPOptions(const PrintSettings& settings) {
|
||||
}
|
||||
}
|
||||
|
||||
// Construct the IPP media-col attribute specifying media size, margins,
|
||||
// source, etc.
|
||||
EncodeMediaCol(options, settings.requested_media().size_microns,
|
||||
printable_area_um, media_source);
|
||||
|
||||
// Add multivalue enum options.
|
||||
for (const auto& it : multival) {
|
||||
ippAddIntegers(options, IPP_TAG_JOB, IPP_TAG_ENUM, it.first.c_str(),
|
||||
@ -325,10 +343,7 @@ mojom::ResultCode PrintingContextChromeos::UseDefaultSettings() {
|
||||
media.vendor_id = paper.vendor_id;
|
||||
media.size_microns = paper.size_um;
|
||||
settings_->set_requested_media(media);
|
||||
|
||||
CupsPrinter::CupsMediaMargins margins =
|
||||
printer_->GetMediaMarginsByName(paper.vendor_id);
|
||||
SetPrintableArea(settings_.get(), media, margins);
|
||||
SetPrintableArea(settings_.get(), media, paper.printable_area_um);
|
||||
|
||||
return mojom::ResultCode::kSuccess;
|
||||
}
|
||||
@ -387,10 +402,10 @@ mojom::ResultCode PrintingContextChromeos::UpdatePrinterSettings(
|
||||
settings_->set_requested_media(media);
|
||||
}
|
||||
|
||||
CupsPrinter::CupsMediaMargins margins =
|
||||
printer_->GetMediaMarginsByName(media.vendor_id);
|
||||
SetPrintableArea(settings_.get(), media, margins);
|
||||
ipp_options_ = SettingsToIPPOptions(*settings_);
|
||||
gfx::Rect printable_area_um =
|
||||
GetPrintableAreaForSize(*printer_, media.size_microns);
|
||||
SetPrintableArea(settings_.get(), media, printable_area_um);
|
||||
ipp_options_ = SettingsToIPPOptions(*settings_, printable_area_um);
|
||||
send_user_info_ = settings_->send_user_info();
|
||||
if (send_user_info_) {
|
||||
DCHECK(printer_);
|
||||
|
@ -67,7 +67,8 @@ class COMPONENT_EXPORT(PRINTING) PrintingContextChromeos
|
||||
// This has the side effect of recording UMA for advanced attributes usage,
|
||||
// so only call once per job.
|
||||
COMPONENT_EXPORT(PRINTING)
|
||||
ScopedIppPtr SettingsToIPPOptions(const PrintSettings& settings);
|
||||
ScopedIppPtr SettingsToIPPOptions(const PrintSettings& settings,
|
||||
const gfx::Rect& printable_area_um);
|
||||
|
||||
} // namespace printing
|
||||
|
||||
|
@ -35,6 +35,9 @@ constexpr char kUsername[] = "test user";
|
||||
constexpr char kDocumentName[] = "document name";
|
||||
constexpr char16_t kDocumentName16[] = u"document name";
|
||||
|
||||
constexpr gfx::Size kDefaultPaperSize = {215900, 279400};
|
||||
constexpr char kDefaultPaperName[] = "some_vendor_id";
|
||||
|
||||
class MockCupsConnection : public CupsConnection {
|
||||
public:
|
||||
MOCK_METHOD1(GetDests, bool(std::vector<std::unique_ptr<CupsPrinter>>&));
|
||||
@ -76,6 +79,7 @@ class PrintingContextTest : public testing::Test,
|
||||
settings->set_duplex_mode(mojom::DuplexMode::kLongEdge);
|
||||
settings->set_username(kUsername);
|
||||
printing_context_->UpdatePrintSettingsFromPOD(std::move(settings));
|
||||
settings_.set_requested_media({kDefaultPaperSize, kDefaultPaperName});
|
||||
}
|
||||
|
||||
ipp_attribute_t* GetAttribute(ipp_t* attributes,
|
||||
@ -97,20 +101,20 @@ class PrintingContextTest : public testing::Test,
|
||||
|
||||
void TestStringOptionValue(const char* attr_name,
|
||||
const char* expected_value) const {
|
||||
auto attributes = SettingsToIPPOptions(settings_);
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
auto* attr = GetAttribute(attributes.get(), attr_name);
|
||||
EXPECT_STREQ(expected_value, ippGetString(attr, 0, nullptr));
|
||||
}
|
||||
|
||||
void TestIntegerOptionValue(const char* attr_name, int expected_value) const {
|
||||
auto attributes = SettingsToIPPOptions(settings_);
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
auto* attr = GetAttribute(attributes.get(), attr_name);
|
||||
EXPECT_EQ(expected_value, ippGetInteger(attr, 0));
|
||||
}
|
||||
|
||||
void TestOctetStringOptionValue(const char* attr_name,
|
||||
base::span<const char> expected_value) const {
|
||||
auto attributes = SettingsToIPPOptions(settings_);
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
auto* attr = GetAttribute(attributes.get(), attr_name);
|
||||
int length;
|
||||
void* value = ippGetOctetString(attr, 0, &length);
|
||||
@ -122,7 +126,7 @@ class PrintingContextTest : public testing::Test,
|
||||
void TestResolutionOptionValue(const char* attr_name,
|
||||
int expected_x_res,
|
||||
int expected_y_res) const {
|
||||
auto attributes = SettingsToIPPOptions(settings_);
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
auto* attr = GetAttribute(attributes.get(), attr_name);
|
||||
ipp_res_t unit;
|
||||
int y_res;
|
||||
@ -132,18 +136,47 @@ class PrintingContextTest : public testing::Test,
|
||||
EXPECT_EQ(expected_y_res, y_res);
|
||||
}
|
||||
|
||||
void TestMediaColValue(const gfx::Size& expected_size,
|
||||
int expected_bottom_margin,
|
||||
int expected_left_margin,
|
||||
int expected_right_margin,
|
||||
int expected_top_margin) {
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
ipp_t* media_col =
|
||||
ippGetCollection(GetAttribute(attributes.get(), kIppMediaCol), 0);
|
||||
ipp_t* media_size =
|
||||
ippGetCollection(GetAttribute(media_col, kIppMediaSize), 0);
|
||||
|
||||
int width = ippGetInteger(GetAttribute(media_size, kIppXDimension), 0);
|
||||
int height = ippGetInteger(GetAttribute(media_size, kIppYDimension), 0);
|
||||
EXPECT_EQ(expected_size.width(), width);
|
||||
EXPECT_EQ(expected_size.height(), height);
|
||||
|
||||
int bottom =
|
||||
ippGetInteger(GetAttribute(media_col, kIppMediaBottomMargin), 0);
|
||||
int left = ippGetInteger(GetAttribute(media_col, kIppMediaLeftMargin), 0);
|
||||
int right = ippGetInteger(GetAttribute(media_col, kIppMediaRightMargin), 0);
|
||||
int top = ippGetInteger(GetAttribute(media_col, kIppMediaTopMargin), 0);
|
||||
|
||||
EXPECT_EQ(expected_bottom_margin, bottom);
|
||||
EXPECT_EQ(expected_left_margin, left);
|
||||
EXPECT_EQ(expected_right_margin, right);
|
||||
EXPECT_EQ(expected_top_margin, top);
|
||||
}
|
||||
|
||||
bool HasAttribute(const char* attr_name) const {
|
||||
auto attributes = SettingsToIPPOptions(settings_);
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
return !!ippFindAttribute(attributes.get(), attr_name, IPP_TAG_ZERO);
|
||||
}
|
||||
|
||||
int GetAttrValueCount(const char* attr_name) const {
|
||||
auto attributes = SettingsToIPPOptions(settings_);
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
auto* attr = GetAttribute(attributes.get(), attr_name);
|
||||
return ippGetCount(attr);
|
||||
}
|
||||
|
||||
TestPrintSettings settings_;
|
||||
gfx::Rect printable_area_;
|
||||
|
||||
// PrintingContext::Delegate methods.
|
||||
gfx::NativeView GetParentView() override { return nullptr; }
|
||||
@ -169,11 +202,12 @@ TEST_F(PrintingContextTest, SettingsToIPPOptions_Duplex) {
|
||||
TestStringOptionValue(kIppDuplex, "two-sided-short-edge");
|
||||
}
|
||||
|
||||
TEST_F(PrintingContextTest, SettingsToIPPOptions_Media) {
|
||||
TestStringOptionValue(kIppMedia, "");
|
||||
TEST_F(PrintingContextTest, SettingsToIPPOptions_MediaCol) {
|
||||
settings_.set_requested_media(
|
||||
{gfx::Size(297000, 420000), "iso_a3_297x420mm"});
|
||||
TestStringOptionValue(kIppMedia, "iso_a3_297x420mm");
|
||||
printable_area_ =
|
||||
gfx::Rect(2000, 1000, 297000 - (2000 + 3000), 420000 - (1000 + 4000));
|
||||
TestMediaColValue(gfx::Size(29700, 42000), 100, 200, 300, 400);
|
||||
}
|
||||
|
||||
TEST_F(PrintingContextTest, SettingsToIPPOptions_Copies) {
|
||||
@ -285,7 +319,7 @@ TEST_F(PrintingContextTest, SettingsToIPPOptionsClientInfo) {
|
||||
"a.1-B_");
|
||||
settings_.set_client_infos({client_info});
|
||||
|
||||
auto attributes = SettingsToIPPOptions(settings_);
|
||||
auto attributes = SettingsToIPPOptions(settings_, printable_area_);
|
||||
auto* attr = ippFindAttribute(attributes.get(), kIppClientInfo,
|
||||
IPP_TAG_BEGIN_COLLECTION);
|
||||
auto* client_info_collection = ippGetCollection(attr, 0);
|
||||
|
Reference in New Issue
Block a user